mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 09:50:27 +00:00
The asm interpreter already inlines ECMAScript calls, but builtin calls still went through the generic C++ Call slow path even when the callee was a plain native function pointer. That added an avoidable boundary around hot builtin calls and kept asm from taking full advantage of the new RawNativeFunction representation. Teach the asm Call handler to recognize RawNativeFunction, allocate the callee frame on the interpreter stack, copy the call-site arguments, and jump straight to the stored C++ entry point. NativeJavaScriptBackedFunction and other non-raw callees keep falling through to the existing C++ slow path unchanged.
414 lines
26 KiB
C++
414 lines
26 KiB
C++
/*
|
|
* Copyright (c) 2026, the Ladybird developers.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
// Small build-time tool that prints struct field offsets as DSL constants.
|
|
// Compiled with the same flags as LibJS so layouts match exactly.
|
|
|
|
#include <AK/Format.h>
|
|
#include <AK/StringBase.h>
|
|
#include <AK/Utf16StringData.h>
|
|
#include <LibJS/Bytecode/Builtins.h>
|
|
#include <LibJS/Bytecode/Executable.h>
|
|
#include <LibJS/Bytecode/PropertyNameIterator.h>
|
|
#include <LibJS/Bytecode/PutKind.h>
|
|
#include <LibJS/Runtime/ArrayBuffer.h>
|
|
#include <LibJS/Runtime/DeclarativeEnvironment.h>
|
|
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
|
#include <LibJS/Runtime/ExecutionContext.h>
|
|
#include <LibJS/Runtime/FunctionObject.h>
|
|
#include <LibJS/Runtime/GlobalEnvironment.h>
|
|
#include <LibJS/Runtime/IndexedProperties.h>
|
|
#include <LibJS/Runtime/NativeFunction.h>
|
|
#include <LibJS/Runtime/Object.h>
|
|
#include <LibJS/Runtime/PrimitiveString.h>
|
|
#include <LibJS/Runtime/Realm.h>
|
|
#include <LibJS/Runtime/Shape.h>
|
|
#include <LibJS/Runtime/SharedFunctionInstanceData.h>
|
|
#include <LibJS/Runtime/TypedArray.h>
|
|
#include <LibJS/Runtime/VM.h>
|
|
|
|
#define EMIT_OFFSET(name, type, member) \
|
|
outln("const " #name " = {}", offsetof(type, member))
|
|
|
|
#define EMIT_SIZEOF(name, type) \
|
|
outln("const " #name " = {}", sizeof(type))
|
|
|
|
int main()
|
|
{
|
|
using namespace JS;
|
|
using namespace JS::Bytecode;
|
|
|
|
struct PrimitiveStringLayoutAccessor : PrimitiveString {
|
|
using PrimitiveString::DeferredKind;
|
|
using PrimitiveString::m_deferred_kind;
|
|
using PrimitiveString::m_utf16_string;
|
|
};
|
|
|
|
outln("# Generated by gen_asm_offsets -- DO NOT EDIT\n");
|
|
|
|
// Object layout
|
|
outln("# Object layout");
|
|
EMIT_OFFSET(OBJECT_SHAPE, Object, m_shape);
|
|
EMIT_OFFSET(OBJECT_NAMED_PROPERTIES, Object, m_named_properties);
|
|
EMIT_OFFSET(OBJECT_INDEXED_ELEMENTS, Object, m_indexed_elements);
|
|
EMIT_OFFSET(OBJECT_INDEXED_STORAGE_KIND, Object, m_indexed_storage_kind);
|
|
EMIT_OFFSET(OBJECT_INDEXED_ARRAY_LIKE_SIZE, Object, m_indexed_array_like_size);
|
|
EMIT_SIZEOF(OBJECT_SIZE, Object);
|
|
|
|
// Object flags byte
|
|
outln("\n# Object flags");
|
|
EMIT_OFFSET(OBJECT_FLAGS, Object, m_flags);
|
|
outln("const OBJECT_FLAG_HAS_MAGICAL_LENGTH = {}", Object::Flag::HasMagicalLengthProperty);
|
|
outln("const OBJECT_FLAG_MAY_INTERFERE = {}", Object::Flag::MayInterfereWithIndexedPropertyAccess);
|
|
outln("const OBJECT_FLAG_IS_TYPED_ARRAY = {}", Object::Flag::IsTypedArray);
|
|
outln("const OBJECT_FLAG_IS_FUNCTION = {}", Object::Flag::IsFunction);
|
|
outln("const OBJECT_FLAG_IS_ECMASCRIPT_FUNCTION_OBJECT = {}", Object::Flag::IsECMAScriptFunctionObject);
|
|
outln("const OBJECT_FLAG_IS_RAW_NATIVE_FUNCTION = {}", Object::Flag::IsRawNativeFunction);
|
|
|
|
// Shape layout
|
|
outln("\n# Shape layout");
|
|
EMIT_OFFSET(SHAPE_REALM, Shape, m_realm);
|
|
EMIT_OFFSET(SHAPE_PROTOTYPE, Shape, m_prototype);
|
|
EMIT_OFFSET(SHAPE_DICTIONARY_GENERATION, Shape, m_dictionary_generation);
|
|
EMIT_SIZEOF(SHAPE_SIZE, Shape);
|
|
|
|
// PropertyLookupCache layout
|
|
outln("\n# PropertyLookupCache layout");
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRIES, PropertyLookupCache, entries);
|
|
EMIT_SIZEOF(PROPERTY_LOOKUP_CACHE_SIZE, PropertyLookupCache);
|
|
|
|
// PropertyLookupCache::Entry layout
|
|
outln("\n# PropertyLookupCache::Entry layout");
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRY_PROPERTY_OFFSET, PropertyLookupCache::Entry, property_offset);
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRY_DICTIONARY_GENERATION, PropertyLookupCache::Entry, shape_dictionary_generation);
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRY_FROM_SHAPE, PropertyLookupCache::Entry, from_shape);
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRY_SHAPE, PropertyLookupCache::Entry, shape);
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRY_PROTOTYPE, PropertyLookupCache::Entry, prototype);
|
|
EMIT_OFFSET(PROPERTY_LOOKUP_CACHE_ENTRY_PROTOTYPE_CHAIN_VALIDITY, PropertyLookupCache::Entry, prototype_chain_validity);
|
|
EMIT_SIZEOF(PROPERTY_LOOKUP_CACHE_ENTRY_SIZE, PropertyLookupCache::Entry);
|
|
|
|
// Composite offsets for entry[0] within a PropertyLookupCache
|
|
outln("\n# Entry[0] offsets within PropertyLookupCache");
|
|
auto plc_entries = offsetof(PropertyLookupCache, entries);
|
|
outln("const PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET = {}", plc_entries + offsetof(PropertyLookupCache::Entry, property_offset));
|
|
outln("const PROPERTY_LOOKUP_CACHE_ENTRY0_DICTIONARY_GENERATION = {}", plc_entries + offsetof(PropertyLookupCache::Entry, shape_dictionary_generation));
|
|
outln("const PROPERTY_LOOKUP_CACHE_ENTRY0_SHAPE = {}", plc_entries + offsetof(PropertyLookupCache::Entry, shape));
|
|
outln("const PROPERTY_LOOKUP_CACHE_ENTRY0_PROTOTYPE = {}", plc_entries + offsetof(PropertyLookupCache::Entry, prototype));
|
|
outln("const PROPERTY_LOOKUP_CACHE_ENTRY0_PROTOTYPE_CHAIN_VALIDITY = {}", plc_entries + offsetof(PropertyLookupCache::Entry, prototype_chain_validity));
|
|
|
|
// ObjectPropertyIteratorCacheData layout
|
|
outln("\n# ObjectPropertyIteratorCacheData layout");
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_PROPERTIES, ObjectPropertyIteratorCacheData, m_properties);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_PROPERTY_VALUES, ObjectPropertyIteratorCacheData, m_property_values);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_SHAPE, ObjectPropertyIteratorCacheData, m_shape);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_PROTOTYPE_CHAIN_VALIDITY, ObjectPropertyIteratorCacheData, m_prototype_chain_validity);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_INDEXED_PROPERTY_COUNT, ObjectPropertyIteratorCacheData, m_indexed_property_count);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_SHAPE_DICTIONARY_GENERATION, ObjectPropertyIteratorCacheData, m_shape_dictionary_generation);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_FAST_PATH, ObjectPropertyIteratorCacheData, m_fast_path);
|
|
|
|
// ObjectPropertyIteratorCache layout
|
|
outln("\n# ObjectPropertyIteratorCache layout");
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_DATA_PTR, ObjectPropertyIteratorCache, data);
|
|
EMIT_OFFSET(OBJECT_PROPERTY_ITERATOR_CACHE_REUSABLE_PROPERTY_NAME_ITERATOR, ObjectPropertyIteratorCache, reusable_property_name_iterator);
|
|
|
|
// PropertyNameIterator layout
|
|
outln("\n# PropertyNameIterator layout");
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_OBJECT, PropertyNameIterator, m_object);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_PROPERTY_CACHE, PropertyNameIterator, m_property_cache);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_SHAPE, PropertyNameIterator, m_shape);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_PROTOTYPE_CHAIN_VALIDITY, PropertyNameIterator, m_prototype_chain_validity);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_ITERATOR_CACHE_SLOT, PropertyNameIterator, m_iterator_cache_slot);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_INDEXED_PROPERTY_COUNT, PropertyNameIterator, m_indexed_property_count);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_NEXT_INDEXED_PROPERTY, PropertyNameIterator, m_next_indexed_property);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_NEXT_PROPERTY, PropertyNameIterator, m_next_property);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_SHAPE_IS_DICTIONARY, PropertyNameIterator, m_shape_is_dictionary);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_SHAPE_DICTIONARY_GENERATION, PropertyNameIterator, m_shape_dictionary_generation);
|
|
EMIT_OFFSET(PROPERTY_NAME_ITERATOR_FAST_PATH, PropertyNameIterator, m_fast_path);
|
|
|
|
// Executable layout
|
|
outln("\n# Executable layout");
|
|
EMIT_OFFSET(EXECUTABLE_CONSTANTS, Executable, constants);
|
|
EMIT_OFFSET(EXECUTABLE_PROPERTY_LOOKUP_CACHES, Executable, property_lookup_caches);
|
|
EMIT_OFFSET(EXECUTABLE_REGISTERS_AND_LOCALS_COUNT, Executable, registers_and_locals_count);
|
|
EMIT_OFFSET(EXECUTABLE_REGISTERS_AND_LOCALS_AND_CONSTANTS_COUNT, Executable, registers_and_locals_and_constants_count);
|
|
EMIT_OFFSET(EXECUTABLE_ASM_CONSTANTS_SIZE, Executable, asm_constants_size);
|
|
EMIT_OFFSET(EXECUTABLE_ASM_CONSTANTS_DATA, Executable, asm_constants_data);
|
|
|
|
// ExecutionContext layout
|
|
outln("\n# ExecutionContext layout");
|
|
VERIFY(alignof(ExecutionContext) == sizeof(Value));
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_EXECUTABLE, ExecutionContext, executable);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_FUNCTION, ExecutionContext, function);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_REALM, ExecutionContext, realm);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_SCRIPT_OR_MODULE, ExecutionContext, script_or_module);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_LEXICAL_ENVIRONMENT, ExecutionContext, lexical_environment);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_VARIABLE_ENVIRONMENT, ExecutionContext, variable_environment);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_PRIVATE_ENVIRONMENT, ExecutionContext, private_environment);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_SKIP_WHEN_DETERMINING_INCUMBENT_COUNTER, ExecutionContext, skip_when_determining_incumbent_counter);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_YIELD_CONTINUATION, ExecutionContext, yield_continuation);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_YIELD_IS_AWAIT, ExecutionContext, yield_is_await);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_CALLER_IS_CONSTRUCT, ExecutionContext, caller_is_construct);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_THIS_VALUE, ExecutionContext, this_value);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_CALLER_FRAME, ExecutionContext, caller_frame);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_PASSED_ARGUMENT_COUNT, ExecutionContext, passed_argument_count);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_CALLER_RETURN_PC, ExecutionContext, caller_return_pc);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_CALLER_DST_RAW, ExecutionContext, caller_dst_raw);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_PROGRAM_COUNTER, ExecutionContext, program_counter);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_REGISTERS_AND_CONSTANTS_AND_LOCALS_AND_ARGUMENTS_COUNT, ExecutionContext, registers_and_constants_and_locals_and_arguments_count);
|
|
EMIT_OFFSET(EXECUTION_CONTEXT_ARGUMENT_COUNT, ExecutionContext, argument_count);
|
|
EMIT_SIZEOF(SIZEOF_EXECUTION_CONTEXT, ExecutionContext);
|
|
outln("const ALIGNOF_EXECUTION_CONTEXT = {}", alignof(ExecutionContext));
|
|
outln("const EXECUTION_CONTEXT_NO_YIELD_CONTINUATION = {}", ExecutionContext::no_yield_continuation);
|
|
outln("const SIZEOF_SCRIPT_OR_MODULE = {}", sizeof(ScriptOrModule));
|
|
|
|
// InterpreterStack layout
|
|
outln("\n# InterpreterStack layout");
|
|
EMIT_OFFSET(INTERPRETER_STACK_LIMIT, InterpreterStack, m_limit);
|
|
EMIT_OFFSET(INTERPRETER_STACK_TOP, InterpreterStack, m_top);
|
|
|
|
// Realm layout
|
|
outln("\n# Realm layout");
|
|
EMIT_OFFSET(REALM_GLOBAL_ENVIRONMENT, Realm, m_global_environment);
|
|
EMIT_OFFSET(REALM_GLOBAL_OBJECT, Realm, m_global_object);
|
|
EMIT_OFFSET(REALM_GLOBAL_DECLARATIVE_ENVIRONMENT, Realm, m_global_declarative_environment);
|
|
|
|
// VM layout
|
|
outln("\n# VM layout");
|
|
EMIT_OFFSET(VM_RUNNING_EXECUTION_CONTEXT, VM, m_running_execution_context);
|
|
EMIT_OFFSET(VM_INTERPRETER_STACK, VM, m_interpreter_stack);
|
|
EMIT_OFFSET(VM_STACK_INFO, VM, m_stack_info);
|
|
EMIT_OFFSET(VM_EXECUTION_GENERATION, VM, m_execution_generation);
|
|
outln("const VM_INTERPRETER_STACK_TOP = {}", offsetof(VM, m_interpreter_stack) + offsetof(InterpreterStack, m_top));
|
|
#if defined(HAS_ADDRESS_SANITIZER)
|
|
outln("const VM_STACK_SPACE_LIMIT = {}", 96 * KiB);
|
|
#else
|
|
outln("const VM_STACK_SPACE_LIMIT = {}", 32 * KiB);
|
|
#endif
|
|
|
|
// StackInfo layout
|
|
outln("\n# StackInfo layout");
|
|
EMIT_OFFSET(STACK_INFO_BASE, StackInfo, m_base);
|
|
|
|
// IndexedStorageKind enum values
|
|
outln("\n# IndexedStorageKind enum values");
|
|
outln("const INDEXED_STORAGE_KIND_NONE = {}", static_cast<u8>(IndexedStorageKind::None));
|
|
outln("const INDEXED_STORAGE_KIND_PACKED = {}", static_cast<u8>(IndexedStorageKind::Packed));
|
|
outln("const INDEXED_STORAGE_KIND_HOLEY = {}", static_cast<u8>(IndexedStorageKind::Holey));
|
|
outln("const INDEXED_STORAGE_KIND_DICTIONARY = {}", static_cast<u8>(IndexedStorageKind::Dictionary));
|
|
|
|
// ObjectPropertyIteratorFastPath enum values
|
|
outln("\n# ObjectPropertyIteratorFastPath enum values");
|
|
outln("const OBJECT_PROPERTY_ITERATOR_FAST_PATH_NONE = {}", static_cast<u8>(ObjectPropertyIteratorFastPath::None));
|
|
outln("const OBJECT_PROPERTY_ITERATOR_FAST_PATH_PLAIN_NAMED = {}", static_cast<u8>(ObjectPropertyIteratorFastPath::PlainNamed));
|
|
outln("const OBJECT_PROPERTY_ITERATOR_FAST_PATH_PACKED_INDEXED = {}", static_cast<u8>(ObjectPropertyIteratorFastPath::PackedIndexed));
|
|
|
|
// Vector<Value> layout (used for bytecode)
|
|
outln("\n# Vector<Value> layout");
|
|
{
|
|
Vector<Value> v;
|
|
auto base = reinterpret_cast<uintptr_t>(&v);
|
|
auto vec_data = reinterpret_cast<uintptr_t>(&v.m_metadata.outline_buffer) - base;
|
|
auto vec_size = reinterpret_cast<uintptr_t>(&v.m_size) - base;
|
|
outln("const VECTOR_DATA = {}", vec_data);
|
|
outln("const VECTOR_SIZE = {}", vec_size);
|
|
|
|
// Composite offset for Executable.bytecode data pointer
|
|
outln("const EXECUTABLE_BYTECODE_DATA = {}", offsetof(Executable, bytecode) + vec_data);
|
|
outln("const EXECUTABLE_CONSTANTS_DATA = {}", offsetof(Executable, constants) + vec_data);
|
|
outln("const EXECUTABLE_CONSTANTS_SIZE = {}", offsetof(Executable, constants) + vec_size);
|
|
outln("const OBJECT_PROPERTY_ITERATOR_CACHE_DATA_PROPERTY_VALUES_DATA = {}", offsetof(ObjectPropertyIteratorCacheData, m_property_values) + vec_data);
|
|
outln("const OBJECT_PROPERTY_ITERATOR_CACHE_DATA_PROPERTY_VALUES_SIZE = {}", offsetof(ObjectPropertyIteratorCacheData, m_property_values) + vec_size);
|
|
}
|
|
|
|
// PutKind enum
|
|
outln("\n# PutKind enum");
|
|
outln("const PUT_KIND_NORMAL = {}", static_cast<u8>(JS::Bytecode::PutKind::Normal));
|
|
|
|
// PrototypeChainValidity layout
|
|
outln("\n# PrototypeChainValidity layout");
|
|
EMIT_OFFSET(PROTOTYPE_CHAIN_VALIDITY_VALID, PrototypeChainValidity, m_valid);
|
|
|
|
// DeclarativeEnvironment layout
|
|
outln("\n# DeclarativeEnvironment layout");
|
|
EMIT_OFFSET(DECLARATIVE_ENVIRONMENT_SERIAL, DeclarativeEnvironment, m_environment_serial_number);
|
|
|
|
// GlobalVariableCache layout
|
|
outln("\n# GlobalVariableCache layout");
|
|
EMIT_OFFSET(GLOBAL_VARIABLE_CACHE_ENVIRONMENT_SERIAL, GlobalVariableCache, environment_serial_number);
|
|
EMIT_OFFSET(GLOBAL_VARIABLE_CACHE_ENVIRONMENT_BINDING_INDEX, GlobalVariableCache, environment_binding_index);
|
|
EMIT_OFFSET(GLOBAL_VARIABLE_CACHE_HAS_ENVIRONMENT_BINDING, GlobalVariableCache, has_environment_binding_index);
|
|
EMIT_OFFSET(GLOBAL_VARIABLE_CACHE_IN_MODULE_ENVIRONMENT, GlobalVariableCache, in_module_environment);
|
|
EMIT_SIZEOF(GLOBAL_VARIABLE_CACHE_SIZE, GlobalVariableCache);
|
|
|
|
// Builtin enum values
|
|
outln("\n# Builtin enum values");
|
|
outln("const BUILTIN_MATH_ABS = {}", static_cast<u8>(Bytecode::Builtin::MathAbs));
|
|
outln("const BUILTIN_MATH_FLOOR = {}", static_cast<u8>(Bytecode::Builtin::MathFloor));
|
|
outln("const BUILTIN_MATH_CEIL = {}", static_cast<u8>(Bytecode::Builtin::MathCeil));
|
|
outln("const BUILTIN_MATH_ROUND = {}", static_cast<u8>(Bytecode::Builtin::MathRound));
|
|
outln("const BUILTIN_MATH_SQRT = {}", static_cast<u8>(Bytecode::Builtin::MathSqrt));
|
|
outln("const BUILTIN_MATH_EXP = {}", static_cast<u8>(Bytecode::Builtin::MathExp));
|
|
outln("const BUILTIN_STRING_FROM_CHAR_CODE = {}", static_cast<u8>(Bytecode::Builtin::StringFromCharCode));
|
|
outln("const BUILTIN_STRING_PROTOTYPE_CHAR_CODE_AT = {}", static_cast<u8>(Bytecode::Builtin::StringPrototypeCharCodeAt));
|
|
outln("const BUILTIN_STRING_PROTOTYPE_CHAR_AT = {}", static_cast<u8>(Bytecode::Builtin::StringPrototypeCharAt));
|
|
|
|
// FunctionObject layout
|
|
outln("\n# FunctionObject layout");
|
|
EMIT_OFFSET(FUNCTION_OBJECT_BUILTIN, FunctionObject, m_builtin);
|
|
{
|
|
// Optional<Builtin> has a value byte and a has_value byte.
|
|
auto base = offsetof(FunctionObject, m_builtin);
|
|
// Optional<Builtin> stores value at offset 0, has_value bool at offset 1.
|
|
// Verify this assumption at compile time:
|
|
Optional<Bytecode::Builtin> opt_test { Bytecode::Builtin::MathFloor };
|
|
auto const* raw = reinterpret_cast<u8 const*>(&opt_test);
|
|
VERIFY(raw[0] == static_cast<u8>(Bytecode::Builtin::MathFloor));
|
|
VERIFY(raw[1] == 1); // has_value
|
|
outln("const FUNCTION_OBJECT_BUILTIN_VALUE = {}", base);
|
|
outln("const FUNCTION_OBJECT_BUILTIN_HAS_VALUE = {}", base + 1);
|
|
}
|
|
|
|
// RawNativeFunction layout
|
|
outln("\n# RawNativeFunction layout");
|
|
EMIT_OFFSET(RAW_NATIVE_FUNCTION_NATIVE_FUNCTION, RawNativeFunction, m_native_function);
|
|
|
|
// ECMAScriptFunctionObject layout
|
|
outln("\n# ECMAScriptFunctionObject layout");
|
|
EMIT_OFFSET(ECMASCRIPT_FUNCTION_OBJECT_SHARED_DATA, ECMAScriptFunctionObject, m_shared_data);
|
|
EMIT_OFFSET(ECMASCRIPT_FUNCTION_OBJECT_ENVIRONMENT, ECMAScriptFunctionObject, m_environment);
|
|
EMIT_OFFSET(ECMASCRIPT_FUNCTION_OBJECT_PRIVATE_ENVIRONMENT, ECMAScriptFunctionObject, m_private_environment);
|
|
EMIT_OFFSET(ECMASCRIPT_FUNCTION_OBJECT_SCRIPT_OR_MODULE, ECMAScriptFunctionObject, m_script_or_module);
|
|
|
|
// SharedFunctionInstanceData layout
|
|
outln("\n# SharedFunctionInstanceData layout");
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_EXECUTABLE, SharedFunctionInstanceData, m_executable);
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_ASM_CALL_METADATA, SharedFunctionInstanceData, m_asm_call_metadata);
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_FORMAL_PARAMETER_COUNT, SharedFunctionInstanceData, m_formal_parameter_count);
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_STRICT, SharedFunctionInstanceData, m_strict);
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_FUNCTION_ENVIRONMENT_NEEDED, SharedFunctionInstanceData, m_function_environment_needed);
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_USES_THIS, SharedFunctionInstanceData, m_uses_this);
|
|
EMIT_OFFSET(SHARED_FUNCTION_INSTANCE_DATA_CAN_INLINE_CALL, SharedFunctionInstanceData, m_can_inline_call);
|
|
outln("const SHARED_FUNCTION_INSTANCE_DATA_ASM_CALL_METADATA_CAN_INLINE_CALL = {}", SharedFunctionInstanceData::asm_call_metadata_can_inline_call);
|
|
outln("const SHARED_FUNCTION_INSTANCE_DATA_ASM_CALL_METADATA_FUNCTION_ENVIRONMENT_NEEDED = {}", SharedFunctionInstanceData::asm_call_metadata_function_environment_needed);
|
|
outln("const SHARED_FUNCTION_INSTANCE_DATA_ASM_CALL_METADATA_USES_THIS = {}", SharedFunctionInstanceData::asm_call_metadata_uses_this);
|
|
outln("const SHARED_FUNCTION_INSTANCE_DATA_ASM_CALL_METADATA_STRICT = {}", SharedFunctionInstanceData::asm_call_metadata_strict);
|
|
|
|
// GlobalEnvironment layout
|
|
outln("\n# GlobalEnvironment layout");
|
|
EMIT_OFFSET(GLOBAL_ENVIRONMENT_GLOBAL_THIS_VALUE, GlobalEnvironment, m_global_this_value);
|
|
|
|
// PrimitiveString layout
|
|
outln("\n# PrimitiveString layout");
|
|
EMIT_OFFSET(PRIMITIVE_STRING_DEFERRED_KIND, PrimitiveStringLayoutAccessor, m_deferred_kind);
|
|
EMIT_OFFSET(PRIMITIVE_STRING_UTF16_STRING, PrimitiveStringLayoutAccessor, m_utf16_string);
|
|
outln("const PRIMITIVE_STRING_DEFERRED_KIND_NONE = {}", static_cast<u8>(PrimitiveStringLayoutAccessor::DeferredKind::None));
|
|
|
|
// Utf16String / ShortString layout
|
|
outln("\n# Utf16String layout");
|
|
outln("const UTF16_SHORT_STRING_FLAG = {}", AK::Detail::StringBase::SHORT_STRING_FLAG);
|
|
outln("const UTF16_SHORT_STRING_BYTE_COUNT_SHIFT_COUNT = {}", AK::Detail::StringBase::SHORT_STRING_BYTE_COUNT_SHIFT_COUNT);
|
|
EMIT_OFFSET(UTF16_SHORT_STRING_BYTE_COUNT_AND_FLAG, AK::Detail::ShortString, byte_count_and_short_string_flag);
|
|
EMIT_OFFSET(UTF16_SHORT_STRING_STORAGE, AK::Detail::ShortString, storage);
|
|
outln("const PRIMITIVE_STRING_UTF16_SHORT_STRING_BYTE_COUNT_AND_FLAG = {}", offsetof(PrimitiveStringLayoutAccessor, m_utf16_string) + offsetof(AK::Detail::ShortString, byte_count_and_short_string_flag));
|
|
outln("const PRIMITIVE_STRING_UTF16_SHORT_STRING_STORAGE = {}", offsetof(PrimitiveStringLayoutAccessor, m_utf16_string) + offsetof(AK::Detail::ShortString, storage));
|
|
|
|
// Utf16StringData layout
|
|
outln("\n# Utf16StringData layout");
|
|
EMIT_OFFSET(UTF16_STRING_DATA_LENGTH_IN_CODE_UNITS, AK::Detail::Utf16StringData, m_length_in_code_units);
|
|
outln("const UTF16_STRING_DATA_STRING_STORAGE = {}", AK::Detail::Utf16StringData::offset_of_string_storage());
|
|
|
|
// Environment layout
|
|
outln("\n# Environment layout");
|
|
EMIT_OFFSET(ENVIRONMENT_SCREWED_BY_EVAL, Environment, m_permanently_screwed_by_eval);
|
|
EMIT_OFFSET(ENVIRONMENT_OUTER, Environment, m_outer_environment);
|
|
|
|
// DeclarativeEnvironment / Binding layout
|
|
outln("\n# DeclarativeEnvironment / Binding layout");
|
|
EMIT_OFFSET(DECLARATIVE_ENVIRONMENT_BINDINGS, DeclarativeEnvironment, m_bindings);
|
|
outln("const BINDING_VALUE = {}", offsetof(DeclarativeEnvironment::Binding, value));
|
|
outln("const BINDING_STRICT = {}", offsetof(DeclarativeEnvironment::Binding, strict));
|
|
outln("const BINDING_MUTABLE = {}", offsetof(DeclarativeEnvironment::Binding, mutable_));
|
|
outln("const BINDING_INITIALIZED = {}", offsetof(DeclarativeEnvironment::Binding, initialized));
|
|
outln("const SIZEOF_BINDING = {}", sizeof(DeclarativeEnvironment::Binding));
|
|
|
|
// Vector<Binding> layout: m_size(0), m_capacity(8), m_metadata.outline_buffer(16)
|
|
outln("const BINDINGS_DATA_PTR = {}", offsetof(DeclarativeEnvironment, m_bindings) + sizeof(size_t) * 2);
|
|
|
|
// EnvironmentCoordinate layout
|
|
outln("\n# EnvironmentCoordinate layout");
|
|
outln("const ENVIRONMENT_COORDINATE_HOPS = {}", offsetof(EnvironmentCoordinate, hops));
|
|
outln("const ENVIRONMENT_COORDINATE_INDEX = {}", offsetof(EnvironmentCoordinate, index));
|
|
outln("const ENVIRONMENT_COORDINATE_INVALID = 0x{:X}", EnvironmentCoordinate::invalid_marker);
|
|
|
|
// TypedArrayBase layout
|
|
outln("\n# TypedArrayBase layout");
|
|
EMIT_OFFSET(TYPED_ARRAY_ELEMENT_SIZE, TypedArrayBase, m_element_size);
|
|
EMIT_OFFSET(TYPED_ARRAY_ARRAY_LENGTH, TypedArrayBase, m_array_length);
|
|
EMIT_OFFSET(TYPED_ARRAY_BYTE_OFFSET, TypedArrayBase, m_byte_offset);
|
|
EMIT_OFFSET(TYPED_ARRAY_KIND, TypedArrayBase, m_kind);
|
|
EMIT_OFFSET(TYPED_ARRAY_CACHED_DATA_PTR, TypedArrayBase, m_data);
|
|
|
|
// ByteLength (Variant<Auto, Detached, u32>) layout
|
|
outln("\n# ByteLength layout");
|
|
{
|
|
// For Variant<Auto, Detached, u32>: u32 index 2 means it holds a u32
|
|
outln("const BYTE_LENGTH_U32_INDEX = 2");
|
|
EMIT_SIZEOF(BYTE_LENGTH_SIZE, ByteLength);
|
|
// Composite: array_length value (u32) and index byte within TypedArrayBase
|
|
auto ta_al = offsetof(TypedArrayBase, m_array_length);
|
|
// Variant<Auto, Detached, u32> stores m_data[4] then m_index (u8)
|
|
outln("const TYPED_ARRAY_ARRAY_LENGTH_VALUE = {}", ta_al); // u32 data at start
|
|
outln("const TYPED_ARRAY_ARRAY_LENGTH_INDEX = {}", ta_al + 4); // index byte after 4 bytes of data
|
|
}
|
|
|
|
// TypedArrayBase::Kind enum values
|
|
outln("\n# TypedArrayBase::Kind values");
|
|
outln("const TYPED_ARRAY_KIND_UINT8 = {}", static_cast<u8>(TypedArrayBase::Kind::Uint8Array));
|
|
outln("const TYPED_ARRAY_KIND_UINT8_CLAMPED = {}", static_cast<u8>(TypedArrayBase::Kind::Uint8ClampedArray));
|
|
outln("const TYPED_ARRAY_KIND_UINT16 = {}", static_cast<u8>(TypedArrayBase::Kind::Uint16Array));
|
|
outln("const TYPED_ARRAY_KIND_UINT32 = {}", static_cast<u8>(TypedArrayBase::Kind::Uint32Array));
|
|
outln("const TYPED_ARRAY_KIND_INT8 = {}", static_cast<u8>(TypedArrayBase::Kind::Int8Array));
|
|
outln("const TYPED_ARRAY_KIND_INT16 = {}", static_cast<u8>(TypedArrayBase::Kind::Int16Array));
|
|
outln("const TYPED_ARRAY_KIND_INT32 = {}", static_cast<u8>(TypedArrayBase::Kind::Int32Array));
|
|
outln("const TYPED_ARRAY_KIND_FLOAT32 = {}", static_cast<u8>(TypedArrayBase::Kind::Float32Array));
|
|
outln("const TYPED_ARRAY_KIND_FLOAT64 = {}", static_cast<u8>(TypedArrayBase::Kind::Float64Array));
|
|
|
|
// Value tags
|
|
outln("\n# Value tags");
|
|
outln("const OBJECT_TAG = 0x{:X}", static_cast<u64>(OBJECT_TAG));
|
|
outln("const STRING_TAG = 0x{:X}", static_cast<u64>(STRING_TAG));
|
|
outln("const SYMBOL_TAG = 0x{:X}", static_cast<u64>(SYMBOL_TAG));
|
|
outln("const BIGINT_TAG = 0x{:X}", static_cast<u64>(BIGINT_TAG));
|
|
outln("const ACCESSOR_TAG = 0x{:X}", static_cast<u64>(ACCESSOR_TAG));
|
|
outln("const INT32_TAG = 0x{:X}", static_cast<u64>(INT32_TAG));
|
|
outln("const BOOLEAN_TAG = 0x{:X}", static_cast<u64>(BOOLEAN_TAG));
|
|
outln("const UNDEFINED_TAG = 0x{:X}", static_cast<u64>(UNDEFINED_TAG));
|
|
outln("const NULL_TAG = 0x{:X}", static_cast<u64>(NULL_TAG));
|
|
|
|
// Shifted value constants
|
|
outln("\n# Shifted value constants");
|
|
outln("const OBJECT_TAG_SHIFTED = 0x{:X}", static_cast<u64>(OBJECT_TAG << GC::TAG_SHIFT));
|
|
outln("const EMPTY_VALUE = 0x{:X}", static_cast<u64>(EMPTY_TAG << GC::TAG_SHIFT));
|
|
outln("const INT32_TAG_SHIFTED = 0x{:X}", static_cast<u64>(INT32_TAG << GC::TAG_SHIFT));
|
|
outln("const BOOLEAN_TRUE = 0x{:X}", static_cast<u64>((BOOLEAN_TAG << GC::TAG_SHIFT) | 1));
|
|
outln("const BOOLEAN_FALSE = 0x{:X}", static_cast<u64>(BOOLEAN_TAG << GC::TAG_SHIFT));
|
|
outln("const UNDEFINED_SHIFTED = 0x{:X}", static_cast<u64>(UNDEFINED_TAG << GC::TAG_SHIFT));
|
|
outln("const EMPTY_TAG_SHIFTED = 0x{:X}", static_cast<u64>(EMPTY_TAG << GC::TAG_SHIFT));
|
|
outln("const NAN_BASE_TAG = 0x{:X}", static_cast<u64>(GC::BASE_TAG));
|
|
outln("const CANON_NAN_BITS = 0x{:X}", static_cast<u64>(GC::CANON_NAN_BITS));
|
|
outln("const DOUBLE_ONE = 0x{:X}", bit_cast<u64>(1.0));
|
|
outln("const NEGATIVE_ZERO = 0x{:X}", static_cast<u64>(NEGATIVE_ZERO_BITS));
|
|
outln("const CELL_TAG_SHIFTED = 0x{:X}", static_cast<u64>(GC::SHIFTED_IS_CELL_PATTERN));
|
|
|
|
outln("const ACCUMULATOR_REG_OFFSET = {}", static_cast<size_t>(Register::accumulator().index()) * sizeof(Value));
|
|
outln("const EXCEPTION_REG_OFFSET = {}", static_cast<size_t>(Register::exception().index()) * sizeof(Value));
|
|
outln("const THIS_VALUE_REG_OFFSET = {}", static_cast<size_t>(Register::this_value().index()) * sizeof(Value));
|
|
outln("const RETURN_VALUE_REG_OFFSET = {}", static_cast<size_t>(Register::return_value().index()) * sizeof(Value));
|
|
outln("const SAVED_LEXICAL_ENVIRONMENT_REG_OFFSET = {}", static_cast<size_t>(Register::saved_lexical_environment().index()) * sizeof(Value));
|
|
outln("const RESERVED_REGISTERS_SIZE = {}", static_cast<size_t>(Register::reserved_register_count) * sizeof(Value));
|
|
|
|
return 0;
|
|
}
|