LibJS/Bytecode: Split SetVariable into four separate instructions

Instead of SetVariable having 2x2 modes for variable/lexical and
initialize/set, those 4 modes are now separate instructions, which
makes each instruction much less branchy.
This commit is contained in:
Andreas Kling 2024-05-14 11:30:30 +02:00
parent 640f195a70
commit b7c04f999a
8 changed files with 203 additions and 96 deletions

View file

@ -647,7 +647,7 @@ struct BindingPattern : RefCounted<BindingPattern> {
bool contains_expression() const;
Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::ScopedOperand const& object, bool create_variables) const;
Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&, Bytecode::Op::BindingInitializationMode initialization_mode, Bytecode::ScopedOperand const& object, bool create_variables) const;
Vector<BindingEntry> entries;
Kind kind { Kind::Object };

View file

@ -585,7 +585,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> AssignmentExpression::g
auto rval = TRY(m_rhs->generate_bytecode(generator)).value();
// 5. Perform ? DestructuringAssignmentEvaluation of assignmentPattern with argument rval.
TRY(pattern->generate_bytecode(generator, Bytecode::Op::SetVariable::InitializationMode::Set, rval, false));
TRY(pattern->generate_bytecode(generator, Bytecode::Op::BindingInitializationMode::Set, rval, false));
// 6. Return rval.
return rval;
@ -1151,7 +1151,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> FunctionDeclaration::ge
auto index = generator.intern_identifier(name());
auto value = generator.allocate_register();
generator.emit<Bytecode::Op::GetVariable>(value, index);
generator.emit<Bytecode::Op::SetVariable>(index, value, Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode::Var);
generator.emit<Bytecode::Op::SetVariableBinding>(index, value);
}
return Optional<ScopedOperand> {};
}
@ -1173,7 +1173,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> FunctionExpression::gen
generator.emit_new_function(new_function, *this, lhs_name);
if (has_name) {
generator.emit<Bytecode::Op::SetVariable>(*name_identifier, new_function, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical);
generator.emit<Bytecode::Op::InitializeLexicalBinding>(*name_identifier, new_function);
generator.end_variable_scope();
}
@ -1186,7 +1186,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> FunctionExpression::gen
return generate_bytecode_with_lhs_name(generator, {}, preferred_dst);
}
static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, ScopedOperand const& object, bool create_variables)
static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::BindingInitializationMode initialization_mode, ScopedOperand const& object, bool create_variables)
{
generator.emit<Bytecode::Op::ThrowIfNullish>(object);
@ -1300,7 +1300,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_byt
return {};
}
static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, ScopedOperand const& input_array, bool create_variables, [[maybe_unused]] Optional<ScopedOperand> preferred_dst = {})
static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::BindingInitializationMode initialization_mode, ScopedOperand const& input_array, bool create_variables, [[maybe_unused]] Optional<ScopedOperand> preferred_dst = {})
{
/*
* Consider the following destructuring assignment:
@ -1476,7 +1476,7 @@ static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_byte
return {};
}
Bytecode::CodeGenerationErrorOr<void> BindingPattern::generate_bytecode(Bytecode::Generator& generator, Bytecode::Op::SetVariable::InitializationMode initialization_mode, ScopedOperand const& input_value, bool create_variables) const
Bytecode::CodeGenerationErrorOr<void> BindingPattern::generate_bytecode(Bytecode::Generator& generator, Bytecode::Op::BindingInitializationMode initialization_mode, ScopedOperand const& input_value, bool create_variables) const
{
if (kind == Kind::Object)
return generate_object_binding_pattern_bytecode(generator, *this, initialization_mode, input_value, create_variables);
@ -1486,7 +1486,7 @@ Bytecode::CodeGenerationErrorOr<void> BindingPattern::generate_bytecode(Bytecode
static Bytecode::CodeGenerationErrorOr<void> assign_value_to_variable_declarator(Bytecode::Generator& generator, VariableDeclarator const& declarator, VariableDeclaration const& declaration, ScopedOperand value)
{
auto initialization_mode = declaration.is_lexical_declaration() ? Bytecode::Op::SetVariable::InitializationMode::Initialize : Bytecode::Op::SetVariable::InitializationMode::Set;
auto initialization_mode = declaration.is_lexical_declaration() ? Bytecode::Op::BindingInitializationMode::Initialize : Bytecode::Op::BindingInitializationMode::Set;
return declarator.target().visit(
[&](NonnullRefPtr<Identifier const> const& id) -> Bytecode::CodeGenerationErrorOr<void> {
@ -2569,14 +2569,14 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TryStatement::generate_
did_create_variable_scope_for_catch_clause = true;
auto parameter_identifier = generator.intern_identifier(parameter);
generator.emit<Bytecode::Op::CreateVariable>(parameter_identifier, Bytecode::Op::EnvironmentMode::Lexical, false);
generator.emit<Bytecode::Op::SetVariable>(parameter_identifier, caught_value, Bytecode::Op::SetVariable::InitializationMode::Initialize);
generator.emit<Bytecode::Op::InitializeLexicalBinding>(parameter_identifier, caught_value);
}
return {};
},
[&](NonnullRefPtr<BindingPattern const> const& binding_pattern) -> Bytecode::CodeGenerationErrorOr<void> {
generator.begin_variable_scope();
did_create_variable_scope_for_catch_clause = true;
TRY(binding_pattern->generate_bytecode(generator, Bytecode::Op::SetVariable::InitializationMode::Initialize, caught_value, true));
TRY(binding_pattern->generate_bytecode(generator, Bytecode::Op::BindingInitializationMode::Initialize, caught_value, true));
return {};
}));
@ -2763,7 +2763,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ClassDeclaration::gener
{
Bytecode::Generator::SourceLocationScope scope(generator, *this);
auto value = TRY(m_class_expression->generate_bytecode(generator)).value();
generator.emit_set_variable(*m_class_expression.ptr()->m_name, value, Bytecode::Op::SetVariable::InitializationMode::Initialize);
generator.emit_set_variable(*m_class_expression.ptr()->m_name, value, Bytecode::Op::BindingInitializationMode::Initialize);
// NOTE: ClassDeclaration does not produce a value.
return Optional<ScopedOperand> {};
}
@ -3130,7 +3130,7 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> for_in_of_body_e
TRY(generator.emit_store_to_reference(**ptr, next_value));
} else {
auto& binding_pattern = lhs.get<NonnullRefPtr<BindingPattern const>>();
TRY(binding_pattern->generate_bytecode(generator, Bytecode::Op::SetVariable::InitializationMode::Set, next_value, false));
TRY(binding_pattern->generate_bytecode(generator, Bytecode::Op::BindingInitializationMode::Set, next_value, false));
}
}
}
@ -3186,7 +3186,7 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> for_in_of_body_e
// 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.
generator.emit_set_variable(*lhs_name, next_value, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical);
generator.emit_set_variable(*lhs_name, next_value, Bytecode::Op::BindingInitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical);
}
}
// i. If destructuring is false, then
@ -3217,7 +3217,7 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> for_in_of_body_e
auto& binding_pattern = declaration.declarations().first()->target().get<NonnullRefPtr<BindingPattern const>>();
(void)TRY(binding_pattern->generate_bytecode(
generator,
head_result.lhs_kind == LHSKind::VarBinding ? Bytecode::Op::SetVariable::InitializationMode::Set : Bytecode::Op::SetVariable::InitializationMode::Initialize,
head_result.lhs_kind == LHSKind::VarBinding ? Bytecode::Op::BindingInitializationMode::Set : Bytecode::Op::BindingInitializationMode::Initialize,
next_value,
false));
} else {
@ -3466,10 +3466,9 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ExportStatement::genera
auto value = TRY(generator.emit_named_evaluation_if_anonymous_function(static_cast<ClassExpression const&>(*m_statement), generator.intern_identifier("default"sv))).value();
if (!static_cast<ClassExpression const&>(*m_statement).has_name()) {
generator.emit<Bytecode::Op::SetVariable>(
generator.emit<Bytecode::Op::InitializeLexicalBinding>(
generator.intern_identifier(ExportStatement::local_name_for_default),
value,
Bytecode::Op::SetVariable::InitializationMode::Initialize);
value);
}
return value;
@ -3478,10 +3477,9 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> ExportStatement::genera
// ExportDeclaration : export default AssignmentExpression ;
VERIFY(is<Expression>(*m_statement));
auto value = TRY(generator.emit_named_evaluation_if_anonymous_function(static_cast<Expression const&>(*m_statement), generator.intern_identifier("default"sv))).value();
generator.emit<Bytecode::Op::SetVariable>(
generator.emit<Bytecode::Op::InitializeLexicalBinding>(
generator.intern_identifier(ExportStatement::local_name_for_default),
value,
Bytecode::Op::SetVariable::InitializationMode::Initialize);
value);
return value;
}

View file

@ -399,29 +399,6 @@ inline ThrowCompletionOr<Value> typeof_variable(VM& vm, DeprecatedFlyString cons
return PrimitiveString::create(vm, value.typeof());
}
inline ThrowCompletionOr<void> set_variable(
VM& vm,
DeprecatedFlyString const& name,
Value value,
Op::EnvironmentMode mode,
Op::SetVariable::InitializationMode initialization_mode,
EnvironmentCoordinate& cache)
{
auto environment = mode == Op::EnvironmentMode::Lexical ? vm.running_execution_context().lexical_environment : vm.running_execution_context().variable_environment;
auto reference = TRY(vm.resolve_binding(name, environment));
if (reference.environment_coordinate().has_value())
cache = reference.environment_coordinate().value();
switch (initialization_mode) {
case Op::SetVariable::InitializationMode::Initialize:
TRY(reference.initialize_referenced_binding(vm, value));
break;
case Op::SetVariable::InitializationMode::Set:
TRY(reference.put_value(vm, value));
break;
}
return {};
}
inline Value new_function(VM& vm, FunctionNode const& function_node, Optional<IdentifierTableIndex> const& lhs_name, Optional<Operand> const& home_object)
{
Value value;

View file

@ -39,7 +39,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
auto id = intern_identifier(parameter_name.key);
emit<Op::CreateVariable>(id, Op::EnvironmentMode::Lexical, false);
if (function.m_has_duplicates) {
emit<Op::SetVariable>(id, add_constant(js_undefined()), Op::SetVariable::InitializationMode::Initialize, Op::EnvironmentMode::Lexical);
emit<Op::InitializeLexicalBinding>(id, add_constant(js_undefined()));
}
}
}
@ -87,17 +87,18 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
set_local_initialized((*identifier)->local_variable_index());
} else {
auto id = intern_identifier((*identifier)->string());
auto init_mode = function.m_has_duplicates ? Op::SetVariable::InitializationMode::Set : Op::SetVariable::InitializationMode::Initialize;
auto argument_reg = allocate_register();
emit<Op::GetArgument>(argument_reg.operand(), param_index);
emit<Op::SetVariable>(id, argument_reg.operand(),
init_mode,
Op::EnvironmentMode::Lexical);
if (function.m_has_duplicates) {
emit<Op::SetLexicalBinding>(id, argument_reg.operand());
} else {
emit<Op::InitializeLexicalBinding>(id, argument_reg.operand());
}
}
} else if (auto const* binding_pattern = parameter.binding.get_pointer<NonnullRefPtr<BindingPattern const>>(); binding_pattern) {
auto input_operand = allocate_register();
emit<Op::GetArgument>(input_operand.operand(), param_index);
auto init_mode = function.m_has_duplicates ? Op::SetVariable::InitializationMode::Set : Bytecode::Op::SetVariable::InitializationMode::Initialize;
auto init_mode = function.m_has_duplicates ? Op::BindingInitializationMode::Set : Bytecode::Op::BindingInitializationMode::Initialize;
TRY((*binding_pattern)->generate_bytecode(*this, init_mode, input_operand, false));
}
}
@ -115,7 +116,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
} else {
auto intern_id = intern_identifier(id.string());
emit<Op::CreateVariable>(intern_id, Op::EnvironmentMode::Var, false);
emit<Op::SetVariable>(intern_id, add_constant(js_undefined()), Bytecode::Op::SetVariable::InitializationMode::Initialize, Op::EnvironmentMode::Var);
emit<Op::InitializeVariableBinding>(intern_id, add_constant(js_undefined()));
}
}
}
@ -141,7 +142,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
} else {
auto intern_id = intern_identifier(id.string());
emit<Op::CreateVariable>(intern_id, Op::EnvironmentMode::Var, false);
emit<Op::SetVariable>(intern_id, initial_value, Op::SetVariable::InitializationMode::Initialize, Op::EnvironmentMode::Var);
emit<Op::InitializeVariableBinding>(intern_id, initial_value);
}
}
}
@ -151,7 +152,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
for (auto const& function_name : function.m_function_names_to_initialize_binding) {
auto intern_id = intern_identifier(function_name);
emit<Op::CreateVariable>(intern_id, Op::EnvironmentMode::Var, false);
emit<Op::SetVariable>(intern_id, add_constant(js_undefined()), Bytecode::Op::SetVariable::InitializationMode::Initialize, Op::EnvironmentMode::Var);
emit<Op::InitializeVariableBinding>(intern_id, add_constant(js_undefined()));
}
}
@ -184,7 +185,7 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
if (declaration.name_identifier()->is_local()) {
emit<Op::Mov>(local(declaration.name_identifier()->local_variable_index()), function);
} else {
emit<Op::SetVariable>(intern_identifier(declaration.name()), function, Op::SetVariable::InitializationMode::Set, Op::EnvironmentMode::Var);
emit<Op::SetVariableBinding>(intern_identifier(declaration.name()), function);
}
}
@ -808,7 +809,7 @@ CodeGenerationErrorOr<Optional<ScopedOperand>> Generator::emit_delete_reference(
return add_constant(Value(true));
}
void Generator::emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Op::EnvironmentMode mode)
void Generator::emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::BindingInitializationMode initialization_mode, Bytecode::Op::EnvironmentMode environment_mode)
{
if (identifier.is_local()) {
if (value.operand().is_local() && value.operand().index() == identifier.local_variable_index()) {
@ -817,7 +818,22 @@ void Generator::emit_set_variable(JS::Identifier const& identifier, ScopedOperan
}
emit<Bytecode::Op::Mov>(local(identifier.local_variable_index()), value);
} else {
emit<Bytecode::Op::SetVariable>(intern_identifier(identifier.string()), value, initialization_mode, mode);
auto identifier_index = intern_identifier(identifier.string());
if (environment_mode == Bytecode::Op::EnvironmentMode::Lexical) {
if (initialization_mode == Bytecode::Op::BindingInitializationMode::Initialize) {
emit<Bytecode::Op::InitializeLexicalBinding>(identifier_index, value);
} else if (initialization_mode == Bytecode::Op::BindingInitializationMode::Set) {
emit<Bytecode::Op::SetLexicalBinding>(identifier_index, value);
}
} else if (environment_mode == Bytecode::Op::EnvironmentMode::Var) {
if (initialization_mode == Bytecode::Op::BindingInitializationMode::Initialize) {
emit<Bytecode::Op::InitializeVariableBinding>(identifier_index, value);
} else if (initialization_mode == Bytecode::Op::BindingInitializationMode::Set) {
emit<Bytecode::Op::SetVariableBinding>(identifier_index, value);
}
} else {
VERIFY_NOT_REACHED();
}
}
}

View file

@ -144,7 +144,7 @@ public:
CodeGenerationErrorOr<ReferenceOperands> emit_super_reference(MemberExpression const&);
void emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::SetVariable::InitializationMode initialization_mode = Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode mode = Bytecode::Op::EnvironmentMode::Lexical);
void emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::BindingInitializationMode initialization_mode = Bytecode::Op::BindingInitializationMode::Set, Bytecode::Op::EnvironmentMode mode = Bytecode::Op::EnvironmentMode::Lexical);
void push_home_object(ScopedOperand);
void pop_home_object();

View file

@ -70,6 +70,8 @@
O(ImportCall) \
O(In) \
O(Increment) \
O(InitializeLexicalBinding) \
O(InitializeVariableBinding) \
O(InstanceOf) \
O(IteratorClose) \
O(IteratorNext) \
@ -122,7 +124,8 @@
O(RightShift) \
O(ScheduleJump) \
O(SetArgument) \
O(SetVariable) \
O(SetLexicalBinding) \
O(SetVariableBinding) \
O(StrictlyEquals) \
O(StrictlyInequals) \
O(Sub) \

View file

@ -584,6 +584,8 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
HANDLE_INSTRUCTION(ImportCall);
HANDLE_INSTRUCTION(In);
HANDLE_INSTRUCTION(Increment);
HANDLE_INSTRUCTION(InitializeLexicalBinding);
HANDLE_INSTRUCTION(InitializeVariableBinding);
HANDLE_INSTRUCTION(InstanceOf);
HANDLE_INSTRUCTION(IteratorClose);
HANDLE_INSTRUCTION(IteratorNext);
@ -618,7 +620,8 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
HANDLE_INSTRUCTION(ResolveThisBinding);
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(RestoreScheduledJump);
HANDLE_INSTRUCTION(RightShift);
HANDLE_INSTRUCTION(SetVariable);
HANDLE_INSTRUCTION(SetLexicalBinding);
HANDLE_INSTRUCTION(SetVariableBinding);
HANDLE_INSTRUCTION(StrictlyEquals);
HANDLE_INSTRUCTION(StrictlyInequals);
HANDLE_INSTRUCTION(Sub);
@ -1376,38 +1379,60 @@ ThrowCompletionOr<void> CreateArguments::execute_impl(Bytecode::Interpreter& int
return {};
}
ThrowCompletionOr<void> SetVariable::execute_impl(Bytecode::Interpreter& interpreter) const
template<EnvironmentMode environment_mode, BindingInitializationMode initialization_mode>
static ThrowCompletionOr<void> initialize_or_set_binding(Interpreter& interpreter, IdentifierTableIndex identifier_index, Value value, EnvironmentCoordinate& cache)
{
auto& vm = interpreter.vm();
if (m_cache.is_valid()) {
auto* environment = m_mode == EnvironmentMode::Lexical
? interpreter.running_execution_context().lexical_environment.ptr()
: interpreter.running_execution_context().variable_environment.ptr();
for (size_t i = 0; i < m_cache.hops; ++i)
auto* environment = environment_mode == EnvironmentMode::Lexical
? interpreter.running_execution_context().lexical_environment.ptr()
: interpreter.running_execution_context().variable_environment.ptr();
if (cache.is_valid()) {
for (size_t i = 0; i < cache.hops; ++i)
environment = environment->outer_environment();
if (!environment->is_permanently_screwed_by_eval()) {
auto value = interpreter.get(src());
if (m_initialization_mode == InitializationMode::Initialize) {
TRY(static_cast<DeclarativeEnvironment&>(*environment).initialize_binding_direct(vm, m_cache.index, value, Environment::InitializeBindingHint::Normal));
return {};
if constexpr (initialization_mode == BindingInitializationMode::Initialize) {
TRY(static_cast<DeclarativeEnvironment&>(*environment).initialize_binding_direct(vm, cache.index, value, Environment::InitializeBindingHint::Normal));
} else {
TRY(static_cast<DeclarativeEnvironment&>(*environment).set_mutable_binding_direct(vm, cache.index, value, vm.in_strict_mode()));
}
TRY(static_cast<DeclarativeEnvironment&>(*environment).set_mutable_binding_direct(vm, m_cache.index, value, vm.in_strict_mode()));
return {};
}
m_cache = {};
cache = {};
}
auto const& name = interpreter.current_executable().get_identifier(m_identifier);
TRY(set_variable(vm,
name,
interpreter.get(src()),
m_mode,
m_initialization_mode,
m_cache));
auto reference = TRY(vm.resolve_binding(interpreter.current_executable().get_identifier(identifier_index), environment));
if (reference.environment_coordinate().has_value())
cache = reference.environment_coordinate().value();
if constexpr (initialization_mode == BindingInitializationMode::Initialize) {
TRY(reference.initialize_referenced_binding(vm, value));
} else if (initialization_mode == BindingInitializationMode::Set) {
TRY(reference.put_value(vm, value));
}
return {};
}
ThrowCompletionOr<void> InitializeLexicalBinding::execute_impl(Bytecode::Interpreter& interpreter) const
{
return initialize_or_set_binding<EnvironmentMode::Lexical, BindingInitializationMode::Initialize>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
}
ThrowCompletionOr<void> InitializeVariableBinding::execute_impl(Bytecode::Interpreter& interpreter) const
{
return initialize_or_set_binding<EnvironmentMode::Var, BindingInitializationMode::Initialize>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
}
ThrowCompletionOr<void> SetLexicalBinding::execute_impl(Bytecode::Interpreter& interpreter) const
{
return initialize_or_set_binding<EnvironmentMode::Lexical, BindingInitializationMode::Set>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
}
ThrowCompletionOr<void> SetVariableBinding::execute_impl(Bytecode::Interpreter& interpreter) const
{
return initialize_or_set_binding<EnvironmentMode::Var, BindingInitializationMode::Set>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
}
ThrowCompletionOr<void> SetArgument::execute_impl(Bytecode::Interpreter&) const
{
// Handled in the interpreter loop.
@ -2152,14 +2177,32 @@ ByteString EnterObjectEnvironment::to_byte_string_impl(Executable const& executa
format_operand("object"sv, m_object, executable));
}
ByteString SetVariable::to_byte_string_impl(Bytecode::Executable const& executable) const
ByteString InitializeLexicalBinding::to_byte_string_impl(Bytecode::Executable const& executable) const
{
auto initialization_mode_name = m_initialization_mode == InitializationMode::Initialize ? "Initialize" : "Set";
auto mode_string = m_mode == EnvironmentMode::Lexical ? "Lexical" : "Variable";
return ByteString::formatted("SetVariable {}, {}, env:{} init:{}",
return ByteString::formatted("InitializeLexicalBinding {}, {}",
executable.identifier_table->get(m_identifier),
format_operand("src"sv, src(), executable),
mode_string, initialization_mode_name);
format_operand("src"sv, src(), executable));
}
ByteString InitializeVariableBinding::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("InitializeVariableBinding {}, {}",
executable.identifier_table->get(m_identifier),
format_operand("src"sv, src(), executable));
}
ByteString SetLexicalBinding::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("SetLexicalBinding {}, {}",
executable.identifier_table->get(m_identifier),
format_operand("src"sv, src(), executable));
}
ByteString SetVariableBinding::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("SetVariableBinding {}, {}",
executable.identifier_table->get(m_identifier),
format_operand("src"sv, src(), executable));
}
ByteString GetArgument::to_byte_string_impl(Bytecode::Executable const& executable) const

View file

@ -528,6 +528,11 @@ enum class EnvironmentMode {
Var,
};
enum class BindingInitializationMode {
Initialize,
Set,
};
class CreateLexicalEnvironment final : public Instruction {
public:
explicit CreateLexicalEnvironment(u32 capacity = 0)
@ -664,18 +669,87 @@ private:
bool m_is_strict { false };
};
class SetVariable final : public Instruction {
class InitializeLexicalBinding final : public Instruction {
public:
enum class InitializationMode {
Initialize,
Set,
};
explicit SetVariable(IdentifierTableIndex identifier, Operand src, InitializationMode initialization_mode = InitializationMode::Set, EnvironmentMode mode = EnvironmentMode::Lexical)
: Instruction(Type::SetVariable)
explicit InitializeLexicalBinding(IdentifierTableIndex identifier, Operand src)
: Instruction(Type::InitializeLexicalBinding)
, m_identifier(identifier)
, m_src(src)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_src);
}
IdentifierTableIndex identifier() const { return m_identifier; }
Operand src() const { return m_src; }
private:
IdentifierTableIndex m_identifier;
Operand m_src;
mutable EnvironmentCoordinate m_cache;
};
class InitializeVariableBinding final : public Instruction {
public:
explicit InitializeVariableBinding(IdentifierTableIndex identifier, Operand src)
: Instruction(Type::InitializeVariableBinding)
, m_identifier(identifier)
, m_src(src)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_src);
}
IdentifierTableIndex identifier() const { return m_identifier; }
Operand src() const { return m_src; }
private:
IdentifierTableIndex m_identifier;
Operand m_src;
mutable EnvironmentCoordinate m_cache;
};
class SetLexicalBinding final : public Instruction {
public:
explicit SetLexicalBinding(IdentifierTableIndex identifier, Operand src)
: Instruction(Type::SetLexicalBinding)
, m_identifier(identifier)
, m_src(src)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
void visit_operands_impl(Function<void(Operand&)> visitor)
{
visitor(m_src);
}
IdentifierTableIndex identifier() const { return m_identifier; }
Operand src() const { return m_src; }
private:
IdentifierTableIndex m_identifier;
Operand m_src;
mutable EnvironmentCoordinate m_cache;
};
class SetVariableBinding final : public Instruction {
public:
explicit SetVariableBinding(IdentifierTableIndex identifier, Operand src)
: Instruction(Type::SetVariableBinding)
, m_identifier(identifier)
, m_src(src)
, m_mode(mode)
, m_initialization_mode(initialization_mode)
{
}
@ -688,14 +762,10 @@ public:
IdentifierTableIndex identifier() const { return m_identifier; }
Operand src() const { return m_src; }
EnvironmentMode mode() const { return m_mode; }
InitializationMode initialization_mode() const { return m_initialization_mode; }
private:
IdentifierTableIndex m_identifier;
Operand m_src;
EnvironmentMode m_mode;
InitializationMode m_initialization_mode { InitializationMode::Set };
mutable EnvironmentCoordinate m_cache;
};