Skip to content

Commit dfa252e

Browse files
AndyAyersMSCopilot
authored andcommitted
[Wasm RyuJit]: don't skip top-level catchrets when marking try resumption (dotnet#129205)
In FlowGraphTryRegions::Build, the BBJ_EHCATCHRET check sat below the early bailout on hasTryIndex, so the catchret of an outer catch was never marking its try region as requiring runtime resumption. Also: ensure loops that partially contain trys have their wasm-interval lengths extended to encompass any throw helpers associated with the try. Also: fix some random extra argument added to a the overflow helper in some cases. This is all platform and has been in the code forever. On native it is somewhat harmless to pass unexpected extra args (especially if register args). On Wasm it is not. Reminder that for Wasm control flow we can always move the end of a Wasm loop later; the extent just delineates where you can branch back to the loop head, not the actual extent of the loop. Likewise we can always move the start of a block earlier. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 823cbf0 commit dfa252e

3 files changed

Lines changed: 85 additions & 15 deletions

File tree

src/coreclr/jit/fgwasm.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,8 +1300,38 @@ PhaseStatus Compiler::fgWasmControlFlow()
13001300
// We may have increased the loop extent (moved the end) to accommodate try regions
13011301
// that begin in the loop but can end outside. Find the last such block...
13021302
//
1303-
loop->VisitLoopBlocksPostOrder([&](BasicBlock* block) {
1303+
AddCodeDscMap* const acdMap = fgGetAddCodeDscMap();
1304+
1305+
loop->VisitLoopBlocksPostOrder([&, this](BasicBlock* block) {
13041306
endCursor = max(endCursor, block->bbPreorderNum + 1);
1307+
1308+
// If this loop block is the header of a try region that requires runtime
1309+
// resumption, also account for the throw-helper blocks of that try region.
1310+
// Those blocks form the try interval's end-block (per VisitWasmSuccs they
1311+
// are sequenced after the region's true successors), and the try interval
1312+
// must perfectly nest inside this loop interval.
1313+
//
1314+
FlowGraphTryRegion* const innerTry = tryRegions->GetTryRegionByHeader(block);
1315+
if ((acdMap != nullptr) && (innerTry != nullptr) && innerTry->RequiresRuntimeResumption())
1316+
{
1317+
AcdKeyDesignator dsg;
1318+
const unsigned blockData = bbThrowIndex(block, &dsg);
1319+
for (const AddCodeDscKey& key : AddCodeDscMap::KeyIteration(acdMap))
1320+
{
1321+
if (key.Data() != blockData)
1322+
{
1323+
continue;
1324+
}
1325+
1326+
AddCodeDsc* acd = nullptr;
1327+
acdMap->Lookup(key, &acd);
1328+
1329+
if (acd->acdUsed && (acd->acdDstBlk != nullptr))
1330+
{
1331+
endCursor = max(endCursor, acd->acdDstBlk->bbPreorderNum + 1);
1332+
}
1333+
}
1334+
}
13051335
return BasicBlockVisit::Continue;
13061336
});
13071337

@@ -1411,6 +1441,46 @@ PhaseStatus Compiler::fgWasmControlFlow()
14111441
}
14121442
JITDUMP("--------------\n\n");
14131443
}
1444+
1445+
// Verify that try intervals perfectly nest with respect to loop intervals
1446+
// (either disjoint or one fully contains the other). If a try overlapped a
1447+
// loop, later conflict resolution would widen the try's start back past the
1448+
// loop header, leaving codegen unable to find GT_WASM_JEXCEPT at the try's
1449+
// start block.
1450+
//
1451+
for (WasmInterval* const tryI : *fgWasmIntervals)
1452+
{
1453+
if (!tryI->IsTry())
1454+
{
1455+
continue;
1456+
}
1457+
1458+
for (WasmInterval* const loopI : *fgWasmIntervals)
1459+
{
1460+
if (!loopI->IsLoop())
1461+
{
1462+
continue;
1463+
}
1464+
1465+
const unsigned ts = tryI->Start();
1466+
const unsigned te = tryI->End();
1467+
const unsigned ls = loopI->Start();
1468+
const unsigned le = loopI->End();
1469+
1470+
const bool disjoint = (te <= ls) || (le <= ts);
1471+
const bool loopContains = (ls <= ts) && (te <= le);
1472+
const bool tryContains = (ts <= ls) && (le <= te);
1473+
1474+
if (!(disjoint || loopContains || tryContains))
1475+
{
1476+
JITDUMP("Try interval ");
1477+
JITDUMPEXEC(tryI->Dump());
1478+
JITDUMP(" overlaps loop interval ");
1479+
JITDUMPEXEC(loopI->Dump());
1480+
assert(!"Try and loop intervals must perfectly nest");
1481+
}
1482+
}
1483+
}
14141484
#endif
14151485

14161486
// -----------------------------------------------

src/coreclr/jit/flowgraph.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7744,6 +7744,19 @@ FlowGraphTryRegions* FlowGraphTryRegions::Build(Compiler* comp, FlowGraphDfsTree
77447744

77457745
for (BasicBlock* block : comp->Blocks())
77467746
{
7747+
// If this block is a BBJ_EHCATCHRET, mark the "dispatching try" region
7748+
// as requiring runtime resumption.
7749+
//
7750+
if (block->KindIs(BBJ_EHCATCHRET))
7751+
{
7752+
assert(block->hasHndIndex());
7753+
unsigned const ehRegionIndex = block->getHndIndex();
7754+
BasicBlock* const dispatchingTryBlock = comp->ehGetDsc(ehRegionIndex)->ebdTryBeg;
7755+
FlowGraphTryRegion* const dispatchingTryRegion = regions->GetTryRegionByHeader(dispatchingTryBlock);
7756+
7757+
dispatchingTryRegion->SetRequiresRuntimeResumption();
7758+
}
7759+
77477760
if (!block->hasTryIndex())
77487761
{
77497762
continue;
@@ -7825,19 +7838,6 @@ FlowGraphTryRegions* FlowGraphTryRegions::Build(Compiler* comp, FlowGraphDfsTree
78257838
// This is a handler block inside a try.
78267839
// For flow purposes we may consider it to be outside the try.
78277840
}
7828-
7829-
// If this block is a BBJ_EHCATCHRET, mark the "dispatching try" region
7830-
// as requiring runtime resumption.
7831-
//
7832-
if (block->KindIs(BBJ_EHCATCHRET))
7833-
{
7834-
assert(block->hasHndIndex());
7835-
unsigned const ehRegionIndex = block->getHndIndex();
7836-
BasicBlock* const dispatchingTryBlock = comp->ehGetDsc(ehRegionIndex)->ebdTryBeg;
7837-
FlowGraphTryRegion* const dispatchingTryRegion = regions->GetTryRegionByHeader(dispatchingTryBlock);
7838-
7839-
dispatchingTryRegion->SetRequiresRuntimeResumption();
7840-
}
78417841
}
78427842

78437843
return regions;

src/coreclr/jit/gentree.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18366,7 +18366,7 @@ GenTree* Compiler::gtFoldExprForOverflow(GenTree* tree)
1836618366
// We will change the cast to a GT_COMMA and attach the exception helper as AsOp()->gtOp1.
1836718367
// The constant expression zero becomes op2.
1836818368

18369-
GenTree* op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID, gtNewIconNode(compCurBB->bbTryIndex));
18369+
GenTree* op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID);
1837018370
GenTree* op2 = gtNewZeroConNode(type);
1837118371

1837218372
// op1 is a call to the JIT helper that throws an Overflow exception.

0 commit comments

Comments
 (0)