mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:42:44 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									1d68c64b98
								
							
						
					
					
						commit
						ec8330b647
					
				
					 4 changed files with 48 additions and 1 deletions
				
			
		|  | @ -268,3 +268,6 @@ set(SOURCES | ||||||
| 
 | 
 | ||||||
| serenity_lib(LibJS js) | serenity_lib(LibJS js) | ||||||
| target_link_libraries(LibJS PRIVATE LibCore LibCrypto LibFileSystem LibRegex LibSyntax LibLocale LibUnicode LibJIT) | 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() | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ | ||||||
| #    define LOG_JIT_SUCCESS 1 | #    define LOG_JIT_SUCCESS 1 | ||||||
| #    define LOG_JIT_FAILURE 1 | #    define LOG_JIT_FAILURE 1 | ||||||
| #    define DUMP_JIT_MACHINE_CODE_TO_STDOUT 0 | #    define DUMP_JIT_MACHINE_CODE_TO_STDOUT 0 | ||||||
|  | #    define DUMP_JIT_DISASSEMBLY 0 | ||||||
| 
 | 
 | ||||||
| #    define TRY_OR_SET_EXCEPTION(expression)                                                                                        \ | #    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); |         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; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include <LibJS/Bytecode/Interpreter.h> | #include <LibJS/Bytecode/Interpreter.h> | ||||||
| #include <LibJS/JIT/NativeExecutable.h> | #include <LibJS/JIT/NativeExecutable.h> | ||||||
| #include <LibJS/Runtime/VM.h> | #include <LibJS/Runtime/VM.h> | ||||||
|  | #include <LibX86/Disassembler.h> | ||||||
| #include <sys/mman.h> | #include <sys/mman.h> | ||||||
| 
 | 
 | ||||||
| namespace JS::JIT { | namespace JS::JIT { | ||||||
|  | @ -30,4 +31,42 @@ void NativeExecutable::run(VM& vm) const | ||||||
|         vm.running_execution_context().local_variables.data()); |         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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ public: | ||||||
|     ~NativeExecutable(); |     ~NativeExecutable(); | ||||||
| 
 | 
 | ||||||
|     void run(VM&) const; |     void run(VM&) const; | ||||||
|  |     void dump_disassembly() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void* m_code { nullptr }; |     void* m_code { nullptr }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Simon Wanner
						Simon Wanner