From 493a04d5fef2a949f89c87fa8e630c6801dd6400 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 2 May 2024 11:13:08 +0200 Subject: [PATCH] LibJS: Add PropertyLookupPhase enum to distinguish Object [[Get]] calls We can now tell the difference between an own property access and a subsequent (automatic) prototype chain access. This will be used to implement caching of prototype chain accesses. --- .../Applications/Spreadsheet/JSIntegration.cpp | 2 +- Userland/Applications/Spreadsheet/JSIntegration.h | 2 +- .../Libraries/LibJS/Runtime/ArgumentsObject.cpp | 4 ++-- Userland/Libraries/LibJS/Runtime/ArgumentsObject.h | 2 +- .../LibJS/Runtime/ModuleNamespaceObject.cpp | 4 ++-- .../LibJS/Runtime/ModuleNamespaceObject.h | 2 +- Userland/Libraries/LibJS/Runtime/Object.cpp | 14 ++++++++------ Userland/Libraries/LibJS/Runtime/Object.h | 6 +++++- Userland/Libraries/LibJS/Runtime/ProxyObject.cpp | 2 +- Userland/Libraries/LibJS/Runtime/ProxyObject.h | 2 +- Userland/Libraries/LibJS/Runtime/TypedArray.h | 4 ++-- .../Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp | 6 +++--- .../Libraries/LibWeb/CSS/CSSStyleDeclaration.h | 2 +- Userland/Libraries/LibWeb/HTML/Location.cpp | 4 ++-- Userland/Libraries/LibWeb/HTML/Location.h | 2 +- Userland/Libraries/LibWeb/HTML/WindowProxy.cpp | 2 +- Userland/Libraries/LibWeb/HTML/WindowProxy.h | 2 +- 17 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Userland/Applications/Spreadsheet/JSIntegration.cpp b/Userland/Applications/Spreadsheet/JSIntegration.cpp index 4eb3dd90c4..0addf56a2b 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.cpp +++ b/Userland/Applications/Spreadsheet/JSIntegration.cpp @@ -113,7 +113,7 @@ JS::ThrowCompletionOr SheetGlobalObject::internal_has_property(JS::Propert return Object::internal_has_property(name); } -JS::ThrowCompletionOr SheetGlobalObject::internal_get(const JS::PropertyKey& property_name, JS::Value receiver, JS::CacheablePropertyMetadata*) const +JS::ThrowCompletionOr SheetGlobalObject::internal_get(const JS::PropertyKey& property_name, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const { if (property_name.is_string()) { if (property_name.as_string() == "value") { diff --git a/Userland/Applications/Spreadsheet/JSIntegration.h b/Userland/Applications/Spreadsheet/JSIntegration.h index 6aed6f0a1b..83f0c41936 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.h +++ b/Userland/Applications/Spreadsheet/JSIntegration.h @@ -29,7 +29,7 @@ public: virtual ~SheetGlobalObject() override = default; virtual JS::ThrowCompletionOr internal_has_property(JS::PropertyKey const& name) const override; - virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const 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; JS_DECLARE_NATIVE_FUNCTION(get_real_cell_contents); diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp index 8183c3d2d4..8e663575b1 100644 --- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.cpp @@ -33,7 +33,7 @@ void ArgumentsObject::visit_edges(Cell::Visitor& visitor) } // 10.4.4.3 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-arguments-exotic-objects-get-p-receiver -ThrowCompletionOr ArgumentsObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const +ThrowCompletionOr ArgumentsObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const { // 1. Let map be args.[[ParameterMap]]. auto& map = *m_parameter_map; @@ -44,7 +44,7 @@ ThrowCompletionOr ArgumentsObject::internal_get(PropertyKey const& proper // 3. If isMapped is false, then if (!is_mapped) { // a. Return ? OrdinaryGet(args, P, Receiver). - return Object::internal_get(property_key, receiver, cacheable_metadata); + return Object::internal_get(property_key, receiver, cacheable_metadata, phase); } // FIXME: a. Assert: map contains a formal parameter mapping for P. diff --git a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h index 261b5d7c27..4769511834 100644 --- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h @@ -24,7 +24,7 @@ public: virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override; - virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) 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_delete(PropertyKey const&) override; diff --git a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp index d59da1dcc1..e9a7c0786e 100644 --- a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp @@ -137,14 +137,14 @@ ThrowCompletionOr ModuleNamespaceObject::internal_has_property(PropertyKey } // 10.4.6.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver -ThrowCompletionOr ModuleNamespaceObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const +ThrowCompletionOr ModuleNamespaceObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const { auto& vm = this->vm(); // 1. If Type(P) is Symbol, then if (property_key.is_symbol()) { // a. Return ! OrdinaryGet(O, P, Receiver). - return MUST(Object::internal_get(property_key, receiver, cacheable_metadata)); + return MUST(Object::internal_get(property_key, receiver, cacheable_metadata, phase)); } // 2. Let exports be O.[[Exports]]. diff --git a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h index 3a43927270..9c211aec77 100644 --- a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h +++ b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h @@ -26,7 +26,7 @@ public: virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; - virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) 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_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index 583f772866..54d3ea9c1f 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -873,7 +873,7 @@ ThrowCompletionOr Object::internal_has_property(PropertyKey const& propert } // 10.1.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver -ThrowCompletionOr Object::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const +ThrowCompletionOr Object::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const { VERIFY(!receiver.is_empty()); VERIFY(property_key.is_valid()); @@ -893,17 +893,19 @@ ThrowCompletionOr Object::internal_get(PropertyKey const& property_key, V return js_undefined(); // c. Return ? parent.[[Get]](P, Receiver). - return parent->internal_get(property_key, receiver); + return parent->internal_get(property_key, receiver, nullptr, PropertyLookupPhase::PrototypeChain); } // 3. If IsDataDescriptor(desc) is true, return desc.[[Value]]. if (descriptor->is_data_descriptor()) { // Non-standard: If the caller has requested cacheable metadata and the property is an own property, fill it in. if (cacheable_metadata && descriptor->property_offset.has_value() && shape().is_cacheable()) { - *cacheable_metadata = CacheablePropertyMetadata { - .type = CacheablePropertyMetadata::Type::OwnProperty, - .property_offset = descriptor->property_offset.value(), - }; + if (phase == PropertyLookupPhase::OwnProperty) { + *cacheable_metadata = CacheablePropertyMetadata { + .type = CacheablePropertyMetadata::Type::OwnProperty, + .property_offset = descriptor->property_offset.value(), + }; + } } return *descriptor->value; } diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index d6e4a04892..7178fa7b63 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -138,7 +138,11 @@ public: virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&); virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const; - virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const; + enum class PropertyLookupPhase { + OwnProperty, + 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_delete(PropertyKey const&); virtual ThrowCompletionOr> internal_own_property_keys() const; diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp index 1bcd9a4a4e..80dfe64beb 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -455,7 +455,7 @@ ThrowCompletionOr ProxyObject::internal_has_property(PropertyKey const& pr } // 10.5.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver -ThrowCompletionOr ProxyObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata*) const +ThrowCompletionOr ProxyObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) const { // NOTE: We don't return any cacheable metadata for proxy lookups. diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.h b/Userland/Libraries/LibJS/Runtime/ProxyObject.h index 462570eadb..9452ae3dd1 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.h +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.h @@ -39,7 +39,7 @@ public: virtual ThrowCompletionOr> internal_get_own_property(PropertyKey const&) const override; virtual ThrowCompletionOr internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; - virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) 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_delete(PropertyKey const&) override; virtual ThrowCompletionOr> internal_own_property_keys() const override; diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.h b/Userland/Libraries/LibJS/Runtime/TypedArray.h index 181233d7d2..8e65929166 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.h @@ -317,7 +317,7 @@ public: } // 10.4.5.4 [[Get]] ( P, Receiver ), 10.4.5.4 [[Get]] ( P, Receiver ) - virtual ThrowCompletionOr internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const override + virtual ThrowCompletionOr internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const override { VERIFY(!receiver.is_empty()); @@ -339,7 +339,7 @@ public: } // 2. Return ? OrdinaryGet(O, P, Receiver). - return Object::internal_get(property_key, receiver, cacheable_metadata); + return Object::internal_get(property_key, receiver, cacheable_metadata, phase); } // 10.4.5.5 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp index eca0ba2a3b..a05ec01a00 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp @@ -409,15 +409,15 @@ JS::ThrowCompletionOr CSSStyleDeclaration::internal_has_property(JS::Prope return property_id_from_name(name.to_string()) != CSS::PropertyID::Invalid; } -JS::ThrowCompletionOr CSSStyleDeclaration::internal_get(JS::PropertyKey const& name, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) const +JS::ThrowCompletionOr CSSStyleDeclaration::internal_get(JS::PropertyKey const& name, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const { if (name.is_number()) return { JS::PrimitiveString::create(vm(), item(name.as_number())) }; if (!name.is_string()) - return Base::internal_get(name, receiver, cacheable_metadata); + return Base::internal_get(name, receiver, cacheable_metadata, phase); auto property_id = property_id_from_name(name.to_string()); if (property_id == CSS::PropertyID::Invalid) - return Base::internal_get(name, receiver, cacheable_metadata); + return Base::internal_get(name, receiver, cacheable_metadata, phase); if (auto maybe_property = property(property_id); maybe_property.has_value()) return { JS::PrimitiveString::create(vm(), maybe_property->value->to_string()) }; return { JS::PrimitiveString::create(vm(), String {}) }; diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h index b485a6169d..0eee4969e8 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h @@ -42,7 +42,7 @@ public: virtual String serialized() const = 0; virtual JS::ThrowCompletionOr internal_has_property(JS::PropertyKey const& name) const override; - virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const 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; protected: diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp index fd004eb3a6..f8feb67ed1 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.cpp +++ b/Userland/Libraries/LibWeb/HTML/Location.cpp @@ -483,13 +483,13 @@ JS::ThrowCompletionOr Location::internal_define_own_property(JS::PropertyK } // 7.10.5.7 [[Get]] ( P, Receiver ), https://html.spec.whatwg.org/multipage/history.html#location-get -JS::ThrowCompletionOr Location::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) const +JS::ThrowCompletionOr Location::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const { auto& vm = this->vm(); // 1. If IsPlatformObjectSameOrigin(this) is true, then return ? OrdinaryGet(this, P, Receiver). if (HTML::is_platform_object_same_origin(*this)) - return JS::Object::internal_get(property_key, receiver, cacheable_metadata); + return JS::Object::internal_get(property_key, receiver, cacheable_metadata, phase); // 2. Return ? CrossOriginGet(this, P, Receiver). return HTML::cross_origin_get(vm, static_cast(*this), property_key, receiver); diff --git a/Userland/Libraries/LibWeb/HTML/Location.h b/Userland/Libraries/LibWeb/HTML/Location.h index a68f9b3c00..68e2c92d62 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.h +++ b/Userland/Libraries/LibWeb/HTML/Location.h @@ -60,7 +60,7 @@ public: virtual JS::ThrowCompletionOr internal_prevent_extensions() override; 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&) override; - virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const 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_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override; diff --git a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp index 7bcc9d954c..7d1f9f1035 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp @@ -153,7 +153,7 @@ JS::ThrowCompletionOr WindowProxy::internal_define_own_property(JS::Proper } // 7.4.7 [[Get]] ( P, Receiver ), https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get -JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata*) const +JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const { auto& vm = this->vm(); diff --git a/Userland/Libraries/LibWeb/HTML/WindowProxy.h b/Userland/Libraries/LibWeb/HTML/WindowProxy.h index c4276e9a67..faa17594cc 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.h +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.h @@ -27,7 +27,7 @@ public: virtual JS::ThrowCompletionOr internal_prevent_extensions() override; 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&) override; - virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const 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_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override;