ladybird/Libraries/LibJS/Runtime/DescriptorArray.h
Andreas Kling e3841a7392 LibJS: Compact Shape property table to a sorted flat array
Replace the lazy per-shape OrderedHashMap cache for non-dictionary
shapes with a GC-allocated descriptor array. Store descriptors in hash
order for lookup while keeping an enum index so callers can still walk
properties in insertion order.

Keep dictionary shapes on the mutable OrderedHashMap path, and migrate
callers that enumerated Shape::property_table() to the new insertion
order iterator. Cap descriptor arrays to their compact u16 index range
and keep larger dictionary shapes on the mutable table path across
prototype transitions and prototype clones.

Add coverage for setting the prototype of a dictionary object with more
than 65536 named properties.
2026-05-14 19:59:40 +02:00

68 lines
1.9 KiB
C++

/*
* Copyright (c) 2026-present, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <AK/NumericLimits.h>
#include <AK/Vector.h>
#include <LibJS/Export.h>
#include <LibJS/Heap/Cell.h>
#include <LibJS/Runtime/PropertyAttributes.h>
#include <LibJS/Runtime/PropertyKey.h>
namespace JS {
struct PropertyMetadata {
u32 offset { 0 };
PropertyAttributes attributes { 0 };
};
class JS_API DescriptorArray final : public Cell {
GC_CELL(DescriptorArray, Cell);
GC_DECLARE_ALLOCATOR(DescriptorArray);
public:
struct Entry {
PropertyKey property_key;
u32 offset { 0 };
u16 attributes { 0 };
u16 enum_index { 0 };
PropertyMetadata metadata() const
{
return { offset, static_cast<u8>(attributes) };
}
};
static constexpr u32 max_descriptor_count = NumericLimits<u16>::max() + 1;
DescriptorArray() = default;
explicit DescriptorArray(DescriptorArray const&, u32 descriptor_count);
virtual ~DescriptorArray() override = default;
[[nodiscard]] u32 size() const { return m_entries.size(); }
[[nodiscard]] Optional<PropertyMetadata> lookup(PropertyKey const&, u32 descriptor_count) const;
void set(PropertyKey const&, PropertyMetadata, u32 enum_index);
void set_attributes(PropertyKey const&, PropertyAttributes, u32 descriptor_count);
void remove(PropertyKey const&, u32 descriptor_count);
void for_each_in_insertion_order(Function<void(PropertyKey const&, PropertyMetadata const&)> const&, u32 descriptor_count) const;
private:
virtual void visit_edges(Visitor&) override;
virtual size_t external_memory_size() const override;
[[nodiscard]] Optional<size_t> find(PropertyKey const&, u32 descriptor_count) const;
[[nodiscard]] size_t find_insertion_index(PropertyKey const&) const;
Vector<Entry> m_entries;
};
static_assert(sizeof(DescriptorArray::Entry) == 16);
}