From ff334ad6a87271c47e7bd7a369ec92e37b370641 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Fri, 10 May 2024 16:47:58 +0200 Subject: [PATCH] LibJS: GetArgument SetArgument --- .../Libraries/LibJS/Bytecode/Generator.cpp | 25 ++++++----- Userland/Libraries/LibJS/Bytecode/Generator.h | 1 - .../Libraries/LibJS/Bytecode/Instruction.h | 2 + .../Libraries/LibJS/Bytecode/Interpreter.cpp | 45 +++++++++++++++---- Userland/Libraries/LibJS/Bytecode/Op.h | 40 +++++++++++++++++ Userland/Libraries/LibJS/Bytecode/Operand.h | 2 - 6 files changed, 92 insertions(+), 23 deletions(-) diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 18bf606a42736dc..7d813247a7ff86d 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -56,19 +56,24 @@ CodeGenerationErrorOr Generator::emit_function_declaration_instantiation(E auto const& parameter = formal_parameters[param_index]; if (parameter.is_rest) { - emit(argument(param_index), param_index); + auto argument_reg = allocate_register(); + emit(argument_reg.operand(), param_index); + emit(param_index, argument_reg.operand()); } 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(param_index), + argument_reg.operand(), Label { if_undefined_block }, Label { if_not_undefined_block }); switch_to_basic_block(if_undefined_block); auto operand = TRY(parameter.default_value->generate_bytecode(*this)); - emit(argument(param_index), *operand); + emit(param_index, *operand); emit(Label { if_not_undefined_block }); switch_to_basic_block(if_not_undefined_block); @@ -77,18 +82,21 @@ 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), argument(param_index)); + emit(local(local_variable_index), param_index); 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; - emit(id, argument(param_index), + auto argument_reg = allocate_register(); + emit(argument_reg.operand(), param_index); + emit(id, argument_reg.operand(), next_environment_variable_cache(), init_mode, Op::EnvironmentMode::Lexical); } } else if (auto const* binding_pattern = parameter.binding.get_pointer>(); binding_pattern) { - auto input_operand = argument(param_index); + auto input_operand = allocate_register(); + emit(input_operand.operand(), param_index); auto init_mode = function.m_has_duplicates ? Op::SetVariable::InitializationMode::Set : Bytecode::Op::SetVariable::InitializationMode::Initialize; TRY((*binding_pattern)->generate_bytecode(*this, init_mode, input_operand, false)); } @@ -410,11 +418,6 @@ ScopedOperand Generator::local(u32 local_index) return ScopedOperand { *this, Operand { Operand::Type::Local, static_cast(local_index) } }; } -ScopedOperand Generator::argument(u32 argument_index) -{ - return ScopedOperand { *this, Operand { Operand::Type::Argument, static_cast(argument_index) } }; -} - Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node) : m_generator(generator) , m_previous_node(m_generator.m_current_ast_node) diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 061fdf895da7b1a..f1e54fa2a041488 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -40,7 +40,6 @@ class Generator { [[nodiscard]] ScopedOperand allocate_register(); [[nodiscard]] ScopedOperand local(u32 local_index); - [[nodiscard]] ScopedOperand argument(u32 argument_index); [[nodiscard]] ScopedOperand accumulator(); void free_register(Register); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 8ad93c0095267a5..f97a3c1a1a6c89f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -14,6 +14,8 @@ #include #define ENUMERATE_BYTECODE_OPS(O) \ + O(GetArgument) \ + O(SetArgument) \ O(Add) \ O(ArrayAppend) \ O(AsyncIteratorClose) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 3c51904b45c4816..59bed11314ae673 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -45,9 +45,6 @@ static ByteString format_operand(StringView name, Operand operand, Bytecode::Exe if (!name.is_empty()) builder.appendff("\033[32m{}\033[0m:", name); switch (operand.type()) { - case Operand::Type::Argument: - builder.appendff("\033[33marg{}\033[0m", operand.index()); - break; case Operand::Type::Register: builder.appendff("\033[33mreg{}\033[0m", operand.index()); break; @@ -162,9 +159,7 @@ ALWAYS_INLINE Value Interpreter::get(Operand op) const case Operand::Type::Local: return m_locals.data()[op.index()]; case Operand::Type::Constant: - return m_constants.data()[op.index()]; - case Operand::Type::Argument: - return m_arguments.data()[op.index()]; + return current_executable().constants[op.index()]; } __builtin_unreachable(); } @@ -178,9 +173,6 @@ ALWAYS_INLINE void Interpreter::set(Operand op, Value value) case Operand::Type::Local: m_locals.data()[op.index()] = value; return; - case Operand::Type::Argument: - m_arguments.data()[op.index()] = value; - return; case Operand::Type::Constant: break; } @@ -353,6 +345,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point) } auto& running_execution_context = vm().running_execution_context(); + auto* arguments = running_execution_context.arguments.data(); auto* locals = running_execution_context.locals.data(); auto& accumulator = this->accumulator(); auto& executable = current_executable(); @@ -395,6 +388,18 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point) DISPATCH_NEXT(SetLocal); } + handle_SetArgument: { + auto const& instruction = *reinterpret_cast(&bytecode[program_counter]); + arguments[instruction.index()] = get(instruction.src()); + DISPATCH_NEXT(SetLocal); + } + + handle_GetArgument: { + auto const& instruction = *reinterpret_cast(&bytecode[program_counter]); + set(instruction.dst(), arguments[instruction.index()]); + DISPATCH_NEXT(SetLocal); + } + handle_Mov: { auto& instruction = *reinterpret_cast(&bytecode[program_counter]); set(instruction.dst(), get(instruction.src())); @@ -1363,6 +1368,18 @@ ThrowCompletionOr SetLocal::execute_impl(Bytecode::Interpreter&) const __builtin_unreachable(); } +ThrowCompletionOr SetArgument::execute_impl(Bytecode::Interpreter&) const +{ + // Handled in the interpreter loop. + __builtin_unreachable(); +} + +ThrowCompletionOr GetArgument::execute_impl(Bytecode::Interpreter&) const +{ + // Handled in the interpreter loop. + __builtin_unreachable(); +} + ThrowCompletionOr GetById::execute_impl(Bytecode::Interpreter& interpreter) const { auto base_identifier = interpreter.current_executable().get_identifier(m_base_identifier); @@ -2096,6 +2113,16 @@ ByteString SetLocal::to_byte_string_impl(Bytecode::Executable const& executable) format_operand("src"sv, src(), executable)); } +ByteString GetArgument::to_byte_string_impl(Bytecode::Executable const&) const +{ + return "GetArgument"sv; +} + +ByteString SetArgument::to_byte_string_impl(Bytecode::Executable const&) const +{ + return "SetArgument"sv; +} + static StringView property_kind_to_string(PropertyKind kind) { switch (kind) { diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 72d2a0ab96536d9..ad956d85716bc73 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -610,6 +610,46 @@ class SetLocal final : public Instruction { Operand m_src; }; +class SetArgument final : public Instruction { +public: + SetArgument(size_t index, Operand src) + : Instruction(Type::SetArgument) + , m_index(index) + , m_src(src) + { + } + + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; + ByteString to_byte_string_impl(Bytecode::Executable const&) const; + + size_t index() const { return m_index; } + Operand src() const { return m_src; } + +private: + u32 m_index; + Operand m_src; +}; + +class GetArgument final : public Instruction { +public: + GetArgument(Operand dst, size_t index) + : Instruction(Type::GetArgument) + , m_index(index) + , m_dst(dst) + { + } + + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; + ByteString to_byte_string_impl(Bytecode::Executable const&) const; + + u32 index() const { return m_index; } + Operand dst() const { return m_dst; } + +private: + u32 m_index; + Operand m_dst; +}; + class GetCalleeAndThisFromEnvironment final : public Instruction { public: explicit GetCalleeAndThisFromEnvironment(Operand callee, Operand this_value, IdentifierTableIndex identifier, u32 cache_index) diff --git a/Userland/Libraries/LibJS/Bytecode/Operand.h b/Userland/Libraries/LibJS/Bytecode/Operand.h index 645dd1b45dce2db..89482af46c51005 100644 --- a/Userland/Libraries/LibJS/Bytecode/Operand.h +++ b/Userland/Libraries/LibJS/Bytecode/Operand.h @@ -14,7 +14,6 @@ namespace JS::Bytecode { class Operand { public: enum class Type { - Argument, Register, Local, Constant, @@ -30,7 +29,6 @@ class Operand { explicit Operand(Register); - [[nodiscard]] bool is_argument() const { return m_type == Type::Argument; } [[nodiscard]] bool is_register() const { return m_type == Type::Register; } [[nodiscard]] bool is_local() const { return m_type == Type::Local; } [[nodiscard]] bool is_constant() const { return m_type == Type::Constant; }