From ec8330b6479dcc33471fb2bec8eb549cb38187ef Mon Sep 17 00:00:00 2001 From: Simon Wanner Date: Mon, 23 Oct 2023 18:37:29 +0200 Subject: [PATCH] LibJS/JIT: Dump disassembly of generated code using LibX86 This avoids the need for redirecting stdout to a file and using ndisasm, which can lead to problems if other things are printed. --- Userland/Libraries/LibJS/CMakeLists.txt | 3 ++ Userland/Libraries/LibJS/JIT/Compiler.cpp | 6 ++- .../Libraries/LibJS/JIT/NativeExecutable.cpp | 39 +++++++++++++++++++ .../Libraries/LibJS/JIT/NativeExecutable.h | 1 + 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index fba6268146..20a04b05c4 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -268,3 +268,6 @@ set(SOURCES serenity_lib(LibJS js) target_link_libraries(LibJS PRIVATE LibCore LibCrypto LibFileSystem LibRegex LibSyntax LibLocale LibUnicode LibJIT) +if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") + target_link_libraries(LibJS PRIVATE LibX86) +endif() diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index a1921386a0..9dcfc56dc8 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -24,6 +24,7 @@ # define LOG_JIT_SUCCESS 1 # define LOG_JIT_FAILURE 1 # define DUMP_JIT_MACHINE_CODE_TO_STDOUT 0 +# define DUMP_JIT_DISASSEMBLY 0 # define TRY_OR_SET_EXCEPTION(expression) \ ({ \ @@ -1154,7 +1155,10 @@ OwnPtr Compiler::compile(Bytecode::Executable& bytecode_execut dbgln("\033[32;1mJIT compilation succeeded!\033[0m {}", bytecode_executable.name); } - return make(executable_memory, compiler.m_output.size()); + auto executable = make(executable_memory, compiler.m_output.size()); + if constexpr (DUMP_JIT_DISASSEMBLY) + executable->dump_disassembly(); + return executable; } } diff --git a/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp b/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp index af71d1c151..d827b8d9db 100644 --- a/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp +++ b/Userland/Libraries/LibJS/JIT/NativeExecutable.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include namespace JS::JIT { @@ -30,4 +31,42 @@ void NativeExecutable::run(VM& vm) const vm.running_execution_context().local_variables.data()); } +void NativeExecutable::dump_disassembly() const +{ +#if ARCH(X86_64) + auto const* code_bytes = static_cast(m_code); + auto stream = X86::SimpleInstructionStream { code_bytes, m_size }; + auto disassembler = X86::Disassembler(stream); + + while (true) { + auto offset = stream.offset(); + auto virtual_offset = bit_cast(m_code) + offset; + auto insn = disassembler.next(); + if (!insn.has_value()) + break; + + StringBuilder builder; + builder.appendff("{:p} ", virtual_offset); + auto length = insn.value().length(); + for (size_t i = 0; i < 7; i++) { + if (i < length) + builder.appendff("{:02x} ", code_bytes[offset + i]); + else + builder.append(" "sv); + } + builder.append(" "sv); + builder.append(insn.value().to_deprecated_string(virtual_offset, nullptr)); + dbgln("{}", builder.string_view()); + + for (size_t bytes_printed = 7; bytes_printed < length; bytes_printed += 7) { + builder.clear(); + builder.appendff("{:p} ", virtual_offset + bytes_printed); + for (size_t i = bytes_printed; i < bytes_printed + 7 && i < length; i++) + builder.appendff(" {:02x}", code_bytes[offset + i]); + dbgln("{}", builder.string_view()); + } + } +#endif +} + } diff --git a/Userland/Libraries/LibJS/JIT/NativeExecutable.h b/Userland/Libraries/LibJS/JIT/NativeExecutable.h index 332a2a7054..d82aaee93e 100644 --- a/Userland/Libraries/LibJS/JIT/NativeExecutable.h +++ b/Userland/Libraries/LibJS/JIT/NativeExecutable.h @@ -21,6 +21,7 @@ public: ~NativeExecutable(); void run(VM&) const; + void dump_disassembly() const; private: void* m_code { nullptr };