Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2807,6 +2807,9 @@ class Compiler
EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
bool ehIsBlockEHLast(BasicBlock* block);

template <typename GetTryLast, typename SetTryLast>
void ehSetTryLasts(GetTryLast getTryLast, SetTryLast setTryLast);

bool ehBlockHasExnFlowDsc(BasicBlock* block);

// Return the region index of the most nested EH region this block is in.
Expand All @@ -2833,6 +2836,10 @@ class Compiler
// Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);

// Update the end pointer of the try region containing 'oldTryLast',
// as well as the end pointers of any parent try regions, to 'newTryLast'.
void ehUpdateLastTryBlocks(BasicBlock* oldTryLast, BasicBlock* newTryLast);

// For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
// or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
// is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
Expand Down
47 changes: 17 additions & 30 deletions src/coreclr/jit/fgehopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1437,38 +1437,13 @@ PhaseStatus Compiler::fgCloneFinally()
originalWeight = BB_ZERO_WEIGHT;
}

for (BasicBlock* block = firstBlock; block != nextBlock; block = block->Next())
for (BasicBlock* block = firstBlock; !reachedEnd; block = block->Next())
{
BasicBlock* newBlock;

if (block == firstBlock)
{
// Put first cloned finally block into the appropriate
// region, somewhere within or after the range of
// callfinallys, depending on the EH implementation.
const unsigned hndIndex = 0;
BasicBlock* const nearBlk = cloneInsertAfter;
newBlock = fgNewBBinRegion(BBJ_ALWAYS, finallyTryIndex, hndIndex, nearBlk);

// If the clone ends up just after the finally, adjust
// the stopping point for finally traversal.
if (newBlock->NextIs(nextBlock))
{
assert(newBlock->PrevIs(lastBlock));
nextBlock = newBlock;
}
}
else
{
// Put subsequent blocks in the same region...
const bool extendRegion = true;
newBlock = fgNewBBafter(BBJ_ALWAYS, insertAfter, extendRegion);
}

BasicBlock* newBlock = fgNewBBafter(BBJ_ALWAYS, cloneInsertAfter, /* extendRegion */ false);
cloneInsertAfter = newBlock;
cloneBBCount++;
assert(cloneBBCount <= regionBBCount);

insertAfter = newBlock;
blockMap.Set(block, newBlock);

BasicBlock::CloneBlockState(this, newBlock, block);
Expand All @@ -1484,13 +1459,14 @@ PhaseStatus Compiler::fgCloneFinally()
{
// Mark the block as the end of the cloned finally.
newBlock->SetFlags(BBF_CLONED_FINALLY_END);
reachedEnd = true;
}

// Cloned finally block does not need any special protection.
newBlock->RemoveFlags(BBF_DONT_REMOVE);

// Make sure clone block state hasn't munged the try region.
assert(newBlock->bbTryIndex == finallyTryIndex);
assert(newBlock->bbTryIndex == firstBlock->bbTryIndex);

// Cloned handler block is no longer within the handler.
newBlock->clearHndIndex();
Expand All @@ -1500,6 +1476,17 @@ PhaseStatus Compiler::fgCloneFinally()
assert(!newBlock->HasInitializedTarget());
}

// If the cloned blocks were inserted at the end of a try region, update the region's end pointer
if (firstBlock->hasTryIndex())
{
BasicBlock* const oldLastTry = ehGetDsc(firstBlock->getTryIndex())->ebdTryLast;
if (!oldLastTry->IsLast() && BasicBlock::sameTryRegion(oldLastTry, oldLastTry->Next()))
{
assert(oldLastTry->NextIs(blockMap[firstBlock]));
ehUpdateLastTryBlocks(oldLastTry, blockMap[lastBlock]);
}
}

// We should have cloned all the finally region blocks.
assert(cloneBBCount == regionBBCount);

Expand All @@ -1509,7 +1496,7 @@ PhaseStatus Compiler::fgCloneFinally()
// Redirect any branches within the newly-cloned
// finally, and any finally returns to jump to the return
// point.
for (BasicBlock* block = firstBlock; block != nextBlock; block = block->Next())
for (BasicBlock* block = firstBlock; !lastBlock->NextIs(block); block = block->Next())
{
BasicBlock* newBlock = blockMap[block];
// Jump kind/target should not be set yet
Expand Down
68 changes: 26 additions & 42 deletions src/coreclr/jit/jiteh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,26 @@ void Compiler::ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast)
}
}

//-----------------------------------------------------------------------------
// ehUpdateLastTryBlocks: Update the end pointer of the try region containing 'oldTryLast',
// as well as the end pointers of any parent try regions, to 'newTryLast'.
//
// Arguments:
// oldTryLast - The previous end block of the try region(s) to be updated
// newTryLast - The new end block
//
void Compiler::ehUpdateLastTryBlocks(BasicBlock* oldTryLast, BasicBlock* newTryLast)
{
assert(oldTryLast->hasTryIndex() && BasicBlock::sameTryRegion(oldTryLast, newTryLast));
unsigned XTnum = oldTryLast->getTryIndex();
for (EHblkDsc* HBtab = ehGetDsc(XTnum); (XTnum < compHndBBtabCount) && (HBtab->ebdTryLast == oldTryLast);
XTnum++, HBtab++)
{
assert((XTnum == oldTryLast->getTryIndex()) || (ehGetDsc(XTnum - 1)->ebdEnclosingTryIndex == XTnum));
fgSetTryEnd(HBtab, newTryLast);
}
}

unsigned Compiler::ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion)
{
assert(finallyIndex != EHblkDsc::NO_ENCLOSING_INDEX);
Expand Down Expand Up @@ -1303,16 +1323,8 @@ EHblkDsc* Compiler::ehFindEHblkDscById(unsigned short id)
void Compiler::fgSetTryBeg(EHblkDsc* handlerTab, BasicBlock* newTryBeg)
{
assert(newTryBeg != nullptr);

// Check if we are going to change the existing value of endTryLast
//
if (handlerTab->ebdTryBeg != newTryBeg)
{
// Update the EH table with the newTryLast block
handlerTab->ebdTryBeg = newTryBeg;

JITDUMP("EH#%u: New first block of try: " FMT_BB "\n", ehGetIndex(handlerTab), handlerTab->ebdTryBeg->bbNum);
}
handlerTab->ebdTryBeg = newTryBeg;
JITDUMP("EH#%u: New first block of try: " FMT_BB "\n", ehGetIndex(handlerTab), newTryBeg->bbNum);
}

/*****************************************************************************
Expand All @@ -1322,22 +1334,8 @@ void Compiler::fgSetTryBeg(EHblkDsc* handlerTab, BasicBlock* newTryBeg)
void Compiler::fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast)
{
assert(newTryLast != nullptr);

//
// Check if we are going to change the existing value of endTryLast
//
if (handlerTab->ebdTryLast != newTryLast)
{
// Update the EH table with the newTryLast block
handlerTab->ebdTryLast = newTryLast;

#ifdef DEBUG
if (verbose)
{
printf("EH#%u: New last block of try: " FMT_BB "\n", ehGetIndex(handlerTab), newTryLast->bbNum);
}
#endif // DEBUG
}
handlerTab->ebdTryLast = newTryLast;
JITDUMP("EH#%u: New last block of try: " FMT_BB "\n", ehGetIndex(handlerTab), newTryLast->bbNum);
}

/*****************************************************************************
Expand All @@ -1348,22 +1346,8 @@ void Compiler::fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast)
void Compiler::fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast)
{
assert(newHndLast != nullptr);

//
// Check if we are going to change the existing value of endHndLast
//
if (handlerTab->ebdHndLast != newHndLast)
{
// Update the EH table with the newHndLast block
handlerTab->ebdHndLast = newHndLast;

#ifdef DEBUG
if (verbose)
{
printf("EH#%u: New last block of handler: " FMT_BB "\n", ehGetIndex(handlerTab), newHndLast->bbNum);
}
#endif // DEBUG
}
handlerTab->ebdHndLast = newHndLast;
JITDUMP("EH#%u: New last block of handler: " FMT_BB "\n", ehGetIndex(handlerTab), newHndLast->bbNum);
}

//-------------------------------------------------------------
Expand Down
Loading