diff --git a/Userland/Applications/Spreadsheet/JSIntegration.cpp b/Userland/Applications/Spreadsheet/JSIntegration.cpp index ea67307c78..8ee5666643 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.cpp +++ b/Userland/Applications/Spreadsheet/JSIntegration.cpp @@ -109,7 +109,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) const +JS::ThrowCompletionOr SheetGlobalObject::internal_get(const JS::PropertyKey& property_name, JS::Value receiver, JS::CacheablePropertyMetadata*) 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 93a766a11a..ac529b77e2 100644 --- a/Userland/Applications/Spreadsheet/JSIntegration.h +++ b/Userland/Applications/Spreadsheet/JSIntegration.h @@ -28,7 +28,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) const override; + virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) 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 3d66852ae9..97d23095b0 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) const +ThrowCompletionOr ArgumentsObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) 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); + return Object::internal_get(property_key, receiver, cacheable_metadata); } // 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 d0e52c34b7..adcb4ff2de 100644 --- a/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h +++ b/Userland/Libraries/LibJS/Runtime/ArgumentsObject.h @@ -23,7 +23,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) const override; + virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override; virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver) override; virtual ThrowCompletionOr internal_delete(PropertyKey const&) override; diff --git a/Userland/Libraries/LibJS/Runtime/IndexedProperties.h b/Userland/Libraries/LibJS/Runtime/IndexedProperties.h index 4532d01a54..b0a923a85e 100644 --- a/Userland/Libraries/LibJS/Runtime/IndexedProperties.h +++ b/Userland/Libraries/LibJS/Runtime/IndexedProperties.h @@ -15,6 +15,8 @@ namespace JS { struct ValueAndAttributes { Value value; PropertyAttributes attributes { default_attributes }; + + Optional property_offset {}; }; class IndexedProperties; diff --git a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.cpp index 55e89eb7ad..5917d9bba8 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) const +ThrowCompletionOr ModuleNamespaceObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) 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)); + return MUST(Object::internal_get(property_key, receiver, cacheable_metadata)); } // 2. Let exports be O.[[Exports]]. diff --git a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h index a592894dc0..d6dd3bce04 100644 --- a/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.h +++ b/Userland/Libraries/LibJS/Runtime/ModuleNamespaceObject.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&) override; virtual ThrowCompletionOr internal_has_property(PropertyKey const&) const override; - virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver) const override; + virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const override; virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver) 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 7da195839d..a0fdd8481d 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -764,7 +764,7 @@ ThrowCompletionOr> Object::internal_get_own_propert PropertyDescriptor descriptor; // 3. Let X be O's own property whose key is P. - auto [value, attributes] = *maybe_storage_entry; + auto [value, attributes, property_offset] = *maybe_storage_entry; // 4. If X is a data property, then if (!value.is_accessor()) { @@ -791,6 +791,9 @@ ThrowCompletionOr> Object::internal_get_own_propert // 7. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute. descriptor.configurable = attributes.is_configurable(); + // Non-standard: Add the property offset to the descriptor. This is used to populate CacheablePropertyMetadata. + descriptor.property_offset = property_offset; + // 8. Return D. return descriptor; } @@ -836,7 +839,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) const +ThrowCompletionOr Object::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const { VERIFY(!receiver.is_empty()); VERIFY(property_key.is_valid()); @@ -860,8 +863,16 @@ ThrowCompletionOr Object::internal_get(PropertyKey const& property_key, V } // 3. If IsDataDescriptor(desc) is true, return desc.[[Value]]. - if (descriptor->is_data_descriptor()) + 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()) { + *cacheable_metadata = CacheablePropertyMetadata { + .type = CacheablePropertyMetadata::Type::OwnProperty, + .property_offset = descriptor->property_offset.value(), + }; + } return *descriptor->value; + } // 4. Assert: IsAccessorDescriptor(desc) is true. VERIFY(descriptor->is_accessor_descriptor()); @@ -1075,6 +1086,7 @@ Optional Object::storage_get(PropertyKey const& property_key Value value; PropertyAttributes attributes; + Optional property_offset; if (property_key.is_number()) { auto value_and_attributes = m_indexed_properties.get(property_key.as_number()); @@ -1094,9 +1106,10 @@ Optional Object::storage_get(PropertyKey const& property_key value = m_storage[metadata->offset]; attributes = metadata->attributes; + property_offset = metadata->offset; } - return ValueAndAttributes { .value = value, .attributes = attributes }; + return ValueAndAttributes { .value = value, .attributes = attributes, .property_offset = property_offset }; } bool Object::storage_has(PropertyKey const& property_key) const @@ -1111,7 +1124,7 @@ void Object::storage_set(PropertyKey const& property_key, ValueAndAttributes con { VERIFY(property_key.is_valid()); - auto [value, attributes] = value_and_attributes; + auto [value, attributes, _] = value_and_attributes; if (property_key.is_number()) { auto index = property_key.as_number(); diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index bde5890b5c..7f2b041291 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -39,6 +39,17 @@ struct PrivateElement { Handle value; }; +// Non-standard: This is information optionally returned by object property access functions. +// It can be used to implement inline caches for property lookup. +struct CacheablePropertyMetadata { + enum class Type { + NotCacheable, + OwnProperty, + }; + Type type { Type::NotCacheable }; + Optional property_offset; +}; + class Object : public Cell { JS_CELL(Object, Cell); @@ -118,7 +129,7 @@ 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) const; + virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const; virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver); virtual ThrowCompletionOr internal_delete(PropertyKey const&); virtual ThrowCompletionOr> internal_own_property_keys() const; diff --git a/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h b/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h index 3fc549d9c5..a3cc985eb9 100644 --- a/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h +++ b/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h @@ -40,6 +40,8 @@ public: Optional writable {}; Optional enumerable {}; Optional configurable {}; + + Optional property_offset {}; }; } diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp index f23d0a852c..1f4b232f8d 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -452,8 +452,10 @@ 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) const +ThrowCompletionOr ProxyObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata*) const { + // NOTE: We don't return any cacheable metadata for proxy lookups. + VERIFY(!receiver.is_empty()); auto& vm = this->vm(); diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.h b/Userland/Libraries/LibJS/Runtime/ProxyObject.h index 15eec64a70..15fe721904 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.h +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.h @@ -38,7 +38,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) const override; + virtual ThrowCompletionOr internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override; virtual ThrowCompletionOr internal_set(PropertyKey const&, Value value, Value receiver) 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 f925ad72ca..4a81ea75a7 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.h @@ -288,7 +288,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) const override + virtual ThrowCompletionOr internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const override { VERIFY(!receiver.is_empty()); @@ -310,7 +310,7 @@ public: } // 2. Return ? OrdinaryGet(O, P, Receiver). - return Object::internal_get(property_key, receiver); + return Object::internal_get(property_key, receiver, cacheable_metadata); } // 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 4767b2ded8..de19d3554d 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp @@ -396,13 +396,13 @@ 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) const +JS::ThrowCompletionOr CSSStyleDeclaration::internal_get(JS::PropertyKey const& name, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) const { if (!name.is_string()) - return Base::internal_get(name, receiver); + return Base::internal_get(name, receiver, cacheable_metadata); auto property_id = property_id_from_name(name.to_string()); if (property_id == CSS::PropertyID::Invalid) - return Base::internal_get(name, receiver); + return Base::internal_get(name, receiver, cacheable_metadata); if (auto maybe_property = property(property_id); maybe_property.has_value()) return { JS::PrimitiveString::create(vm(), maybe_property->value->to_string().release_value_but_fixme_should_propagate_errors().to_deprecated_string()) }; return { JS::PrimitiveString::create(vm(), String {}) }; diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h index 139994eaf2..62cabc1a4d 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h @@ -41,7 +41,7 @@ public: virtual DeprecatedString 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) const override; + virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; protected: diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp index afcd037982..f4fd9fa132 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.cpp +++ b/Userland/Libraries/LibWeb/HTML/Location.cpp @@ -442,13 +442,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) const +JS::ThrowCompletionOr Location::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) 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); + return JS::Object::internal_get(property_key, receiver, cacheable_metadata); // 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 e154137562..b7c4b0449d 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.h +++ b/Userland/Libraries/LibWeb/HTML/Location.h @@ -58,7 +58,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) const override; + virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) 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 fdcf39d01a..7cf010ece5 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp @@ -144,7 +144,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) const +JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) const { auto& vm = this->vm(); @@ -156,7 +156,7 @@ JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const // 3. If IsPlatformObjectSameOrigin(W) is true, then return ? OrdinaryGet(this, P, Receiver). // NOTE: this is passed rather than W as OrdinaryGet and CrossOriginGet will invoke the [[GetOwnProperty]] internal method. if (is_platform_object_same_origin(*m_window)) - return JS::Object::internal_get(property_key, receiver); + return JS::Object::internal_get(property_key, receiver, cacheable_metadata); // 4. Return ? CrossOriginGet(this, P, Receiver). // NOTE: this is passed rather than W as OrdinaryGet and CrossOriginGet will invoke the [[GetOwnProperty]] internal method. diff --git a/Userland/Libraries/LibWeb/HTML/WindowProxy.h b/Userland/Libraries/LibWeb/HTML/WindowProxy.h index 5c32c7b63e..43dd46e0a1 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.h +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.h @@ -26,7 +26,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) const override; + virtual JS::ThrowCompletionOr internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override; virtual JS::ThrowCompletionOr internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; virtual JS::ThrowCompletionOr internal_delete(JS::PropertyKey const&) override; virtual JS::ThrowCompletionOr> internal_own_property_keys() const override;