diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index 99076d5773..6b8d18acc1 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -24,6 +24,8 @@ namespace JS { +static HashMap> s_intrinsics; + // 10.1.12 OrdinaryObjectCreate ( proto [ , additionalInternalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinaryobjectcreate Object* Object::create(Realm& realm, Object* prototype) { @@ -67,6 +69,11 @@ Object::Object(Shape& shape) m_storage.resize(shape.property_count()); } +Object::~Object() +{ + s_intrinsics.remove(this); +} + void Object::initialize(Realm&) { } @@ -970,6 +977,23 @@ ThrowCompletionOr Object::set_immutable_prototype(Object* prototype) return false; } +static Optional find_intrinsic_accessor(Object const* object, PropertyKey const& property_key) +{ + if (!property_key.is_string()) + return {}; + + auto intrinsics = s_intrinsics.find(object); + if (intrinsics == s_intrinsics.end()) + return {}; + + auto accessor = intrinsics->value.find(property_key.as_string()); + if (accessor == intrinsics->value.end()) + return {}; + + intrinsics->value.remove(accessor); + return move(accessor->value); +} + Optional Object::storage_get(PropertyKey const& property_key) const { VERIFY(property_key.is_valid()); @@ -987,9 +1011,14 @@ Optional Object::storage_get(PropertyKey const& property_key auto metadata = shape().lookup(property_key.to_string_or_symbol()); if (!metadata.has_value()) return {}; + + if (auto accessor = find_intrinsic_accessor(this, property_key); accessor.has_value()) + const_cast(*this).m_storage[metadata->offset] = (*accessor)(shape().realm()); + value = m_storage[metadata->offset]; attributes = metadata->attributes; } + return ValueAndAttributes { .value = value, .attributes = attributes }; } @@ -1013,6 +1042,11 @@ void Object::storage_set(PropertyKey const& property_key, ValueAndAttributes con return; } + if (property_key.is_string()) { + if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end()) + intrinsics->value.remove(property_key.as_string()); + } + auto property_key_string_or_symbol = property_key.to_string_or_symbol(); auto metadata = shape().lookup(property_key_string_or_symbol); @@ -1050,6 +1084,11 @@ void Object::storage_delete(PropertyKey const& property_key) if (property_key.is_number()) return m_indexed_properties.remove(property_key.as_number()); + if (property_key.is_string()) { + if (auto intrinsics = s_intrinsics.find(this); intrinsics != s_intrinsics.end()) + intrinsics->value.remove(property_key.as_string()); + } + auto metadata = shape().lookup(property_key.to_string_or_symbol()); VERIFY(metadata.has_value()); @@ -1098,6 +1137,16 @@ void Object::define_direct_accessor(PropertyKey const& property_key, FunctionObj } } +void Object::define_intrinsic_accessor(PropertyKey const& property_key, PropertyAttributes attributes, IntrinsicAccessor accessor) +{ + VERIFY(property_key.is_string()); + + storage_set(property_key, { {}, attributes }); + + auto& intrinsics = s_intrinsics.ensure(this); + intrinsics.set(property_key.as_string(), move(accessor)); +} + void Object::ensure_shape_is_unique() { if (shape().is_unique()) diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index 93a29a0256..1f16bb6021 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -47,7 +47,7 @@ public: static Object* create(Realm&, Object* prototype); virtual void initialize(Realm&) override; - virtual ~Object() = default; + virtual ~Object(); enum class PropertyKind { Key, @@ -151,6 +151,9 @@ public: void define_direct_property(PropertyKey const& property_key, Value value, PropertyAttributes attributes) { storage_set(property_key, { value, attributes }); }; void define_direct_accessor(PropertyKey const&, FunctionObject* getter, FunctionObject* setter, PropertyAttributes attributes); + using IntrinsicAccessor = Value (*)(Realm&); + virtual void define_intrinsic_accessor(PropertyKey const&, PropertyAttributes attributes, IntrinsicAccessor accessor); + void define_native_function(Realm&, PropertyKey const&, SafeFunction(VM&)>, i32 length, PropertyAttributes attributes); void define_native_accessor(Realm&, PropertyKey const&, SafeFunction(VM&)> getter, SafeFunction(VM&)> setter, PropertyAttributes attributes);