diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2020-06-03 09:40:17 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-06 22:13:01 +0200 |
commit | 79958f45204fc386ecc09a68b2ee46f785c4bca4 (patch) | |
tree | 8ef2c1d279ddafc01c366dc3fbd05ff741cc1505 /Libraries | |
parent | 5ad5322f6a1f9119e676ea74499ec6d19b085047 (diff) | |
download | serenity-79958f45204fc386ecc09a68b2ee46f785c4bca4.zip |
LibJS: Add PropertyDescriptor object
This new struct is now returned from get_own_property_descriptor. To
preserve the old functionality of returning an object, there is now a
get_own_property_descriptor_object method, for use in
{Object,Reflect}.getOwnPropertyDescriptor().
This change will be useful for the implementation of Proxies, which do a
lot of descriptor checks. We want to avoid as many object gets and puts
as possible.
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibJS/Runtime/Object.cpp | 84 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Object.h | 16 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ObjectConstructor.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ReflectObject.cpp | 2 |
4 files changed, 89 insertions, 15 deletions
diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 2b3995f98a..9adad035af 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -40,6 +40,46 @@ namespace JS { +PropertyDescriptor PropertyDescriptor::from_object(Interpreter& interpreter, const Object& object) +{ + PropertyAttributes attributes; + if (object.has_property("configurable")) { + if (interpreter.exception()) + return {}; + attributes.set_has_configurable(); + if (object.get("configurable").value_or(Value(false)).to_boolean()) + attributes.set_configurable(); + if (interpreter.exception()) + return {}; + } + if (object.has_property("enumerable")) { + if (interpreter.exception()) + return {}; + attributes.set_has_enumerable(); + if (object.get("enumerable").value_or(Value(false)).to_boolean()) + attributes.set_enumerable(); + if (interpreter.exception()) + return {}; + } + if (object.has_property("writable")) { + if (interpreter.exception()) + return {}; + attributes.set_has_writable(); + if (object.get("writable").value_or(Value(false)).to_boolean()) + attributes.set_writable(); + if (interpreter.exception()) + return {}; + } + PropertyDescriptor descriptor { attributes, object.get("value"), nullptr, nullptr }; + auto getter = object.get("get"); + if (getter.is_function()) + descriptor.getter = &getter.as_function(); + auto setter = object.get("set"); + if (setter.is_function()) + descriptor.setter = &setter.as_function(); + return descriptor; +} + Object* Object::create_empty(Interpreter&, GlobalObject& global_object) { return global_object.heap().allocate<Object>(global_object.object_prototype()); @@ -191,7 +231,7 @@ Value Object::get_own_properties(const Object& this_object, GetOwnPropertyMode k return properties_array; } -Value Object::get_own_property_descriptor(PropertyName property_name) const +Optional<PropertyDescriptor> Object::get_own_property_descriptor(PropertyName property_name) const { Value value; PropertyAttributes attributes; @@ -199,40 +239,60 @@ Value Object::get_own_property_descriptor(PropertyName property_name) const if (property_name.is_number()) { auto existing_value = m_indexed_properties.get(nullptr, property_name.as_number(), false); if (!existing_value.has_value()) - return js_undefined(); + return {}; value = existing_value.value().value; attributes = existing_value.value().attributes; attributes = default_attributes; } else { auto metadata = shape().lookup(property_name.as_string()); if (!metadata.has_value()) - return js_undefined(); + return {}; value = m_storage[metadata.value().offset]; if (interpreter().exception()) return {}; attributes = metadata.value().attributes; } - auto* descriptor = Object::create_empty(interpreter(), interpreter().global_object()); - descriptor->define_property("enumerable", Value(attributes.is_enumerable())); - descriptor->define_property("configurable", Value(attributes.is_configurable())); + PropertyDescriptor descriptor { attributes, {}, nullptr, nullptr }; if (value.is_object() && value.as_object().is_native_property()) { auto result = call_native_property_getter(const_cast<Object*>(this), value); - descriptor->define_property("value", result); - descriptor->define_property("writable", Value(attributes.is_writable())); + descriptor.value = result.value_or(js_undefined()); } else if (value.is_accessor()) { auto& pair = value.as_accessor(); if (pair.getter()) - descriptor->define_property("get", pair.getter()); + descriptor.getter = pair.getter(); if (pair.setter()) - descriptor->define_property("set", pair.setter()); + descriptor.setter = pair.setter(); } else { - descriptor->define_property("value", value.value_or(js_undefined())); - descriptor->define_property("writable", Value(attributes.is_writable())); + descriptor.value = value.value_or(js_undefined()); } + return descriptor; } +Value Object::get_own_property_descriptor_object(PropertyName property_name) const +{ + auto descriptor_opt = get_own_property_descriptor(property_name); + if (!descriptor_opt.has_value()) + return js_undefined(); + auto descriptor = descriptor_opt.value(); + + auto* descriptor_object = Object::create_empty(interpreter(), interpreter().global_object()); + descriptor_object->define_property("enumerable", Value(descriptor.attributes.is_enumerable())); + descriptor_object->define_property("configurable", Value(descriptor.attributes.is_configurable())); + if (descriptor.is_data_descriptor()) { + descriptor_object->define_property("value", descriptor.value.value_or(js_undefined())); + descriptor_object->define_property("writable", Value(descriptor.attributes.is_writable())); + } else if (descriptor.is_accessor_descriptor()) { + if (descriptor.getter) { + descriptor_object->define_property("get", Value(descriptor.getter)); + } + if (descriptor.setter) + descriptor_object->define_property("set", Value(descriptor.setter)); + } + return descriptor_object; +} + void Object::set_shape(Shape& new_shape) { m_storage.resize(new_shape.property_count()); diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index f39d816c08..333150ed8d 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -39,6 +39,19 @@ namespace JS { +struct PropertyDescriptor { + PropertyAttributes attributes; + Value value; + Function* getter; + Function* setter; + + static PropertyDescriptor from_object(Interpreter&, const Object&); + + bool is_accessor_descriptor() const { return getter || setter; } + bool is_data_descriptor() const { return !(value.is_empty() && !attributes.has_writable()); } + bool is_generic_descriptor() const { return !is_accessor_descriptor() && !is_data_descriptor(); } +}; + class Object : public Cell { public: static Object* create_empty(Interpreter&, GlobalObject&); @@ -69,7 +82,8 @@ public: Value get_own_property(const Object& this_object, PropertyName) const; Value get_own_properties(const Object& this_object, GetOwnPropertyMode, PropertyAttributes attributes = default_attributes) const; - Value get_own_property_descriptor(PropertyName) const; + Optional<PropertyDescriptor> get_own_property_descriptor(PropertyName) const; + Value get_own_property_descriptor_object(PropertyName) const; bool define_property(const FlyString& property_name, const Object& descriptor, bool throw_exceptions = true); bool define_property(PropertyName, Value value, PropertyAttributes attributes = default_attributes, bool throw_exceptions = true); diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Libraries/LibJS/Runtime/ObjectConstructor.cpp index a4882889b4..244791cacd 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -147,7 +147,7 @@ Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter) auto property_key = interpreter.argument(1).to_string(interpreter); if (interpreter.exception()) return {}; - return object->get_own_property_descriptor(property_key); + return object->get_own_property_descriptor_object(property_key); } Value ObjectConstructor::define_property_(Interpreter& interpreter) diff --git a/Libraries/LibJS/Runtime/ReflectObject.cpp b/Libraries/LibJS/Runtime/ReflectObject.cpp index 2a10fce38e..c81ba0fea2 100644 --- a/Libraries/LibJS/Runtime/ReflectObject.cpp +++ b/Libraries/LibJS/Runtime/ReflectObject.cpp @@ -189,7 +189,7 @@ Value ReflectObject::get_own_property_descriptor(Interpreter& interpreter) auto property_key = interpreter.argument(1).to_string(interpreter); if (interpreter.exception()) return {}; - return target->get_own_property_descriptor(property_key); + return target->get_own_property_descriptor_object(property_key); } Value ReflectObject::get_prototype_of(Interpreter& interpreter) |