Skip to content

Commit b44fd4a

Browse files
authored
Some cleanups in Native AOT suspension area (#69885)
* some renames * strongly typed transition frames * remove remaining pieces of LoopHijack * comments and some refactoring * IsManaged * removed m_CodeManagerList * m_ModuleListLock * better comment for a SafeHandle hack * Renamed SetupHackPInvokeTunnel (to not have "hack in the name) * made IsInForbidBlockingRegion a debug-only assert * removed ForbidBlockingHolder * remove forbidBlocking tracking. It only affects 4 methods. * Fix Unix build * typo * record managed code range in RuntimeInstance.
1 parent ff8393d commit b44fd4a

30 files changed

+198
-301
lines changed

src/coreclr/nativeaot/Runtime/AsmOffsets.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ ASM_OFFSET( 14, 18, MethodTable, m_VTable)
4242
ASM_OFFSET( 0, 0, Thread, m_rgbAllocContextBuffer)
4343
ASM_OFFSET( 28, 38, Thread, m_ThreadStateFlags)
4444
ASM_OFFSET( 2c, 40, Thread, m_pTransitionFrame)
45-
ASM_OFFSET( 30, 48, Thread, m_pHackPInvokeTunnel)
45+
ASM_OFFSET( 30, 48, Thread, m_pDeferredTransitionFrame)
4646
ASM_OFFSET( 40, 68, Thread, m_ppvHijackedReturnAddressLocation)
4747
ASM_OFFSET( 44, 70, Thread, m_pvHijackedReturnAddress)
4848
#ifdef HOST_64BIT

src/coreclr/nativeaot/Runtime/EHHelpers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ int32_t __stdcall RhpHardwareExceptionHandler(uintptr_t faultCode, uintptr_t fau
390390
{
391391
uintptr_t faultingIP = palContext->GetIp();
392392

393-
ICodeManager * pCodeManager = GetRuntimeInstance()->FindCodeManagerByAddress((PTR_VOID)faultingIP);
393+
ICodeManager * pCodeManager = GetRuntimeInstance()->GetCodeManagerForAddress((PTR_VOID)faultingIP);
394394
bool translateToManagedException = false;
395395
if (pCodeManager != NULL)
396396
{
@@ -471,7 +471,7 @@ int32_t __stdcall RhpVectoredExceptionHandler(PEXCEPTION_POINTERS pExPtrs)
471471

472472
uintptr_t faultingIP = pExPtrs->ContextRecord->GetIp();
473473

474-
ICodeManager * pCodeManager = GetRuntimeInstance()->FindCodeManagerByAddress((PTR_VOID)faultingIP);
474+
ICodeManager * pCodeManager = GetRuntimeInstance()->GetCodeManagerForAddress((PTR_VOID)faultingIP);
475475
bool translateToManagedException = false;
476476
if (pCodeManager != NULL)
477477
{

src/coreclr/nativeaot/Runtime/GCHelpers.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ EXTERN_C NATIVEAOT_API void __cdecl RhpCollect(uint32_t uGeneration, uint32_t uM
3131

3232
Thread * pCurThread = ThreadStore::GetCurrentThread();
3333

34-
pCurThread->SetupHackPInvokeTunnel();
34+
pCurThread->DeferTransitionFrame();
3535
pCurThread->DisablePreemptiveMode();
3636

3737
ASSERT(!pCurThread->IsDoNotTriggerGcSet());
@@ -46,7 +46,7 @@ EXTERN_C NATIVEAOT_API int64_t __cdecl RhpGetGcTotalMemory()
4646

4747
Thread * pCurThread = ThreadStore::GetCurrentThread();
4848

49-
pCurThread->SetupHackPInvokeTunnel();
49+
pCurThread->DeferTransitionFrame();
5050
pCurThread->DisablePreemptiveMode();
5151

5252
int64_t ret = GCHeapUtilities::GetGCHeap()->GetTotalBytesInUse();
@@ -61,7 +61,7 @@ EXTERN_C NATIVEAOT_API int32_t __cdecl RhpStartNoGCRegion(int64_t totalSize, UIn
6161
Thread *pCurThread = ThreadStore::GetCurrentThread();
6262
ASSERT(!pCurThread->IsCurrentThreadInCooperativeMode());
6363

64-
pCurThread->SetupHackPInvokeTunnel();
64+
pCurThread->DeferTransitionFrame();
6565
pCurThread->DisablePreemptiveMode();
6666

6767
int result = GCHeapUtilities::GetGCHeap()->StartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC);
@@ -316,7 +316,7 @@ EXTERN_C NATIVEAOT_API void RhAllocateNewArray(MethodTable* pArrayEEType, uint32
316316
{
317317
Thread* pThread = ThreadStore::GetCurrentThread();
318318

319-
pThread->SetupHackPInvokeTunnel();
319+
pThread->DeferTransitionFrame();
320320
pThread->DisablePreemptiveMode();
321321

322322
ASSERT(!pThread->IsDoNotTriggerGcSet());
@@ -330,7 +330,7 @@ EXTERN_C NATIVEAOT_API void RhAllocateNewObject(MethodTable* pEEType, uint32_t f
330330
{
331331
Thread* pThread = ThreadStore::GetCurrentThread();
332332

333-
pThread->SetupHackPInvokeTunnel();
333+
pThread->DeferTransitionFrame();
334334
pThread->DisablePreemptiveMode();
335335

336336
ASSERT(!pThread->IsDoNotTriggerGcSet());

src/coreclr/nativeaot/Runtime/ICodeManager.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
3-
#pragma once
43

5-
#define ICODEMANAGER_INCLUDED
4+
#pragma once
5+
#include <rhbinder.h>
66

77
// TODO: Debugger/DAC support (look for TODO: JIT)
88

99
struct REGDISPLAY;
1010

1111
#define GC_CALL_INTERIOR 0x1
1212
#define GC_CALL_PINNED 0x2
13-
#define GC_CALL_CHECK_APP_DOMAIN 0x4
14-
#define GC_CALL_STATIC 0x8
1513

1614
typedef void (*GCEnumCallback)(
1715
void * hCallback, // callback data
@@ -47,6 +45,27 @@ enum GCRefKind : unsigned char
4745
};
4846

4947
#ifdef TARGET_ARM64
48+
// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
49+
C_ASSERT(PTFF_X0_IS_GCREF == ((uint64_t)GCRK_Object << 32));
50+
C_ASSERT(PTFF_X0_IS_BYREF == ((uint64_t)GCRK_Byref << 32));
51+
C_ASSERT(PTFF_X1_IS_GCREF == ((uint64_t)GCRK_Scalar_Obj << 32));
52+
C_ASSERT(PTFF_X1_IS_BYREF == ((uint64_t)GCRK_Scalar_Byref << 32));
53+
54+
inline uint64_t ReturnKindToTransitionFrameFlags(GCRefKind returnKind)
55+
{
56+
if (returnKind == GCRK_Scalar)
57+
return 0;
58+
59+
return PTFF_SAVE_X0 | PTFF_SAVE_X1 | ((uint64_t)returnKind << 32);
60+
}
61+
62+
inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
63+
{
64+
GCRefKind returnKind = (GCRefKind)((transFrameFlags & (PTFF_X0_IS_GCREF | PTFF_X0_IS_BYREF | PTFF_X1_IS_GCREF | PTFF_X1_IS_BYREF)) >> 32);
65+
ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_X0) && (transFrameFlags & PTFF_SAVE_X1)));
66+
return returnKind;
67+
}
68+
5069
// Extract individual GCRefKind components from a composite return kind
5170
inline GCRefKind ExtractReg0ReturnKind(GCRefKind returnKind)
5271
{
@@ -135,7 +154,7 @@ class ICodeManager
135154

136155
virtual bool UnwindStackFrame(MethodInfo * pMethodInfo,
137156
REGDISPLAY * pRegisterSet, // in/out
138-
PTR_VOID * ppPreviousTransitionFrame) = 0; // out
157+
PInvokeTransitionFrame** ppPreviousTransitionFrame) = 0; // out
139158

140159
virtual uintptr_t GetConservativeUpperBoundForOutgoingArgs(MethodInfo * pMethodInfo,
141160
REGDISPLAY * pRegisterSet) = 0;

src/coreclr/nativeaot/Runtime/MiscHelpers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ COOP_PINVOKE_HELPER(uint32_t, RhGetLoadedOSModules, (Array * pResultArray))
109109

110110
COOP_PINVOKE_HELPER(HANDLE, RhGetOSModuleFromPointer, (PTR_VOID pPointerVal))
111111
{
112-
ICodeManager * pCodeManager = GetRuntimeInstance()->FindCodeManagerByAddress(pPointerVal);
112+
ICodeManager * pCodeManager = GetRuntimeInstance()->GetCodeManagerForAddress(pPointerVal);
113113

114114
if (pCodeManager != NULL)
115115
return (HANDLE)pCodeManager->GetOsModuleHandle();
@@ -393,7 +393,7 @@ EXTERN_C NATIVEAOT_API int32_t __cdecl RhpGetCurrentThreadStackTrace(void* pOutp
393393
{
394394
// This must be called via p/invoke rather than RuntimeImport to make the stack crawlable.
395395

396-
ThreadStore::GetCurrentThread()->SetupHackPInvokeTunnel();
396+
ThreadStore::GetCurrentThread()->DeferTransitionFrame();
397397

398398
return RhpCalculateStackTraceWorker(pOutputBuffer, outputBufferLength, pAddressInCurrentFrame);
399399
}

src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp

Lines changed: 30 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ COOP_PINVOKE_HELPER(uint8_t *, RhFindMethodStartAddress, (void * codeAddr))
5656

5757
PTR_UInt8 RuntimeInstance::FindMethodStartAddress(PTR_VOID ControlPC)
5858
{
59-
ICodeManager * pCodeManager = FindCodeManagerByAddress(ControlPC);
59+
ICodeManager * pCodeManager = GetCodeManagerForAddress(ControlPC);
6060
MethodInfo methodInfo;
6161
if (pCodeManager != NULL && pCodeManager->FindMethodInfo(ControlPC, &methodInfo))
6262
{
@@ -66,20 +66,23 @@ PTR_UInt8 RuntimeInstance::FindMethodStartAddress(PTR_VOID ControlPC)
6666
return NULL;
6767
}
6868

69-
ICodeManager * RuntimeInstance::FindCodeManagerByAddress(PTR_VOID pvAddress)
69+
// WARNING: This method is called by suspension while one thread is interrupted
70+
// in a random location, possibly holding random locks.
71+
// It is unsafe to use blocking APIs or allocate in this method.
72+
// Please ensure that all methods called by this one also have this warning.
73+
bool RuntimeInstance::IsManaged(PTR_VOID pvAddress)
7074
{
71-
ReaderWriterLock::ReadHolder read(&m_ModuleListLock);
75+
return (dac_cast<TADDR>(pvAddress) - dac_cast<TADDR>(m_pvManagedCodeStartRange) < m_cbManagedCodeRange);
76+
}
7277

73-
// TODO: ICodeManager support in DAC
74-
#ifndef DACCESS_COMPILE
75-
for (CodeManagerEntry * pEntry = m_CodeManagerList.GetHead(); pEntry != NULL; pEntry = pEntry->m_pNext)
78+
ICodeManager * RuntimeInstance::GetCodeManagerForAddress(PTR_VOID pvAddress)
79+
{
80+
if (!IsManaged(pvAddress))
7681
{
77-
if (dac_cast<TADDR>(pvAddress) - dac_cast<TADDR>(pEntry->m_pvStartRange) < pEntry->m_cbRange)
78-
return pEntry->m_pCodeManager;
82+
return NULL;
7983
}
80-
#endif
8184

82-
return NULL;
85+
return m_CodeManager;
8386
}
8487

8588
#ifndef DACCESS_COMPILE
@@ -90,7 +93,7 @@ ICodeManager * RuntimeInstance::FindCodeManagerByAddress(PTR_VOID pvAddress)
9093
ICodeManager * RuntimeInstance::FindCodeManagerForClasslibFunction(PTR_VOID address)
9194
{
9295
// Try looking up the code manager assuming the address is for code first. This is expected to be most common.
93-
ICodeManager * pCodeManager = FindCodeManagerByAddress(address);
96+
ICodeManager * pCodeManager = GetCodeManagerForAddress(address);
9497
if (pCodeManager != NULL)
9598
return pCodeManager;
9699

@@ -119,7 +122,7 @@ void * RuntimeInstance::GetClasslibFunctionFromCodeAddress(PTR_VOID address, Cla
119122

120123
PTR_UInt8 RuntimeInstance::GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID ControlPC)
121124
{
122-
ICodeManager * pCodeManager = FindCodeManagerByAddress(ControlPC);
125+
ICodeManager * pCodeManager = GetCodeManagerForAddress(ControlPC);
123126
if (pCodeManager != NULL)
124127
{
125128
PTR_UInt8 pData = (PTR_UInt8)pCodeManager->GetAssociatedData(ControlPC);
@@ -137,6 +140,10 @@ PTR_UInt8 RuntimeInstance::GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID Cont
137140

138141
GPTR_IMPL_INIT(RuntimeInstance, g_pTheRuntimeInstance, NULL);
139142

143+
// WARNING: This method is called by suspension while one thread is interrupted
144+
// in a random location, possibly holding random locks.
145+
// It is unsafe to use blocking APIs or allocate in this method.
146+
// Please ensure that all methods called by this one also have this warning.
140147
PTR_RuntimeInstance GetRuntimeInstance()
141148
{
142149
return g_pTheRuntimeInstance;
@@ -150,28 +157,21 @@ void RuntimeInstance::EnumAllStaticGCRefs(void * pfnCallback, void * pvCallbackD
150157
}
151158
}
152159

153-
void RuntimeInstance::SetLoopHijackFlags(uint32_t flag)
154-
{
155-
for (TypeManagerList::Iterator iter = m_TypeManagerList.Begin(); iter != m_TypeManagerList.End(); iter++)
156-
{
157-
iter->m_pTypeManager->SetLoopHijackFlag(flag);
158-
}
159-
}
160-
161160
RuntimeInstance::OsModuleList* RuntimeInstance::GetOsModuleList()
162161
{
163162
return dac_cast<DPTR(OsModuleList)>(dac_cast<TADDR>(this) + offsetof(RuntimeInstance, m_OsModuleList));
164163
}
165164

166165
ReaderWriterLock& RuntimeInstance::GetTypeManagerLock()
167166
{
168-
return m_ModuleListLock;
167+
return m_TypeManagerLock;
169168
}
170169

171170
#ifndef DACCESS_COMPILE
172171

173172
RuntimeInstance::RuntimeInstance() :
174173
m_pThreadStore(NULL),
174+
m_CodeManager(NULL),
175175
m_conservativeStackReportingEnabled(false),
176176
m_pUnboxingStubsRegion(NULL)
177177
{
@@ -196,56 +196,19 @@ void RuntimeInstance::EnableConservativeStackReporting()
196196
m_conservativeStackReportingEnabled = true;
197197
}
198198

199-
bool RuntimeInstance::RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
199+
void RuntimeInstance::RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
200200
{
201-
CodeManagerEntry * pEntry = new (nothrow) CodeManagerEntry();
202-
if (NULL == pEntry)
203-
return false;
201+
_ASSERTE(m_CodeManager == NULL);
202+
_ASSERTE(pCodeManager != NULL);
204203

205-
pEntry->m_pvStartRange = pvStartRange;
206-
pEntry->m_cbRange = cbRange;
207-
pEntry->m_pCodeManager = pCodeManager;
208-
209-
{
210-
ReaderWriterLock::WriteHolder write(&m_ModuleListLock);
211-
212-
m_CodeManagerList.PushHead(pEntry);
213-
}
214-
215-
return true;
216-
}
217-
218-
void RuntimeInstance::UnregisterCodeManager(ICodeManager * pCodeManager)
219-
{
220-
CodeManagerEntry * pEntry = NULL;
221-
222-
{
223-
ReaderWriterLock::WriteHolder write(&m_ModuleListLock);
224-
225-
for (CodeManagerList::Iterator i = m_CodeManagerList.Begin(), end = m_CodeManagerList.End(); i != end; i++)
226-
{
227-
if (i->m_pCodeManager == pCodeManager)
228-
{
229-
pEntry = *i;
230-
231-
m_CodeManagerList.Remove(i);
232-
break;
233-
}
234-
}
235-
}
236-
237-
ASSERT(pEntry != NULL);
238-
delete pEntry;
239-
}
240-
241-
extern "C" bool __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
242-
{
243-
return GetRuntimeInstance()->RegisterCodeManager(pCodeManager, pvStartRange, cbRange);
204+
m_CodeManager = pCodeManager;
205+
m_pvManagedCodeStartRange = pvStartRange;
206+
m_cbManagedCodeRange = cbRange;
244207
}
245208

246-
extern "C" void __stdcall UnregisterCodeManager(ICodeManager * pCodeManager)
209+
extern "C" void __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
247210
{
248-
return GetRuntimeInstance()->UnregisterCodeManager(pCodeManager);
211+
GetRuntimeInstance()->RegisterCodeManager(pCodeManager, pvStartRange, cbRange);
249212
}
250213

251214
bool RuntimeInstance::RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange)
@@ -297,7 +260,7 @@ bool RuntimeInstance::RegisterTypeManager(TypeManager * pTypeManager)
297260
pEntry->m_pTypeManager = pTypeManager;
298261

299262
{
300-
ReaderWriterLock::WriteHolder write(&m_ModuleListLock);
263+
ReaderWriterLock::WriteHolder write(&m_TypeManagerLock);
301264

302265
m_TypeManagerList.PushHead(pEntry);
303266
}

src/coreclr/nativeaot/Runtime/RuntimeInstance.h

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class RuntimeInstance
2525

2626
PTR_ThreadStore m_pThreadStore;
2727
HANDLE m_hPalInstance; // this is the HANDLE passed into DllMain
28-
ReaderWriterLock m_ModuleListLock;
28+
ReaderWriterLock m_TypeManagerLock;
2929

3030
public:
3131
struct OsModuleEntry;
@@ -40,19 +40,11 @@ class RuntimeInstance
4040
private:
4141
OsModuleList m_OsModuleList;
4242

43-
struct CodeManagerEntry;
44-
typedef DPTR(CodeManagerEntry) PTR_CodeManagerEntry;
43+
ICodeManager* m_CodeManager;
4544

46-
struct CodeManagerEntry
47-
{
48-
PTR_CodeManagerEntry m_pNext;
49-
PTR_VOID m_pvStartRange;
50-
uint32_t m_cbRange;
51-
ICodeManager * m_pCodeManager;
52-
};
53-
54-
typedef SList<CodeManagerEntry> CodeManagerList;
55-
CodeManagerList m_CodeManagerList;
45+
// we support only one code manager for now, so we just record the range.
46+
void* m_pvManagedCodeStartRange;
47+
uint32_t m_cbManagedCodeRange;
5648

5749
public:
5850
struct TypeManagerEntry
@@ -99,10 +91,9 @@ class RuntimeInstance
9991
void EnableConservativeStackReporting();
10092
bool IsConservativeStackReportingEnabled() { return m_conservativeStackReportingEnabled; }
10193

102-
bool RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
103-
void UnregisterCodeManager(ICodeManager * pCodeManager);
94+
void RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
10495

105-
ICodeManager * FindCodeManagerByAddress(PTR_VOID ControlPC);
96+
ICodeManager * GetCodeManagerForAddress(PTR_VOID ControlPC);
10697
PTR_VOID GetClasslibFunctionFromCodeAddress(PTR_VOID address, ClasslibFunctionId functionId);
10798

10899
bool RegisterTypeManager(TypeManager * pTypeManager);
@@ -113,14 +104,15 @@ class RuntimeInstance
113104
bool RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange);
114105
bool IsUnboxingStub(uint8_t* pCode);
115106

107+
bool IsManaged(PTR_VOID pvAddress);
108+
116109
static bool Initialize(HANDLE hPalInstance);
117110
void Destroy();
118111

119112
void EnumAllStaticGCRefs(void * pfnCallback, void * pvCallbackData);
120113

121114
bool ShouldHijackCallsiteForGcStress(uintptr_t CallsiteIP);
122115
bool ShouldHijackLoopForGcStress(uintptr_t CallsiteIP);
123-
void SetLoopHijackFlags(uint32_t flag);
124116
};
125117
typedef DPTR(RuntimeInstance) PTR_RuntimeInstance;
126118

0 commit comments

Comments
 (0)