mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-28 10:51:06 +00:00
Move architecture-specific code out of JitBlockCache
This commit is contained in:
parent
a5be0976bd
commit
5aadce59a2
@ -271,17 +271,17 @@ const u8 *ArmJit::DoJit(u32 em_address, JitBlock *b)
|
||||
JumpTarget backJump = GetCodePtr();
|
||||
gpr.SetRegImm(R0, js.blockStart);
|
||||
B((const void *)outerLoopPCInR0);
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
SetCC(CC_LT);
|
||||
B(backJump);
|
||||
SetCC(CC_AL);
|
||||
} else if (jo.useForwardJump) {
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
SetCC(CC_LT);
|
||||
bail = B();
|
||||
SetCC(CC_AL);
|
||||
} else {
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
SetCC(CC_LT);
|
||||
gpr.SetRegImm(R0, js.blockStart);
|
||||
B((const void *)outerLoopPCInR0);
|
||||
@ -397,6 +397,37 @@ void ArmJit::Comp_RunBlock(MIPSOpcode op)
|
||||
ERROR_LOG(JIT, "Comp_RunBlock should never be reached!");
|
||||
}
|
||||
|
||||
void ArmJit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) {
|
||||
ARMXEmitter emit(exitPoint);
|
||||
u32 op = *((const u32 *)emit.GetCodePtr());
|
||||
bool prelinked = (op & 0xFF000000) == 0xEA000000;
|
||||
// Jump directly to the block, yay.
|
||||
emit.B(checkedEntry);
|
||||
|
||||
if (!prelinked) {
|
||||
do {
|
||||
op = *((const u32 *)emit.GetCodePtr());
|
||||
// Overwrite whatever is here with a breakpoint.
|
||||
emit.BKPT(1);
|
||||
// Stop after overwriting the next unconditional branch or BKPT.
|
||||
// It can be a BKPT if we unlinked, and are now linking a different one.
|
||||
} while ((op & 0xFF000000) != 0xEA000000 && (op & 0xFFF000F0) != 0xE1200070);
|
||||
}
|
||||
emit.FlushIcache();
|
||||
}
|
||||
|
||||
void ArmJit::UnlinkBlock(u8 *checkedEntry, u32 originalAddress) {
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. pretty good.
|
||||
// I hope there's enough space...
|
||||
// checkedEntry is the only "linked" entrance so it's enough to overwrite that.
|
||||
ARMXEmitter emit(checkedEntry);
|
||||
emit.MOVI2R(R0, originalAddress);
|
||||
emit.STR(R0, CTXREG, offsetof(MIPSState, pc));
|
||||
emit.B(MIPSComp::jit->GetDispatcher());
|
||||
emit.FlushIcache();
|
||||
}
|
||||
|
||||
bool ArmJit::ReplaceJalTo(u32 dest) {
|
||||
#ifdef ARM
|
||||
const ReplacementTableEntry *entry = nullptr;
|
||||
|
@ -179,6 +179,9 @@ public:
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
|
||||
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
|
||||
|
||||
private:
|
||||
const u8 *DoJit(u32 em_address, JitBlock *b);
|
||||
|
||||
|
@ -262,13 +262,13 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) {
|
||||
const u8 *backJump = GetCodePtr();
|
||||
MOVI2R(SCRATCH1, js.blockStart);
|
||||
B((const void *)outerLoopPCInSCRATCH1);
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
B(CC_LT, backJump);
|
||||
} else if (jo.useForwardJump) {
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
bail = B(CC_LT);
|
||||
} else if (jo.enableBlocklink) {
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
MOVI2R(SCRATCH1, js.blockStart);
|
||||
FixupBranch skip = B(CC_GE);
|
||||
B((const void *)outerLoopPCInSCRATCH1);
|
||||
@ -395,6 +395,24 @@ void Arm64Jit::Comp_RunBlock(MIPSOpcode op) {
|
||||
ERROR_LOG(JIT, "Comp_RunBlock should never be reached!");
|
||||
}
|
||||
|
||||
void Arm64Jit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) {
|
||||
ARM64XEmitter emit(exitPoint);
|
||||
emit.B(checkedEntry);
|
||||
// TODO: Write stuff after.
|
||||
emit.FlushIcache();
|
||||
}
|
||||
|
||||
void Arm64Jit::UnlinkBlock(u8 *checkedEntry, u32 originalAddress) {
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. works.
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
ARM64XEmitter emit(checkedEntry);
|
||||
emit.MOVI2R(SCRATCH1, originalAddress);
|
||||
emit.STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, pc));
|
||||
emit.B(MIPSComp::jit->GetDispatcher());
|
||||
emit.FlushIcache();
|
||||
}
|
||||
|
||||
bool Arm64Jit::ReplaceJalTo(u32 dest) {
|
||||
#ifdef ARM64
|
||||
const ReplacementTableEntry *entry = nullptr;
|
||||
|
@ -180,6 +180,9 @@ public:
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
|
||||
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
|
||||
|
||||
private:
|
||||
void GenerateFixedCode(const JitOptions &jo);
|
||||
void FlushAll();
|
||||
|
@ -44,9 +44,6 @@
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "Core/MIPS/JitCommon/NativeJit.h"
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
#include "Common/x64Analyzer.h"
|
||||
#endif
|
||||
// #include "JitBase.h"
|
||||
|
||||
#if defined USE_OPROFILE && USE_OPROFILE
|
||||
@ -61,18 +58,6 @@ op_agent_t agent;
|
||||
#pragma comment(lib, "jitprofiling.lib")
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
#include "Core/MIPS/ARM/ArmRegCache.h"
|
||||
using namespace ArmGen;
|
||||
using namespace ArmJitConstants;
|
||||
#elif defined(_M_X64) || defined(_M_IX86)
|
||||
using namespace Gen;
|
||||
#elif defined(ARM64)
|
||||
#include "Core/MIPS/ARM64/Arm64RegCache.h"
|
||||
using namespace Arm64Gen;
|
||||
using namespace Arm64JitConstants;
|
||||
#endif
|
||||
|
||||
const u32 INVALID_EXIT = 0xFFFFFFFF;
|
||||
|
||||
JitBlockCache::JitBlockCache(MIPSState *mips, NativeCodeBlock *codeBlock) :
|
||||
@ -198,7 +183,7 @@ void JitBlockCache::ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, cons
|
||||
|
||||
// Make binary searches and stuff work ok
|
||||
b.normalEntry = codePtr;
|
||||
b.checkedEntry = codePtr;
|
||||
b.checkedEntry = (u8 *)codePtr; // Ugh, casting away const..
|
||||
proxyBlockMap_.insert(std::make_pair(startAddress, num_blocks_));
|
||||
AddBlockMap(num_blocks_);
|
||||
|
||||
@ -416,46 +401,8 @@ void JitBlockCache::LinkBlockExits(int i) {
|
||||
JitBlock &eb = blocks_[destinationBlock];
|
||||
// Make sure the destination is not invalid.
|
||||
if (!eb.invalid) {
|
||||
#if defined(ARM)
|
||||
ARMXEmitter emit(b.exitPtrs[e]);
|
||||
u32 op = *((const u32 *)emit.GetCodePtr());
|
||||
bool prelinked = (op & 0xFF000000) == 0xEA000000;
|
||||
// Jump directly to the block, yay.
|
||||
emit.B(eb.checkedEntry);
|
||||
|
||||
if (!prelinked) {
|
||||
do {
|
||||
op = *((const u32 *)emit.GetCodePtr());
|
||||
// Overwrite whatever is here with a breakpoint.
|
||||
emit.BKPT(1);
|
||||
// Stop after overwriting the next unconditional branch or BKPT.
|
||||
// It can be a BKPT if we unlinked, and are now linking a different one.
|
||||
} while ((op & 0xFF000000) != 0xEA000000 && (op & 0xFFF000F0) != 0xE1200070);
|
||||
}
|
||||
emit.FlushIcache();
|
||||
MIPSComp::jit->LinkBlock(b.exitPtrs[e], eb.checkedEntry);
|
||||
b.linkStatus[e] = true;
|
||||
#elif defined(_M_IX86) || defined(_M_X64)
|
||||
XEmitter emit(b.exitPtrs[e]);
|
||||
// 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;
|
||||
emit.JMP(eb.checkedEntry, true);
|
||||
|
||||
if (!prelinked) {
|
||||
ptrdiff_t actualSize = emit.GetWritableCodePtr() - b.exitPtrs[e];
|
||||
int pad = JitBlockCache::GetBlockExitSize() - (int)actualSize;
|
||||
for (int i = 0; i < pad; ++i) {
|
||||
emit.INT3();
|
||||
}
|
||||
}
|
||||
b.linkStatus[e] = true;
|
||||
#elif defined(ARM64)
|
||||
ARM64XEmitter emit(b.exitPtrs[e]);
|
||||
emit.B(eb.checkedEntry);
|
||||
// TODO: Write stuff after.
|
||||
emit.FlushIcache();
|
||||
b.linkStatus[e] = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -588,39 +535,7 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(ARM)
|
||||
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. pretty good.
|
||||
// I hope there's enough space...
|
||||
// checkedEntry is the only "linked" entrance so it's enough to overwrite that.
|
||||
ARMXEmitter emit((u8 *)b->checkedEntry);
|
||||
emit.MOVI2R(R0, b->originalAddress);
|
||||
emit.STR(R0, CTXREG, offsetof(MIPSState, pc));
|
||||
emit.B(MIPSComp::jit->GetDispatcher());
|
||||
emit.FlushIcache();
|
||||
|
||||
#elif defined(_M_IX86) || defined(_M_X64)
|
||||
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. pretty good.
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
XEmitter emit((u8 *)b->checkedEntry);
|
||||
emit.MOV(32, M(&mips_->pc), Imm32(b->originalAddress));
|
||||
emit.JMP(MIPSComp::jit->GetDispatcher(), true);
|
||||
|
||||
#elif defined(ARM64)
|
||||
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. works.
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
ARM64XEmitter emit((u8 *)b->checkedEntry);
|
||||
emit.MOVI2R(SCRATCH1, b->originalAddress);
|
||||
emit.STR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, pc));
|
||||
emit.B(MIPSComp::jit->GetDispatcher());
|
||||
emit.FlushIcache();
|
||||
|
||||
#endif
|
||||
MIPSComp::jit->UnlinkBlock(b->checkedEntry, b->originalAddress);
|
||||
}
|
||||
|
||||
void JitBlockCache::InvalidateICache(u32 address, const u32 length) {
|
||||
|
@ -73,7 +73,7 @@ struct BlockCacheStats {
|
||||
struct JitBlock {
|
||||
bool ContainsAddress(u32 em_address);
|
||||
|
||||
const u8 *checkedEntry;
|
||||
u8 *checkedEntry; // not const, may need to write through this to unlink
|
||||
const u8 *normalEntry;
|
||||
|
||||
u8 *exitPtrs[MAX_JIT_BLOCK_EXITS]; // to be able to rewrite the exit jump
|
||||
|
@ -49,6 +49,11 @@ namespace MIPSComp {
|
||||
virtual void ClearCache() = 0;
|
||||
virtual void EatPrefix() = 0;
|
||||
|
||||
// Block linking. This may need to work differently for whole-function JITs and stuff
|
||||
// like that.
|
||||
virtual void LinkBlock(u8 *exitPoint, const u8 *entryPoint) = 0;
|
||||
virtual void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) = 0;
|
||||
|
||||
virtual void Comp_Generic(MIPSOpcode op) = 0;
|
||||
virtual void Comp_RunBlock(MIPSOpcode op) = 0;
|
||||
virtual void Comp_ReplacementFunc(MIPSOpcode op) = 0;
|
||||
|
@ -359,7 +359,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
|
||||
js.PrefixStart();
|
||||
|
||||
// We add a check before the block, used when entering from a linked block.
|
||||
b->checkedEntry = GetCodePtr();
|
||||
b->checkedEntry = (u8 *)GetCodePtr();
|
||||
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
|
||||
FixupBranch skip = J_CC(CC_NS);
|
||||
MOV(32, M(&mips_->pc), Imm32(js.blockStart));
|
||||
@ -501,6 +501,30 @@ void Jit::Comp_RunBlock(MIPSOpcode op)
|
||||
ERROR_LOG(JIT, "Comp_RunBlock");
|
||||
}
|
||||
|
||||
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;
|
||||
emit.JMP(checkedEntry, true);
|
||||
if (!prelinked) {
|
||||
ptrdiff_t actualSize = emit.GetWritableCodePtr() - exitPoint;
|
||||
int pad = JitBlockCache::GetBlockExitSize() - (int)actualSize;
|
||||
for (int i = 0; i < pad; ++i) {
|
||||
emit.INT3();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::UnlinkBlock(u8 *checkedEntry, u32 originalAddress) {
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. pretty good.
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
XEmitter emit(checkedEntry);
|
||||
emit.MOV(32, M(&mips_->pc), Imm32(originalAddress));
|
||||
emit.JMP(MIPSComp::jit->GetDispatcher(), true);
|
||||
}
|
||||
|
||||
bool Jit::ReplaceJalTo(u32 dest) {
|
||||
const ReplacementTableEntry *entry = nullptr;
|
||||
u32 funcSize = 0;
|
||||
|
@ -174,6 +174,9 @@ public:
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override;
|
||||
void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override;
|
||||
|
||||
private:
|
||||
void GenerateFixedCode(JitOptions &jo);
|
||||
void GetStateAndFlushAll(RegCacheState &state);
|
||||
|
Loading…
Reference in New Issue
Block a user