mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 18:02:05 -05:00
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:
parent
640f195a70
commit
b7c04f999a
8 changed files with 203 additions and 96 deletions
|
@ -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 };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue