diff --git a/src/backend_x64/block_of_code.cpp b/src/backend_x64/block_of_code.cpp index 6db3f3bf..78db4e1d 100644 --- a/src/backend_x64/block_of_code.cpp +++ b/src/backend_x64/block_of_code.cpp @@ -57,6 +57,25 @@ void BlockOfCode::ClearCache() { SetCodePtr(near_code_begin); } +size_t BlockOfCode::SpaceRemaining() const { + // This function provides an underestimate of near-code-size but that's okay. + // (Why? The maximum size of near code should be measured from near_code_begin, not top_.) + // These are offsets from Xbyak::CodeArray::top_. + std::size_t far_code_offset, near_code_offset; + if (in_far_code) { + near_code_offset = static_cast(near_code_ptr) - getCode(); + far_code_offset = getCurr() - getCode(); + } else { + near_code_offset = getCurr() - getCode(); + far_code_offset = static_cast(far_code_ptr) - getCode(); + } + if (far_code_offset > TOTAL_CODE_SIZE) + return 0; + if (near_code_offset > FAR_CODE_OFFSET) + return 0; + return std::min(TOTAL_CODE_SIZE - far_code_offset, FAR_CODE_OFFSET - near_code_offset); +} + size_t BlockOfCode::RunCode(JitState* jit_state, size_t cycles_to_run) const { constexpr size_t max_cycles_to_run = static_cast(std::numeric_limitscycles_remaining)>::max()); ASSERT(cycles_to_run <= max_cycles_to_run); diff --git a/src/backend_x64/block_of_code.h b/src/backend_x64/block_of_code.h index e264f215..603be129 100644 --- a/src/backend_x64/block_of_code.h +++ b/src/backend_x64/block_of_code.h @@ -28,6 +28,8 @@ public: /// Clears this block of code and resets code pointer to beginning. void ClearCache(); + /// Calculates how much space is remaining to use. This is the minimum of near code and far code. + size_t SpaceRemaining() const; /// Runs emulated code for approximately `cycles_to_run` cycles. size_t RunCode(JitState* jit_state, size_t cycles_to_run) const; diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index 694daa4e..0f3fdc8c 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -141,6 +141,12 @@ private: if (block) return *block; + constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024; + if (block_of_code.SpaceRemaining() < MINIMUM_REMAINING_CODESIZE) { + invalidate_entire_cache = true; + PerformCacheInvalidation(); + } + IR::Block ir_block = Arm::Translate(descriptor, callbacks.memory.ReadCode); Optimization::GetSetElimination(ir_block); Optimization::DeadCodeElimination(ir_block);