From edf2329b72a100d032770a45bcf1dea47ce51981 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:10:32 +0000 Subject: [PATCH 01/12] Inline GC handle write barrier worker Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/handletable.cpp | 69 -------------------------------- src/coreclr/gc/handletable.h | 6 ++- src/coreclr/gc/handletable.inl | 58 ++++++++++++++++++++++++++- src/coreclr/gc/handletablepriv.h | 8 ---- 4 files changed, 61 insertions(+), 80 deletions(-) diff --git a/src/coreclr/gc/handletable.cpp b/src/coreclr/gc/handletable.cpp index 356b0e0bdc314b..926bd1be9149c2 100644 --- a/src/coreclr/gc/handletable.cpp +++ b/src/coreclr/gc/handletable.cpp @@ -549,74 +549,6 @@ void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) } #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,4 +1090,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..97698014e5aebc 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -89,7 +89,6 @@ HHANDLETABLE HndGetHandleTable(OBJECTHANDLE handle); /* * write barrier */ -void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value); void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF value); /* @@ -148,6 +147,10 @@ void ValidateFetchObjrefForHandle(OBJECTREF); */ void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref); +#ifndef DACCESS_COMPILE +int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj); +#endif // DACCESS_COMPILE + /* * interlocked-exchange assignment */ @@ -224,4 +227,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..657c7009591dd3 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -7,6 +7,62 @@ #ifndef _HANDLETABLE_INL #define _HANDLETABLE_INL +#ifndef DACCESS_COMPILE +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); + 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; + } + } +} +#else +void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value); +#endif // DACCESS_COMPILE + inline void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF objref) { STATIC_CONTRACT_NOTHROW; @@ -41,7 +97,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. diff --git a/src/coreclr/gc/handletablepriv.h b/src/coreclr/gc/handletablepriv.h index e09e89cecaaae5..7a2cae0b5f5657 100644 --- a/src/coreclr/gc/handletablepriv.h +++ b/src/coreclr/gc/handletablepriv.h @@ -945,12 +945,4 @@ PTR_TableSegment CALLBACK xxxAsyncSegmentIterator(PTR_HandleTable pTable, TableS #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 From 135c59e1a1305ed7fa49c0360597d63fc8e612b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:15:49 +0000 Subject: [PATCH 02/12] Optimize GC handle write barrier Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/handletable.cpp | 2 -- src/coreclr/gc/handletable.h | 2 ++ src/coreclr/gc/handletable.inl | 7 +++++++ src/coreclr/gc/handletablepriv.h | 13 ------------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/coreclr/gc/handletable.cpp b/src/coreclr/gc/handletable.cpp index 926bd1be9149c2..88f97ea1e6989b 100644 --- a/src/coreclr/gc/handletable.cpp +++ b/src/coreclr/gc/handletable.cpp @@ -548,7 +548,6 @@ void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) #endif } -#ifndef DACCESS_COMPILE /* * HndEnumHandles * @@ -1089,4 +1088,3 @@ void DEBUG_LogScanningStatistics(HandleTable *pTable, uint32_t level) /*--------------------------------------------------------------------------*/ - diff --git a/src/coreclr/gc/handletable.h b/src/coreclr/gc/handletable.h index 97698014e5aebc..e05135a072dfe4 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -14,6 +14,7 @@ #define _HANDLETABLE_H #include "gcinterface.h" +#include "handletableconstants.h" /**************************************************************************** * @@ -149,6 +150,7 @@ void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref); #ifndef DACCESS_COMPILE int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj); +uint32_t HandleFetchType(OBJECTHANDLE handle); #endif // DACCESS_COMPILE /* diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index 657c7009591dd3..711941f2ef1e0c 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -30,6 +30,13 @@ FORCEINLINE void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF if (*pClumpAge != 0) { int generation = GetConvertedGeneration(value); + + if (generation == 0) + { + *pClumpAge = 0; + return; + } + uint32_t uType = HandleFetchType(handle); #ifdef FEATURE_ASYNC_PINNED_HANDLES diff --git a/src/coreclr/gc/handletablepriv.h b/src/coreclr/gc/handletablepriv.h index 7a2cae0b5f5657..d62b0918da9051 100644 --- a/src/coreclr/gc/handletablepriv.h +++ b/src/coreclr/gc/handletablepriv.h @@ -609,15 +609,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 * @@ -942,7 +933,3 @@ void CALLBACK BlockVerifyAgeMapForBlocks(PTR_TableSegment pSegment, uint32_t uBl PTR_TableSegment CALLBACK xxxAsyncSegmentIterator(PTR_HandleTable pTable, TableSegment *pPrevSegment, CrstHolderWithState *pCrstHolder); /*--------------------------------------------------------------------------*/ - -#ifndef DACCESS_COMPILE - -#endif //DACCESS_COMPILE From a40af76b57af066c2b18ee74beff63d8acf1880f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 05:51:22 +0000 Subject: [PATCH 03/12] Inline GC handle helpers Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/gchandletable.cpp | 2 ++ src/coreclr/gc/handletable.cpp | 9 +------- src/coreclr/gc/handletable.h | 9 -------- src/coreclr/gc/handletable.inl | 24 +++++++++++++++++++++ src/coreclr/gc/handletableconstants.h | 3 +++ src/coreclr/gc/handletablecore.cpp | 30 --------------------------- src/coreclr/gc/handletablepriv.h | 2 ++ src/coreclr/gc/handletablescan.cpp | 2 +- src/coreclr/gc/objecthandle.cpp | 1 + 9 files changed, 34 insertions(+), 48 deletions(-) diff --git a/src/coreclr/gc/gchandletable.cpp b/src/coreclr/gc/gchandletable.cpp index e70b38ebb6c339..6aa03a6aa04816 100644 --- a/src/coreclr/gc/gchandletable.cpp +++ b/src/coreclr/gc/gchandletable.cpp @@ -4,9 +4,11 @@ #include "common.h" #include "gcenv.h" +#include "gc.h" #include "gchandletableimpl.h" #include "objecthandle.h" #include "handletablepriv.h" +#include "handletable.inl" GCHandleStore* g_gcGlobalHandleStore; diff --git a/src/coreclr/gc/handletable.cpp b/src/coreclr/gc/handletable.cpp index 88f97ea1e6989b..d3e7eef739a13c 100644 --- a/src/coreclr/gc/handletable.cpp +++ b/src/coreclr/gc/handletable.cpp @@ -19,19 +19,12 @@ #include "objecthandle.h" #include "handletablepriv.h" +#include "handletable.inl" #if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE) 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 diff --git a/src/coreclr/gc/handletable.h b/src/coreclr/gc/handletable.h index e05135a072dfe4..fcd3f9345cd5f2 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -148,11 +148,6 @@ void ValidateFetchObjrefForHandle(OBJECTREF); */ void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref); -#ifndef DACCESS_COMPILE -int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj); -uint32_t HandleFetchType(OBJECTHANDLE handle); -#endif // DACCESS_COMPILE - /* * interlocked-exchange assignment */ @@ -224,8 +219,4 @@ FORCEINLINE BOOL HndIsNullOrDestroyedHandle(_UNCHECKED_OBJECTREF value) return (value == NULL); } -/*--------------------------------------------------------------------------*/ - -#include "handletable.inl" - #endif //_HANDLETABLE_H diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index 711941f2ef1e0c..b2d3cc4ac4f247 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -8,6 +8,30 @@ #define _HANDLETABLE_INL #ifndef DACCESS_COMPILE +#include "gc.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); 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 d62b0918da9051..ea8f61e7aced9d 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; diff --git a/src/coreclr/gc/handletablescan.cpp b/src/coreclr/gc/handletablescan.cpp index 15137c85f1e2e1..bf8a16f93dca1b 100644 --- a/src/coreclr/gc/handletablescan.cpp +++ b/src/coreclr/gc/handletablescan.cpp @@ -18,6 +18,7 @@ #include "objecthandle.h" #include "handletablepriv.h" +#include "handletable.inl" /**************************************************************************** * @@ -1878,4 +1879,3 @@ uint32_t TableSegment::DacSize(TADDR addr) } #endif /*--------------------------------------------------------------------------*/ - diff --git a/src/coreclr/gc/objecthandle.cpp b/src/coreclr/gc/objecthandle.cpp index 756dd52411f904..0ca872549da16a 100644 --- a/src/coreclr/gc/objecthandle.cpp +++ b/src/coreclr/gc/objecthandle.cpp @@ -17,6 +17,7 @@ #include "objecthandle.h" #include "handletablepriv.h" +#include "handletable.inl" #include "gchandletableimpl.h" From 86e3eb77279f9ad1deba56a14f1d363394a3e00c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 05:52:57 +0000 Subject: [PATCH 04/12] Remove redundant GC include Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/gchandletable.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/gc/gchandletable.cpp b/src/coreclr/gc/gchandletable.cpp index 6aa03a6aa04816..b9d4d18921d887 100644 --- a/src/coreclr/gc/gchandletable.cpp +++ b/src/coreclr/gc/gchandletable.cpp @@ -4,7 +4,6 @@ #include "common.h" #include "gcenv.h" -#include "gc.h" #include "gchandletableimpl.h" #include "objecthandle.h" #include "handletablepriv.h" From e4315e5ca19be0a07ad9c9d4ac3bb71c264ad0d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 06:10:46 +0000 Subject: [PATCH 05/12] Drop handletable.inl include from gcinternal.h Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/gcinternal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/gc/gcinternal.h b/src/coreclr/gc/gcinternal.h index 20100696d596a3..367158260027c5 100644 --- a/src/coreclr/gc/gcinternal.h +++ b/src/coreclr/gc/gcinternal.h @@ -12,7 +12,6 @@ #include "gcdesc.h" #include "softwarewritewatch.h" #include "handletable.h" -#include "handletable.inl" #include "gcenv.inl" #include "gceventstatus.h" #include From f180588e72a298b7af5e7ab73b03f8473fd6b910 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:18:20 +0000 Subject: [PATCH 06/12] Restore handletable.inl include in gcinternal.h Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/gcinternal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/gc/gcinternal.h b/src/coreclr/gc/gcinternal.h index 367158260027c5..20100696d596a3 100644 --- a/src/coreclr/gc/gcinternal.h +++ b/src/coreclr/gc/gcinternal.h @@ -12,6 +12,7 @@ #include "gcdesc.h" #include "softwarewritewatch.h" #include "handletable.h" +#include "handletable.inl" #include "gcenv.inl" #include "gceventstatus.h" #include From f212be44e76eac9431a5c4a10b2041a5fa8dc16d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:29:47 +0000 Subject: [PATCH 07/12] Include handletable.inl from handletable.h only Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/gc.h | 6 ++++-- src/coreclr/gc/gchandletable.cpp | 1 - src/coreclr/gc/gcinternal.h | 1 - src/coreclr/gc/handletable.cpp | 1 - src/coreclr/gc/handletable.h | 4 ++++ src/coreclr/gc/handletable.inl | 4 +--- src/coreclr/gc/handletablescan.cpp | 1 - src/coreclr/gc/objecthandle.cpp | 1 - 8 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/coreclr/gc/gc.h b/src/coreclr/gc/gc.h index f3658411478732..38e85ba77cb318 100644 --- a/src/coreclr/gc/gc.h +++ b/src/coreclr/gc/gc.h @@ -16,8 +16,6 @@ Module Name: #include "gcinterface.h" #include "env/gcenv.os.h" -#include "gchandletableimpl.h" - #ifdef BUILD_AS_STANDALONE #include "gcenv.ee.standalone.inl" @@ -486,4 +484,8 @@ void log_init_error_to_host (const char* format, ...); uint64_t GetHighPrecisionTimeStamp(); +// Included last since handletable.inl (pulled in by this header) depends on +// the declarations above, such as g_theGCHeap. +#include "gchandletableimpl.h" + #endif // __GC_H diff --git a/src/coreclr/gc/gchandletable.cpp b/src/coreclr/gc/gchandletable.cpp index b9d4d18921d887..e70b38ebb6c339 100644 --- a/src/coreclr/gc/gchandletable.cpp +++ b/src/coreclr/gc/gchandletable.cpp @@ -7,7 +7,6 @@ #include "gchandletableimpl.h" #include "objecthandle.h" #include "handletablepriv.h" -#include "handletable.inl" GCHandleStore* g_gcGlobalHandleStore; diff --git a/src/coreclr/gc/gcinternal.h b/src/coreclr/gc/gcinternal.h index 20100696d596a3..367158260027c5 100644 --- a/src/coreclr/gc/gcinternal.h +++ b/src/coreclr/gc/gcinternal.h @@ -12,7 +12,6 @@ #include "gcdesc.h" #include "softwarewritewatch.h" #include "handletable.h" -#include "handletable.inl" #include "gcenv.inl" #include "gceventstatus.h" #include diff --git a/src/coreclr/gc/handletable.cpp b/src/coreclr/gc/handletable.cpp index d3e7eef739a13c..87679791268c2a 100644 --- a/src/coreclr/gc/handletable.cpp +++ b/src/coreclr/gc/handletable.cpp @@ -19,7 +19,6 @@ #include "objecthandle.h" #include "handletablepriv.h" -#include "handletable.inl" #if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE) DWORD g_dwHandles = 0; diff --git a/src/coreclr/gc/handletable.h b/src/coreclr/gc/handletable.h index fcd3f9345cd5f2..54a321a5f0580e 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -219,4 +219,8 @@ FORCEINLINE BOOL HndIsNullOrDestroyedHandle(_UNCHECKED_OBJECTREF value) return (value == NULL); } +/*--------------------------------------------------------------------------*/ + +#include "handletable.inl" + #endif //_HANDLETABLE_H diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index b2d3cc4ac4f247..8e5fe4e405aa72 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -90,9 +90,6 @@ FORCEINLINE void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF } } } -#else -void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value); -#endif // DACCESS_COMPILE inline void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF objref) { @@ -221,5 +218,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/handletablescan.cpp b/src/coreclr/gc/handletablescan.cpp index bf8a16f93dca1b..bad713c6a51b55 100644 --- a/src/coreclr/gc/handletablescan.cpp +++ b/src/coreclr/gc/handletablescan.cpp @@ -18,7 +18,6 @@ #include "objecthandle.h" #include "handletablepriv.h" -#include "handletable.inl" /**************************************************************************** * diff --git a/src/coreclr/gc/objecthandle.cpp b/src/coreclr/gc/objecthandle.cpp index 0ca872549da16a..756dd52411f904 100644 --- a/src/coreclr/gc/objecthandle.cpp +++ b/src/coreclr/gc/objecthandle.cpp @@ -17,7 +17,6 @@ #include "objecthandle.h" #include "handletablepriv.h" -#include "handletable.inl" #include "gchandletableimpl.h" From fde52c210c85f7cccc5d2f97cf332d6011610309 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 21:15:52 +0000 Subject: [PATCH 08/12] Move handletableconstants.h include into handletable.inl Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/handletable.h | 1 - src/coreclr/gc/handletable.inl | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/gc/handletable.h b/src/coreclr/gc/handletable.h index 54a321a5f0580e..ec3208579cba29 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -14,7 +14,6 @@ #define _HANDLETABLE_H #include "gcinterface.h" -#include "handletableconstants.h" /**************************************************************************** * diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index 8e5fe4e405aa72..7bd333837b88fd 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -9,6 +9,7 @@ #ifndef DACCESS_COMPILE #include "gc.h" +#include "handletableconstants.h" FORCEINLINE int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj) { From 372ce5b36b20d67af0914a170210be41ba37f387 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Aug 2026 23:39:59 +0000 Subject: [PATCH 09/12] Fix include cycle by moving gchandletableimpl.h include to gcinternal.h Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/gc.h | 4 ---- src/coreclr/gc/gcinternal.h | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/gc/gc.h b/src/coreclr/gc/gc.h index 38e85ba77cb318..eac77019ff3e89 100644 --- a/src/coreclr/gc/gc.h +++ b/src/coreclr/gc/gc.h @@ -484,8 +484,4 @@ void log_init_error_to_host (const char* format, ...); uint64_t GetHighPrecisionTimeStamp(); -// Included last since handletable.inl (pulled in by this header) depends on -// the declarations above, such as g_theGCHeap. -#include "gchandletableimpl.h" - #endif // __GC_H diff --git a/src/coreclr/gc/gcinternal.h b/src/coreclr/gc/gcinternal.h index 367158260027c5..cf184bbb52d63f 100644 --- a/src/coreclr/gc/gcinternal.h +++ b/src/coreclr/gc/gcinternal.h @@ -12,6 +12,7 @@ #include "gcdesc.h" #include "softwarewritewatch.h" #include "handletable.h" +#include "gchandletableimpl.h" #include "gcenv.inl" #include "gceventstatus.h" #include From 465171bbb10990295f2c00550ebf497c8af36d62 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Aug 2026 04:52:55 +0000 Subject: [PATCH 10/12] Inline HndLogSetEvent into handletable.inl Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/handletable.cpp | 33 --------------------------------- src/coreclr/gc/handletable.h | 5 ----- src/coreclr/gc/handletable.inl | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/coreclr/gc/handletable.cpp b/src/coreclr/gc/handletable.cpp index b33423e8d8ab79..4aacd03e668ccb 100644 --- a/src/coreclr/gc/handletable.cpp +++ b/src/coreclr/gc/handletable.cpp @@ -508,39 +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 -} - /* * HndEnumHandles * diff --git a/src/coreclr/gc/handletable.h b/src/coreclr/gc/handletable.h index ec3208579cba29..2df719aa400be7 100644 --- a/src/coreclr/gc/handletable.h +++ b/src/coreclr/gc/handletable.h @@ -91,11 +91,6 @@ HHANDLETABLE HndGetHandleTable(OBJECTHANDLE handle); */ void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF value); -/* - * logging an ETW event (for inlined methods) - */ -void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value); - /* * NON-GC handle enumeration */ diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index 7bd333837b88fd..570464f37cd1e4 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -9,6 +9,7 @@ #ifndef DACCESS_COMPILE #include "gc.h" +#include "gceventstatus.h" #include "handletableconstants.h" FORCEINLINE int GetConvertedGeneration(_UNCHECKED_OBJECTREF obj) @@ -92,6 +93,39 @@ FORCEINLINE void HndWriteBarrierWorker(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF } } +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; From 796149b7a5a62448aed8f4ea9397d45d13be19b7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Aug 2026 04:13:05 +0000 Subject: [PATCH 11/12] Delete dead TableFreeHandlesToCache method Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/handletablecache.cpp | 30 ----------------------------- src/coreclr/gc/handletablepriv.h | 9 --------- 2 files changed, 39 deletions(-) diff --git a/src/coreclr/gc/handletablecache.cpp b/src/coreclr/gc/handletablecache.cpp index c201e32929c308..fec3e033ae61bb 100644 --- a/src/coreclr/gc/handletablecache.cpp +++ b/src/coreclr/gc/handletablecache.cpp @@ -851,35 +851,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/handletablepriv.h b/src/coreclr/gc/handletablepriv.h index ea8f61e7aced9d..2ea6c63499597e 100644 --- a/src/coreclr/gc/handletablepriv.h +++ b/src/coreclr/gc/handletablepriv.h @@ -754,15 +754,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); - /*--------------------------------------------------------------------------*/ From 55c837be92c323b112b792431e72530f3f0e7a7a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Aug 2026 04:28:43 +0000 Subject: [PATCH 12/12] Inline TableFreeSingleHandleToCache, remove dead error handling, cache GetGlobalHandleStore in NativeAOT Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/gc/handletablecache.cpp | 60 ------------------ src/coreclr/gc/handletablepriv.h | 63 ++++++++++++++++++- .../nativeaot/Runtime/HandleTableHelpers.cpp | 6 +- .../nativeaot/Runtime/clrgc.enabled.cpp | 1 + .../nativeaot/Runtime/gchandleutilities.h | 10 +++ .../nativeaot/Runtime/gcheaputilities.cpp | 2 + src/coreclr/vm/appdomain.cpp | 4 -- 7 files changed, 78 insertions(+), 68 deletions(-) diff --git a/src/coreclr/gc/handletablecache.cpp b/src/coreclr/gc/handletablecache.cpp index fec3e033ae61bb..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 * diff --git a/src/coreclr/gc/handletablepriv.h b/src/coreclr/gc/handletablepriv.h index 2ea6c63499597e..149413c772e21b 100644 --- a/src/coreclr/gc/handletablepriv.h +++ b/src/coreclr/gc/handletablepriv.h @@ -733,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 * @@ -741,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 /* 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);