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.
This commit is contained in:
Andreas Kling 2024-05-02 11:13:08 +02:00
parent 3945e1a82a
commit 493a04d5fe
17 changed files with 34 additions and 28 deletions

View file

@ -113,7 +113,7 @@ JS::ThrowCompletionOr<bool> SheetGlobalObject::internal_has_property(JS::Propert
return Object::internal_has_property(name);
}
JS::ThrowCompletionOr<JS::Value> SheetGlobalObject::internal_get(const JS::PropertyKey& property_name, JS::Value receiver, JS::CacheablePropertyMetadata*) const
JS::ThrowCompletionOr<JS::Value> 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") {

View file

@ -29,7 +29,7 @@ public:
virtual ~SheetGlobalObject() override = default;
virtual JS::ThrowCompletionOr<bool> internal_has_property(JS::PropertyKey const& name) const override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
JS_DECLARE_NATIVE_FUNCTION(get_real_cell_contents);

View file

@ -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<Value> ArgumentsObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const
ThrowCompletionOr<Value> 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<Value> 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.

View file

@ -24,7 +24,7 @@ public:
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override;
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;

View file

@ -137,14 +137,14 @@ ThrowCompletionOr<bool> 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<Value> ModuleNamespaceObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const
ThrowCompletionOr<Value> 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]].

View file

@ -26,7 +26,7 @@ public:
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override;
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const override;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const override;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty) const override;
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;

View file

@ -873,7 +873,7 @@ ThrowCompletionOr<bool> 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<Value> Object::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const
ThrowCompletionOr<Value> 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<Value> 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;
}

View file

@ -138,7 +138,11 @@ public:
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const;
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&);
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr) const;
enum class PropertyLookupPhase {
OwnProperty,
PrototypeChain,
};
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata* = nullptr, PropertyLookupPhase = PropertyLookupPhase::OwnProperty) const;
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata* = nullptr);
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&);
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const;

View file

@ -455,7 +455,7 @@ ThrowCompletionOr<bool> 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<Value> ProxyObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata*) const
ThrowCompletionOr<Value> ProxyObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) const
{
// NOTE: We don't return any cacheable metadata for proxy lookups.

View file

@ -39,7 +39,7 @@ public:
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override;
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override;
virtual ThrowCompletionOr<bool> internal_has_property(PropertyKey const&) const override;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*) const override;
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const&, Value receiver, CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual ThrowCompletionOr<bool> internal_set(PropertyKey const&, Value value, Value receiver, CacheablePropertyMetadata*) override;
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override;

View file

@ -317,7 +317,7 @@ public:
}
// 10.4.5.4 [[Get]] ( P, Receiver ), 10.4.5.4 [[Get]] ( P, Receiver )
virtual ThrowCompletionOr<Value> internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata) const override
virtual ThrowCompletionOr<Value> 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

View file

@ -409,15 +409,15 @@ JS::ThrowCompletionOr<bool> CSSStyleDeclaration::internal_has_property(JS::Prope
return property_id_from_name(name.to_string()) != CSS::PropertyID::Invalid;
}
JS::ThrowCompletionOr<JS::Value> CSSStyleDeclaration::internal_get(JS::PropertyKey const& name, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) const
JS::ThrowCompletionOr<JS::Value> 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 {}) };

View file

@ -42,7 +42,7 @@ public:
virtual String serialized() const = 0;
virtual JS::ThrowCompletionOr<bool> internal_has_property(JS::PropertyKey const& name) const override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
protected:

View file

@ -483,13 +483,13 @@ JS::ThrowCompletionOr<bool> 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<JS::Value> Location::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata* cacheable_metadata) const
JS::ThrowCompletionOr<JS::Value> 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<JS::Object const&>(*this), property_key, receiver);

View file

@ -60,7 +60,7 @@ public:
virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override;
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
virtual JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> internal_own_property_keys() const override;

View file

@ -153,7 +153,7 @@ JS::ThrowCompletionOr<bool> 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<JS::Value> WindowProxy::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata*) const
JS::ThrowCompletionOr<JS::Value> WindowProxy::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const
{
auto& vm = this->vm();

View file

@ -27,7 +27,7 @@ public:
virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override;
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*) const override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) override;
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
virtual JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> internal_own_property_keys() const override;