diff --git a/Userland/Libraries/LibJS/Bytecode/Executable.cpp b/Userland/Libraries/LibJS/Bytecode/Executable.cpp index ed2288d3fa..392a1f4d86 100644 --- a/Userland/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Executable.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace JS::Bytecode { diff --git a/Userland/Libraries/LibJS/Bytecode/Executable.h b/Userland/Libraries/LibJS/Bytecode/Executable.h index a3cfbca349..831af875ad 100644 --- a/Userland/Libraries/LibJS/Bytecode/Executable.h +++ b/Userland/Libraries/LibJS/Bytecode/Executable.h @@ -15,9 +15,12 @@ #include #include #include -#include #include +namespace JS::JIT { +class NativeExecutable; +} + namespace JS::Bytecode { struct PropertyLookupCache { @@ -70,6 +73,7 @@ public: void dump() const; JIT::NativeExecutable const* get_or_create_native_executable(); + JIT::NativeExecutable const* native_executable() const { return m_native_executable; } private: OwnPtr m_native_executable; diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 9ed16122ac..91647cb433 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -157,10 +157,10 @@ private: class InstructionStreamIterator { public: - InstructionStreamIterator(ReadonlyBytes bytes, Executable const* executable = nullptr) + InstructionStreamIterator(ReadonlyBytes bytes, Executable const* executable = nullptr, size_t offset = 0) : m_begin(bytes.data()) , m_end(bytes.data() + bytes.size()) - , m_ptr(bytes.data()) + , m_ptr(bytes.data() + offset) , m_executable(executable) { } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index decb48ab69..0701b9cc9a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,13 @@ void Interpreter::visit_edges(Cell::Visitor& visitor) } } +Optional Interpreter::instruction_stream_iterator() const +{ + if (m_current_executable && m_current_executable->native_executable()) + return m_current_executable->native_executable()->instruction_stream_iterator(*m_current_executable); + return m_pc; +} + // 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation ThrowCompletionOr Interpreter::run(Script& script_record, JS::GCPtr lexical_environment_override) { diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 2b26e38277..bb98c8f746 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -77,7 +78,7 @@ public: Executable& current_executable() { return *m_current_executable; } Executable const& current_executable() const { return *m_current_executable; } BasicBlock const& current_block() const { return *m_current_block; } - auto& instruction_stream_iterator() const { return m_pc; } + Optional instruction_stream_iterator() const; void visit_edges(Cell::Visitor&); diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index ccaa14e04c..2f8f1fd8fc 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -8,12 +8,12 @@ #pragma once #include +#include #if ARCH(X86_64) # include # include # include -# include namespace JS::JIT { diff --git a/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp b/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp index c9ce836606..6c39a4c69d 100644 --- a/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp +++ b/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp @@ -12,6 +12,11 @@ #include #include +#if __has_include() +# include +# define EXECINFO_BACKTRACE +#endif + namespace JS::JIT { NativeExecutable::NativeExecutable(void* code, size_t size, Vector mapping) @@ -34,6 +39,7 @@ void NativeExecutable::run(VM& vm) const vm.running_execution_context().local_variables.data()); } +#if ARCH(X86_64) class JITSymbolProvider : public X86::SymbolProvider { public: JITSymbolProvider(NativeExecutable const& executable) @@ -67,8 +73,9 @@ public: private: NativeExecutable const& m_executable; }; +#endif -void NativeExecutable::dump_disassembly(Bytecode::Executable const& executable) const +void NativeExecutable::dump_disassembly([[maybe_unused]] Bytecode::Executable const& executable) const { #if ARCH(X86_64) auto const* code_bytes = static_cast(m_code); @@ -148,4 +155,33 @@ BytecodeMapping const& NativeExecutable::find_mapping_entry(size_t native_offset return m_mapping[nearby_index]; } +Optional NativeExecutable::instruction_stream_iterator([[maybe_unused]] Bytecode::Executable const& executable) const +{ +#ifdef EXECINFO_BACKTRACE + void* buffer[10]; + auto count = backtrace(buffer, 10); + auto start = bit_cast(m_code); + auto end = start + m_size; + for (auto i = 0; i < count; i++) { + auto address = bit_cast(buffer[i]); + if (address < start || address >= end) + continue; + // return address points after the call + // let's subtract 1 to make sure we don't hit the next bytecode + // (in practice that's not necessary, because our native_call() sequence continues) + auto offset = address - start - 1; + auto& entry = find_mapping_entry(offset); + if (entry.block_index < executable.basic_blocks.size()) { + auto const& block = *executable.basic_blocks[entry.block_index]; + if (entry.bytecode_offset < block.size()) { + // This is rather clunky, but Interpreter::instruction_stream_iterator() gives out references, so we need to keep it alive. + m_instruction_stream_iterator = make(block.instruction_stream(), &executable, entry.bytecode_offset); + return *m_instruction_stream_iterator; + } + } + } +#endif + return {}; +} + } diff --git a/Userland/Libraries/LibJS/JIT/NativeExecutable.h b/Userland/Libraries/LibJS/JIT/NativeExecutable.h index 3fb05608c5..d8790618de 100644 --- a/Userland/Libraries/LibJS/JIT/NativeExecutable.h +++ b/Userland/Libraries/LibJS/JIT/NativeExecutable.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace JS::JIT { @@ -33,6 +34,7 @@ public: void run(VM&) const; void dump_disassembly(Bytecode::Executable const& executable) const; BytecodeMapping const& find_mapping_entry(size_t native_offset) const; + Optional instruction_stream_iterator(Bytecode::Executable const& executable) const; ReadonlyBytes code_bytes() const { return { m_code, m_size }; } @@ -40,6 +42,7 @@ private: void* m_code { nullptr }; size_t m_size { 0 }; Vector m_mapping; + mutable OwnPtr m_instruction_stream_iterator; }; }