x64/block_of_code: Only commit minimum required memory

This commit is contained in:
Merry 2023-03-05 17:48:49 +00:00 committed by merry
parent c08c5a9362
commit b1584b66b6
5 changed files with 51 additions and 3 deletions

View file

@ -167,6 +167,7 @@ private:
invalidate_entire_cache = true; invalidate_entire_cache = true;
PerformCacheInvalidation(); 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}); 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); Optimization::PolyfillPass(ir_block, polyfill_options);

View file

@ -270,6 +270,7 @@ private:
invalidate_entire_cache = true; invalidate_entire_cache = true;
PerformRequestedCacheInvalidation(); PerformRequestedCacheInvalidation();
} }
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
// JIT Compile // JIT Compile
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };

View file

@ -55,10 +55,25 @@ const std::array<Xbyak::Reg64, ABI_PARAM_COUNT> BlockOfCode::ABI_PARAMS = {Block
namespace { namespace {
constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024; constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024;
constexpr size_t PRELUDE_COMMIT_SIZE = 16 * 1024 * 1024;
class CustomXbyakAllocator : public Xbyak::Allocator { class CustomXbyakAllocator : public Xbyak::Allocator {
public: 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<uint8_t*>(p);
}
void free(uint8_t* p) override {
VirtualFree(static_cast<void*>(p), 0, MEM_RELEASE);
}
bool useProtect() const override { return false; }
#else
static constexpr size_t DYNARMIC_PAGE_SIZE = 4096; static constexpr size_t DYNARMIC_PAGE_SIZE = 4096;
// Can't subclass Xbyak::MmapAllocator because it is not a pure interface // Can't subclass Xbyak::MmapAllocator because it is not a pure interface
@ -91,11 +106,11 @@ public:
std::memcpy(&size, p - DYNARMIC_PAGE_SIZE, sizeof(size_t)); std::memcpy(&size, p - DYNARMIC_PAGE_SIZE, sizeof(size_t));
munmap(p - DYNARMIC_PAGE_SIZE, size); 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; } bool useProtect() const override { return false; }
# endif # endif
#endif
}; };
// This is threadsafe as Xbyak::Allocator does not contain any state; it is a pure interface. // This is threadsafe as Xbyak::Allocator does not contain any state; it is a pure interface.
@ -211,6 +226,7 @@ BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_cod
, constant_pool(*this, CONSTANT_POOL_SIZE) , constant_pool(*this, CONSTANT_POOL_SIZE)
, host_features(GetHostFeatures()) { , host_features(GetHostFeatures()) {
EnableWriting(); EnableWriting();
EnsureMemoryCommitted(PRELUDE_COMMIT_SIZE);
GenRunCode(rcp); GenRunCode(rcp);
} }
@ -223,14 +239,22 @@ void BlockOfCode::PreludeComplete() {
void BlockOfCode::EnableWriting() { void BlockOfCode::EnableWriting() {
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
# ifdef _WIN32
ProtectMemory(getCode(), committed_size, false);
# else
ProtectMemory(getCode(), maxSize_, false); ProtectMemory(getCode(), maxSize_, false);
# endif # endif
#endif
} }
void BlockOfCode::DisableWriting() { void BlockOfCode::DisableWriting() {
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
# ifdef _WIN32
ProtectMemory(getCode(), committed_size, true);
# else
ProtectMemory(getCode(), maxSize_, true); ProtectMemory(getCode(), maxSize_, true);
# endif # endif
#endif
} }
void BlockOfCode::ClearCache() { void BlockOfCode::ClearCache() {
@ -246,6 +270,19 @@ size_t BlockOfCode::SpaceRemaining() const {
return &top_[maxSize_] - current_ptr; return &top_[maxSize_] - current_ptr;
} }
void BlockOfCode::EnsureMemoryCommitted([[maybe_unused]] size_t codesize) {
#ifdef _WIN32
if (committed_size < size_ + codesize) {
committed_size = std::min<size_t>(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 { HaltReason BlockOfCode::RunCode(void* jit_state, CodePtr code_ptr) const {
return run_code(jit_state, code_ptr); 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); throw Xbyak::Error(Xbyak::ERR_CODE_IS_TOO_BIG);
} }
EnsureMemoryCommitted(alloc_size);
void* ret = getCurr<void*>(); void* ret = getCurr<void*>();
size_ += alloc_size; size_ += alloc_size;
memset(ret, 0, alloc_size); memset(ret, 0, alloc_size);

View file

@ -51,6 +51,8 @@ public:
void ClearCache(); void ClearCache();
/// Calculates how much space is remaining to use. /// Calculates how much space is remaining to use.
size_t SpaceRemaining() const; 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. /// Runs emulated code from code_ptr.
HaltReason RunCode(void* jit_state, CodePtr code_ptr) const; HaltReason RunCode(void* jit_state, CodePtr code_ptr) const;
@ -176,6 +178,10 @@ private:
bool prelude_complete = false; bool prelude_complete = false;
CodePtr code_begin = nullptr; CodePtr code_begin = nullptr;
#ifdef _WIN32
size_t committed_size = 0;
#endif
ConstantPool constant_pool; ConstantPool constant_pool;
using RunCodeFuncType = HaltReason (*)(void*, CodePtr); using RunCodeFuncType = HaltReason (*)(void*, CodePtr);

View file

@ -15,6 +15,7 @@ namespace Dynarmic::Backend::X64 {
ConstantPool::ConstantPool(BlockOfCode& code, size_t size) ConstantPool::ConstantPool(BlockOfCode& code, size_t size)
: code(code), insertion_point(0) { : code(code), insertion_point(0) {
code.EnsureMemoryCommitted(align_size + size);
code.int3(); code.int3();
code.align(align_size); code.align(align_size);
pool = std::span<ConstantT>( pool = std::span<ConstantT>(