Commit ab5aebc3 authored by Jean-Philip Desjardins's avatar Jean-Philip Desjardins
Browse files

Make sure everything is coherent when deleting blocks.

parent 3952e74d
......@@ -52,6 +52,10 @@ CBasicBlock::CBasicBlock(CMIPS& context, uint32 begin, uint32 end)
assert(m_end >= m_begin);
for(uint32 i = 0; i < LINK_SLOT_MAX; i++)
{
#ifdef _DEBUG
m_linkBlock[i] = nullptr;
#endif
m_linkTargetAddress[i] = MIPS_INVALID_PC;
m_linkBlockTrampolineOffset[i] = INVALID_LINK_SLOT;
}
}
......@@ -293,17 +297,47 @@ bool CBasicBlock::IsEmpty() const
(m_end == MIPS_INVALID_PC);
}
uint32 CBasicBlock::GetLinkTargetAddress(LINK_SLOT linkSlot)
{
assert(linkSlot < LINK_SLOT_MAX);
return m_linkTargetAddress[linkSlot];
}
void CBasicBlock::SetLinkTargetAddress(LINK_SLOT linkSlot, uint32 address)
{
assert(linkSlot < LINK_SLOT_MAX);
m_linkTargetAddress[linkSlot] = address;
}
void CBasicBlock::LinkBlock(LINK_SLOT linkSlot, CBasicBlock* otherBlock)
{
assert(!IsEmpty());
assert(!otherBlock->IsEmpty());
assert(linkSlot < LINK_SLOT_MAX);
assert(m_linkBlockTrampolineOffset[linkSlot] != INVALID_LINK_SLOT);
#ifdef _DEBUG
assert(m_linkBlock[linkSlot] == nullptr);
m_linkBlock[linkSlot] = otherBlock;
#endif
auto patchValue = reinterpret_cast<uintptr_t>(otherBlock->m_function.GetCode());
auto code = reinterpret_cast<uint8*>(m_function.GetCode());
*reinterpret_cast<uintptr_t*>(code + m_linkBlockTrampolineOffset[linkSlot]) = patchValue;
}
void CBasicBlock::UnlinkBlock(LINK_SLOT linkSlot)
{
assert(!IsEmpty());
assert(linkSlot < LINK_SLOT_MAX);
assert(m_linkBlockTrampolineOffset[linkSlot] != INVALID_LINK_SLOT);
#ifdef _DEBUG
assert(m_linkBlock[linkSlot] != nullptr);
m_linkBlock[linkSlot] = nullptr;
#endif
auto patchValue = reinterpret_cast<uintptr_t>(&NextBlockTrampoline);
auto code = reinterpret_cast<uint8*>(m_function.GetCode());
*reinterpret_cast<uintptr_t*>(code + m_linkBlockTrampolineOffset[linkSlot]) = patchValue;
}
void CBasicBlock::HandleExternalFunctionReference(uintptr_t symbol, uint32 offset)
{
if(symbol == reinterpret_cast<uintptr_t>(&NextBlockTrampoline))
......
......@@ -60,7 +60,10 @@ public:
bool IsCompiled() const;
bool IsEmpty() const;
uint32 GetLinkTargetAddress(LINK_SLOT);
void SetLinkTargetAddress(LINK_SLOT, uint32);
void LinkBlock(LINK_SLOT, CBasicBlock*);
void UnlinkBlock(LINK_SLOT);
#ifdef AOT_BUILD_CACHE
static void SetAotBlockOutputStream(Framework::CStdStream*);
......@@ -90,5 +93,9 @@ private:
#else
void (*m_function)(void*);
#endif
uint32 m_linkTargetAddress[LINK_SLOT_MAX];
uint32 m_linkBlockTrampolineOffset[LINK_SLOT_MAX];
#ifdef _DEBUG
CBasicBlock* m_linkBlock[LINK_SLOT_MAX];
#endif
};
......@@ -217,18 +217,6 @@ public:
return m_blockLookup.FindBlockAt(address);
}
void DeleteBlock(CBasicBlock* block)
{
assert(block != m_emptyBlock.get());
m_blockLookup.DeleteBlock(block);
//Remove block from our lists
auto blockIterator = std::find_if(std::begin(m_blocks), std::end(m_blocks), [&](const BasicBlockPtr& blockPtr) { return blockPtr.get() == block; });
assert(blockIterator != std::end(m_blocks));
m_blocks.erase(blockIterator);
}
virtual void Reset()
{
ClearActiveBlocks();
......@@ -305,27 +293,33 @@ protected:
{
uint32 nextBlockAddress = endAddress + 4;
block->SetLinkTargetAddress(CBasicBlock::LINK_SLOT_NEXT, nextBlockAddress);
auto link = std::make_pair(nextBlockAddress, BLOCK_LINK{CBasicBlock::LINK_SLOT_NEXT, startAddress});
auto nextBlock = m_blockLookup.FindBlockAt(nextBlockAddress);
if(!nextBlock->IsEmpty())
{
block->LinkBlock(CBasicBlock::LINK_SLOT_NEXT, nextBlock);
m_blockLinks.insert(link);
}
else
{
m_pendingBlockLinks.insert(std::make_pair(nextBlockAddress, BLOCK_LINK { CBasicBlock::LINK_SLOT_NEXT, startAddress }));
m_pendingBlockLinks.insert(link);
}
}
if(branchAddress != 0)
{
block->SetLinkTargetAddress(CBasicBlock::LINK_SLOT_BRANCH, branchAddress);
auto link = std::make_pair(branchAddress, BLOCK_LINK{CBasicBlock::LINK_SLOT_BRANCH, startAddress});
auto branchBlock = m_blockLookup.FindBlockAt(branchAddress);
if(!branchBlock->IsEmpty())
{
block->LinkBlock(CBasicBlock::LINK_SLOT_BRANCH, branchBlock);
m_blockLinks.insert(link);
}
else
{
m_pendingBlockLinks.insert(std::make_pair(branchAddress, BLOCK_LINK { CBasicBlock::LINK_SLOT_BRANCH, startAddress }));
m_pendingBlockLinks.insert(link);
}
}
......@@ -339,6 +333,7 @@ protected:
auto referringBlock = m_blockLookup.FindBlockAt(blockLink.address);
if(referringBlock->IsEmpty()) continue;
referringBlock->LinkBlock(blockLink.slot, block);
m_blockLinks.insert(*blockLinkIterator);
}
m_pendingBlockLinks.erase(lowerBound, upperBound);
}
......@@ -369,6 +364,40 @@ protected:
SetupBlockLinks(startAddress, endAddress, branchAddress);
}
//Unlink and removes block from all of our bookkeeping structures
void OrphanBlock(CBasicBlock* block)
{
auto orphanBlockLinkSlot =
[&](CBasicBlock::LINK_SLOT linkSlot)
{
auto slotSearch =
[&](const std::pair<uint32, BLOCK_LINK>& link) {
return (link.second.address == block->GetBeginAddress()) &&
(link.second.slot == linkSlot);
};
uint32 linkTargetAddress = block->GetLinkTargetAddress(linkSlot);
//Check if block has this specific link slot
if(linkTargetAddress != MIPS_INVALID_PC)
{
//If it has that link slot, it's either linked or pending to be linked
auto slotIterator = std::find_if(m_blockLinks.begin(), m_blockLinks.end(), slotSearch);
if(slotIterator != std::end(m_blockLinks))
{
block->UnlinkBlock(linkSlot);
m_blockLinks.erase(slotIterator);
}
else
{
slotIterator = std::find_if(m_pendingBlockLinks.begin(), m_pendingBlockLinks.end(), slotSearch);
assert(slotIterator != std::end(m_pendingBlockLinks));
m_pendingBlockLinks.erase(slotIterator);
}
}
};
orphanBlockLinkSlot(CBasicBlock::LINK_SLOT_NEXT);
orphanBlockLinkSlot(CBasicBlock::LINK_SLOT_BRANCH);
}
void ClearActiveBlocksInRangeInternal(uint32 start, uint32 end, CBasicBlock* protectedBlock)
{
//Widen scan range since blocks starting before the range can end in the range
......@@ -387,6 +416,28 @@ protected:
m_blockLookup.DeleteBlock(block);
}
//Remove pending block link entries for the blocks that are about to be cleared
for(auto& block : clearedBlocks)
{
OrphanBlock(block);
}
//Undo all stale links
for(auto& block : clearedBlocks)
{
auto lowerBound = m_blockLinks.lower_bound(block->GetBeginAddress());
auto upperBound = m_blockLinks.upper_bound(block->GetBeginAddress());
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
{
const auto& blockLink = blockLinkIterator->second;
auto referringBlock = m_blockLookup.FindBlockAt(blockLink.address);
if(referringBlock->IsEmpty()) continue;
referringBlock->UnlinkBlock(blockLink.slot);
m_pendingBlockLinks.insert(*blockLinkIterator);
}
m_blockLinks.erase(lowerBound, upperBound);
}
if(!clearedBlocks.empty())
{
m_blocks.remove_if([&](const BasicBlockPtr& block) { return clearedBlocks.find(block.get()) != std::end(clearedBlocks); });
......@@ -395,6 +446,7 @@ protected:
BlockList m_blocks;
BasicBlockPtr m_emptyBlock;
BlockLinkMap m_blockLinks;
BlockLinkMap m_pendingBlockLinks;
CMIPS& m_context;
uint32 m_maxAddress = 0;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment