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

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.
This commit is contained in:
Aliaksandr Kalenik 2023-07-13 21:30:36 +02:00 committed by Andreas Kling
parent 6b191ab73d
commit a1692931af

View file

@ -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.