Skip to content

Commit

Permalink
Create portable box helper and wrap the thread-local alloc context in…
Browse files Browse the repository at this point in the history
… a struct (#103607)

* Create a portable box helper and remove the assembly-based one. The codegen is close, but we don't need to be exact as most box operations are inlined anyway

* Create a new struct we can put GC-focused thread-locals on (like GC mode, frame/gc frame chains, etc)

* Update jithelpers.cpp

Co-authored-by: Jan Kotas <[email protected]>

* GCThreadLocals/ThreadBuffer->RuntimeThreadLocals

* Change pointer to be to RuntimeThreadLocals

* Update cDAC

* Update src/native/managed/cdacreader/src/Data/RuntimeThreadLocals.cs

Co-authored-by: Elinor Fung <[email protected]>

---------

Co-authored-by: Jan Kotas <[email protected]>
Co-authored-by: Elinor Fung <[email protected]>
  • Loading branch information
3 people authored and pull[bot] committed Jul 22, 2024
1 parent 292934c commit 7082a89
Show file tree
Hide file tree
Showing 29 changed files with 156 additions and 168 deletions.
7 changes: 6 additions & 1 deletion src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ CDAC_TYPE_FIELD(Thread, /*uint32*/, Id, cdac_offsets<Thread>::Id)
CDAC_TYPE_FIELD(Thread, /*nuint*/, OSId, cdac_offsets<Thread>::OSId)
CDAC_TYPE_FIELD(Thread, /*uint32*/, State, cdac_offsets<Thread>::State)
CDAC_TYPE_FIELD(Thread, /*uint32*/, PreemptiveGCDisabled, cdac_offsets<Thread>::PreemptiveGCDisabled)
CDAC_TYPE_FIELD(Thread, /*pointer*/, AllocContext, cdac_offsets<Thread>::AllocContext)
CDAC_TYPE_FIELD(Thread, /*pointer*/, RuntimeThreadLocals, cdac_offsets<Thread>::RuntimeThreadLocals)
CDAC_TYPE_FIELD(Thread, /*pointer*/, Frame, cdac_offsets<Thread>::Frame)
CDAC_TYPE_FIELD(Thread, /*pointer*/, ExceptionTracker, cdac_offsets<Thread>::ExceptionTracker)
CDAC_TYPE_FIELD(Thread, GCHandle, GCHandle, cdac_offsets<Thread>::ExposedObject)
Expand All @@ -130,6 +130,11 @@ CDAC_TYPE_FIELD(ThreadStore, /*int32*/, PendingCount, cdac_offsets<ThreadStore>:
CDAC_TYPE_FIELD(ThreadStore, /*int32*/, DeadCount, cdac_offsets<ThreadStore>::DeadCount)
CDAC_TYPE_END(ThreadStore)

CDAC_TYPE_BEGIN(RuntimeThreadLocals)
CDAC_TYPE_INDETERMINATE(RuntimeThreadLocals)
CDAC_TYPE_FIELD(RuntimeThreadLocals, AllocContext, AllocContext, offsetof(RuntimeThreadLocals, alloc_context))
CDAC_TYPE_END(RuntimeThreadLocals)

CDAC_TYPE_BEGIN(GCAllocContext)
CDAC_TYPE_INDETERMINATE(GCAllocContext)
CDAC_TYPE_FIELD(GCAllocContext, /*pointer*/, Pointer, offsetof(gc_alloc_context, alloc_ptr))
Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/nativeaot/Runtime/DebugHeader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,12 @@ extern "C" void PopulateDebugHeaders()
MAKE_SIZE_ENTRY(ThreadStore);
MAKE_DEBUG_FIELD_ENTRY(ThreadStore, m_ThreadList);

MAKE_SIZE_ENTRY(ThreadBuffer);
MAKE_DEBUG_FIELD_ENTRY(ThreadBuffer, m_pNext);
MAKE_DEBUG_FIELD_ENTRY(ThreadBuffer, m_rgbAllocContextBuffer);
MAKE_DEBUG_FIELD_ENTRY(ThreadBuffer, m_threadId);
MAKE_DEBUG_FIELD_ENTRY(ThreadBuffer, m_pThreadStressLog);
MAKE_DEBUG_FIELD_ENTRY(ThreadBuffer, m_pExInfoStackHead);
MAKE_SIZE_ENTRY(RuntimeThreadLocals);
MAKE_DEBUG_FIELD_ENTRY(RuntimeThreadLocals, m_pNext);
MAKE_DEBUG_FIELD_ENTRY(RuntimeThreadLocals, m_rgbAllocContextBuffer);
MAKE_DEBUG_FIELD_ENTRY(RuntimeThreadLocals, m_threadId);
MAKE_DEBUG_FIELD_ENTRY(RuntimeThreadLocals, m_pThreadStressLog);
MAKE_DEBUG_FIELD_ENTRY(RuntimeThreadLocals, m_pExInfoStackHead);

MAKE_SIZE_ENTRY(ExInfo);
MAKE_DEBUG_FIELD_ENTRY(ExInfo, m_pPrevExInfo);
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/nativeaot/Runtime/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ struct InlinedThreadStaticRoot
TypeManager* m_typeManager;
};

struct ThreadBuffer
struct RuntimeThreadLocals
{
uint8_t m_rgbAllocContextBuffer[SIZEOF_ALLOC_CONTEXT];
uint32_t volatile m_ThreadStateFlags; // see Thread::ThreadStateFlags enum
Expand Down Expand Up @@ -126,7 +126,7 @@ struct ReversePInvokeFrame
Thread* m_savedThread;
};

class Thread : private ThreadBuffer
class Thread : private RuntimeThreadLocals
{
friend class AsmOffsets;
friend struct DefaultSListTraits<Thread>;
Expand Down Expand Up @@ -158,7 +158,7 @@ class Thread : private ThreadBuffer
// For suspension APCs it is mostly harmless, but wasteful and in extreme
// cases may force the target thread into stack oveflow.
// We use this flag to avoid sending another APC when one is still going through.
//
//
// On Unix this is an optimization to not queue up more signals when one is
// still being processed.
};
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/nativeaot/Runtime/threadstore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,13 @@ FCIMPL1(void, RhpCancelThreadAbort, void* thread)
}
FCIMPLEND

C_ASSERT(sizeof(Thread) == sizeof(ThreadBuffer));
C_ASSERT(sizeof(Thread) == sizeof(RuntimeThreadLocals));

#ifndef _MSC_VER
__thread ThreadBuffer tls_CurrentThread;
__thread RuntimeThreadLocals tls_CurrentThread;
#endif

EXTERN_C ThreadBuffer* RhpGetThread()
EXTERN_C RuntimeThreadLocals* RhpGetThread()
{
return &tls_CurrentThread;
}
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/nativeaot/Runtime/threadstore.inl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

#ifdef _MSC_VER
// a workaround to prevent tls_CurrentThread from becoming dynamically checked/initialized.
EXTERN_C __declspec(selectany) __declspec(thread) ThreadBuffer tls_CurrentThread;
EXTERN_C __declspec(selectany) __declspec(thread) RuntimeThreadLocals tls_CurrentThread;
#else
EXTERN_C __thread ThreadBuffer tls_CurrentThread;
EXTERN_C __thread RuntimeThreadLocals tls_CurrentThread;
#endif

// static
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
${ARCH_SOURCES_DIR}/GenericCLRToCOMCallStubs.asm
${ARCH_SOURCES_DIR}/getstate.asm
${ARCH_SOURCES_DIR}/JitHelpers_Fast.asm
${ARCH_SOURCES_DIR}/JitHelpers_FastMP.asm
${ARCH_SOURCES_DIR}/JitHelpers_FastWriteBarriers.asm
${ARCH_SOURCES_DIR}/JitHelpers_SingleAppDomain.asm
${ARCH_SOURCES_DIR}/JitHelpers_Slow.asm
Expand Down
20 changes: 0 additions & 20 deletions src/coreclr/vm/amd64/AsmMacros.inc
Original file line number Diff line number Diff line change
Expand Up @@ -206,26 +206,6 @@ INLINE_GETTHREAD macro Reg

endm

;
; Inlined macro to get the current thread's allocation context
; Trashes rax and r11
;

INLINE_GET_ALLOC_CONTEXT macro Reg

EXTERN _tls_index: DWORD
EXTERN t_thread_alloc_context: DWORD

mov r11d, [_tls_index]
mov rax, gs:[OFFSET__TEB__ThreadLocalStoragePointer]
mov rax, [rax + r11 * 8]
mov r11d, SECTIONREL t_thread_alloc_context
add rax, r11
mov Reg, rax

endm


; if you change this code there will be corresponding code in JITInterfaceGen.cpp which will need to be changed
;

Expand Down
75 changes: 0 additions & 75 deletions src/coreclr/vm/amd64/JitHelpers_FastMP.asm

This file was deleted.

1 change: 1 addition & 0 deletions src/coreclr/vm/arm/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1776,6 +1776,7 @@ void InitJITHelpers1()
SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable);
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable);

ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
}
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/arm64/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,7 @@ void InitJITHelpers1()
SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable);
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable);

ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/comutilnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ FCIMPL0(INT64, GCInterface::GetAllocatedBytesForCurrentThread)

INT64 currentAllocated = 0;
Thread *pThread = GetThread();
gc_alloc_context* ac = &t_thread_alloc_context;
gc_alloc_context* ac = &t_runtime_thread_locals.alloc_context;
currentAllocated = ac->alloc_bytes + ac->alloc_bytes_uoh - (ac->alloc_limit - ac->alloc_ptr);

return currentAllocated;
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/vm/gccover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ void GCCoverageInfo::SprinkleBreakpoints(
{
case InstructionType::Call_IndirectUnconditional:
#ifdef TARGET_AMD64
if(!(EECodeManager::InterruptibleSafePointsEnabled() && safePointDecoder.AreSafePointsInterruptible()) &&
if(!(EECodeManager::InterruptibleSafePointsEnabled() && safePointDecoder.AreSafePointsInterruptible()) &&
safePointDecoder.IsSafePoint((UINT32)(cur + len - codeStart + regionOffsetAdj)))
#endif
{
Expand Down Expand Up @@ -1349,7 +1349,7 @@ void RemoveGcCoverageInterrupt(TADDR instrPtr, BYTE * savedInstrPtr, GCCoverageI
#endif

#ifdef TARGET_X86
// Epilog checking relies on precise control of when instrumentation for the first prolog
// Epilog checking relies on precise control of when instrumentation for the first prolog
// instruction is enabled or disabled. In particular, if a function has multiple epilogs, or
// the first execution of the function terminates via an exception, and subsequent completions
// do not, then the function may trigger a false stress fault if epilog checks are not disabled.
Expand Down Expand Up @@ -1859,7 +1859,7 @@ void DoGcStress (PCONTEXT regs, NativeCodeVersion nativeCodeVersion)
// BUG(github #10318) - when not using allocation contexts, the alloc lock
// must be acquired here. Until fixed, this assert prevents random heap corruption.
assert(GCHeapUtilities::UseThreadAllocationContexts());
GCHeapUtilities::GetGCHeap()->StressHeap(&t_thread_alloc_context);
GCHeapUtilities::GetGCHeap()->StressHeap(&t_runtime_thread_locals.alloc_context);

// StressHeap can exit early w/o forcing a SuspendEE to trigger the instruction update
// We can not rely on the return code to determine if the instruction update happened
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ gc_alloc_context * GCToEEInterface::GetAllocContext()
return nullptr;
}

return &t_thread_alloc_context;
return &t_runtime_thread_locals.alloc_context;
}

void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param)
Expand Down
10 changes: 2 additions & 8 deletions src/coreclr/vm/gcheaputilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ bool g_sw_ww_enabled_for_gc_heap = false;

GVAL_IMPL_INIT(gc_alloc_context, g_global_alloc_context, {});

// on MP systems, each thread has its own allocation chunk so we can avoid
// lock prefixes and expensive MP cache snooping stuff
#ifndef _MSC_VER
__thread gc_alloc_context t_thread_alloc_context;
#endif

enum GC_LOAD_STATUS {
GC_LOAD_STATUS_BEFORE_START,
GC_LOAD_STATUS_START,
Expand Down Expand Up @@ -182,9 +176,9 @@ HMODULE LoadStandaloneGc(LPCWSTR libFileName, LPCWSTR libFilePath)
// The libFileName originates either from an environment variable or from the runtimeconfig.json
// These are trusted locations, and therefore even if it is a relative path, there is no security risk.
//
// However, users often don't know the absolute path to their coreclr module, especially on production.
// However, users often don't know the absolute path to their coreclr module, especially on production.
// Therefore we allow referencing it from an arbitrary location through libFilePath instead. Users, however
// are warned that they should keep the file in a secure location such that it cannot be tampered.
// are warned that they should keep the file in a secure location such that it cannot be tampered.
//
if (!ValidateModuleName(libFileName))
{
Expand Down
8 changes: 0 additions & 8 deletions src/coreclr/vm/gcheaputilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ GVAL_DECL(gc_alloc_context, g_global_alloc_context);
}
#endif // !DACCESS_COMPILE

// on MP systems, each thread has its own allocation chunk so we can avoid
// lock prefixes and expensive MP cache snooping stuff
#ifdef _MSC_VER
EXTERN_C __declspec(selectany) __declspec(thread) gc_alloc_context t_thread_alloc_context;
#else
EXTERN_C __thread gc_alloc_context t_thread_alloc_context;
#endif

extern "C" uint32_t* g_card_bundle_table;
extern "C" uint8_t* g_ephemeral_low;
extern "C" uint8_t* g_ephemeral_high;
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/gchelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ inline gc_alloc_context* GetThreadAllocContext()

assert(GCHeapUtilities::UseThreadAllocationContexts());

return &t_thread_alloc_context;
return &t_runtime_thread_locals.alloc_context;
}

// When not using per-thread allocation contexts, we (the EE) need to take care that
Expand Down Expand Up @@ -1484,4 +1484,4 @@ void ErectWriteBarrierForMT(MethodTable **dst, MethodTable *ref)
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/coreclr/vm/gcstress.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ namespace _GCStress
// BUG(github #10318) - when not using allocation contexts, the alloc lock
// must be acquired here. Until fixed, this assert prevents random heap corruption.
_ASSERTE(GCHeapUtilities::UseThreadAllocationContexts());
GCHeapUtilities::GetGCHeap()->StressHeap(&t_thread_alloc_context);
GCHeapUtilities::GetGCHeap()->StressHeap(&t_runtime_thread_locals.alloc_context);
}

FORCEINLINE
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/vm/i386/stublinkerx86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2434,7 +2434,7 @@ namespace
{
gc_alloc_context* STDCALL GetAllocContextHelper()
{
return &t_thread_alloc_context;
return &t_runtime_thread_locals.alloc_context;
}
}
#endif
Expand Down Expand Up @@ -2490,8 +2490,8 @@ VOID StubLinkerCPU::X86EmitCurrentThreadAllocContextFetch(X86Reg dstreg, unsigne

X86EmitIndexRegLoad(dstreg, dstreg, sizeof(void *) * _tls_index);

_ASSERTE(Thread::GetOffsetOfThreadStatic(&t_thread_alloc_context) < INT_MAX);
X86EmitAddReg(dstreg, (int32_t)Thread::GetOffsetOfThreadStatic(&t_thread_alloc_context));
_ASSERTE(Thread::GetOffsetOfThreadStatic(&t_runtime_thread_locals.alloc_context) < INT_MAX);
X86EmitAddReg(dstreg, (int32_t)Thread::GetOffsetOfThreadStatic(&t_runtime_thread_locals.alloc_context));

#endif // TARGET_UNIX
}
Expand Down
Loading

0 comments on commit 7082a89

Please sign in to comment.