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 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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