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 <vector>
#include "Common/CodeBlock.h"
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/MemoryUtil.h"
#if defined(__SYMBIAN32__) || defined(PANDORA) #if defined(__SYMBIAN32__) || defined(PANDORA)
#include <signal.h> #include <signal.h>
@ -700,78 +700,18 @@ public:
void VST1(u32 Size, ARMReg Vd, ARMReg Rn, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC); 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. class ARMCodeBlock : public CodeBlock<ARMXEmitter>
// 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
{ {
protected: private:
u8 *region; void PoisonMemory() override
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)
{ {
region_size = size; u32* ptr = (u32*)region;
region = (u8*)AllocateExecutableMemory(region_size); u32* maxptr = (u32*)region + region_size;
SetCodePtr(region); // 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
// Always clear code space with breakpoints, so that if someone accidentally executes while (ptr < maxptr)
// uninitialized, it just breaks into the debugger. *ptr++ = 0x01200070;
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;
} }
}; };

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="BreakPoints.h" />
<ClInclude Include="CDUtils.h" /> <ClInclude Include="CDUtils.h" />
<ClInclude Include="ChunkFile.h" /> <ClInclude Include="ChunkFile.h" />
<ClInclude Include="CodeBlock.h" />
<ClInclude Include="ColorUtil.h" /> <ClInclude Include="ColorUtil.h" />
<ClInclude Include="Common.h" /> <ClInclude Include="Common.h" />
<ClInclude Include="CommonFuncs.h" /> <ClInclude Include="CommonFuncs.h" />

View File

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

View File

@ -10,8 +10,8 @@
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include "Common/CodeBlock.h"
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/MemoryUtil.h"
namespace Gen namespace Gen
{ {
@ -762,65 +762,13 @@ public:
} }
}; // class XEmitter }; // class XEmitter
class X64CodeBlock : public CodeBlock<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
{ {
protected: private:
u8 *region; void PoisonMemory() override
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()
{ {
// x86/64: 0xCC = breakpoint // x86/64: 0xCC = breakpoint
memset(region, 0xCC, region_size); 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 u32 (*DSPCompiledCode)();
typedef const u8 *Block; typedef const u8 *Block;
class DSPEmitter : public Gen::XCodeBlock, NonCopyable class DSPEmitter : public Gen::X64CodeBlock
{ {
public: public:
DSPEmitter(); DSPEmitter();

View File

@ -27,7 +27,7 @@
#include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitBase.h"
#define PPCSTATE_OFF(elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0])) #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: private:
JitArmBlockCache blocks; JitArmBlockCache blocks;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ namespace MMIO { class Mapping; }
// Like XCodeBlock but has some utilities for memory access. // Like XCodeBlock but has some utilities for memory access.
class EmuCodeBlock : public Gen::XCodeBlock class EmuCodeBlock : public Gen::X64CodeBlock
{ {
public: public:
void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset = 0, bool signExtend = false); 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 // ARMTODO: This should be done in a better way
#ifndef _M_GENERIC #ifndef _M_GENERIC
class VertexLoader : public Gen::XCodeBlock, NonCopyable class VertexLoader : public Gen::X64CodeBlock
#else #else
class VertexLoader class VertexLoader
#endif #endif