1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 04:17:35 +00:00

LibJS: Avoid pointless transitions and metadata lookups in storage_set()

- Replace the misleading abuse of the m_transitions_enabled flag for the
  fast path without lookup with a new m_initialized boolean that's set
  either by Heap::allocate() after calling the Object's initialize(), or
  by the GlobalObject in its special initialize_global_object(). This
  makes it work regardless of the shape's uniqueness.
- When we're adding a new property past the initialization phase,
  there's no need to do a second metadata lookup to retrieve the storage
  value offset - it's known to always be the shape's property count
  minus one. Also, instead of doing manual storage resizing and
  assignment via indexing, just use Vector::append().
- When we didn't add a new property but are overwriting an existing one,
  the property count and therefore storage value offset doesn't change,
  so we don't have to retrieve it either.

As a result, Object::set_shape() is now solely responsible for updating
the m_shape pointer and is not resizing storage anymore, so I moved it
into the header.
This commit is contained in:
Linus Groh 2021-08-28 17:12:14 +01:00
parent d6de0613f5
commit 222e518a53
4 changed files with 40 additions and 29 deletions

View file

@ -943,16 +943,21 @@ void Object::storage_set(PropertyName const& property_name, ValueAndAttributes c
return;
}
// NOTE: We disable transitions during initialize(), this makes building common runtime objects significantly faster.
// Transitions are primarily interesting when scripts add properties to objects.
if (!m_transitions_enabled && !m_shape->is_unique()) {
m_shape->add_property_without_transition(property_name, attributes);
m_storage.resize(m_shape->property_count());
m_storage[m_shape->property_count() - 1] = value;
auto property_name_string_or_symbol = property_name.to_string_or_symbol();
// NOTE: We don't do transitions or check for attribute changes during object initialization,
// which makes building common runtime objects significantly faster. Transitions are primarily
// interesting when scripts add properties to objects.
if (!m_initialized) {
if (m_shape->is_unique())
m_shape->add_property_to_unique_shape(property_name_string_or_symbol, attributes);
else
m_shape->add_property_without_transition(property_name_string_or_symbol, attributes);
m_storage.append(value);
return;
}
auto property_name_string_or_symbol = property_name.to_string_or_symbol();
auto metadata = shape().lookup(property_name_string_or_symbol);
if (!metadata.has_value()) {
@ -962,27 +967,24 @@ void Object::storage_set(PropertyName const& property_name, ValueAndAttributes c
ensure_shape_is_unique();
}
if (m_shape->is_unique()) {
if (m_shape->is_unique())
m_shape->add_property_to_unique_shape(property_name_string_or_symbol, attributes);
m_storage.resize(m_shape->property_count());
} else if (m_transitions_enabled) {
else if (!m_transitions_enabled)
m_shape->add_property_without_transition(property_name_string_or_symbol, attributes);
else
set_shape(*m_shape->create_put_transition(property_name_string_or_symbol, attributes));
} else {
m_shape->add_property_without_transition(property_name, attributes);
m_storage.resize(m_shape->property_count());
}
metadata = shape().lookup(property_name_string_or_symbol);
VERIFY(metadata.has_value());
m_storage.append(value);
return;
}
if (attributes != metadata->attributes) {
if (m_shape->is_unique()) {
if (m_shape->is_unique())
m_shape->reconfigure_property_in_unique_shape(property_name_string_or_symbol, attributes);
} else {
else if (!m_transitions_enabled)
VERIFY_NOT_REACHED(); // We currently don't have a way of doing this, and it's not used anywhere either.
else
set_shape(*m_shape->create_configure_transition(property_name_string_or_symbol, attributes));
}
metadata = shape().lookup(property_name_string_or_symbol);
VERIFY(metadata.has_value());
}
m_storage[metadata->offset] = value;
@ -1005,12 +1007,6 @@ void Object::storage_delete(PropertyName const& property_name)
m_storage.remove(metadata->offset);
}
void Object::set_shape(Shape& new_shape)
{
m_storage.resize(new_shape.property_count());
m_shape = &new_shape;
}
void Object::define_native_accessor(PropertyName const& property_name, Function<Value(VM&, GlobalObject&)> getter, Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attribute)
{
auto& vm = this->vm();