Merge pull request #5121 from MerryMage/children-happen
Jit64: Merge memory allocations into a single allocation
This commit is contained in:
commit
9ea59133b3
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#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<CodeBlock*> 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<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);
|
||||
}
|
||||
|
||||
// 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<size_t>(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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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<u8*>(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();
|
||||
}
|
||||
|
|
|
@ -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<const void*, ConstantInfo> m_const_info;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue