@@ -1948,6 +1948,9 @@ typedef BOOL(WINAPI* PINITIALIZECONTEXT2)(PVOID Buffer, DWORD ContextFlags, PCON
19481948PINITIALIZECONTEXT2 pfnInitializeContext2 = NULL ;
19491949
19501950#ifdef TARGET_X86
1951+ typedef VOID (__cdecl* PRTLRESTORECONTEXT )(PCONTEXT ContextRecord, struct _EXCEPTION_RECORD * ExceptionRecord);
1952+ PRTLRESTORECONTEXT pfnRtlRestoreContext = NULL ;
1953+
19511954#define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_FLOATING_POINT | \
19521955 CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST )
19531956#else
@@ -1967,6 +1970,14 @@ CONTEXT* AllocateOSContextHelper(BYTE** contextBuffer)
19671970 pfnInitializeContext2 = (PINITIALIZECONTEXT2 )GetProcAddress (hm, " InitializeContext2" );
19681971 }
19691972
1973+ #ifdef TARGET_X86
1974+ if (pfnRtlRestoreContext == NULL )
1975+ {
1976+ HMODULE hm = GetModuleHandleW (_T (" ntdll.dll" ));
1977+ pfnRtlRestoreContext = (PRTLRESTORECONTEXT )GetProcAddress (hm, " RtlRestoreContext" );
1978+ }
1979+ #endif // TARGET_X86
1980+
19701981 // Determine if the processor supports AVX so we could
19711982 // retrieve extended registers
19721983 DWORD64 FeatureMask = GetEnabledXStateFeatures ();
@@ -2515,18 +2526,18 @@ void RedirectedThreadFrame::ExceptionUnwind()
25152526int RedirectedHandledJITCaseExceptionFilter (
25162527 PEXCEPTION_POINTERS pExcepPtrs, // Exception data
25172528 RedirectedThreadFrame *pFrame, // Frame on stack
2518- BOOL fDone , // Whether redirect completed without exception
2519- CONTEXT *pCtx ) // Saved context
2529+ CONTEXT *pCtx , // Saved context
2530+ DWORD dwLastError ) // saved last error
25202531{
25212532 // !!! Do not use a non-static contract here.
25222533 // !!! Contract may insert an exception handling record.
25232534 // !!! This function assumes that GetCurrentSEHRecord() returns the exception record set up in
2524- // !!! Thread::RedirectedHandledJITCase
2535+ // !!! Thread::RestoreContextSimulated
25252536 //
25262537 // !!! Do not use an object with dtor, since it injects a fs:0 entry.
25272538 STATIC_CONTRACT_NOTHROW ;
25282539 STATIC_CONTRACT_GC_TRIGGERS ;
2529- STATIC_CONTRACT_MODE_ANY ;
2540+ STATIC_CONTRACT_MODE_COOPERATIVE ;
25302541
25312542 if (pExcepPtrs->ExceptionRecord ->ExceptionCode == STATUS_STACK_OVERFLOW )
25322543 {
@@ -2535,48 +2546,18 @@ int RedirectedHandledJITCaseExceptionFilter(
25352546
25362547 // Get the thread handle
25372548 Thread *pThread = GetThread ();
2538-
2539- STRESS_LOG2 (LF_SYNC , LL_INFO100 , " In RedirectedHandledJITCaseExceptionFilter fDone = %d pFrame = %p\n " , fDone , pFrame);
2540-
2541- // If we get here via COM+ exception, gc-mode is unknown. We need it to
2542- // be cooperative for this function.
2543- GCX_COOP_NO_DTOR ();
2544-
2545- // If the exception was due to the called client, then we need to figure out if it
2546- // is an exception that can be eaten or if it needs to be handled elsewhere.
2547- if (!fDone )
2548- {
2549- if (pExcepPtrs->ExceptionRecord ->ExceptionFlags & EXCEPTION_NONCONTINUABLE )
2550- {
2551- return (EXCEPTION_CONTINUE_SEARCH );
2552- }
2553-
2554- // Get the latest thrown object
2555- OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord (pExcepPtrs->ExceptionRecord );
2556-
2557- // If this is an uncatchable exception, then let the exception be handled elsewhere
2558- if (IsUncatchable (&throwable))
2559- {
2560- pThread->EnablePreemptiveGC ();
2561- return (EXCEPTION_CONTINUE_SEARCH );
2562- }
2563- }
2564- #ifdef _DEBUG
2565- else
2566- {
2567- _ASSERTE (pExcepPtrs->ExceptionRecord ->ExceptionCode == EXCEPTION_HIJACK );
2568- }
2569- #endif
2549+ STRESS_LOG1 (LF_SYNC , LL_INFO100 , " In RedirectedHandledJITCaseExceptionFilter pFrame = %p\n " , pFrame);
2550+ _ASSERTE (pExcepPtrs->ExceptionRecord ->ExceptionCode == EXCEPTION_HIJACK );
25702551
25712552 // Unlink the frame in preparation for resuming in managed code
25722553 pFrame->Pop ();
25732554
2574- // Copy the saved context record into the EH context;
2575- // NB: cannot use ReplaceExceptionContextRecord here .
2576- // these contexts may contain extended registers and may have different format
2577- // for reasons such as alignment or context compaction
2555+ // Copy everything in the saved context record into the EH context.
2556+ // Historically the EH context has enough space for every enabled context feature .
2557+ // That may not hold for the future features beyond AVX, but this codepath is
2558+ // supposed to be used only on OSes that do not have RtlRestoreContext.
25782559 CONTEXT * pTarget = pExcepPtrs->ContextRecord ;
2579- if (!CopyContext (pTarget, pTarget ->ContextFlags , pCtx))
2560+ if (!CopyContext (pTarget, pCtx ->ContextFlags , pCtx))
25802561 {
25812562 STRESS_LOG1 (LF_SYNC , LL_ERROR , " ERROR: Could not set context record, lastError = 0x%x\n " , GetLastError ());
25822563 EEPOLICY_HANDLE_FATAL_ERROR (COR_E_EXECUTIONENGINE );
@@ -2610,6 +2591,9 @@ int RedirectedHandledJITCaseExceptionFilter(
26102591 // Register the special OS handler as the top handler with the OS
26112592 SetCurrentSEHRecord (pCurSEH);
26122593
2594+ // restore last error
2595+ SetLastError (dwLastError);
2596+
26132597 // Resume execution at point where thread was originally redirected
26142598 return (EXCEPTION_CONTINUE_EXECUTION );
26152599}
@@ -2642,6 +2626,38 @@ extern "C" PCONTEXT __stdcall GetCurrentSavedRedirectContext()
26422626 return pContext;
26432627}
26442628
2629+ #ifdef TARGET_X86
2630+
2631+ void Thread::RestoreContextSimulated (Thread* pThread, CONTEXT * pCtx, void * pFrame, DWORD dwLastError)
2632+ {
2633+ pThread->HandleThreadAbort (); // Might throw an exception.
2634+
2635+ // A counter to avoid a nasty case where an
2636+ // up-stack filter throws another exception
2637+ // causing our filter to be run again for
2638+ // some unrelated exception.
2639+ int filter_count = 0 ;
2640+
2641+ __try
2642+ {
2643+ // Save the instruction pointer where we redirected last. This does not race with the check
2644+ // against this variable in HandledJitCase because the GC will not attempt to redirect the
2645+ // thread until the instruction pointer of this thread is back in managed code.
2646+ pThread->m_LastRedirectIP = GetIP (pCtx);
2647+ pThread->m_SpinCount = 0 ;
2648+
2649+ RaiseException (EXCEPTION_HIJACK , 0 , 0 , NULL );
2650+ }
2651+ __except (++filter_count == 1
2652+ ? RedirectedHandledJITCaseExceptionFilter (GetExceptionInformation (), (RedirectedThreadFrame*)pFrame, pCtx, dwLastError)
2653+ : EXCEPTION_CONTINUE_SEARCH )
2654+ {
2655+ _ASSERTE (!" Reached body of __except in Thread::RedirectedHandledJITCase" );
2656+ }
2657+ }
2658+
2659+ #endif // TARGET_X86
2660+
26452661void __stdcall Thread::RedirectedHandledJITCase (RedirectReason reason)
26462662{
26472663 STATIC_CONTRACT_THROWS ;
@@ -2665,140 +2681,106 @@ void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason)
26652681
26662682 STRESS_LOG5 (LF_SYNC , LL_INFO1000 , " In RedirectedHandledJITcase reason 0x%x pFrame = %p pc = %p sp = %p fp = %p" , reason, &frame, GetIP (pCtx), GetSP (pCtx), GetFP (pCtx));
26672683
2668- #ifdef TARGET_X86
2669- // This will indicate to the exception filter whether or not the exception is caused
2670- // by us or the client.
2671- BOOL fDone = FALSE ;
2672- int filter_count = 0 ; // A counter to avoid a nasty case where an
2673- // up-stack filter throws another exception
2674- // causing our filter to be run again for
2675- // some unrelated exception.
2676-
2677- __try
2678- #endif // TARGET_X86
2679- {
2680- // Make sure this thread doesn't reuse the context memory.
2681- pThread->MarkRedirectContextInUse (pCtx);
2684+ // Make sure this thread doesn't reuse the context memory.
2685+ pThread->MarkRedirectContextInUse (pCtx);
26822686
2683- // Link in the frame
2684- frame.Push ();
2687+ // Link in the frame
2688+ frame.Push ();
26852689
26862690#if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
2687- if (reason == RedirectReason_GCStress)
2688- {
2689- _ASSERTE (pThread->PreemptiveGCDisabledOther ());
2690- DoGcStress (frame.GetContext (), NULL );
2691- }
2692- else
2691+ if (reason == RedirectReason_GCStress)
2692+ {
2693+ _ASSERTE (pThread->PreemptiveGCDisabledOther ());
2694+ DoGcStress (frame.GetContext (), NULL );
2695+ }
2696+ else
26932697#endif // HAVE_GCCOVER && USE_REDIRECT_FOR_GCSTRESS
2694- {
2695- // Enable PGC before calling out to the client to allow runtime suspend to finish
2696- GCX_PREEMP_NO_DTOR ();
2698+ {
2699+ _ASSERTE (reason == RedirectReason_GCSuspension ||
2700+ reason == RedirectReason_DebugSuspension ||
2701+ reason == RedirectReason_UserSuspension);
26972702
2698- // Notify the interface of the pending suspension
2699- switch (reason) {
2700- case RedirectReason_GCSuspension:
2701- break ;
2702- case RedirectReason_DebugSuspension:
2703- break ;
2704- case RedirectReason_UserSuspension:
2705- // Do nothing;
2706- break ;
2707- default :
2708- _ASSERTE (!" Invalid redirect reason" );
2709- break ;
2710- }
2703+ // Actual self-suspension.
2704+ // Leave and reenter COOP mode to be trapped on the way back.
2705+ GCX_PREEMP_NO_DTOR ();
2706+ GCX_PREEMP_NO_DTOR_END ();
2707+ }
27112708
2712- // Disable preemptive GC so we can unlink the frame
2713- GCX_PREEMP_NO_DTOR_END ();
2714- }
2709+ // Once we get here the suspension is over!
2710+ // We will restore the state as it was at the point of redirection
2711+ // and continue normal execution.
27152712
27162713#ifdef TARGET_X86
2717- pThread->HandleThreadAbort (); // Might throw an exception.
2718-
2719- // Indicate that the call to the service went without an exception, and that
2720- // we're raising our own exception to resume the thread to where it was
2721- // redirected from
2722- fDone = TRUE ;
2723-
2724- // Save the instruction pointer where we redirected last. This does not race with the check
2725- // against this variable in HandledJitCase because the GC will not attempt to redirect the
2726- // thread until the instruction pointer of this thread is back in managed code.
2727- pThread->m_LastRedirectIP = GetIP (pCtx);
2728- pThread->m_SpinCount = 0 ;
2729-
2730- RaiseException (EXCEPTION_HIJACK , 0 , 0 , NULL );
2714+ if (!pfnRtlRestoreContext)
2715+ {
2716+ RestoreContextSimulated (pThread, pCtx, &frame, dwLastError);
27312717
2732- #else // TARGET_X86
2718+ // we never return to the caller.
2719+ __UNREACHABLE ();
2720+ }
2721+ #endif // TARGET_X86
27332722
27342723#if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
2735- //
2736- // If GCStress interrupts an IL stub or inlined p/invoke while it's running in preemptive mode, it switches the mode to
2737- // cooperative - but we will resume to preemptive below. We should not trigger an abort in that case, as it will fail
2738- // due to the GC mode.
2739- //
2740- if (!pThread->m_fPreemptiveGCDisabledForGCStress )
2724+ //
2725+ // If GCStress interrupts an IL stub or inlined p/invoke while it's running in preemptive mode, it switches the mode to
2726+ // cooperative - but we will resume to preemptive below. We should not trigger an abort in that case, as it will fail
2727+ // due to the GC mode.
2728+ //
2729+ if (!pThread->m_fPreemptiveGCDisabledForGCStress )
27412730#endif
2742- {
2731+ {
27432732
2744- UINT_PTR uAbortAddr;
2745- UINT_PTR uResumePC = (UINT_PTR )GetIP (pCtx);
2746- CopyOSContext (pThread->m_OSContext , pCtx);
2747- uAbortAddr = (UINT_PTR )COMPlusCheckForAbort ();
2748- if (uAbortAddr)
2749- {
2750- LOG ((LF_EH , LL_INFO100 , " thread abort in progress, resuming thread under control... (handled jit case)\n " ));
2733+ UINT_PTR uAbortAddr;
2734+ UINT_PTR uResumePC = (UINT_PTR )GetIP (pCtx);
2735+ CopyOSContext (pThread->m_OSContext , pCtx);
2736+ uAbortAddr = (UINT_PTR )COMPlusCheckForAbort ();
2737+ if (uAbortAddr)
2738+ {
2739+ LOG ((LF_EH , LL_INFO100 , " thread abort in progress, resuming thread under control... (handled jit case)\n " ));
27512740
2752- CONSISTENCY_CHECK (CheckPointer (pCtx));
2741+ CONSISTENCY_CHECK (CheckPointer (pCtx));
27532742
2754- STRESS_LOG1 (LF_EH , LL_INFO10 , " resume under control: ip: %p (handled jit case)\n " , uResumePC);
2743+ STRESS_LOG1 (LF_EH , LL_INFO10 , " resume under control: ip: %p (handled jit case)\n " , uResumePC);
27552744
2756- SetIP (pThread->m_OSContext , uResumePC);
2745+ SetIP (pThread->m_OSContext , uResumePC);
27572746
27582747#if defined(TARGET_ARM)
2759- // Save the original resume PC in Lr
2760- pCtx->Lr = uResumePC;
2748+ // Save the original resume PC in Lr
2749+ pCtx->Lr = uResumePC;
27612750
2762- // Since we have set a new IP, we have to clear conditional execution flags too.
2763- ClearITState (pThread->m_OSContext );
2751+ // Since we have set a new IP, we have to clear conditional execution flags too.
2752+ ClearITState (pThread->m_OSContext );
27642753#endif // TARGET_ARM
27652754
2766- SetIP (pCtx, uAbortAddr);
2767- }
2755+ SetIP (pCtx, uAbortAddr);
27682756 }
2757+ }
27692758
2770- // Unlink the frame in preparation for resuming in managed code
2771- frame.Pop ();
2759+ // Unlink the frame in preparation for resuming in managed code
2760+ frame.Pop ();
27722761
2773- {
2774- // Allow future use of the context
2775- pThread->UnmarkRedirectContextInUse (pCtx);
2762+ // Allow future use of the context
2763+ pThread->UnmarkRedirectContextInUse (pCtx);
27762764
27772765#if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
2778- if (pThread->m_fPreemptiveGCDisabledForGCStress )
2779- {
2780- pThread->EnablePreemptiveGC ();
2781- pThread->m_fPreemptiveGCDisabledForGCStress = false ;
2782- }
2766+ if (pThread->m_fPreemptiveGCDisabledForGCStress )
2767+ {
2768+ pThread->EnablePreemptiveGC ();
2769+ pThread->m_fPreemptiveGCDisabledForGCStress = false ;
2770+ }
27832771#endif
27842772
2785- LOG ((LF_SYNC , LL_INFO1000 , " Resuming execution with RtlRestoreContext\n " ));
2786-
2787- SetLastError (dwLastError); // END_PRESERVE_LAST_ERROR
2773+ LOG ((LF_SYNC , LL_INFO1000 , " Resuming execution with RtlRestoreContext\n " ));
2774+ SetLastError (dwLastError); // END_PRESERVE_LAST_ERROR
27882775
2789- RtlRestoreContext (pCtx, NULL );
2790- }
2791- #endif // TARGET_X86
2792- }
27932776#ifdef TARGET_X86
2794- __except (++filter_count == 1
2795- ? RedirectedHandledJITCaseExceptionFilter (GetExceptionInformation (), &frame, fDone , pCtx)
2796- : EXCEPTION_CONTINUE_SEARCH )
2797- {
2798- _ASSERTE (!" Reached body of __except in Thread::RedirectedHandledJITCase" );
2799- }
2777+ pfnRtlRestoreContext (pCtx, NULL );
2778+ #else
2779+ RtlRestoreContext (pCtx, NULL );
2780+ #endif
28002781
2801- #endif // TARGET_X86
2782+ // we never return to the caller.
2783+ __UNREACHABLE ();
28022784}
28032785
28042786// ****************************************************************************************
0 commit comments