diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 17a13736e6c..7cd078d4402 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1224,20 +1224,54 @@ inline ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value thi break; } case Op::PropertyKind::KeyValue: { - if (cache && cache->shape == &object->shape()) { - object->put_direct(*cache->property_offset, value); - return {}; + if (cache) { + if (cache->prototype) { + // OPTIMIZATION: If the prototype chain hasn't been mutated in a way that would invalidate the cache, we can use it. + bool can_use_cache = [&]() -> bool { + if (&object->shape() != cache->shape) + return false; + if (!cache->prototype_chain_validity) + return false; + if (!cache->prototype_chain_validity->is_valid()) + return false; + return true; + }(); + if (can_use_cache) { + auto value_in_prototype = cache->prototype->get_direct(cache->property_offset.value()); + if (value_in_prototype.is_accessor()) { + TRY(call(vm, value_in_prototype.as_accessor().setter(), this_value, value)); + return {}; + } + } + } else if (cache->shape == &object->shape()) { + auto value_in_object = object->get_direct(cache->property_offset.value()); + if (value_in_object.is_accessor()) { + TRY(call(vm, value_in_object.as_accessor().setter(), this_value, value)); + } else { + object->put_direct(*cache->property_offset, value); + } + return {}; + } } CacheablePropertyMetadata cacheable_metadata; bool succeeded = TRY(object->internal_set(name, value, this_value, &cacheable_metadata)); - if (succeeded && cache && cacheable_metadata.type == CacheablePropertyMetadata::Type::OwnProperty) { - cache->shape = object->shape(); - cache->property_offset = cacheable_metadata.property_offset.value(); + if (succeeded && cache) { + if (cacheable_metadata.type == CacheablePropertyMetadata::Type::OwnProperty) { + *cache = {}; + cache->shape = object->shape(); + cache->property_offset = cacheable_metadata.property_offset.value(); + } else if (cacheable_metadata.type == CacheablePropertyMetadata::Type::InPrototypeChain) { + *cache = {}; + cache->shape = object->shape(); + cache->property_offset = cacheable_metadata.property_offset.value(); + cache->prototype = *cacheable_metadata.prototype; + cache->prototype_chain_validity = *cacheable_metadata.prototype->shape().prototype_chain_validity(); + } } - if (!succeeded && vm.in_strict_mode()) { + if (!succeeded && vm.in_strict_mode()) [[unlikely]] { if (base.is_object()) return vm.throw_completion(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); return vm.throw_completion(ErrorType::ReferencePrimitiveSetProperty, name, base.typeof_(vm)->utf8_string(), base.to_string_without_side_effects()); @@ -2318,7 +2352,7 @@ ThrowCompletionOr SetGlobal::execute_impl(Bytecode::Interpreter& interpret if (&shape == cache.shape) { auto value = binding_object.get_direct(cache.property_offset.value()); if (value.is_accessor()) - TRY(call(vm, value.as_accessor().setter(), js_undefined(), value)); + TRY(call(vm, value.as_accessor().setter(), &binding_object, src)); else binding_object.put_direct(cache.property_offset.value(), src); return {}; diff --git a/Libraries/LibJS/Runtime/ArgumentsObject.cpp b/Libraries/LibJS/Runtime/ArgumentsObject.cpp index 20bc1cb0db4..e60a124ea5e 100644 --- a/Libraries/LibJS/Runtime/ArgumentsObject.cpp +++ b/Libraries/LibJS/Runtime/ArgumentsObject.cpp @@ -54,7 +54,7 @@ ThrowCompletionOr ArgumentsObject::internal_get(PropertyKey const& proper } // 10.4.4.4 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-set-p-v-receiver -ThrowCompletionOr ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) +ThrowCompletionOr ArgumentsObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) { bool is_mapped = false; diff --git a/Libraries/LibJS/Runtime/ArgumentsObject.h b/Libraries/LibJS/Runtime/ArgumentsObject.h index 675afcd400f..4c7e34df4fd 100644 --- a/Libraries/LibJS/Runtime/ArgumentsObject.h +++ b/Libraries/LibJS/Runtime/ArgumentsObject.h @@ -25,7 +25,7 @@ public: virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&, Optional* precomputed_get_own_property = nullptr) override; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) const override; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; // [[ParameterMap]] diff --git a/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp b/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp index b3f4ebc12d8..7d467c743c6 100644 --- a/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp +++ b/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp @@ -185,7 +185,7 @@ ThrowCompletionOr ModuleNamespaceObject::internal_get(PropertyKey const& } // 10.4.6.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver -ThrowCompletionOr ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value, CacheablePropertyMetadata*) +ThrowCompletionOr ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value, CacheablePropertyMetadata*, PropertyLookupPhase) { // 1. Return false. return false; diff --git a/Libraries/LibJS/Runtime/ModuleNamespaceObject.h b/Libraries/LibJS/Runtime/ModuleNamespaceObject.h index 388e7a07071..81b56852f54 100644 --- a/Libraries/LibJS/Runtime/ModuleNamespaceObject.h +++ b/Libraries/LibJS/Runtime/ModuleNamespaceObject.h @@ -27,7 +27,7 @@ public: virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&, Optional* precomputed_get_own_property = nullptr) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty) const override; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; virtual void initialize(Realm&) override; diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index d523484f2fc..2723a2a8b8c 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -952,7 +952,7 @@ ThrowCompletionOr Object::internal_get(PropertyKey const& property_key, V // 10.1.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-set-p-v-receiver // 10.1.9.1 OrdinarySet ( O, P, V, Receiver ), https://tc39.es/ecma262/#sec-ordinaryset -ThrowCompletionOr Object::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata* cacheable_metadata) +ThrowCompletionOr Object::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) { VERIFY(!value.is_special_empty_value()); VERIFY(!receiver.is_special_empty_value()); @@ -961,11 +961,11 @@ ThrowCompletionOr Object::internal_set(PropertyKey const& property_key, Va auto own_descriptor = TRY(internal_get_own_property(property_key)); // 3. Return ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc). - return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor, cacheable_metadata); + return ordinary_set_with_own_descriptor(property_key, value, receiver, own_descriptor, cacheable_metadata, phase); } // 10.1.9.2 OrdinarySetWithOwnDescriptor ( O, P, V, Receiver, ownDesc ), https://tc39.es/ecma262/#sec-ordinarysetwithowndescriptor -ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional own_descriptor, CacheablePropertyMetadata* cacheable_metadata) +ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey const& property_key, Value value, Value receiver, Optional own_descriptor, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) { VERIFY(!value.is_special_empty_value()); VERIFY(!receiver.is_special_empty_value()); @@ -980,7 +980,7 @@ ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey con // b. If parent is not null, then if (parent) { // i. Return ? parent.[[Set]](P, V, Receiver). - return TRY(parent->internal_set(property_key, value, receiver)); + return TRY(parent->internal_set(property_key, value, receiver, cacheable_metadata, PropertyLookupPhase::PrototypeChain)); } // c. Else, else { @@ -994,6 +994,27 @@ ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey con } } + auto update_inline_cache = [&] { + // Non-standard: If the caller has requested cacheable metadata and the property is an own property, fill it in. + if (!cacheable_metadata || !own_descriptor->property_offset.has_value() || !shape().is_cacheable()) + return; + if (phase == PropertyLookupPhase::OwnProperty) { + *cacheable_metadata = CacheablePropertyMetadata { + .type = CacheablePropertyMetadata::Type::OwnProperty, + .property_offset = own_descriptor->property_offset.value(), + .prototype = nullptr, + }; + } else if (phase == PropertyLookupPhase::PrototypeChain) { + VERIFY(shape().is_prototype_shape()); + VERIFY(shape().prototype_chain_validity()->is_valid()); + *cacheable_metadata = CacheablePropertyMetadata { + .type = CacheablePropertyMetadata::Type::InPrototypeChain, + .property_offset = own_descriptor->property_offset.value(), + .prototype = this, + }; + } + }; + // 2. If IsDataDescriptor(ownDesc) is true, then if (own_descriptor->is_data_descriptor()) { // a. If ownDesc.[[Writable]] is false, return false. @@ -1022,13 +1043,10 @@ ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey con // iii. Let valueDesc be the PropertyDescriptor { [[Value]]: V }. auto value_descriptor = PropertyDescriptor { .value = value }; - if (cacheable_metadata && own_descriptor.has_value() && own_descriptor->property_offset.has_value() && shape().is_cacheable()) { - *cacheable_metadata = CacheablePropertyMetadata { - .type = CacheablePropertyMetadata::Type::OwnProperty, - .property_offset = own_descriptor->property_offset.value(), - .prototype = nullptr, - }; - } + // NOTE: We don't cache non-setter properties in the prototype chain, as that's a weird + // use-case, and doesn't seem like something in need of optimization. + if (phase == PropertyLookupPhase::OwnProperty) + update_inline_cache(); // iv. Return ? Receiver.[[DefineOwnProperty]](P, valueDesc). return TRY(receiver_object.internal_define_own_property(property_key, value_descriptor, &existing_descriptor)); @@ -1053,6 +1071,8 @@ ThrowCompletionOr Object::ordinary_set_with_own_descriptor(PropertyKey con if (!setter) return false; + update_inline_cache(); + // 6. Perform ? Call(setter, Receiver, « V »). (void)TRY(call(vm, *setter, receiver, value)); diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index b6e4c3b276d..61a117588f3 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -145,7 +145,7 @@ public: PrototypeChain, }; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty) const; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata* = nullptr); + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty); virtual ThrowCompletionOr internal_delete(PropertyKey const&); virtual ThrowCompletionOr> internal_own_property_keys() const; @@ -155,7 +155,7 @@ public: // might not hold when property access behaves differently. bool may_interfere_with_indexed_property_access() const { return m_may_interfere_with_indexed_property_access; } - ThrowCompletionOr ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional, CacheablePropertyMetadata* = nullptr); + ThrowCompletionOr ordinary_set_with_own_descriptor(PropertyKey const&, Value, Value, Optional, CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty); // 10.4.7 Immutable Prototype Exotic Objects, https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects diff --git a/Libraries/LibJS/Runtime/ProxyObject.cpp b/Libraries/LibJS/Runtime/ProxyObject.cpp index 75c6c5dad09..5b882904b15 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -535,7 +535,7 @@ ThrowCompletionOr ProxyObject::internal_get(PropertyKey const& property_k } // 10.5.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver -ThrowCompletionOr ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) +ThrowCompletionOr ProxyObject::internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) { LIMIT_PROXY_RECURSION_DEPTH(); diff --git a/Libraries/LibJS/Runtime/ProxyObject.h b/Libraries/LibJS/Runtime/ProxyObject.h index b49105e6cf4..c499d608493 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.h +++ b/Libraries/LibJS/Runtime/ProxyObject.h @@ -39,7 +39,7 @@ public: virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&, Optional* precomputed_get_own_property = nullptr) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) const override; - virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override; + virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; virtual ThrowCompletionOr internal_call(ExecutionContext&, Value this_argument) override; diff --git a/Libraries/LibJS/Runtime/TypedArray.h b/Libraries/LibJS/Runtime/TypedArray.h index ee5d67fb522..9e5d8403bd2 100644 --- a/Libraries/LibJS/Runtime/TypedArray.h +++ b/Libraries/LibJS/Runtime/TypedArray.h @@ -352,7 +352,7 @@ public: } // 10.4.5.6 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver - virtual ThrowCompletionOr internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*) override + virtual ThrowCompletionOr internal_set(PropertyKey const& property_key, Value value, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) override { VERIFY(!value.is_special_empty_value()); VERIFY(!receiver.is_special_empty_value()); diff --git a/Libraries/LibWeb/Bindings/PlatformObject.cpp b/Libraries/LibWeb/Bindings/PlatformObject.cpp index 7d9549e42de..87daa2ca0da 100644 --- a/Libraries/LibWeb/Bindings/PlatformObject.cpp +++ b/Libraries/LibWeb/Bindings/PlatformObject.cpp @@ -215,10 +215,10 @@ JS::ThrowCompletionOr> PlatformObject::internal } // https://webidl.spec.whatwg.org/#legacy-platform-object-set -JS::ThrowCompletionOr PlatformObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata) +JS::ThrowCompletionOr PlatformObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata, PropertyLookupPhase phase) { if (!m_legacy_platform_object_flags.has_value() || m_legacy_platform_object_flags->has_global_interface_extended_attribute) - return Base::internal_set(property_name, value, receiver, metadata); + return Base::internal_set(property_name, value, receiver, metadata, phase); auto& vm = this->vm(); diff --git a/Libraries/LibWeb/Bindings/PlatformObject.h b/Libraries/LibWeb/Bindings/PlatformObject.h index 99bbc35f0aa..c01b86b60d9 100644 --- a/Libraries/LibWeb/Bindings/PlatformObject.h +++ b/Libraries/LibWeb/Bindings/PlatformObject.h @@ -36,7 +36,7 @@ public: // ^JS::Object virtual JS::ThrowCompletionOr> internal_get_own_property(JS::PropertyKey const&) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value, JS::Value, JS::CacheablePropertyMetadata* = nullptr) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value, JS::Value, JS::CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty) override; virtual JS::ThrowCompletionOr internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&, Optional* precomputed_get_own_property = nullptr) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr internal_prevent_extensions() override; diff --git a/Libraries/LibWeb/HTML/Location.cpp b/Libraries/LibWeb/HTML/Location.cpp index b50a9205db3..832baa9842b 100644 --- a/Libraries/LibWeb/HTML/Location.cpp +++ b/Libraries/LibWeb/HTML/Location.cpp @@ -672,13 +672,13 @@ JS::ThrowCompletionOr Location::internal_get(JS::PropertyKey const& p } // 7.10.5.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/history.html#location-set -JS::ThrowCompletionOr Location::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) +JS::ThrowCompletionOr Location::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) { auto& vm = this->vm(); // 1. If IsPlatformObjectSameOrigin(this) is true, then return ? OrdinarySet(this, P, V, Receiver). if (HTML::is_platform_object_same_origin(*this)) - return JS::Object::internal_set(property_key, value, receiver, cacheable_metadata); + return JS::Object::internal_set(property_key, value, receiver, cacheable_metadata, phase); // 2. Return ? CrossOriginSet(this, P, V, Receiver). return HTML::cross_origin_set(vm, static_cast(*this), property_key, value, receiver); diff --git a/Libraries/LibWeb/HTML/Location.h b/Libraries/LibWeb/HTML/Location.h index a8ff216ead0..b28620ed3f3 100644 --- a/Libraries/LibWeb/HTML/Location.h +++ b/Libraries/LibWeb/HTML/Location.h @@ -61,7 +61,7 @@ public: virtual JS::ThrowCompletionOr> internal_get_own_property(JS::PropertyKey const&) const override; virtual JS::ThrowCompletionOr internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&, Optional* precomputed_get_own_property = nullptr) override; virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override; diff --git a/Libraries/LibWeb/HTML/WindowProxy.cpp b/Libraries/LibWeb/HTML/WindowProxy.cpp index a2ba643a4e8..10f66089ee5 100644 --- a/Libraries/LibWeb/HTML/WindowProxy.cpp +++ b/Libraries/LibWeb/HTML/WindowProxy.cpp @@ -175,7 +175,7 @@ JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const // 7.4.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowproxy-set // https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowproxy-set -JS::ThrowCompletionOr WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) +JS::ThrowCompletionOr WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) { auto& vm = this->vm(); diff --git a/Libraries/LibWeb/HTML/WindowProxy.h b/Libraries/LibWeb/HTML/WindowProxy.h index 6d813c28e4a..7b313ab4862 100644 --- a/Libraries/LibWeb/HTML/WindowProxy.h +++ b/Libraries/LibWeb/HTML/WindowProxy.h @@ -28,7 +28,7 @@ public: virtual JS::ThrowCompletionOr> internal_get_own_property(JS::PropertyKey const&) const override; virtual JS::ThrowCompletionOr internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&, Optional* precomputed_get_own_property = nullptr) override; virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override; - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override; diff --git a/Libraries/LibWeb/WebIDL/ObservableArray.cpp b/Libraries/LibWeb/WebIDL/ObservableArray.cpp index 789f2ceebcc..ebd7a26d924 100644 --- a/Libraries/LibWeb/WebIDL/ObservableArray.cpp +++ b/Libraries/LibWeb/WebIDL/ObservableArray.cpp @@ -39,11 +39,11 @@ void ObservableArray::set_on_delete_an_indexed_value_callback(DeleteAnIndexedVal m_on_delete_an_indexed_value = GC::create_function(heap(), move(callback)); } -JS::ThrowCompletionOr ObservableArray::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata) +JS::ThrowCompletionOr ObservableArray::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata, PropertyLookupPhase phase) { if (property_key.is_number() && m_on_set_an_indexed_value) TRY(Bindings::throw_dom_exception_if_needed(vm(), [&] { return m_on_set_an_indexed_value->function()(value); })); - return TRY(Base::internal_set(property_key, value, receiver, metadata)); + return TRY(Base::internal_set(property_key, value, receiver, metadata, phase)); } JS::ThrowCompletionOr ObservableArray::internal_delete(JS::PropertyKey const& property_key) diff --git a/Libraries/LibWeb/WebIDL/ObservableArray.h b/Libraries/LibWeb/WebIDL/ObservableArray.h index 59b31999ec2..ccb00c7553f 100644 --- a/Libraries/LibWeb/WebIDL/ObservableArray.h +++ b/Libraries/LibWeb/WebIDL/ObservableArray.h @@ -19,7 +19,7 @@ class ObservableArray final : public JS::Array { public: static GC::Ref create(JS::Realm& realm); - virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata = nullptr) override; + virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const& property_key) override; using SetAnIndexedValueCallbackFunction = Function(JS::Value&)>;