diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 7d8843f347..af4984c221 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -525,6 +525,9 @@ static int sceUtilitySavedataInitStart(u32 paramAddr) { } } + // TODO: In issue #19957, we're looking at NFL Street 3 which gets stuck. Possibly if a dialog is already open here, + // we should block until it's done? + ActivateDialog(UtilityDialogType::SAVEDATA); return hleLogDebug(Log::sceUtility, saveDialog->Init(paramAddr)); } diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 78ec6164bb..1173592d3b 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -299,8 +299,7 @@ MIPSOpcode ArmJit::GetOffsetInstruction(int offset) { return Memory::Read_Instruction(GetCompilerPC() + 4 * offset); } -const u8 *ArmJit::DoJit(u32 em_address, JitBlock *b) -{ +void ArmJit::DoJit(u32 em_address, JitBlock *b) { js.cancel = false; js.blockStart = em_address; js.compilerPC = em_address; @@ -424,10 +423,9 @@ const u8 *ArmJit::DoJit(u32 em_address, JitBlock *b) else { // We continued at least once. Add the last proxy and set the originalSize correctly. - blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); b->originalSize = js.initialBlockSize; } - return b->normalEntry; } void ArmJit::AddContinuedBlock(u32 dest) @@ -436,7 +434,7 @@ void ArmJit::AddContinuedBlock(u32 dest) if (js.lastContinuedPC == 0) js.initialBlockSize = js.numInstructions; else - blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); js.lastContinuedPC = dest; } @@ -544,7 +542,7 @@ bool ArmJit::ReplaceJalTo(u32 dest) { } // Add a trigger so that if the inlined code changes, we invalidate this block. - blocks.ProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); return true; } diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 04f1ac79d3..292a107d1c 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -193,7 +193,7 @@ public: void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override; private: - const u8 *DoJit(u32 em_address, JitBlock *b); + void DoJit(u32 em_address, JitBlock *b); void GenerateFixedCode(); void FlushAll(); diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 63fbd4e90d..6929aef95a 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -256,7 +256,7 @@ void Arm64Jit::Compile(u32 em_address) { JitBlock *b = blocks.GetBlock(block_num); DoJit(em_address, b); - _assert_msg_(b->originalAddress == em_address, "original %08x != em_address %08x (block %d)", b->originalAddress, em_address, b->blockNum); + b->DoIntegrityCheck(em_address, block_num); blocks.FinalizeBlock(block_num, jo.enableBlocklink); EndWrite(); @@ -303,7 +303,7 @@ MIPSOpcode Arm64Jit::GetOffsetInstruction(int offset) { return Memory::Read_Instruction(GetCompilerPC() + 4 * offset); } -const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) { +void Arm64Jit::DoJit(u32 em_address, JitBlock *b) { js.cancel = false; js.blockStart = em_address; js.compilerPC = em_address; @@ -411,11 +411,9 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) { b->originalSize = js.numInstructions; } else { // We continued at least once. Add the last proxy and set the originalSize correctly. - blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); b->originalSize = js.initialBlockSize; } - - return b->normalEntry; } void Arm64Jit::AddContinuedBlock(u32 dest) { @@ -423,7 +421,7 @@ void Arm64Jit::AddContinuedBlock(u32 dest) { if (js.lastContinuedPC == 0) js.initialBlockSize = js.numInstructions; else - blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); js.lastContinuedPC = dest; } @@ -549,7 +547,7 @@ bool Arm64Jit::ReplaceJalTo(u32 dest) { } // Add a trigger so that if the inlined code changes, we invalidate this block. - blocks.ProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); #endif return true; } diff --git a/Core/MIPS/ARM64/Arm64Jit.h b/Core/MIPS/ARM64/Arm64Jit.h index f3d6acc6a7..15ff701c81 100644 --- a/Core/MIPS/ARM64/Arm64Jit.h +++ b/Core/MIPS/ARM64/Arm64Jit.h @@ -50,7 +50,7 @@ public: void RunLoopUntil(u64 globalticks) override; void Compile(u32 em_address) override; // Compiles a block at current MIPS PC - const u8 *DoJit(u32 em_address, JitBlock *b); + void DoJit(u32 em_address, JitBlock *b); const u8 *GetCrashHandler() const override { return crashHandler; } bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index e192195760..4a08353d2a 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -41,6 +41,7 @@ #include "Core/MIPS/JitCommon/JitCommon.h" constexpr u32 INVALID_EXIT = 0xFFFFFFFF; +constexpr u32 SENTINEL_VAL = 0xc0ffeefe; static uint64_t HashJitBlock(const JitBlock &b) { PROFILE_THIS_SCOPE("jithash"); @@ -56,6 +57,17 @@ static uint64_t HashJitBlock(const JitBlock &b) { return 0; } +bool JitBlock::ContainsAddress(u32 address) const { + // WARNING - THIS DOES NOT WORK WITH JIT INLINING ENABLED. + // However, that doesn't exist yet so meh. + return address >= originalAddress && address < originalAddress + 4 * originalSize; +} + +void JitBlock::DoIntegrityCheck(u32 em_address, int blockNum) const { + _assert_msg_(sentinel == SENTINEL_VAL, "Block %d sentinel got corrupted: %08x (origAddr: %08x)", blockNum, sentinel, originalAddress); + _assert_msg_(originalAddress == em_address, "Block %d address got corrupted: %08x != %08x", blockNum, em_address, originalAddress); +} + JitBlockCache::JitBlockCache(MIPSState *mipsState, CodeBlockCommon *codeBlock) : codeBlock_(codeBlock) { } @@ -64,12 +76,6 @@ JitBlockCache::~JitBlockCache() { Shutdown(); } -bool JitBlock::ContainsAddress(u32 em_address) const { - // WARNING - THIS DOES NOT WORK WITH JIT INLINING ENABLED. - // However, that doesn't exist yet so meh. - return em_address >= originalAddress && em_address < originalAddress + 4 * originalSize; -} - bool JitBlockCache::IsFull() const { // Subtract some amount to safely leave space for some proxy blocks, which we don't check before we allocate (not ideal, but should be enough). return num_blocks_ >= MAX_NUM_BLOCKS - 512; @@ -109,14 +115,6 @@ void JitBlockCache::Reset() { Init(); } -JitBlock *JitBlockCache::GetBlock(int no) { - return &blocks_[no]; -} - -const JitBlock *JitBlockCache::GetBlock(int no) const { - return &blocks_[no]; -} - int JitBlockCache::AllocateBlock(u32 startAddress) { _assert_(num_blocks_ < MAX_NUM_BLOCKS); @@ -146,11 +144,12 @@ int JitBlockCache::AllocateBlock(u32 startAddress) { b.linkStatus[i] = false; } b.blockNum = num_blocks_; + b.sentinel = SENTINEL_VAL; num_blocks_++; //commit the current block return num_blocks_ - 1; } -void JitBlockCache::ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, const u8 *codePtr) { +void JitBlockCache::CreateProxyBlock(u32 rootAddress, u32 startAddress, u32 size, const u8 *codePtr) { _assert_(num_blocks_ < MAX_NUM_BLOCKS); // If there's an existing block at the startAddress, add rootAddress as a proxy root of that block @@ -333,18 +332,17 @@ int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr, bool realBlocksOnly) return bl; } -void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers) { +void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers) const { for (int i = 0; i < num_blocks_; i++) if (blocks_[i].ContainsAddress(em_address)) block_numbers->push_back(i); } -int JitBlockCache::GetBlockNumberFromAddress(u32 em_address) { +int JitBlockCache::GetBlockNumberFromAddress(u32 em_address) const { for (int i = 0; i < num_blocks_; i++) { if (blocks_[i].ContainsAddress(em_address)) return i; } - return -1; } @@ -363,7 +361,7 @@ u32 JitBlockCache::GetAddressFromBlockPtr(const u8 *ptr) const { return 0; } -MIPSOpcode JitBlockCache::GetOriginalFirstOp(int block_num) { +MIPSOpcode JitBlockCache::GetOriginalFirstOp(int block_num) const { if (block_num >= num_blocks_ || block_num < 0) { return MIPSOpcode(block_num); } diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index 1bcd5ba3ab..b461e2a362 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -33,6 +33,7 @@ const int MAX_JIT_BLOCK_EXITS = 4; #else const int MAX_JIT_BLOCK_EXITS = 8; #endif + constexpr bool JIT_USE_COMPILEDHASH = true; struct BlockCacheStats { @@ -54,17 +55,21 @@ enum class DestroyType { // We should be careful not to access these block structures during runtime as they are large. // Fine to mess with them at block compile time though. struct JitBlock { - bool ContainsAddress(u32 em_address) const; + bool ContainsAddress(u32 address) const; + void DoIntegrityCheck(u32 emAddress, int blockNum) const; const u8 *checkedEntry; // const, we have to translate to writable. const u8 *normalEntry; u8 *exitPtrs[MAX_JIT_BLOCK_EXITS]; // to be able to rewrite the exit jump u32 exitAddress[MAX_JIT_BLOCK_EXITS]; // 0xFFFFFFFF == unknown + u32 sentinel; u32 originalAddress; MIPSOpcode originalFirstOpcode; //to be able to restore + uint64_t compiledHash; + u16 codeSize; u16 originalSize; u16 blockNum; @@ -72,8 +77,8 @@ struct JitBlock { bool invalid; bool linkStatus[MAX_JIT_BLOCK_EXITS]; - // By having a pointer, we avoid a constructor/destructor being generated and dog slow - // performance in debug. + // By having a pointer, we avoid a constructor/destructor call being generated if unused, + // thus avoiding dog slow performance in debug build. std::vector *proxyFor; bool IsPureProxy() const { @@ -127,7 +132,7 @@ public: int AllocateBlock(u32 em_address); // When a proxy block is invalidated, the block located at the rootAddress is invalidated too. - void ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, const u8 *codePtr); + void CreateProxyBlock(u32 rootAddress, u32 startAddress, u32 size, const u8 *codePtr); void FinalizeBlock(int block_num, bool block_link); void Clear(); @@ -139,8 +144,8 @@ public: void ComputeStats(BlockCacheStats &bcStats) const override; // Code Cache - JitBlock *GetBlock(int block_num); - const JitBlock *GetBlock(int block_num) const; + JitBlock *GetBlock(int no) { return &blocks_[no]; } + const JitBlock *GetBlock(int no) const { return &blocks_[no]; } // Fast way to get a block. Only works on the first source-cpu instruction of a block. int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override; @@ -149,14 +154,14 @@ public: // WARNING! WILL NOT WORK WITH JIT INLINING ENABLED (not yet a feature but will be soon) // Returns a list of block numbers - only one block can start at a particular address, but they CAN overlap. // This one is slow so should only be used for one-shots from the debugger UI, not for anything during runtime. - void GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers); + void GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers) const; // Similar to above, but only the first matching address. - int GetBlockNumberFromAddress(u32 em_address); + int GetBlockNumberFromAddress(u32 em_address) const; int GetBlockNumberFromEmuHackOp(MIPSOpcode inst, bool ignoreBad = false) const; u32 GetAddressFromBlockPtr(const u8 *ptr) const; - MIPSOpcode GetOriginalFirstOp(int block_num); + MIPSOpcode GetOriginalFirstOp(int block_num) const; bool RangeMayHaveEmuHacks(u32 start, u32 end) const; diff --git a/Core/MIPS/fake/FakeJit.cpp b/Core/MIPS/fake/FakeJit.cpp index 088f4d50d8..82011bb55e 100644 --- a/Core/MIPS/fake/FakeJit.cpp +++ b/Core/MIPS/fake/FakeJit.cpp @@ -132,9 +132,8 @@ void FakeJit::RunLoopUntil(u64 globalticks) { MIPSInterpret_RunUntil(globalticks); } -const u8 *FakeJit::DoJit(u32 em_address, JitBlock *b) { +void FakeJit::DoJit(u32 em_address, JitBlock *b) { _assert_(false); - return nullptr; } void FakeJit::AddContinuedBlock(u32 dest) diff --git a/Core/MIPS/fake/FakeJit.h b/Core/MIPS/fake/FakeJit.h index bce7fe92d3..1b88fb37d3 100644 --- a/Core/MIPS/fake/FakeJit.h +++ b/Core/MIPS/fake/FakeJit.h @@ -45,7 +45,7 @@ public: void RunLoopUntil(u64 globalticks) override; void Compile(u32 em_address) override; // Compiles a block at current MIPS PC - const u8 *DoJit(u32 em_address, JitBlock *b); + void DoJit(u32 em_address, JitBlock *b); const u8 *GetCrashHandler() const override { return nullptr; } bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 829c80c794..8c9b175754 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -446,10 +446,9 @@ void Jit::DoJit(u32 em_address, JitBlock *b) { b->originalSize = js.numInstructions; } else { // We continued at least once. Add the last proxy and set the originalSize correctly. - blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); b->originalSize = js.initialBlockSize; } - return b->normalEntry; } void Jit::AddContinuedBlock(u32 dest) { @@ -457,7 +456,7 @@ void Jit::AddContinuedBlock(u32 dest) { if (js.lastContinuedPC == 0) js.initialBlockSize = js.numInstructions; else - blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, js.lastContinuedPC, (GetCompilerPC() - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); js.lastContinuedPC = dest; } @@ -591,7 +590,7 @@ bool Jit::ReplaceJalTo(u32 dest) { } // Add a trigger so that if the inlined code changes, we invalidate this block. - blocks.ProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); + blocks.CreateProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); return true; }