diff --git a/Common/FakeEmitter.h b/Common/FakeEmitter.h index 6b827655c84b..25954ee35060 100644 --- a/Common/FakeEmitter.h +++ b/Common/FakeEmitter.h @@ -24,6 +24,7 @@ #include #include "Common.h" +#include "Common/CodeBlock.h" // VCVT flags #define TO_FLOAT 0 @@ -167,7 +168,7 @@ class Operand2 Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR { Type = TYPE_RSR; - _assert_msg_(JIT, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); + _assert_msg_(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); IndexOrShift = shift; Shift = type; Value = base; @@ -179,29 +180,29 @@ class Operand2 switch (type) { case ST_LSL: - _assert_msg_(JIT, shift < 32, "Invalid Operand2: LSL %u", shift); + _assert_msg_(shift < 32, "Invalid Operand2: LSL %u", shift); break; case ST_LSR: - _assert_msg_(JIT, shift <= 32, "Invalid Operand2: LSR %u", shift); + _assert_msg_(shift <= 32, "Invalid Operand2: LSR %u", shift); if (!shift) type = ST_LSL; if (shift == 32) shift = 0; break; case ST_ASR: - _assert_msg_(JIT, shift < 32, "Invalid Operand2: ASR %u", shift); + _assert_msg_(shift < 32, "Invalid Operand2: ASR %u", shift); if (!shift) type = ST_LSL; if (shift == 32) shift = 0; break; case ST_ROR: - _assert_msg_(JIT, shift < 32, "Invalid Operand2: ROR %u", shift); + _assert_msg_(shift < 32, "Invalid Operand2: ROR %u", shift); if (!shift) type = ST_LSL; break; case ST_RRX: - _assert_msg_(JIT, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount"); + _assert_msg_(shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount"); type = ST_ROR; break; } @@ -223,45 +224,45 @@ class Operand2 case TYPE_RSR: return RSR(); default: - _assert_msg_(JIT, false, "GetData with Invalid Type"); + _assert_msg_(false, "GetData with Invalid Type"); return 0; } } u32 IMMSR() // IMM shifted register { - _assert_msg_(JIT, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); + _assert_msg_(Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value); } u32 RSR() // Register shifted register { - _assert_msg_(JIT, Type == TYPE_RSR, "RSR must be RSR Of Course"); + _assert_msg_(Type == TYPE_RSR, "RSR must be RSR Of Course"); return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value; } u32 Rm() { - _assert_msg_(JIT, Type == TYPE_REG, "Rm must be with Reg"); + _assert_msg_(Type == TYPE_REG, "Rm must be with Reg"); return Value; } u32 Imm5() { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm5 not IMM value"); + _assert_msg_(Type == TYPE_IMM, "Imm5 not IMM value"); return ((Value & 0x0000001F) << 7); } u32 Imm8() { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value"); + _assert_msg_(Type == TYPE_IMM, "Imm8Rot not IMM value"); return Value & 0xFF; } u32 Imm8Rot() // IMM8 with Rotation { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value"); - _assert_msg_(JIT, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); + _assert_msg_(Type == TYPE_IMM, "Imm8Rot not IMM value"); + _assert_msg_((Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF); } u32 Imm12() { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm12 not IMM"); + _assert_msg_(Type == TYPE_IMM, "Imm12 not IMM"); return (Value & 0x00000FFF); } @@ -272,12 +273,12 @@ class Operand2 // expand a 8bit IMM to a 32bit value and gives you some rotation as // well. // Each rotation rotates to the right by 2 bits - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm12Mod not IMM"); + _assert_msg_(Type == TYPE_IMM, "Imm12Mod not IMM"); return ((Rotation & 0xF) << 8) | (Value & 0xFF); } u32 Imm16() { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM"); + _assert_msg_(Type == TYPE_IMM, "Imm16 not IMM"); return ( (Value & 0xF000) << 4) | (Value & 0x0FFF); } u32 Imm16Low() @@ -286,12 +287,12 @@ class Operand2 } u32 Imm16High() // Returns high 16bits { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM"); + _assert_msg_(Type == TYPE_IMM, "Imm16 not IMM"); return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF); } u32 Imm24() { - _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM"); + _assert_msg_(Type == TYPE_IMM, "Imm16 not IMM"); return (Value & 0x0FFFFFFF); } }; @@ -380,6 +381,9 @@ class FakeXEmitter } virtual ~FakeXEmitter() {} + void SetCodePointer(u8 *ptr, u8 *writePtr) {} + const u8 *GetCodePointer() const { return nullptr; } + void SetCodePtr(u8 *ptr) {} void ReserveCodeSpace(u32 bytes) {} const u8 *AlignCode16() { return nullptr; } @@ -411,52 +415,9 @@ class FakeXEmitter // Everything that needs to generate machine 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 FakeXCodeBlock : public FakeXEmitter -{ -protected: - u8 *region; - size_t region_size; - +class FakeXCodeBlock : public CodeBlock { public: - FakeXCodeBlock() : region(NULL), region_size(0) {} - virtual ~FakeXCodeBlock() { if (region) FreeCodeSpace(); } - - // Call this before you generate any code. - void AllocCodeSpace(int size) { } - - // Always clear code space with breakpoints, so that if someone accidentally executes - // uninitialized, it just breaks into the debugger. - void ClearCodeSpace() { } - - // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. - void FreeCodeSpace() { } - - bool IsInSpace(const u8 *ptr) const - { - 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() { } - void UnWriteProtect() { } - - void ResetCodePtr() - { - SetCodePtr(region); - } - - size_t GetSpaceLeft() const - { - return region_size - (GetCodePtr() - region); - } - - u8 *GetBasePtr() { - return region; - } - - size_t GetOffset(const u8 *ptr) const { - return ptr - region; + void PoisonMemory(int offset) override { } }; diff --git a/Common/MipsEmitter.cpp b/Common/MipsEmitter.cpp index 5d6288be3ede..682de9304c7e 100644 --- a/Common/MipsEmitter.cpp +++ b/Common/MipsEmitter.cpp @@ -474,7 +474,7 @@ void MIPSCodeBlock::AllocCodeSpace(int size) { // Always clear code space with breakpoints, so that if someone accidentally executes // uninitialized, it just breaks into the debugger. -void MIPSCodeBlock::ClearCodeSpace() { +void MIPSCodeBlock::ClearCodeSpace(int offset) { // Set BREAK instructions on all of it. u32 *region32 = (u32 *)region; for (u32 i = 0; i < region_size / 4; ++i) { diff --git a/Common/MipsEmitter.h b/Common/MipsEmitter.h index 19913ec2e242..298ad06b9b6a 100644 --- a/Common/MipsEmitter.h +++ b/Common/MipsEmitter.h @@ -285,7 +285,7 @@ class MIPSCodeBlock : public MIPSEmitter { // Always clear code space with breakpoints, so that if someone accidentally executes // uninitialized, it just breaks into the debugger. - void ClearCodeSpace(); + void ClearCodeSpace(int offset); // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. void FreeCodeSpace(); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 060eeb4ddbb4..065a61aff354 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -457,6 +457,7 @@ + @@ -1004,6 +1005,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 93b6b137effd..51d07653fd1e 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -88,6 +88,9 @@ {0201ff27-4fa8-4cf3-bbb9-accfdc0c7046} + + {678fa299-0ff7-4983-982d-2da47b52e238} + @@ -971,6 +974,9 @@ Debugger\WebSocket + + MIPS\fake + @@ -1661,6 +1667,9 @@ Debugger\WebSocket + + MIPS\fake + diff --git a/Core/MIPS/JitCommon/JitState.cpp b/Core/MIPS/JitCommon/JitState.cpp index 895589cadf54..d564b57d52c9 100644 --- a/Core/MIPS/JitCommon/JitState.cpp +++ b/Core/MIPS/JitCommon/JitState.cpp @@ -47,7 +47,11 @@ namespace MIPSComp { // We can get block linking to work with W^X by doing even more unprotect/re-protect, but let's try without first. // enableBlocklink = !PlatformIsWXExclusive(); // Revert to this line if block linking is slow in W^X mode +#if PPSSPP_ARCH(MIPS) + enableBlocklink = false; +#else enableBlocklink = !Disabled(JitDisable::BLOCKLINK); +#endif immBranches = false; continueBranches = false; continueJumps = false; diff --git a/Core/MIPS/MIPS/MipsJit.cpp b/Core/MIPS/MIPS/MipsJit.cpp index 5201437784c5..5103b226a573 100644 --- a/Core/MIPS/MIPS/MipsJit.cpp +++ b/Core/MIPS/MIPS/MipsJit.cpp @@ -79,10 +79,20 @@ void MipsJit::FlushPrefixV() { } +MIPSOpcode MipsJit::GetOriginalOp(MIPSOpcode op) { + JitBlockCache *bc = GetBlockCache(); + int block_num = bc->GetBlockNumberFromEmuHackOp(op, true); + if (block_num >= 0) { + return bc->GetOriginalFirstOp(block_num); + } else { + return op; + } +} + void MipsJit::ClearCache() { blocks.Clear(); - ClearCodeSpace(); + ClearCodeSpace(0); //GenerateFixedCode(); } @@ -226,6 +236,14 @@ void MipsJit::Comp_RunBlock(MIPSOpcode op) ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); } +void MipsJit::LinkBlock(u8 *exitPoint, const u8 *checkedEntry) { + // TODO +} + +void MipsJit::UnlinkBlock(u8 *checkedEntry, u32 originalAddress) { + // TODO +} + bool MipsJit::ReplaceJalTo(u32 dest) { const ReplacementTableEntry *entry = nullptr; u32 funcSize = 0; diff --git a/Core/MIPS/MIPS/MipsJit.h b/Core/MIPS/MIPS/MipsJit.h index 23b164b1e77f..2ef4ccbece61 100644 --- a/Core/MIPS/MIPS/MipsJit.h +++ b/Core/MIPS/MIPS/MipsJit.h @@ -49,6 +49,8 @@ class MipsJit : public MIPSGen::MIPSCodeBlock, public JitInterface, public MIPSF void Compile(u32 em_address) override; // Compiles a block at current MIPS PC const u8 *DoJit(u32 em_address, JitBlock *b); + const u8 *GetCrashHandler() const override { return nullptr; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name); void CompileDelaySlot(int flags); @@ -131,6 +133,8 @@ class MipsJit : public MIPSGen::MIPSCodeBlock, public JitInterface, public MIPSF JitBlockCache *GetBlockCache() override { return &blocks; } JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; } + MIPSOpcode GetOriginalOp(MIPSOpcode op) override; + std::vector SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); } void RestoreSavedEmuHackOps(std::vector saved) override { blocks.RestoreSavedEmuHackOps(saved); } @@ -138,6 +142,13 @@ class MipsJit : public MIPSGen::MIPSCodeBlock, public JitInterface, public MIPSF void InvalidateCacheAt(u32 em_address, int length = 4) override; void UpdateFCR31() override; + const u8 *GetDispatcher() const override { + return dispatcher; + } + + void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override; + void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override; + void EatPrefix() override { js.EatPrefix(); } private: @@ -183,8 +194,5 @@ class MipsJit : public MIPSGen::MIPSCodeBlock, public JitInterface, public MIPSF const u8 *dispatcherNoCheck; }; -typedef void (MipsJit::*MIPSCompileFunc)(MIPSOpcode opcode); -typedef int (MipsJit::*MIPSReplaceFunc)(); - } // namespace MIPSComp diff --git a/Core/MIPS/fake/FakeJit.cpp b/Core/MIPS/fake/FakeJit.cpp index 257005a42935..a03c7321186e 100644 --- a/Core/MIPS/fake/FakeJit.cpp +++ b/Core/MIPS/fake/FakeJit.cpp @@ -16,10 +16,12 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/Debugger/Breakpoints.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" @@ -45,19 +47,22 @@ FakeJit::FakeJit(MIPSState *mips) : blocks(mips, this), mips_(mips) blocks.Init(); } -void FakeJit::DoState(PointerWrap &p) -{ - auto s = p.Section("FakeJit", 1, 2); +void FakeJit::DoState(PointerWrap &p) { + auto s = p.Section("Jit", 1, 2); if (!s) return; - p.Do(js.startDefaultPrefix); + Do(p, js.startDefaultPrefix); if (s >= 2) { - p.Do(js.hasSetRounding); + Do(p, js.hasSetRounding); js.lastSetRounding = 0; } else { js.hasSetRounding = 1; } + + // The debugger sets this so that "go" on a breakpoint will actually... go. + // But if they load a state, we can end up hitting it by mistake, since it's based on PC and ticks. + CBreakPoints::SetSkipFirst(0); } // This is here so the savestate matches between jit and non-jit. @@ -68,10 +73,10 @@ void FakeJit::DoDummyState(PointerWrap &p) return; bool dummy = false; - p.Do(dummy); + Do(p, dummy); if (s >= 2) { dummy = true; - p.Do(dummy); + Do(p, dummy); } } @@ -89,7 +94,7 @@ void FakeJit::FlushPrefixV() void FakeJit::ClearCache() { blocks.Clear(); - ClearCodeSpace(); + ClearCodeSpace(0); //GenerateFixedCode(); } diff --git a/Core/MIPS/fake/FakeJit.h b/Core/MIPS/fake/FakeJit.h index d23303a65463..dd1954d1bc6c 100644 --- a/Core/MIPS/fake/FakeJit.h +++ b/Core/MIPS/fake/FakeJit.h @@ -18,8 +18,9 @@ #pragma once #include "Common/FakeEmitter.h" -#include "Core/MIPS/JitCommon/JitState.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" +#include "Core/MIPS/JitCommon/JitState.h" +#include "Core/MIPS/JitCommon/JitCommon.h" #include "../MIPSVFPUUtils.h" #ifndef offsetof @@ -30,7 +31,7 @@ namespace MIPSComp { typedef int FakeReg; -class FakeJit : public FakeGen::FakeXCodeBlock { +class FakeJit : public FakeGen::FakeXCodeBlock, public JitInterface, public MIPSFrontendInterface { public: FakeJit(MIPSState *mips); @@ -46,7 +47,9 @@ class FakeJit : public FakeGen::FakeXCodeBlock { void Compile(u32 em_address); // Compiles a block at current MIPS PC const u8 *DoJit(u32 em_address, JitBlock *b); - bool DescribeCodePtr(const u8 *ptr, std::string &name); + const u8 *GetCrashHandler() const override { return nullptr; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } + bool DescribeCodePtr(const u8 *ptr, std::string &name) override; void CompileDelaySlot(int flags); void EatInstruction(MIPSOpcode op); @@ -126,9 +129,23 @@ class FakeJit : public FakeGen::FakeXCodeBlock { int Replace_fabsf() { return 0; } JitBlockCache *GetBlockCache() { return &blocks; } + JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; } + + MIPSOpcode GetOriginalOp(MIPSOpcode op) override { return op; } + + std::vector SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); } + void RestoreSavedEmuHackOps(std::vector saved) override { blocks.RestoreSavedEmuHackOps(saved); } + + void ClearCache() override; + void InvalidateCacheAt(u32 em_address, int length = 4) override; + void UpdateFCR31() override {} + + const u8 *GetDispatcher() const override { + return nullptr; + } - void ClearCache(); - void InvalidateCacheAt(u32 em_address, int length = 4); + void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override {} + void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override {} void EatPrefix() { js.EatPrefix(); }