diff options
author | Andrew Au <andrewau@microsoft.com> | 2017-07-07 18:59:18 +0300 |
---|---|---|
committer | Andrew Au <andrewau@microsoft.com> | 2017-07-07 18:59:18 +0300 |
commit | a61fac9dce2b1873a61cbe70489d8c0ecdad3ad4 (patch) | |
tree | 9dc81f67e77366aa2c4af1a74cf668b9bb69a518 /src/Native/Runtime/amd64 | |
parent | b5be0e6aac9002f171012ee6c48488d7d43448d9 (diff) |
(On behalf of Jan Vorlicek) Thread abort stage 1
[tfs-changeset: 1664997]
Diffstat (limited to 'src/Native/Runtime/amd64')
-rw-r--r-- | src/Native/Runtime/amd64/AsmMacros.inc | 8 | ||||
-rw-r--r-- | src/Native/Runtime/amd64/ExceptionHandling.asm | 23 | ||||
-rw-r--r-- | src/Native/Runtime/amd64/GcProbe.asm | 36 | ||||
-rw-r--r-- | src/Native/Runtime/amd64/PInvoke.S | 6 | ||||
-rw-r--r-- | src/Native/Runtime/amd64/PInvoke.asm | 57 |
5 files changed, 110 insertions, 20 deletions
diff --git a/src/Native/Runtime/amd64/AsmMacros.inc b/src/Native/Runtime/amd64/AsmMacros.inc index b9835375b..799dc2fde 100644 --- a/src/Native/Runtime/amd64/AsmMacros.inc +++ b/src/Native/Runtime/amd64/AsmMacros.inc @@ -370,7 +370,15 @@ PTFF_SAVE_RAX equ 00000100h ;; RAX is saved if it contains a GC ref PTFF_SAVE_ALL_SCRATCH equ 00007F00h PTFF_RAX_IS_GCREF equ 00010000h ;; iff PTFF_SAVE_RAX: set -> eax is Object, clear -> eax is scalar PTFF_RAX_IS_BYREF equ 00020000h ;; iff PTFF_SAVE_RAX: set -> eax is ByRef, clear -> eax is Object or scalar +PTFF_THREAD_ABORT equ 00040000h ;; indicates that ThreadAbortException should be thrown when returning from the transition +;; These must match the TrapThreadsFlags enum +TrapThreadsFlags_None equ 0 +TrapThreadsFlags_AbortInProgress equ 1 +TrapThreadsFlags_TrapThreads equ 2 + +;; This must match HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT +STATUS_REDHAWK_THREAD_ABORT equ 43h ;; ;; CONSTANTS -- SYMBOLS diff --git a/src/Native/Runtime/amd64/ExceptionHandling.asm b/src/Native/Runtime/amd64/ExceptionHandling.asm index ccea8d02d..b2fb7e036 100644 --- a/src/Native/Runtime/amd64/ExceptionHandling.asm +++ b/src/Native/Runtime/amd64/ExceptionHandling.asm @@ -353,11 +353,12 @@ endm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NESTED_ENTRY RhpCallCatchFunclet, _TEXT - FUNCLET_CALL_PROLOGUE 2, 1 + FUNCLET_CALL_PROLOGUE 3, 0 ;; locals rsp_offsetof_thread = rsp_offsetof_locals rsp_offsetof_resume_ip = rsp_offsetof_locals + 8; + rsp_offsetof_is_handling_thread_abort = rsp_offsetof_locals + 16; mov [rsp + rsp_offsetof_arguments + 0h], rcx ;; save arguments for later mov [rsp + rsp_offsetof_arguments + 8h], rdx @@ -367,6 +368,9 @@ NESTED_ENTRY RhpCallCatchFunclet, _TEXT INLINE_GETTHREAD rax, rbx ;; rax <- Thread*, rbx is trashed mov [rsp + rsp_offsetof_thread], rax ;; save Thread* for later + cmp rcx, [rax + OFFSETOF__Thread__m_threadAbortException] + setz byte ptr [rsp + rsp_offsetof_is_handling_thread_abort] + ;; Clear the DoNotTriggerGc state before calling out to our managed catch funclet. lock and dword ptr [rax + OFFSETOF__Thread__m_ThreadStateFlags], NOT TSF_DoNotTriggerGc @@ -435,7 +439,6 @@ endif ifdef _DEBUG ;; Call into some C++ code to validate the pop of the ExInfo. We only do this in debug because we ;; have to spill all the preserved registers and then refill them after the call. - mov [rsp + rsp_offsetof_resume_ip], rax ;; save resume IP for later mov rcx, [r8 + OFFSETOF__REGDISPLAY__pRbx] @@ -498,10 +501,24 @@ endif @@: mov [rdx + OFFSETOF__Thread__m_pExInfoStackHead], rcx ;; store the new head on the Thread + test [RhpTrapThreads], TrapThreadsFlags_AbortInProgress + jz @f + + ;; test if the exception handled by the catch was the ThreadAbortException + cmp byte ptr [rsp + rsp_offsetof_is_handling_thread_abort], 0 + je @f + + ;; It was the ThreadAbortException, so rethrow it + mov rcx, STATUS_REDHAWK_THREAD_ABORT + mov rdx, rax ;; rdx <- continuation address as exception RIP + mov rsp, r8 ;; reset the SP to resume SP value + jmp RhpThrowHwEx ;; Throw the ThreadAbortException as a special kind of hardware exception + ;; reset RSP and jump to the continuation address - mov rsp, r8 ;; reset the SP + @@: mov rsp, r8 ;; reset the SP to resume SP value jmp rax + NESTED_END RhpCallCatchFunclet, _TEXT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/Native/Runtime/amd64/GcProbe.asm b/src/Native/Runtime/amd64/GcProbe.asm index 02e977d4f..2f2f2ae58 100644 --- a/src/Native/Runtime/amd64/GcProbe.asm +++ b/src/Native/Runtime/amd64/GcProbe.asm @@ -124,14 +124,14 @@ endm ;; All other registers trashed ;; -EXTERN RhpWaitForGC : PROC +EXTERN RhpWaitForGCNoAbort : PROC WaitForGCCompletion macro test dword ptr [rbx + OFFSETOF__Thread__m_ThreadStateFlags], TSF_SuppressGcStress + TSF_DoNotTriggerGc jnz @F mov rcx, [rbx + OFFSETOF__Thread__m_pHackPInvokeTunnel] - call RhpWaitForGC + call RhpWaitForGCNoAbort @@: endm @@ -215,9 +215,11 @@ NESTED_END RhpGcStressProbe, _TEXT endif ;; FEATURE_GC_STRESS +EXTERN RhpThrowHwEx : PROC + NESTED_ENTRY RhpGcProbe, _TEXT - cmp [RhpTrapThreads], 0 - jne @f + test [RhpTrapThreads], TrapThreadsFlags_TrapThreads + jnz @f ret @@: PUSH_PROBE_FRAME rdx, rax, 0, rcx @@ -226,8 +228,17 @@ NESTED_ENTRY RhpGcProbe, _TEXT mov rbx, rdx WaitForGCCompletion + mov rax, [rbx + OFFSETOF__Thread__m_pHackPInvokeTunnel] + test dword ptr [rax + OFFSETOF__PInvokeTransitionFrame__m_dwFlags], PTFF_THREAD_ABORT + jnz Abort POP_PROBE_FRAME 0 ret +Abort: + POP_PROBE_FRAME 0 + mov rcx, STATUS_REDHAWK_THREAD_ABORT + pop rdx ;; return address as exception RIP + jmp RhpThrowHwEx ;; Throw the ThreadAbortException as a special kind of hardware exception + NESTED_END RhpGcProbe, _TEXT @@ -483,8 +494,8 @@ ifdef _DEBUG ;; If we get here, then we have been hijacked for a real GC, and our SyncState must ;; reflect that we've been requested to synchronize. - cmp [RhpTrapThreads], 0 - jne @F + test [RhpTrapThreads], TrapThreadsFlags_TrapThreads + jnz @F call RhDebugBreak @@: @@ -730,7 +741,7 @@ ifdef FEATURE_GC_STRESS endif ;; FEATURE_GC_STRESS lea rcx, [rsp + sizeof_OutgoingScratchSpace] ; calculate PInvokeTransitionFrame pointer - call RhpWaitForGC + call RhpWaitForGCNoAbort DoneWaitingForGc: ;; Prepare for our return by stashing a scratch register where we can pop it just before returning @@ -762,6 +773,8 @@ endif ;; FEATURE_GC_STRESS DontRestoreXmmAgain: add rsp, sizeof_OutgoingScratchSpace + mov eax, [rsp + OFFSETOF__PInvokeTransitionFrame__m_dwFlags] + test eax, PTFF_THREAD_ABORT pop rax ; m_RIP pop rbp ; m_FramePointer pop rax ; m_pThread @@ -793,6 +806,15 @@ DontRestoreXmmAgain: ;; The final step is to restore eflags, rcx, and return back to the loop target location. lea rsp, [rcx - 20h] + jz @f ;; result of the test instruction before the pops above + popfq ;; restore flags + pop rcx ;; discard ModuleHeader* + pop rcx ;; restore rcx + mov rcx, STATUS_REDHAWK_THREAD_ABORT + pop rdx ;; return address as exception RIP + jmp RhpThrowHwEx ;; Throw the ThreadAbortException as a special kind of hardware exception + +@@: popfq ;; restore flags pop rcx ;; discard ModuleHeader* pop rcx ;; restore rcx diff --git a/src/Native/Runtime/amd64/PInvoke.S b/src/Native/Runtime/amd64/PInvoke.S index 958da80f5..e1def2bef 100644 --- a/src/Native/Runtime/amd64/PInvoke.S +++ b/src/Native/Runtime/amd64/PInvoke.S @@ -33,9 +33,9 @@ NESTED_ENTRY RhpPInvoke, _TEXT, NoHandler mov qword ptr [rax + OFFSETOF__Thread__m_pTransitionFrame], rbx - cmp dword ptr [C_VAR(RhpTrapThreads)], 0 + test dword ptr [C_VAR(RhpTrapThreads)], TrapThreadsFlags_TrapThreads pop_nonvol_reg rbx - jne 0f // forward branch - predicted not taken + jnz 0f // forward branch - predicted not taken ret 0: jmp C_FUNC(RhpWaitForSuspend2) @@ -50,7 +50,7 @@ NESTED_END RhpPInvoke, _TEXT LEAF_ENTRY RhpPInvokeReturn, _TEXT mov rsi, [rdi + OFFSETOF__PInvokeTransitionFrame__m_pThread] mov qword ptr [rsi + OFFSETOF__Thread__m_pTransitionFrame], 0 - cmp dword ptr [C_VAR(RhpTrapThreads)], 0 + cmp dword ptr [C_VAR(RhpTrapThreads)], TrapThreadsFlags_None jne 0f // forward branch - predicted not taken ret 0: diff --git a/src/Native/Runtime/amd64/PInvoke.asm b/src/Native/Runtime/amd64/PInvoke.asm index 9f5be2546..762b3d1dc 100644 --- a/src/Native/Runtime/amd64/PInvoke.asm +++ b/src/Native/Runtime/amd64/PInvoke.asm @@ -35,8 +35,12 @@ NESTED_ENTRY RhpWaitForSuspend, _TEXT END_PROLOGUE + test [RhpTrapThreads], TrapThreadsFlags_TrapThreads + jz NoWait + call RhpWaitForSuspend2 +NoWait: movdqa xmm0, [rsp + 20h + 0*10h] movdqa xmm1, [rsp + 20h + 1*10h] movdqa xmm2, [rsp + 20h + 2*10h] @@ -55,7 +59,7 @@ NESTED_END RhpWaitForSuspend, _TEXT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; RhpWaitForGC -- rare path for RhpPInvokeReturn +;; RhpWaitForGCNoAbort -- rare path for RhpPInvokeReturn ;; ;; ;; INPUT: RCX: transition frame @@ -63,7 +67,7 @@ NESTED_END RhpWaitForSuspend, _TEXT ;; TRASHES: RCX, RDX, R8, R9, R10, R11 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -NESTED_ENTRY RhpWaitForGC, _TEXT +NESTED_ENTRY RhpWaitForGCNoAbort, _TEXT push_vol_reg rax ; don't trash the integer return value alloc_stack 30h movdqa [rsp + 20h], xmm0 ; don't trash the FP return value @@ -83,6 +87,45 @@ Done: pop rax ret +NESTED_END RhpWaitForGCNoAbort, _TEXT + +EXTERN RhpThrowHwEx : PROC + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; RhpWaitForGC -- rare path for RhpPInvokeReturn +;; +;; +;; INPUT: RCX: transition frame +;; +;; TRASHES: RCX, RDX, R8, R9, R10, R11 +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +NESTED_ENTRY RhpWaitForGC, _TEXT + push_nonvol_reg rbx + END_PROLOGUE + + mov rbx, rcx + + test [RhpTrapThreads], TrapThreadsFlags_TrapThreads + jz NoWait + + call RhpWaitForGCNoAbort +NoWait: + test [RhpTrapThreads], TrapThreadsFlags_AbortInProgress + jz Done + test dword ptr [rbx + OFFSETOF__PInvokeTransitionFrame__m_dwFlags], PTFF_THREAD_ABORT + jz Done + + mov rcx, STATUS_REDHAWK_THREAD_ABORT + pop rbx + pop rdx ; return address as exception RIP + jmp RhpThrowHwEx ; Throw the ThreadAbortException as a special kind of hardware exception + +Done: + pop rbx + ret + NESTED_END RhpWaitForGC, _TEXT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -125,8 +168,8 @@ LEAF_ENTRY RhpReversePInvoke, _TEXT mov [rax], r11 mov qword ptr [r10 + OFFSETOF__Thread__m_pTransitionFrame], 0 - cmp [RhpTrapThreads], 0 - jne TrapThread + test [RhpTrapThreads], TrapThreadsFlags_TrapThreads + jnz TrapThread ret @@ -221,7 +264,7 @@ LEAF_ENTRY RhpReversePInvokeReturn, _TEXT mov rcx, [rcx + 0] ; get previous M->U transition frame mov [rdx + OFFSETOF__Thread__m_pTransitionFrame], rcx - cmp [RhpTrapThreads], 0 + cmp [RhpTrapThreads], TrapThreadsFlags_None jne RhpWaitForSuspend ret LEAF_END RhpReversePInvokeReturn, _TEXT @@ -255,7 +298,7 @@ LEAF_ENTRY RhpPInvoke, _TEXT mov qword ptr [r10 + OFFSETOF__Thread__m_pTransitionFrame], rcx - cmp [RhpTrapThreads], 0 + cmp [RhpTrapThreads], TrapThreadsFlags_None jne @F ; forward branch - predicted not taken ret @@: @@ -275,7 +318,7 @@ LEAF_END RhpPInvoke, _TEXT LEAF_ENTRY RhpPInvokeReturn, _TEXT mov rdx, [rcx + OFFSETOF__PInvokeTransitionFrame__m_pThread] mov qword ptr [rdx + OFFSETOF__Thread__m_pTransitionFrame], 0 - cmp [RhpTrapThreads], 0 + cmp [RhpTrapThreads], TrapThreadsFlags_None jne @F ; forward branch - predicted not taken ret @@: |