diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 7d27533386..986e84de8a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -275,12 +275,14 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNo HashMap source_map; + Optional undefined_constant; + for (auto& block : generator.m_root_basic_blocks) { if (!block->is_terminated()) { // NOTE: We must ensure that the "undefined" constant, which will be used by the not yet // emitted End instruction, is taken into account while shifting local operands by the // number of constants. - (void)generator.add_constant(js_undefined()); + undefined_constant = generator.add_constant(js_undefined()); break; } } @@ -288,6 +290,35 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNo auto number_of_registers = generator.m_next_register; auto number_of_constants = generator.m_constants.size(); + // Pass: Rewrite the bytecode to use the correct register and constant indices. + for (auto& block : generator.m_root_basic_blocks) { + Bytecode::InstructionStreamIterator it(block->instruction_stream()); + while (!it.at_end()) { + auto& instruction = const_cast(*it); + + instruction.visit_operands([number_of_registers, number_of_constants](Operand& operand) { + switch (operand.type()) { + case Operand::Type::Register: + break; + case Operand::Type::Local: + operand.offset_index_by(number_of_registers + number_of_constants); + break; + case Operand::Type::Constant: + operand.offset_index_by(number_of_registers); + break; + default: + VERIFY_NOT_REACHED(); + } + }); + + ++it; + } + } + + // Also rewrite the `undefined` constant if we have one for inserting End. + if (undefined_constant.has_value()) + undefined_constant.value().operand().offset_index_by(number_of_registers); + for (auto& block : generator.m_root_basic_blocks) { basic_block_start_offsets.append(bytecode.size()); if (block->handler() || block->finalizer()) { @@ -309,21 +340,6 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNo while (!it.at_end()) { auto& instruction = const_cast(*it); - instruction.visit_operands([number_of_registers, number_of_constants](Operand& operand) { - switch (operand.type()) { - case Operand::Type::Register: - break; - case Operand::Type::Local: - operand.offset_index_by(number_of_registers + number_of_constants); - break; - case Operand::Type::Constant: - operand.offset_index_by(number_of_registers); - break; - default: - VERIFY_NOT_REACHED(); - } - }); - // OPTIMIZATION: Don't emit jumps that just jump to the next block. if (instruction.type() == Instruction::Type::Jump) { auto& jump = static_cast(instruction); @@ -369,21 +385,7 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNo ++it; } if (!block->is_terminated()) { - Op::End end(generator.add_constant(js_undefined())); - end.visit_operands([number_of_registers, number_of_constants](Operand& operand) { - switch (operand.type()) { - case Operand::Type::Register: - break; - case Operand::Type::Local: - operand.offset_index_by(number_of_registers + number_of_constants); - break; - case Operand::Type::Constant: - operand.offset_index_by(number_of_registers); - break; - default: - VERIFY_NOT_REACHED(); - } - }); + Op::End end(*undefined_constant); bytecode.append(reinterpret_cast(&end), end.length()); } if (block->handler() || block->finalizer()) { diff --git a/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h index 1dccec1946..81c4b2b922 100644 --- a/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h +++ b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h @@ -21,7 +21,8 @@ public: ~ScopedOperandImpl(); - [[nodiscard]] Operand operand() const { return m_operand; } + [[nodiscard]] Operand const& operand() const { return m_operand; } + [[nodiscard]] Operand& operand() { return m_operand; } private: Generator& m_generator; @@ -35,7 +36,8 @@ public: { } - [[nodiscard]] Operand operand() const { return m_impl->operand(); } + [[nodiscard]] Operand const& operand() const { return m_impl->operand(); } + [[nodiscard]] Operand& operand() { return m_impl->operand(); } operator Operand() const { return operand(); } [[nodiscard]] bool operator==(ScopedOperand const& other) const { return operand() == other.operand(); }