-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EH filters for generic catch(T) blocks #72721
Changes from 24 commits
8d9b3ef
7d4bcbd
39752c7
3a045da
fd57c28
f24208a
f7c55a7
861c6c3
8a72927
58d3b77
54763a7
a32b92a
3668e25
49635eb
f8a50a5
2a47ff9
bee1fb3
10ca969
79e87b8
5420035
9cf10d2
fd3130e
22f2520
9110e5f
d3c01cb
aaa075e
98ce006
5c7c157
40ca568
d13147d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2506,6 +2506,94 @@ bool Compiler::fgNormalizeEHCase2() | |
return modified; | ||
} | ||
|
||
//------------------------------------------------------------------------ | ||
// fgCreateFiltersForGenericExceptions: | ||
// For Exception types which require runtime lookup it creates a "fake" single-block | ||
// EH filter that performs "catchArg isinst T!!" and in case of success forwards to the | ||
// original EH handler. | ||
// | ||
|
||
void Compiler::fgCreateFiltersForGenericExceptions() | ||
{ | ||
for (unsigned ehNum = 0; ehNum < compHndBBtabCount; ehNum++) | ||
{ | ||
EHblkDsc* eh = ehGetDsc(ehNum); | ||
if (eh->ebdHandlerType == EH_HANDLER_CATCH) | ||
{ | ||
// Resolve Exception type and check if it needs a runtime lookup | ||
CORINFO_RESOLVED_TOKEN resolvedToken; | ||
resolvedToken.tokenContext = impTokenLookupContextHandle; | ||
resolvedToken.tokenScope = info.compScopeHnd; | ||
resolvedToken.token = eh->ebdTyp; | ||
resolvedToken.tokenType = CORINFO_TOKENKIND_Casting; | ||
info.compCompHnd->resolveToken(&resolvedToken); | ||
|
||
CORINFO_GENERICHANDLE_RESULT embedInfo; | ||
info.compCompHnd->embedGenericHandle(&resolvedToken, true, &embedInfo); | ||
if (!embedInfo.lookup.lookupKind.needsRuntimeLookup) | ||
{ | ||
// Exception type does not need runtime lookup | ||
continue; | ||
} | ||
|
||
// Create a new bb for the fake filter | ||
BasicBlock* filterBb = bbNewBasicBlock(BBJ_EHFILTERRET); | ||
BasicBlock* handlerBb = eh->ebdHndBeg; | ||
|
||
// Now we need to spill CATCH_ARG (it should be the first thing evaluated) | ||
GenTree* arg = new (this, GT_CATCH_ARG) GenTree(GT_CATCH_ARG, TYP_REF); | ||
arg->gtFlags |= GTF_ORDER_SIDEEFF; | ||
unsigned tempNum = lvaGrabTemp(false DEBUGARG("SpillCatchArg")); | ||
lvaTable[tempNum].lvType = TYP_REF; | ||
GenTree* argAsg = gtNewTempAssign(tempNum, arg); | ||
arg = gtNewLclvNode(tempNum, TYP_REF); | ||
filterBb->bbStkTempsIn = tempNum; | ||
fgInsertStmtAtBeg(filterBb, gtNewStmt(argAsg, handlerBb->firstStmt()->GetDebugInfo())); | ||
|
||
// Create "catchArg is TException" tree | ||
GenTree* runtimeLookup; | ||
if (embedInfo.lookup.runtimeLookup.indirections == CORINFO_USEHELPER) | ||
{ | ||
GenTree* ctxTree = getRuntimeContextTree(embedInfo.lookup.lookupKind.runtimeLookupKind); | ||
runtimeLookup = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, | ||
TYP_I_IMPL, &embedInfo.lookup.lookupKind, ctxTree); | ||
} | ||
else | ||
{ | ||
runtimeLookup = getTokenHandleTree(&resolvedToken, true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious if this is measurable for something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It turns out Xunit's Assert.Throws doesn't use generic "catch" blocks. Also, this PR actually improves perf 😮: static void Main(string[] args) =>
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
[Benchmark]
public void Test()
{
Throws<DivideByZeroException>(() =>
{
int b = 0;
int x = 100 / b;
});
}
static void Throws<T>(Action action) where T : Exception
{
try { action(); }
catch (T) { return; }
throw new Exception();
} by 5% |
||
} | ||
GenTree* isInstOfT = gtNewHelperCallNode(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, TYP_INT, runtimeLookup, arg); | ||
GenTree* retFilt = gtNewOperNode(GT_RETFILT, TYP_INT, isInstOfT); | ||
|
||
// Insert it right before the handler (and make it a pred of the handler) | ||
fgInsertBBbefore(handlerBb, filterBb); | ||
fgAddRefPred(handlerBb, filterBb); | ||
fgNewStmtAtEnd(filterBb, retFilt, handlerBb->firstStmt()->GetDebugInfo()); | ||
|
||
filterBb->bbCatchTyp = BBCT_FILTER; | ||
filterBb->bbCodeOffs = handlerBb->bbCodeOffs; | ||
filterBb->bbHndIndex = handlerBb->bbHndIndex; | ||
filterBb->bbTryIndex = handlerBb->bbTryIndex; | ||
filterBb->bbJumpDest = handlerBb; | ||
filterBb->bbSetRunRarely(); | ||
filterBb->bbFlags |= BBF_INTERNAL | BBF_DONT_REMOVE; | ||
|
||
handlerBb->bbCatchTyp = BBCT_FILTER_HANDLER; | ||
eh->ebdHandlerType = EH_HANDLER_FILTER; | ||
eh->ebdFilter = filterBb; | ||
|
||
#ifdef DEBUG | ||
if (verbose) | ||
{ | ||
JITDUMP("EH%d: Adding EH filter block " FMT_BB " in front of generic handler " FMT_BB ":\n", ehNum, | ||
filterBb->bbNum, handlerBb->bbNum); | ||
fgDumpBlock(filterBb); | ||
} | ||
#endif // DEBUG | ||
} | ||
} | ||
} | ||
|
||
bool Compiler::fgNormalizeEHCase3() | ||
{ | ||
bool modified = false; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit -- you don't need to set this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm.. I think I had to actually, let me see if CI is happy then