Browse Source

LibJS: Prevent object shape transitions during runtime object buildup

While initialization common runtime objects like functions, prototypes,
etc, we don't really care about tracking transitions for each and every
property added to them.

This patch puts objects into a "disable transitions" mode while we call
initialize() on them. After that, adding more properties will cause new
transitions to be generated and added to the chain.

This gives a ~10% speed-up on test-js. :^)
Andreas Kling 4 years ago
parent
commit
69bae3fd9a

+ 6 - 0
Libraries/LibJS/Heap/Heap.h

@@ -35,6 +35,7 @@
 #include <LibJS/Forward.h>
 #include <LibJS/Forward.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibJS/Runtime/Cell.h>
 #include <LibJS/Runtime/Cell.h>
+#include <LibJS/Runtime/Object.h>
 
 
 namespace JS {
 namespace JS {
 
 
@@ -60,7 +61,12 @@ public:
         auto* memory = allocate_cell(sizeof(T));
         auto* memory = allocate_cell(sizeof(T));
         new (memory) T(forward<Args>(args)...);
         new (memory) T(forward<Args>(args)...);
         auto* cell = static_cast<T*>(memory);
         auto* cell = static_cast<T*>(memory);
+        constexpr bool is_object = IsBaseOf<Object, T>::value;
+        if constexpr (is_object)
+            static_cast<Object*>(cell)->disable_transitions();
         cell->initialize(global_object);
         cell->initialize(global_object);
+        if constexpr (is_object)
+            static_cast<Object*>(cell)->enable_transitions();
         return cell;
         return cell;
     }
     }
 
 

+ 4 - 1
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()) {
         if (m_shape->is_unique()) {
             m_shape->add_property_to_unique_shape(property_name, attributes);
             m_shape->add_property_to_unique_shape(property_name, attributes);
             m_storage.resize(m_shape->property_count());
             m_storage.resize(m_shape->property_count());
-        } else {
+        } else if (m_transitions_enabled) {
             set_shape(*m_shape->create_put_transition(property_name, attributes));
             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);
         metadata = shape().lookup(property_name);
         ASSERT(metadata.has_value());
         ASSERT(metadata.has_value());

+ 4 - 0
Libraries/LibJS/Runtime/Object.h

@@ -151,6 +151,9 @@ public:
 
 
     void ensure_shape_is_unique();
     void ensure_shape_is_unique();
 
 
+    void enable_transitions() { m_transitions_enabled = true; }
+    void disable_transitions() { m_transitions_enabled = false; }
+
 protected:
 protected:
     enum class GlobalObjectTag { Tag };
     enum class GlobalObjectTag { Tag };
     enum class ConstructWithoutPrototypeTag { Tag };
     enum class ConstructWithoutPrototypeTag { Tag };
@@ -169,6 +172,7 @@ private:
     void set_shape(Shape&);
     void set_shape(Shape&);
 
 
     bool m_is_extensible { true };
     bool m_is_extensible { true };
+    bool m_transitions_enabled { true };
     Shape* m_shape { nullptr };
     Shape* m_shape { nullptr };
     Vector<Value> m_storage;
     Vector<Value> m_storage;
     IndexedProperties m_indexed_properties;
     IndexedProperties m_indexed_properties;

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

+ 2 - 0
Libraries/LibJS/Runtime/Shape.h

@@ -70,6 +70,8 @@ public:
     Shape* create_configure_transition(const StringOrSymbol&, PropertyAttributes attributes);
     Shape* create_configure_transition(const StringOrSymbol&, PropertyAttributes attributes);
     Shape* create_prototype_transition(Object* new_prototype);
     Shape* create_prototype_transition(Object* new_prototype);
 
 
+    void add_property_without_transition(const StringOrSymbol&, PropertyAttributes);
+
     bool is_unique() const { return m_unique; }
     bool is_unique() const { return m_unique; }
     Shape* create_unique_clone() const;
     Shape* create_unique_clone() const;