diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index a5a68820600..b4886e22c05 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -991,11 +992,18 @@ inline ThrowCompletionOr get_by_id(VM& vm, Optional return false; return true; }(); - if (can_use_cache) - return cache.prototype->get_direct(cache.property_offset.value()); + if (can_use_cache) { + auto value = cache.prototype->get_direct(cache.property_offset.value()); + if (value.is_accessor()) + return TRY(call(vm, value.as_accessor().getter(), this_value)); + return value; + } } else if (&shape == cache.shape) { // OPTIMIZATION: If the shape of the object hasn't changed, we can use the cached property offset. - return base_obj->get_direct(cache.property_offset.value()); + auto value = base_obj->get_direct(cache.property_offset.value()); + if (value.is_accessor()) + return TRY(call(vm, value.as_accessor().getter(), this_value)); + return value; } CacheablePropertyMetadata cacheable_metadata; @@ -1103,7 +1111,9 @@ inline ThrowCompletionOr get_global(Interpreter& interpreter, IdentifierT // OPTIMIZATION: For global var bindings, if the shape of the global object hasn't changed, // we can use the cached property offset. if (&shape == cache.shape) { - return binding_object.get_direct(cache.property_offset.value()); + auto value = binding_object.get_direct(cache.property_offset.value()); + if (value.is_accessor()) + return TRY(call(vm, value.as_accessor().getter(), js_undefined())); } // OPTIMIZATION: For global lexical bindings, if the global declarative environment hasn't changed, diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index e3f0f8e8de8..9c2c9382dc0 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -911,26 +911,30 @@ ThrowCompletionOr 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 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)); }