diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 7fb0d7982f93df..6edc4f3f6ea9e5 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2355,8 +2355,8 @@ void CodeGen::genReportEH() { for (XTnum = 0; XTnum < compiler->compHndBBtabCount; XTnum++) { - for (enclosingTryIndex = compiler->ehTrueEnclosingTryIndexIL(XTnum); // find the true enclosing try index, - // ignoring 'mutual protect' trys + for (enclosingTryIndex = compiler->ehTrueEnclosingTryIndex(XTnum); // find the true enclosing try index, + // ignoring 'mutual protect' trys enclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX; enclosingTryIndex = compiler->ehGetEnclosingTryIndex(enclosingTryIndex)) { @@ -2662,8 +2662,8 @@ void CodeGen::genReportEH() EHblkDsc* fletTab = compiler->ehGetDsc(XTnum2); - for (enclosingTryIndex = compiler->ehTrueEnclosingTryIndexIL(XTnum2); // find the true enclosing try index, - // ignoring 'mutual protect' trys + for (enclosingTryIndex = compiler->ehTrueEnclosingTryIndex(XTnum2); // find the true enclosing try index, + // ignoring 'mutual protect' trys enclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX; enclosingTryIndex = compiler->ehGetEnclosingTryIndex(enclosingTryIndex)) { diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index e5d99dc152fd33..43b23d1372a84c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -2779,6 +2779,9 @@ class Compiler // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check. unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex); + // Find the true enclosing try index, ignoring 'mutual protect' try. Uses blocks to check. + unsigned ehTrueEnclosingTryIndex(unsigned regionIndex); + // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler. @@ -5285,6 +5288,8 @@ class Compiler // This is derived from the profile data // or is BB_UNITY_WEIGHT when we don't have profile data + bool fgImportDone = false; // true once importation has finished + bool fgFuncletsCreated = false; // true if the funclet creation phase has been run bool fgGlobalMorph = false; // indicates if we are during the global morphing phase diff --git a/src/coreclr/jit/fgehopt.cpp b/src/coreclr/jit/fgehopt.cpp index 7ea85224a863bc..6e0b726266bad6 100644 --- a/src/coreclr/jit/fgehopt.cpp +++ b/src/coreclr/jit/fgehopt.cpp @@ -2736,7 +2736,7 @@ BasicBlock* Compiler::fgCloneTryRegion(BasicBlock* tryEntry, CloneTryInfo& info, break; } outermostEbd = ehGetDsc(enclosingTryIndex); - if (!EHblkDsc::ebdIsSameILTry(outermostEbd, tryEbd)) + if (!EHblkDsc::ebdIsSameTry(outermostEbd, tryEbd)) { break; } diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index e5eb99a3bd3bd2..c900ae003fe1dc 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -590,6 +590,8 @@ PhaseStatus Compiler::fgImport() INDEBUG(fgPgoDeferredInconsistency = false); } + fgImportDone = true; + return PhaseStatus::MODIFIED_EVERYTHING; } @@ -6140,7 +6142,7 @@ bool FlowGraphNaturalLoop::CanDuplicateWithEH(INDEBUG(const char** reason)) // const bool headerInTry = header->hasTryIndex(); unsigned blockIndex = block->getTryIndex(); - unsigned outermostBlockIndex = comp->ehTrueEnclosingTryIndexIL(blockIndex); + unsigned outermostBlockIndex = comp->ehTrueEnclosingTryIndex(blockIndex); if ((headerInTry && (outermostBlockIndex == header->getTryIndex())) || (!headerInTry && (outermostBlockIndex == EHblkDsc::NO_ENCLOSING_INDEX))) diff --git a/src/coreclr/jit/jiteh.cpp b/src/coreclr/jit/jiteh.cpp index 8f840953193b91..e647925f036edc 100644 --- a/src/coreclr/jit/jiteh.cpp +++ b/src/coreclr/jit/jiteh.cpp @@ -799,14 +799,24 @@ unsigned Compiler::ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegi return mostNestedRegion; } -/***************************************************************************** - * Returns the try index of the enclosing try, skipping all EH regions with the - * same try region (that is, all 'mutual protect' regions). If there is no such - * enclosing try, returns EHblkDsc::NO_ENCLOSING_INDEX. - */ +//------------------------------------------------------------- +// ehTrueEnclosingTryIndexIL: find the outermost enclosing try +// region that is not a mutual-protect try +// +// Arguments: +// regionIndex - index of interest +// +// Returns: +// Index of enclosng non-mutual protect try region, or EHblkDsc::NO_ENCLOSING_INDEX. +// +// Notes: +// Only safe to use during importation, before we have normalize the +// EH in the flow graph. Post importation use, the non-IL version. +// unsigned Compiler::ehTrueEnclosingTryIndexIL(unsigned regionIndex) { assert(regionIndex != EHblkDsc::NO_ENCLOSING_INDEX); + assert(!fgImportDone); EHblkDsc* ehDscRoot = ehGetDsc(regionIndex); EHblkDsc* HBtab = ehDscRoot; @@ -832,6 +842,49 @@ unsigned Compiler::ehTrueEnclosingTryIndexIL(unsigned regionIndex) return regionIndex; } +//------------------------------------------------------------- +// ehTrueEnclosingTryIndex: find the closest enclosing try +// region that is not a mutual-protect try +// +// Arguments: +// regionIndex - index of interest +// +// Returns: +// Index of enclosng non-mutual protect try region, or EHblkDsc::NO_ENCLOSING_INDEX. +// +// Notes: +// Only safe to use after importation, once we have normalized the +// EH in the flow graph. For importation, use the IL version. +// +unsigned Compiler::ehTrueEnclosingTryIndex(unsigned regionIndex) +{ + assert(regionIndex != EHblkDsc::NO_ENCLOSING_INDEX); + assert(fgImportDone); + + EHblkDsc* ehDscRoot = ehGetDsc(regionIndex); + EHblkDsc* HBtab = ehDscRoot; + + for (;;) + { + regionIndex = HBtab->ebdEnclosingTryIndex; + if (regionIndex == EHblkDsc::NO_ENCLOSING_INDEX) + { + // No enclosing 'try'; we're done + break; + } + + HBtab = ehGetDsc(regionIndex); + if (!EHblkDsc::ebdIsSameTry(ehDscRoot, HBtab)) + { + // Found an enclosing 'try' that has a different 'try' region (is not mutually-protect with the + // original region). Return it. + break; + } + } + + return regionIndex; +} + unsigned Compiler::ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion) { assert(regionIndex != EHblkDsc::NO_ENCLOSING_INDEX); @@ -3614,8 +3667,8 @@ void Compiler::fgVerifyHandlerTab() // on the block. for (XTnum = 0, HBtab = compHndBBtab; XTnum < compHndBBtabCount; XTnum++, HBtab++) { - unsigned enclosingTryIndex = ehTrueEnclosingTryIndexIL(XTnum); // find the true enclosing try index, - // ignoring 'mutual protect' trys + unsigned enclosingTryIndex = ehTrueEnclosingTryIndex(XTnum); // find the true enclosing try index, + // ignoring 'mutual protect' trys if (enclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX) { // The handler funclet for 'XTnum' has a try index of 'enclosingTryIndex' (at least, the parts of the diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 133671ac5afc06..b649967ef42521 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13388,47 +13388,22 @@ void Compiler::fgSetOptions() codeGen->setFramePointerRequired(true); } - // Assert that the EH table has been initialized by now. Note that - // compHndBBtabAllocCount never decreases; it is a high-water mark - // of table allocation. In contrast, compHndBBtabCount does shrink - // if we delete a dead EH region, and if it shrinks to zero, the - // table pointer compHndBBtab is unreliable. - assert(compHndBBtabAllocCount >= info.compXcptnsCount); - -#ifdef TARGET_X86 - - // Note: this case, and the !X86 case below, should both use the - // !X86 path. This would require a few more changes for X86 to use - // compHndBBtabCount (the current number of EH clauses) instead of - // info.compXcptnsCount (the number of EH clauses in IL), such as - // in ehNeedsShadowSPslots(). This is because sometimes the IL has - // an EH clause that we delete as statically dead code before we - // get here, leaving no EH clauses left, and thus no requirement - // to use a frame pointer because of EH. But until all the code uses - // the same test, leave info.compXcptnsCount here. Also test for - // CORINFO_FLG_SYNCH methods which are converted into try-finally - // with Monitor helper calls in funclet ABI and need to be treated - // as methods with EH. - if (info.compXcptnsCount > 0 || (UsesFunclets() && (info.compFlags & CORINFO_FLG_SYNCH))) + // If there is EH, we need a frame pointer. + // Note this may premature... we can eliminate all EH after morph, sometimes. + // + if (compHndBBtabCount > 0) { codeGen->setFramePointerRequiredEH(true); +#ifdef TARGET_X86 if (UsesFunclets()) { assert(!codeGen->isGCTypeFixed()); // Enforce fully interruptible codegen for funclet unwinding SetInterruptible(true); } - } - -#else // !TARGET_X86 - - if (compHndBBtabCount > 0) - { - codeGen->setFramePointerRequiredEH(true); - } - #endif // TARGET_X86 + } if (compMethodRequiresPInvokeFrame()) { diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index fa27c21f9772f7..e0793bb0ee1e37 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -2866,7 +2866,7 @@ bool Compiler::optCreatePreheader(FlowGraphNaturalLoop* loop) { // Preheader should be in the true enclosing region of the header. // - preheaderEHRegion = ehTrueEnclosingTryIndexIL(preheaderEHRegion); + preheaderEHRegion = ehTrueEnclosingTryIndex(preheaderEHRegion); inSameRegionAsHeader = false; break; } @@ -5208,7 +5208,7 @@ void Compiler::fgSetEHRegionForNewPreheaderOrExit(BasicBlock* block) { // `next` is the beginning of a try block. Figure out the EH region to use. assert(next->hasTryIndex()); - unsigned newTryIndex = ehTrueEnclosingTryIndexIL(next->getTryIndex()); + unsigned newTryIndex = ehTrueEnclosingTryIndex(next->getTryIndex()); if (newTryIndex == EHblkDsc::NO_ENCLOSING_INDEX) { // No EH try index.