void BlockCache::MarkModified(BlockCacheBlock* block) { ScopedLock lock(&bcache_mutex); UnlinkBlock(block); LinkBlock(block); block->information |= BCACHE_MODIFIED; }
void BlockCache::ReleaseBlock(BlockCacheBlock* block) { ScopedLock lock(&bcache_mutex); assert(block->information & BCACHE_PRESENT); assert(block->information & BCACHE_USED); blocks_used--; if ( blocks_per_area < unused_block_count ) { blocks_allocated--; uint8_t* block_data = BlockDataUnlocked(block); addr_t block_data_addr = Memory::Unmap((addr_t) block_data); Page::Put(block_data_addr, PAGE_USAGE_FILESYSTEM_CACHE); // TODO: We leak this block's meta information here. Rather, we should // put this block into a list of non-present blocks so we can reuse it // later and reallocate a physical frame for it - then we will just // reuse the block's meta information. block->information &= ~(BCACHE_USED | BCACHE_PRESENT); return; } UnlinkBlock(block); unused_block_count++; if ( unused_block ) unused_block->prev_block = block; block->next_block = unused_block; block->prev_block = NULL; block->information &= ~BCACHE_USED; unused_block = block; }
void JitBlockCache::DestroyBlock(int block_num, bool invalidate) { if (block_num < 0 || block_num >= num_blocks_) { ERROR_LOG_REPORT(JIT, "DestroyBlock: Invalid block number %d", block_num); return; } JitBlock *b = &blocks_[block_num]; // No point it being in there anymore. RemoveBlockMap(block_num); // Pure proxy blocks always point directly to a real block, there should be no chains of // proxy-only blocks pointing to proxy-only blocks. // Follow a block proxy chain. // Destroy the block that transitively has this as a proxy. Likely the root block once inlined // this block or its 'parent', so now that this block has changed, the root block must be destroyed. if (b->proxyFor) { for (size_t i = 0; i < b->proxyFor->size(); i++) { int proxied_blocknum = GetBlockNumberFromStartAddress((*b->proxyFor)[i], false); // If it was already cleared, we don't know which to destroy. if (proxied_blocknum != -1) { DestroyBlock(proxied_blocknum, invalidate); } } b->proxyFor->clear(); delete b->proxyFor; b->proxyFor = 0; } auto range = proxyBlockMap_.equal_range(b->originalAddress); for (auto it = range.first; it != range.second; ++it) { if (it->second == block_num) { // Found it. Delete and bail. proxyBlockMap_.erase(it); break; } } // TODO: Handle the case when there's a proxy block and a regular JIT block at the same location. // In this case we probably "leak" the proxy block currently (no memory leak but it'll stay enabled). if (b->invalid) { if (invalidate) ERROR_LOG(JIT, "Invalidating invalid block %d", block_num); return; } b->invalid = true; if (Memory::ReadUnchecked_U32(b->originalAddress) == GetEmuHackOpForBlock(block_num).encoding) Memory::Write_Opcode_JIT(b->originalAddress, b->originalFirstOpcode); // It's not safe to set normalEntry to 0 here, since we use a binary search // that looks at that later to find blocks. Marking it invalid is enough. UnlinkBlock(block_num); #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->dispatcher); 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->Asm().dispatcher, true); #elif defined(PPC) PPCXEmitter emit((u8 *)b->checkedEntry); emit.MOVI2R(R3, b->originalAddress); emit.STW(R0, CTXREG, offsetof(MIPSState, pc)); emit.B(MIPSComp::jit->dispatcher); emit.FlushIcache(); #endif }
void BlockCache::MarkUsed(BlockCacheBlock* block) { ScopedLock lock(&bcache_mutex); UnlinkBlock(block); LinkBlock(block); }