Merge pull request #5121 from MerryMage/children-happen

Jit64: Merge memory allocations into a single allocation
This commit is contained in:
Markus Wick
2017-03-22 22:42:46 +01:00
committed by GitHub
13 changed files with 101 additions and 108 deletions

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <vector>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -27,12 +28,13 @@ private:
protected: protected:
u8* region = nullptr; u8* region = nullptr;
// Size of region we can use.
size_t region_size = 0; 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; bool m_is_child = false;
CodeBlock* m_child = nullptr; std::vector<CodeBlock*> m_children;
public: public:
virtual ~CodeBlock() virtual ~CodeBlock()
@ -42,16 +44,17 @@ public:
} }
// Call this before you generate any code. // 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_size = size;
region = static_cast<u8*>(Common::AllocateExecutableMemory(region_size, need_low)); total_region_size = size;
region = static_cast<u8*>(Common::AllocateExecutableMemory(total_region_size, need_low));
T::SetCodePtr(region); T::SetCodePtr(region);
} }
// Always clear code space with breakpoints, so that if someone accidentally executes // Always clear code space with breakpoints, so that if someone accidentally executes
// uninitialized, it just breaks into the debugger. // uninitialized, it just breaks into the debugger.
virtual void ClearCodeSpace() void ClearCodeSpace()
{ {
PoisonMemory(); PoisonMemory();
ResetCodePtr(); ResetCodePtr();
@ -60,14 +63,16 @@ public:
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job. // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace() void FreeCodeSpace()
{ {
Common::FreeMemoryPages(region, region_size); _assert_(!m_is_child);
Common::FreeMemoryPages(region, total_region_size);
region = nullptr; region = nullptr;
region_size = 0; region_size = 0;
parent_region_size = 0; total_region_size = 0;
if (m_has_child) for (CodeBlock* child : m_children)
{ {
m_child->region = nullptr; child->region = nullptr;
m_child->region_size = 0; child->region_size = 0;
child->total_region_size = 0;
} }
} }
@ -78,7 +83,8 @@ public:
void ResetCodePtr() { T::SetCodePtr(region); } void ResetCodePtr() { T::SetCodePtr(region); }
size_t GetSpaceLeft() const size_t GetSpaceLeft() const
{ {
return (m_has_child ? parent_region_size : region_size) - (T::GetCodePtr() - region); _assert_(static_cast<size_t>(T::GetCodePtr() - region) < region_size);
return region_size - (T::GetCodePtr() - region);
} }
bool IsAlmostFull() const bool IsAlmostFull() const
@ -86,16 +92,23 @@ public:
// This should be bigger than the biggest block ever. // This should be bigger than the biggest block ever.
return GetSpaceLeft() < 0x10000; 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!"); _assert_msg_(DYNA_REG, child_size < GetSpaceLeft(), "Insufficient space for child allocation.");
m_child = child; u8* child_region = region + region_size - child_size;
m_has_child = true; region_size -= child_size;
m_child->m_is_child = true; return child_region;
u8* child_region = region + region_size - size; }
m_child->region = child_region; void AddChildCodeSpace(CodeBlock* child, size_t child_size)
m_child->region_size = size; {
m_child->ResetCodePtr(); u8* child_region = AllocChildCodeSpace(child_size);
parent_region_size = region_size - 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);
} }
}; };

View File

@ -229,8 +229,15 @@ void Jit64::Init()
gpr.SetEmitter(this); gpr.SetEmitter(this);
fpr.SetEmitter(this); fpr.SetEmitter(this);
trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); const size_t routines_size = asm_routines.CODE_SIZE;
AllocCodeSpace(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 // 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. // 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 // important: do this *after* generating the global asm routines, because we can't use farcode in
// them. // them.
// it'll crash because the farcode functions get cleared on JIT clears. // 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(); Clear();
code_block.m_stats = &js.st; code_block.m_stats = &js.st;
@ -262,6 +269,7 @@ void Jit64::ClearCache()
blocks.Clear(); blocks.Clear();
trampolines.ClearCodeSpace(); trampolines.ClearCodeSpace();
m_far_code.ClearCodeSpace(); m_far_code.ClearCodeSpace();
m_const_pool.Clear();
ClearCodeSpace(); ClearCodeSpace();
Clear(); Clear();
UpdateMemoryOptions(); UpdateMemoryOptions();
@ -273,9 +281,8 @@ void Jit64::Shutdown()
FreeCodeSpace(); FreeCodeSpace();
blocks.Shutdown(); blocks.Shutdown();
trampolines.Shutdown();
asm_routines.Shutdown();
m_far_code.Shutdown(); m_far_code.Shutdown();
m_const_pool.Shutdown();
} }
void Jit64::FallBackToInterpreter(UGeckoInstruction inst) void Jit64::FallBackToInterpreter(UGeckoInstruction inst)

View File

@ -2,7 +2,7 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // 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/CommonTypes.h"
#include "Common/JitRegister.h" #include "Common/JitRegister.h"
#include "Common/x64ABI.h" #include "Common/x64ABI.h"
@ -11,7 +11,7 @@
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/HW/CPU.h" #include "Core/HW/CPU.h"
#include "Core/HW/Memmap.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/Jit64Common/Jit64PowerPCState.h"
#include "Core/PowerPC/PowerPC.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... // Not PowerPC state. Can't put in 'this' because it's out of range...
static void* s_saved_rsp; 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 // PLAN: no more block numbers - crazy opcodes just contain offset within
// dynarec buffer // dynarec buffer
// At this offset - 4, there is an int specifying the block number. // At this offset - 4, there is an int specifying the block number.

View File

@ -34,16 +34,11 @@ private:
u8* m_stack_top; u8* m_stack_top;
public: public:
void Init(u8* stack_top) // NOTE: When making large additions to the AsmCommon code, you might
{ // want to ensure this number is big enough.
m_stack_top = stack_top; static constexpr size_t CODE_SIZE = 16384;
// NOTE: When making large additions to the AsmCommon code, you might
// want to ensure this number is big enough. void Init(u8* stack_top);
AllocCodeSpace(16384);
Generate();
WriteProtect();
}
void Shutdown() { FreeCodeSpace(); }
void ResetStack(Gen::X64CodeBlock& emitter); void ResetStack(Gen::X64CodeBlock& emitter);
}; };

View File

@ -10,21 +10,31 @@
#include "Common/x64Emitter.h" #include "Common/x64Emitter.h"
#include "Core/PowerPC/Jit64Common/ConstantPool.h" #include "Core/PowerPC/Jit64Common/ConstantPool.h"
ConstantPool::ConstantPool(Gen::X64CodeBlock* parent) : m_parent(parent) ConstantPool::ConstantPool() = default;
{
}
ConstantPool::~ConstantPool() = default; ConstantPool::~ConstantPool() = default;
void ConstantPool::AllocCodeSpace() void ConstantPool::Init(void* memory, size_t size)
{ {
_assert_(!m_current_ptr); m_region = memory;
Init(); 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, 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<u8*>(info.m_location); u8* location = static_cast<u8*>(info.m_location);
return Gen::M(location + element_size * index); 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();
}

View File

@ -22,13 +22,12 @@ public:
static constexpr size_t CONST_POOL_SIZE = 1024 * 32; static constexpr size_t CONST_POOL_SIZE = 1024 * 32;
static constexpr size_t ALIGNMENT = 16; static constexpr size_t ALIGNMENT = 16;
explicit ConstantPool(Gen::X64CodeBlock* parent); ConstantPool();
~ConstantPool(); ~ConstantPool();
// ConstantPool reserves CONST_POOL_SIZE bytes from parent, and uses void Init(void* memory, size_t size);
// that space to store its constants. void Clear();
void AllocCodeSpace(); void Shutdown();
void ClearCodeSpace();
// Copies the value into the pool if it doesn't exist. Returns a pointer // 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 // to existing values if they were already copied. Pointer equality is
@ -37,16 +36,15 @@ public:
size_t index); size_t index);
private: private:
void Init();
struct ConstantInfo struct ConstantInfo
{ {
void* m_location; void* m_location;
size_t m_size; size_t m_size;
}; };
Gen::X64CodeBlock* m_parent; void* m_region = nullptr;
size_t m_region_size = 0;
void* m_current_ptr = nullptr; void* m_current_ptr = nullptr;
size_t m_remaining_size = CONST_POOL_SIZE; size_t m_remaining_size = 0;
std::map<const void*, ConstantInfo> m_const_info; std::map<const void*, ConstantInfo> m_const_info;
}; };

View File

@ -40,18 +40,6 @@ OpArg FixImmediate(int access_size, OpArg arg)
} }
} // Anonymous namespace } // 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() void EmuCodeBlock::MemoryExceptionCheck()
{ {
// TODO: We really should untangle the trampolines, exception handlers and // TODO: We really should untangle the trampolines, exception handlers and

View File

@ -23,9 +23,6 @@ class Mapping;
class EmuCodeBlock : public Gen::X64CodeBlock class EmuCodeBlock : public Gen::X64CodeBlock
{ {
public: public:
void ClearCodeSpace() override;
void AllocCodeSpace(size_t size, bool need_low = true) override;
void MemoryExceptionCheck(); void MemoryExceptionCheck();
// Simple functions to switch between near and far code emitting // Simple functions to switch between near and far code emitting
@ -121,7 +118,7 @@ public:
void Clear(); void Clear();
protected: protected:
ConstantPool m_const_pool{this}; ConstantPool m_const_pool;
FarCodeCache m_far_code; FarCodeCache m_far_code;
u8* m_near_code; // Backed up when we switch to far code. u8* m_near_code; // Backed up when we switch to far code.

View File

@ -4,15 +4,13 @@
#include "Core/PowerPC/Jit64Common/FarCodeCache.h" #include "Core/PowerPC/Jit64Common/FarCodeCache.h"
void FarCodeCache::Init(size_t size) void FarCodeCache::Init()
{ {
AllocCodeSpace(size);
m_enabled = true; m_enabled = true;
} }
void FarCodeCache::Shutdown() void FarCodeCache::Shutdown()
{ {
FreeCodeSpace();
m_enabled = false; m_enabled = false;
} }

View File

@ -17,7 +17,7 @@ constexpr size_t FARCODE_SIZE_MMU = 1024 * 1024 * 48;
class FarCodeCache : public Gen::X64CodeBlock class FarCodeCache : public Gen::X64CodeBlock
{ {
public: public:
void Init(size_t size); void Init();
void Shutdown(); void Shutdown();
bool Enabled() const; bool Enabled() const;

View File

@ -23,21 +23,11 @@
using namespace Gen; using namespace Gen;
void TrampolineCache::Init(size_t size)
{
AllocCodeSpace(size);
}
void TrampolineCache::ClearCodeSpace() void TrampolineCache::ClearCodeSpace()
{ {
X64CodeBlock::ClearCodeSpace(); X64CodeBlock::ClearCodeSpace();
} }
void TrampolineCache::Shutdown()
{
FreeCodeSpace();
}
const u8* TrampolineCache::GenerateTrampoline(const TrampolineInfo& info) const u8* TrampolineCache::GenerateTrampoline(const TrampolineInfo& info)
{ {
if (info.read) if (info.read)

View File

@ -24,8 +24,6 @@ class TrampolineCache : public EmuCodeBlock
const u8* GenerateWriteTrampoline(const TrampolineInfo& info); const u8* GenerateWriteTrampoline(const TrampolineInfo& info);
public: public:
void Init(size_t size);
void Shutdown();
const u8* GenerateTrampoline(const TrampolineInfo& info); const u8* GenerateTrampoline(const TrampolineInfo& info);
void ClearCodeSpace(); void ClearCodeSpace();
}; };

View File

@ -262,12 +262,19 @@ void JitIL::Init()
jo.accurateSinglePrecision = false; jo.accurateSinglePrecision = false;
UpdateMemoryOptions(); UpdateMemoryOptions();
trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); const size_t routines_size = asm_routines.CODE_SIZE;
AllocCodeSpace(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(); blocks.Init();
asm_routines.Init(nullptr); asm_routines.Init(nullptr);
m_far_code.Init();
m_far_code.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE);
Clear(); Clear();
code_block.m_stats = &js.st; code_block.m_stats = &js.st;
@ -299,8 +306,6 @@ void JitIL::Shutdown()
FreeCodeSpace(); FreeCodeSpace();
blocks.Shutdown(); blocks.Shutdown();
trampolines.Shutdown();
asm_routines.Shutdown();
m_far_code.Shutdown(); m_far_code.Shutdown();
} }