LibJS: Inline more of cached environment variable access in interpreter

And stop passing VM strictness to direct access, since it doesn't care
about strictness anyway.
This commit is contained in:
Andreas Kling
2024-05-11 17:22:59 +02:00
parent 9b6a1de777
commit 8447f6f6da
6 changed files with 42 additions and 48 deletions

View File

@@ -523,28 +523,6 @@ inline ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Optional<Depreca
return {};
}
inline ThrowCompletionOr<Value> get_variable(Bytecode::Interpreter& interpreter, DeprecatedFlyString const& name, EnvironmentVariableCache& cache)
{
auto& vm = interpreter.vm();
if (cache.has_value()) {
auto environment = vm.running_execution_context().lexical_environment;
for (size_t i = 0; i < cache->hops; ++i)
environment = environment->outer_environment();
VERIFY(environment);
VERIFY(environment->is_declarative_environment());
if (!environment->is_permanently_screwed_by_eval()) {
return TRY(verify_cast<DeclarativeEnvironment>(*environment).get_binding_value_direct(vm, cache.value().index, vm.in_strict_mode()));
}
cache = {};
}
auto reference = TRY(vm.resolve_binding(name));
if (reference.environment_coordinate().has_value())
cache = reference.environment_coordinate();
return TRY(reference.get_value(vm));
}
struct CalleeAndThis {
Value callee;
Value this_value;
@@ -558,13 +536,11 @@ inline ThrowCompletionOr<CalleeAndThis> get_callee_and_this_from_environment(Byt
Value this_value = js_undefined();
if (cache.has_value()) {
auto environment = vm.running_execution_context().lexical_environment;
auto const* environment = vm.running_execution_context().lexical_environment.ptr();
for (size_t i = 0; i < cache->hops; ++i)
environment = environment->outer_environment();
VERIFY(environment);
VERIFY(environment->is_declarative_environment());
if (!environment->is_permanently_screwed_by_eval()) {
callee = TRY(verify_cast<DeclarativeEnvironment>(*environment).get_binding_value_direct(vm, cache.value().index, vm.in_strict_mode()));
callee = TRY(static_cast<DeclarativeEnvironment const&>(*environment).get_binding_value_direct(vm, cache.value().index));
this_value = js_undefined();
if (auto base_object = environment->with_base_object())
this_value = base_object;

View File

@@ -1232,7 +1232,25 @@ ThrowCompletionOr<void> ConcatString::execute_impl(Bytecode::Interpreter& interp
ThrowCompletionOr<void> GetVariable::execute_impl(Bytecode::Interpreter& interpreter) const
{
interpreter.set(dst(), TRY(get_variable(interpreter, interpreter.current_executable().get_identifier(m_identifier), interpreter.current_executable().environment_variable_caches[m_cache_index])));
auto& vm = interpreter.vm();
auto& executable = interpreter.current_executable();
auto& cache = executable.environment_variable_caches[m_cache_index];
if (cache.has_value()) {
auto const* environment = vm.running_execution_context().lexical_environment.ptr();
for (size_t i = 0; i < cache->hops; ++i)
environment = environment->outer_environment();
if (!environment->is_permanently_screwed_by_eval()) {
interpreter.set(dst(), TRY(static_cast<DeclarativeEnvironment const&>(*environment).get_binding_value_direct(vm, cache.value().index)));
return {};
}
cache = {};
}
auto reference = TRY(vm.resolve_binding(executable.get_identifier(m_identifier)));
if (reference.environment_coordinate().has_value())
cache = reference.environment_coordinate();
interpreter.set(dst(), TRY(reference.get_value(vm)));
return {};
}

View File

@@ -182,29 +182,14 @@ ThrowCompletionOr<void> DeclarativeEnvironment::set_mutable_binding_direct(VM& v
}
// 9.1.1.1.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s
ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value(VM& vm, DeprecatedFlyString const& name, bool strict)
ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value(VM& vm, DeprecatedFlyString const& name, [[maybe_unused]] bool strict)
{
// 1. Assert: envRec has a binding for N.
auto binding_and_index = find_binding_and_index(name);
VERIFY(binding_and_index.has_value());
// 2-3. (extracted into a non-standard function below)
return get_binding_value_direct(vm, binding_and_index->binding(), strict);
}
ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value_direct(VM& vm, size_t index, bool strict)
{
return get_binding_value_direct(vm, m_bindings[index], strict);
}
ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value_direct(VM&, Binding& binding, bool)
{
// 2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if (!binding.initialized)
return vm().throw_completion<ReferenceError>(ErrorType::BindingNotInitialized, binding.name);
// 3. Return the value currently bound to N in envRec.
return binding.value;
return get_binding_value_direct(vm, binding_and_index->binding());
}
// 9.1.1.1.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n

View File

@@ -57,7 +57,7 @@ public:
}
ThrowCompletionOr<void> set_mutable_binding_direct(VM&, size_t index, Value, bool strict);
ThrowCompletionOr<Value> get_binding_value_direct(VM&, size_t index, bool strict);
ThrowCompletionOr<Value> get_binding_value_direct(VM&, size_t index) const;
void shrink_to_fit();
@@ -69,7 +69,7 @@ public:
[[nodiscard]] u64 environment_serial_number() const { return m_environment_serial_number; }
private:
ThrowCompletionOr<Value> get_binding_value_direct(VM&, Binding&, bool strict);
ThrowCompletionOr<Value> get_binding_value_direct(VM&, Binding const&) const;
ThrowCompletionOr<void> set_mutable_binding_direct(VM&, Binding&, Value, bool strict);
friend Completion dispose_resources(VM&, GCPtr<DeclarativeEnvironment>, Completion);
@@ -131,6 +131,21 @@ private:
u64 m_environment_serial_number { 0 };
};
inline ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value_direct(VM& vm, size_t index) const
{
return get_binding_value_direct(vm, m_bindings[index]);
}
inline ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value_direct(VM&, Binding const& binding) const
{
// 2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if (!binding.initialized)
return vm().throw_completion<ReferenceError>(ErrorType::BindingNotInitialized, binding.name);
// 3. Return the value currently bound to N in envRec.
return binding.value;
}
template<>
inline bool Environment::fast_is<DeclarativeEnvironment>() const { return is_declarative_environment(); }

View File

@@ -119,7 +119,7 @@ ThrowCompletionOr<Value> GlobalEnvironment::get_binding_value(VM& vm, Deprecated
if (MUST(m_declarative_record->has_binding(name, &index))) {
// a. Return ? DclRec.GetBindingValue(N, S).
if (index.has_value())
return m_declarative_record->get_binding_value_direct(vm, index.value(), strict);
return m_declarative_record->get_binding_value_direct(vm, index.value());
return m_declarative_record->get_binding_value(vm, name, strict);
}

View File

@@ -142,7 +142,7 @@ ThrowCompletionOr<Value> Reference::get_value(VM& vm) const
// c. Return ? base.GetBindingValue(V.[[ReferencedName]], V.[[Strict]]) (see 9.1).
if (m_environment_coordinate.has_value())
return static_cast<DeclarativeEnvironment*>(m_base_environment)->get_binding_value_direct(vm, m_environment_coordinate->index, m_strict);
return static_cast<DeclarativeEnvironment*>(m_base_environment)->get_binding_value_direct(vm, m_environment_coordinate->index);
return m_base_environment->get_binding_value(vm, m_name.as_string(), m_strict);
}