diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index 07d401d96ce..7eb45767cd7 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -45,6 +46,9 @@ public: BasicBlock const* handler() const { return m_handler; } BasicBlock const* finalizer() const { return m_finalizer; } + auto const& source_map() const { return m_source_map; } + void add_source_map_entry(size_t bytecode_offset, SourceRecord const& source_record) { m_source_map.set(bytecode_offset, source_record); } + private: explicit BasicBlock(String name); @@ -53,6 +57,8 @@ private: BasicBlock const* m_finalizer { nullptr }; String m_name; bool m_terminated { false }; + + HashMap m_source_map; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Executable.cpp b/Userland/Libraries/LibJS/Bytecode/Executable.cpp index a2d90bf5e4b..fad33864d87 100644 --- a/Userland/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Executable.cpp @@ -106,11 +106,13 @@ UnrealizedSourceRange Executable::source_range_at(size_t offset) const return {}; auto it = InstructionStreamIterator(bytecode.span().slice(offset), this); VERIFY(!it.at_end()); - auto& instruction = *it; + auto mapping = source_map.get(offset); + if (!mapping.has_value()) + return {}; return UnrealizedSourceRange { .source_code = source_code, - .start_offset = instruction.source_record().source_start_offset, - .end_offset = instruction.source_record().source_end_offset, + .start_offset = mapping->source_start_offset, + .end_offset = mapping->source_end_offset, }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Executable.h b/Userland/Libraries/LibJS/Bytecode/Executable.h index ecdfc417c5a..79b026ca07a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Executable.h +++ b/Userland/Libraries/LibJS/Bytecode/Executable.h @@ -84,6 +84,8 @@ public: Vector exception_handlers; Vector basic_block_start_offsets; + HashMap source_map; + ByteString const& get_string(StringTableIndex index) const { return string_table->get(index); } DeprecatedFlyString const& get_identifier(IdentifierTableIndex index) const { return identifier_table->get(index); } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 00c0d3d472b..137fc7f0d02 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -96,6 +96,8 @@ CodeGenerationErrorOr> Generator::generate(VM& vm, ASTN }; Vector unlinked_exception_handlers; + HashMap source_map; + for (auto& block : generator.m_root_basic_blocks) { basic_block_start_offsets.append(bytecode.size()); if (block->handler() || block->finalizer()) { @@ -108,6 +110,11 @@ CodeGenerationErrorOr> Generator::generate(VM& vm, ASTN } block_offsets.set(block.ptr(), bytecode.size()); + + for (auto& [offset, source_record] : block->source_map()) { + source_map.set(bytecode.size() + offset, source_record); + } + Bytecode::InstructionStreamIterator it(block->instruction_stream()); while (!it.at_end()) { auto& instruction = const_cast(*it); @@ -161,6 +168,7 @@ CodeGenerationErrorOr> Generator::generate(VM& vm, ASTN executable->exception_handlers = move(linked_exception_handlers); executable->basic_block_start_offsets = move(basic_block_start_offsets); + executable->source_map = move(source_map); return executable; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index b41a13ee432..7279d39203a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -77,8 +77,7 @@ public: new (slot) OpType(forward(args)...); if constexpr (OpType::IsTerminator) m_current_basic_block->terminate({}); - auto* op = static_cast(slot); - op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); + m_current_basic_block->add_source_map_entry(slot_offset, { m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); } template @@ -93,8 +92,7 @@ public: new (slot) OpType(forward(args)...); if constexpr (OpType::IsTerminator) m_current_basic_block->terminate({}); - auto* op = static_cast(slot); - op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); + m_current_basic_block->add_source_map_entry(slot_offset, { m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); } template diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp index f20bae513c6..4f7ccbf76d8 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp @@ -52,7 +52,7 @@ void Instruction::visit_labels(Function visitor) UnrealizedSourceRange InstructionStreamIterator::source_range() const { VERIFY(m_executable); - auto record = dereference().source_record(); + auto record = m_executable->source_map.get(offset()).value(); return { .source_code = m_executable->source_code, .start_offset = record.source_start_offset, diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index e8f9e96a8ed..5a6375bb551 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -140,17 +141,12 @@ public: void visit_labels(Function visitor); static void destroy(Instruction&); - // FIXME: Find a better way to organize this information - void set_source_record(SourceRecord rec) { m_source_record = rec; } - SourceRecord source_record() const { return m_source_record; } - protected: Instruction(Type, size_t length); void visit_labels_impl(Function) { } private: - SourceRecord m_source_record {}; Type m_type {}; u32 m_length {}; }; diff --git a/Userland/Libraries/LibJS/Bytecode/Label.h b/Userland/Libraries/LibJS/Bytecode/Label.h index 59bd9011512..d20dd1843d1 100644 --- a/Userland/Libraries/LibJS/Bytecode/Label.h +++ b/Userland/Libraries/LibJS/Bytecode/Label.h @@ -7,10 +7,11 @@ #pragma once #include -#include namespace JS::Bytecode { +class BasicBlock; + class Label { public: explicit Label(BasicBlock const& block)