Remove dumb CodeBlock duplication in the emitters.

Fixes issue 6990.
This uses a bit of templating to remove the duplicate code that is the CodeBlocks in each emitter headers.
No actual functionality change in this.
This commit is contained in:
Ryan Houdek 2014-04-09 01:22:52 -05:00
parent 7d8604ac1c
commit 87d106d65c
15 changed files with 111 additions and 145 deletions

View File

@ -8,8 +8,8 @@
#include <vector>
#include "Common/CodeBlock.h"
#include "Common/Common.h"
#include "Common/MemoryUtil.h"
#if defined(__SYMBIAN32__) || defined(PANDORA)
#include <signal.h>
@ -700,78 +700,18 @@ public:
void VST1(u32 Size, ARMReg Vd, ARMReg Rn, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
};
// Everything that needs to generate X86 code should inherit from this.
// You get memory management for free, plus, you can use all the MOV etc functions without
// having to prefix them with gen-> or something similar.
class ARMXCodeBlock : public ARMXEmitter
class ARMCodeBlock : public CodeBlock<ARMXEmitter>
{
protected:
u8 *region;
size_t region_size;
public:
ARMXCodeBlock() : region(nullptr), region_size(0) {}
virtual ~ARMXCodeBlock() { if (region) FreeCodeSpace(); }
// Call this before you generate any code.
void AllocCodeSpace(int size)
private:
void PoisonMemory() override
{
region_size = size;
region = (u8*)AllocateExecutableMemory(region_size);
SetCodePtr(region);
}
// Always clear code space with breakpoints, so that if someone accidentally executes
// uninitialized, it just breaks into the debugger.
void ClearCodeSpace()
{
// x86/64: 0xCC = breakpoint
memset(region, 0xCC, region_size);
ResetCodePtr();
}
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace()
{
#ifndef __SYMBIAN32__
FreeMemoryPages(region, region_size);
region = nullptr;
#endif
region_size = 0;
}
bool IsInSpace(u8 *ptr)
{
return ptr >= region && ptr < region + region_size;
}
// Cannot currently be undone. Will write protect the entire code region.
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
void WriteProtect()
{
WriteProtectMemory(region, region_size, true);
}
void UnWriteProtect()
{
UnWriteProtectMemory(region, region_size, false);
}
void ResetCodePtr()
{
SetCodePtr(region);
}
size_t GetSpaceLeft() const
{
return region_size - (GetCodePtr() - region);
}
u8 *GetBasePtr() {
return region;
}
size_t GetOffset(u8 *ptr) {
return ptr - region;
u32* ptr = (u32*)region;
u32* maxptr = (u32*)region + region_size;
// If our memory isn't a multiple of u32 then this won't write the last remaining bytes with anything
// Less than optimal, but there would be nothing we could do but throw a runtime warning anyway.
// ARM: 0x01200070 = BKPT 0
while (ptr < maxptr)
*ptr++ = 0x01200070;
}
};

View File

@ -0,0 +1,76 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "Common/Common.h"
#include "Common/MemoryUtil.h"
// Everything that needs to generate code should inherit from this.
// You get memory management for free, plus, you can use all emitter functions without
// having to prefix them with gen-> or something similar.
// Example implementation:
// class JIT : public CodeBlock<ARMXEmitter> {}
template<class T> class CodeBlock : public T, NonCopyable
{
private:
// A privately used function to set the executable RAM space to something invalid.
// For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction
virtual void PoisonMemory() = 0;
protected:
u8 *region;
size_t region_size;
public:
CodeBlock() : region(nullptr), region_size(0) {}
virtual ~CodeBlock() { if (region) FreeCodeSpace(); }
// Call this before you generate any code.
void AllocCodeSpace(int size)
{
region_size = size;
region = (u8*)AllocateExecutableMemory(region_size);
T::SetCodePtr(region);
}
// Always clear code space with breakpoints, so that if someone accidentally executes
// uninitialized, it just breaks into the debugger.
void ClearCodeSpace()
{
PoisonMemory();
ResetCodePtr();
}
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace()
{
FreeMemoryPages(region, region_size);
region = nullptr;
region_size = 0;
}
bool IsInSpace(u8 *ptr)
{
return (ptr >= region) && (ptr < (region + region_size));
}
// Cannot currently be undone. Will write protect the entire code region.
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
void WriteProtect()
{
WriteProtectMemory(region, region_size, true);
}
void ResetCodePtr()
{
T::SetCodePtr(region);
}
size_t GetSpaceLeft() const
{
return region_size - (T::GetCodePtr() - region);
}
};

View File

@ -50,6 +50,7 @@
<ClInclude Include="BreakPoints.h" />
<ClInclude Include="CDUtils.h" />
<ClInclude Include="ChunkFile.h" />
<ClInclude Include="CodeBlock.h" />
<ClInclude Include="ColorUtil.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="CommonFuncs.h" />

View File

@ -16,6 +16,7 @@
<ClInclude Include="BreakPoints.h" />
<ClInclude Include="CDUtils.h" />
<ClInclude Include="ChunkFile.h" />
<ClInclude Include="CodeBlock.h" />
<ClInclude Include="ColorUtil.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="CommonFuncs.h" />

View File

@ -10,8 +10,8 @@
#include <cstring>
#include <functional>
#include "Common/CodeBlock.h"
#include "Common/Common.h"
#include "Common/MemoryUtil.h"
namespace Gen
{
@ -762,65 +762,13 @@ public:
}
}; // class XEmitter
// Everything that needs to generate X86 code should inherit from this.
// You get memory management for free, plus, you can use all the MOV etc functions without
// having to prefix them with gen-> or something similar.
class XCodeBlock : public XEmitter
class X64CodeBlock : public CodeBlock<XEmitter>
{
protected:
u8 *region;
size_t region_size;
public:
XCodeBlock() : region(nullptr), region_size(0) {}
virtual ~XCodeBlock() { if (region) FreeCodeSpace(); }
// Call this before you generate any code.
void AllocCodeSpace(int size)
{
region_size = size;
region = (u8*)AllocateExecutableMemory(region_size);
SetCodePtr(region);
}
// Always clear code space with breakpoints, so that if someone accidentally executes
// uninitialized, it just breaks into the debugger.
void ClearCodeSpace()
private:
void PoisonMemory() override
{
// x86/64: 0xCC = breakpoint
memset(region, 0xCC, region_size);
ResetCodePtr();
}
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace()
{
FreeMemoryPages(region, region_size);
region = nullptr;
region_size = 0;
}
bool IsInSpace(u8 *ptr)
{
return ptr >= region && ptr < region + region_size;
}
// Cannot currently be undone. Will write protect the entire code region.
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
void WriteProtect()
{
WriteProtectMemory(region, region_size, true);
}
void ResetCodePtr()
{
SetCodePtr(region);
}
size_t GetSpaceLeft() const
{
return region_size - (GetCodePtr() - region);
}
};

View File

@ -18,7 +18,7 @@
typedef u32 (*DSPCompiledCode)();
typedef const u8 *Block;
class DSPEmitter : public Gen::XCodeBlock, NonCopyable
class DSPEmitter : public Gen::X64CodeBlock
{
public:
DSPEmitter();

View File

@ -27,7 +27,7 @@
#include "Core/PowerPC/JitCommon/JitBase.h"
#define PPCSTATE_OFF(elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0]))
class JitArm : public JitBase, public ArmGen::ARMXCodeBlock
class JitArm : public JitBase, public ArmGen::ARMCodeBlock
{
private:
JitArmBlockCache blocks;

View File

@ -7,8 +7,7 @@
#include "Common/ArmEmitter.h"
#include "Core/PowerPC/JitCommon/JitAsmCommon.h"
using namespace ArmGen;
class JitArmAsmRoutineManager : public CommonAsmRoutinesBase, public ARMXCodeBlock
class JitArmAsmRoutineManager : public CommonAsmRoutinesBase, public ArmGen::ARMCodeBlock
{
private:
void Generate();

View File

@ -13,7 +13,7 @@
#include "Core/PowerPC/JitILCommon/JitILBase.h"
#define PPCSTATE_OFF(elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0]))
class JitArmIL : public JitILBase, public ArmGen::ARMXCodeBlock
class JitArmIL : public JitILBase, public ArmGen::ARMCodeBlock
{
private:
JitArmBlockCache blocks;
@ -60,8 +60,8 @@ public:
//
void WriteCode(u32 exitAddress);
void WriteExit(u32 destination);
void WriteExitDestInReg(ARMReg Reg);
void WriteRfiExitDestInR(ARMReg Reg);
void WriteExitDestInReg(ArmGen::ARMReg Reg);
void WriteRfiExitDestInR(ArmGen::ARMReg Reg);
void WriteExceptionExit();
// OPCODES
@ -78,10 +78,10 @@ public:
void DynaRunTable63(UGeckoInstruction inst);
// Binary ops
void BIN_AND(ARMReg reg, Operand2 op2);
void BIN_XOR(ARMReg reg, Operand2 op2);
void BIN_OR(ARMReg reg, Operand2 op2);
void BIN_ADD(ARMReg reg, Operand2 op2);
void BIN_AND(ArmGen::ARMReg reg, ArmGen::Operand2 op2);
void BIN_XOR(ArmGen::ARMReg reg, ArmGen::Operand2 op2);
void BIN_OR(ArmGen::ARMReg reg, ArmGen::Operand2 op2);
void BIN_ADD(ArmGen::ARMReg reg, ArmGen::Operand2 op2);
// Branches
void bx(UGeckoInstruction inst);

View File

@ -14,6 +14,8 @@
#include "Core/PowerPC/JitArmIL/JitILAsm.h"
#include "Core/PowerPC/JitCommon/JitCache.h"
using namespace ArmGen;
JitArmILAsmRoutineManager armil_asm_routines;
void JitArmILAsmRoutineManager::Generate()
{

View File

@ -7,8 +7,7 @@
#include "Common/ArmEmitter.h"
#include "Core/PowerPC/JitCommon/JitAsmCommon.h"
using namespace ArmGen;
class JitArmILAsmRoutineManager : public CommonAsmRoutinesBase, public ARMXCodeBlock
class JitArmILAsmRoutineManager : public CommonAsmRoutinesBase, public ArmGen::ARMCodeBlock
{
private:
void Generate();

View File

@ -234,7 +234,7 @@ static inline u64 *ContextRN(SContext* ctx, int n)
#define CTX_PC CTX_EIP
#endif
class TrampolineCache : public Gen::XCodeBlock
class TrampolineCache : public Gen::X64CodeBlock
{
public:
void Init();

View File

@ -125,7 +125,7 @@ template <typename T>
class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
{
public:
MMIOReadCodeGenerator(Gen::XCodeBlock* code, u32 registers_in_use,
MMIOReadCodeGenerator(Gen::X64CodeBlock* code, u32 registers_in_use,
Gen::X64Reg dst_reg, u32 address, bool sign_extend)
: m_code(code), m_registers_in_use(registers_in_use), m_dst_reg(dst_reg),
m_address(address), m_sign_extend(sign_extend)
@ -199,7 +199,7 @@ private:
MoveOpArgToReg(sbits, R(EAX));
}
Gen::XCodeBlock* m_code;
Gen::X64CodeBlock* m_code;
u32 m_registers_in_use;
Gen::X64Reg m_dst_reg;
u32 m_address;

View File

@ -22,7 +22,7 @@ namespace MMIO { class Mapping; }
// Like XCodeBlock but has some utilities for memory access.
class EmuCodeBlock : public Gen::XCodeBlock
class EmuCodeBlock : public Gen::X64CodeBlock
{
public:
void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset = 0, bool signExtend = false);

View File

@ -88,7 +88,7 @@ private:
// ARMTODO: This should be done in a better way
#ifndef _M_GENERIC
class VertexLoader : public Gen::XCodeBlock, NonCopyable
class VertexLoader : public Gen::X64CodeBlock
#else
class VertexLoader
#endif