Add CodeBlockCommon base class to remove further arch-specificity in JitBlockCache

Remove unused ArmThunk.
This commit is contained in:
Henrik Rydgard 2016-05-01 11:13:51 +02:00
parent 8b450c8034
commit ffe4c266ef
21 changed files with 80 additions and 175 deletions

View file

@ -306,8 +306,7 @@ endmacro()
set(CommonExtra)
if(ARM)
set(CommonExtra ${CommonExtra}
Common/ArmCPUDetect.cpp
Common/ArmThunk.cpp)
Common/ArmCPUDetect.cpp)
if(ARMV7)
set(CommonExtra ${CommonExtra}
Common/ColorConvNEON.cpp)

View file

@ -265,14 +265,14 @@ static int EncodeSize(int size) {
}
}
void ARM64XEmitter::SetCodePtr(u8* ptr)
void ARM64XEmitter::SetCodePointer(u8* ptr)
{
m_code = ptr;
m_startcode = m_code;
m_lastCacheFlushEnd = ptr;
}
const u8* ARM64XEmitter::GetCodePtr() const
const u8* ARM64XEmitter::GetCodePointer() const
{
return m_code;
}
@ -1914,7 +1914,7 @@ void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize)
}
}
u64 aligned_pc = (u64)GetCodePtr() & ~0xFFF;
u64 aligned_pc = (u64)GetCodePointer() & ~0xFFF;
s64 aligned_offset = (s64)imm - (s64)aligned_pc;
if (upload_part.Count() > 1 && abs64(aligned_offset) < 0xFFFFFFFFLL)
{
@ -1929,7 +1929,7 @@ void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize)
else
{
// If the address is within 1MB of PC we can load it in a single instruction still
s64 offset = (s64)imm - (s64)GetCodePtr();
s64 offset = (s64)imm - (s64)GetCodePointer();
if (offset >= -0xFFFFF && offset <= 0xFFFFF)
{
ADR(Rd, (s32)offset);
@ -2100,7 +2100,7 @@ void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type,
if (type == INDEX_UNSIGNED)
{
_assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", __FUNCTION__, imm, m_emit->GetCodePtr());
_assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", __FUNCTION__, imm, m_emit->GetCodePointer());
_assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", __FUNCTION__);
if (size == 16)
imm >>= 1;

View file

@ -394,11 +394,12 @@ public:
{
}
void SetCodePtr(u8* ptr);
void SetCodePointer(u8* ptr);
const u8* GetCodePointer() const;
void ReserveCodeSpace(u32 bytes);
const u8* AlignCode16();
const u8* AlignCodePage();
const u8* GetCodePtr() const;
void FlushIcache();
void FlushIcacheSection(u8* start, u8* end);
u8* GetWritableCodePtr();

View file

@ -589,14 +589,14 @@ void ARMXEmitter::QuickCallFunction(ARMReg reg, const void *func) {
}
}
void ARMXEmitter::SetCodePtr(u8 *ptr)
void ARMXEmitter::SetCodePointer(u8 *ptr)
{
code = ptr;
startcode = code;
lastCacheFlushEnd = ptr;
}
const u8 *ARMXEmitter::GetCodePtr() const
const u8 *ARMXEmitter::GetCodePointer() const
{
return code;
}

View file

@ -445,11 +445,12 @@ public:
}
virtual ~ARMXEmitter() {}
void SetCodePtr(u8 *ptr);
void SetCodePointer(u8 *ptr);
const u8 *GetCodePointer() const;
void ReserveCodeSpace(u32 bytes);
const u8 *AlignCode16();
const u8 *AlignCodePage();
const u8 *GetCodePtr() const;
void FlushIcache();
void FlushIcacheSection(u8 *start, u8 *end);
u8 *GetWritableCodePtr();

View file

@ -1,74 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "MemoryUtil.h"
#include "Thunk.h"
#define THUNK_ARENA_SIZE 1024*1024*1
namespace
{
static u8 GC_ALIGNED32(saved_fp_state[16 * 4 * 4]);
static u8 GC_ALIGNED32(saved_gpr_state[16 * 8]);
static u16 saved_mxcsr;
} // namespace
using namespace ArmGen;
void ThunkManager::Init()
{
}
void ThunkManager::Reset()
{
thunks.clear();
ResetCodePtr();
}
void ThunkManager::Shutdown()
{
Reset();
FreeCodeSpace();
}
int ThunkManager::ThunkStackOffset()
{
return 0;
}
int ThunkManager::ThunkBytesNeeded()
{
return 0;
}
const void *ThunkManager::ProtectFunction(const void *function, int num_params)
{
_dbg_assert_msg_(JIT, false, "Arm ThunkManager not implemented? Will crash.");
return NULL;
}
void Enter(ThunkEmitter *emit)
{
_dbg_assert_msg_(JIT, false, "Arm ThunkManager not implemented? Will crash.");
}
void Leave(ThunkEmitter *emit)
{
_dbg_assert_msg_(JIT, false, "Arm ThunkManager not implemented? Will crash.");
}

View file

@ -12,19 +12,41 @@
// having to prefix them with gen-> or something similar.
// Example implementation:
// class JIT : public CodeBlock<ARMXEmitter>, public JitInterface {}
template<class T> class CodeBlock : public T, NonCopyable
class CodeBlockCommon {
public:
CodeBlockCommon() : region(nullptr), region_size(0) {}
virtual ~CodeBlockCommon() {}
bool IsInSpace(const u8 *ptr) {
return (ptr >= region) && (ptr < (region + region_size));
}
virtual void SetCodePtr(u8 *ptr) = 0;
virtual const u8 *GetCodePtr() const = 0;
u8 *GetBasePtr() {
return region;
}
size_t GetOffset(const u8 *ptr) const {
return ptr - region;
}
protected:
u8 *region;
size_t region_size;
};
template<class T> class CodeBlock : public CodeBlockCommon, 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) {}
CodeBlock() {}
virtual ~CodeBlock() { if (region) FreeCodeSpace(); }
// Call this before you generate any code.
@ -32,7 +54,7 @@ public:
{
region_size = size;
region = (u8*)AllocateExecutableMemory(region_size);
T::SetCodePtr(region);
T::SetCodePointer(region);
}
// Always clear code space with breakpoints, so that if someone accidentally executes
@ -55,11 +77,6 @@ public:
region_size = 0;
}
bool IsInSpace(const 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()
@ -67,22 +84,21 @@ public:
WriteProtectMemory(region, region_size, true);
}
void SetCodePtr(u8 *ptr) override {
T::SetCodePointer(ptr);
}
const u8 *GetCodePtr() const override {
return T::GetCodePointer();
}
void ResetCodePtr()
{
T::SetCodePtr(region);
T::SetCodePointer(region);
}
size_t GetSpaceLeft() const
{
return region_size - (T::GetCodePtr() - region);
}
u8 *GetBasePtr() {
return region;
}
size_t GetOffset(const u8 *ptr) const {
return ptr - region;
size_t GetSpaceLeft() const {
return region_size - (T::GetCodePointer() - region);
}
};

View file

@ -258,12 +258,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="ArmEmitter.cpp" />
<ClCompile Include="ArmThunk.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="ColorConvNEON.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -332,4 +326,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -104,7 +104,6 @@
<Filter>Crypto</Filter>
</ClCompile>
<ClCompile Include="ChunkFile.cpp" />
<ClCompile Include="ArmThunk.cpp" />
<ClCompile Include="MipsEmitter.cpp" />
<ClCompile Include="Arm64Emitter.cpp" />
<ClCompile Include="ColorConv.cpp" />
@ -151,4 +150,4 @@
<UniqueIdentifier>{c14d66ef-5f7c-4565-975a-72774e7ccfb9}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View file

@ -20,11 +20,7 @@
#include <map>
#include "Common.h"
#if defined(ARM)
#include "ArmEmitter.h"
#else
#include "x64Emitter.h"
#endif
// This simple class creates a wrapper around a C/C++ function that saves all fp state
// before entering it, and restores it upon exit. This is required to be able to selectively
@ -32,18 +28,14 @@
// of complexity that it means to protect the generated code from this problem.
// This process is called thunking.
// Only used for X86 right now.
// There will only ever be one level of thunking on the stack, plus,
// we don't want to pollute the stack, so we store away regs somewhere global.
// NOT THREAD SAFE. This may only be used from the CPU thread.
// Any other thread using this stuff will be FATAL.
#if defined(ARM)
typedef ArmGen::ARMXEmitter ThunkEmitter;
typedef ArmGen::ARMXCodeBlock ThunkCodeBlock;
#else
typedef Gen::XEmitter ThunkEmitter;
typedef Gen::XCodeBlock ThunkCodeBlock;
#endif
class ThunkManager : public ThunkCodeBlock
{

View file

@ -96,12 +96,12 @@ enum NormalSSEOps
};
void XEmitter::SetCodePtr(u8 *ptr)
void XEmitter::SetCodePointer(u8 *ptr)
{
code = ptr;
}
const u8 *XEmitter::GetCodePtr() const
const u8 *XEmitter::GetCodePointer() const
{
return code;
}
@ -235,7 +235,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
emit->WriteModRM(0, _operandReg, _offsetOrBaseReg);
//TODO : add some checks
#ifdef _M_X64
u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes;
u64 ripAddr = (u64)emit->GetCodePointer() + 4 + extraBytes;
s64 distance = (s64)offset - (s64)ripAddr;
_assert_msg_(DYNA_REC,
(distance < 0x80000000LL &&

View file

@ -374,12 +374,13 @@ public:
void WriteModRM(int mod, int rm, int reg);
void WriteSIB(int scale, int index, int base);
void SetCodePtr(u8 *ptr);
void SetCodePointer(u8 *ptr);
const u8 *GetCodePointer() const;
void ReserveCodeSpace(int bytes);
const u8 *AlignCode4();
const u8 *AlignCode16();
const u8 *AlignCodePage();
const u8 *GetCodePtr() const;
u8 *GetWritableCodePtr();
void LockFlags() { flags_locked = true; }

View file

@ -399,14 +399,14 @@ void ArmJit::Comp_RunBlock(MIPSOpcode op)
void ArmJit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) {
ARMXEmitter emit(exitPoint);
u32 op = *((const u32 *)emit.GetCodePtr());
u32 op = *((const u32 *)emit.GetCodePointer());
bool prelinked = (op & 0xFF000000) == 0xEA000000;
// Jump directly to the block, yay.
emit.B(checkedEntry);
if (!prelinked) {
do {
op = *((const u32 *)emit.GetCodePtr());
op = *((const u32 *)emit.GetCodePointer());
// Overwrite whatever is here with a breakpoint.
emit.BKPT(1);
// Stop after overwriting the next unconditional branch or BKPT.

View file

@ -59,7 +59,7 @@ op_agent_t agent;
const u32 INVALID_EXIT = 0xFFFFFFFF;
JitBlockCache::JitBlockCache(MIPSState *mips, NativeCodeBlock *codeBlock) :
JitBlockCache::JitBlockCache(MIPSState *mips, CodeBlockCommon *codeBlock) :
mips_(mips), codeBlock_(codeBlock), blocks_(0), num_blocks_(0) {
}

View file

@ -23,31 +23,10 @@
#include <string>
#include "Common/CommonTypes.h"
#include "Common/CodeBlock.h"
#include "Core/MIPS/MIPSAnalyst.h"
#include "Core/MIPS/MIPS.h"
#if defined(ARM)
#include "Common/ArmEmitter.h"
namespace ArmGen { class ARMXEmitter; }
typedef ArmGen::ARMXCodeBlock NativeCodeBlock;
#elif defined(ARM64)
#include "Common/Arm64Emitter.h"
namespace Arm64Gen { class ARM64XEmitter; }
typedef Arm64Gen::ARM64CodeBlock NativeCodeBlock;
#elif defined(_M_IX86) || defined(_M_X64)
#include "Common/x64Emitter.h"
namespace Gen { class XEmitter; }
typedef Gen::XCodeBlock NativeCodeBlock;
#elif defined(MIPS)
#include "Common/MipsEmitter.h"
namespace MIPSGen { class MIPSEmitter; }
typedef MIPSGen::MIPSCodeBlock NativeCodeBlock;
#else
#include "Common/FakeEmitter.h"
namespace FakeGen { class FakeXEmitter; }
typedef FakeGen::FakeXCodeBlock NativeCodeBlock;
#endif
#if defined(ARM) || defined(ARM64)
const int MAX_JIT_BLOCK_EXITS = 2;
#else
@ -109,12 +88,12 @@ typedef void (*CompiledCode)();
class JitBlockCache {
public:
JitBlockCache(MIPSState *mips_, NativeCodeBlock *codeBlock);
JitBlockCache(MIPSState *mips_, CodeBlockCommon *codeBlock);
~JitBlockCache();
int AllocateBlock(u32 em_address);
// When a proxy block is invalidated, the block located at the rootAddress
void ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, u8 *codePtr);
void ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, const u8 *codePtr);
void FinalizeBlock(int block_num, bool block_link);
void Clear();
@ -173,7 +152,7 @@ private:
MIPSOpcode GetEmuHackOpForBlock(int block_num) const;
MIPSState *mips_;
NativeCodeBlock *codeBlock_;
CodeBlockCommon *codeBlock_;
JitBlock *blocks_;
std::unordered_multimap<u32, int> proxyBlockMap_;

View file

@ -505,7 +505,7 @@ void Jit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) {
XEmitter emit(exitPoint);
// Okay, this is a bit ugly, but we check here if it already has a JMP.
// That means it doesn't have a full exit to pad with INT 3.
bool prelinked = *emit.GetCodePtr() == 0xE9;
bool prelinked = *emit.GetCodePointer() == 0xE9;
emit.JMP(checkedEntry, true);
if (!prelinked) {
ptrdiff_t actualSize = emit.GetWritableCodePtr() - exitPoint;

View file

@ -7,8 +7,7 @@ include(Settings.pri)
# CPU
arm {
SOURCES += $$P/Common/ArmCPUDetect.cpp \
$$P/Common/ArmThunk.cpp
SOURCES += $$P/Common/ArmCPUDetect.cpp
}
else:i86 {
SOURCES += $$P/Common/ABI.cpp \

View file

@ -57,7 +57,6 @@ ARCH_FILES := \
$(SRC)/Core/Util/AudioFormatNEON.cpp.neon \
$(SRC)/Common/ArmEmitter.cpp \
$(SRC)/Common/ArmCPUDetect.cpp \
$(SRC)/Common/ArmThunk.cpp \
$(SRC)/Common/ColorConvNEON.cpp.neon \
$(SRC)/Core/MIPS/ARM/ArmCompALU.cpp \
$(SRC)/Core/MIPS/ARM/ArmCompBranch.cpp \
@ -102,7 +101,6 @@ ifeq ($(TARGET_ARCH_ABI),armeabi)
ARCH_FILES := \
$(SRC)/Common/ArmEmitter.cpp \
$(SRC)/Common/ArmCPUDetect.cpp \
$(SRC)/Common/ArmThunk.cpp \
$(SRC)/Core/MIPS/ARM/ArmCompALU.cpp \
$(SRC)/Core/MIPS/ARM/ArmCompBranch.cpp \
$(SRC)/Core/MIPS/ARM/ArmCompFPU.cpp \

View file

@ -10,7 +10,7 @@
static bool CheckLast(Arm64Gen::ARM64XEmitter &emit, const char *comp) {
u32 instr;
memcpy(&instr, emit.GetCodePtr() - 4, 4);
memcpy(&instr, emit.GetCodePointer() - 4, 4);
char disasm[512];
Arm64Dis(0, instr, disasm, sizeof(disasm), true);
EXPECT_EQ_STR(std::string(disasm), std::string(comp));

View file

@ -11,7 +11,7 @@
static bool CheckLast(ArmGen::ARMXEmitter &emit, const char *comp) {
u32 instr;
memcpy(&instr, emit.GetCodePtr() - 4, 4);
memcpy(&instr, emit.GetCodePointer() - 4, 4);
char disasm[512];
ArmDis(0, instr, disasm, sizeof(disasm), true);
EXPECT_EQ_STR(std::string(disasm), std::string(comp));
@ -227,7 +227,7 @@ bool TestArmEmitter() {
//RET(CheckLast(emitter, "eef70a00 VMOV.f32 s1, #112"));
const u8 *codeStart = emitter.GetCodePtr();
const u8 *codeStart = emitter.GetCodePointer();
MIPSState mips;
MIPSComp::JitState js;
@ -269,7 +269,7 @@ bool TestArmEmitter() {
fpr.QMapReg(C000, V_Quad, MAP_DIRTY);
fpr.FlushAll();
const u8 *codeEnd = emitter.GetCodePtr();
const u8 *codeEnd = emitter.GetCodePointer();
DisassembleARMBetween(codeStart, codeEnd);

View file

@ -11,13 +11,13 @@
static const u8 *prevStart = NULL;
bool CheckLast(Gen::XEmitter &emit, const char *comp) {
auto vec = DisassembleX86(prevStart, emit.GetCodePtr() - prevStart);
auto vec = DisassembleX86(prevStart, emit.GetCodePointer() - prevStart);
EXPECT_EQ_STR(vec[0], std::string(comp));
return true;
}
void PrintLast(Gen::XEmitter &emit) {
for (const u8 *p = prevStart; p < emit.GetCodePtr(); p++) {
for (const u8 *p = prevStart; p < emit.GetCodePointer(); p++) {
printf("%02x ", *p);
}
printf("\n");
@ -29,11 +29,11 @@ bool TestX64Emitter() {
u32 code[512];
XEmitter emitter((u8 *)code);
prevStart = emitter.GetCodePtr();
prevStart = emitter.GetCodePointer();
emitter.VADDSD(XMM0, XMM1, R(XMM7));
RET(CheckLast(emitter, "vaddsd xmm0, xmm1, xmm7"));
prevStart = emitter.GetCodePtr();
prevStart = emitter.GetCodePointer();
emitter.VMULSD(XMM0, XMM1, R(XMM7));
RET(CheckLast(emitter, "vmulsd xmm0, xmm1, xmm7"));