Store bytecode property lookup caches as tiered handles instead of eagerly allocating four entries for every cache slot. Each slot starts empty, grows to one monomorphic entry after the first cacheable lookup, and promotes to the existing four-entry table when another cache key appears. Global variable caches keep one inline property entry because they usually warm up as global object property accesses. This keeps common global access allocation-free while still avoiding the inherited polymorphic cache cost. Generated asm offsets now point at the lazy property-cache storage and the inline global entry, and asm fast paths bail out for empty property cache slots.
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_DATA, PropertyLookupCache, m_data);
|
|
outln("const PROPERTY_LOOKUP_CACHE_POLYMORPHIC_DATA_TAG = {}", PropertyLookupCache::polymorphic_data_tag);
|
|
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);
|
|
|
|
// 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_GLOBAL_VARIABLE_CACHES, Executable, global_variable_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) + InstructionStream::data_member_offset());
|
|
outln("const EXECUTABLE_PROPERTY_LOOKUP_CACHES_DATA = {}", offsetof(Executable, property_lookup_caches) + vec_data);
|
|
outln("const EXECUTABLE_GLOBAL_VARIABLE_CACHES_DATA = {}", offsetof(Executable, global_variable_caches) + 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_RARE_DATA, DeclarativeEnvironment, m_rare_data);
|
|
EMIT_OFFSET(DECLARATIVE_ENVIRONMENT_RARE_DATA_SERIAL, DeclarativeEnvironment::RareData, m_environment_serial_number);
|
|
|
|
// GlobalVariableCache layout
|
|
outln("\n# GlobalVariableCache layout");
|
|
EMIT_OFFSET(GLOBAL_VARIABLE_CACHE_ENTRY, GlobalVariableCache, entry);
|
|
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);
|
|
outln("const GLOBAL_VARIABLE_CACHE_ENTRY_PROPERTY_OFFSET = {}", offsetof(GlobalVariableCache, entry) + offsetof(PropertyLookupCache::Entry, property_offset));
|
|
outln("const GLOBAL_VARIABLE_CACHE_ENTRY_DICTIONARY_GENERATION = {}", offsetof(GlobalVariableCache, entry) + offsetof(PropertyLookupCache::Entry, shape_dictionary_generation));
|
|
outln("const GLOBAL_VARIABLE_CACHE_ENTRY_SHAPE = {}", offsetof(GlobalVariableCache, entry) + offsetof(PropertyLookupCache::Entry, shape));
|
|
|
|
// 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_NEEDS_ENVIRONMENT_OR_THIS_VALUE_RESOLUTION = {}", SharedFunctionInstanceData::asm_call_metadata_needs_environment_or_this_value_resolution);
|
|
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 storage layout
|
|
outln("\n# DeclarativeEnvironment binding storage layout");
|
|
EMIT_OFFSET(DECLARATIVE_ENVIRONMENT_SHAPE, DeclarativeEnvironment, m_shape);
|
|
EMIT_OFFSET(DECLARATIVE_ENVIRONMENT_BINDING_VALUES, DeclarativeEnvironment, m_binding_values);
|
|
EMIT_OFFSET(DECLARATIVE_ENVIRONMENT_RARE_DATA_BINDING_FLAGS, DeclarativeEnvironment::RareData, m_binding_flags);
|
|
EMIT_OFFSET(ENVIRONMENT_SHAPE_BINDING_FLAGS, EnvironmentShape, m_binding_flags);
|
|
outln("const BINDING_FLAG_MUTABLE = {}", 1 << 1);
|
|
|
|
// Vector<T> layout: m_size(0), m_capacity(8), m_metadata.outline_buffer(16)
|
|
outln("const BINDING_VALUES_DATA_PTR = {}", offsetof(DeclarativeEnvironment, m_binding_values) + sizeof(size_t) * 2);
|
|
outln("const BINDING_FLAGS_DATA_PTR = {}", offsetof(DeclarativeEnvironment::RareData, m_binding_flags) + sizeof(size_t) * 2);
|
|
outln("const ENVIRONMENT_SHAPE_BINDING_FLAGS_DATA_PTR = {}", offsetof(EnvironmentShape, m_binding_flags) + 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;
|
|
}
|