LibJS: Add Value::get() and Object::get() overloads with lookup cache

To speed up property access, callers of get() can now provide a lookup
cache like so:

    static Bytecode::PropertyLookupCache cache;
    auto value = TRY(object.get(property, cache));

Note that the cache has to be `static` or it won't make sense!

This basically brings the inline caches from our bytecode VM straight
into C++ land, allowing us to gain serious performance improvements.
The implementation shares code with the GetById bytecode instruction.
This commit is contained in:
Andreas Kling 2025-10-14 13:26:26 +02:00 committed by Andreas Kling
parent 26c1dea22a
commit 0fb9ba1e3a
4 changed files with 38 additions and 1 deletions

View File

@ -125,6 +125,13 @@ ThrowCompletionOr<Value> Object::get(PropertyKey const& property_key) const
return TRY(internal_get(property_key, this));
}
// 7.3.2 Get ( O, P ), https://tc39.es/ecma262/#sec-get-o-p
ThrowCompletionOr<Value> Object::get(PropertyKey const& property_key, Bytecode::PropertyLookupCache& cache) const
{
// 1. Return ? O.[[Get]](P, O).
return TRY(Value(this).get(vm(), property_key, cache));
}
// NOTE: 7.3.3 GetV ( V, P ) is implemented as Value::get().
// 7.3.4 Set ( O, P, V, Throw ), https://tc39.es/ecma262/#sec-set-o-p-v-throw

View File

@ -121,6 +121,7 @@ public:
// 7.3 Operations on Objects, https://tc39.es/ecma262/#sec-operations-on-objects
ThrowCompletionOr<Value> get(PropertyKey const&) const;
ThrowCompletionOr<Value> get(PropertyKey const&, Bytecode::PropertyLookupCache&) const;
ThrowCompletionOr<void> set(PropertyKey const&, Value, ShouldThrowExceptions);
ThrowCompletionOr<bool> create_data_property(PropertyKey const&, Value, Optional<u32>* new_property_offset = nullptr);
void create_method_property(PropertyKey const&, Value);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2020-2025, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, David Tuin <davidot@serenityos.org>
*
@ -15,6 +15,7 @@
#include <AK/Utf16String.h>
#include <AK/Utf8View.h>
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibJS/Bytecode/PropertyAccess.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Accessor.h>
#include <LibJS/Runtime/Array.h>
@ -1306,6 +1307,13 @@ ThrowCompletionOr<Value> Value::get(VM& vm, PropertyKey const& property_key) con
return TRY(object->internal_get(property_key, *this));
}
ThrowCompletionOr<Value> Value::get(VM& vm, PropertyKey const& property, Bytecode::PropertyLookupCache& cache) const
{
if (is_nullish())
return vm.throw_completion<TypeError>(ErrorType::ToObjectNullOrUndefined);
return Bytecode::get_by_id<Bytecode::GetByIdMode::Normal>(vm, [&]() { return Optional<Utf16FlyString const&> {}; }, [&]() { return property; }, *this, *this, cache);
}
// 7.3.11 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod
ThrowCompletionOr<GC::Ptr<FunctionObject>> Value::get_method(VM& vm, PropertyKey const& property_key) const
{
@ -1324,6 +1332,24 @@ ThrowCompletionOr<GC::Ptr<FunctionObject>> Value::get_method(VM& vm, PropertyKey
return function.as_function();
}
// 7.3.11 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod
ThrowCompletionOr<GC::Ptr<FunctionObject>> Value::get_method(VM& vm, PropertyKey const& property_key, Bytecode::PropertyLookupCache& cache) const
{
// 1. Let func be ? GetV(V, P).
auto function = TRY(get(vm, property_key, cache));
// 2. If func is either undefined or null, return undefined.
if (function.is_nullish())
return nullptr;
// 3. If IsCallable(func) is false, throw a TypeError exception.
if (!function.is_function())
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, function.to_string_without_side_effects());
// 4. Return func.
return function.as_function();
}
// 13.10 Relational Operators, https://tc39.es/ecma262/#sec-relational-operators
// RelationalExpression : RelationalExpression > ShiftExpression
ThrowCompletionOr<bool> greater_than(VM& vm, Value lhs, Value rhs)

View File

@ -382,7 +382,10 @@ public:
bool to_boolean() const;
ThrowCompletionOr<Value> get(VM&, PropertyKey const&) const;
ThrowCompletionOr<Value> get(VM&, PropertyKey const&, Bytecode::PropertyLookupCache&) const;
ThrowCompletionOr<GC::Ptr<FunctionObject>> get_method(VM&, PropertyKey const&) const;
ThrowCompletionOr<GC::Ptr<FunctionObject>> get_method(VM&, PropertyKey const&, Bytecode::PropertyLookupCache&) const;
[[nodiscard]] String to_string_without_side_effects() const;
[[nodiscard]] Utf16String to_utf16_string_without_side_effects() const;