diff options
author | Pat Gavlin <pagavlin@microsoft.com> | 2016-05-03 12:58:16 -0700 |
---|---|---|
committer | Pat Gavlin <pagavlin@microsoft.com> | 2016-05-03 12:58:16 -0700 |
commit | 8f71b159a1edb4fbb187bcc95c6e20bc9e2ea4d8 (patch) | |
tree | 5d88aeed51400b36d38af662acff9ad60f3e2703 | |
parent | adce1932c1138b9e6b48592aa21b6729d4dedcc8 (diff) | |
download | coreclr-8f71b159a1edb4fbb187bcc95c6e20bc9e2ea4d8.tar.gz coreclr-8f71b159a1edb4fbb187bcc95c6e20bc9e2ea4d8.tar.bz2 coreclr-8f71b159a1edb4fbb187bcc95c6e20bc9e2ea4d8.zip |
Remove SEH interactions between the JIT and the EE.
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 #3058 and #4130.
[tfs-changeset: 1601288]
-rw-r--r-- | src/inc/corinfo.h | 21 | ||||
-rw-r--r-- | src/jit/compiler.h | 8 | ||||
-rw-r--r-- | src/jit/ee_il_dll.cpp | 44 | ||||
-rw-r--r-- | src/jit/error.cpp | 9 | ||||
-rw-r--r-- | src/jit/error.h | 12 | ||||
-rw-r--r-- | src/jit/flowgraph.cpp | 7 | ||||
-rw-r--r-- | src/jit/importer.cpp | 7 | ||||
-rw-r--r-- | src/vm/jitinterface.cpp | 75 | ||||
-rw-r--r-- | src/vm/jitinterface.h | 2 | ||||
-rw-r--r-- | src/zap/zapinfo.cpp | 5 | ||||
-rw-r--r-- | src/zap/zapinfo.h | 2 |
11 files changed, 160 insertions, 32 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index 8978b951a5..0eca760f38 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -231,11 +231,11 @@ TODO: Talk about initializing strutures before use #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 @@ -2723,6 +2723,17 @@ public: 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 diff --git a/src/jit/compiler.h b/src/jit/compiler.h index e1c0046575..818408a35d 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -6456,6 +6456,14 @@ public : 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) diff --git a/src/jit/ee_il_dll.cpp b/src/jit/ee_il_dll.cpp index 8193b1573b..004642e4a8 100644 --- a/src/jit/ee_il_dll.cpp +++ b/src/jit/ee_il_dll.cpp @@ -1227,6 +1227,45 @@ bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken) 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) @@ -1234,6 +1273,11 @@ 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 /***************************************************************************** diff --git a/src/jit/error.cpp b/src/jit/error.cpp index 91b4f7a056..a52f9e5836 100644 --- a/src/jit/error.cpp +++ b/src/jit/error.cpp @@ -197,15 +197,6 @@ void notYetImplemented(const char * msg, const char * filename, unsigned line) #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; diff --git a/src/jit/error.h b/src/jit/error.h index d883fb08c9..fa4ba0d636 100644 --- a/src/jit/error.h +++ b/src/jit/error.h @@ -21,8 +21,7 @@ struct ErrorTrapParam 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) \ @@ -37,20 +36,13 @@ extern LONG __JITfilter(PEXCEPTION_POINTERS pExceptionPointers, LPVO { \ 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 diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index a847091f51..2cfed2e23c 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -21922,7 +21922,7 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, 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); @@ -21988,8 +21988,8 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, } } } - } - impErrorTrap() + }, ¶m); + if (!success) { #ifdef DEBUG if (verbose) @@ -22006,7 +22006,6 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, inlineResult->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR); } } - endErrorTrap(); if (inlineResult->IsFailure()) { diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 7c24aa87e4..707f4fe417 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -15605,7 +15605,7 @@ void Compiler::impCheckCanInline(GenTreePtr call, param.result = inlineResult; param.ppInlineCandidateInfo = ppInlineCandidateInfo; - setErrorTrap(info.compCompHnd, Param *, pParam, ¶m) + bool success = eeRunWithErrorTrap<Param>([](Param* pParam) { DWORD dwRestrictions = 0; CorInfoInitClassResult initClassResult; @@ -15741,12 +15741,11 @@ void Compiler::impCheckCanInline(GenTreePtr call, _exit: ; - } - impErrorTrap() + }, ¶m); + if (!success) { param.result->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR); } - endErrorTrap(); } void Compiler::impInlineRecordArgInfo(InlineInfo * pInlineInfo, diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index 2cf2ab4838..8316f88c6f 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -10063,6 +10063,81 @@ DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes) } /*********************************************************************/ +#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 { diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h index e31a07d17b..ace9608f0e 100644 --- a/src/vm/jitinterface.h +++ b/src/vm/jitinterface.h @@ -1097,6 +1097,8 @@ public: 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. diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp index d9c984c93b..2a2760f76a 100644 --- a/src/zap/zapinfo.cpp +++ b/src/zap/zapinfo.cpp @@ -867,6 +867,11 @@ IEEMemoryManager* ZapInfo::getMemoryManager() { return GetEEMemoryManager(); } + +bool ZapInfo::runWithErrorTrap(void (*function)(void*), void* param) +{ + return m_pEEJitInfo->runWithErrorTrap(function, param); +} HRESULT ZapInfo::allocBBProfileBuffer ( ULONG cBlock, diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h index 7fc93820d2..b472d4870b 100644 --- a/src/zap/zapinfo.h +++ b/src/zap/zapinfo.h @@ -317,6 +317,8 @@ public: DWORD getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes); + bool runWithErrorTrap(void (*function)(void*), void* param); + // ICorDynamicInfo DWORD getThreadTLSIndex(void **ppIndirection); |