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

Create portable box helper and wrap the thread-local alloc context in a struct #103607

Merged
merged 8 commits into from
Jun 20, 2024
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 @@ -621,7 +621,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
Loading