Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NativeAOT] ThreadStatics part 2 #87148

Merged
merged 24 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bac3227
introduced TlsRootNode
VSadov Jun 2, 2023
1ff41b9
remove RhGetInlinedThreadStaticStorage
VSadov Jun 4, 2023
e1d070d
get rid of c++ tls_InlinedThreadStatics
VSadov Jun 4, 2023
f5812e7
remove GetSingleTypeManager
VSadov Jun 4, 2023
aeee609
use .tdata on unix
VSadov Jun 5, 2023
447969c
do not switch OSX just yet
VSadov Jun 5, 2023
860ab1a
bring back tls_InlinedThreadStatics on Windows temporarily
VSadov Jun 8, 2023
4e3a8e5
emit inline access on windows
VSadov Jun 8, 2023
d96709c
unify tls sections
VSadov Jun 8, 2023
790dc9b
inline TLS access on linux-x64
VSadov Jun 8, 2023
7a4d903
no need for RhpGetInlinedThreadStaticBase when inlining the access
VSadov Jun 9, 2023
a585ff6
some comments and TODOs
VSadov Jun 9, 2023
62b60de
enable ILC generation of tls_InlinedThreadStatics on win-x64
VSadov Jun 9, 2023
2921dc4
allow storage inlining in multimodule case when TLS access is inlined
VSadov Jun 12, 2023
97cf520
disable "Initial Exec" optimizations
VSadov Jun 12, 2023
8dfa7e9
some comments and formatting
VSadov Jun 14, 2023
cdfd0a3
follow up change that was suggested in the previous PR
VSadov Jun 14, 2023
b650cbb
Remove use of RhpGetInlinedThreadstaticBase on x64
VSadov Jun 15, 2023
f9c5f01
Remove use of RhpGetInlinedThreadStaticBase on arm64
VSadov Jun 15, 2023
bca1c3b
removed tls_InlinedThreadStatics
VSadov Jun 15, 2023
ff29a93
a few cleanups/typos
VSadov Jun 15, 2023
6065863
fix after rebase
VSadov Jun 19, 2023
e48b82b
inlined TLS support for linux-arm64
VSadov Jun 19, 2023
dab05cf
PR feedback
VSadov Jun 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,25 +267,6 @@ RuntimeInstance::TypeManagerList& RuntimeInstance::GetTypeManagerList()
return m_TypeManagerList;
}

TypeManager* RuntimeInstance::GetSingleTypeManager()
{
auto head = m_TypeManagerList.GetHead();
if (head != NULL && head->m_pNext == NULL)
{
return head->m_pTypeManager;
}

return NULL;
}

COOP_PINVOKE_HELPER(TypeManagerHandle, RhGetSingleTypeManager, ())
{
TypeManager* typeManager = GetRuntimeInstance()->GetSingleTypeManager();
ASSERT(typeManager != NULL);

return TypeManagerHandle::Create(typeManager);
}

// static
bool RuntimeInstance::Initialize(HANDLE hPalInstance)
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/nativeaot/Runtime/RuntimeInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ class RuntimeInstance

bool RegisterTypeManager(TypeManager * pTypeManager);
TypeManagerList& GetTypeManagerList();
TypeManager* GetSingleTypeManager();
OsModuleList* GetOsModuleList();

bool RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange);
Expand Down
19 changes: 0 additions & 19 deletions src/coreclr/nativeaot/Runtime/amd64/MiscStubs.S
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,3 @@ LOCAL_LABEL(ProbeLoop):
RESET_FRAME_WITH_RBP
ret
NESTED_END RhpStackProbe, _TEXT

#ifndef TARGET_ANDROID
NESTED_ENTRY RhpGetInlinedThreadStaticBase, _TEXT, NoHandler
// On exit:
// rax - the thread static base for the given type

// rdi = &tls_InlinedThreadStatics
INLINE_GET_TLS_VAR tls_InlinedThreadStatics
mov rdi, rax

// get per-thread storage
mov rax, [rdi]
test rax, rax
jz C_FUNC(RhpGetInlinedThreadStaticBaseSlow) // rdi contains the storage ref

// return it
ret
NESTED_END RhpGetInlinedThreadStaticBase, _TEXT
#endif
18 changes: 0 additions & 18 deletions src/coreclr/nativeaot/Runtime/amd64/MiscStubs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

include AsmMacros.inc

EXTERN RhpGetInlinedThreadStaticBaseSlow : PROC

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The following helper will access ("probe") a word on each page of the stack
; starting with the page right beneath rsp down to the one pointed to by r11.
Expand Down Expand Up @@ -39,20 +37,4 @@ ProbeLoop:

LEAF_END RhpStackProbe, _TEXT

LEAF_ENTRY RhpGetInlinedThreadStaticBase, _TEXT
; On exit:
; rax - the thread static base for the given type

;; rcx = &tls_InlinedThreadStatics, TRASHES r8
INLINE_GET_TLS_VAR rcx, r8, tls_InlinedThreadStatics

;; get per-thread storage
mov rax, [rcx]
test rax, rax
jz RhpGetInlinedThreadStaticBaseSlow ;; rcx contains the storage ref

;; return it
ret
LEAF_END RhpGetInlinedThreadStaticBase, _TEXT

end
21 changes: 0 additions & 21 deletions src/coreclr/nativeaot/Runtime/arm64/MiscStubs.S
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,3 @@

#include <unixasmmacros.inc>
#include "AsmOffsets.inc"

#ifndef TARGET_ANDROID
NESTED_ENTRY RhpGetInlinedThreadStaticBase, _TEXT, NoHandler
// On exit:
// x0 - the thread static base for the given type

// x1 = GetThread()
INLINE_GET_TLS_VAR x1, C_FUNC(tls_InlinedThreadStatics)

// get per-thread storage
ldr x0, [x1]
cbnz x0, HaveValue
mov x0, x1
b C_FUNC(RhpGetInlinedThreadStaticBaseSlow)

HaveValue:
// return it
ret

NESTED_END RhpGetInlinedThreadStaticBase, _TEXT
#endif
19 changes: 0 additions & 19 deletions src/coreclr/nativeaot/Runtime/arm64/MiscStubs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,6 @@

#include "AsmMacros.h"

EXTERN RhpGetInlinedThreadStaticBaseSlow

TEXTAREA

;; On exit:
;; x0 - the thread static base for the given type
LEAF_ENTRY RhpGetInlinedThreadStaticBase
;; x1 = &tls_InlinedThreadStatics, TRASHES x2
INLINE_GET_TLS_VAR x1, x2, tls_InlinedThreadStatics

;; get per-thread storage
ldr x0, [x1]
cbnz x0, HaveValue
mov x0, x1
b RhpGetInlinedThreadStaticBaseSlow

HaveValue
;; return it
ret
LEAF_END RhpGetInlinedThreadStaticBase

end
10 changes: 0 additions & 10 deletions src/coreclr/nativeaot/Runtime/threadstore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,23 +430,13 @@ C_ASSERT(sizeof(Thread) == sizeof(ThreadBuffer));

#ifndef _MSC_VER
__thread ThreadBuffer tls_CurrentThread;

// the root of inlined threadstatics storage
// there is only one now,
// eventually this will be emitted by ILC and we may have more than one such variable
__thread InlinedThreadStaticRoot tls_InlinedThreadStatics;
#endif

EXTERN_C ThreadBuffer* RhpGetThread()
{
return &tls_CurrentThread;
}

COOP_PINVOKE_HELPER(Object**, RhGetInlinedThreadStaticStorage, ())
{
return &tls_InlinedThreadStatics.m_threadStaticsBase;
}

#endif // !DACCESS_COMPILE

#ifdef _WIN32
Expand Down
6 changes: 0 additions & 6 deletions src/coreclr/nativeaot/Runtime/threadstore.inl
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@
#ifdef _MSC_VER
// a workaround to prevent tls_CurrentThread from becoming dynamically checked/initialized.
EXTERN_C __declspec(selectany) __declspec(thread) ThreadBuffer tls_CurrentThread;

// the root of inlined threadstatics storage
// there is only one now,
// eventually this will be emitted by ILC and we may have more than one such variable
EXTERN_C __declspec(selectany) __declspec(thread) InlinedThreadStaticRoot tls_InlinedThreadStatics;
#else
EXTERN_C __thread ThreadBuffer tls_CurrentThread;
EXTERN_C __thread InlinedThreadStaticRoot tls_InlinedThreadStatics;
#endif

// static
Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,12 @@ C_FUNC(\Name):
movq _\Var@TLVP(%rip), %rdi
callq *(%rdi)
#else
leaq \Var@TLSLD(%rip), %rdi
.byte 0x66 // data16 prefix - padding to have space for linker relaxations
leaq \Var@TLSGD(%rip), %rdi
jkotas marked this conversation as resolved.
Show resolved Hide resolved
.byte 0x66 //
.byte 0x66 //
.byte 0x48 // rex.W prefix, also for padding
callq __tls_get_addr@PLT
addq $\Var@DTPOFF, %rax
#endif
.intel_syntax noprefix
.endm
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,35 @@ namespace Internal.Runtime
/// </summary>
internal static class ThreadStatics
{
[ThreadStatic]
private static object t_inlinedThreadStaticBase;

/// <summary>
/// This method is called from a ReadyToRun helper to get base address of thread
/// static storage for the given type.
/// </summary>
internal static unsafe object GetThreadStaticBaseForType(TypeManagerSlot* pModuleData, int typeTlsIndex)
{
if (typeTlsIndex >= 0)
return GetUninlinedThreadStaticBaseForType(pModuleData, typeTlsIndex);

ref object? threadStorage = ref RuntimeImports.RhGetInlinedThreadStaticStorage();
if (threadStorage != null)
return threadStorage;
if (typeTlsIndex < 0)
return t_inlinedThreadStaticBase;

return GetInlinedThreadStaticBaseSlow(ref threadStorage);
return GetUninlinedThreadStaticBaseForType(pModuleData, typeTlsIndex);
}

[RuntimeExport("RhpGetInlinedThreadStaticBaseSlow")]
internal static unsafe object GetInlinedThreadStaticBaseSlow(ref object? threadStorage)
{
Debug.Assert(threadStorage == null);
// Allocate an object that will represent a memory block for all thread static fields
TypeManagerHandle typeManager = RuntimeImports.RhGetSingleTypeManager();
TypeManagerHandle typeManager = (new object()).GetMethodTable()->TypeManager;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
TypeManagerHandle typeManager = (new object()).GetMethodTable()->TypeManager;
TypeManagerHandle typeManager = EETypePtr.EETypePtrOf<object>().ToPointer()->TypeManager;

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also, I have noticed that we have unused broken MethodTableOf<T> - you can delete it while you are on it.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there might be a way to just fetch the method table of the type, but did not want to involve anything reflection-like by accident. This code will run once per thread, so allocating one object seemed both simple and affordable.
I did not know about EETypePtrOf.

object threadStaticBase = AllocateThreadStaticStorageForType(typeManager, 0);

// register the storage location with the thread for GC reporting.
RuntimeImports.RhRegisterInlinedThreadStaticRoot(ref threadStorage);

// assign the storage block to the storage variable and return
threadStorage = threadStaticBase;
t_inlinedThreadStaticBase = threadStaticBase;

return threadStaticBase;
}

Expand All @@ -55,13 +55,13 @@ internal static unsafe object GetUninlinedThreadStaticBaseForType(TypeManagerSlo
int moduleIndex = pModuleData->ModuleIndex;
Debug.Assert(moduleIndex >= 0);

object[][] threadStorage = RuntimeImports.RhGetThreadStaticStorage();
if (threadStorage != null && threadStorage.Length > moduleIndex)
object[][] perThreadStorage = RuntimeImports.RhGetThreadStaticStorage();
if (perThreadStorage != null && perThreadStorage.Length > moduleIndex)
{
object[] moduleStorage = threadStorage[moduleIndex];
if (moduleStorage != null && moduleStorage.Length > typeTlsIndex)
object[] perModuleStorage = perThreadStorage[moduleIndex];
if (perModuleStorage != null && perModuleStorage.Length > typeTlsIndex)
{
object threadStaticBase = moduleStorage[typeTlsIndex];
object threadStaticBase = perModuleStorage[typeTlsIndex];
if (threadStaticBase != null)
{
return threadStaticBase;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,6 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
[RuntimeImport(RuntimeLibrary, "RhGetThreadStaticStorage")]
internal static extern ref object[][] RhGetThreadStaticStorage();

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetInlinedThreadStaticStorage")]
internal static extern ref object? RhGetInlinedThreadStaticStorage();

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhRegisterInlinedThreadStaticRoot")]
internal static extern void RhRegisterInlinedThreadStaticRoot(ref object? root);
Expand Down Expand Up @@ -592,10 +588,6 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
[RuntimeImport(RuntimeLibrary, "RhGetTargetOfUnboxingAndInstantiatingStub")]
public static extern IntPtr RhGetTargetOfUnboxingAndInstantiatingStub(IntPtr pCode);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetSingleTypeManager")]
public static extern TypeManagerHandle RhGetSingleTypeManager();

//
// EH helpers
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
case RelocType.IMAGE_REL_BASED_ABSOLUTE:
case RelocType.IMAGE_REL_BASED_HIGHLOW:
case RelocType.IMAGE_REL_SECREL:
case RelocType.IMAGE_REL_TLSGD:
case RelocType.IMAGE_REL_TPOFF:
case RelocType.IMAGE_REL_FILE_ABSOLUTE:
case RelocType.IMAGE_REL_BASED_ADDR32NB:
case RelocType.IMAGE_REL_SYMBOL_SIZE:
Expand All @@ -305,6 +307,14 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:

case RelocType.IMAGE_REL_AARCH64_TLSDESC_ADR_PAGE21:
case RelocType.IMAGE_REL_AARCH64_TLSDESC_LD64_LO12:
case RelocType.IMAGE_REL_AARCH64_TLSDESC_ADD_LO12:
case RelocType.IMAGE_REL_AARCH64_TLSDESC_CALL:
case RelocType.IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_HI12:
case RelocType.IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_LO12_NC:

case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
Debug.Assert(delta == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public bool IsStandardSection
public static readonly ObjectNodeSection ReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly);
public static readonly ObjectNodeSection FoldableReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly);
public static readonly ObjectNodeSection TextSection = new ObjectNodeSection("text", SectionType.Executable);
public static readonly ObjectNodeSection TLSSection = new ObjectNodeSection("TLS", SectionType.Writeable);
public static readonly ObjectNodeSection TLSSection = new ObjectNodeSection("tdata", SectionType.Writeable);
public static readonly ObjectNodeSection BssSection = new ObjectNodeSection("bss", SectionType.Uninitialized);
public static readonly ObjectNodeSection HydrationTargetSection = new ObjectNodeSection("hydrated", SectionType.Uninitialized);
public static readonly ObjectNodeSection ManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,34 @@ public enum RelocType
// This is a special NGEN-specific relocation type
// for relative pointer (used to make NGen relocation
// section smaller)
IMAGE_REL_SECREL = 0x80, // 32 bit offset from base of section containing target

IMAGE_REL_BASED_ARM64_PAGEBASE_REL21 = 0x81, // ADRP
IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A = 0x82, // ADD/ADDS (immediate) with zero shift, for page offset
IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L = 0x83, // LDR (indexed, unsigned immediate), for page offset

//
// Relocation operators related to TLS access
//

// Windows x64
IMAGE_REL_SECREL = 0x104,

// Linux x64
// GD model
IMAGE_REL_TLSGD = 0x105,
// LE model
IMAGE_REL_TPOFF = 0x106,

// Linux arm64
// TLSDESC (dynamic)
IMAGE_REL_AARCH64_TLSDESC_ADR_PAGE21 = 0x107,
IMAGE_REL_AARCH64_TLSDESC_LD64_LO12 = 0x108,
IMAGE_REL_AARCH64_TLSDESC_ADD_LO12 = 0x109,
IMAGE_REL_AARCH64_TLSDESC_CALL = 0x10A,
// LE model
IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_HI12 = 0x10B,
IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 0x10C,

//
// Relocations for R2R image production
//
Expand Down Expand Up @@ -459,6 +481,8 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
case RelocType.IMAGE_REL_BASED_REL32:
case RelocType.IMAGE_REL_BASED_RELPTR32:
case RelocType.IMAGE_REL_SECREL:
case RelocType.IMAGE_REL_TLSGD:
case RelocType.IMAGE_REL_TPOFF:
case RelocType.IMAGE_REL_FILE_ABSOLUTE:
case RelocType.IMAGE_REL_SYMBOL_SIZE:
return *(int*)location;
Expand All @@ -475,6 +499,20 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
return GetArm64Rel21((uint*)location);
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
return GetArm64Rel12((uint*)location);
case RelocType.IMAGE_REL_AARCH64_TLSDESC_LD64_LO12:
case RelocType.IMAGE_REL_AARCH64_TLSDESC_ADD_LO12:
case RelocType.IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_HI12:
case RelocType.IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
// TLS relocs do not have offsets
Debug.Assert((GetArm64Rel12((uint*)location) & 0xFF) == 0);
return 0;
case RelocType.IMAGE_REL_AARCH64_TLSDESC_ADR_PAGE21:
// TLS relocs do not have offsets
Debug.Assert((GetArm64Rel21((uint*)location) & 0xFF) == 0);
return 0;
case RelocType.IMAGE_REL_AARCH64_TLSDESC_CALL:
// TLS relocs do not have offsets
return 0;
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
return (long)GetLoongArch64PC12((uint*)location);
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
Expand Down
Loading