Skip to content

Commit 36c507f

Browse files
authored
[NativeAOT] Simplifying access to thread static variables (#84566)
Fixes: #84373 - [x] separate "fast" inlinable case . (used for singlemodule, not dynamic cases, when optimizing) - [x] make the storage for fast threadstatics a single "combo" instance instead of array of instances.
1 parent 15aa8d3 commit 36c507f

File tree

33 files changed

+571
-160
lines changed

33 files changed

+571
-160
lines changed

src/coreclr/nativeaot/Runtime/AsmOffsets.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ ASM_OFFSET( 0, 78, Thread, m_uHijackedReturnValueFlags)
5858
ASM_OFFSET( 48, 80, Thread, m_pExInfoStackHead)
5959
ASM_OFFSET( 4c, 88, Thread, m_threadAbortException)
6060

61-
ASM_OFFSET( 50, 90, Thread, m_pThreadLocalModuleStatics)
62-
6361
ASM_SIZEOF( 14, 20, EHEnum)
6462

6563
ASM_OFFSET( 0, 0, gc_alloc_context, alloc_ptr)

src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,25 @@ RuntimeInstance::TypeManagerList& RuntimeInstance::GetTypeManagerList()
275275
return m_TypeManagerList;
276276
}
277277

278+
TypeManager* RuntimeInstance::GetSingleTypeManager()
279+
{
280+
auto head = m_TypeManagerList.GetHead();
281+
if (head != NULL && head->m_pNext == NULL)
282+
{
283+
return head->m_pTypeManager;
284+
}
285+
286+
return NULL;
287+
}
288+
289+
COOP_PINVOKE_HELPER(TypeManagerHandle, RhGetSingleTypeManager, ())
290+
{
291+
TypeManager* typeManager = GetRuntimeInstance()->GetSingleTypeManager();
292+
ASSERT(typeManager != NULL);
293+
294+
return TypeManagerHandle::Create(typeManager);
295+
}
296+
278297
// static
279298
bool RuntimeInstance::Initialize(HANDLE hPalInstance)
280299
{

src/coreclr/nativeaot/Runtime/RuntimeInstance.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class RuntimeInstance
9999

100100
bool RegisterTypeManager(TypeManager * pTypeManager);
101101
TypeManagerList& GetTypeManagerList();
102+
TypeManager* GetSingleTypeManager();
102103
OsModuleList* GetOsModuleList();
103104

104105
bool RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange);

src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,11 @@ Name dq offset AddressToExport
235235
_tls_array equ 58h ;; offsetof(TEB, ThreadLocalStoragePointer)
236236

237237
;;
238-
;; __declspec(thread) version
238+
;; __declspec(thread) variable
239239
;;
240-
INLINE_GETTHREAD macro destReg, trashReg
240+
INLINE_GET_TLS_VAR macro destReg, trashReg, variable
241241
EXTERN _tls_index : DWORD
242-
EXTERN tls_CurrentThread:DWORD
242+
EXTERN variable:DWORD
243243

244244
;;
245245
;; construct 'eax' from 'rax' so that the register size and data size match
@@ -255,11 +255,18 @@ endif
255255
mov destRegDWORD, [_tls_index]
256256
mov trashReg, gs:[_tls_array]
257257
mov trashReg, [trashReg + destReg * 8]
258-
mov destRegDWORD, SECTIONREL tls_CurrentThread
258+
mov destRegDWORD, SECTIONREL variable
259259
add destReg, trashReg
260260

261261
endm
262262

263+
;;
264+
;; __declspec(thread) tls_CurrentThread
265+
;;
266+
INLINE_GETTHREAD macro destReg, trashReg
267+
INLINE_GET_TLS_VAR destReg, trashReg, tls_CurrentThread
268+
endm
269+
263270
INLINE_THREAD_UNHIJACK macro threadReg, trashReg1, trashReg2
264271
;;
265272
;; Thread::Unhijack()

src/coreclr/nativeaot/Runtime/amd64/MiscStubs.S

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,57 +45,20 @@ LOCAL_LABEL(ProbeLoop):
4545
ret
4646
NESTED_END RhpStackProbe, _TEXT
4747

48-
NESTED_ENTRY RhpGetThreadStaticBaseForType, _TEXT, NoHandler
49-
// On entry:
50-
// rdi - TypeManagerSlot*
51-
// rsi - type index
48+
NESTED_ENTRY RhpGetInlinedThreadStaticBase, _TEXT, NoHandler
5249
// On exit:
5350
// rax - the thread static base for the given type
5451

55-
push_nonvol_reg rbx
56-
push_nonvol_reg r12
57-
58-
mov rbx, rdi // Save TypeManagerSlot*
59-
mov r12, rsi // Save type index
60-
61-
// rax = GetThread()
62-
INLINE_GETTHREAD
63-
64-
mov r8d, [rbx + 8] // Get ModuleIndex out of the TypeManagerSlot
52+
// rdi = &tls_InlinedThreadStatics
53+
INLINE_GET_TLS_VAR tls_InlinedThreadStatics
54+
mov rdi, rax
6555

6656
// get per-thread storage
67-
mov rax, [rax + OFFSETOF__Thread__m_pThreadLocalModuleStatics]
68-
69-
// get per-module storage
57+
mov rax, [rdi]
7058
test rax, rax
71-
jz LOCAL_LABEL(RhpGetThreadStaticBaseForType_RarePath)
72-
cmp r8d, [rax + OFFSETOF__Array__m_Length]
73-
jae LOCAL_LABEL(RhpGetThreadStaticBaseForType_RarePath)
74-
mov rax, [rax + r8 * 8 + 0x10]
59+
jz C_FUNC(RhpGetInlinedThreadStaticBaseSlow) // rdi contains the storage ref
7560

76-
// get the actual per-type storage
77-
test rax, rax
78-
jz LOCAL_LABEL(RhpGetThreadStaticBaseForType_RarePath)
79-
cmp r12d, [rax + OFFSETOF__Array__m_Length]
80-
jae LOCAL_LABEL(RhpGetThreadStaticBaseForType_RarePath)
81-
mov rax, [rax + r12 * 8 + 0x10]
82-
83-
// if have storage, return it
84-
test rax, rax
85-
jz LOCAL_LABEL(RhpGetThreadStaticBaseForType_RarePath)
86-
87-
.cfi_remember_state
88-
pop_nonvol_reg r12
89-
pop_nonvol_reg rbx
61+
// return it
9062
ret
63+
NESTED_END RhpGetInlinedThreadStaticBase, _TEXT
9164

92-
.cfi_restore_state
93-
.cfi_def_cfa_offset 24 // workaround cfi_restore_state bug
94-
LOCAL_LABEL(RhpGetThreadStaticBaseForType_RarePath):
95-
mov rdi, rbx // restore TypeManagerSlot*
96-
mov rsi, r12 // restore type index
97-
98-
pop_nonvol_reg r12
99-
pop_nonvol_reg rbx
100-
jmp C_FUNC(RhpGetThreadStaticBaseForTypeSlow)
101-
NESTED_END RhpGetThreadStaticBaseForType, _TEXT

src/coreclr/nativeaot/Runtime/amd64/MiscStubs.asm

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
include AsmMacros.inc
55

6-
EXTERN RhpGetThreadStaticBaseForTypeSlow : PROC
6+
EXTERN RhpGetInlinedThreadStaticBaseSlow : PROC
77

88
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
99
; The following helper will access ("probe") a word on each page of the stack
@@ -39,41 +39,20 @@ ProbeLoop:
3939

4040
LEAF_END RhpStackProbe, _TEXT
4141

42-
LEAF_ENTRY RhpGetThreadStaticBaseForType, _TEXT
43-
; On entry and thorough the procedure:
44-
; rcx - TypeManagerSlot*
45-
; rdx - type index
42+
LEAF_ENTRY RhpGetInlinedThreadStaticBase, _TEXT
4643
; On exit:
4744
; rax - the thread static base for the given type
4845

49-
;; rax = GetThread(), TRASHES r8
50-
INLINE_GETTHREAD rax, r8
51-
52-
mov r8d, [rcx + 8] ; Get ModuleIndex out of the TypeManagerSlot
46+
;; rcx = &tls_InlinedThreadStatics, TRASHES r8
47+
INLINE_GET_TLS_VAR rcx, r8, tls_InlinedThreadStatics
5348

5449
;; get per-thread storage
55-
mov rax, [rax + OFFSETOF__Thread__m_pThreadLocalModuleStatics]
56-
57-
;; get per-module storage
58-
test rax, rax
59-
jz RhpGetThreadStaticBaseForTypeSlow
60-
cmp r8d, [rax + OFFSETOF__Array__m_Length]
61-
jae RhpGetThreadStaticBaseForTypeSlow
62-
mov rax, [rax + r8 * 8 + 10h]
63-
64-
;; get the actual per-type storage
50+
mov rax, [rcx]
6551
test rax, rax
66-
jz RhpGetThreadStaticBaseForTypeSlow
67-
cmp edx, [rax + OFFSETOF__Array__m_Length]
68-
jae RhpGetThreadStaticBaseForTypeSlow
69-
mov rax, [rax + rdx * 8 + 10h]
70-
71-
;; if have storage, return it
72-
test rax, rax
73-
jz RhpGetThreadStaticBaseForTypeSlow
52+
jz RhpGetInlinedThreadStaticBaseSlow ;; rcx contains the storage ref
7453

54+
;; return it
7555
ret
76-
77-
LEAF_END RhpGetThreadStaticBaseForType, _TEXT
56+
LEAF_END RhpGetInlinedThreadStaticBase, _TEXT
7857

7958
end

src/coreclr/nativeaot/Runtime/arm64/MiscStubs.S

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,21 @@
44
#include <unixasmmacros.inc>
55
#include "AsmOffsets.inc"
66

7+
NESTED_ENTRY RhpGetInlinedThreadStaticBase, _TEXT, NoHandler
8+
// On exit:
9+
// x0 - the thread static base for the given type
10+
11+
// x1 = GetThread()
12+
INLINE_GET_TLS_VAR x1, C_FUNC(tls_InlinedThreadStatics)
13+
14+
// get per-thread storage
15+
ldr x0, [x1]
16+
cbnz x0, HaveValue
17+
mov x0, x1
18+
b C_FUNC(RhpGetInlinedThreadStaticBaseSlow)
19+
20+
HaveValue:
21+
// return it
22+
ret
23+
24+
NESTED_END RhpGetInlinedThreadStaticBase, _TEXT

src/coreclr/nativeaot/Runtime/arm64/MiscStubs.asm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@
33

44
#include "AsmMacros.h"
55

6+
EXTERN RhpGetInlinedThreadStaticBaseSlow
7+
68
TEXTAREA
79

10+
;; On exit:
11+
;; x0 - the thread static base for the given type
12+
LEAF_ENTRY RhpGetInlinedThreadStaticBase
13+
;; x1 = &tls_InlinedThreadStatics, TRASHES x2
14+
INLINE_GET_TLS_VAR x1, x2, tls_InlinedThreadStatics
15+
16+
;; get per-thread storage
17+
ldr x0, [x1]
18+
cbnz x0, HaveValue
19+
mov x0, x1
20+
b RhpGetInlinedThreadStaticBaseSlow
21+
22+
HaveValue
23+
;; return it
24+
ret
25+
LEAF_END RhpGetInlinedThreadStaticBase
26+
827
end

src/coreclr/nativeaot/Runtime/gcrhscan.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ void GCToEEInterface::GcScanRoots(EnumGcRefCallbackFunc * fn, int condemned, in
5454
else
5555
#endif
5656
{
57+
InlinedThreadStaticRoot* pRoot = pThread->GetInlinedThreadStaticList();
58+
while (pRoot != NULL)
59+
{
60+
STRESS_LOG2(LF_GC | LF_GCROOTS, LL_INFO100, "{ Scanning Thread's %p inline thread statics root %p. \n", pThread, pRoot);
61+
GcEnumObject(&pRoot->m_threadStaticsBase, 0 /*flags*/, fn, sc);
62+
pRoot = pRoot->m_next;
63+
}
64+
5765
STRESS_LOG1(LF_GC | LF_GCROOTS, LL_INFO100, "{ Scanning Thread's %p thread statics root. \n", pThread);
5866
GcEnumObject(pThread->GetThreadStaticStorage(), 0 /*flags*/, fn, sc);
5967

src/coreclr/nativeaot/Runtime/thread.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ void Thread::Construct()
284284

285285
// Everything else should be initialized to 0 via the static initialization of tls_CurrentThread.
286286

287-
ASSERT(m_pThreadLocalModuleStatics == NULL);
287+
ASSERT(m_pThreadLocalStatics == NULL);
288+
ASSERT(m_pInlinedThreadLocalStatics == NULL);
288289

289290
ASSERT(m_pGCFrameRegistrations == NULL);
290291

@@ -1266,15 +1267,33 @@ COOP_PINVOKE_HELPER(Object *, RhpGetThreadAbortException, ())
12661267

12671268
Object** Thread::GetThreadStaticStorage()
12681269
{
1269-
return &m_pThreadLocalModuleStatics;
1270+
return &m_pThreadLocalStatics;
12701271
}
12711272

12721273
COOP_PINVOKE_HELPER(Object**, RhGetThreadStaticStorage, ())
12731274
{
1274-
Thread * pCurrentThread = ThreadStore::RawGetCurrentThread();
1275+
Thread* pCurrentThread = ThreadStore::RawGetCurrentThread();
12751276
return pCurrentThread->GetThreadStaticStorage();
12761277
}
12771278

1279+
InlinedThreadStaticRoot* Thread::GetInlinedThreadStaticList()
1280+
{
1281+
return m_pInlinedThreadLocalStatics;
1282+
}
1283+
1284+
void Thread::RegisterInlinedThreadStaticRoot(InlinedThreadStaticRoot* newRoot)
1285+
{
1286+
ASSERT(newRoot->m_next == NULL);
1287+
newRoot->m_next = m_pInlinedThreadLocalStatics;
1288+
m_pInlinedThreadLocalStatics = newRoot;
1289+
}
1290+
1291+
COOP_PINVOKE_HELPER(void, RhRegisterInlinedThreadStaticRoot, (Object** root))
1292+
{
1293+
Thread* pCurrentThread = ThreadStore::RawGetCurrentThread();
1294+
pCurrentThread->RegisterInlinedThreadStaticRoot((InlinedThreadStaticRoot*)root);
1295+
}
1296+
12781297
// This is function is used to quickly query a value that can uniquely identify a thread
12791298
COOP_PINVOKE_HELPER(uint8_t*, RhCurrentNativeThreadId, ())
12801299
{

0 commit comments

Comments
 (0)