LibJS: Generate bytecode for the BlockDeclarationInstantiation AO

This necessitated adding some new instructions for creating mutable and
immutable bindings.
This commit is contained in:
Andreas Kling 2025-10-25 14:06:48 +02:00 committed by Andreas Kling
parent 892c7d980e
commit 44fa9566a8
Notes: github-actions[bot] 2025-10-27 20:15:37 +00:00
6 changed files with 131 additions and 117 deletions

View file

@ -1621,80 +1621,6 @@ bool ImportStatement::has_bound_name(Utf16FlyString const& name) const
});
}
// 14.2.3 BlockDeclarationInstantiation ( code, env ), https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
void ScopeNode::block_declaration_instantiation(VM& vm, Environment* environment) const
{
// See also B.3.2.6 Changes to BlockDeclarationInstantiation, https://tc39.es/ecma262/#sec-web-compat-blockdeclarationinstantiation
auto& realm = *vm.current_realm();
VERIFY(environment);
// 1. Let declarations be the LexicallyScopedDeclarations of code.
// 2. Let privateEnv be the running execution context's PrivateEnvironment.
auto private_environment = vm.running_execution_context().private_environment;
// Note: All the calls here are ! and thus we do not need to TRY this callback.
// We use MUST to ensure it does not throw and to avoid discarding the returned ThrowCompletionOr<void>.
// 3. For each element d of declarations, do
MUST(for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
auto is_constant_declaration = declaration.is_constant_declaration();
// NOTE: Due to the use of MUST with `create_immutable_binding` and `create_mutable_binding` below,
// an exception should not result from `for_each_bound_name`.
// a. For each element dn of the BoundNames of d, do
MUST(declaration.for_each_bound_identifier([&](Identifier const& identifier) {
if (identifier.is_local()) {
// NOTE: No need to create bindings for local variables as their values are not stored in an environment.
return;
}
auto const& name = identifier.string();
// i. If IsConstantDeclaration of d is true, then
if (is_constant_declaration) {
// 1. Perform ! env.CreateImmutableBinding(dn, true).
MUST(environment->create_immutable_binding(vm, name, true));
}
// ii. Else,
else {
// 1. Perform ! env.CreateMutableBinding(dn, false). NOTE: This step is replaced in section B.3.2.6.
if (!MUST(environment->has_binding(name)))
MUST(environment->create_mutable_binding(vm, name, false));
}
}));
// b. If d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
if (is<FunctionDeclaration>(declaration)) {
// i. Let fn be the sole element of the BoundNames of d.
auto& function_declaration = static_cast<FunctionDeclaration const&>(declaration);
// ii. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
auto function = ECMAScriptFunctionObject::create_from_function_node(
function_declaration,
function_declaration.name(),
realm,
environment,
private_environment);
// iii. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6.
if (function_declaration.name_identifier()->is_local()) {
auto& running_execution_context = vm.running_execution_context();
auto number_of_registers = running_execution_context.executable->number_of_registers;
auto number_of_constants = running_execution_context.executable->constants.size();
auto local_index = function_declaration.name_identifier()->local_index();
if (local_index.is_variable()) {
running_execution_context.local(local_index.index + number_of_registers + number_of_constants) = function;
} else {
VERIFY_NOT_REACHED();
}
} else {
VERIFY(is<DeclarativeEnvironment>(*environment));
static_cast<DeclarativeEnvironment&>(*environment).initialize_or_set_mutable_binding({}, vm, function->name(), function);
}
}
}));
}
// 16.1.7 GlobalDeclarationInstantiation ( script, env ), https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
ThrowCompletionOr<void> Program::global_declaration_instantiation(VM& vm, GlobalEnvironment& global_environment) const
{