diff --git a/src/dynarmic/backend/x64/a32_interface.cpp b/src/dynarmic/backend/x64/a32_interface.cpp index 4193e22e..2c6b22f9 100644 --- a/src/dynarmic/backend/x64/a32_interface.cpp +++ b/src/dynarmic/backend/x64/a32_interface.cpp @@ -167,6 +167,7 @@ private: invalidate_entire_cache = true; PerformCacheInvalidation(); } + block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE); IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); Optimization::PolyfillPass(ir_block, polyfill_options); diff --git a/src/dynarmic/backend/x64/a64_interface.cpp b/src/dynarmic/backend/x64/a64_interface.cpp index b2bfa6c8..1ad0d196 100644 --- a/src/dynarmic/backend/x64/a64_interface.cpp +++ b/src/dynarmic/backend/x64/a64_interface.cpp @@ -270,6 +270,7 @@ private: invalidate_entire_cache = true; PerformRequestedCacheInvalidation(); } + block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE); // JIT Compile const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; diff --git a/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/backend/x64/block_of_code.cpp index 2b26c6c6..e949c466 100644 --- a/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/backend/x64/block_of_code.cpp @@ -55,10 +55,25 @@ const std::array BlockOfCode::ABI_PARAMS = {Block namespace { constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024; +constexpr size_t PRELUDE_COMMIT_SIZE = 16 * 1024 * 1024; class CustomXbyakAllocator : public Xbyak::Allocator { public: -#ifndef _WIN32 +#ifdef _WIN32 + uint8_t* alloc(size_t size) override { + void* p = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); + if (p == nullptr) { + throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC); + } + return static_cast(p); + } + + void free(uint8_t* p) override { + VirtualFree(static_cast(p), 0, MEM_RELEASE); + } + + bool useProtect() const override { return false; } +#else static constexpr size_t DYNARMIC_PAGE_SIZE = 4096; // Can't subclass Xbyak::MmapAllocator because it is not a pure interface @@ -91,10 +106,10 @@ public: std::memcpy(&size, p - DYNARMIC_PAGE_SIZE, sizeof(size_t)); munmap(p - DYNARMIC_PAGE_SIZE, size); } -#endif -#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT +# ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT bool useProtect() const override { return false; } +# endif #endif }; @@ -211,6 +226,7 @@ BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_cod , constant_pool(*this, CONSTANT_POOL_SIZE) , host_features(GetHostFeatures()) { EnableWriting(); + EnsureMemoryCommitted(PRELUDE_COMMIT_SIZE); GenRunCode(rcp); } @@ -223,13 +239,21 @@ void BlockOfCode::PreludeComplete() { void BlockOfCode::EnableWriting() { #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT +# ifdef _WIN32 + ProtectMemory(getCode(), committed_size, false); +# else ProtectMemory(getCode(), maxSize_, false); +# endif #endif } void BlockOfCode::DisableWriting() { #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT +# ifdef _WIN32 + ProtectMemory(getCode(), committed_size, true); +# else ProtectMemory(getCode(), maxSize_, true); +# endif #endif } @@ -246,6 +270,19 @@ size_t BlockOfCode::SpaceRemaining() const { return &top_[maxSize_] - current_ptr; } +void BlockOfCode::EnsureMemoryCommitted([[maybe_unused]] size_t codesize) { +#ifdef _WIN32 + if (committed_size < size_ + codesize) { + committed_size = std::min(maxSize_, committed_size + codesize); +# ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT + VirtualAlloc(top_, committed_size, MEM_COMMIT, PAGE_READWRITE); +# else + VirtualAlloc(top_, committed_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +# endif + } +#endif +} + HaltReason BlockOfCode::RunCode(void* jit_state, CodePtr code_ptr) const { return run_code(jit_state, code_ptr); } @@ -480,6 +517,8 @@ void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) { throw Xbyak::Error(Xbyak::ERR_CODE_IS_TOO_BIG); } + EnsureMemoryCommitted(alloc_size); + void* ret = getCurr(); size_ += alloc_size; memset(ret, 0, alloc_size); diff --git a/src/dynarmic/backend/x64/block_of_code.h b/src/dynarmic/backend/x64/block_of_code.h index 73ab9cf2..2481e94c 100644 --- a/src/dynarmic/backend/x64/block_of_code.h +++ b/src/dynarmic/backend/x64/block_of_code.h @@ -51,6 +51,8 @@ public: void ClearCache(); /// Calculates how much space is remaining to use. size_t SpaceRemaining() const; + /// Ensure at least codesize bytes of code cache memory are committed at the current code_ptr. + void EnsureMemoryCommitted(size_t codesize); /// Runs emulated code from code_ptr. HaltReason RunCode(void* jit_state, CodePtr code_ptr) const; @@ -176,6 +178,10 @@ private: bool prelude_complete = false; CodePtr code_begin = nullptr; +#ifdef _WIN32 + size_t committed_size = 0; +#endif + ConstantPool constant_pool; using RunCodeFuncType = HaltReason (*)(void*, CodePtr); diff --git a/src/dynarmic/backend/x64/constant_pool.cpp b/src/dynarmic/backend/x64/constant_pool.cpp index 29678847..443cb4c0 100644 --- a/src/dynarmic/backend/x64/constant_pool.cpp +++ b/src/dynarmic/backend/x64/constant_pool.cpp @@ -15,6 +15,7 @@ namespace Dynarmic::Backend::X64 { ConstantPool::ConstantPool(BlockOfCode& code, size_t size) : code(code), insertion_point(0) { + code.EnsureMemoryCommitted(align_size + size); code.int3(); code.align(align_size); pool = std::span(