mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:18:12 +00:00
LibJS/Bytecode: Leave BlockDeclarationInstantiation in C++
Instead of implementing this AO in bytecode, we now have an instruction for it that simply invokes the C++ implementation. This allows us to simplify Bytecode::Generator quite a bit by removing all the variable scope tracking.
This commit is contained in:
parent
4684d3fe54
commit
ac246d764d
6 changed files with 56 additions and 91 deletions
|
@ -29,62 +29,30 @@ Bytecode::CodeGenerationErrorOr<void> ASTNode::generate_bytecode(Bytecode::Gener
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Optional<Bytecode::CodeGenerationError> maybe_error;
|
||||
size_t pushed_scope_count = 0;
|
||||
auto const failing_completion = Completion(Completion::Type::Throw, {}, {});
|
||||
|
||||
// Note: SwitchStatement has its own codegen, but still calls into this function to handle the scoping of the switch body.
|
||||
auto is_switch_statement = is<SwitchStatement>(*this);
|
||||
bool did_create_lexical_environment = false;
|
||||
|
||||
if (is<BlockStatement>(*this) || is_switch_statement) {
|
||||
// Perform the steps of BlockDeclarationInstantiation.
|
||||
if (has_lexical_declarations()) {
|
||||
generator.begin_variable_scope(Bytecode::Generator::BindingMode::Lexical, Bytecode::Generator::SurroundingScopeKind::Block);
|
||||
pushed_scope_count++;
|
||||
generator.block_declaration_instantiation(*this);
|
||||
did_create_lexical_environment = true;
|
||||
}
|
||||
|
||||
(void)for_each_lexically_scoped_declaration([&](Declaration const& declaration) -> ThrowCompletionOr<void> {
|
||||
auto is_constant_declaration = declaration.is_constant_declaration();
|
||||
// NOTE: Nothing in the callback throws an exception.
|
||||
MUST(declaration.for_each_bound_name([&](auto const& name) {
|
||||
auto index = generator.intern_identifier(name);
|
||||
// NOTE: BlockDeclarationInstantiation takes as input the new lexical environment that was created and checks if there is a binding for the current name only in this new scope.
|
||||
// For example: `{ let a = 1; { let a = 2; } }`. The second `a` will shadow the first `a` instead of re-initializing or setting it.
|
||||
if (is_constant_declaration || !generator.has_binding_in_current_scope(index)) {
|
||||
generator.register_binding(index);
|
||||
generator.emit<Bytecode::Op::CreateVariable>(index, Bytecode::Op::EnvironmentMode::Lexical, is_constant_declaration);
|
||||
}
|
||||
}));
|
||||
|
||||
if (is<FunctionDeclaration>(declaration)) {
|
||||
auto& function_declaration = static_cast<FunctionDeclaration const&>(declaration);
|
||||
auto const& name = function_declaration.name();
|
||||
auto index = generator.intern_identifier(name);
|
||||
generator.emit<Bytecode::Op::NewFunction>(function_declaration);
|
||||
generator.emit<Bytecode::Op::SetVariable>(index, Bytecode::Op::SetVariable::InitializationMode::InitializeOrSet);
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
if (is_switch_statement)
|
||||
return {};
|
||||
|
||||
} else if (is<Program>(*this)) {
|
||||
// GlobalDeclarationInstantiation is handled by the C++ AO.
|
||||
} else {
|
||||
// FunctionDeclarationInstantiation is handled by the C++ AO.
|
||||
}
|
||||
|
||||
if (maybe_error.has_value())
|
||||
return maybe_error.release_value();
|
||||
|
||||
for (auto& child : children()) {
|
||||
TRY(child->generate_bytecode(generator));
|
||||
if (generator.is_current_block_terminated())
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pushed_scope_count; ++i)
|
||||
if (did_create_lexical_environment)
|
||||
generator.end_variable_scope();
|
||||
|
||||
return {};
|
||||
|
@ -788,13 +756,12 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_labelled_evaluation
|
|||
has_lexical_environment = true;
|
||||
|
||||
// FIXME: Is Block correct?
|
||||
generator.begin_variable_scope(Bytecode::Generator::BindingMode::Lexical, Bytecode::Generator::SurroundingScopeKind::Block);
|
||||
generator.begin_variable_scope();
|
||||
|
||||
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);
|
||||
generator.register_binding(index);
|
||||
generator.emit<Bytecode::Op::CreateVariable>(index, Bytecode::Op::EnvironmentMode::Lexical, is_const);
|
||||
}));
|
||||
}
|
||||
|
@ -994,7 +961,7 @@ Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode(Byte
|
|||
Optional<Bytecode::IdentifierTableIndex> name_identifier;
|
||||
|
||||
if (has_name) {
|
||||
generator.begin_variable_scope(Bytecode::Generator::BindingMode::Lexical);
|
||||
generator.begin_variable_scope();
|
||||
|
||||
name_identifier = generator.intern_identifier(name());
|
||||
generator.emit<Bytecode::Op::CreateVariable>(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true);
|
||||
|
@ -2036,12 +2003,11 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode::
|
|||
if (!m_finalizer)
|
||||
generator.emit<Bytecode::Op::LeaveUnwindContext>();
|
||||
|
||||
generator.begin_variable_scope(Bytecode::Generator::BindingMode::Lexical, Bytecode::Generator::SurroundingScopeKind::Block);
|
||||
generator.begin_variable_scope();
|
||||
TRY(m_handler->parameter().visit(
|
||||
[&](DeprecatedFlyString const& parameter) -> Bytecode::CodeGenerationErrorOr<void> {
|
||||
if (!parameter.is_empty()) {
|
||||
auto parameter_identifier = generator.intern_identifier(parameter);
|
||||
generator.register_binding(parameter_identifier);
|
||||
generator.emit<Bytecode::Op::CreateVariable>(parameter_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
|
||||
generator.emit<Bytecode::Op::SetVariable>(parameter_identifier, Bytecode::Op::SetVariable::InitializationMode::Initialize);
|
||||
}
|
||||
|
@ -2313,7 +2279,6 @@ static Bytecode::CodeGenerationErrorOr<ForInOfHeadEvaluationResult> for_in_of_he
|
|||
MUST(variable_declaration.for_each_bound_name([&](auto const& name) {
|
||||
// i. Perform ! newEnv.CreateMutableBinding(name, false).
|
||||
auto identifier = generator.intern_identifier(name);
|
||||
generator.register_binding(identifier);
|
||||
generator.emit<Bytecode::Op::CreateVariable>(identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
|
||||
}));
|
||||
// d. Set the running execution context's LexicalEnvironment to newEnv.
|
||||
|
@ -2461,7 +2426,7 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode:
|
|||
// iii. Let iterationEnv be NewDeclarativeEnvironment(oldEnv).
|
||||
// iv. Perform ForDeclarationBindingInstantiation of lhs with argument iterationEnv.
|
||||
// v. Set the running execution context's LexicalEnvironment to iterationEnv.
|
||||
generator.begin_variable_scope(Bytecode::Generator::BindingMode::Lexical);
|
||||
generator.begin_variable_scope();
|
||||
has_lexical_binding = true;
|
||||
|
||||
// 14.7.5.4 Runtime Semantics: ForDeclarationBindingInstantiation, https://tc39.es/ecma262/#sec-runtime-semantics-fordeclarationbindinginstantiation
|
||||
|
@ -2472,7 +2437,6 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode:
|
|||
// NOTE: Nothing in the callback throws an exception.
|
||||
MUST(variable_declaration.for_each_bound_name([&](auto const& name) {
|
||||
auto identifier = generator.intern_identifier(name);
|
||||
generator.register_binding(identifier, Bytecode::Generator::BindingMode::Lexical);
|
||||
// a. If IsConstantDeclaration of LetOrConst is true, then
|
||||
if (variable_declaration.is_constant_declaration()) {
|
||||
// i. Perform ! environment.CreateImmutableBinding(name, true).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue