ladybird/Libraries/LibJS/Bytecode/AsmInterpreter/gen_asm_offsets.cpp
Andreas Kling 583fa475fb LibJS: Call RawNativeFunction directly from asm Call
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.
2026-04-15 15:57:48 +02:00

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;
}