diff --git a/Libraries/LibJS/Heap/Heap.h b/Libraries/LibJS/Heap/Heap.h index 9f2697a0f2..ddf6d32c17 100644 --- a/Libraries/LibJS/Heap/Heap.h +++ b/Libraries/LibJS/Heap/Heap.h @@ -35,6 +35,7 @@ #include #include #include +#include namespace JS { @@ -60,7 +61,12 @@ public: auto* memory = allocate_cell(sizeof(T)); new (memory) T(forward(args)...); auto* cell = static_cast(memory); + constexpr bool is_object = IsBaseOf::value; + if constexpr (is_object) + static_cast(cell)->disable_transitions(); cell->initialize(global_object); + if constexpr (is_object) + static_cast(cell)->enable_transitions(); return cell; } diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 6e4ca6b98f..fa54720367 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -486,8 +486,11 @@ bool Object::put_own_property(Object& this_object, const StringOrSymbol& propert if (m_shape->is_unique()) { m_shape->add_property_to_unique_shape(property_name, attributes); m_storage.resize(m_shape->property_count()); - } else { + } else if (m_transitions_enabled) { set_shape(*m_shape->create_put_transition(property_name, attributes)); + } else { + m_shape->add_property_without_transition(property_name, attributes); + m_storage.resize(m_shape->property_count()); } metadata = shape().lookup(property_name); ASSERT(metadata.has_value()); diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index 7f55582258..0885914195 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -151,6 +151,9 @@ public: void ensure_shape_is_unique(); + void enable_transitions() { m_transitions_enabled = true; } + void disable_transitions() { m_transitions_enabled = false; } + protected: enum class GlobalObjectTag { Tag }; enum class ConstructWithoutPrototypeTag { Tag }; @@ -169,6 +172,7 @@ private: void set_shape(Shape&); bool m_is_extensible { true }; + bool m_transitions_enabled { true }; Shape* m_shape { nullptr }; Vector m_storage; IndexedProperties m_indexed_properties; diff --git a/Libraries/LibJS/Runtime/Shape.cpp b/Libraries/LibJS/Runtime/Shape.cpp index 49d0bfc816..d30c701c60 100644 --- a/Libraries/LibJS/Runtime/Shape.cpp +++ b/Libraries/LibJS/Runtime/Shape.cpp @@ -210,4 +210,11 @@ void Shape::remove_property_from_unique_shape(const StringOrSymbol& property_nam } } +void Shape::add_property_without_transition(const StringOrSymbol& property_name, PropertyAttributes attributes) +{ + ensure_property_table(); + if (m_property_table->set(property_name, { m_property_count, attributes }) == AK::HashSetResult::InsertedNewEntry) + ++m_property_count; +} + } diff --git a/Libraries/LibJS/Runtime/Shape.h b/Libraries/LibJS/Runtime/Shape.h index 96717d1434..3c2f402a86 100644 --- a/Libraries/LibJS/Runtime/Shape.h +++ b/Libraries/LibJS/Runtime/Shape.h @@ -70,6 +70,8 @@ public: Shape* create_configure_transition(const StringOrSymbol&, PropertyAttributes attributes); Shape* create_prototype_transition(Object* new_prototype); + void add_property_without_transition(const StringOrSymbol&, PropertyAttributes); + bool is_unique() const { return m_unique; } Shape* create_unique_clone() const;