From 3f04d18ef7ea3b287df907eaae04eba6ec207f56 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 24 Apr 2025 22:10:41 +0200 Subject: [PATCH] LibJS: Add new operand type for function arguments This allows us to directly access passed arguments instead of copying them to register/local first using GetArgument instruction. --- Libraries/LibJS/Bytecode/Executable.h | 1 + Libraries/LibJS/Bytecode/Generator.cpp | 28 +++++++-------- Libraries/LibJS/Bytecode/Instruction.h | 2 -- Libraries/LibJS/Bytecode/Interpreter.cpp | 32 ++++------------- Libraries/LibJS/Bytecode/Interpreter.h | 6 ++-- Libraries/LibJS/Bytecode/Op.h | 46 ------------------------ Libraries/LibJS/Bytecode/Operand.h | 5 +-- 7 files changed, 27 insertions(+), 93 deletions(-) diff --git a/Libraries/LibJS/Bytecode/Executable.h b/Libraries/LibJS/Bytecode/Executable.h index d60268980c5..6354b374d3a 100644 --- a/Libraries/LibJS/Bytecode/Executable.h +++ b/Libraries/LibJS/Bytecode/Executable.h @@ -87,6 +87,7 @@ public: Vector local_variable_names; size_t local_index_base { 0 }; + size_t argument_index_base { 0 }; Optional length_identifier; diff --git a/Libraries/LibJS/Bytecode/Generator.cpp b/Libraries/LibJS/Bytecode/Generator.cpp index 0bd16a12e46..de43c27ed7d 100644 --- a/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Libraries/LibJS/Bytecode/Generator.cpp @@ -72,15 +72,13 @@ CodeGenerationErrorOr Generator::emit_function_declaration_instantiation(E auto const& parameter = formal_parameters.parameters()[param_index]; if (parameter.is_rest) { - auto argument_reg = allocate_register(); - emit(argument_reg.operand(), param_index); - emit(param_index, argument_reg.operand()); + emit(Operand { Operand::Type::Argument, param_index }, param_index); } else if (parameter.default_value) { auto& if_undefined_block = make_block(); auto& if_not_undefined_block = make_block(); auto argument_reg = allocate_register(); - emit(argument_reg.operand(), param_index); + emit(argument_reg.operand(), Operand { Operand::Type::Argument, param_index }); emit( argument_reg.operand(), @@ -89,7 +87,7 @@ CodeGenerationErrorOr Generator::emit_function_declaration_instantiation(E switch_to_basic_block(if_undefined_block); auto operand = TRY(parameter.default_value->generate_bytecode(*this)); - emit(param_index, *operand); + emit(Operand { Operand::Type::Argument, param_index }, *operand); emit(Label { if_not_undefined_block }); switch_to_basic_block(if_not_undefined_block); @@ -98,23 +96,20 @@ CodeGenerationErrorOr Generator::emit_function_declaration_instantiation(E if (auto const* identifier = parameter.binding.get_pointer>(); identifier) { if ((*identifier)->is_local()) { auto local_variable_index = (*identifier)->local_variable_index(); - emit(local(local_variable_index), param_index); + emit(local(local_variable_index), Operand { Operand::Type::Argument, param_index }); set_local_initialized((*identifier)->local_variable_index()); } else { auto id = intern_identifier((*identifier)->string()); - auto argument_reg = allocate_register(); - emit(argument_reg.operand(), param_index); if (function.shared_data().m_has_duplicates) { - emit(id, argument_reg.operand()); + emit(id, Operand { Operand::Type::Argument, param_index }); } else { - emit(id, argument_reg.operand()); + emit(id, Operand { Operand::Type::Argument, param_index }); } } } else if (auto const* binding_pattern = parameter.binding.get_pointer>(); binding_pattern) { - auto input_operand = allocate_register(); - emit(input_operand.operand(), param_index); + ScopedOperand argument { *this, Operand { Operand::Type::Argument, param_index } }; auto init_mode = function.shared_data().m_has_duplicates ? Op::BindingInitializationMode::Set : Bytecode::Op::BindingInitializationMode::Initialize; - TRY((*binding_pattern)->generate_bytecode(*this, init_mode, input_operand)); + TRY((*binding_pattern)->generate_bytecode(*this, init_mode, argument)); } } @@ -312,6 +307,7 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode co auto number_of_registers = generator.m_next_register; auto number_of_constants = generator.m_constants.size(); + auto number_of_locals = function ? function->local_variables_names().size() : 0; // Pass: Rewrite the bytecode to use the correct register and constant indices. for (auto& block : generator.m_root_basic_blocks) { @@ -319,7 +315,7 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode co while (!it.at_end()) { auto& instruction = const_cast(*it); - instruction.visit_operands([number_of_registers, number_of_constants](Operand& operand) { + instruction.visit_operands([number_of_registers, number_of_constants, number_of_locals](Operand& operand) { switch (operand.type()) { case Operand::Type::Register: break; @@ -329,6 +325,9 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode co case Operand::Type::Constant: operand.offset_index_by(number_of_registers); break; + case Operand::Type::Argument: + operand.offset_index_by(number_of_registers + number_of_constants + number_of_locals); + break; default: VERIFY_NOT_REACHED(); } @@ -476,6 +475,7 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode co executable->source_map = move(source_map); executable->local_variable_names = move(local_variable_names); executable->local_index_base = number_of_registers + number_of_constants; + executable->argument_index_base = number_of_registers + number_of_constants + number_of_locals; executable->length_identifier = generator.m_length_identifier; generator.m_finished = true; diff --git a/Libraries/LibJS/Bytecode/Instruction.h b/Libraries/LibJS/Bytecode/Instruction.h index 00ea60b96b5..0b81a8fd93d 100644 --- a/Libraries/LibJS/Bytecode/Instruction.h +++ b/Libraries/LibJS/Bytecode/Instruction.h @@ -51,7 +51,6 @@ O(EnterObjectEnvironment) \ O(EnterUnwindContext) \ O(Exp) \ - O(GetArgument) \ O(GetById) \ O(GetByIdWithThis) \ O(GetByValue) \ @@ -131,7 +130,6 @@ O(Return) \ O(RightShift) \ O(ScheduleJump) \ - O(SetArgument) \ O(SetCompletionType) \ O(SetLexicalBinding) \ O(SetVariableBinding) \ diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 358762db20e..4f41a4c8aa2 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -83,6 +83,9 @@ static ByteString format_operand(StringView name, Operand operand, Bytecode::Exe case Operand::Type::Local: builder.appendff("\033[34m{}~{}\033[0m", executable.local_variable_names[operand.index() - executable.local_index_base], operand.index() - executable.local_index_base); break; + case Operand::Type::Argument: + builder.appendff("\033[34marg{}\033[0m", operand.index() - executable.argument_index_base); + break; case Operand::Type::Constant: { builder.append("\033[36m"sv); auto value = executable.constants[operand.index() - executable.number_of_registers]; @@ -184,12 +187,12 @@ Interpreter::~Interpreter() ALWAYS_INLINE Value Interpreter::get(Operand op) const { - return m_registers_and_constants_and_locals.data()[op.index()]; + return m_registers_and_constants_and_locals_arguments.data()[op.index()]; } ALWAYS_INLINE void Interpreter::set(Operand op, Value value) { - m_registers_and_constants_and_locals.data()[op.index()] = value; + m_registers_and_constants_and_locals_arguments.data()[op.index()] = value; } ALWAYS_INLINE Value Interpreter::do_yield(Value value, Optional