From fa6c06ce8de4972cda93af9557a6ad6c0dd58d49 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 8 Oct 2021 12:49:10 +0200 Subject: [PATCH] LibJS: Elide some declarative environments in ECMAScript function calls By spec, calling an ECMAScript function object in non-strict mode should always create a new top-level declarative environment, even if there are no lexically scoped bindings (let/const) that belong in it. This is used for scope disambiguation in direct eval() calls. However, if there are no direct eval() calls within the function, and no lexically scoped bindings, we can simply not allocate the extra environment and save ourselves the trouble. --- .../Runtime/ECMAScriptFunctionObject.cpp | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index ba8fb91805..1691ce4dae 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -345,11 +345,28 @@ ThrowCompletionOr ECMAScriptFunctionObject::function_declaration_instantia Environment* lex_environment; - if (!is_strict_mode()) - lex_environment = new_declarative_environment(*var_environment); - else + // 30. If strict is false, then + if (!is_strict_mode()) { + // Optimization: We avoid creating empty top-level declarative environments in non-strict mode, if both of these conditions are true: + // 1. there is no direct call to eval() within this function + // 2. there are no lexical declarations that would go into the environment + bool can_elide_declarative_environment = !m_contains_direct_call_to_eval && (!scope_body || !scope_body->has_lexical_declarations()); + if (can_elide_declarative_environment) { + lex_environment = var_environment; + } else { + // a. Let lexEnv be NewDeclarativeEnvironment(varEnv). + // b. NOTE: Non-strict functions use a separate Environment Record for top-level lexical declarations so that a direct eval + // can determine whether any var scoped declarations introduced by the eval code conflict with pre-existing top-level + // lexically scoped declarations. This is not needed for strict functions because a strict direct eval always places + // all declarations into a new Environment Record. + lex_environment = new_declarative_environment(*var_environment); + } + } else { + // 31. Else, let lexEnv be varEnv. lex_environment = var_environment; + } + // 32. Set the LexicalEnvironment of calleeContext to lexEnv. callee_context.lexical_environment = lex_environment; if (!scope_body)