This change replaces the final uses of SEH between the JIT and the EE with a new method
on ICorJitInfo, `ICorJitInfo::runWithErrorTrap`. This method runs a given function under an
error trap that prevents recoverable errors from propagating out of the call. This allows
the JIT to make calls to JIT/EE interface functions that may throw exceptions without
needing to be aware of the EH ABI, exception types, etc. The method returns true if the
given function completed successfully and false otherwise. This change deprecates
all other SEH-related functionality on the JIT/EE interface (e.g. `ICJI::FilterException` and
`ICJI::HandleException`).
This change does not completely eliminate SEH over the JIT/EE interface: there are still a
handful of places where the JIT expects to be able to catch exceptions thrown by
SuperPMI. These uses of SEH will be removed later on.
Fixes dotnet/coreclr#3058 and dotnet/coreclr#4130.
[tfs-changeset: 1601288]
Commit migrated from https://github.com/dotnet/coreclr/commit/
8f71b159a1edb4fbb187bcc95c6e20bc9e2ea4d8
#if COR_JIT_EE_VERSION > 460
// Update this one
-SELECTANY const GUID JITEEVersionIdentifier = { /* 8c8e61ca-2b88-4bc5-b03f-d390acdc7fc3 */
- 0x8c8e61ca,
- 0x2b88,
- 0x4bc5,
- { 0xb0, 0x3f, 0xd3, 0x90, 0xac, 0xdc, 0x7f, 0xc3 }
+SELECTANY const GUID JITEEVersionIdentifier = { /* 57813506-0058-41df-8b1b-e0b68c3a9da3 */
+ 0x57813506,
+ 0x58,
+ 0x41df,
+ { 0x8b, 0x1b, 0xe0, 0xb6, 0x8c, 0x3a, 0x9d, 0xa3 }
};
#else
virtual void ThrowExceptionForHelper(
const CORINFO_HELPER_DESC * throwHelper) = 0;
+#if COR_JIT_EE_VERSION > 460
+ // Runs the given function under an error trap. This allows the JIT to make calls
+ // to interface functions that may throw exceptions without needing to be aware of
+ // the EH ABI, exception types, etc. Returns true if the given function completed
+ // successfully and false otherwise.
+ virtual bool runWithErrorTrap(
+ void (*function)(void*), // The function to run
+ void* parameter // The context parameter that will be passed to the function and the handler
+ ) = 0;
+#endif
+
/*****************************************************************************
* ICorStaticInfo contains EE interface methods which return values that are
* constant from invocation to invocation. Thus they may be embedded in
bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
+ template<typename ParamType>
+ bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
+ {
+ return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
+ }
+
+ bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
+
// Utility functions
#if defined(DEBUG)
return param.m_success;
}
+struct TrapParam
+{
+ ICorJitInfo* m_corInfo;
+ EXCEPTION_POINTERS m_exceptionPointers;
+
+ void (*m_function)(void*);
+ void* m_param;
+ bool m_success;
+};
+
+static LONG __EEFilter(PEXCEPTION_POINTERS exceptionPointers, void* param)
+{
+ auto* trapParam = reinterpret_cast<TrapParam*>(param);
+ trapParam->m_exceptionPointers = *exceptionPointers;
+ return trapParam->m_corInfo->FilterException(exceptionPointers);
+}
+
+bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
+{
+ TrapParam trapParam;
+ trapParam.m_corInfo = info.compCompHnd;
+ trapParam.m_function = function;
+ trapParam.m_param = param;
+ trapParam.m_success = true;
+
+ PAL_TRY(TrapParam*, __trapParam, &trapParam)
+ {
+ __trapParam->m_function(__trapParam->m_param);
+ }
+ PAL_EXCEPT_FILTER(__EEFilter)
+ {
+ trapParam.m_corInfo->HandleException(&trapParam.m_exceptionPointers);
+ trapParam.m_success = false;
+ }
+ PAL_ENDTRY
+
+ return trapParam.m_success;
+}
+
#else // CORJIT_EE_VER <= 460
bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
return info.compCompHnd->tryResolveToken(resolvedToken);
}
+bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
+{
+ return info.compCompHnd->runWithErrorTrap(function, param);
+}
+
#endif // CORJIT_EE_VER > 460
/*****************************************************************************
#endif // #if !defined(_TARGET_X86_) || !defined(LEGACY_BACKEND)
/*****************************************************************************/
-LONG __EEfilter(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
-{
- ErrorTrapParam *pErrorTrapParam = (ErrorTrapParam *)lpvParam;
- ICorJitInfo * m_jitInfo = pErrorTrapParam->jitInfo;
- pErrorTrapParam->exceptionPointers = *pExceptionPointers;
- return m_jitInfo->FilterException(pExceptionPointers);
-}
-
-/*****************************************************************************/
LONG __JITfilter(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
{
DWORD exceptCode = pExceptionPointers->ExceptionRecord->ExceptionCode;
ErrorTrapParam() { jitInfo = NULL; }
};
-extern LONG __EEfilter(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam);
- // Only catch JIT internal errors (will not catch EE generated Errors)
+// Only catch JIT internal errors (will not catch EE generated Errors)
extern LONG __JITfilter(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam);
#define setErrorTrap(compHnd, ParamType, paramDef, paramRef) \
{ \
ParamType paramDef = __JITpParam->param;
- // Catch only JitGeneratedErrors
+// Only catch JIT internal errors (will not catch EE generated Errors)
#define impJitErrorTrap() \
} \
PAL_EXCEPT_FILTER(__JITfilter) \
{ \
int __errc = __JITparam.errc; (void) __errc;
- // Catch all errors (including recoverable ones from the EE)
-#define impErrorTrap() \
- } \
- PAL_EXCEPT_FILTER(__EEfilter) \
- { \
- __JITparam.jitInfo->HandleException(&__JITparam.exceptionPointers);
-
#define endErrorTrap() \
} \
PAL_ENDTRY
param.fncHandle = fncHandle;
param.inlineCandidateInfo = inlineCandidateInfo;
param.inlineInfo = &inlineInfo;
- setErrorTrap(info.compCompHnd, Param*, pParam, ¶m)
+ bool success = eeRunWithErrorTrap<Param>([](Param* pParam)
{
// Init the local var info of the inlinee
pParam->pThis->impInlineInitVars(pParam->inlineInfo);
}
}
}
- }
- impErrorTrap()
+ }, ¶m);
+ if (!success)
{
#ifdef DEBUG
if (verbose)
inlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR);
}
}
- endErrorTrap();
if (inlineResult->IsFailure())
{
param.result = inlineResult;
param.ppInlineCandidateInfo = ppInlineCandidateInfo;
- setErrorTrap(info.compCompHnd, Param *, pParam, ¶m)
+ bool success = eeRunWithErrorTrap<Param>([](Param* pParam)
{
DWORD dwRestrictions = 0;
CorInfoInitClassResult initClassResult;
_exit:
;
- }
- impErrorTrap()
+ }, ¶m);
+ if (!success)
{
param.result->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR);
}
- endErrorTrap();
}
void Compiler::impInlineRecordArgInfo(InlineInfo * pInlineInfo,
}
/*********************************************************************/
+#if !defined(PLATFORM_UNIX)
+
+struct RunWithErrorTrapFilterParam
+{
+ ICorDynamicInfo* m_corInfo;
+ void (*m_function)(void*);
+ void* m_param;
+ EXCEPTION_POINTERS m_exceptionPointers;
+};
+
+static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
+{
+ WRAPPER_NO_CONTRACT;
+
+ auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
+ param->m_exceptionPointers = *exceptionPointers;
+ return param->m_corInfo->FilterException(exceptionPointers);
+}
+
+#endif // !defined(PLATFORM_UNIX)
+
+bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
+{
+ // No dynamic contract here because SEH is used
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_SO_INTOLERANT;
+ STATIC_CONTRACT_MODE_PREEMPTIVE;
+
+ // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
+ // transitions into the EE proper should occur either via the call to
+ // `EEFilterException` (which is appropraitely marked) or via JIT/EE
+ // interface calls made by `function`.
+
+ bool success = true;
+
+#if !defined(PLATFORM_UNIX)
+
+ RunWithErrorTrapFilterParam trapParam;
+ trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
+ trapParam.m_function = function;
+ trapParam.m_param = param;
+
+ PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
+ {
+ pTrapParam->m_function(pTrapParam->m_param);
+ }
+ PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
+ {
+ HandleException(&trapParam.m_exceptionPointers);
+ success = false;
+ }
+ PAL_ENDTRY
+
+#else // !defined(PLATFORM_UNIX)
+
+ // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
+ // ought to originate from the runtime itself and should be catchable inside of
+ // EX_TRY/EX_CATCH, including emulated SEH exceptions.
+ EX_TRY
+ {
+ function(param);
+ }
+ EX_CATCH
+ {
+ success = false;
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+
+#endif
+
+ return success;
+}
+
+/*********************************************************************/
IEEMemoryManager* CEEInfo::getMemoryManager()
{
CONTRACTL {
DWORD getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes);
+ bool runWithErrorTrap(void (*function)(void*), void* param);
+
private:
// Shrinking these buffers drastically reduces the amount of stack space
// required for each instance of the interpreter, and thereby reduces SOs.
{
return GetEEMemoryManager();
}
+
+bool ZapInfo::runWithErrorTrap(void (*function)(void*), void* param)
+{
+ return m_pEEJitInfo->runWithErrorTrap(function, param);
+}
HRESULT ZapInfo::allocBBProfileBuffer (
ULONG cBlock,
DWORD getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes);
+ bool runWithErrorTrap(void (*function)(void*), void* param);
+
// ICorDynamicInfo
DWORD getThreadTLSIndex(void **ppIndirection);