Skip to content

Commit 69dc5ec

Browse files
authored
Add ee_alloc_context (#104849)
This change is some preparatory refactoring for the randomized allocation sampling feature. We need to add more state onto allocation context but we don't want to do a breaking change of the GC interface. The new state only needs to be visible to the EE but we want it physically near the existing alloc context state for good cache locality. To accomplish this we created a new ee_alloc_context struct which contains an instance of gc_alloc_context within it. The new ee_alloc_context.combined_limit field should be used by fast allocation helpers to determine when to go down the slow path. Most of the time combined_limit has the same value as alloc_limit, but periodically we need to emit an allocation sampling event on an object that is somewhere in the middle of an AC. Using combined_limit rather than alloc_limit as the slow path trigger allows us to keep all the sampling event logic in the slow path. PR feedback Co-authored-by: Jan Kotas <[email protected]>
1 parent dedb7d1 commit 69dc5ec

File tree

24 files changed

+217
-83
lines changed

24 files changed

+217
-83
lines changed

src/coreclr/debug/daccess/dacdbiimpl.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6518,10 +6518,11 @@ HRESULT DacHeapWalker::Init(CORDB_ADDRESS start, CORDB_ADDRESS end)
65186518
j++;
65196519
}
65206520
}
6521-
if ((&g_global_alloc_context)->alloc_ptr != nullptr)
6521+
gc_alloc_context globalCtx = ((ee_alloc_context)g_global_alloc_context).m_GCAllocContext;
6522+
if (globalCtx.alloc_ptr != nullptr)
65226523
{
6523-
mAllocInfo[j].Ptr = (CORDB_ADDRESS)(&g_global_alloc_context)->alloc_ptr;
6524-
mAllocInfo[j].Limit = (CORDB_ADDRESS)(&g_global_alloc_context)->alloc_limit;
6524+
mAllocInfo[j].Ptr = (CORDB_ADDRESS)globalCtx.alloc_ptr;
6525+
mAllocInfo[j].Limit = (CORDB_ADDRESS)globalCtx.alloc_limit;
65256526
}
65266527

65276528
mThreadCount = j;

src/coreclr/debug/daccess/request.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ ClrDataAccess::GetThreadAllocData(CLRDATA_ADDRESS addr, struct DacpAllocData *da
795795

796796
Thread* thread = PTR_Thread(TO_TADDR(addr));
797797

798-
PTR_gc_alloc_context pAllocContext = thread->GetAllocContext();
798+
gc_alloc_context* pAllocContext = thread->GetAllocContext();
799799

800800
if (pAllocContext != NULL)
801801
{
@@ -860,7 +860,7 @@ HRESULT ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThre
860860
threadData->state = thread->m_State;
861861
threadData->preemptiveGCDisabled = thread->m_fPreemptiveGCDisabled;
862862

863-
PTR_gc_alloc_context allocContext = thread->GetAllocContext();
863+
gc_alloc_context* allocContext = thread->GetAllocContext();
864864
if (allocContext)
865865
{
866866
threadData->allocContextPtr = TO_CDADDR(allocContext->alloc_ptr);
@@ -5351,8 +5351,9 @@ HRESULT ClrDataAccess::GetGlobalAllocationContext(
53515351
}
53525352

53535353
SOSDacEnter();
5354-
*allocPtr = (CLRDATA_ADDRESS)((&g_global_alloc_context)->alloc_ptr);
5355-
*allocLimit = (CLRDATA_ADDRESS)((&g_global_alloc_context)->alloc_limit);
5354+
gc_alloc_context global_alloc_context = ((ee_alloc_context)g_global_alloc_context).m_GCAllocContext;
5355+
*allocPtr = (CLRDATA_ADDRESS)global_alloc_context.alloc_ptr;
5356+
*allocLimit = (CLRDATA_ADDRESS)global_alloc_context.alloc_limit;
53565357
SOSDacLeave();
53575358
return hr;
53585359
}

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,14 @@ CDAC_TYPE_END(ThreadStore)
134134

135135
CDAC_TYPE_BEGIN(RuntimeThreadLocals)
136136
CDAC_TYPE_INDETERMINATE(RuntimeThreadLocals)
137-
CDAC_TYPE_FIELD(RuntimeThreadLocals, AllocContext, AllocContext, offsetof(RuntimeThreadLocals, alloc_context))
137+
CDAC_TYPE_FIELD(RuntimeThreadLocals, /*EEAllocContext*/, AllocContext, offsetof(RuntimeThreadLocals, alloc_context))
138138
CDAC_TYPE_END(RuntimeThreadLocals)
139139

140+
CDAC_TYPE_BEGIN(EEAllocContext)
141+
CDAC_TYPE_INDETERMINATE(EEAllocContext)
142+
CDAC_TYPE_FIELD(EEAllocContext, /*GCAllocContext*/, GCAllocationContext, offsetof(ee_alloc_context, m_GCAllocContext))
143+
CDAC_TYPE_END(EEAllocContext)
144+
140145
CDAC_TYPE_BEGIN(GCAllocContext)
141146
CDAC_TYPE_INDETERMINATE(GCAllocContext)
142147
CDAC_TYPE_FIELD(GCAllocContext, /*pointer*/, Pointer, offsetof(gc_alloc_context, alloc_ptr))

src/coreclr/gc/gcinterface.ee.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ class IGCToCLR {
281281
gc_alloc_context * GetAllocContext() PURE_VIRTUAL
282282

283283
// Calls the given enum_alloc_context_func with every active alloc context.
284+
// NOTE: The GC may mutate the allocation context fields inside the callback.
285+
// If the GC does modify the fields, the only legal modification for the alloc_ptr
286+
// alloc_limit fields is to setting them both to zero.
284287
virtual
285288
void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param) PURE_VIRTUAL
286289

src/coreclr/inc/dacvars.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ DEFINE_DACVAR(ProfControlBlock, dac__g_profControlBlock, ::g_profControlBlock)
140140
DEFINE_DACVAR(PTR_DWORD, dac__g_card_table, ::g_card_table)
141141
DEFINE_DACVAR(PTR_BYTE, dac__g_lowest_address, ::g_lowest_address)
142142
DEFINE_DACVAR(PTR_BYTE, dac__g_highest_address, ::g_highest_address)
143-
DEFINE_DACVAR(gc_alloc_context, dac__g_global_alloc_context, ::g_global_alloc_context)
143+
DEFINE_DACVAR(ee_alloc_context, dac__g_global_alloc_context, ::g_global_alloc_context)
144144

145145
DEFINE_DACVAR(IGCHeap, dac__g_pGCHeap, ::g_pGCHeap)
146146

src/coreclr/vm/amd64/JitHelpers_Slow.asm

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,15 @@ LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT
178178
inc [g_global_alloc_lock]
179179
jnz JIT_NEW
180180

181-
mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr
182-
mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr
181+
mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr
182+
mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit
183183

184184
add r8, rax
185185

186186
cmp r8, r10
187187
ja AllocFailed
188188

189-
mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
189+
mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr
190190
mov [rax], rcx
191191
mov [g_global_alloc_lock], -1
192192

@@ -206,8 +206,8 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT
206206
inc [g_global_alloc_lock]
207207
jnz JIT_Box
208208

209-
mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr
210-
mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr
209+
mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr
210+
mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit
211211

212212
add r8, rax
213213

@@ -217,7 +217,7 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT
217217
test rdx, rdx
218218
je NullRef
219219

220-
mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
220+
mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr
221221
mov [rax], rcx
222222
mov [g_global_alloc_lock], -1
223223

@@ -285,15 +285,15 @@ LEAF_ENTRY AllocateStringFastUP, _TEXT
285285
inc [g_global_alloc_lock]
286286
jnz FramedAllocateString
287287

288-
mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr
289-
mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr
288+
mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr
289+
mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit
290290

291291
add r8, rax
292292

293293
cmp r8, r10
294294
ja AllocFailed
295295

296-
mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
296+
mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr
297297
mov [rax], r11
298298
mov [g_global_alloc_lock], -1
299299

@@ -341,16 +341,16 @@ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT
341341
inc [g_global_alloc_lock]
342342
jnz JIT_NewArr1
343343

344-
mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr
345-
mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr
344+
mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr
345+
mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit
346346

347347
add r8, rax
348348
jc AllocFailed
349349

350350
cmp r8, r10
351351
ja AllocFailed
352352

353-
mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
353+
mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr
354354
mov [rax], rcx
355355
mov [g_global_alloc_lock], -1
356356

@@ -394,15 +394,15 @@ LEAF_ENTRY JIT_NewArr1OBJ_UP, _TEXT
394394
inc [g_global_alloc_lock]
395395
jnz JIT_NewArr1
396396

397-
mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr
398-
mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr
397+
mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr
398+
mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit
399399

400400
add r8, rax
401401

402402
cmp r8, r10
403403
ja AllocFailed
404404

405-
mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
405+
mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr
406406
mov [rax], rcx
407407
mov [g_global_alloc_lock], -1
408408

src/coreclr/vm/amd64/asmconstants.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,12 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_pFrame
111111
#define Thread_m_pFrame OFFSETOF__Thread__m_pFrame
112112

113113

114-
#define OFFSETOF__gc_alloc_context__alloc_ptr 0x0
115-
ASMCONSTANT_OFFSETOF_ASSERT(gc_alloc_context, alloc_ptr);
114+
#define OFFSETOF__ee_alloc_context__alloc_ptr 0x8
115+
ASMCONSTANTS_C_ASSERT(OFFSETOF__ee_alloc_context__alloc_ptr == offsetof(ee_alloc_context, m_GCAllocContext) +
116+
offsetof(gc_alloc_context, alloc_ptr));
116117

117-
#define OFFSETOF__gc_alloc_context__alloc_limit 0x8
118-
ASMCONSTANT_OFFSETOF_ASSERT(gc_alloc_context, alloc_limit);
118+
#define OFFSETOF__ee_alloc_context__m_CombinedLimit 0x0
119+
ASMCONSTANTS_C_ASSERT(OFFSETOF__ee_alloc_context__m_CombinedLimit == offsetof(ee_alloc_context, m_CombinedLimit));
119120

120121
#define OFFSETOF__ThreadExceptionState__m_pCurrentTracker 0x000
121122
ASMCONSTANTS_C_ASSERT(OFFSETOF__ThreadExceptionState__m_pCurrentTracker

src/coreclr/vm/comutilnative.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ FCIMPL0(INT64, GCInterface::GetAllocatedBytesForCurrentThread)
908908

909909
INT64 currentAllocated = 0;
910910
Thread *pThread = GetThread();
911-
gc_alloc_context* ac = &t_runtime_thread_locals.alloc_context;
911+
gc_alloc_context* ac = &t_runtime_thread_locals.alloc_context.m_GCAllocContext;
912912
currentAllocated = ac->alloc_bytes + ac->alloc_bytes_uoh - (ac->alloc_limit - ac->alloc_ptr);
913913

914914
return currentAllocated;

src/coreclr/vm/gccover.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1834,7 +1834,7 @@ void DoGcStress (PCONTEXT regs, NativeCodeVersion nativeCodeVersion)
18341834
// BUG(github #10318) - when not using allocation contexts, the alloc lock
18351835
// must be acquired here. Until fixed, this assert prevents random heap corruption.
18361836
assert(GCHeapUtilities::UseThreadAllocationContexts());
1837-
GCHeapUtilities::GetGCHeap()->StressHeap(&t_runtime_thread_locals.alloc_context);
1837+
GCHeapUtilities::GetGCHeap()->StressHeap(&t_runtime_thread_locals.alloc_context.m_GCAllocContext);
18381838

18391839
// StressHeap can exit early w/o forcing a SuspendEE to trigger the instruction update
18401840
// We can not rely on the return code to determine if the instruction update happened

src/coreclr/vm/gcenv.ee.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ gc_alloc_context * GCToEEInterface::GetAllocContext()
445445
return nullptr;
446446
}
447447

448-
return &t_runtime_thread_locals.alloc_context;
448+
return &t_runtime_thread_locals.alloc_context.m_GCAllocContext;
449449
}
450450

451451
void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param)
@@ -462,16 +462,29 @@ void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* par
462462
Thread * pThread = NULL;
463463
while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
464464
{
465-
gc_alloc_context* palloc_context = pThread->GetAllocContext();
465+
ee_alloc_context* palloc_context = pThread->GetEEAllocContext();
466466
if (palloc_context != nullptr)
467467
{
468-
fn(palloc_context, param);
468+
gc_alloc_context* ac = &palloc_context->m_GCAllocContext;
469+
fn(ac, param);
470+
// The GC may zero the alloc_ptr and alloc_limit fields of AC during enumeration and we need to keep
471+
// m_CombinedLimit up-to-date. Note that the GC has multiple threads running this enumeration concurrently
472+
// with no synchronization. If you need to change this code think carefully about how that concurrency
473+
// may affect the results.
474+
if (ac->alloc_limit == 0 && palloc_context->m_CombinedLimit != 0)
475+
{
476+
palloc_context->m_CombinedLimit = 0;
477+
}
469478
}
470479
}
471480
}
472481
else
473482
{
474-
fn(&g_global_alloc_context, param);
483+
fn(&g_global_alloc_context.m_GCAllocContext, param);
484+
if (g_global_alloc_context.m_GCAllocContext.alloc_limit == 0 && g_global_alloc_context.m_CombinedLimit != 0)
485+
{
486+
g_global_alloc_context.m_CombinedLimit = 0;
487+
}
475488
}
476489
}
477490

0 commit comments

Comments
 (0)