diff --git a/Source/Core/Common/CodeBlock.h b/Source/Core/Common/CodeBlock.h index 28a4919e66..9c3da1058b 100644 --- a/Source/Core/Common/CodeBlock.h +++ b/Source/Core/Common/CodeBlock.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "Common/Assert.h" #include "Common/CommonTypes.h" @@ -27,12 +28,13 @@ private: protected: u8* region = nullptr; + // Size of region we can use. size_t region_size = 0; - size_t parent_region_size = 0; + // Original size of the region we allocated. + size_t total_region_size = 0; - bool m_has_child = false; bool m_is_child = false; - CodeBlock* m_child = nullptr; + std::vector m_children; public: virtual ~CodeBlock() @@ -42,16 +44,17 @@ public: } // Call this before you generate any code. - virtual void AllocCodeSpace(size_t size, bool need_low = true) + void AllocCodeSpace(size_t size, bool need_low = true) { region_size = size; - region = static_cast(Common::AllocateExecutableMemory(region_size, need_low)); + total_region_size = size; + region = static_cast(Common::AllocateExecutableMemory(total_region_size, need_low)); T::SetCodePtr(region); } // Always clear code space with breakpoints, so that if someone accidentally executes // uninitialized, it just breaks into the debugger. - virtual void ClearCodeSpace() + void ClearCodeSpace() { PoisonMemory(); ResetCodePtr(); @@ -60,14 +63,16 @@ public: // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. void FreeCodeSpace() { - Common::FreeMemoryPages(region, region_size); + _assert_(!m_is_child); + Common::FreeMemoryPages(region, total_region_size); region = nullptr; region_size = 0; - parent_region_size = 0; - if (m_has_child) + total_region_size = 0; + for (CodeBlock* child : m_children) { - m_child->region = nullptr; - m_child->region_size = 0; + child->region = nullptr; + child->region_size = 0; + child->total_region_size = 0; } } @@ -78,7 +83,8 @@ public: void ResetCodePtr() { T::SetCodePtr(region); } size_t GetSpaceLeft() const { - return (m_has_child ? parent_region_size : region_size) - (T::GetCodePtr() - region); + _assert_(static_cast(T::GetCodePtr() - region) < region_size); + return region_size - (T::GetCodePtr() - region); } bool IsAlmostFull() const @@ -86,16 +92,23 @@ public: // This should be bigger than the biggest block ever. return GetSpaceLeft() < 0x10000; } - void AddChildCodeSpace(CodeBlock* child, size_t size) + + bool HasChildren() const { return region_size != total_region_size; } + u8* AllocChildCodeSpace(size_t child_size) { - _assert_msg_(DYNA_REC, !m_has_child, "Already have a child! Can't have another!"); - m_child = child; - m_has_child = true; - m_child->m_is_child = true; - u8* child_region = region + region_size - size; - m_child->region = child_region; - m_child->region_size = size; - m_child->ResetCodePtr(); - parent_region_size = region_size - size; + _assert_msg_(DYNA_REG, child_size < GetSpaceLeft(), "Insufficient space for child allocation."); + u8* child_region = region + region_size - child_size; + region_size -= child_size; + return child_region; + } + void AddChildCodeSpace(CodeBlock* child, size_t child_size) + { + u8* child_region = AllocChildCodeSpace(child_size); + child->m_is_child = true; + child->region = child_region; + child->region_size = child_size; + child->total_region_size = child_size; + child->ResetCodePtr(); + m_children.emplace_back(child); } }; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 74ca3ffd96..6d506b3d06 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -229,8 +229,15 @@ void Jit64::Init() gpr.SetEmitter(this); fpr.SetEmitter(this); - trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); - AllocCodeSpace(CODE_SIZE); + const size_t routines_size = asm_routines.CODE_SIZE; + const size_t trampolines_size = jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE; + const size_t farcode_size = jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE; + const size_t constpool_size = m_const_pool.CONST_POOL_SIZE; + AllocCodeSpace(CODE_SIZE + routines_size + trampolines_size + farcode_size + constpool_size); + AddChildCodeSpace(&asm_routines, routines_size); + AddChildCodeSpace(&trampolines, trampolines_size); + AddChildCodeSpace(&m_far_code, farcode_size); + m_const_pool.Init(AllocChildCodeSpace(constpool_size), constpool_size); // BLR optimization has the same consequences as block linking, as well as // depending on the fault handler to be safe in the event of excessive BL. @@ -248,7 +255,7 @@ void Jit64::Init() // important: do this *after* generating the global asm routines, because we can't use farcode in // them. // it'll crash because the farcode functions get cleared on JIT clears. - m_far_code.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE); + m_far_code.Init(); Clear(); code_block.m_stats = &js.st; @@ -262,6 +269,7 @@ void Jit64::ClearCache() blocks.Clear(); trampolines.ClearCodeSpace(); m_far_code.ClearCodeSpace(); + m_const_pool.Clear(); ClearCodeSpace(); Clear(); UpdateMemoryOptions(); @@ -273,9 +281,8 @@ void Jit64::Shutdown() FreeCodeSpace(); blocks.Shutdown(); - trampolines.Shutdown(); - asm_routines.Shutdown(); m_far_code.Shutdown(); + m_const_pool.Shutdown(); } void Jit64::FallBackToInterpreter(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index 1239570dbd..cb2d12156d 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/PowerPC/Jit64/Jit.h" +#include "Core/PowerPC/Jit64/JitAsm.h" #include "Common/CommonTypes.h" #include "Common/JitRegister.h" #include "Common/x64ABI.h" @@ -11,7 +11,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/Jit64/JitAsm.h" +#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" #include "Core/PowerPC/PowerPC.h" @@ -20,6 +20,14 @@ using namespace Gen; // Not PowerPC state. Can't put in 'this' because it's out of range... static void* s_saved_rsp; +void Jit64AsmRoutineManager::Init(u8* stack_top) +{ + m_const_pool.Init(AllocChildCodeSpace(4096), 4096); + m_stack_top = stack_top; + Generate(); + WriteProtect(); +} + // PLAN: no more block numbers - crazy opcodes just contain offset within // dynarec buffer // At this offset - 4, there is an int specifying the block number. diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.h b/Source/Core/Core/PowerPC/Jit64/JitAsm.h index 2cdac46b45..6aaad10031 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.h +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.h @@ -34,16 +34,11 @@ private: u8* m_stack_top; public: - void Init(u8* stack_top) - { - m_stack_top = stack_top; - // NOTE: When making large additions to the AsmCommon code, you might - // want to ensure this number is big enough. - AllocCodeSpace(16384); - Generate(); - WriteProtect(); - } + // NOTE: When making large additions to the AsmCommon code, you might + // want to ensure this number is big enough. + static constexpr size_t CODE_SIZE = 16384; + + void Init(u8* stack_top); - void Shutdown() { FreeCodeSpace(); } void ResetStack(Gen::X64CodeBlock& emitter); }; diff --git a/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp index 20c3f46802..cd8da238a0 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp @@ -10,21 +10,31 @@ #include "Common/x64Emitter.h" #include "Core/PowerPC/Jit64Common/ConstantPool.h" -ConstantPool::ConstantPool(Gen::X64CodeBlock* parent) : m_parent(parent) -{ -} +ConstantPool::ConstantPool() = default; ConstantPool::~ConstantPool() = default; -void ConstantPool::AllocCodeSpace() +void ConstantPool::Init(void* memory, size_t size) { - _assert_(!m_current_ptr); - Init(); + m_region = memory; + m_region_size = size; + Clear(); } -void ConstantPool::ClearCodeSpace() +void ConstantPool::Clear() { - Init(); + m_current_ptr = m_region; + m_remaining_size = m_region_size; + m_const_info.clear(); +} + +void ConstantPool::Shutdown() +{ + m_region = nullptr; + m_region_size = 0; + m_current_ptr = nullptr; + m_remaining_size = 0; + m_const_info.clear(); } Gen::OpArg ConstantPool::GetConstantOpArg(const void* value, size_t element_size, @@ -51,17 +61,3 @@ Gen::OpArg ConstantPool::GetConstantOpArg(const void* value, size_t element_size u8* location = static_cast(info.m_location); return Gen::M(location + element_size * index); } - -void ConstantPool::Init() -{ - // If execution happens to run to the start of the constant pool, halt. - m_parent->INT3(); - m_parent->AlignCode16(); - - // Reserve a block of memory CONST_POOL_SIZE in size. - m_current_ptr = m_parent->GetWritableCodePtr(); - m_parent->ReserveCodeSpace(CONST_POOL_SIZE); - - m_remaining_size = CONST_POOL_SIZE; - m_const_info.clear(); -} diff --git a/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h index eba5cbec0f..732a41af9d 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h +++ b/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.h @@ -22,13 +22,12 @@ public: static constexpr size_t CONST_POOL_SIZE = 1024 * 32; static constexpr size_t ALIGNMENT = 16; - explicit ConstantPool(Gen::X64CodeBlock* parent); + ConstantPool(); ~ConstantPool(); - // ConstantPool reserves CONST_POOL_SIZE bytes from parent, and uses - // that space to store its constants. - void AllocCodeSpace(); - void ClearCodeSpace(); + void Init(void* memory, size_t size); + void Clear(); + void Shutdown(); // Copies the value into the pool if it doesn't exist. Returns a pointer // to existing values if they were already copied. Pointer equality is @@ -37,16 +36,15 @@ public: size_t index); private: - void Init(); - struct ConstantInfo { void* m_location; size_t m_size; }; - Gen::X64CodeBlock* m_parent; + void* m_region = nullptr; + size_t m_region_size = 0; void* m_current_ptr = nullptr; - size_t m_remaining_size = CONST_POOL_SIZE; + size_t m_remaining_size = 0; std::map m_const_info; }; diff --git a/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp index 3a35c8dfa7..7408765a68 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp @@ -40,18 +40,6 @@ OpArg FixImmediate(int access_size, OpArg arg) } } // Anonymous namespace -void EmuCodeBlock::ClearCodeSpace() -{ - X64CodeBlock::ClearCodeSpace(); - m_const_pool.ClearCodeSpace(); -} - -void EmuCodeBlock::AllocCodeSpace(size_t size, bool need_low) -{ - X64CodeBlock::AllocCodeSpace(size + ConstantPool::CONST_POOL_SIZE, need_low); - m_const_pool.AllocCodeSpace(); -} - void EmuCodeBlock::MemoryExceptionCheck() { // TODO: We really should untangle the trampolines, exception handlers and diff --git a/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h index 08bafb49d7..244494a31e 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h +++ b/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.h @@ -23,9 +23,6 @@ class Mapping; class EmuCodeBlock : public Gen::X64CodeBlock { public: - void ClearCodeSpace() override; - void AllocCodeSpace(size_t size, bool need_low = true) override; - void MemoryExceptionCheck(); // Simple functions to switch between near and far code emitting @@ -121,7 +118,7 @@ public: void Clear(); protected: - ConstantPool m_const_pool{this}; + ConstantPool m_const_pool; FarCodeCache m_far_code; u8* m_near_code; // Backed up when we switch to far code. diff --git a/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp index 72909f6a6a..7efdd6f331 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp @@ -4,15 +4,13 @@ #include "Core/PowerPC/Jit64Common/FarCodeCache.h" -void FarCodeCache::Init(size_t size) +void FarCodeCache::Init() { - AllocCodeSpace(size); m_enabled = true; } void FarCodeCache::Shutdown() { - FreeCodeSpace(); m_enabled = false; } diff --git a/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h index bc82045870..9cbbf2c052 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h +++ b/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.h @@ -17,7 +17,7 @@ constexpr size_t FARCODE_SIZE_MMU = 1024 * 1024 * 48; class FarCodeCache : public Gen::X64CodeBlock { public: - void Init(size_t size); + void Init(); void Shutdown(); bool Enabled() const; diff --git a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp index 5fa7c2d911..25848a1a24 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp @@ -23,21 +23,11 @@ using namespace Gen; -void TrampolineCache::Init(size_t size) -{ - AllocCodeSpace(size); -} - void TrampolineCache::ClearCodeSpace() { X64CodeBlock::ClearCodeSpace(); } -void TrampolineCache::Shutdown() -{ - FreeCodeSpace(); -} - const u8* TrampolineCache::GenerateTrampoline(const TrampolineInfo& info) { if (info.read) diff --git a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h index 769c4b4c84..9fc9a0b940 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h +++ b/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.h @@ -24,8 +24,6 @@ class TrampolineCache : public EmuCodeBlock const u8* GenerateWriteTrampoline(const TrampolineInfo& info); public: - void Init(size_t size); - void Shutdown(); const u8* GenerateTrampoline(const TrampolineInfo& info); void ClearCodeSpace(); }; diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp index 9a9730efc0..c2200791f2 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp @@ -262,12 +262,19 @@ void JitIL::Init() jo.accurateSinglePrecision = false; UpdateMemoryOptions(); - trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); - AllocCodeSpace(CODE_SIZE); + const size_t routines_size = asm_routines.CODE_SIZE; + const size_t trampolines_size = jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE; + const size_t farcode_size = jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE; + const size_t constpool_size = m_const_pool.CONST_POOL_SIZE; + AllocCodeSpace(CODE_SIZE + routines_size + trampolines_size + farcode_size + constpool_size); + AddChildCodeSpace(&asm_routines, routines_size); + AddChildCodeSpace(&trampolines, trampolines_size); + AddChildCodeSpace(&m_far_code, farcode_size); + m_const_pool.Init(AllocChildCodeSpace(constpool_size), constpool_size); + blocks.Init(); asm_routines.Init(nullptr); - - m_far_code.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE); + m_far_code.Init(); Clear(); code_block.m_stats = &js.st; @@ -299,8 +306,6 @@ void JitIL::Shutdown() FreeCodeSpace(); blocks.Shutdown(); - trampolines.Shutdown(); - asm_routines.Shutdown(); m_far_code.Shutdown(); }