diff --git a/src/coreclr/gc/gc.h b/src/coreclr/gc/gc.h index 47e66e22b93ed1..d06f9d02182b1b 100644 --- a/src/coreclr/gc/gc.h +++ b/src/coreclr/gc/gc.h @@ -17,8 +17,6 @@ Module Name: #include "env/gcenv.os.h" #include -#include "gchandletableimpl.h" - #ifdef BUILD_AS_STANDALONE #include "gcenv.ee.standalone.inl" diff --git a/src/coreclr/gc/gcinternal.h b/src/coreclr/gc/gcinternal.h index 8a2ae31dffb939..4ffeb0a17e04c2 100644 --- a/src/coreclr/gc/gcinternal.h +++ b/src/coreclr/gc/gcinternal.h @@ -12,7 +12,7 @@ #include "gcdesc.h" #include "softwarewritewatch.h" #include "handletable.h" -#include "handletable.inl" +#include "gchandletableimpl.h" #include "gcenv.inl" #include "gceventstatus.h" #include diff --git a/src/coreclr/gc/handletable.cpp b/src/coreclr/gc/handletable.cpp index b13e881ba84886..4aacd03e668ccb 100644 --- a/src/coreclr/gc/handletable.cpp +++ b/src/coreclr/gc/handletable.cpp @@ -25,14 +25,6 @@ DWORD g_dwHandles = 0; #endif // ENABLE_PERF_COUNTERS || FEATURE_EVENT_TRACE -#ifndef DACCESS_COMPILE -int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj) -{ - int generation = g_theGCHeap->WhichGeneration(obj); - return generation == INT_MAX ? max_generation : generation; -} -#endif //DACCESS_COMPILE - /**************************************************************************** * * FORWARD DECLARATIONS @@ -516,108 +508,6 @@ HHANDLETABLE HndGetHandleTable(OBJECTHANDLE handle) return (HHANDLETABLE)pTable; } -void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE; - -#if !defined(DACCESS_COMPILE) && defined(FEATURE_EVENT_TRACE) - if (EVENT_ENABLED(SetGCHandle) || EVENT_ENABLED(PrvSetGCHandle)) - { - uint32_t hndType = HandleFetchType(handle); - uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0; - FIRE_EVENT(SetGCHandle, (void *)handle, (void *)value, hndType, generation); - FIRE_EVENT(PrvSetGCHandle, (void *) handle, (void *)value, hndType, generation); - -#ifdef FEATURE_ASYNC_PINNED_HANDLES - // Also fire the things pinned by Async pinned handles - if (hndType == HNDTYPE_ASYNCPINNED) - { - GCToEEInterface::WalkAsyncPinned(value, value, [](Object*, Object* to, void* ctx) - { - Object* overlapped = reinterpret_cast(ctx); - uint32_t generation = to != nullptr ? g_theGCHeap->WhichGeneration(to) : 0; - FIRE_EVENT(SetGCHandle, (void *)overlapped, (void *)to, HNDTYPE_PINNED, generation); - }); - } -#endif - } -#else - UNREFERENCED_PARAMETER(handle); - UNREFERENCED_PARAMETER(value); -#endif -} - -#ifndef DACCESS_COMPILE -/* - * HndWriteBarrierWorker - * - * Resets the generation number for the handle's clump to zero. - * - */ -void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) -{ - _ASSERTE (value != NULL); - - // find the write barrier for this handle - uint8_t *barrier = (uint8_t *)((uintptr_t)handle & HANDLE_SEGMENT_ALIGN_MASK); - - // sanity - _ASSERTE(barrier); - - // find the offset of this handle into the segment - uintptr_t offset = (uintptr_t)handle & HANDLE_SEGMENT_CONTENT_MASK; - - // make sure it is in the handle area and not the header - _ASSERTE(offset >= HANDLE_HEADER_SIZE); - - // compute the clump index for this handle - offset = (offset - HANDLE_HEADER_SIZE) / (HANDLE_SIZE * HANDLE_HANDLES_PER_CLUMP); - - // Be careful to read and write the age byte via volatile operations. Otherwise the compiler has been - // observed to translate the read + conditional write sequence below into an unconditional read/write - // (utilizing a conditional register move to determine whether the write is an update or simply writes - // back what was read). This is a legal transformation for non-volatile accesses but obviously leads to a - // race condition where we can lose an update (see the comment below for the race condition). - volatile uint8_t * pClumpAge = barrier + offset; - - // if this age is smaller than age of the clump, update the clump age - if (*pClumpAge != 0) // Perf optimization: if clumpAge is 0, nothing more to do - { - // find out generation - int generation = GetConvertedGeneration(value); - uint32_t uType = HandleFetchType(handle); - -#ifdef FEATURE_ASYNC_PINNED_HANDLES - //OverlappedData need special treatment: because all user data pointed by it needs to be reported by this handle, - //its age is consider to be min age of the user data, to be simple, we just make it 0 - if (uType == HNDTYPE_ASYNCPINNED) - { - generation = 0; - } -#endif - - if (uType == HNDTYPE_DEPENDENT) - { - generation = 0; - } - - if (*pClumpAge > (uint8_t) generation) - { - // We have to be careful here. HndWriteBarrier is not under any synchronization - // Consider the scenario where 2 threads are hitting the line below at the same - // time. Only one will win. If the winner has an older age than the loser, we - // just created a potential GC hole (The clump will not be reporting the - // youngest handle in the clump, thus GC may skip the clump). To fix this - // we just set the clump age to 0, which means that whoever wins the race - // results are the same, as GC will always look at the clump - *pClumpAge = (uint8_t)0; - } - } -} -#endif // DACCESS_COMPILE - /* * HndEnumHandles * @@ -1158,5 +1048,3 @@ void DEBUG_LogScanningStatistics(HandleTable *pTable, uint32_t level) /*--------------------------------------------------------------------------*/ - - diff --git a/src/coreclr/gc/handletable.h b/src/coreclr/gc/handletable.h index 4bd6aa1a7bbd6b..2df719aa400be7 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -89,14 +89,8 @@ HHANDLETABLE HndGetHandleTable(OBJECTHANDLE handle); /* * write barrier */ -void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value); void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF value); -/* - * logging an ETW event (for inlined methods) - */ -void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value); - /* * NON-GC handle enumeration */ @@ -224,4 +218,3 @@ FORCEINLINE BOOL HndIsNullOrDestroyedHandle(_UNCHECKED_OBJECTREF value) #include "handletable.inl" #endif //_HANDLETABLE_H - diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index c21d835ea11c4d..570464f37cd1e4 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -7,6 +7,125 @@ #ifndef _HANDLETABLE_INL #define _HANDLETABLE_INL +#ifndef DACCESS_COMPILE +#include "gc.h" +#include "gceventstatus.h" +#include "handletableconstants.h" + +FORCEINLINE int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj) +{ + int generation = g_theGCHeap->WhichGeneration(obj); + return generation == INT_MAX ? max_generation : generation; +} + +FORCEINLINE uint32_t HandleFetchType(OBJECTHANDLE handle) +{ + WRAPPER_NO_CONTRACT; + + uint8_t* segment = reinterpret_cast(reinterpret_cast(handle) & HANDLE_SEGMENT_ALIGN_MASK); + _ASSERTE(segment); + + uintptr_t offset = reinterpret_cast(handle) & HANDLE_SEGMENT_CONTENT_MASK; + _ASSERTE(offset >= HANDLE_HEADER_SIZE); + + uint32_t uHandle = static_cast((offset - HANDLE_HEADER_SIZE) / HANDLE_SIZE); + uint32_t uBlock = uHandle / HANDLE_HANDLES_PER_BLOCK; + + return segment[HANDLE_SEGMENT_BLOCK_TYPE_OFFSET + uBlock]; +} + +FORCEINLINE void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) +{ + _ASSERTE(value != NULL); + + uint8_t* barrier = (uint8_t*)((uintptr_t)handle & HANDLE_SEGMENT_ALIGN_MASK); + _ASSERTE(barrier); + + uintptr_t offset = (uintptr_t)handle & HANDLE_SEGMENT_CONTENT_MASK; + _ASSERTE(offset >= HANDLE_HEADER_SIZE); + + offset = (offset - HANDLE_HEADER_SIZE) / (HANDLE_SIZE * HANDLE_HANDLES_PER_CLUMP); + + // Be careful to read and write the age byte via volatile operations. Otherwise the compiler has been + // observed to translate the read + conditional write sequence below into an unconditional read/write + // (utilizing a conditional register move to determine whether the write is an update or simply writes + // back what was read). This is a legal transformation for non-volatile accesses but obviously leads to a + // race condition where we can lose an update (see the comment below for the race condition). + volatile uint8_t* pClumpAge = barrier + offset; + + if (*pClumpAge != 0) + { + int generation = GetConvertedGeneration(value); + + if (generation == 0) + { + *pClumpAge = 0; + return; + } + + uint32_t uType = HandleFetchType(handle); + +#ifdef FEATURE_ASYNC_PINNED_HANDLES + //OverlappedData need special treatment: because all user data pointed by it needs to be reported by this handle, + //its age is consider to be min age of the user data, to be simple, we just make it 0 + if (uType == HNDTYPE_ASYNCPINNED) + { + generation = 0; + } +#endif + + if (uType == HNDTYPE_DEPENDENT) + { + generation = 0; + } + + if (*pClumpAge > (uint8_t)generation) + { + // We have to be careful here. HndWriteBarrier is not under any synchronization + // Consider the scenario where 2 threads are hitting the line below at the same + // time. Only one will win. If the winner has an older age than the loser, we + // just created a potential GC hole (The clump will not be reporting the + // youngest handle in the clump, thus GC may skip the clump). To fix this + // we just set the clump age to 0, which means that whoever wins the race + // results are the same, as GC will always look at the clump + *pClumpAge = (uint8_t)0; + } + } +} + +FORCEINLINE void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) +{ + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_NOTRIGGER; + STATIC_CONTRACT_MODE_COOPERATIVE; + +#ifdef FEATURE_EVENT_TRACE + if (EVENT_ENABLED(SetGCHandle) || EVENT_ENABLED(PrvSetGCHandle)) + { + uint32_t hndType = HandleFetchType(handle); + uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0; + FIRE_EVENT(SetGCHandle, (void *)handle, (void *)value, hndType, generation); + FIRE_EVENT(PrvSetGCHandle, (void *) handle, (void *)value, hndType, generation); + +#ifdef FEATURE_ASYNC_PINNED_HANDLES + // Also fire the things pinned by Async pinned handles + if (hndType == HNDTYPE_ASYNCPINNED) + { + GCToEEInterface::WalkAsyncPinned(value, value, [](Object*, Object* to, void* ctx) + { + Object* overlapped = reinterpret_cast(ctx); + uint32_t generation = to != nullptr ? g_theGCHeap->WhichGeneration(to) : 0; + FIRE_EVENT(SetGCHandle, (void *)overlapped, (void *)to, HNDTYPE_PINNED, generation); + }); + } +#endif + } +#else + UNREFERENCED_PARAMETER(handle); + UNREFERENCED_PARAMETER(value); +#endif // FEATURE_EVENT_TRACE +} + inline void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF objref) { STATIC_CONTRACT_NOTHROW; @@ -41,7 +160,7 @@ inline void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref) // if we are doing a non-NULL pointer store then invoke the write-barrier if (value) - HndWriteBarrier(handle, objref); + HndWriteBarrierWorker(handle, value); // Store the pointer with release semantics so object field writes are visible // before the handle can publish the object to another thread. @@ -134,5 +253,6 @@ inline BOOL HndFirstAssignHandle(OBJECTHANDLE handle, OBJECTREF objref) // return our result return success; } +#endif // DACCESS_COMPILE #endif // _HANDLETABLE_INL diff --git a/src/coreclr/gc/handletablecache.cpp b/src/coreclr/gc/handletablecache.cpp index c201e32929c308..44eec4d2199781 100644 --- a/src/coreclr/gc/handletablecache.cpp +++ b/src/coreclr/gc/handletablecache.cpp @@ -756,66 +756,6 @@ OBJECTHANDLE TableAllocSingleHandleFromCache(HandleTable *pTable, uint32_t uType } -/* - * TableFreeSingleHandleToCache - * - * Returns a single handle of the specified type to the handle table - * by trying to store it in the free cache for that handle type. If the - * free cache is full, this routine calls TableCacheMissOnFree. - * - */ -void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHANDLE handle) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - CAN_TAKE_LOCK; // because of TableCacheMissOnFree - } - CONTRACTL_END; - -#ifdef DEBUG_DestroyedHandleValue - *(_UNCHECKED_OBJECTREF *)handle = DEBUG_DestroyedHandleValue; -#else - // zero the handle's object pointer - *(_UNCHECKED_OBJECTREF *)handle = NULL; -#endif - - // if this handle type has user data then clear it - AFTER the referent is cleared! - if (TypeHasUserData(pTable, uType)) - HandleQuickSetUserData(handle, 0L); - - // is there room in the quick cache? - if (!pTable->rgQuickCache[uType]) - { - // yup - try to stuff our handle in the slot we saw - handle = Interlocked::ExchangePointer(&pTable->rgQuickCache[uType], handle); - - // if we didn't end up with another handle then we're done - if (!handle) - return; - } - - // ok, get the main handle cache for this type - HandleTypeCache *pCache = pTable->rgMainCache + uType; - - // try to take a free slot from the main cache - int32_t lFreeIndex = Interlocked::Decrement(&pCache->lFreeIndex); - - // did we underflow? - if (lFreeIndex < 0) - { - // yep - we're out of free slots - TableCacheMissOnFree(pTable, pCache, uType, handle); - return; - } - - // we got a slot - save the handle in the free bank - pCache->rgFreeBank[lFreeIndex] = handle; -} - - /* * TableAllocHandlesFromCache * @@ -851,35 +791,5 @@ uint32_t TableAllocHandlesFromCache(HandleTable *pTable, uint32_t uType, OBJECTH } -/* - * TableFreeHandlesToCache - * - * Frees multiple handles of the specified type by repeatedly - * calling TableFreeSingleHandleToCache. - * - */ -void TableFreeHandlesToCache(HandleTable *pTable, uint32_t uType, const OBJECTHANDLE *pHandleBase, uint32_t uCount) -{ - WRAPPER_NO_CONTRACT; - - // loop until we have freed all the handles - while (uCount) - { - // get the next handle to free - OBJECTHANDLE handle = *pHandleBase; - - // advance our state - uCount--; - pHandleBase++; - - // sanity - _ASSERTE(handle); - - // return the handle to the cache - TableFreeSingleHandleToCache(pTable, uType, handle); - } -} - /*--------------------------------------------------------------------------*/ - diff --git a/src/coreclr/gc/handletableconstants.h b/src/coreclr/gc/handletableconstants.h index 599185cb7b17c5..4118173e229c6b 100644 --- a/src/coreclr/gc/handletableconstants.h +++ b/src/coreclr/gc/handletableconstants.h @@ -93,6 +93,9 @@ #define HANDLE_MASKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_MASK) #define HANDLE_MASKS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_MASK) #define HANDLE_CLUMPS_PER_MASK (HANDLE_HANDLES_PER_MASK / HANDLE_HANDLES_PER_CLUMP) +#define HANDLE_SEGMENT_BLOCK_TYPE_OFFSET ((HANDLE_BLOCKS_PER_SEGMENT * sizeof(uint32_t)) + \ + HANDLE_BLOCKS_PER_SEGMENT + \ + (HANDLE_MASKS_PER_SEGMENT * sizeof(uint32_t))) // We use this relation to check for free mask per block. static_assert (HANDLE_HANDLES_PER_MASK * 2 == HANDLE_HANDLES_PER_BLOCK); diff --git a/src/coreclr/gc/handletablecore.cpp b/src/coreclr/gc/handletablecore.cpp index 2a5b36200b312e..f26648173b8342 100644 --- a/src/coreclr/gc/handletablecore.cpp +++ b/src/coreclr/gc/handletablecore.cpp @@ -442,35 +442,6 @@ void HandleQuickSetUserData(OBJECTHANDLE handle, uintptr_t lUserData) #endif // !DACCESS_COMPILE -/* - * HandleFetchType - * - * Computes the type index for a given handle. - * - */ -uint32_t HandleFetchType(OBJECTHANDLE handle) -{ - WRAPPER_NO_CONTRACT; - - // get the segment for this handle - PTR__TableSegmentHeader pSegment = HandleFetchSegmentPointer(handle); - - // find the offset of this handle into the segment - uintptr_t offset = (uintptr_t)handle & HANDLE_SEGMENT_CONTENT_MASK; - - // make sure it is in the handle area and not the header - _ASSERTE(offset >= HANDLE_HEADER_SIZE); - - // convert the offset to a handle index - uint32_t uHandle = (uint32_t)((offset - HANDLE_HEADER_SIZE) / HANDLE_SIZE); - - // compute the block this handle resides in - uint32_t uBlock = uHandle / HANDLE_HANDLES_PER_BLOCK; - - // return the block's type - return pSegment->rgBlockType[uBlock]; -} - /* * HandleFetchHandleTable * @@ -2213,4 +2184,3 @@ void TableFreeBulkUnpreparedHandles(HandleTable *pTable, uint32_t uType, const O /*--------------------------------------------------------------------------*/ - diff --git a/src/coreclr/gc/handletablepriv.h b/src/coreclr/gc/handletablepriv.h index e09e89cecaaae5..149413c772e21b 100644 --- a/src/coreclr/gc/handletablepriv.h +++ b/src/coreclr/gc/handletablepriv.h @@ -168,6 +168,8 @@ struct _TableSegmentHeader uint8_t bSequence; }; +static_assert(offsetof(_TableSegmentHeader, rgBlockType) == HANDLE_SEGMENT_BLOCK_TYPE_OFFSET); + typedef DPTR(struct _TableSegmentHeader) PTR__TableSegmentHeader; typedef DPTR(uintptr_t) PTR_uintptr_t; @@ -609,15 +611,6 @@ PTR_uintptr_t HandleQuickFetchUserDataPointer(OBJECTHANDLE handle); void HandleQuickSetUserData(OBJECTHANDLE handle, uintptr_t lUserData); -/* - * HandleFetchType - * - * Computes the type index for a given handle. - * - */ -uint32_t HandleFetchType(OBJECTHANDLE handle); - - /* * HandleFetchHandleTable * @@ -740,6 +733,16 @@ void TableFreeBulkUnpreparedHandles(HandleTable *pTable, uint32_t uType, const O OBJECTHANDLE TableAllocSingleHandleFromCache(HandleTable *pTable, uint32_t uType); +/* + * TableCacheMissOnFree + * + * Called when a handle cannot be stored in the free cache for its type + * because the cache is full. + * + */ +void TableCacheMissOnFree(HandleTable *pTable, HandleTypeCache *pCache, uint32_t uType, OBJECTHANDLE handle); + + /* * TableFreeSingleHandleToCache * @@ -748,7 +751,58 @@ OBJECTHANDLE TableAllocSingleHandleFromCache(HandleTable *pTable, uint32_t uType * free cache is full, this routine calls TableCacheMissOnFree. * */ -void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHANDLE handle); +#ifndef DACCESS_COMPILE +__inline void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHANDLE handle) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + CAN_TAKE_LOCK; // because of TableCacheMissOnFree + } + CONTRACTL_END; + +#ifdef DEBUG_DestroyedHandleValue + *(_UNCHECKED_OBJECTREF *)handle = DEBUG_DestroyedHandleValue; +#else + // zero the handle's object pointer + *(_UNCHECKED_OBJECTREF *)handle = NULL; +#endif + + // if this handle type has user data then clear it - AFTER the referent is cleared! + if (TypeHasUserData(pTable, uType)) + HandleQuickSetUserData(handle, 0L); + + // is there room in the quick cache? + if (!pTable->rgQuickCache[uType]) + { + // yup - try to stuff our handle in the slot we saw + handle = Interlocked::ExchangePointer(&pTable->rgQuickCache[uType], handle); + + // if we didn't end up with another handle then we're done + if (!handle) + return; + } + + // ok, get the main handle cache for this type + HandleTypeCache *pCache = pTable->rgMainCache + uType; + + // try to take a free slot from the main cache + int32_t lFreeIndex = Interlocked::Decrement(&pCache->lFreeIndex); + + // did we underflow? + if (lFreeIndex < 0) + { + // yep - we're out of free slots + TableCacheMissOnFree(pTable, pCache, uType, handle); + return; + } + + // we got a slot - save the handle in the free bank + pCache->rgFreeBank[lFreeIndex] = handle; +} +#endif // !DACCESS_COMPILE /* @@ -761,15 +815,6 @@ void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHAN uint32_t TableAllocHandlesFromCache(HandleTable *pTable, uint32_t uType, OBJECTHANDLE *pHandleBase, uint32_t uCount); -/* - * TableFreeHandlesToCache - * - * Frees multiple handles of the specified type by repeatedly - * calling TableFreeSingleHandleToCache. - * - */ -void TableFreeHandlesToCache(HandleTable *pTable, uint32_t uType, const OBJECTHANDLE *pHandleBase, uint32_t uCount); - /*--------------------------------------------------------------------------*/ @@ -942,15 +987,3 @@ void CALLBACK BlockVerifyAgeMapForBlocks(PTR_TableSegment pSegment, uint32_t uBl PTR_TableSegment CALLBACK xxxAsyncSegmentIterator(PTR_HandleTable pTable, TableSegment *pPrevSegment, CrstHolderWithState *pCrstHolder); /*--------------------------------------------------------------------------*/ - -#ifndef DACCESS_COMPILE - -/* - * GetConvertedGeneration - * - * Get the generation of an object, where a frozen object is regarded as max_generation - * - */ -int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj); - -#endif //DACCESS_COMPILE diff --git a/src/coreclr/gc/handletablescan.cpp b/src/coreclr/gc/handletablescan.cpp index 15137c85f1e2e1..bad713c6a51b55 100644 --- a/src/coreclr/gc/handletablescan.cpp +++ b/src/coreclr/gc/handletablescan.cpp @@ -1878,4 +1878,3 @@ uint32_t TableSegment::DacSize(TADDR addr) } #endif /*--------------------------------------------------------------------------*/ - diff --git a/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp b/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp index 285b5555274fd8..f87ce5072ee84b 100644 --- a/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/HandleTableHelpers.cpp @@ -11,13 +11,13 @@ FCIMPL2(OBJECTHANDLE, RhpHandleAlloc, Object *pObject, int type) { - return GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore()->CreateHandleOfType(pObject, (HandleType)type); + return GCHandleUtilities::GetGlobalHandleStore()->CreateHandleOfType(pObject, (HandleType)type); } FCIMPLEND FCIMPL2(OBJECTHANDLE, RhpHandleAllocDependent, Object *pPrimary, Object *pSecondary) { - return GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore()->CreateDependentHandle(pPrimary, pSecondary); + return GCHandleUtilities::GetGlobalHandleStore()->CreateDependentHandle(pPrimary, pSecondary); } FCIMPLEND @@ -67,7 +67,7 @@ FCIMPLEND FCIMPL2(OBJECTHANDLE, RhpHandleAllocCrossReference, Object *pPrimary, void *pContext) { - return GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore()->CreateHandleWithExtraInfo(pPrimary, HNDTYPE_CROSSREFERENCE, pContext); + return GCHandleUtilities::GetGlobalHandleStore()->CreateHandleWithExtraInfo(pPrimary, HNDTYPE_CROSSREFERENCE, pContext); } FCIMPLEND diff --git a/src/coreclr/nativeaot/Runtime/clrgc.enabled.cpp b/src/coreclr/nativeaot/Runtime/clrgc.enabled.cpp index 68753a20548f9c..16fcf309715da6 100644 --- a/src/coreclr/nativeaot/Runtime/clrgc.enabled.cpp +++ b/src/coreclr/nativeaot/Runtime/clrgc.enabled.cpp @@ -226,6 +226,7 @@ HRESULT GCHeapUtilities::InitializeStandaloneGC() g_gcEventTracingInitialized = TRUE; } g_pGCHandleManager = manager; + g_pGlobalHandleStore = manager->GetGlobalHandleStore(); g_gcDacGlobals = &g_gc_dac_vars; LOG((LF_GC, LL_INFO100, "GC load successful\n")); } diff --git a/src/coreclr/nativeaot/Runtime/gchandleutilities.h b/src/coreclr/nativeaot/Runtime/gchandleutilities.h index a4e6ae384cbc90..4574b931eba762 100644 --- a/src/coreclr/nativeaot/Runtime/gchandleutilities.h +++ b/src/coreclr/nativeaot/Runtime/gchandleutilities.h @@ -7,6 +7,7 @@ #include "gcinterface.h" extern "C" IGCHandleManager* g_pGCHandleManager; +extern "C" IGCHandleStore* g_pGlobalHandleStore; class GCHandleUtilities { @@ -20,6 +21,15 @@ class GCHandleUtilities return g_pGCHandleManager; } + // Retrieves the global GC handle store. + static IGCHandleStore* GetGlobalHandleStore() + { + LIMITED_METHOD_CONTRACT; + + assert(g_pGlobalHandleStore != nullptr); + return g_pGlobalHandleStore; + } + private: // This class should never be instantiated. GCHandleUtilities() = delete; diff --git a/src/coreclr/nativeaot/Runtime/gcheaputilities.cpp b/src/coreclr/nativeaot/Runtime/gcheaputilities.cpp index edafc599814e51..8980a6a6f14bef 100644 --- a/src/coreclr/nativeaot/Runtime/gcheaputilities.cpp +++ b/src/coreclr/nativeaot/Runtime/gcheaputilities.cpp @@ -33,6 +33,7 @@ bool g_sw_ww_enabled_for_gc_heap = false; #endif IGCHandleManager* g_pGCHandleManager = nullptr; +IGCHandleStore* g_pGlobalHandleStore = nullptr; GcDacVars g_gc_dac_vars; GPTR_IMPL(GcDacVars, g_gcDacGlobals); @@ -79,6 +80,7 @@ HRESULT GCHeapUtilities::InitializeDefaultGC() { g_pGCHeap = heap; g_pGCHandleManager = manager; + g_pGlobalHandleStore = manager->GetGlobalHandleStore(); g_gcDacGlobals = &g_gc_dac_vars; LOG((LF_GC, LL_INFO100, "GC load successful\n")); } diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 5e610ed1967c1d..f3c53062b1e21f 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1704,10 +1704,6 @@ void AppDomain::Init() m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap()); m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore(); - if (!m_handleStore) - { - COMPlusThrowOM(); - } #ifdef FEATURE_TYPEEQUIVALENCE m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);