diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 0a2aa5c148..96f69677e0 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2510,7 +2510,7 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener auto& target_block = generator.make_block(); generator.switch_to_basic_block(saved_block); - generator.emit(Bytecode::Label { target_block }); + generator.emit(Bytecode::Label { target_block }, handler_target, finalizer_target); generator.start_boundary(Bytecode::Generator::BlockBoundaryType::Unwind); if (m_finalizer) generator.start_boundary(Bytecode::Generator::BlockBoundaryType::ReturnToFinally); diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index 61252a3eb0..2d3ea5cc2e 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -35,7 +36,7 @@ public: void grow(size_t additional_size); - void terminate(Badge) { m_terminated = true; } + void terminate(Badge, size_t slot_offset) { terminate(slot_offset); } bool is_terminated() const { return m_terminated; } String const& name() const { return m_name; } @@ -46,14 +47,56 @@ public: BasicBlock const* handler() const { return m_handler; } BasicBlock const* finalizer() const { return m_finalizer; } + Instruction const* terminator() const + { + VERIFY(m_terminated); + return reinterpret_cast(data() + m_terminator_offset); + } + + template + void append(u32 start_offset, u32 end_offset, Args&&... args) + { + VERIFY(!m_terminated); + size_t const slot_offset = size(); + grow(sizeof(OpType)); + void* slot = data() + slot_offset; + new (slot) OpType(forward(args)...); + if constexpr (OpType::IsTerminator) + terminate(slot_offset); + auto* op = static_cast(slot); + op->set_source_record({ start_offset, end_offset }); + } + + template + void append_with_extra_operand_slots(u32 start_offset, u32 end_offset, size_t extra_operand_slots, Args&&... args) + { + VERIFY(!m_terminated); + size_t size_to_allocate = round_up_to_power_of_two(sizeof(OpType) + extra_operand_slots * sizeof(Operand), alignof(void*)); + size_t slot_offset = size(); + grow(size_to_allocate); + void* slot = data() + slot_offset; + new (slot) OpType(forward(args)...); + if constexpr (OpType::IsTerminator) + terminate(slot_offset); + auto* op = static_cast(slot); + op->set_source_record({ start_offset, end_offset }); + } + private: explicit BasicBlock(String name); + void terminate(size_t slot_offset) + { + m_terminated = true; + m_terminator_offset = slot_offset; + } + Vector m_buffer; BasicBlock const* m_handler { nullptr }; BasicBlock const* m_finalizer { nullptr }; String m_name; bool m_terminated { false }; + size_t m_terminator_offset { 0 }; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 79d0302b29..c38a8977cb 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -76,7 +76,7 @@ public: void* slot = m_current_basic_block->data() + slot_offset; new (slot) OpType(forward(args)...); if constexpr (OpType::IsTerminator) - m_current_basic_block->terminate({}); + m_current_basic_block->terminate({}, slot_offset); auto* op = static_cast(slot); op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); } @@ -92,7 +92,7 @@ public: void* slot = m_current_basic_block->data() + slot_offset; new (slot) OpType(forward(args)...); if constexpr (OpType::IsTerminator) - m_current_basic_block->terminate({}); + m_current_basic_block->terminate({}, slot_offset); auto* op = static_cast(slot); op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); } diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp index 58e44ba1bb..4323ccbf08 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp @@ -10,6 +10,36 @@ namespace JS::Bytecode { +bool Instruction::is_terminator() const +{ +#define __BYTECODE_OP(op) \ + case Type::op: \ + return Op::op::IsTerminator; + + switch (type()) { + ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) + default: + VERIFY_NOT_REACHED(); + } + +#undef __BYTECODE_OP +} + +void Instruction::replace_references(BasicBlock const& from, BasicBlock const& to) +{ +#define __BYTECODE_OP(op) \ + case Instruction::Type::op: \ + return static_cast(*this).replace_references_impl(from, to); + + switch (type()) { + ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) + default: + VERIFY_NOT_REACHED(); + } + +#undef __BYTECODE_OP +} + void Instruction::destroy(Instruction& instruction) { #define __BYTECODE_OP(op) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 31d9f7d7eb..453969ad85 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -131,10 +131,13 @@ public: #undef __BYTECODE_OP }; + [[nodiscard]] bool is_terminator() const; + Type type() const { return m_type; } size_t length() const { return m_length; } ByteString to_byte_string(Bytecode::Executable const&) const; ThrowCompletionOr execute(Bytecode::Interpreter&) const; + void replace_references(BasicBlock const& from, BasicBlock const& to); static void destroy(Instruction&); // FIXME: Find a better way to organize this information diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index c4fad2b5a8..83efe89c56 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -532,6 +533,25 @@ void Interpreter::enter_object_environment(Object& object) vm().running_execution_context().lexical_environment = new_object_environment(object, true, old_environment); } +static PassManager& optimization_pipeline() +{ + static auto s_optimization_pipeline = [] { + auto pm = make(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + return pm; + }(); + return *s_optimization_pipeline; +} + ThrowCompletionOr> compile(VM& vm, ASTNode const& node, ReadonlySpan parameters, FunctionKind kind, DeprecatedFlyString const& name) { auto executable_result = Bytecode::Generator::generate(vm, node, parameters, kind); @@ -541,6 +561,13 @@ ThrowCompletionOr> compile(VM& vm, ASTNode co auto bytecode_executable = executable_result.release_value(); bytecode_executable->name = name; + auto& passes = optimization_pipeline(); + passes.perform(*bytecode_executable); + if constexpr (JS_BYTECODE_DEBUG) { + dbgln("Optimisation passes took {}us", passes.elapsed()); + dbgln("Compiled Bytecode::Block for function '{}':", name); + } + if (Bytecode::g_dump_bytecode) bytecode_executable->dump(); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index ae9f91c5be..f65df12888 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -18,6 +18,7 @@ namespace JS::Bytecode { class InstructionStreamIterator; +class PassManager; struct CallFrame { static NonnullOwnPtr create(size_t register_count); diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index ceef01e776..ed9968d52b 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -42,6 +42,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -77,28 +78,29 @@ private: O(StrictlyEquals, strict_equals) \ O(LeftShift, left_shift) -#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \ - class OpTitleCase final : public Instruction { \ - public: \ - explicit OpTitleCase(Operand dst, Operand lhs, Operand rhs) \ - : Instruction(Type::OpTitleCase, sizeof(*this)) \ - , m_dst(dst) \ - , m_lhs(lhs) \ - , m_rhs(rhs) \ - { \ - } \ - \ - ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ - ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ - \ - Operand dst() const { return m_dst; } \ - Operand lhs() const { return m_lhs; } \ - Operand rhs() const { return m_rhs; } \ - \ - private: \ - Operand m_dst; \ - Operand m_lhs; \ - Operand m_rhs; \ +#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \ + class OpTitleCase final : public Instruction { \ + public: \ + explicit OpTitleCase(Operand dst, Operand lhs, Operand rhs) \ + : Instruction(Type::OpTitleCase, sizeof(*this)) \ + , m_dst(dst) \ + , m_lhs(lhs) \ + , m_rhs(rhs) \ + { \ + } \ + \ + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ + ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \ + \ + Operand dst() const { return m_dst; } \ + Operand lhs() const { return m_lhs; } \ + Operand rhs() const { return m_rhs; } \ + \ + private: \ + Operand m_dst; \ + Operand m_lhs; \ + Operand m_rhs; \ }; JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH(JS_DECLARE_COMMON_BINARY_OP) @@ -112,25 +114,26 @@ JS_ENUMERATE_COMMON_BINARY_OPS_WITH_FAST_PATH(JS_DECLARE_COMMON_BINARY_OP) O(UnaryMinus, unary_minus) \ O(Typeof, typeof_) -#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \ - class OpTitleCase final : public Instruction { \ - public: \ - OpTitleCase(Operand dst, Operand src) \ - : Instruction(Type::OpTitleCase, sizeof(*this)) \ - , m_dst(dst) \ - , m_src(src) \ - { \ - } \ - \ - ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ - ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ - \ - Operand dst() const { return m_dst; } \ - Operand src() const { return m_src; } \ - \ - private: \ - Operand m_dst; \ - Operand m_src; \ +#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \ + class OpTitleCase final : public Instruction { \ + public: \ + OpTitleCase(Operand dst, Operand src) \ + : Instruction(Type::OpTitleCase, sizeof(*this)) \ + , m_dst(dst) \ + , m_src(src) \ + { \ + } \ + \ + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ + ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \ + \ + Operand dst() const { return m_dst; } \ + Operand src() const { return m_src; } \ + \ + private: \ + Operand m_dst; \ + Operand m_src; \ }; JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP) @@ -146,6 +149,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } @@ -166,6 +170,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } StringTableIndex source_index() const { return m_source_index; } @@ -182,25 +187,26 @@ private: #define JS_ENUMERATE_NEW_BUILTIN_ERROR_OPS(O) \ O(TypeError) -#define JS_DECLARE_NEW_BUILTIN_ERROR_OP(ErrorName) \ - class New##ErrorName final : public Instruction { \ - public: \ - New##ErrorName(Operand dst, StringTableIndex error_string) \ - : Instruction(Type::New##ErrorName, sizeof(*this)) \ - , m_dst(dst) \ - , m_error_string(error_string) \ - { \ - } \ - \ - ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ - ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ - \ - Operand dst() const { return m_dst; } \ - StringTableIndex error_string() const { return m_error_string; } \ - \ - private: \ - Operand m_dst; \ - StringTableIndex m_error_string; \ +#define JS_DECLARE_NEW_BUILTIN_ERROR_OP(ErrorName) \ + class New##ErrorName final : public Instruction { \ + public: \ + New##ErrorName(Operand dst, StringTableIndex error_string) \ + : Instruction(Type::New##ErrorName, sizeof(*this)) \ + , m_dst(dst) \ + , m_error_string(error_string) \ + { \ + } \ + \ + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ + ByteString to_byte_string_impl(Bytecode::Executable const&) const; \ + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \ + \ + Operand dst() const { return m_dst; } \ + StringTableIndex error_string() const { return m_error_string; } \ + \ + private: \ + Operand m_dst; \ + StringTableIndex m_error_string; \ }; JS_ENUMERATE_NEW_BUILTIN_ERROR_OPS(JS_DECLARE_NEW_BUILTIN_ERROR_OP) @@ -221,6 +227,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } size_t length_impl(size_t excluded_names_count) const { @@ -260,6 +267,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } @@ -306,6 +314,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } ReadonlySpan elements() const { return { m_elements, m_element_count }; } @@ -328,6 +337,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -351,6 +361,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand specifier() const { return m_specifier; } @@ -373,6 +384,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand iterator() const { return m_iterator; } @@ -393,6 +405,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -416,6 +429,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } }; class EnterObjectEnvironment final : public Instruction { @@ -428,6 +442,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand object() const { return m_object; } @@ -445,6 +460,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } @@ -466,6 +482,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } IdentifierTableIndex identifier() const { return m_identifier; } EnvironmentMode mode() const { return m_mode; } @@ -499,6 +516,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } IdentifierTableIndex identifier() const { return m_identifier; } Operand src() const { return m_src; } @@ -525,6 +543,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } size_t index() const { return m_index; } Operand dst() const { return Operand(Operand::Type::Local, m_index); } @@ -548,6 +567,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } IdentifierTableIndex identifier() const { return m_identifier; } u32 cache_index() const { return m_cache_index; } @@ -573,6 +593,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } IdentifierTableIndex identifier() const { return m_identifier; } @@ -596,6 +617,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } IdentifierTableIndex identifier() const { return m_identifier; } @@ -618,6 +640,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } IdentifierTableIndex identifier() const { return m_identifier; } @@ -640,6 +663,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -667,6 +691,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -694,6 +719,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -717,6 +743,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -751,6 +778,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand base() const { return m_base; } IdentifierTableIndex property() const { return m_property; } @@ -781,6 +809,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand base() const { return m_base; } Operand this_value() const { return m_this_value; } @@ -811,6 +840,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand base() const { return m_base; } IdentifierTableIndex property() const { return m_property; } @@ -835,6 +865,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -859,6 +890,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -884,6 +916,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -908,6 +941,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -934,6 +968,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand base() const { return m_base; } Operand property() const { return m_property; } @@ -961,6 +996,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand base() const { return m_base; } Operand property() const { return m_property; } @@ -988,6 +1024,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand base() const { return m_base; } @@ -1017,6 +1054,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Operand m_dst; @@ -1052,6 +1090,13 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const& from, BasicBlock const& to) + { + if (m_true_target.has_value() && &m_true_target->block() == &from) + m_true_target = Label { to }; + if (m_false_target.has_value() && &m_false_target->block() == &from) + m_false_target = Label { to }; + } auto& true_target() const { return m_true_target; } auto& false_target() const { return m_false_target; } @@ -1151,6 +1196,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Operand m_dst; @@ -1185,6 +1231,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Operand m_dst; @@ -1207,6 +1254,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand arguments() const { return m_arguments; } @@ -1231,6 +1279,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Optional const& super_class() const { return m_super_class; } @@ -1257,6 +1306,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } FunctionExpression const& function_node() const { return m_function_node; } @@ -1280,6 +1330,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } ScopeNode const& scope_node() const { return m_scope_node; } @@ -1299,6 +1350,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Optional const& value() const { return m_value; } @@ -1316,6 +1368,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } @@ -1334,6 +1387,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -1353,6 +1407,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } @@ -1371,6 +1426,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand dst() const { return m_dst; } Operand src() const { return m_src; } @@ -1392,6 +1448,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand src() const { return m_src; } @@ -1409,6 +1466,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand src() const { return m_src; } @@ -1426,6 +1484,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand src() const { return m_src; } @@ -1443,6 +1502,7 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; ByteString to_byte_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } Operand src() const { return m_src; } @@ -1454,19 +1514,34 @@ class EnterUnwindContext final : public Instruction { public: constexpr static bool IsTerminator = true; - EnterUnwindContext(Label entry_point) + EnterUnwindContext(Label entry_point, Optional