diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 0157d9a672ac39..a908d4ca8a9f7a 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -6567,10 +6567,10 @@ HRESULT DacHeapWalker::Init(CORDB_ADDRESS start, CORDB_ADDRESS end) j++; } } - if ((&g_global_alloc_context)->alloc_ptr != nullptr) + if (g_global_alloc_context->alloc_ptr != nullptr) { - mAllocInfo[j].Ptr = (CORDB_ADDRESS)(&g_global_alloc_context)->alloc_ptr; - mAllocInfo[j].Limit = (CORDB_ADDRESS)(&g_global_alloc_context)->alloc_limit; + mAllocInfo[j].Ptr = (CORDB_ADDRESS)g_global_alloc_context->alloc_ptr; + mAllocInfo[j].Limit = (CORDB_ADDRESS)g_global_alloc_context->alloc_limit; } mThreadCount = j; diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 3df729cd8cf79f..1805a6eb6a5a3a 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -685,8 +685,8 @@ ClrDataAccess::GetThreadAllocData(CLRDATA_ADDRESS addr, struct DacpAllocData *da Thread* thread = PTR_Thread(TO_TADDR(addr)); - data->allocBytes = TO_CDADDR(thread->m_alloc_context.alloc_bytes); - data->allocBytesLoh = TO_CDADDR(thread->m_alloc_context.alloc_bytes_uoh); + data->allocBytes = TO_CDADDR(thread->m_alloc_context.gc_alloc_context.alloc_bytes); + data->allocBytesLoh = TO_CDADDR(thread->m_alloc_context.gc_alloc_context.alloc_bytes_uoh); SOSDacLeave(); return hr; @@ -740,8 +740,8 @@ ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData * threadData->osThreadId = (DWORD)thread->m_OSThreadId; threadData->state = thread->m_State; threadData->preemptiveGCDisabled = thread->m_fPreemptiveGCDisabled; - threadData->allocContextPtr = TO_CDADDR(thread->m_alloc_context.alloc_ptr); - threadData->allocContextLimit = TO_CDADDR(thread->m_alloc_context.alloc_limit); + threadData->allocContextPtr = TO_CDADDR(thread->m_alloc_context.gc_alloc_context.alloc_ptr); + threadData->allocContextLimit = TO_CDADDR(thread->m_alloc_context.gc_alloc_context.alloc_limit); threadData->fiberData = NULL; @@ -5300,8 +5300,8 @@ HRESULT ClrDataAccess::GetGlobalAllocationContext( } SOSDacEnter(); - *allocPtr = (CLRDATA_ADDRESS)((&g_global_alloc_context)->alloc_ptr); - *allocLimit = (CLRDATA_ADDRESS)((&g_global_alloc_context)->alloc_limit); + *allocPtr = (CLRDATA_ADDRESS)(g_global_alloc_context->alloc_ptr); + *allocLimit = (CLRDATA_ADDRESS)(g_global_alloc_context->alloc_limit); SOSDacLeave(); return hr; } diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index b632887e86d0f8..9573cbfe13196c 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -141,7 +141,7 @@ DEFINE_DACVAR(ProfControlBlock, dac__g_profControlBlock, ::g_profControlBlock) DEFINE_DACVAR(PTR_DWORD, dac__g_card_table, ::g_card_table) DEFINE_DACVAR(PTR_BYTE, dac__g_lowest_address, ::g_lowest_address) DEFINE_DACVAR(PTR_BYTE, dac__g_highest_address, ::g_highest_address) -DEFINE_DACVAR(gc_alloc_context, dac__g_global_alloc_context, ::g_global_alloc_context) +DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_global_alloc_context, ::g_global_alloc_context) DEFINE_DACVAR(IGCHeap, dac__g_pGCHeap, ::g_pGCHeap) diff --git a/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm b/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm index bf79668e567e29..120e4681870720 100644 --- a/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm +++ b/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm @@ -41,7 +41,7 @@ LEAF_ENTRY JIT_TrialAllocSFastMP_InlineGetThread, _TEXT ; m_BaseSize is guaranteed to be a multiple of 8. INLINE_GETTHREAD r11 - mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit] + mov r10, [r11 + OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit] mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr] add rdx, rax @@ -65,7 +65,7 @@ NESTED_ENTRY JIT_BoxFastMP_InlineGetThread, _TEXT mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize] INLINE_GETTHREAD r11 - mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit] + mov r10, [r11 + OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit] mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr] add r8, rax @@ -136,7 +136,7 @@ LEAF_ENTRY AllocateStringFastMP_InlineGetThread, _TEXT and edx, -8 INLINE_GETTHREAD r11 - mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit] + mov r10, [r11 + OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit] mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr] add rdx, rax @@ -189,7 +189,7 @@ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread, _TEXT INLINE_GETTHREAD r11 - mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit] + mov r10, [r11 + OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit] mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr] add r8, rax @@ -238,7 +238,7 @@ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread, _TEXT ; to be a multiple of 8. INLINE_GETTHREAD r11 - mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit] + mov r10, [r11 + OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit] mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr] add r8, rax diff --git a/src/coreclr/vm/amd64/JitHelpers_Slow.asm b/src/coreclr/vm/amd64/JitHelpers_Slow.asm index b864801bfd60c8..fe47e0e8745670 100644 --- a/src/coreclr/vm/amd64/JitHelpers_Slow.asm +++ b/src/coreclr/vm/amd64/JitHelpers_Slow.asm @@ -172,7 +172,7 @@ endif extern g_global_alloc_lock:dword -extern g_global_alloc_context:qword +extern g_global_ee_alloc_context:qword LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT @@ -183,15 +183,15 @@ LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT inc [g_global_alloc_lock] jnz JIT_NEW - mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr - mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr + mov rax, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr + mov r10, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__fast_alloc_helper_limit] ; fast_alloc_helper_limit_ptr add r8, rax cmp r8, r10 ja AllocFailed - mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr + mov qword ptr [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr mov [rax], rcx mov [g_global_alloc_lock], -1 @@ -211,8 +211,8 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT inc [g_global_alloc_lock] jnz JIT_Box - mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr - mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr + mov rax, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr + mov r10, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__fast_alloc_helper_limit] ; fast_alloc_helper_limit_ptr add r8, rax @@ -222,7 +222,7 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT test rdx, rdx je NullRef - mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr + mov qword ptr [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr mov [rax], rcx mov [g_global_alloc_lock], -1 @@ -290,15 +290,15 @@ LEAF_ENTRY AllocateStringFastUP, _TEXT inc [g_global_alloc_lock] jnz FramedAllocateString - mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr - mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr + mov rax, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr + mov r10, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__fast_alloc_helper_limit] ; fast_alloc_helper_limit_ptr add r8, rax cmp r8, r10 ja AllocFailed - mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr + mov qword ptr [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr mov [rax], r11 mov [g_global_alloc_lock], -1 @@ -346,8 +346,8 @@ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT inc [g_global_alloc_lock] jnz JIT_NewArr1 - mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr - mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr + mov rax, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr + mov r10, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__fast_alloc_helper_limit] ; fast_alloc_helper_limit_ptr add r8, rax jc AllocFailed @@ -355,7 +355,7 @@ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT cmp r8, r10 ja AllocFailed - mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr + mov qword ptr [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr mov [rax], rcx mov [g_global_alloc_lock], -1 @@ -399,15 +399,15 @@ LEAF_ENTRY JIT_NewArr1OBJ_UP, _TEXT inc [g_global_alloc_lock] jnz JIT_NewArr1 - mov rax, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr] ; alloc_ptr - mov r10, [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_limit] ; limit_ptr + mov rax, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr + mov r10, [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__fast_alloc_helper_limit] ; fast_alloc_helper_limit_ptr add r8, rax cmp r8, r10 ja AllocFailed - mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr + mov qword ptr [g_global_ee_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr mov [rax], rcx mov [g_global_alloc_lock], -1 diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h index e12f3e1eafd26e..9c49020ce01f36 100644 --- a/src/coreclr/vm/amd64/asmconstants.h +++ b/src/coreclr/vm/amd64/asmconstants.h @@ -119,17 +119,17 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__Thread__m_pFrame #define Thread_m_pFrame OFFSETOF__Thread__m_pFrame -#define OFFSET__Thread__m_alloc_context__alloc_ptr 0x58 -ASMCONSTANTS_C_ASSERT(OFFSET__Thread__m_alloc_context__alloc_ptr == offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); +#define OFFSET__Thread__m_alloc_context__alloc_ptr 0x60 +ASMCONSTANTS_C_ASSERT(OFFSET__Thread__m_alloc_context__alloc_ptr == offsetof(Thread, m_alloc_context) + offsetof(ee_alloc_context, gc_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); -#define OFFSET__Thread__m_alloc_context__alloc_limit 0x60 -ASMCONSTANTS_C_ASSERT(OFFSET__Thread__m_alloc_context__alloc_limit == offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_limit)); +#define OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit 0x58 +ASMCONSTANTS_C_ASSERT(OFFSET__Thread__m_alloc_context__fast_alloc_helper_limit == offsetof(Thread, m_alloc_context) + offsetof(ee_alloc_context, fast_alloc_helper_limit_ptr)); -#define OFFSETOF__gc_alloc_context__alloc_ptr 0x0 -ASMCONSTANT_OFFSETOF_ASSERT(gc_alloc_context, alloc_ptr); +#define OFFSETOF__ee_alloc_context__alloc_ptr 0x8 +ASMCONSTANTS_C_ASSERT(OFFSETOF__ee_alloc_context__alloc_ptr == offsetof(ee_alloc_context, gc_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); -#define OFFSETOF__gc_alloc_context__alloc_limit 0x8 -ASMCONSTANT_OFFSETOF_ASSERT(gc_alloc_context, alloc_limit); +#define OFFSETOF__ee_alloc_context__fast_alloc_helper_limit 0x0 +ASMCONSTANTS_C_ASSERT(OFFSETOF__ee_alloc_context__fast_alloc_helper_limit == offsetof(ee_alloc_context, fast_alloc_helper_limit_ptr)); #define OFFSETOF__ThreadExceptionState__m_pCurrentTracker 0x000 ASMCONSTANTS_C_ASSERT(OFFSETOF__ThreadExceptionState__m_pCurrentTracker diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index f0edc0f15cd007..4d7765f3851753 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -157,6 +157,7 @@ typedef VPTR(class VirtualCallStubManager) PTR_VirtualCallStubManager; typedef VPTR(class VirtualCallStubManagerManager) PTR_VirtualCallStubManagerManager; typedef VPTR(class IGCHeap) PTR_IGCHeap; typedef VPTR(class ModuleBase) PTR_ModuleBase; +typedef DPTR(struct gc_alloc_context) PTR_gc_alloc_context; // // _UNCHECKED_OBJECTREF is for code that can't deal with DEBUG OBJECTREFs diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp index a4a538780aa4ad..56011ecbf626b6 100644 --- a/src/coreclr/vm/gcenv.ee.cpp +++ b/src/coreclr/vm/gcenv.ee.cpp @@ -444,6 +444,20 @@ gc_alloc_context * GCToEEInterface::GetAllocContext() return pThread->GetAllocContext(); } +void InvokeGCAllocCallback(ee_alloc_context* pEEAllocContext, enum_alloc_context_func* fn, void* param) +{ + gc_alloc_context* pAllocContext = &pEEAllocContext->gc_alloc_context; + fn(pAllocContext, param); + if(pEEAllocContext->fast_alloc_helper_limit_ptr > pAllocContext->alloc_limit || + pAllocContext->alloc_ptr > pEEAllocContext->fast_alloc_helper_limit_ptr) + { + // fast_alloc_limit_ptr should be in the range [alloc_ptr, alloc_limit]. + // If it isn't that means the GC just moved the allocation context to a + // different region of memory within the callback and we need to fix it up. + pEEAllocContext->SetFastAllocHelperLimit(); + } +} + void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* param) { CONTRACTL @@ -458,12 +472,12 @@ void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* par Thread * pThread = NULL; while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL) { - fn(pThread->GetAllocContext(), param); + InvokeGCAllocCallback(pThread->GetEEAllocContext(), fn, param); } } else { - fn(&g_global_alloc_context, param); + InvokeGCAllocCallback(&g_global_ee_alloc_context, fn, param); } } diff --git a/src/coreclr/vm/gcheaputilities.cpp b/src/coreclr/vm/gcheaputilities.cpp index 1eeca5d999db65..d2dc733bf6190e 100644 --- a/src/coreclr/vm/gcheaputilities.cpp +++ b/src/coreclr/vm/gcheaputilities.cpp @@ -40,7 +40,8 @@ bool g_sw_ww_enabled_for_gc_heap = false; #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -GVAL_IMPL_INIT(gc_alloc_context, g_global_alloc_context, {}); +ee_alloc_context g_global_ee_alloc_context = {}; +GPTR_IMPL_INIT(gc_alloc_context, g_global_alloc_context, &(g_global_ee_alloc_context.gc_alloc_context)); enum GC_LOAD_STATUS { GC_LOAD_STATUS_BEFORE_START, diff --git a/src/coreclr/vm/gcheaputilities.h b/src/coreclr/vm/gcheaputilities.h index c652cc52bf417c..ba16d680fb4d54 100644 --- a/src/coreclr/vm/gcheaputilities.h +++ b/src/coreclr/vm/gcheaputilities.h @@ -12,6 +12,32 @@ GPTR_DECL(IGCHeap, g_pGCHeap); #ifndef DACCESS_COMPILE extern "C" { #endif // !DACCESS_COMPILE + +// This struct adds some state that is only visible to the EE onto the standard gc_alloc_context +typedef struct _ee_alloc_context +{ + uint8_t* fast_alloc_helper_limit_ptr; + gc_alloc_context gc_alloc_context; + + public: + void init() + { + LIMITED_METHOD_CONTRACT; + fast_alloc_helper_limit_ptr = 0; + gc_alloc_context.init(); + } + + inline void SetFastAllocHelperLimit() + { + // If sampling is off this is just setting fast_alloc_helper_limit_ptr = alloc_limit + // If sampling is on then we'd do some pseudo-random number generation to decide what is + // the next sampled byte in the gc_alloc_context, if any. + + //TODO: implement sampling limit placement strategy + fast_alloc_helper_limit_ptr = gc_alloc_context.alloc_limit; + } +} ee_alloc_context; + GPTR_DECL(uint8_t,g_lowest_address); GPTR_DECL(uint8_t,g_highest_address); GPTR_DECL(uint32_t,g_card_table); @@ -21,7 +47,11 @@ GVAL_DECL(GCHeapType, g_heap_type); // for all allocations. In order to avoid extra indirections in assembly // allocation helpers, the EE owns the global allocation context and the // GC will update it when it needs to. -GVAL_DECL(gc_alloc_context, g_global_alloc_context); +extern "C" ee_alloc_context g_global_ee_alloc_context; + +// This is a pointer into the g_global_ee_alloc_context for the GC visible +// subset of the data +GPTR_DECL(gc_alloc_context, g_global_alloc_context); #ifndef DACCESS_COMPILE } #endif // !DACCESS_COMPILE diff --git a/src/coreclr/vm/gchelpers.cpp b/src/coreclr/vm/gchelpers.cpp index ecbf8f09ce293d..7e9d4e94ed8547 100644 --- a/src/coreclr/vm/gchelpers.cpp +++ b/src/coreclr/vm/gchelpers.cpp @@ -40,13 +40,13 @@ // //======================================================================== -inline gc_alloc_context* GetThreadAllocContext() +inline ee_alloc_context* GetThreadAllocContext() { WRAPPER_NO_CONTRACT; assert(GCHeapUtilities::UseThreadAllocationContexts()); - return & GetThread()->m_alloc_context; + return GetThread()->GetEEAllocContext(); } // When not using per-thread allocation contexts, we (the EE) need to take care that @@ -183,6 +183,50 @@ inline void CheckObjectSize(size_t alloc_size) } } +inline Object* Alloc(ee_alloc_context* pEEAllocContext, size_t size, GC_ALLOC_FLAGS flags) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; // returns an objref without pinning it => cooperative + } CONTRACTL_END; + + gc_alloc_context* pAllocContext = &pEEAllocContext->gc_alloc_context; + + if (flags & GC_ALLOC_USER_OLD_HEAP) + { + // if sampling is on, decide if this object should be sampled + } + else + { + size_t available = (pAllocContext->alloc_limit - pAllocContext->alloc_ptr); + if(pEEAllocContext->fast_alloc_helper_limit_ptr < pAllocContext->alloc_limit && + size > available) + { + // this allocation overlaps the SOH sampling point, record an allocation sampling event + // TODO: route this to a sampling callback. I'm thinking we might just add a + // bool* was_sampled out parameter and get this signal routed back to PublishObjectAndNotify that is going to + // called a few frames up the stack. That lets us get the object initialized before delivering + // the notification. + } + } + + GCStress::MaybeTrigger(pAllocContext); + Object* retVal = GCHeapUtilities::GetGCHeap()->Alloc(pAllocContext, size, flags); + + if(pEEAllocContext->fast_alloc_helper_limit_ptr > pAllocContext->alloc_limit || + pAllocContext->alloc_ptr > pEEAllocContext->fast_alloc_helper_limit_ptr) + { + // fast_alloc_limit_ptr should be in the range [alloc_ptr, alloc_limit] + // if it isn't that means at least one of these things just happened: + // 1) We allocated a new object that advanced alloc_ptr past fast_alloc_helper_limit_ptr + // 2) The GC just moved the allocation context to a different region of memory + // Either way we need to update the fast_alloc_limit_ptr to place it back within the + // allocation context area. + pEEAllocContext->SetFastAllocHelperLimit(); + } + return retVal; +} // There are only two ways to allocate an object. // * Call optimized helpers that were generated on the fly. This is how JIT compiled code does most @@ -222,16 +266,12 @@ inline Object* Alloc(size_t size, GC_ALLOC_FLAGS flags) if (GCHeapUtilities::UseThreadAllocationContexts()) { - gc_alloc_context *threadContext = GetThreadAllocContext(); - GCStress::MaybeTrigger(threadContext); - retVal = GCHeapUtilities::GetGCHeap()->Alloc(threadContext, size, flags); + retVal = Alloc(GetThreadAllocContext(), size, flags); } else { GlobalAllocLockHolder holder(&g_global_alloc_lock); - gc_alloc_context *globalContext = &g_global_alloc_context; - GCStress::MaybeTrigger(globalContext); - retVal = GCHeapUtilities::GetGCHeap()->Alloc(globalContext, size, flags); + retVal = Alloc(&g_global_ee_alloc_context, size, flags); } diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp index 08360e9ff0c060..38839e21f59932 100644 --- a/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -257,8 +257,8 @@ void JIT_TrialAlloc::EmitCore(CPUSTUBLINKER *psl, CodeLabel *noLock, CodeLabel * if (flags & (ALIGN8 | SIZE_IN_EAX | ALIGN8OBJ)) { - // MOV EBX, [edx]Thread.m_alloc_context.alloc_ptr - psl->X86EmitOffsetModRM(0x8B, kEBX, kEDX, offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); + // MOV EBX, [edx]Thread.m_alloc_context.gc_alloc_context.alloc_ptr + psl->X86EmitOffsetModRM(0x8B, kEBX, kEDX, offsetof(Thread, m_alloc_context) + offsetof(ee_alloc_context, gc_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); // add EAX, EBX psl->Emit16(0xC303); if (flags & ALIGN8) @@ -266,20 +266,20 @@ void JIT_TrialAlloc::EmitCore(CPUSTUBLINKER *psl, CodeLabel *noLock, CodeLabel * } else { - // add eax, [edx]Thread.m_alloc_context.alloc_ptr - psl->X86EmitOffsetModRM(0x03, kEAX, kEDX, offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); + // add eax, [edx]Thread.m_alloc_context.gc_alloc_context.alloc_ptr + psl->X86EmitOffsetModRM(0x03, kEAX, kEDX, offsetof(Thread, m_alloc_context) + offsetof(ee_alloc_context, gc_alloc_context) + offsetof(gc_alloc_context, alloc_ptr)); } - // cmp eax, [edx]Thread.m_alloc_context.alloc_limit - psl->X86EmitOffsetModRM(0x3b, kEAX, kEDX, offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_limit)); + // cmp eax, [edx]Thread.m_alloc_context.fast_alloc_helper_limit_ptr + psl->X86EmitOffsetModRM(0x3b, kEAX, kEDX, offsetof(Thread, m_alloc_context) + offsetof(ee_alloc_context, fast_alloc_helper_limit_ptr)); // ja noAlloc psl->X86EmitCondJump(noAlloc, X86CondCode::kJA); // Fill in the allocation and get out. - // mov [edx]Thread.m_alloc_context.alloc_ptr, eax - psl->X86EmitIndexRegStore(kEDX, offsetof(Thread, m_alloc_context) + offsetof(gc_alloc_context, alloc_ptr), kEAX); + // mov [edx]Thread.m_alloc_context.gc_alloc_context.alloc_ptr, eax + psl->X86EmitIndexRegStore(kEDX, offsetof(Thread, m_alloc_context) + offsetof(ee_alloc_context, gc_alloc_context) + offsetof(gc_alloc_context, alloc_ptr), kEAX); if (flags & (ALIGN8 | SIZE_IN_EAX | ALIGN8OBJ)) { diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 6f31284615846a..650c24f23bdfed 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2408,10 +2408,11 @@ HCIMPL1(Object*, JIT_NewS_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_) SIZE_T size = methodTable->GetBaseSize(); _ASSERTE(size % DATA_ALIGNMENT == 0); - gc_alloc_context *allocContext = thread->GetAllocContext(); + ee_alloc_context *eeAllocContext = thread->GetEEAllocContext(); + gc_alloc_context *allocContext = &eeAllocContext->gc_alloc_context; BYTE *allocPtr = allocContext->alloc_ptr; - _ASSERTE(allocPtr <= allocContext->alloc_limit); - if (size > static_cast(allocContext->alloc_limit - allocPtr)) + _ASSERTE(allocPtr <= eeAllocContext->fast_alloc_helper_limit_ptr); + if (size > static_cast(eeAllocContext->fast_alloc_helper_limit_ptr - allocPtr)) { break; } @@ -2532,10 +2533,11 @@ HCIMPL1(StringObject*, AllocateString_MP_FastPortable, DWORD stringLength) _ASSERTE(alignedTotalSize >= totalSize); totalSize = alignedTotalSize; - gc_alloc_context *allocContext = thread->GetAllocContext(); + ee_alloc_context *eeAllocContext = thread->GetEEAllocContext(); + gc_alloc_context *allocContext = &eeAllocContext->gc_alloc_context; BYTE *allocPtr = allocContext->alloc_ptr; - _ASSERTE(allocPtr <= allocContext->alloc_limit); - if (totalSize > static_cast(allocContext->alloc_limit - allocPtr)) + _ASSERTE(allocPtr <= eeAllocContext->fast_alloc_helper_limit_ptr); + if (totalSize > static_cast(eeAllocContext->fast_alloc_helper_limit_ptr - allocPtr)) { break; } @@ -2680,10 +2682,11 @@ HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, IN _ASSERTE(alignedTotalSize >= totalSize); totalSize = alignedTotalSize; - gc_alloc_context *allocContext = thread->GetAllocContext(); + ee_alloc_context *eeAllocContext = thread->GetEEAllocContext(); + gc_alloc_context *allocContext = &eeAllocContext->gc_alloc_context; BYTE *allocPtr = allocContext->alloc_ptr; - _ASSERTE(allocPtr <= allocContext->alloc_limit); - if (totalSize > static_cast(allocContext->alloc_limit - allocPtr)) + _ASSERTE(allocPtr <= eeAllocContext->fast_alloc_helper_limit_ptr); + if (totalSize > static_cast(eeAllocContext->fast_alloc_helper_limit_ptr - allocPtr)) { break; } @@ -2739,10 +2742,11 @@ HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, I _ASSERTE(ALIGN_UP(totalSize, DATA_ALIGNMENT) == totalSize); - gc_alloc_context *allocContext = thread->GetAllocContext(); + ee_alloc_context *eeAllocContext = thread->GetEEAllocContext(); + gc_alloc_context *allocContext = &eeAllocContext->gc_alloc_context; BYTE *allocPtr = allocContext->alloc_ptr; - _ASSERTE(allocPtr <= allocContext->alloc_limit); - if (totalSize > static_cast(allocContext->alloc_limit - allocPtr)) + _ASSERTE(allocPtr <= eeAllocContext->fast_alloc_helper_limit_ptr); + if (totalSize > static_cast(eeAllocContext->fast_alloc_helper_limit_ptr - allocPtr)) { break; } diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index 507a8eb0ea2cad..84b865e77b21a4 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -2967,8 +2967,9 @@ void Thread::OnThreadTerminate(BOOL holdingLock) GCX_COOP(); // GetTotalAllocatedBytes reads dead_threads_non_alloc_bytes, but will suspend EE, being in COOP mode we cannot race with that // however, there could be other threads terminating and doing the same Add. - InterlockedExchangeAdd64((LONG64*)&dead_threads_non_alloc_bytes, m_alloc_context.alloc_limit - m_alloc_context.alloc_ptr); - GCHeapUtilities::GetGCHeap()->FixAllocContext(&m_alloc_context, NULL, NULL); + gc_alloc_context* alloc_context = GetAllocContext(); + InterlockedExchangeAdd64((LONG64*)&dead_threads_non_alloc_bytes, alloc_context->alloc_limit - alloc_context->alloc_ptr); + GCHeapUtilities::GetGCHeap()->FixAllocContext(alloc_context, NULL, NULL); m_alloc_context.init(); } } @@ -3025,8 +3026,9 @@ void Thread::OnThreadTerminate(BOOL holdingLock) { // We must be holding the ThreadStore lock in order to clean up alloc context. // We should never call FixAllocContext during GC. - dead_threads_non_alloc_bytes += m_alloc_context.alloc_limit - m_alloc_context.alloc_ptr; - GCHeapUtilities::GetGCHeap()->FixAllocContext(&m_alloc_context, NULL, NULL); + gc_alloc_context* alloc_context = GetAllocContext(); + dead_threads_non_alloc_bytes += alloc_context->alloc_limit - alloc_context->alloc_ptr; + GCHeapUtilities::GetGCHeap()->FixAllocContext(alloc_context, NULL, NULL); m_alloc_context.init(); } diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index bfb154b0e539de..3e59090fafcae2 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -1401,9 +1401,10 @@ class Thread // on MP systems, each thread has its own allocation chunk so we can avoid // lock prefixes and expensive MP cache snooping stuff - gc_alloc_context m_alloc_context; + ee_alloc_context m_alloc_context; - inline gc_alloc_context *GetAllocContext() { LIMITED_METHOD_CONTRACT; return &m_alloc_context; } + inline ee_alloc_context *GetEEAllocContext() { LIMITED_METHOD_CONTRACT; return &m_alloc_context; } + inline gc_alloc_context *GetAllocContext() { LIMITED_METHOD_CONTRACT; return &(m_alloc_context.gc_alloc_context); } // This is the type handle of the first object in the alloc context at the time // we fire the AllocationTick event. It's only for tooling purpose.