mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 03:58:12 +00:00
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.
This commit is contained in:
parent
5ad5322f6a
commit
79958f4520
4 changed files with 89 additions and 15 deletions
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue