LibJS: Replace Vector<Value> with Value* for named property storage

Replace the 24-byte Vector<Value> m_storage with an 8-byte raw
Value* m_named_properties pointer, backed by a malloc'd allocation
with an inline capacity header.

Memory layout of the allocation:
  [u32 capacity] [u32 padding] [Value 0] [Value 1] ...
  m_named_properties points to Value 0.

This shrinks JS::Object from 64 to 48 bytes (on non-Windows
platforms) and removes one level of indirection for property access
in the asm interpreter, since the data pointer is now stored directly
on the object rather than inside a Vector's internal metadata.

Growth policy: max(4, max(needed, old_capacity * 2)).
This commit is contained in:
Andreas Kling
2026-03-17 00:50:31 -05:00
committed by Andreas Kling
parent 15af5fb420
commit f574ef528d
Notes: github-actions[bot] 2026-03-18 03:30:08 +00:00
4 changed files with 89 additions and 26 deletions

View File

@@ -1460,7 +1460,7 @@ handler GetById
branch_ne t0, t2, .try_cache
# IC hit! Load property value via get_direct (own property)
load32 t0, [t5, PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET]
load64 t5, [t3, OBJECT_STORAGE_DATA]
load64 t5, [t3, OBJECT_NAMED_PROPERTIES]
load64 t0, [t5, t0, 8]
# Check value is not an accessor
extract_tag t2, t0
@@ -1480,7 +1480,7 @@ handler GetById
branch_ne t1, t2, .try_cache
# IC hit! Load property value via get_direct (from prototype)
load32 t1, [t5, PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET]
load64 t2, [t0, OBJECT_STORAGE_DATA]
load64 t2, [t0, OBJECT_NAMED_PROPERTIES]
load64 t0, [t2, t1, 8]
# Check value is not an accessor
extract_tag t2, t0
@@ -1521,7 +1521,7 @@ handler PutById
branch_ne t0, t2, .try_cache
# Check current value at property_offset is not an accessor
load32 t0, [t5, PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET]
load64 t5, [t3, OBJECT_STORAGE_DATA]
load64 t5, [t3, OBJECT_NAMED_PROPERTIES]
load64 t2, [t5, t0, 8]
extract_tag t4, t2
branch_eq t4, ACCESSOR_TAG, .try_cache
@@ -1715,7 +1715,7 @@ handler GetLength
branch_ne t0, t2, .slow
# IC hit
load32 t0, [t5, PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET]
load64 t5, [t3, OBJECT_STORAGE_DATA]
load64 t5, [t3, OBJECT_NAMED_PROPERTIES]
load64 t0, [t5, t0, 8]
extract_tag t2, t0
branch_eq t2, ACCESSOR_TAG, .slow
@@ -1772,7 +1772,7 @@ handler GetGlobal
branch_ne t0, t5, .try_env_binding
# IC hit! Load property value via get_direct
load32 t0, [t3, PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET]
load64 t5, [t2, OBJECT_STORAGE_DATA]
load64 t5, [t2, OBJECT_NAMED_PROPERTIES]
load64 t0, [t5, t0, 8]
# Check not accessor
extract_tag t5, t0
@@ -1830,7 +1830,7 @@ handler SetGlobal
branch_ne t0, t5, .try_env_binding
# IC hit! Load current value to check it's not an accessor
load32 t1, [t3, PROPERTY_LOOKUP_CACHE_ENTRY0_PROPERTY_OFFSET]
load64 t5, [t2, OBJECT_STORAGE_DATA]
load64 t5, [t2, OBJECT_NAMED_PROPERTIES]
load64 t4, [t5, t1, 8]
extract_tag t4, t4
branch_eq t4, ACCESSOR_TAG, .slow

View File

@@ -37,7 +37,7 @@ int main()
// Object layout
outln("# Object layout");
EMIT_OFFSET(OBJECT_SHAPE, Object, m_shape);
EMIT_OFFSET(OBJECT_STORAGE, Object, m_storage);
EMIT_OFFSET(OBJECT_NAMED_PROPERTIES, Object, m_named_properties);
EMIT_OFFSET(OBJECT_INDEXED_PROPERTIES, Object, m_indexed_properties);
EMIT_SIZEOF(OBJECT_SIZE, Object);
@@ -110,7 +110,7 @@ int main()
outln("\n# SimpleIndexedPropertyStorage layout");
EMIT_OFFSET(SIMPLE_INDEXED_PROPERTY_STORAGE_PACKED_ELEMENTS, SimpleIndexedPropertyStorage, m_packed_elements);
// Vector<Value> layout (used for m_packed_elements and m_storage)
// Vector<Value> layout (used for m_packed_elements and bytecode)
outln("\n# Vector<Value> layout");
{
Vector<Value> v;
@@ -120,9 +120,6 @@ int main()
outln("const VECTOR_DATA = {}", vec_data);
outln("const VECTOR_SIZE = {}", vec_size);
// Composite offsets for Object.m_storage data pointer
outln("const OBJECT_STORAGE_DATA = {}", offsetof(Object, m_storage) + vec_data);
outln("const OBJECT_STORAGE_SIZE = {}", offsetof(Object, m_storage) + vec_size);
// Composite offsets for SimpleIndexedPropertyStorage.m_packed_elements data pointer
outln("const SIMPLE_INDEXED_PROPERTY_STORAGE_PACKED_DATA = {}", offsetof(SimpleIndexedPropertyStorage, m_packed_elements) + vec_data);
// Composite offset for Executable.bytecode data pointer