Просмотр исходного кода

LibJS/Bytecode: Skip CreateVariable for locals in "for" loop head

CreateVariable is not needed for locals because they are not stored in
environment and created binding will not be used. Also if all variables
in loop initialization sections are local then CreateLexicalEnvironment
and LeaveLexicalEnvironment can also be ommitted.
Aliaksandr Kalenik 2 лет назад
Родитель
Сommit
a1692931af
1 измененных файлов с 42 добавлено и 22 удалено
  1. 42 22
      Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

+ 42 - 22
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -829,7 +829,13 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_labelled_evaluation
         if (m_init->is_variable_declaration()) {
             auto& variable_declaration = verify_cast<VariableDeclaration>(*m_init);
 
-            if (variable_declaration.is_lexical_declaration()) {
+            auto has_non_local_variables = false;
+            MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) {
+                if (!identifier.is_local())
+                    has_non_local_variables = true;
+            }));
+
+            if (variable_declaration.is_lexical_declaration() && has_non_local_variables) {
                 has_lexical_environment = true;
 
                 // FIXME: Is Block correct?
@@ -837,8 +843,10 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_labelled_evaluation
 
                 bool is_const = variable_declaration.is_constant_declaration();
                 // NOTE: Nothing in the callback throws an exception.
-                MUST(variable_declaration.for_each_bound_name([&](auto const& name) {
-                    auto index = generator.intern_identifier(name);
+                MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) {
+                    if (identifier.is_local())
+                        return;
+                    auto index = generator.intern_identifier(identifier.string());
                     generator.emit<Bytecode::Op::CreateVariable>(index, Bytecode::Op::EnvironmentMode::Lexical, is_const);
                 }));
             }
@@ -2528,22 +2536,32 @@ static Bytecode::CodeGenerationErrorOr<ForInOfHeadEvaluationResult> for_in_of_he
                 generator.emit_set_variable(*identifier);
             }
         } else {
-            // 1. Let oldEnv be the running execution context's LexicalEnvironment.
-            // NOTE: 'uninitializedBoundNames' refers to the lexical bindings (i.e. Const/Let) present in the second and last form.
-            // 2. If uninitializedBoundNames is not an empty List, then
-            entered_lexical_scope = true;
-            // a. Assert: uninitializedBoundNames has no duplicate entries.
-            // b. Let newEnv be NewDeclarativeEnvironment(oldEnv).
-            generator.begin_variable_scope();
-            // c. For each String name of uninitializedBoundNames, do
-            // NOTE: Nothing in the callback throws an exception.
-            MUST(variable_declaration.for_each_bound_name([&](auto const& name) {
-                // i. Perform ! newEnv.CreateMutableBinding(name, false).
-                auto identifier = generator.intern_identifier(name);
-                generator.emit<Bytecode::Op::CreateVariable>(identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
+            auto has_non_local_variables = false;
+            MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) {
+                if (!identifier.is_local())
+                    has_non_local_variables = true;
             }));
-            // d. Set the running execution context's LexicalEnvironment to newEnv.
-            // NOTE: Done by CreateLexicalEnvironment.
+
+            if (has_non_local_variables) {
+                // 1. Let oldEnv be the running execution context's LexicalEnvironment.
+                // NOTE: 'uninitializedBoundNames' refers to the lexical bindings (i.e. Const/Let) present in the second and last form.
+                // 2. If uninitializedBoundNames is not an empty List, then
+                entered_lexical_scope = true;
+                // a. Assert: uninitializedBoundNames has no duplicate entries.
+                // b. Let newEnv be NewDeclarativeEnvironment(oldEnv).
+                generator.begin_variable_scope();
+                // c. For each String name of uninitializedBoundNames, do
+                // NOTE: Nothing in the callback throws an exception.
+                MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) {
+                    if (identifier.is_local())
+                        return;
+                    // i. Perform ! newEnv.CreateMutableBinding(name, false).
+                    auto interned_identifier = generator.intern_identifier(identifier.string());
+                    generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
+                }));
+                // d. Set the running execution context's LexicalEnvironment to newEnv.
+                // NOTE: Done by CreateLexicalEnvironment.
+            }
         }
     } else {
         // Runtime Semantics: ForInOfLoopEvaluation, for any of:
@@ -2691,17 +2709,19 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode:
         auto& variable_declaration = static_cast<VariableDeclaration const&>(*lhs.get<NonnullRefPtr<ASTNode const>>());
         // 2. For each element name of the BoundNames of ForBinding, do
         // NOTE: Nothing in the callback throws an exception.
-        MUST(variable_declaration.for_each_bound_name([&](auto const& name) {
-            auto identifier = generator.intern_identifier(name);
+        MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) {
+            if (identifier.is_local())
+                return;
+            auto interned_identifier = generator.intern_identifier(identifier.string());
             // a. If IsConstantDeclaration of LetOrConst is true, then
             if (variable_declaration.is_constant_declaration()) {
                 // i. Perform ! environment.CreateImmutableBinding(name, true).
-                generator.emit<Bytecode::Op::CreateVariable>(identifier, Bytecode::Op::EnvironmentMode::Lexical, true);
+                generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, true);
             }
             // b. Else,
             else {
                 // i. Perform ! environment.CreateMutableBinding(name, false).
-                generator.emit<Bytecode::Op::CreateVariable>(identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
+                generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
             }
         }));
         // 3. Return unused.