diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 925f862a4bda..9a507eed318f 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -3443,6 +3443,8 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() } else { + bool inFuncletSection = false; + for (lblk = nullptr, block = fgFirstBB; block != nullptr; lblk = block, block = block->bbNext) { bool blockMustBeInHotSection = false; @@ -3454,6 +3456,15 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() } #endif // HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION +#ifdef FEATURE_EH_FUNCLETS + // Make note of if we're in the funclet section, + // so we can stop the search early. + if (block == fgFirstFuncletBB) + { + inFuncletSection = true; + } +#endif // FEATURE_EH_FUNCLETS + // Do we have a candidate for the first cold block? if (firstColdBlock != nullptr) { @@ -3465,6 +3476,21 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() // We have to restart the search for the first cold block firstColdBlock = nullptr; prevToFirstColdBlock = nullptr; + +#ifdef FEATURE_EH_FUNCLETS + // If we're already in the funclet section, try to split + // at fgFirstFuncletBB, and stop the search. + if (inFuncletSection) + { + if (fgFuncletsAreCold()) + { + firstColdBlock = fgFirstFuncletBB; + prevToFirstColdBlock = fgFirstFuncletBB->bbPrev; + } + + break; + } +#endif // FEATURE_EH_FUNCLETS } } else // (firstColdBlock == NULL) -- we don't have a candidate for first cold block @@ -3476,7 +3502,7 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() // consider splitting at the first funclet; do not consider splitting between funclets, // as this may break unwind info. // - if (block == fgFirstFuncletBB) + if (inFuncletSection) { if (fgFuncletsAreCold()) { diff --git a/src/coreclr/jit/unwind.cpp b/src/coreclr/jit/unwind.cpp index 5cae88b36e36..ea9ee5787aaa 100644 --- a/src/coreclr/jit/unwind.cpp +++ b/src/coreclr/jit/unwind.cpp @@ -102,7 +102,15 @@ void Compiler::unwindGetFuncLocations(FuncInfoDsc* func, assert(fgFirstColdBlock != nullptr); // There better be a cold section! *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock)); - *ppEndLoc = nullptr; // nullptr end location means the end of the code + + if (fgFirstFuncletBB != nullptr) + { + *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstFuncletBB)); + } + else + { + *ppEndLoc = nullptr; // nullptr end location means the end of the code + } } } else diff --git a/src/coreclr/jit/unwindamd64.cpp b/src/coreclr/jit/unwindamd64.cpp index ff9a5094cb0a..fa5f9df5ae33 100644 --- a/src/coreclr/jit/unwindamd64.cpp +++ b/src/coreclr/jit/unwindamd64.cpp @@ -656,17 +656,34 @@ void Compiler::unwindReserve() // void Compiler::unwindReserveFunc(FuncInfoDsc* func) { - unwindReserveFuncHelper(func, true); - - if (fgFirstColdBlock != nullptr) - { #ifdef DEBUG - if (!JitConfig.JitFakeProcedureSplitting()) + // If fake-splitting, treat all unwind info as hot. + if (JitConfig.JitFakeProcedureSplitting()) + { + unwindReserveFuncHelper(func, true); + return; + } #endif // DEBUG + + if (func->funKind == FUNC_ROOT) + { + unwindReserveFuncHelper(func, true); + + // If the function's main body is split, reserve unwind info of size 0 for the cold section. + // If only funclets are cold, the main body is hot, so don't make a second call. + const bool isFunctionSplit = ((fgFirstColdBlock != nullptr) && (fgFirstColdBlock != fgFirstFuncletBB)); + if (isFunctionSplit) { unwindReserveFuncHelper(func, false); } } + else + { + // Make only one call for funclets. + // If function is split and has EH, the funclets will be cold. + const bool isFuncletHot = (fgFirstColdBlock == nullptr); + unwindReserveFuncHelper(func, isFuncletHot); + } } //------------------------------------------------------------------------ @@ -679,8 +696,10 @@ void Compiler::unwindReserveFunc(FuncInfoDsc* func) // void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode) { - DWORD unwindCodeBytes = 0; - if (isHotCode) + const bool isFunclet = (func->funKind != FUNC_ROOT); + DWORD unwindCodeBytes = 0; + + if (isHotCode || isFunclet) { #ifdef UNIX_AMD64_ABI if (generateCFIUnwindCodes()) @@ -717,9 +736,7 @@ void Compiler::unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode) } } - bool isFunclet = (func->funKind != FUNC_ROOT); - bool isColdCode = !isHotCode; - + const bool isColdCode = !isHotCode; eeReserveUnwindInfo(isFunclet, isColdCode, unwindCodeBytes); } @@ -779,7 +796,32 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo { endOffset = func->endLoc->CodeOffset(GetEmitter()); } + } + else + { + assert(fgFirstColdBlock != nullptr); + + if (func->coldStartLoc == nullptr) + { + startOffset = 0; + } + else + { + startOffset = func->coldStartLoc->CodeOffset(GetEmitter()); + } + + if (func->coldEndLoc == nullptr) + { + endOffset = info.compNativeCodeSize; + } + else + { + endOffset = func->coldEndLoc->CodeOffset(GetEmitter()); + } + } + if (isHotCode || (func->funKind != FUNC_ROOT)) + { #ifdef UNIX_AMD64_ABI if (generateCFIUnwindCodes()) { @@ -807,28 +849,6 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot]; } } - else - { - assert(fgFirstColdBlock != nullptr); - - if (func->coldStartLoc == nullptr) - { - startOffset = 0; - } - else - { - startOffset = func->coldStartLoc->CodeOffset(GetEmitter()); - } - - if (func->coldEndLoc == nullptr) - { - endOffset = info.compNativeCodeSize; - } - else - { - endOffset = func->coldEndLoc->CodeOffset(GetEmitter()); - } - } #ifdef DEBUG if (opts.dspUnwind) @@ -894,17 +914,34 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER); static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER); - unwindEmitFuncHelper(func, pHotCode, pColdCode, true); - - if (pColdCode != nullptr) - { #ifdef DEBUG - if (!JitConfig.JitFakeProcedureSplitting()) + // If fake-splitting, treat all unwind info as hot. + if (JitConfig.JitFakeProcedureSplitting()) + { + unwindEmitFuncHelper(func, pHotCode, pColdCode, true); + return; + } #endif // DEBUG + + if (func->funKind == FUNC_ROOT) + { + unwindEmitFuncHelper(func, pHotCode, pColdCode, true); + + // If the function's main body is split, reserve unwind info of size 0 for the cold section. + // If only funclets are cold, the main body is hot, so don't make a second call. + const bool isFunctionSplit = ((fgFirstColdBlock != nullptr) && (fgFirstColdBlock != fgFirstFuncletBB)); + if (isFunctionSplit) { unwindEmitFuncHelper(func, pHotCode, pColdCode, false); } } + else + { + // Make only one call for funclets. + // If function is split and has EH, the funclets will be cold. + const bool isFuncletHot = (fgFirstColdBlock == nullptr); + unwindEmitFuncHelper(func, pHotCode, pColdCode, isFuncletHot); + } } #endif // TARGET_AMD64