Example #1
0
void BlockCache::MarkModified(BlockCacheBlock* block)
{
	ScopedLock lock(&bcache_mutex);
	UnlinkBlock(block);
	LinkBlock(block);
	block->information |= BCACHE_MODIFIED;
}
Example #2
0
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
}
Example #4
0
void BlockCache::MarkUsed(BlockCacheBlock* block)
{
	ScopedLock lock(&bcache_mutex);
	UnlinkBlock(block);
	LinkBlock(block);
}