Skip to content

Commit f7e7d27

Browse files
authored
Unify SEH wrapping for method calls in the interpexec.cpp (#121311)
This change adds a way to wrap any method call in a SEH exception try / catch. Until now, we were adding a new function for each case that needed this wrapping. I've verified that the generated code in the release build is the same as before this change.
1 parent 8c78b43 commit f7e7d27

File tree

1 file changed

+49
-71
lines changed

1 file changed

+49
-71
lines changed

src/coreclr/vm/interpexec.cpp

Lines changed: 49 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
// for numeric_limits
1414
#include <limits>
15+
#include <functional>
1516

1617
#ifdef TARGET_WASM
1718
// Unused on WASM
@@ -37,6 +38,36 @@ LONG IgnoreCppExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pv)
3738
: EXCEPTION_EXECUTE_HANDLER;
3839
}
3940

41+
template<typename Function>
42+
std::invoke_result_t<Function> CallWithSEHWrapper(Function function)
43+
{
44+
struct Local
45+
{
46+
Function function;
47+
std::invoke_result_t<Function> result;
48+
} local { function };
49+
50+
PAL_TRY(Local *, pParam, &local)
51+
{
52+
pParam->result = pParam->function();
53+
}
54+
PAL_EXCEPT_FILTER(IgnoreCppExceptionFilter)
55+
{
56+
// There can be both C++ (thrown by the COMPlusThrow) and managed exceptions thrown
57+
// from the called method's call chain.
58+
// We need to process only managed ones here, the C++ ones are handled by the
59+
// INSTALL_/UNINSTALL_UNWIND_AND_CONTINUE_HANDLER in the InterpExecMethod.
60+
// The managed ones are represented by SEH exception, which cannot be handled there
61+
// because it is not possible to handle both SEH and C++ exceptions in the same frame.
62+
GCX_COOP_NO_DTOR();
63+
OBJECTREF ohThrowable = GetThread()->LastThrownObject();
64+
DispatchManagedException(ohThrowable);
65+
}
66+
PAL_ENDTRY
67+
68+
return local.result;
69+
}
70+
4071
// Use the NOINLINE to ensure that the InlinedCallFrame in this method is a lower stack address than any InterpMethodContextFrame values.
4172
NOINLINE
4273
void InvokeUnmanagedMethodWithTransition(MethodDesc *targetMethod, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet, PCODE callTarget)
@@ -699,74 +730,6 @@ void* DoGenericLookup(void* genericVarAsPtr, InterpGenericLookup* pLookup)
699730
return result;
700731
}
701732

702-
// Wrapper around MethodDesc::DoPrestub to handle possible managed exceptions thrown by it.
703-
static void CallPreStub(MethodDesc *pMD)
704-
{
705-
STATIC_STANDARD_VM_CONTRACT;
706-
_ASSERTE(pMD != NULL);
707-
708-
if (!pMD->ShouldCallPrestub())
709-
return;
710-
711-
struct Param
712-
{
713-
MethodDesc *pMethodDesc;
714-
}
715-
param = { pMD };
716-
717-
PAL_TRY(Param *, pParam, &param)
718-
{
719-
(void)pParam->pMethodDesc->DoPrestub(NULL /* MethodTable */, CallerGCMode::Coop);
720-
}
721-
PAL_EXCEPT_FILTER(IgnoreCppExceptionFilter)
722-
{
723-
// There can be both C++ (thrown by the COMPlusThrow) and managed exceptions thrown
724-
// from the PrepareInitialCode call chain.
725-
// We need to process only managed ones here, the C++ ones are handled by the
726-
// INSTALL_/UNINSTALL_UNWIND_AND_CONTINUE_HANDLER in the InterpExecMethod.
727-
// The managed ones are represented by SEH exception, which cannot be handled there
728-
// because it is not possible to handle both SEH and C++ exceptions in the same frame.
729-
GCX_COOP_NO_DTOR();
730-
OBJECTREF ohThrowable = GetThread()->LastThrownObject();
731-
DispatchManagedException(ohThrowable);
732-
}
733-
PAL_ENDTRY
734-
}
735-
736-
MethodDesc* CallGetMethodDescOfVirtualizedCode(MethodDesc *pMD, OBJECTREF *orThis)
737-
{
738-
STATIC_STANDARD_VM_CONTRACT;
739-
_ASSERTE(pMD != NULL);
740-
741-
struct Param
742-
{
743-
MethodDesc *pMD;
744-
OBJECTREF *orThis;
745-
MethodDesc *pRetMD;
746-
}
747-
param = { pMD, orThis, NULL };
748-
749-
PAL_TRY(Param *, pParam, &param)
750-
{
751-
pParam->pRetMD = pParam->pMD->GetMethodDescOfVirtualizedCode(pParam->orThis, pParam->pMD->GetMethodTable());
752-
}
753-
PAL_EXCEPT_FILTER(IgnoreCppExceptionFilter)
754-
{
755-
// There can be both C++ (thrown by the COMPlusThrow) and managed exceptions thrown
756-
// from the GetMethodDescOfVirtualizedCode call chain.
757-
// We need to process only managed ones here, the C++ ones are handled by the
758-
// INSTALL_/UNINSTALL_UNWIND_AND_CONTINUE_HANDLER in the InterpExecMethod.
759-
// The managed ones are represented by SEH exception, which cannot be handled there
760-
// because it is not possible to handle both SEH and C++ exceptions in the same frame.
761-
GCX_COOP_NO_DTOR();
762-
OBJECTREF ohThrowable = GetThread()->LastThrownObject();
763-
DispatchManagedException(ohThrowable);
764-
}
765-
PAL_ENDTRY
766-
767-
return param.pRetMD;
768-
}
769-
770733
void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFrame *pFrame, InterpThreadContext *pThreadContext, ExceptionClauseArgs *pExceptionClauseArgs)
771734
{
772735
CONTRACTL
@@ -2460,7 +2423,11 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
24602423
// Interpreter-TODO
24612424
// This needs to be optimized, not operating at MethodDesc level, rather with ftnptr
24622425
// slots containing the interpreter IR pointer
2463-
targetMethod = CallGetMethodDescOfVirtualizedCode(pMD, pThisArg);
2426+
targetMethod = CallWithSEHWrapper(
2427+
[&pMD, &pThisArg]() {
2428+
return pMD->GetMethodDescOfVirtualizedCode(pThisArg, pMD->GetMethodTable());
2429+
});
2430+
24642431
ip += 4;
24652432
goto CALL_INTERP_METHOD;
24662433
}
@@ -2601,7 +2568,11 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
26012568
if (isOpenVirtual)
26022569
{
26032570
targetMethod = COMDelegate::GetMethodDescForOpenVirtualDelegate(*delegateObj);
2604-
targetMethod = CallGetMethodDescOfVirtualizedCode(targetMethod, LOCAL_VAR_ADDR(callArgsOffset + INTERP_STACK_SLOT_SIZE, OBJECTREF));
2571+
targetMethod = CallWithSEHWrapper(
2572+
[&targetMethod, &callArgsOffset, &stack]() {
2573+
return targetMethod->GetMethodDescOfVirtualizedCode(LOCAL_VAR_ADDR(callArgsOffset + INTERP_STACK_SLOT_SIZE, OBJECTREF), targetMethod->GetMethodTable());
2574+
});
2575+
26052576
}
26062577
else
26072578
{
@@ -2709,7 +2680,14 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
27092680
// small subset of frames high.
27102681
pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame);
27112682
GCX_PREEMP();
2712-
CallPreStub(targetMethod);
2683+
2684+
if (targetMethod->ShouldCallPrestub())
2685+
{
2686+
CallWithSEHWrapper(
2687+
[&targetMethod]() {
2688+
return targetMethod->DoPrestub(nullptr, CallerGCMode::Coop);
2689+
});
2690+
}
27132691

27142692
targetIp = targetMethod->GetInterpreterCode();
27152693
if (targetIp == NULL)

0 commit comments

Comments
 (0)