1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:47:34 +00:00

LibJS: Automatically & lazily coerce PropertyNames into numbers

This commit expands on 5eef07d232 by
automatically trying to coerce Type::String PropertyNames into numbers
when a caller checks if the PropertyName is_number/is_string.
This has several benefits:
 - We no longer have to duplicate the number coercion code to every
   function that accepts a PropertyNumber. (Or more likely, forget to.)
 - This keeps the lazy nature of only doing the coercion when and if
   there is a semantic difference to the different PropertyName types,
   which means this shouldnt cause any performance drop.
 - Since this coercion changes the state of the PropertyName itself the
   result is essentially cached and can speed up any repeat uses of the
   same PropertyName instance.
This commit is contained in:
Idan Horowitz 2021-06-16 20:51:07 +03:00 committed by Linus Groh
parent 623eadb44e
commit b9d9187feb
2 changed files with 31 additions and 49 deletions

View file

@ -196,11 +196,6 @@ bool Object::set_integrity_level(IntegrityLevel level)
case IntegrityLevel::Sealed: case IntegrityLevel::Sealed:
for (auto& key : keys) { for (auto& key : keys) {
auto property_name = PropertyName::from_value(global_object(), key); auto property_name = PropertyName::from_value(global_object(), key);
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
property_name = property_index;
}
update_property(property_name, ~Attribute::Configurable); update_property(property_name, ~Attribute::Configurable);
if (vm.exception()) if (vm.exception())
return {}; return {};
@ -209,11 +204,6 @@ bool Object::set_integrity_level(IntegrityLevel level)
case IntegrityLevel::Frozen: case IntegrityLevel::Frozen:
for (auto& key : keys) { for (auto& key : keys) {
auto property_name = PropertyName::from_value(global_object(), key); auto property_name = PropertyName::from_value(global_object(), key);
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
property_name = property_index;
}
auto property_descriptor = get_own_property_descriptor(property_name); auto property_descriptor = get_own_property_descriptor(property_name);
if (!property_descriptor.has_value()) if (!property_descriptor.has_value())
continue; continue;
@ -395,11 +385,6 @@ Optional<PropertyDescriptor> Object::get_own_property_descriptor(const PropertyN
value = existing_value.value().value; value = existing_value.value().value;
attributes = existing_value.value().attributes; attributes = existing_value.value().attributes;
} else { } else {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return get_own_property_descriptor(property_index);
}
auto metadata = shape().lookup(property_name.to_string_or_symbol()); auto metadata = shape().lookup(property_name.to_string_or_symbol());
if (!metadata.has_value()) if (!metadata.has_value())
return {}; return {};
@ -545,11 +530,6 @@ bool Object::define_property(const PropertyName& property_name, Value value, Pro
if (property_name.is_number()) if (property_name.is_number())
return put_own_property_by_index(property_name.as_number(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions); return put_own_property_by_index(property_name.as_number(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return put_own_property_by_index(property_index, value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
}
return put_own_property(property_name.to_string_or_symbol(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions); return put_own_property(property_name.to_string_or_symbol(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
} }
@ -775,12 +755,6 @@ bool Object::delete_property(const PropertyName& property_name)
if (property_name.is_number()) if (property_name.is_number())
return m_indexed_properties.remove(property_name.as_number()); return m_indexed_properties.remove(property_name.as_number());
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return m_indexed_properties.remove(property_index);
}
auto metadata = shape().lookup(property_name.to_string_or_symbol()); auto metadata = shape().lookup(property_name.to_string_or_symbol());
if (!metadata.has_value()) if (!metadata.has_value())
return true; return true;
@ -836,13 +810,6 @@ Value Object::get(const PropertyName& property_name, Value receiver, bool withou
if (property_name.is_number()) if (property_name.is_number())
return get_by_index(property_name.as_number(), without_side_effects); return get_by_index(property_name.as_number(), without_side_effects);
if (property_name.is_string() && property_name.string_may_be_number()) {
auto& property_string = property_name.as_string();
i32 property_index = property_string.to_int().value_or(-1);
if (property_index >= 0)
return get_by_index(property_index, without_side_effects);
}
if (receiver.is_empty()) if (receiver.is_empty())
receiver = Value(this); receiver = Value(this);
@ -904,13 +871,6 @@ bool Object::put(const PropertyName& property_name, Value value, Value receiver)
VERIFY(!value.is_empty()); VERIFY(!value.is_empty());
if (property_name.is_string() && property_name.string_may_be_number()) {
auto& property_string = property_name.as_string();
i32 property_index = property_string.to_int().value_or(-1);
if (property_index >= 0)
return put_by_index(property_index, value);
}
auto string_or_symbol = property_name.to_string_or_symbol(); auto string_or_symbol = property_name.to_string_or_symbol();
if (receiver.is_empty()) if (receiver.is_empty())
@ -1045,12 +1005,6 @@ bool Object::has_own_property(const PropertyName& property_name) const
if (property_name.is_number()) if (property_name.is_number())
return has_indexed_property(property_name.as_number()); return has_indexed_property(property_name.as_number());
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return has_indexed_property(property_index);
}
return shape().lookup(property_name.to_string_or_symbol()).has_value(); return shape().lookup(property_name.to_string_or_symbol()).has_value();
} }

View file

@ -88,10 +88,38 @@ public:
} }
bool is_valid() const { return m_type != Type::Invalid; } bool is_valid() const { return m_type != Type::Invalid; }
bool is_number() const { return m_type == Type::Number; } bool is_number() const
bool is_string() const { return m_type == Type::String; } {
if (m_type == Type::Number)
return true;
if (m_type != Type::String || !m_string_may_be_number)
return false;
return const_cast<PropertyName*>(this)->try_coerce_into_number();
}
bool is_string() const
{
if (m_type != Type::String)
return false;
if (!m_string_may_be_number)
return true;
return !const_cast<PropertyName*>(this)->try_coerce_into_number();
}
bool is_symbol() const { return m_type == Type::Symbol; } bool is_symbol() const { return m_type == Type::Symbol; }
bool string_may_be_number() const { return m_string_may_be_number; }
bool try_coerce_into_number()
{
VERIFY(m_string_may_be_number);
i32 property_index = m_string.to_int().value_or(-1);
if (property_index < 0) {
m_string_may_be_number = false;
return false;
}
m_type = Type::Number;
m_number = property_index;
return true;
}
u32 as_number() const u32 as_number() const
{ {