diff --git a/Utilities/JIT.cpp b/Utilities/JIT.cpp index da86e3b81e..836f737ee2 100644 --- a/Utilities/JIT.cpp +++ b/Utilities/JIT.cpp @@ -194,10 +194,75 @@ void jit_runtime::finalize() noexcept std::memcpy(alloc(s_data_init.size(), 1, false), s_data_init.data(), s_data_init.size()); } -asmjit::JitRuntime& asmjit::get_global_runtime() +asmjit::Runtime& asmjit::get_global_runtime() { + // 16 MiB for internal needs + static constexpr u64 size = 1024 * 1024 * 16; + + struct custom_runtime final : asmjit::HostRuntime + { + custom_runtime() noexcept + { + // Search starting in first 2 GiB of memory + for (u64 addr = size;; addr += size) + { + if (auto ptr = utils::memory_reserve(size, reinterpret_cast(addr))) + { + m_pos.raw() = static_cast(ptr); + break; + } + } + + // Initialize "end" pointer + m_max = m_pos + size; + + // Make memory writable + executable + utils::memory_commit(m_pos, size, utils::protection::wx); + } + + asmjit::Error _add(void** dst, asmjit::CodeHolder* code) noexcept override + { + std::size_t codeSize = code->getCodeSize(); + if (!codeSize) [[unlikely]] + { + *dst = nullptr; + return asmjit::kErrorNoCodeGenerated; + } + + void* p = m_pos.fetch_add(::align(codeSize, 4096)); + if (!p || m_pos > m_max) [[unlikely]] + { + *dst = nullptr; + return asmjit::kErrorNoVirtualMemory; + } + + std::size_t relocSize = code->relocate(p); + if (!relocSize) [[unlikely]] + { + *dst = nullptr; + return asmjit::kErrorInvalidState; + } + + utils::memory_protect(p, ::align(codeSize, 4096), utils::protection::rx); + flush(p, relocSize); + *dst = p; + + return asmjit::kErrorOk; + } + + asmjit::Error _release(void* ptr) noexcept override + { + return asmjit::kErrorOk; + } + + private: + atomic_t m_pos{}; + + std::byte* m_max{}; + }; + // Magic static - static asmjit::JitRuntime g_rt; + static custom_runtime g_rt; return g_rt; } diff --git a/Utilities/JIT.h b/Utilities/JIT.h index f3b13218a1..ac26c2392e 100644 --- a/Utilities/JIT.h +++ b/Utilities/JIT.h @@ -53,7 +53,7 @@ struct jit_runtime final : asmjit::HostRuntime namespace asmjit { // Should only be used to build global functions - asmjit::JitRuntime& get_global_runtime(); + asmjit::Runtime& get_global_runtime(); // Emit xbegin and adjacent loop, return label at xbegin [[nodiscard]] asmjit::Label build_transaction_enter(X86Assembler& c, Label fallback, const X86Gp& ctr, uint less_than); @@ -64,7 +64,7 @@ namespace asmjit // Build runtime function with asmjit::X86Assembler template -FT build_function_asm(F&& builder) +inline FT build_function_asm(F&& builder) { using namespace asmjit;