diff --git a/Source/Core/Common/ArmEmitter.h b/Source/Core/Common/ArmEmitter.h index e974bed331..c4820b6a9c 100644 --- a/Source/Core/Common/ArmEmitter.h +++ b/Source/Core/Common/ArmEmitter.h @@ -8,8 +8,8 @@ #include +#include "Common/CodeBlock.h" #include "Common/Common.h" -#include "Common/MemoryUtil.h" #if defined(__SYMBIAN32__) || defined(PANDORA) #include @@ -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 { -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; } }; diff --git a/Source/Core/Common/CodeBlock.h b/Source/Core/Common/CodeBlock.h new file mode 100644 index 0000000000..4885a58faf --- /dev/null +++ b/Source/Core/Common/CodeBlock.h @@ -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 {} +template 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); + } +}; + diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index f45ae50c12..a7cc5df100 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -50,6 +50,7 @@ + diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index a663f170ab..2fbca73212 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -16,6 +16,7 @@ + diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index f15287620c..8d9c90e3b0 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -10,8 +10,8 @@ #include #include +#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 { -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); } }; diff --git a/Source/Core/Core/DSP/DSPEmitter.h b/Source/Core/Core/DSP/DSPEmitter.h index 1d6e60a899..e392fbf42d 100644 --- a/Source/Core/Core/DSP/DSPEmitter.h +++ b/Source/Core/Core/DSP/DSPEmitter.h @@ -18,7 +18,7 @@ typedef u32 (*DSPCompiledCode)(); typedef const u8 *Block; -class DSPEmitter : public Gen::XCodeBlock, NonCopyable +class DSPEmitter : public Gen::X64CodeBlock { public: DSPEmitter(); diff --git a/Source/Core/Core/PowerPC/JitArm32/Jit.h b/Source/Core/Core/PowerPC/JitArm32/Jit.h index e6921d1a87..87b0c3be39 100644 --- a/Source/Core/Core/PowerPC/JitArm32/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm32/Jit.h @@ -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; diff --git a/Source/Core/Core/PowerPC/JitArm32/JitAsm.h b/Source/Core/Core/PowerPC/JitArm32/JitAsm.h index 061a2bac39..f9d8aefa00 100644 --- a/Source/Core/Core/PowerPC/JitArm32/JitAsm.h +++ b/Source/Core/Core/PowerPC/JitArm32/JitAsm.h @@ -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(); diff --git a/Source/Core/Core/PowerPC/JitArmIL/JitIL.h b/Source/Core/Core/PowerPC/JitArmIL/JitIL.h index 66eb636cca..8260ffe114 100644 --- a/Source/Core/Core/PowerPC/JitArmIL/JitIL.h +++ b/Source/Core/Core/PowerPC/JitArmIL/JitIL.h @@ -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); diff --git a/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.cpp b/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.cpp index be7c34f5d8..72f76ec001 100644 --- a/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.cpp +++ b/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.cpp @@ -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() { diff --git a/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.h b/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.h index ef95b6db07..1c2dbbd4e1 100644 --- a/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.h +++ b/Source/Core/Core/PowerPC/JitArmIL/JitILAsm.h @@ -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(); diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.h b/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.h index 3147f32d31..8f285fe88c 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.h @@ -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(); diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp index ebe89b0e5b..3601a1973c 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp @@ -125,7 +125,7 @@ template class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor { 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; diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h index cb67a2efbc..b452ca4741 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h @@ -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); diff --git a/Source/Core/VideoCommon/VertexLoader.h b/Source/Core/VideoCommon/VertexLoader.h index 01c4bb0acd..8086888b7d 100644 --- a/Source/Core/VideoCommon/VertexLoader.h +++ b/Source/Core/VideoCommon/VertexLoader.h @@ -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