Merge pull request #1218 from hthh/trampolinecaching
JIT: reuse trampolines when possible
This commit is contained in:
commit
b3b34d16e6
|
@ -223,3 +223,19 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
|
|||
info->instructionSize = (int)(codePtr - startCodePtr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InstructionInfo::operator==(const InstructionInfo &other) const
|
||||
{
|
||||
return operandSize == other.operandSize &&
|
||||
instructionSize == other.instructionSize &&
|
||||
regOperandReg == other.regOperandReg &&
|
||||
otherReg == other.otherReg &&
|
||||
scaledReg == other.scaledReg &&
|
||||
zeroExtend == other.zeroExtend &&
|
||||
signExtend == other.signExtend &&
|
||||
hasImmediate == other.hasImmediate &&
|
||||
isMemoryWrite == other.isMemoryWrite &&
|
||||
byteSwap == other.byteSwap &&
|
||||
immediate == other.immediate &&
|
||||
displacement == other.displacement;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ struct InstructionInfo
|
|||
bool byteSwap;
|
||||
u64 immediate;
|
||||
s32 displacement;
|
||||
|
||||
bool operator==(const InstructionInfo &other) const;
|
||||
};
|
||||
|
||||
struct ModRM
|
||||
|
|
|
@ -19,25 +19,42 @@
|
|||
|
||||
using namespace Gen;
|
||||
|
||||
extern u8 *trampolineCodePtr;
|
||||
|
||||
void TrampolineCache::Init()
|
||||
{
|
||||
AllocCodeSpace(4 * 1024 * 1024);
|
||||
AllocCodeSpace(8 * 1024 * 1024);
|
||||
}
|
||||
|
||||
void TrampolineCache::ClearCodeSpace()
|
||||
{
|
||||
X64CodeBlock::ClearCodeSpace();
|
||||
cachedTrampolines.clear();
|
||||
}
|
||||
|
||||
void TrampolineCache::Shutdown()
|
||||
{
|
||||
FreeCodeSpace();
|
||||
cachedTrampolines.clear();
|
||||
}
|
||||
|
||||
// Extremely simplistic - just generate the requested trampoline. May reuse them in the future.
|
||||
const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 registersInUse)
|
||||
const u8* TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 registersInUse)
|
||||
{
|
||||
TrampolineCacheKey key = { registersInUse, 0, info };
|
||||
|
||||
auto it = cachedTrampolines.find(key);
|
||||
if (it != cachedTrampolines.end())
|
||||
return it->second;
|
||||
|
||||
const u8* trampoline = GenerateReadTrampoline(info, registersInUse);
|
||||
cachedTrampolines[key] = trampoline;
|
||||
return trampoline;
|
||||
}
|
||||
|
||||
const u8* TrampolineCache::GenerateReadTrampoline(const InstructionInfo &info, u32 registersInUse)
|
||||
{
|
||||
if (GetSpaceLeft() < 1024)
|
||||
PanicAlert("Trampoline cache full");
|
||||
|
||||
const u8 *trampoline = GetCodePtr();
|
||||
const u8* trampoline = GetCodePtr();
|
||||
X64Reg addrReg = (X64Reg)info.scaledReg;
|
||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||
|
||||
|
@ -80,13 +97,25 @@ const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 re
|
|||
return trampoline;
|
||||
}
|
||||
|
||||
// Extremely simplistic - just generate the requested trampoline. May reuse them in the future.
|
||||
const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc)
|
||||
const u8* TrampolineCache::GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc)
|
||||
{
|
||||
TrampolineCacheKey key = { registersInUse, pc, info };
|
||||
|
||||
auto it = cachedTrampolines.find(key);
|
||||
if (it != cachedTrampolines.end())
|
||||
return it->second;
|
||||
|
||||
const u8* trampoline = GenerateWriteTrampoline(info, registersInUse, pc);
|
||||
cachedTrampolines[key] = trampoline;
|
||||
return trampoline;
|
||||
}
|
||||
|
||||
const u8* TrampolineCache::GenerateWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc)
|
||||
{
|
||||
if (GetSpaceLeft() < 1024)
|
||||
PanicAlert("Trampoline cache full");
|
||||
|
||||
const u8 *trampoline = GetCodePtr();
|
||||
const u8* trampoline = GetCodePtr();
|
||||
|
||||
X64Reg dataReg = (X64Reg)info.regOperandReg;
|
||||
X64Reg addrReg = (X64Reg)info.scaledReg;
|
||||
|
@ -153,4 +182,25 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info, u32 r
|
|||
return trampoline;
|
||||
}
|
||||
|
||||
size_t TrampolineCacheKeyHasher::operator()(const TrampolineCacheKey& k) const
|
||||
{
|
||||
size_t res = std::hash<int>()(k.registersInUse);
|
||||
res ^= std::hash<int>()(k.info.operandSize) >> 1;
|
||||
res ^= std::hash<int>()(k.info.regOperandReg) >> 2;
|
||||
res ^= std::hash<int>()(k.info.scaledReg) >> 3;
|
||||
res ^= std::hash<u64>()(k.info.immediate) >> 4;
|
||||
res ^= std::hash<int>()(k.pc) >> 5;
|
||||
res ^= std::hash<int>()(k.info.displacement) << 1;
|
||||
res ^= std::hash<bool>()(k.info.signExtend) << 2;
|
||||
res ^= std::hash<bool>()(k.info.hasImmediate) << 3;
|
||||
res ^= std::hash<bool>()(k.info.isMemoryWrite) << 4;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool TrampolineCacheKey::operator==(const TrampolineCacheKey &other) const
|
||||
{
|
||||
return pc == other.pc &&
|
||||
registersInUse == other.registersInUse &&
|
||||
info == other.info;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,33 @@
|
|||
// We need at least this many bytes for backpatching.
|
||||
const int BACKPATCH_SIZE = 5;
|
||||
|
||||
struct TrampolineCacheKey
|
||||
{
|
||||
u32 registersInUse;
|
||||
u32 pc;
|
||||
InstructionInfo info;
|
||||
|
||||
bool operator==(const TrampolineCacheKey &other) const;
|
||||
};
|
||||
|
||||
struct TrampolineCacheKeyHasher
|
||||
{
|
||||
size_t operator()(const TrampolineCacheKey& k) const;
|
||||
};
|
||||
|
||||
class TrampolineCache : public Gen::X64CodeBlock
|
||||
{
|
||||
public:
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
const u8 *GetReadTrampoline(const InstructionInfo &info, u32 registersInUse);
|
||||
const u8 *GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc);
|
||||
const u8* GetReadTrampoline(const InstructionInfo &info, u32 registersInUse);
|
||||
const u8* GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc);
|
||||
void ClearCodeSpace();
|
||||
|
||||
private:
|
||||
const u8* GenerateReadTrampoline(const InstructionInfo &info, u32 registersInUse);
|
||||
const u8* GenerateWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc);
|
||||
|
||||
std::unordered_map<TrampolineCacheKey, const u8*, TrampolineCacheKeyHasher> cachedTrampolines;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue