Browse Source

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.
Simon Wanner 1 năm trước cách đây
mục cha
commit
ec8330b647

+ 3 - 0
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()

+ 5 - 1
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<NativeExecutable> Compiler::compile(Bytecode::Executable& bytecode_execut
         dbgln("\033[32;1mJIT compilation succeeded!\033[0m {}", bytecode_executable.name);
     }
 
-    return make<NativeExecutable>(executable_memory, compiler.m_output.size());
+    auto executable = make<NativeExecutable>(executable_memory, compiler.m_output.size());
+    if constexpr (DUMP_JIT_DISASSEMBLY)
+        executable->dump_disassembly();
+    return executable;
 }
 
 }

+ 39 - 0
Userland/Libraries/LibJS/JIT/NativeExecutable.cpp

@@ -7,6 +7,7 @@
 #include <LibJS/Bytecode/Interpreter.h>
 #include <LibJS/JIT/NativeExecutable.h>
 #include <LibJS/Runtime/VM.h>
+#include <LibX86/Disassembler.h>
 #include <sys/mman.h>
 
 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<u8 const*>(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<size_t>(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
+}
+
 }

+ 1 - 0
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 };