LibJS: Allow GetById to cache getters

1.25x speed-up on this microbenchmark:

    let o = { get x() { return 1; } };
    for (let i = 0; i < 10_000_000; ++i)
        o.x;

I looked into this because I noticed getter invocation when profiling
long-running WPT tests. We already had the mechanism for non-getter
properties, and the change to support getters turned out to be trivial.
This commit is contained in:
Andreas Kling 2024-10-17 20:29:07 +02:00 committed by Andreas Kling
commit 3c5819a6d2
Notes: github-actions[bot] 2024-10-17 20:07:21 +00:00
2 changed files with 38 additions and 22 deletions

View file

@ -911,26 +911,30 @@ ThrowCompletionOr<Value> Object::internal_get(PropertyKey const& property_key, V
return parent->internal_get(property_key, receiver, cacheable_metadata, PropertyLookupPhase::PrototypeChain);
}
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 || !descriptor->property_offset.has_value() || !shape().is_cacheable())
return;
if (phase == PropertyLookupPhase::OwnProperty) {
*cacheable_metadata = CacheablePropertyMetadata {
.type = CacheablePropertyMetadata::Type::OwnProperty,
.property_offset = 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 = descriptor->property_offset.value(),
.prototype = this,
};
}
};
// 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()) {
if (phase == PropertyLookupPhase::OwnProperty) {
*cacheable_metadata = CacheablePropertyMetadata {
.type = CacheablePropertyMetadata::Type::OwnProperty,
.property_offset = 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 = descriptor->property_offset.value(),
.prototype = this,
};
}
}
update_inline_cache();
return *descriptor->value;
}
@ -944,6 +948,8 @@ ThrowCompletionOr<Value> Object::internal_get(PropertyKey const& property_key, V
if (!getter)
return js_undefined();
update_inline_cache();
// 7. Return ? Call(getter, Receiver).
return TRY(call(vm, *getter, receiver));
}