1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 21:08:12 +00:00

LibJS: Combine DeclarativeEnvironment's bindings and names into one list

This reduces the size of the DeclarativeEnvironment from 72 bytes to 48
bytes. This savings helps in the context of nested for-loops which use
'let' to bind the initial variable declarations. In this case, the spec
dicates we create a new environment for each loop iteration by way of
the CreatePerIterationEnvironment AO.

In particular, test262's generated RegExp tests contains many loops of
the form:

    for (let i = 0; i < a_number_on_the_order_of_10; ++i)
        for (let j = 0; j < a_number_on_the_order_of_10_thousand; ++j)

This results in creating hundreds of thousands of environments.
This commit is contained in:
Timothy Flynn 2022-03-08 11:56:42 -05:00 committed by Linus Groh
parent 8d784310e0
commit 533170fbfa
2 changed files with 35 additions and 16 deletions

View file

@ -37,7 +37,7 @@ void DeclarativeEnvironment::visit_edges(Visitor& visitor)
// 9.1.1.1.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-hasbinding-n
ThrowCompletionOr<bool> DeclarativeEnvironment::has_binding(FlyString const& name, Optional<size_t>* out_index) const
{
auto index = m_names.find_first_index(name);
auto index = find_binding_index(name);
if (!index.has_value())
return false;
if (!is_permanently_screwed_by_eval() && out_index)
@ -50,16 +50,16 @@ ThrowCompletionOr<void> DeclarativeEnvironment::create_mutable_binding(GlobalObj
{
// 2. Create a mutable binding in envRec for N and record that it is uninitialized. If D is true, record that the newly created binding may be deleted by a subsequent DeleteBinding call.
m_bindings.append(Binding {
.name = name,
.value = {},
.strict = false,
.mutable_ = true,
.can_be_deleted = can_be_deleted,
.initialized = false,
});
m_names.append(name);
// 1. Assert: envRec does not already have a binding for N.
// NOTE: We skip this to avoid O(n) traversal of m_names.
// NOTE: We skip this to avoid O(n) traversal of m_bindings.
// 3. Return NormalCompletion(empty).
return {};
@ -70,16 +70,16 @@ ThrowCompletionOr<void> DeclarativeEnvironment::create_immutable_binding(GlobalO
{
// 2. Create an immutable binding in envRec for N and record that it is uninitialized. If S is true, record that the newly created binding is a strict binding.
m_bindings.append(Binding {
.name = name,
.value = {},
.strict = strict,
.mutable_ = false,
.can_be_deleted = false,
.initialized = false,
});
m_names.append(name);
// 1. Assert: envRec does not already have a binding for N.
// NOTE: We skip this to avoid O(n) traversal of m_names.
// NOTE: We skip this to avoid O(n) traversal of m_bindings.
// 3. Return NormalCompletion(empty).
return {};
@ -88,7 +88,7 @@ ThrowCompletionOr<void> DeclarativeEnvironment::create_immutable_binding(GlobalO
// 9.1.1.1.4 InitializeBinding ( N, V ), https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v
ThrowCompletionOr<void> DeclarativeEnvironment::initialize_binding(GlobalObject&, FlyString const& name, Value value)
{
auto index = m_names.find_first_index(name);
auto index = find_binding_index(name);
VERIFY(index.has_value());
auto& binding = m_bindings[*index];
@ -109,7 +109,7 @@ ThrowCompletionOr<void> DeclarativeEnvironment::initialize_binding(GlobalObject&
ThrowCompletionOr<void> DeclarativeEnvironment::set_mutable_binding(GlobalObject& global_object, FlyString const& name, Value value, bool strict)
{
// 1. If envRec does not have a binding for N, then
auto index = m_names.find_first_index(name);
auto index = find_binding_index(name);
if (!index.has_value()) {
// a. If S is true, throw a ReferenceError exception.
if (strict)
@ -139,7 +139,7 @@ ThrowCompletionOr<void> DeclarativeEnvironment::set_mutable_binding_direct(Globa
strict = true;
if (!binding.initialized)
return vm().throw_completion<ReferenceError>(global_object, ErrorType::BindingNotInitialized, m_names[index]);
return vm().throw_completion<ReferenceError>(global_object, ErrorType::BindingNotInitialized, binding.name);
if (binding.mutable_) {
binding.value = value;
@ -155,7 +155,7 @@ ThrowCompletionOr<void> DeclarativeEnvironment::set_mutable_binding_direct(Globa
ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value(GlobalObject& global_object, FlyString const& name, bool strict)
{
// 1. Assert: envRec has a binding for N.
auto index = m_names.find_first_index(name);
auto index = find_binding_index(name);
VERIFY(index.has_value());
// 2-3. (extracted into a non-standard function below)
@ -168,7 +168,7 @@ ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value_direct(Global
// 2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if (!binding.initialized)
return vm().throw_completion<ReferenceError>(global_object, ErrorType::BindingNotInitialized, m_names[index]);
return vm().throw_completion<ReferenceError>(global_object, ErrorType::BindingNotInitialized, binding.name);
// 3. Return the value currently bound to N in envRec.
return binding.value;
@ -178,7 +178,7 @@ ThrowCompletionOr<Value> DeclarativeEnvironment::get_binding_value_direct(Global
ThrowCompletionOr<bool> DeclarativeEnvironment::delete_binding(GlobalObject&, FlyString const& name)
{
// 1. Assert: envRec has a binding for the name that is the value of N.
auto index = m_names.find_first_index(name);
auto index = find_binding_index(name);
VERIFY(index.has_value());
auto& binding = m_bindings[*index];
@ -188,9 +188,8 @@ ThrowCompletionOr<bool> DeclarativeEnvironment::delete_binding(GlobalObject&, Fl
return false;
// 3. Remove the binding for N from envRec.
// NOTE: We keep the entries in m_bindings and m_names to avoid disturbing indices.
// NOTE: We keep the entries in m_bindings to avoid disturbing indices.
binding = {};
m_names[*index] = {};
// 4. Return true.
return true;
@ -198,7 +197,7 @@ ThrowCompletionOr<bool> DeclarativeEnvironment::delete_binding(GlobalObject&, Fl
ThrowCompletionOr<void> DeclarativeEnvironment::initialize_or_set_mutable_binding(GlobalObject& global_object, FlyString const& name, Value value)
{
auto index = m_names.find_first_index(name);
auto index = find_binding_index(name);
VERIFY(index.has_value());
auto& binding = m_bindings[*index];
if (!binding.initialized)