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
commit 9ea59133b3
13 changed files with 101 additions and 108 deletions

View File

@ -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);
}
};

View File

@ -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)

View File

@ -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.

View File

@ -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);
};

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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();
};

View File

@ -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();
}