Remove SEH interactions between the JIT and the EE.
authorPat Gavlin <pagavlin@microsoft.com>
Tue, 3 May 2016 19:58:16 +0000 (12:58 -0700)
committerPat Gavlin <pagavlin@microsoft.com>
Tue, 3 May 2016 19:58:16 +0000 (12:58 -0700)
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

src/coreclr/src/inc/corinfo.h
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/ee_il_dll.cpp
src/coreclr/src/jit/error.cpp
src/coreclr/src/jit/error.h
src/coreclr/src/jit/flowgraph.cpp
src/coreclr/src/jit/importer.cpp
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/jitinterface.h
src/coreclr/src/zap/zapinfo.cpp
src/coreclr/src/zap/zapinfo.h

index 8978b95..0eca760 100644 (file)
@@ -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
index e1c0046..818408a 100644 (file)
@@ -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)
index 8193b15..004642e 100644 (file)
@@ -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
 
 /*****************************************************************************
index 91b4f7a..a52f9e5 100644 (file)
@@ -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;
index d883fb0..fa4ba0d 100644 (file)
@@ -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
index a847091..2cfed2e 100644 (file)
@@ -21922,7 +21922,7 @@ void       Compiler::fgInvokeInlineeCompiler(GenTreeCall*  call,
     param.fncHandle = fncHandle;
     param.inlineCandidateInfo = inlineCandidateInfo;
     param.inlineInfo = &inlineInfo;
-    setErrorTrap(info.compCompHnd, Param*, pParam, &param)
+    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()
+    }, &param);
+    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())
     {
index 7c24aa8..707f4fe 100644 (file)
@@ -15605,7 +15605,7 @@ void  Compiler::impCheckCanInline(GenTreePtr                call,
     param.result = inlineResult;
     param.ppInlineCandidateInfo = ppInlineCandidateInfo;
 
-    setErrorTrap(info.compCompHnd, Param *, pParam, &param)
+    bool success = eeRunWithErrorTrap<Param>([](Param* pParam)
     {
         DWORD  dwRestrictions = 0;
         CorInfoInitClassResult initClassResult;
@@ -15741,12 +15741,11 @@ void  Compiler::impCheckCanInline(GenTreePtr                call,
   
 _exit:
         ;
-    }
-    impErrorTrap()
+    }, &param);
+    if (!success)
     {
         param.result->NoteFatal(InlineObservation::CALLSITE_COMPILATION_ERROR);
     }
-    endErrorTrap();
 }
       
 void Compiler::impInlineRecordArgInfo(InlineInfo *  pInlineInfo,
index 2cf2ab4..8316f88 100644 (file)
@@ -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 {
index e31a07d..ace9608 100644 (file)
@@ -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.
index d9c984c..2a2760f 100644 (file)
@@ -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,
index 7fc9382..b472d48 100644 (file)
@@ -317,6 +317,8 @@ public:
 
     DWORD getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes);
 
+    bool runWithErrorTrap(void (*function)(void*), void* param);
+
     // ICorDynamicInfo
 
     DWORD getThreadTLSIndex(void **ppIndirection);