mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 10:22:05 -05:00
LibJS: Update bytecode generator to use local variables
- Update ECMAScriptFunctionObject::function_declaration_instantiation to initialize local variables - Introduce GetLocal, SetLocal, TypeofLocal that will be used to operate on local variables. - Update bytecode generator to emit instructions for local variables
This commit is contained in:
parent
0daff637e2
commit
ae3a7fd4b8
8 changed files with 170 additions and 37 deletions
|
@ -221,7 +221,11 @@ Bytecode::CodeGenerationErrorOr<void> UnaryExpression::generate_bytecode(Bytecod
|
|||
case UnaryOp::Typeof:
|
||||
if (is<Identifier>(*m_lhs)) {
|
||||
auto& identifier = static_cast<Identifier const&>(*m_lhs);
|
||||
generator.emit<Bytecode::Op::TypeofVariable>(generator.intern_identifier(identifier.string()));
|
||||
if (identifier.is_local()) {
|
||||
generator.emit<Bytecode::Op::TypeofLocal>(identifier.local_variable_index());
|
||||
} else {
|
||||
generator.emit<Bytecode::Op::TypeofVariable>(generator.intern_identifier(identifier.string()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -291,7 +295,11 @@ Bytecode::CodeGenerationErrorOr<void> RegExpLiteral::generate_bytecode(Bytecode:
|
|||
|
||||
Bytecode::CodeGenerationErrorOr<void> Identifier::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
generator.emit<Bytecode::Op::GetVariable>(generator.intern_identifier(m_string));
|
||||
if (is_local()) {
|
||||
generator.emit<Bytecode::Op::GetLocal>(local_variable_index());
|
||||
} else {
|
||||
generator.emit<Bytecode::Op::GetVariable>(generator.intern_identifier(m_string));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -415,7 +423,7 @@ Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(By
|
|||
// e. Perform ? PutValue(lref, rval).
|
||||
if (is<Identifier>(*lhs)) {
|
||||
auto& identifier = static_cast<Identifier const&>(*lhs);
|
||||
generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier.string()));
|
||||
generator.emit_set_variable(identifier);
|
||||
} else if (is<MemberExpression>(*lhs)) {
|
||||
auto& expression = static_cast<MemberExpression const&>(*lhs);
|
||||
|
||||
|
@ -1043,13 +1051,15 @@ static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_byt
|
|||
if (is_rest) {
|
||||
VERIFY(!initializer);
|
||||
if (name.has<NonnullRefPtr<Identifier const>>()) {
|
||||
auto identifier = name.get<NonnullRefPtr<Identifier const>>()->string();
|
||||
auto interned_identifier = generator.intern_identifier(identifier);
|
||||
auto identifier = name.get<NonnullRefPtr<Identifier const>>();
|
||||
auto interned_identifier = generator.intern_identifier(identifier->string());
|
||||
|
||||
generator.emit_with_extra_register_slots<Bytecode::Op::CopyObjectExcludingProperties>(excluded_property_names.size(), value_reg, excluded_property_names);
|
||||
if (create_variables)
|
||||
if (create_variables) {
|
||||
VERIFY(!identifier->is_local());
|
||||
generator.emit<Bytecode::Op::CreateVariable>(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
|
||||
generator.emit<Bytecode::Op::SetVariable>(interned_identifier, initialization_mode);
|
||||
}
|
||||
generator.emit_set_variable(*identifier, initialization_mode);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -1126,19 +1136,19 @@ static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_byt
|
|||
};
|
||||
}
|
||||
|
||||
auto& identifier = name.get<NonnullRefPtr<Identifier const>>()->string();
|
||||
auto identifier_ref = generator.intern_identifier(identifier);
|
||||
auto const& identifier = *name.get<NonnullRefPtr<Identifier const>>();
|
||||
auto identifier_ref = generator.intern_identifier(identifier.string());
|
||||
if (create_variables)
|
||||
generator.emit<Bytecode::Op::CreateVariable>(identifier_ref, Bytecode::Op::EnvironmentMode::Lexical, false);
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier_ref, initialization_mode);
|
||||
generator.emit_set_variable(identifier, initialization_mode);
|
||||
} else if (alias.has<NonnullRefPtr<MemberExpression const>>()) {
|
||||
TRY(generator.emit_store_to_reference(alias.get<NonnullRefPtr<MemberExpression const>>()));
|
||||
} else {
|
||||
auto& identifier = alias.get<NonnullRefPtr<Identifier const>>()->string();
|
||||
auto identifier_ref = generator.intern_identifier(identifier);
|
||||
auto const& identifier = *alias.get<NonnullRefPtr<Identifier const>>();
|
||||
auto identifier_ref = generator.intern_identifier(identifier.string());
|
||||
if (create_variables)
|
||||
generator.emit<Bytecode::Op::CreateVariable>(identifier_ref, Bytecode::Op::EnvironmentMode::Lexical, false);
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier_ref, initialization_mode);
|
||||
generator.emit_set_variable(identifier, initialization_mode);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
@ -1189,7 +1199,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_byte
|
|||
auto interned_index = generator.intern_identifier(identifier->string());
|
||||
if (create_variables)
|
||||
generator.emit<Bytecode::Op::CreateVariable>(interned_index, Bytecode::Op::EnvironmentMode::Lexical, false);
|
||||
generator.emit<Bytecode::Op::SetVariable>(interned_index, initialization_mode);
|
||||
generator.emit_set_variable(*identifier, initialization_mode);
|
||||
return {};
|
||||
},
|
||||
[&](NonnullRefPtr<BindingPattern const> const& pattern) -> Bytecode::CodeGenerationErrorOr<void> {
|
||||
|
@ -1355,7 +1365,7 @@ static Bytecode::CodeGenerationErrorOr<void> assign_accumulator_to_variable_decl
|
|||
|
||||
return declarator.target().visit(
|
||||
[&](NonnullRefPtr<Identifier const> const& id) -> Bytecode::CodeGenerationErrorOr<void> {
|
||||
generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(id->string()), initialization_mode);
|
||||
generator.emit_set_variable(*id, initialization_mode);
|
||||
return {};
|
||||
},
|
||||
[&](NonnullRefPtr<BindingPattern const> const& pattern) -> Bytecode::CodeGenerationErrorOr<void> {
|
||||
|
@ -2309,7 +2319,7 @@ Bytecode::CodeGenerationErrorOr<void> ClassDeclaration::generate_bytecode(Byteco
|
|||
generator.emit<Bytecode::Op::Store>(accumulator_backup_reg);
|
||||
|
||||
TRY(m_class_expression->generate_bytecode(generator));
|
||||
generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(m_class_expression.ptr()->name()), Bytecode::Op::SetVariable::InitializationMode::Initialize);
|
||||
generator.emit_set_variable(*m_class_expression.ptr()->m_name, Bytecode::Op::SetVariable::InitializationMode::Initialize);
|
||||
|
||||
generator.emit<Bytecode::Op::Load>(accumulator_backup_reg);
|
||||
return {};
|
||||
|
@ -2464,9 +2474,10 @@ static Bytecode::CodeGenerationErrorOr<ForInOfHeadEvaluationResult> for_in_of_he
|
|||
auto& variable = variable_declaration.declarations().first();
|
||||
if (variable->init()) {
|
||||
VERIFY(variable->target().has<NonnullRefPtr<Identifier const>>());
|
||||
auto binding_id = generator.intern_identifier(variable->target().get<NonnullRefPtr<Identifier const>>()->string());
|
||||
TRY(generator.emit_named_evaluation_if_anonymous_function(*variable->init(), binding_id));
|
||||
generator.emit<Bytecode::Op::SetVariable>(binding_id);
|
||||
auto identifier = variable->target().get<NonnullRefPtr<Identifier const>>();
|
||||
auto identifier_table_ref = generator.intern_identifier(identifier->string());
|
||||
TRY(generator.emit_named_evaluation_if_anonymous_function(*variable->init(), identifier_table_ref));
|
||||
generator.emit_set_variable(*identifier);
|
||||
}
|
||||
} else {
|
||||
// 1. Let oldEnv be the running execution context's LexicalEnvironment.
|
||||
|
@ -2652,11 +2663,10 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode:
|
|||
if (!destructuring) {
|
||||
// 1. Assert: lhs binds a single name.
|
||||
// 2. Let lhsName be the sole element of BoundNames of lhs.
|
||||
auto lhs_name = variable_declaration.declarations().first()->target().get<NonnullRefPtr<Identifier const>>()->string();
|
||||
auto lhs_name = variable_declaration.declarations().first()->target().get<NonnullRefPtr<Identifier const>>();
|
||||
// 3. Let lhsRef be ! ResolveBinding(lhsName).
|
||||
// NOTE: We're skipping all the completion stuff that the spec does, as the unwinding mechanism will take case of doing that.
|
||||
auto identifier = generator.intern_identifier(lhs_name);
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical);
|
||||
generator.emit_set_variable(*lhs_name, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical);
|
||||
}
|
||||
}
|
||||
// i. If destructuring is false, then
|
||||
|
|
|
@ -141,7 +141,7 @@ CodeGenerationErrorOr<void> Generator::emit_load_from_reference(JS::ASTNode cons
|
|||
{
|
||||
if (is<Identifier>(node)) {
|
||||
auto& identifier = static_cast<Identifier const&>(node);
|
||||
emit<Bytecode::Op::GetVariable>(intern_identifier(identifier.string()));
|
||||
TRY(identifier.generate_bytecode(*this));
|
||||
return {};
|
||||
}
|
||||
if (is<MemberExpression>(node)) {
|
||||
|
@ -217,7 +217,7 @@ CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const
|
|||
{
|
||||
if (is<Identifier>(node)) {
|
||||
auto& identifier = static_cast<Identifier const&>(node);
|
||||
emit<Bytecode::Op::SetVariable>(intern_identifier(identifier.string()));
|
||||
emit_set_variable(identifier);
|
||||
return {};
|
||||
}
|
||||
if (is<MemberExpression>(node)) {
|
||||
|
@ -306,6 +306,15 @@ CodeGenerationErrorOr<void> Generator::emit_delete_reference(JS::ASTNode const&
|
|||
return {};
|
||||
}
|
||||
|
||||
void Generator::emit_set_variable(JS::Identifier const& identifier, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Op::EnvironmentMode mode)
|
||||
{
|
||||
if (identifier.is_local()) {
|
||||
emit<Bytecode::Op::SetLocal>(identifier.local_variable_index());
|
||||
} else {
|
||||
emit<Bytecode::Op::SetVariable>(intern_identifier(identifier.string()), initialization_mode, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void Generator::generate_break()
|
||||
{
|
||||
bool last_was_finally = false;
|
||||
|
|
|
@ -83,6 +83,8 @@ public:
|
|||
CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&);
|
||||
CodeGenerationErrorOr<void> emit_delete_reference(JS::ASTNode const&);
|
||||
|
||||
void emit_set_variable(JS::Identifier const& identifier, Bytecode::Op::SetVariable::InitializationMode initialization_mode = Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode mode = Bytecode::Op::EnvironmentMode::Lexical);
|
||||
|
||||
void push_home_object(Register);
|
||||
void pop_home_object();
|
||||
void emit_new_function(JS::FunctionExpression const&, Optional<IdentifierTableIndex> lhs_name);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
O(GetObjectPropertyIterator) \
|
||||
O(GetPrivateById) \
|
||||
O(GetVariable) \
|
||||
O(GetLocal) \
|
||||
O(GreaterThan) \
|
||||
O(GreaterThanEquals) \
|
||||
O(HasPrivateId) \
|
||||
|
@ -87,6 +88,7 @@
|
|||
O(RightShift) \
|
||||
O(ScheduleJump) \
|
||||
O(SetVariable) \
|
||||
O(SetLocal) \
|
||||
O(Store) \
|
||||
O(StrictlyEquals) \
|
||||
O(StrictlyInequals) \
|
||||
|
@ -98,6 +100,7 @@
|
|||
O(ToNumeric) \
|
||||
O(Typeof) \
|
||||
O(TypeofVariable) \
|
||||
O(TypeofLocal) \
|
||||
O(UnaryMinus) \
|
||||
O(UnaryPlus) \
|
||||
O(UnsignedRightShift) \
|
||||
|
|
|
@ -422,6 +422,17 @@ ThrowCompletionOr<void> GetVariable::execute_impl(Bytecode::Interpreter& interpr
|
|||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetLocal::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
if (vm.running_execution_context().local_variables[m_index].is_empty()) {
|
||||
auto const& variable_name = vm.running_execution_context().function->local_variables_names()[m_index];
|
||||
return interpreter.vm().throw_completion<ReferenceError>(ErrorType::BindingNotInitialized, variable_name);
|
||||
}
|
||||
interpreter.accumulator() = vm.running_execution_context().local_variables[m_index];
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> DeleteVariable::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
@ -506,6 +517,12 @@ ThrowCompletionOr<void> SetVariable::execute_impl(Bytecode::Interpreter& interpr
|
|||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> SetLocal::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.vm().running_execution_context().local_variables[m_index] = interpreter.accumulator();
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetById::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
@ -1240,6 +1257,14 @@ ThrowCompletionOr<void> TypeofVariable::execute_impl(Bytecode::Interpreter& inte
|
|||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> TypeofLocal::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
auto const& value = vm.running_execution_context().local_variables[m_index];
|
||||
interpreter.accumulator() = MUST_OR_THROW_OOM(PrimitiveString::create(vm, value.typeof()));
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ToNumeric::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.accumulator() = TRY(interpreter.accumulator().to_numeric(interpreter.vm()));
|
||||
|
@ -1335,6 +1360,11 @@ DeprecatedString GetVariable::to_deprecated_string_impl(Bytecode::Executable con
|
|||
return DeprecatedString::formatted("GetVariable {} ({})", m_identifier, executable.identifier_table->get(m_identifier));
|
||||
}
|
||||
|
||||
DeprecatedString GetLocal::to_deprecated_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return DeprecatedString::formatted("GetLocal {}", m_index);
|
||||
}
|
||||
|
||||
DeprecatedString DeleteVariable::to_deprecated_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
return DeprecatedString::formatted("DeleteVariable {} ({})", m_identifier, executable.identifier_table->get(m_identifier));
|
||||
|
@ -1365,6 +1395,11 @@ DeprecatedString SetVariable::to_deprecated_string_impl(Bytecode::Executable con
|
|||
return DeprecatedString::formatted("SetVariable env:{} init:{} {} ({})", mode_string, initialization_mode_name, m_identifier, executable.identifier_table->get(m_identifier));
|
||||
}
|
||||
|
||||
DeprecatedString SetLocal::to_deprecated_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return DeprecatedString::formatted("SetLocal {}", m_index);
|
||||
}
|
||||
|
||||
DeprecatedString PutById::to_deprecated_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
auto kind = m_kind == PropertyKind::Getter
|
||||
|
@ -1652,6 +1687,11 @@ DeprecatedString TypeofVariable::to_deprecated_string_impl(Bytecode::Executable
|
|||
return DeprecatedString::formatted("TypeofVariable {} ({})", m_identifier, executable.identifier_table->get(m_identifier));
|
||||
}
|
||||
|
||||
DeprecatedString TypeofLocal::to_deprecated_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return DeprecatedString::formatted("TypeofLocal {}", m_index);
|
||||
}
|
||||
|
||||
DeprecatedString ToNumeric::to_deprecated_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return "ToNumeric"sv;
|
||||
|
|
|
@ -484,6 +484,25 @@ private:
|
|||
InitializationMode m_initialization_mode { InitializationMode::Set };
|
||||
};
|
||||
|
||||
class SetLocal final : public Instruction {
|
||||
public:
|
||||
explicit SetLocal(size_t index)
|
||||
: Instruction(Type::SetLocal)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
void replace_references_impl(Register, Register) { }
|
||||
|
||||
size_t index() const { return m_index; }
|
||||
|
||||
private:
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
class GetVariable final : public Instruction {
|
||||
public:
|
||||
explicit GetVariable(IdentifierTableIndex identifier)
|
||||
|
@ -505,6 +524,25 @@ private:
|
|||
Optional<EnvironmentCoordinate> mutable m_cached_environment_coordinate;
|
||||
};
|
||||
|
||||
class GetLocal final : public Instruction {
|
||||
public:
|
||||
explicit GetLocal(size_t index)
|
||||
: Instruction(Type::GetLocal)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
void replace_references_impl(Register, Register) { }
|
||||
|
||||
size_t index() const { return m_index; }
|
||||
|
||||
private:
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
class DeleteVariable final : public Instruction {
|
||||
public:
|
||||
explicit DeleteVariable(IdentifierTableIndex identifier)
|
||||
|
@ -1338,6 +1376,23 @@ private:
|
|||
IdentifierTableIndex m_identifier;
|
||||
};
|
||||
|
||||
class TypeofLocal final : public Instruction {
|
||||
public:
|
||||
explicit TypeofLocal(size_t index)
|
||||
: Instruction(Type::TypeofLocal)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
void replace_references_impl(Register, Register) { }
|
||||
|
||||
private:
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
|
|
@ -184,6 +184,7 @@ class HeapBlock;
|
|||
struct ImportEntry;
|
||||
class ImportStatement;
|
||||
class Interpreter;
|
||||
class Identifier;
|
||||
class Intrinsics;
|
||||
struct IteratorRecord;
|
||||
class MetaProperty;
|
||||
|
|
|
@ -503,10 +503,14 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
if (scope_body) {
|
||||
// NOTE: Due to the use of MUST with `create_mutable_binding` and `initialize_binding` below,
|
||||
// an exception should not result from `for_each_var_declared_name`.
|
||||
MUST(scope_body->for_each_var_declared_name([&](auto const& name) {
|
||||
if (!parameter_names.contains(name) && instantiated_var_names.set(name) == AK::HashSetResult::InsertedNewEntry) {
|
||||
MUST(environment->create_mutable_binding(vm, name, false));
|
||||
MUST(environment->initialize_binding(vm, name, js_undefined(), Environment::InitializeBindingHint::Normal));
|
||||
MUST(scope_body->for_each_var_declared_identifier([&](auto const& id) {
|
||||
if (!parameter_names.contains(id.string()) && instantiated_var_names.set(id.string()) == AK::HashSetResult::InsertedNewEntry) {
|
||||
if (vm.bytecode_interpreter_if_exists() && id.is_local()) {
|
||||
callee_context.local_variables[id.local_variable_index()] = js_undefined();
|
||||
} else {
|
||||
MUST(environment->create_mutable_binding(vm, id.string(), false));
|
||||
MUST(environment->initialize_binding(vm, id.string(), js_undefined(), Environment::InitializeBindingHint::Normal));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -518,18 +522,23 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
if (scope_body) {
|
||||
// NOTE: Due to the use of MUST with `create_mutable_binding`, `get_binding_value` and `initialize_binding` below,
|
||||
// an exception should not result from `for_each_var_declared_name`.
|
||||
MUST(scope_body->for_each_var_declared_name([&](auto const& name) {
|
||||
if (instantiated_var_names.set(name) != AK::HashSetResult::InsertedNewEntry)
|
||||
MUST(scope_body->for_each_var_declared_identifier([&](auto const& id) {
|
||||
if (instantiated_var_names.set(id.string()) != AK::HashSetResult::InsertedNewEntry)
|
||||
return;
|
||||
MUST(var_environment->create_mutable_binding(vm, name, false));
|
||||
MUST(var_environment->create_mutable_binding(vm, id.string(), false));
|
||||
|
||||
Value initial_value;
|
||||
if (!parameter_names.contains(name) || function_names.contains(name))
|
||||
if (!parameter_names.contains(id.string()) || function_names.contains(id.string()))
|
||||
initial_value = js_undefined();
|
||||
else
|
||||
initial_value = MUST(environment->get_binding_value(vm, name, false));
|
||||
initial_value = MUST(environment->get_binding_value(vm, id.string(), false));
|
||||
|
||||
MUST(var_environment->initialize_binding(vm, name, initial_value, Environment::InitializeBindingHint::Normal));
|
||||
if (vm.bytecode_interpreter_if_exists() && id.is_local()) {
|
||||
// NOTE: Local variables are supported only in bytecode interpreter
|
||||
callee_context.local_variables[id.local_variable_index()] = initial_value;
|
||||
} else {
|
||||
MUST(var_environment->initialize_binding(vm, id.string(), initial_value, Environment::InitializeBindingHint::Normal));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -586,11 +595,15 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
MUST(scope_body->for_each_lexically_scoped_declaration([&](Declaration const& 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`.
|
||||
MUST(declaration.for_each_bound_name([&](auto const& name) {
|
||||
MUST(declaration.for_each_bound_identifier([&](auto const& id) {
|
||||
if (vm.bytecode_interpreter_if_exists() && id.is_local()) {
|
||||
// NOTE: Local variables are supported only in bytecode interpreter
|
||||
return;
|
||||
}
|
||||
if (declaration.is_constant_declaration())
|
||||
MUST(lex_environment->create_immutable_binding(vm, name, true));
|
||||
MUST(lex_environment->create_immutable_binding(vm, id.string(), true));
|
||||
else
|
||||
MUST(lex_environment->create_mutable_binding(vm, name, false));
|
||||
MUST(lex_environment->create_mutable_binding(vm, id.string(), false));
|
||||
}));
|
||||
}));
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue