Skip to content

Commit 4cd3e78

Browse files
EgorBojkotas
andauthored
Add EH filters for generic catch(T) blocks (#72721)
Co-authored-by: Jan Kotas <[email protected]>
1 parent a01aea9 commit 4cd3e78

File tree

31 files changed

+389
-317
lines changed

31 files changed

+389
-317
lines changed

docs/design/coreclr/botr/readytorun-format.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ enum ReadyToRunHelper
797797
READYTORUN_HELPER_GenericGcTlsBase = 0x66,
798798
READYTORUN_HELPER_GenericNonGcTlsBase = 0x67,
799799
READYTORUN_HELPER_VirtualFuncPtr = 0x68,
800+
READYTORUN_HELPER_IsInstanceOfException = 0x69,
800801

801802
// Long mul/div/shift ops
802803
READYTORUN_HELPER_LMul = 0xC0,

src/coreclr/inc/corinfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ enum CorInfoHelpFunc
438438
CORINFO_HELP_CHKCASTCLASS_SPECIAL, // Optimized helper for classes. Assumes that the trivial cases
439439
// has been taken care of by the inlined check
440440

441+
CORINFO_HELP_ISINSTANCEOF_EXCEPTION,
442+
441443
CORINFO_HELP_BOX, // Fast box helper. Only possible exception is OutOfMemory
442444
CORINFO_HELP_BOX_NULLABLE, // special form of boxing for Nullable<T>
443445
CORINFO_HELP_UNBOX,

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

46-
constexpr GUID JITEEVersionIdentifier = { /* 0d853657-7a01-421f-b1b0-d22a8e691441 */
47-
0x0d853657,
48-
0x7a01,
49-
0x421f,
50-
{0xb1, 0xb0, 0xd2, 0x2a, 0x8e, 0x69, 0x14, 0x41}
46+
constexpr GUID JITEEVersionIdentifier = { /* 4efa8fe2-8489-4b61-aac9-b4df74af15b7 */
47+
0x4efa8fe2,
48+
0x8489,
49+
0x4b61,
50+
{0xaa, 0xc9, 0xb4, 0xdf, 0x74, 0xaf, 0x15, 0xb7}
5151
};
5252

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/inc/jithelpers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@
9999
DYNAMICJITHELPER(CORINFO_HELP_CHKCASTANY, NULL, CORINFO_HELP_SIG_REG_ONLY)
100100
DYNAMICJITHELPER(CORINFO_HELP_CHKCASTCLASS_SPECIAL, NULL, CORINFO_HELP_SIG_REG_ONLY)
101101

102+
JITHELPER(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, JIT_IsInstanceOfException, CORINFO_HELP_SIG_REG_ONLY)
103+
102104
DYNAMICJITHELPER(CORINFO_HELP_BOX, JIT_Box, CORINFO_HELP_SIG_REG_ONLY)
103105
JITHELPER(CORINFO_HELP_BOX_NULLABLE, JIT_Box, CORINFO_HELP_SIG_REG_ONLY)
104106
DYNAMICJITHELPER(CORINFO_HELP_UNBOX, NULL, CORINFO_HELP_SIG_REG_ONLY)

src/coreclr/inc/readytorun.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
1818
#define READYTORUN_MAJOR_VERSION 0x0007
19-
#define READYTORUN_MINOR_VERSION 0x0000
19+
#define READYTORUN_MINOR_VERSION 0x0001
2020

2121
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006
2222

@@ -329,6 +329,7 @@ enum ReadyToRunHelper
329329
READYTORUN_HELPER_GenericGcTlsBase = 0x66,
330330
READYTORUN_HELPER_GenericNonGcTlsBase = 0x67,
331331
READYTORUN_HELPER_VirtualFuncPtr = 0x68,
332+
READYTORUN_HELPER_IsInstanceOfException = 0x69,
332333

333334
// Long mul/div/shift ops
334335
READYTORUN_HELPER_LMul = 0xC0,

src/coreclr/inc/readytorunhelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ HELPER(READYTORUN_HELPER_GenericGcTlsBase, CORINFO_HELP_GETGENERICS_GCT
5454
HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,)
5555

5656
HELPER(READYTORUN_HELPER_VirtualFuncPtr, CORINFO_HELP_VIRTUAL_FUNC_PTR, )
57+
HELPER(READYTORUN_HELPER_IsInstanceOfException, CORINFO_HELP_ISINSTANCEOF_EXCEPTION, )
5758

5859
HELPER(READYTORUN_HELPER_LMul, CORINFO_HELP_LMUL, )
5960
HELPER(READYTORUN_HELPER_LMulOfv, CORINFO_HELP_LMUL_OVF, )

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,8 @@ class Compiler
22162216
bool fgNormalizeEHCase2();
22172217
bool fgNormalizeEHCase3();
22182218

2219+
void fgCreateFiltersForGenericExceptions();
2220+
22192221
void fgCheckForLoopsInHandlers();
22202222

22212223
#ifdef DEBUG

src/coreclr/jit/flowgraph.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,6 +2590,10 @@ void Compiler::fgAddInternal()
25902590
{
25912591
noway_assert(!compIsForInlining());
25922592

2593+
// For runtime determined Exception types we're going to emit a fake EH filter with isinst for this
2594+
// type with a runtime lookup
2595+
fgCreateFiltersForGenericExceptions();
2596+
25932597
// The backend requires a scratch BB into which it can safely insert a P/Invoke method prolog if one is
25942598
// required. Similarly, we need a scratch BB for poisoning. Create it here.
25952599
if (compMethodRequiresPInvokeFrame() || compShouldPoisonFrame())

src/coreclr/jit/jiteh.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,6 +2506,93 @@ bool Compiler::fgNormalizeEHCase2()
25062506
return modified;
25072507
}
25082508

2509+
//------------------------------------------------------------------------
2510+
// fgCreateFiltersForGenericExceptions:
2511+
// For Exception types which require runtime lookup it creates a "fake" single-block
2512+
// EH filter that performs "catchArg isinst T!!" and in case of success forwards to the
2513+
// original EH handler.
2514+
//
2515+
2516+
void Compiler::fgCreateFiltersForGenericExceptions()
2517+
{
2518+
for (unsigned ehNum = 0; ehNum < compHndBBtabCount; ehNum++)
2519+
{
2520+
EHblkDsc* eh = ehGetDsc(ehNum);
2521+
if (eh->ebdHandlerType == EH_HANDLER_CATCH)
2522+
{
2523+
// Resolve Exception type and check if it needs a runtime lookup
2524+
CORINFO_RESOLVED_TOKEN resolvedToken;
2525+
resolvedToken.tokenContext = impTokenLookupContextHandle;
2526+
resolvedToken.tokenScope = info.compScopeHnd;
2527+
resolvedToken.token = eh->ebdTyp;
2528+
resolvedToken.tokenType = CORINFO_TOKENKIND_Casting;
2529+
info.compCompHnd->resolveToken(&resolvedToken);
2530+
2531+
CORINFO_GENERICHANDLE_RESULT embedInfo;
2532+
info.compCompHnd->embedGenericHandle(&resolvedToken, true, &embedInfo);
2533+
if (!embedInfo.lookup.lookupKind.needsRuntimeLookup)
2534+
{
2535+
// Exception type does not need runtime lookup
2536+
continue;
2537+
}
2538+
2539+
// Create a new bb for the fake filter
2540+
BasicBlock* filterBb = bbNewBasicBlock(BBJ_EHFILTERRET);
2541+
BasicBlock* handlerBb = eh->ebdHndBeg;
2542+
2543+
// Now we need to spill CATCH_ARG (it should be the first thing evaluated)
2544+
GenTree* arg = new (this, GT_CATCH_ARG) GenTree(GT_CATCH_ARG, TYP_REF);
2545+
arg->gtFlags |= GTF_ORDER_SIDEEFF;
2546+
unsigned tempNum = lvaGrabTemp(false DEBUGARG("SpillCatchArg"));
2547+
lvaTable[tempNum].lvType = TYP_REF;
2548+
GenTree* argAsg = gtNewTempAssign(tempNum, arg);
2549+
arg = gtNewLclvNode(tempNum, TYP_REF);
2550+
fgInsertStmtAtBeg(filterBb, gtNewStmt(argAsg, handlerBb->firstStmt()->GetDebugInfo()));
2551+
2552+
// Create "catchArg is TException" tree
2553+
GenTree* runtimeLookup;
2554+
if (embedInfo.lookup.runtimeLookup.indirections == CORINFO_USEHELPER)
2555+
{
2556+
GenTree* ctxTree = getRuntimeContextTree(embedInfo.lookup.lookupKind.runtimeLookupKind);
2557+
runtimeLookup = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE,
2558+
TYP_I_IMPL, &embedInfo.lookup.lookupKind, ctxTree);
2559+
}
2560+
else
2561+
{
2562+
runtimeLookup = getTokenHandleTree(&resolvedToken, true);
2563+
}
2564+
GenTree* isInstOfT = gtNewHelperCallNode(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, TYP_INT, runtimeLookup, arg);
2565+
GenTree* retFilt = gtNewOperNode(GT_RETFILT, TYP_INT, isInstOfT);
2566+
2567+
// Insert it right before the handler (and make it a pred of the handler)
2568+
fgInsertBBbefore(handlerBb, filterBb);
2569+
fgAddRefPred(handlerBb, filterBb);
2570+
fgNewStmtAtEnd(filterBb, retFilt, handlerBb->firstStmt()->GetDebugInfo());
2571+
2572+
filterBb->bbCatchTyp = BBCT_FILTER;
2573+
filterBb->bbCodeOffs = handlerBb->bbCodeOffs;
2574+
filterBb->bbHndIndex = handlerBb->bbHndIndex;
2575+
filterBb->bbTryIndex = handlerBb->bbTryIndex;
2576+
filterBb->bbJumpDest = handlerBb;
2577+
filterBb->bbSetRunRarely();
2578+
filterBb->bbFlags |= BBF_INTERNAL | BBF_DONT_REMOVE;
2579+
2580+
handlerBb->bbCatchTyp = BBCT_FILTER_HANDLER;
2581+
eh->ebdHandlerType = EH_HANDLER_FILTER;
2582+
eh->ebdFilter = filterBb;
2583+
2584+
#ifdef DEBUG
2585+
if (verbose)
2586+
{
2587+
JITDUMP("EH%d: Adding EH filter block " FMT_BB " in front of generic handler " FMT_BB ":\n", ehNum,
2588+
filterBb->bbNum, handlerBb->bbNum);
2589+
fgDumpBlock(filterBb);
2590+
}
2591+
#endif // DEBUG
2592+
}
2593+
}
2594+
}
2595+
25092596
bool Compiler::fgNormalizeEHCase3()
25102597
{
25112598
bool modified = false;

src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ private static bool ShouldTypedClauseCatchThisException(object exception, Method
847847
AssertNotRuntimeObject(pClauseType);
848848
#endif
849849

850-
return TypeCast.IsInstanceOfClass(pClauseType, exception) != null;
850+
return TypeCast.IsInstanceOfException(pClauseType, exception);
851851
}
852852

853853
private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart)

0 commit comments

Comments
 (0)