Skip to content

Commit be318b1

Browse files
Gc enter/leave/poll without HELPER_METHOD_FRAME (#109378)
Rewrite gc polling logic as a managed helper and remove the stress helper. Also move the pinvoke suspension and rare disable paths to take advantage of the QCall infrastructure.
1 parent 1af7c23 commit be318b1

File tree

20 files changed

+210
-85
lines changed

20 files changed

+210
-85
lines changed

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,5 +490,37 @@ private void ResetFinalizerThreadSlow()
490490
Priority = ThreadPriority.Highest;
491491
}
492492
}
493+
494+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_PollGC")]
495+
private static partial void ThreadNative_PollGC();
496+
497+
// GC Suspension is done by simply dropping into native code via p/invoke, and we reuse the p/invoke
498+
// mechanism for suspension. On all architectures we should have the actual stub used for the check be implemented
499+
// as a small assembly stub which checks the global g_TrapReturningThreads flag and tail-call to this helper
500+
private static unsafe void PollGC()
501+
{
502+
NativeThreadState catchAtSafePoint = ((NativeThreadClass*)Thread.DirectOnThreadLocalData.pNativeThread)->m_State & NativeThreadState.TS_CatchAtSafePoint;
503+
if (catchAtSafePoint != NativeThreadState.None)
504+
{
505+
ThreadNative_PollGC();
506+
}
507+
}
508+
509+
[StructLayout(LayoutKind.Sequential)]
510+
private struct NativeThreadClass
511+
{
512+
public NativeThreadState m_State;
513+
}
514+
515+
private enum NativeThreadState
516+
{
517+
None = 0,
518+
TS_AbortRequested = 0x00000001, // Abort the thread
519+
TS_DebugSuspendPending = 0x00000008, // Is the debugger suspending threads?
520+
TS_GCOnTransitions = 0x00000010, // Force a GC on stub transitions (GCStress only)
521+
522+
// We require (and assert) that the following bits are less than 0x100.
523+
TS_CatchAtSafePoint = (TS_AbortRequested | TS_DebugSuspendPending | TS_GCOnTransitions),
524+
};
493525
}
494526
}

src/coreclr/inc/jithelpers.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@
149149

150150
// GC support
151151
DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper, METHOD__NIL)
152-
JITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, METHOD__NIL)
153-
152+
DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, METHOD__THREAD__POLLGC)
153+
154154
JITHELPER(CORINFO_HELP_CHECK_OBJ, JIT_CheckObj, METHOD__NIL)
155155

156156
// GC Write barrier support

src/coreclr/vm/amd64/AsmHelpers.asm

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ extern ProfileTailcall:proc
1212
extern OnHijackWorker:proc
1313
extern JIT_RareDisableHelperWorker:proc
1414

15+
extern g_pPollGC:QWORD
16+
extern g_TrapReturningThreads:DWORD
1517

1618
; EXTERN_C int __fastcall HelperMethodFrameRestoreState(
1719
; INDEBUG_COMMA(HelperMethodFrame *pFrame)
@@ -447,5 +449,13 @@ NESTED_END OnCallCountThresholdReachedStub, _TEXT
447449

448450
endif ; FEATURE_TIERED_COMPILATION
449451

450-
end
452+
LEAF_ENTRY JIT_PollGC, _TEXT
453+
cmp [g_TrapReturningThreads], 0
454+
jnz JIT_PollGCRarePath
455+
ret
456+
JIT_PollGCRarePath:
457+
mov rax, g_pPollGC
458+
TAILJMP_RAX
459+
LEAF_END JIT_PollGC, _TEXT
451460

461+
end

src/coreclr/vm/amd64/asmhelpers.S

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,14 @@ LEAF_ENTRY GetTlsIndexObjectDescOffset, _TEXT
319319
int 3
320320
LEAF_END GetTlsIndexObjectDescOffset, _TEXT
321321
#endif
322+
323+
LEAF_ENTRY JIT_PollGC, _TEXT
324+
PREPARE_EXTERNAL_VAR g_TrapReturningThreads, rax
325+
cmp dword ptr [rax], 0
326+
jnz LOCAL_LABEL(JIT_PollGCRarePath)
327+
ret
328+
LOCAL_LABEL(JIT_PollGCRarePath):
329+
PREPARE_EXTERNAL_VAR g_pPollGC, rax
330+
mov rax, [rax]
331+
jmp rax
332+
LEAF_END JIT_PollGC, _TEXT

src/coreclr/vm/appdomain.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,8 @@ extern "C" PCODE g_pGetGCStaticBase;
10061006
PCODE g_pGetGCStaticBase;
10071007
extern "C" PCODE g_pGetNonGCStaticBase;
10081008
PCODE g_pGetNonGCStaticBase;
1009+
extern "C" PCODE g_pPollGC;
1010+
PCODE g_pPollGC;
10091011

10101012
void SystemDomain::LoadBaseSystemClasses()
10111013
{
@@ -1144,6 +1146,7 @@ void SystemDomain::LoadBaseSystemClasses()
11441146

11451147
g_pGetGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_GC_STATIC)->GetMultiCallableAddrOfCode();
11461148
g_pGetNonGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_NONGC_STATIC)->GetMultiCallableAddrOfCode();
1149+
g_pPollGC = CoreLibBinder::GetMethod(METHOD__THREAD__POLLGC)->GetMultiCallableAddrOfCode();
11471150

11481151
#ifdef PROFILING_SUPPORTED
11491152
// Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after

src/coreclr/vm/arm/asmhelpers.S

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,3 +914,26 @@ ProbeLoop:
914914
NESTED_END OnCallCountThresholdReachedStub, _TEXT
915915

916916
#endif // FEATURE_TIERED_COMPILATION
917+
918+
LEAF_ENTRY JIT_PollGC, _TEXT
919+
#if defined(__clang__)
920+
ldr r2, =g_TrapReturningThreads-(1f+4)
921+
1:
922+
add r2, pc
923+
#else
924+
ldr r2, =g_TrapReturningThreads
925+
#endif
926+
ldr r2, [r2]
927+
cbnz r2, LOCAL_LABEL(JIT_PollGCRarePath)
928+
bx lr
929+
LOCAL_LABEL(JIT_PollGCRarePath):
930+
#if defined(__clang__)
931+
ldr r2, =g_pPollGC-(1f+4)
932+
1:
933+
add r2, pc
934+
#else
935+
ldr r2, =g_pPollGC
936+
#endif
937+
ldr r2, [r2]
938+
EPILOG_BRANCH_REG r2
939+
LEAF_END JIT_PollGC, _TEXT

src/coreclr/vm/arm64/asmhelpers.S

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,3 +806,14 @@ LEAF_ENTRY GetTLSResolverAddress, _TEXT
806806
LEAF_END GetTLSResolverAddress, _TEXT
807807
// ------------------------------------------------------------------
808808
#endif // !TARGET_OSX
809+
810+
LEAF_ENTRY JIT_PollGC, _TEXT
811+
PREPARE_EXTERNAL_VAR g_TrapReturningThreads, x9
812+
ldr w9, [x9]
813+
cbnz w9, LOCAL_LABEL(JIT_PollGCRarePath)
814+
ret
815+
LOCAL_LABEL(JIT_PollGCRarePath):
816+
PREPARE_EXTERNAL_VAR g_pPollGC, x9
817+
ldr x9, [x9]
818+
br x9
819+
LEAF_END JIT_PollGC, _TEXT

src/coreclr/vm/arm64/asmhelpers.asm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
IMPORT g_pGetGCStaticBase
4040
IMPORT g_pGetNonGCStaticBase
4141

42+
IMPORT g_pPollGC
43+
IMPORT g_TrapReturningThreads
44+
4245
#ifdef WRITE_BARRIER_CHECK
4346
SETALIAS g_GCShadow, ?g_GCShadow@@3PEAEEA
4447
SETALIAS g_GCShadowEnd, ?g_GCShadowEnd@@3PEAEEA
@@ -1179,6 +1182,17 @@ __HelperNakedFuncName SETS "$helper":CC:"Naked"
11791182

11801183
#endif ; FEATURE_SPECIAL_USER_MODE_APC
11811184

1185+
LEAF_ENTRY JIT_PollGC
1186+
ldr x9, =g_TrapReturningThreads
1187+
ldr w9, [x9]
1188+
cbnz w9, JIT_PollGCRarePath
1189+
ret
1190+
JIT_PollGCRarePath
1191+
ldr x9, =g_pPollGC
1192+
ldr x9, [x9]
1193+
br x9
1194+
LEAF_END
1195+
11821196

11831197
; Must be at very end of file
11841198
END

src/coreclr/vm/comsynchronizable.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,12 @@ extern "C" void QCALLTYPE ThreadNative_DisableComObjectEagerCleanup(QCall::Threa
848848
}
849849
#endif //FEATURE_COMINTEROP
850850

851+
extern "C" void QCALLTYPE ThreadNative_PollGC()
852+
{
853+
// This is an intentional no-op. The call is made to ensure that the thread goes through a GC transition
854+
// and is thus marked as a GC safe point, and that the p/invoke rare path will kick in
855+
}
856+
851857
extern "C" BOOL QCALLTYPE ThreadNative_YieldThread()
852858
{
853859
QCALL_CONTRACT;

src/coreclr/vm/comsynchronizable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ extern "C" BOOL QCALLTYPE ThreadNative_GetIsBackground(QCall::ThreadHandle threa
5050
extern "C" void QCALLTYPE ThreadNative_SetIsBackground(QCall::ThreadHandle thread, BOOL value);
5151
extern "C" void QCALLTYPE ThreadNative_InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len);
5252
extern "C" BOOL QCALLTYPE ThreadNative_YieldThread();
53+
extern "C" void QCALLTYPE ThreadNative_PollGC();
5354
extern "C" UINT64 QCALLTYPE ThreadNative_GetCurrentOSThreadId();
5455
extern "C" void QCALLTYPE ThreadNative_Initialize(QCall::ObjectHandleOnStack t);
5556
extern "C" INT32 QCALLTYPE ThreadNative_GetThreadState(QCall::ThreadHandle thread);

0 commit comments

Comments
 (0)