Skip to content

Commit e8fbb78

Browse files
committed
no copy of redirect context
1 parent 4962377 commit e8fbb78

File tree

6 files changed

+130
-83
lines changed

6 files changed

+130
-83
lines changed

src/coreclr/nativeaot/Runtime/PalRedhawk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
405405
void SetArg1Reg(uintptr_t val) { X1 = val; }
406406
uintptr_t GetIp() { return Pc; }
407407
uintptr_t GetLr() { return Lr; }
408+
uintptr_t GetSp() { return Sp; }
408409
} CONTEXT, *PCONTEXT;
409410

410411
#elif defined(HOST_WASM)

src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,18 @@ StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PInvokeTransition
9292
{
9393
STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ GC ]\n");
9494
ASSERT(!pThreadToWalk->DangerousCrossThreadIsHijacked());
95-
InternalInit(pThreadToWalk, pInitialTransitionFrame, GcStackWalkFlags);
95+
96+
#ifdef FEATURE_SUSPEND_REDIRECTION
97+
if (pInitialTransitionFrame == REDIRECTED_THREAD_MARKER)
98+
{
99+
InternalInit(pThreadToWalk, pThreadToWalk->GetRedirectionContext(), GcStackWalkFlags);
100+
}
101+
else
102+
#endif
103+
{
104+
InternalInit(pThreadToWalk, pInitialTransitionFrame, GcStackWalkFlags);
105+
}
106+
96107
PrepareToYieldFrame();
97108
}
98109

@@ -497,6 +508,112 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PAL_LIMITED_CO
497508
#endif // TARGET_ARM
498509
}
499510

511+
// Prepare to start a stack walk from the context listed in the supplied CONTEXT.
512+
// The supplied context can describe a location in either managed or unmanaged code. In the
513+
// latter case the iterator is left in an invalid state when this function returns.
514+
void StackFrameIterator::InternalInit(Thread * pThreadToWalk, CONTEXT* pCtx, uint32_t dwFlags)
515+
{
516+
ASSERT((dwFlags & MethodStateCalculated) == 0);
517+
518+
EnterInitialInvalidState(pThreadToWalk);
519+
520+
m_dwFlags = dwFlags;
521+
522+
// We need to walk the ExInfo chain in parallel with the stackwalk so that we know when we cross over
523+
// exception throw points. So we must find our initial point in the ExInfo chain here so that we can
524+
// properly walk it in parallel.
525+
ResetNextExInfoForSP(pCtx->GetSp());
526+
527+
// This codepath is used by the hijack stackwalk and we can get arbitrary ControlPCs from there. If this
528+
// context has a non-managed control PC, then we're done.
529+
if (!m_pInstance->IsManaged(dac_cast<PTR_VOID>(pCtx->GetIp())))
530+
return;
531+
532+
//
533+
// control state
534+
//
535+
SetControlPC(dac_cast<PTR_VOID>(pCtx->GetIp()));
536+
m_RegDisplay.SP = pCtx->GetSp();
537+
m_RegDisplay.IP = pCtx->GetIp();
538+
539+
#ifdef TARGET_ARM64
540+
541+
m_RegDisplay.pIP = PTR_TO_MEMBER(CONTEXT, pCtx, Pc);
542+
543+
//
544+
// preserved regs
545+
//
546+
m_RegDisplay.pX19 = PTR_TO_MEMBER(CONTEXT, pCtx, X19);
547+
m_RegDisplay.pX20 = PTR_TO_MEMBER(CONTEXT, pCtx, X20);
548+
m_RegDisplay.pX21 = PTR_TO_MEMBER(CONTEXT, pCtx, X21);
549+
m_RegDisplay.pX22 = PTR_TO_MEMBER(CONTEXT, pCtx, X22);
550+
m_RegDisplay.pX23 = PTR_TO_MEMBER(CONTEXT, pCtx, X23);
551+
m_RegDisplay.pX24 = PTR_TO_MEMBER(CONTEXT, pCtx, X24);
552+
m_RegDisplay.pX25 = PTR_TO_MEMBER(CONTEXT, pCtx, X25);
553+
m_RegDisplay.pX26 = PTR_TO_MEMBER(CONTEXT, pCtx, X26);
554+
m_RegDisplay.pX27 = PTR_TO_MEMBER(CONTEXT, pCtx, X27);
555+
m_RegDisplay.pX28 = PTR_TO_MEMBER(CONTEXT, pCtx, X28);
556+
m_RegDisplay.pFP = PTR_TO_MEMBER(CONTEXT, pCtx, Fp);
557+
m_RegDisplay.pLR = PTR_TO_MEMBER(CONTEXT, pCtx, Lr);
558+
559+
//
560+
// scratch regs
561+
//
562+
m_RegDisplay.pX0 = PTR_TO_MEMBER(CONTEXT, pCtx, X0);
563+
m_RegDisplay.pX1 = PTR_TO_MEMBER(CONTEXT, pCtx, X1);
564+
m_RegDisplay.pX2 = PTR_TO_MEMBER(CONTEXT, pCtx, X2);
565+
m_RegDisplay.pX3 = PTR_TO_MEMBER(CONTEXT, pCtx, X3);
566+
m_RegDisplay.pX4 = PTR_TO_MEMBER(CONTEXT, pCtx, X4);
567+
m_RegDisplay.pX5 = PTR_TO_MEMBER(CONTEXT, pCtx, X5);
568+
m_RegDisplay.pX6 = PTR_TO_MEMBER(CONTEXT, pCtx, X6);
569+
m_RegDisplay.pX7 = PTR_TO_MEMBER(CONTEXT, pCtx, X7);
570+
m_RegDisplay.pX8 = PTR_TO_MEMBER(CONTEXT, pCtx, X8);
571+
m_RegDisplay.pX9 = PTR_TO_MEMBER(CONTEXT, pCtx, X9);
572+
m_RegDisplay.pX10 = PTR_TO_MEMBER(CONTEXT, pCtx, X10);
573+
m_RegDisplay.pX11 = PTR_TO_MEMBER(CONTEXT, pCtx, X11);
574+
m_RegDisplay.pX12 = PTR_TO_MEMBER(CONTEXT, pCtx, X12);
575+
m_RegDisplay.pX13 = PTR_TO_MEMBER(CONTEXT, pCtx, X13);
576+
m_RegDisplay.pX14 = PTR_TO_MEMBER(CONTEXT, pCtx, X14);
577+
m_RegDisplay.pX15 = PTR_TO_MEMBER(CONTEXT, pCtx, X15);
578+
m_RegDisplay.pX16 = PTR_TO_MEMBER(CONTEXT, pCtx, X16);
579+
m_RegDisplay.pX17 = PTR_TO_MEMBER(CONTEXT, pCtx, X17);
580+
m_RegDisplay.pX18 = PTR_TO_MEMBER(CONTEXT, pCtx, X18);
581+
582+
#elif defined(TARGET_X86) || defined(TARGET_AMD64)
583+
584+
m_RegDisplay.pIP = (PTR_PCODE)PTR_TO_MEMBER(CONTEXT, pCtx, Rip);
585+
586+
//
587+
// preserved regs
588+
//
589+
m_RegDisplay.pRbp = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rbp);
590+
m_RegDisplay.pRsi = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rsi);
591+
m_RegDisplay.pRdi = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rdi);
592+
m_RegDisplay.pRbx = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rbx);
593+
#ifdef TARGET_AMD64
594+
m_RegDisplay.pR12 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R12);
595+
m_RegDisplay.pR13 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R13);
596+
m_RegDisplay.pR14 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R14);
597+
m_RegDisplay.pR15 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R15);
598+
#endif // TARGET_AMD64
599+
600+
//
601+
// scratch regs
602+
//
603+
m_RegDisplay.pRax = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rax);
604+
m_RegDisplay.pRcx = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rcx);
605+
m_RegDisplay.pRdx = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, Rdx);
606+
#ifdef TARGET_AMD64
607+
m_RegDisplay.pR8 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R8);
608+
m_RegDisplay.pR9 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R9);
609+
m_RegDisplay.pR10 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R10);
610+
m_RegDisplay.pR11 = (PTR_UIntNative)PTR_TO_MEMBER(CONTEXT, pCtx, R11);
611+
#endif // TARGET_AMD64
612+
#else
613+
PORTABILITY_ASSERT("StackFrameIterator::InternalInit");
614+
#endif // TARGET_ARM
615+
}
616+
500617
PTR_VOID StackFrameIterator::HandleExCollide(PTR_ExInfo pExInfo)
501618
{
502619
STRESS_LOG3(LF_STACKWALK, LL_INFO10000, " [ ex collide ] kind = %d, pass = %d, idxCurClause = %d\n",

src/coreclr/nativeaot/Runtime/StackFrameIterator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class StackFrameIterator
3636
StackFrameIterator(Thread * pThreadToWalk, PInvokeTransitionFrame* pInitialTransitionFrame);
3737
StackFrameIterator(Thread * pThreadToWalk, PTR_PAL_LIMITED_CONTEXT pCtx);
3838

39-
4039
bool IsValid();
4140
void CalculateCurrentMethodState();
4241
void Next();
@@ -82,6 +81,8 @@ class StackFrameIterator
8281

8382
void InternalInit(Thread * pThreadToWalk, PTR_PInvokeTransitionFrame pFrame, uint32_t dwFlags); // GC stackwalk
8483
void InternalInit(Thread * pThreadToWalk, PTR_PAL_LIMITED_CONTEXT pCtx, uint32_t dwFlags); // EH and hijack stackwalk, and collided unwind
84+
void InternalInit(Thread * pThreadToWalk, CONTEXT* pCtx, uint32_t dwFlags); // GC stackwalk of redirected thread
85+
8586
void InternalInitForEH(Thread * pThreadToWalk, PAL_LIMITED_CONTEXT * pCtx, bool instructionFault); // EH stackwalk
8687
void InternalInitForStackTrace(); // Environment.StackTrace
8788

src/coreclr/nativeaot/Runtime/inc/rhbinder.h

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ enum PInvokeTransitionFrameFlags : uint64_t
392392
PTFF_SAVE_X26 = 0x0000000000000080,
393393
PTFF_SAVE_X27 = 0x0000000000000100,
394394
PTFF_SAVE_X28 = 0x0000000000000200,
395-
PTFF_SAVE_ALL_PRESERVED = 0x0000000000003FF,// NOTE: x19-x28
396395

397396
PTFF_SAVE_SP = 0x0000000000000400, // Used for 'coop pinvokes' in runtime helper routines. Methods with
398397
// PInvokes are required to have a frame pointers, but methods which
@@ -419,7 +418,6 @@ enum PInvokeTransitionFrameFlags : uint64_t
419418
PTFF_SAVE_X16 = 0x0000000008000000,
420419
PTFF_SAVE_X17 = 0x0000000010000000,
421420
PTFF_SAVE_X18 = 0x0000000020000000,
422-
PTFF_SAVE_ALL_SCRATCH = 0x00000003FFFF800, // NOTE: X0-X18
423421

424422
PTFF_SAVE_FP = 0x0000000040000000, // should never be used, we require FP frames for methods with
425423
// pinvoke and it is saved into the frame pointer field instead
@@ -435,9 +433,6 @@ enum PInvokeTransitionFrameFlags : uint64_t
435433
PTFF_X1_IS_BYREF = 0x0000000800000000,
436434

437435
PTFF_THREAD_ABORT = 0x0000001000000000, // indicates that ThreadAbortException should be thrown when returning from the transition
438-
439-
DEFAULT_FRAME_SAVE_FLAGS = PTFF_SAVE_ALL_PRESERVED + PTFF_SAVE_SP,
440-
PROBE_SAVE_FLAGS_EVERYTHING = DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_ALL_SCRATCH + PTFF_SAVE_LR,
441436
};
442437

443438

@@ -460,10 +455,8 @@ enum PInvokeTransitionFrameFlags
460455
PTFF_SAVE_R14 = 0x00000040,
461456
PTFF_SAVE_R15 = 0x00000080,
462457

463-
PTFF_SAVE_ALL_PRESERVED = 0x000000F7,// NOTE: RBP is not included in this set!
464-
465458
PTFF_SAVE_RSP = 0x00008000, // Used for 'coop pinvokes' in runtime helper routines. Methods with
466-
// PInvokes are required to have frame pointers, but methods which
459+
// PInvokes are required to have a frame pointers, but methods which
467460
// call runtime helpers are not. Therefore, methods that call runtime
468461
// helpers may need RSP to seed the stackwalk.
469462
//
@@ -478,15 +471,10 @@ enum PInvokeTransitionFrameFlags
478471
PTFF_SAVE_R10 = 0x00002000,
479472
PTFF_SAVE_R11 = 0x00004000,
480473

481-
PTFF_SAVE_ALL_SCRATCH = 0x00007F00,
482-
483474
PTFF_RAX_IS_GCREF = 0x00010000, // used by hijack handler to report return value of hijacked method
484475
PTFF_RAX_IS_BYREF = 0x00020000, // used by hijack handler to report return value of hijacked method
485476

486477
PTFF_THREAD_ABORT = 0x00040000, // indicates that ThreadAbortException should be thrown when returning from the transition
487-
488-
DEFAULT_FRAME_SAVE_FLAGS = PTFF_SAVE_ALL_PRESERVED + PTFF_SAVE_RSP,
489-
PROBE_SAVE_FLAGS_EVERYTHING = DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_ALL_SCRATCH,
490478
};
491479
#endif // TARGET_ARM
492480

@@ -533,22 +521,14 @@ struct PInvokeTransitionFrame
533521
#ifdef TARGET_AMD64
534522
// RBX, RSI, RDI, R12, R13, R14, R15, RAX, RSP
535523
#define PInvokeTransitionFrame_SaveRegs_count 9
536-
// RBX, RSI, RDI, R12, R13, R14, R15, RAX, RSP, RAX, RCX, RDX, R8, R9, R10, R11
537-
#define PInvokeTransitionFrame_SaveAllRegs_count 16
538524
#elif defined(TARGET_X86)
539525
// RBX, RSI, RDI, RAX, RSP
540526
#define PInvokeTransitionFrame_SaveRegs_count 5
541527
#elif defined(TARGET_ARM)
542528
// R4-R10, R0, SP
543529
#define PInvokeTransitionFrame_SaveRegs_count 9
544-
#elif defined(TARGET_ARM64)
545-
// R19-R28, SP
546-
#define PInvokeTransitionFrame_SaveRegs_count 10
547-
// X19-X28, SP, X0-X18, LR
548-
#define PInvokeTransitionFrame_SaveAllRegs_count 31
549530
#endif
550-
#define PInvokeTransitionFrame_SaveRegs_SIZE (sizeof(PInvokeTransitionFrame) + (POINTER_SIZE * PInvokeTransitionFrame_SaveRegs_count))
551-
#define PInvokeTransitionFrame_SaveAllRegs_SIZE (sizeof(PInvokeTransitionFrame) + (POINTER_SIZE * PInvokeTransitionFrame_SaveAllRegs_count))
531+
#define PInvokeTransitionFrame_MAX_SIZE (sizeof(PInvokeTransitionFrame) + (POINTER_SIZE * PInvokeTransitionFrame_SaveRegs_count))
552532

553533
#ifdef TARGET_AMD64
554534
#define OFFSETOF__Thread__m_pTransitionFrame 0x40

src/coreclr/nativeaot/Runtime/thread.cpp

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ UInt32_BOOL Thread::HijackCallback(HANDLE /*hThread*/, PAL_LIMITED_CONTEXT* pThr
689689
if (codeManager->IsSafePoint(pvAddress))
690690
{
691691
#ifdef FEATURE_SUSPEND_REDIRECTION
692-
if (pThread->Redirect(pThreadContext))
692+
if (pThread->Redirect())
693693
{
694694
return true;
695695
}
@@ -812,7 +812,7 @@ CONTEXT* Thread::GetRedirectionContext()
812812
return m_redirectionContext;
813813
}
814814

815-
bool Thread::Redirect(PAL_LIMITED_CONTEXT * pSuspendCtx)
815+
bool Thread::Redirect()
816816
{
817817
if (IsDoNotTriggerGcSet())
818818
return false;
@@ -821,26 +821,18 @@ bool Thread::Redirect(PAL_LIMITED_CONTEXT * pSuspendCtx)
821821
if (redirectionContext == NULL)
822822
return false;
823823

824-
StackFrameIterator frameIterator(this, pSuspendCtx);
825-
826-
if (!frameIterator.IsValid())
827-
return false;
828-
829-
frameIterator.CalculateCurrentMethodState();
830-
831824
if (!PalGetCompleteThreadContext(m_hPalThread, redirectionContext))
832825
return false;
833826

834827
uintptr_t origIP = redirectionContext->GetIp();
835828
redirectionContext->SetIp((uintptr_t)RhpSuspendRedirected);
836-
837829
if (!PalSetThreadContext(m_hPalThread, redirectionContext))
838830
return false;
839831

840832
redirectionContext->SetIp(origIP);
841833

842834
STRESS_LOG2(LF_STACKWALK, LL_INFO10000, "InternalRedirect: TgtThread = %llx, IP = %p\n",
843-
GetPalThreadIdForLogging(), pSuspendCtx->GetIp());
835+
GetPalThreadIdForLogging(), origIP);
844836

845837
return true;
846838
}
@@ -1047,55 +1039,10 @@ EXTERN_C NOINLINE void FASTCALL RhpGcPoll2(PInvokeTransitionFrame* pFrame)
10471039
EXTERN_C NOINLINE void FASTCALL RhpSuspendRedirected()
10481040
{
10491041
Thread* pThread = ThreadStore::GetCurrentThread();
1050-
CONTEXT* pCtx = pThread->GetRedirectionContext();
1051-
1052-
PInvokeTransitionFrame* frame =
1053-
(PInvokeTransitionFrame*)_alloca(PInvokeTransitionFrame_SaveAllRegs_SIZE);
1054-
1055-
frame->m_Flags = PROBE_SAVE_FLAGS_EVERYTHING;
1056-
frame->m_pThread = pThread;
1057-
frame->m_RIP = (void*)pCtx->GetIp();
1058-
1059-
UIntTarget* pPreservedRegs = frame->m_PreservedRegs;
1060-
1061-
#ifdef TARGET_AMD64
1062-
frame->m_FramePointer = (void*)pCtx->Rbp;
1063-
1064-
pPreservedRegs[0] = pCtx->Rbx;
1065-
pPreservedRegs[1] = pCtx->Rsi;
1066-
pPreservedRegs[2] = pCtx->Rdi;
1067-
pPreservedRegs[3] = pCtx->R12;
1068-
pPreservedRegs[4] = pCtx->R13;
1069-
pPreservedRegs[5] = pCtx->R14;
1070-
pPreservedRegs[6] = pCtx->R15;
1071-
1072-
pPreservedRegs[7] = pCtx->Rsp;
1073-
1074-
pPreservedRegs[8] = pCtx->Rax;
1075-
pPreservedRegs[9] = pCtx->Rcx;
1076-
pPreservedRegs[10] = pCtx->Rdx;
1077-
pPreservedRegs[11] = pCtx->R8;
1078-
pPreservedRegs[12] = pCtx->R9;
1079-
pPreservedRegs[13] = pCtx->R10;
1080-
pPreservedRegs[14] = pCtx->R11;
1081-
#elif defined(TARGET_ARM64)
1082-
frame->m_FramePointer = (void*)pCtx->Fp;
1083-
// X19-X28
1084-
memcpy(&pPreservedRegs[0], &pCtx->X19, sizeof(uint64_t) * 10);
1085-
// SP
1086-
pPreservedRegs[10] = pCtx->Sp;
1087-
// X0-X18
1088-
memcpy(&pPreservedRegs[11], &pCtx->X0, sizeof(uint64_t) * 19);
1089-
// LR
1090-
pPreservedRegs[30] = pCtx->Lr;
1091-
#elif
1092-
ASSERT_UNCONDITIONALLY("NYI for this arch");
1093-
#endif
1094-
1095-
pThread->WaitForGC(frame);
1042+
pThread->WaitForGC(REDIRECTED_THREAD_MARKER);
10961043

10971044
// restore execution at interrupted location
1098-
PalRestoreContext(pCtx);
1045+
PalRestoreContext(pThread->GetRedirectionContext());
10991046
UNREACHABLE();
11001047
}
11011048

src/coreclr/nativeaot/Runtime/thread.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class Thread;
2828
#endif // HOST_64BIT
2929

3030
#define TOP_OF_STACK_MARKER ((PInvokeTransitionFrame*)(ptrdiff_t)-1)
31+
#define REDIRECTED_THREAD_MARKER ((PInvokeTransitionFrame*)(ptrdiff_t)-2)
3132

3233
#define DYNAMIC_TYPE_TLS_OFFSET_FLAG 0x80000000
3334

@@ -144,7 +145,7 @@ class Thread : private ThreadBuffer
144145
bool InternalHijack(PAL_LIMITED_CONTEXT * pSuspendCtx, void * pvHijackTargets[]);
145146

146147
#ifdef FEATURE_SUSPEND_REDIRECTION
147-
bool Redirect(PAL_LIMITED_CONTEXT * pSuspendCtx);
148+
bool Redirect();
148149
#endif //FEATURE_SUSPEND_REDIRECTION
149150

150151
bool CacheTransitionFrameForSuspend();

0 commit comments

Comments
 (0)