Skip to content

Commit 56510f0

Browse files
Weak interior handles (dotnet#100446)
- Implementation of weak interior handle - Use new weak interior handle to make managed class object storage consistent between collectible and non-collectible types
1 parent d7e2bc9 commit 56510f0

21 files changed

+294
-269
lines changed

src/coreclr/debug/daccess/daccess.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7770,6 +7770,8 @@ void CALLBACK DacHandleWalker::EnumCallback(PTR_UNCHECKED_OBJECTREF handle, uint
77707770
data.Type = param->Type;
77717771
if (param->Type == HNDTYPE_DEPENDENT)
77727772
data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
7773+
else if (param->Type == HNDTYPE_WEAK_INTERIOR_POINTER)
7774+
data.Secondary = TO_CDADDR(HndGetHandleExtraInfo(handle.GetAddr()));
77737775
else
77747776
data.Secondary = 0;
77757777
data.AppDomain = param->AppDomain;

src/coreclr/debug/daccess/request.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3290,7 +3290,7 @@ ClrDataAccess::GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int ind
32903290
HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
32913291
{
32923292
unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_DEPENDENT,
3293-
HNDTYPE_SIZEDREF,
3293+
HNDTYPE_SIZEDREF, HNDTYPE_WEAK_INTERIOR_POINTER,
32943294
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
32953295
HNDTYPE_REFCOUNTED,
32963296
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL

src/coreclr/gc/gchandletable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ Object* GCHandleManager::InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE h
213213
HandleType GCHandleManager::HandleFetchType(OBJECTHANDLE handle)
214214
{
215215
uint32_t type = ::HandleFetchType(handle);
216-
assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM);
216+
assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_INTERIOR_POINTER);
217217
return static_cast<HandleType>(type);
218218
}
219219

src/coreclr/gc/gcinterface.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,17 @@ typedef enum
502502
* but we are keeping it here for backward compatibility purposes"
503503
*
504504
*/
505-
HNDTYPE_WEAK_NATIVE_COM = 9
505+
HNDTYPE_WEAK_NATIVE_COM = 9,
506+
507+
/*
508+
* INTERIOR POINTER HANDLES
509+
*
510+
* Interior pointer handles allow the vm to request that the GC keep an interior pointer to
511+
* a given object updated to keep pointing at the same location within an object. These handles
512+
* have an extra pointer which points at an interior pointer into the first object.
513+
*
514+
*/
515+
HNDTYPE_WEAK_INTERIOR_POINTER = 10
506516
} HandleType;
507517

508518
typedef enum

src/coreclr/gc/gcscan.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void GCScan::GcScanHandles (promote_func* fn, int condemned, int max_gen,
171171
Ref_UpdatePointers(condemned, max_gen, sc, fn);
172172
Ref_UpdatePinnedPointers(condemned, max_gen, sc, fn);
173173
Ref_ScanDependentHandlesForRelocation(condemned, max_gen, sc, fn);
174+
Ref_ScanWeakInteriorPointersForRelocation(condemned, max_gen, sc, fn);
174175
}
175176
}
176177

src/coreclr/gc/handletablescan.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,15 @@ static void VerifyObjectAndAge(_UNCHECKED_OBJECTREF from, _UNCHECKED_OBJECTREF o
931931
}
932932
}
933933

934+
size_t my_get_size (_UNCHECKED_OBJECTREF ob)
935+
{
936+
MethodTable* mT = ob->GetGCSafeMethodTable();
937+
938+
return (mT->GetBaseSize() +
939+
(mT->HasComponentSize() ?
940+
((size_t)reinterpret_cast<ArrayBase*>(ob)->GetNumComponents() * mT->RawGetComponentSize()) : 0));
941+
}
942+
934943
/*
935944
* BlockVerifyAgeMapForBlocksWorker
936945
*
@@ -992,6 +1001,23 @@ void BlockVerifyAgeMapForBlocksWorker(uint32_t *pdwGen, uint32_t dwClumpMask, Sc
9921001
}
9931002
}
9941003
}
1004+
if (uType == HNDTYPE_WEAK_INTERIOR_POINTER)
1005+
{
1006+
PTR_uintptr_t pUserData = HandleQuickFetchUserDataPointer((OBJECTHANDLE)pValue);
1007+
1008+
// if we did then copy the value
1009+
if (pUserData)
1010+
{
1011+
uintptr_t pObjectInteriorPointer = **reinterpret_cast<uintptr_t**>(pUserData);
1012+
_UNCHECKED_OBJECTREF pObjectPointerRef = *pValue;
1013+
uintptr_t pObjectPointer = reinterpret_cast<uintptr_t>(pObjectPointerRef);
1014+
if (pObjectInteriorPointer < pObjectPointer || pObjectInteriorPointer >= (pObjectPointer + my_get_size(pObjectPointerRef)))
1015+
{
1016+
_ASSERTE(!"Weak interior pointer has interior pointer which does not point at the object of the handle.");
1017+
GCToEEInterface::HandleFatalError(COR_E_EXECUTIONENGINE);
1018+
}
1019+
}
1020+
}
9951021
}
9961022
}
9971023
}

src/coreclr/gc/objecthandle.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,47 @@ void CALLBACK TraceDependentHandle(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pEx
145145
}
146146
}
147147

148+
void CALLBACK UpdateWeakInteriorHandle(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo, uintptr_t lp1, uintptr_t lp2)
149+
{
150+
LIMITED_METHOD_CONTRACT;
151+
_ASSERTE(pExtraInfo);
152+
153+
Object **pPrimaryRef = (Object **)pObjRef;
154+
uintptr_t **ppInteriorPtrRef = (uintptr_t **)pExtraInfo;
155+
156+
LOG((LF_GC, LL_INFO10000, LOG_HANDLE_OBJECT("Querying for new location of ",
157+
pPrimaryRef, "to ", *pPrimaryRef)));
158+
159+
Object *pOldPrimary = *pPrimaryRef;
160+
161+
_ASSERTE(lp2);
162+
promote_func* callback = (promote_func*) lp2;
163+
callback(pPrimaryRef, (ScanContext *)lp1, 0);
164+
165+
Object *pNewPrimary = *pPrimaryRef;
166+
if (pNewPrimary != NULL)
167+
{
168+
uintptr_t pOldInterior = **ppInteriorPtrRef;
169+
uintptr_t delta = ((uintptr_t)pNewPrimary) - ((uintptr_t)pOldPrimary);
170+
uintptr_t pNewInterior = pOldInterior + delta;
171+
**ppInteriorPtrRef = pNewInterior;
172+
#ifdef _DEBUG
173+
if (pOldPrimary != *pPrimaryRef)
174+
LOG((LF_GC, LL_INFO10000, "Updating " FMT_HANDLE "from" FMT_ADDR "to " FMT_OBJECT "\n",
175+
DBG_ADDR(pPrimaryRef), DBG_ADDR(pOldPrimary), DBG_ADDR(*pPrimaryRef)));
176+
else
177+
LOG((LF_GC, LL_INFO10000, "Updating " FMT_HANDLE "- " FMT_OBJECT "did not move\n",
178+
DBG_ADDR(pPrimaryRef), DBG_ADDR(*pPrimaryRef)));
179+
if (pOldInterior != pNewInterior)
180+
LOG((LF_GC, LL_INFO10000, "Updating " FMT_HANDLE "from" FMT_ADDR "to " FMT_OBJECT "\n",
181+
DBG_ADDR(*ppInteriorPtrRef), DBG_ADDR(pOldInterior), DBG_ADDR(pNewInterior)));
182+
else
183+
LOG((LF_GC, LL_INFO10000, "Updating " FMT_HANDLE "- " FMT_OBJECT "did not move\n",
184+
DBG_ADDR(*ppInteriorPtrRef), DBG_ADDR(pOldInterior)));
185+
#endif
186+
}
187+
}
188+
148189
void CALLBACK UpdateDependentHandle(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo, uintptr_t lp1, uintptr_t lp2)
149190
{
150191
LIMITED_METHOD_CONTRACT;
@@ -427,6 +468,7 @@ void CALLBACK ScanPointerForProfilerAndETW(_UNCHECKED_OBJECTREF *pObjRef, uintpt
427468
break;
428469
case HNDTYPE_WEAK_SHORT:
429470
case HNDTYPE_WEAK_LONG:
471+
case HNDTYPE_WEAK_INTERIOR_POINTER:
430472
#ifdef FEATURE_WEAK_NATIVE_COM_HANDLES
431473
case HNDTYPE_WEAK_NATIVE_COM:
432474
#endif // FEATURE_WEAK_NATIVE_COM_HANDLES
@@ -527,6 +569,7 @@ static const uint32_t s_rgTypeFlags[] =
527569
HNDF_NORMAL, // HNDTYPE_ASYNCPINNED
528570
HNDF_EXTRAINFO, // HNDTYPE_SIZEDREF
529571
HNDF_EXTRAINFO, // HNDTYPE_WEAK_NATIVE_COM
572+
HNDF_EXTRAINFO, // HNDTYPE_WEAK_INTERIOR_POINTER
530573
};
531574

532575
int getNumberOfSlots()
@@ -1170,6 +1213,7 @@ void Ref_CheckReachable(uint32_t condemned, uint32_t maxgen, ScanContext *sc)
11701213
#ifdef FEATURE_REFCOUNTED_HANDLES
11711214
HNDTYPE_REFCOUNTED,
11721215
#endif
1216+
HNDTYPE_WEAK_INTERIOR_POINTER
11731217
};
11741218

11751219
// check objects pointed to by short weak handles
@@ -1339,6 +1383,40 @@ void Ref_ScanDependentHandlesForClearing(uint32_t condemned, uint32_t maxgen, Sc
13391383
}
13401384
}
13411385

1386+
// Perform a scan of weak interior pointers for the purpose of updating handles to track relocated objects.
1387+
void Ref_ScanWeakInteriorPointersForRelocation(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn)
1388+
{
1389+
LOG((LF_GC, LL_INFO10000, "Relocating moved dependent handles in generation %u\n", condemned));
1390+
uint32_t type = HNDTYPE_WEAK_INTERIOR_POINTER;
1391+
uint32_t flags = (sc->concurrent) ? HNDGCF_ASYNC : HNDGCF_NORMAL;
1392+
flags |= HNDGCF_EXTRAINFO;
1393+
1394+
HandleTableMap *walk = &g_HandleTableMap;
1395+
while (walk)
1396+
{
1397+
for (uint32_t i = 0; i < INITIAL_HANDLE_TABLE_ARRAY_SIZE; i ++)
1398+
{
1399+
if (walk->pBuckets[i] != NULL)
1400+
{
1401+
int uCPUindex = getSlotNumber(sc);
1402+
int uCPUlimit = getNumberOfSlots();
1403+
assert(uCPUlimit > 0);
1404+
int uCPUstep = getThreadCount(sc);
1405+
HHANDLETABLE* pTable = walk->pBuckets[i]->pTable;
1406+
for ( ; uCPUindex < uCPUlimit; uCPUindex += uCPUstep)
1407+
{
1408+
HHANDLETABLE hTable = pTable[uCPUindex];
1409+
if (hTable)
1410+
{
1411+
HndScanHandlesForGC(hTable, UpdateWeakInteriorHandle, uintptr_t(sc), uintptr_t(fn), &type, 1, condemned, maxgen, flags );
1412+
}
1413+
}
1414+
}
1415+
}
1416+
walk = walk->pNext;
1417+
}
1418+
}
1419+
13421420
// Perform a scan of dependent handles for the purpose of updating handles to track relocated objects.
13431421
void Ref_ScanDependentHandlesForRelocation(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn)
13441422
{
@@ -1590,6 +1668,7 @@ void Ref_ScanHandlesForProfilerAndETW(uint32_t maxgen, uintptr_t lp1, handle_sca
15901668
HNDTYPE_ASYNCPINNED,
15911669
#endif
15921670
HNDTYPE_SIZEDREF,
1671+
HNDTYPE_WEAK_INTERIOR_POINTER
15931672
};
15941673

15951674
uint32_t flags = HNDGCF_NORMAL;
@@ -1712,6 +1791,7 @@ void Ref_AgeHandles(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
17121791
HNDTYPE_ASYNCPINNED,
17131792
#endif
17141793
HNDTYPE_SIZEDREF,
1794+
HNDTYPE_WEAK_INTERIOR_POINTER
17151795
};
17161796

17171797
// perform a multi-type scan that ages the handles
@@ -1766,6 +1846,7 @@ void Ref_RejuvenateHandles(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
17661846
HNDTYPE_ASYNCPINNED,
17671847
#endif
17681848
HNDTYPE_SIZEDREF,
1849+
HNDTYPE_WEAK_INTERIOR_POINTER
17691850
};
17701851

17711852
// reset the ages of these handles
@@ -1819,6 +1900,7 @@ void Ref_VerifyHandleTable(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
18191900
#endif
18201901
HNDTYPE_SIZEDREF,
18211902
HNDTYPE_DEPENDENT,
1903+
HNDTYPE_WEAK_INTERIOR_POINTER
18221904
};
18231905

18241906
// verify these handles

src/coreclr/gc/objecthandle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ DhContext *Ref_GetDependentHandleContext(ScanContext* sc);
102102
bool Ref_ScanDependentHandlesForPromotion(DhContext *pDhContext);
103103
void Ref_ScanDependentHandlesForClearing(uint32_t condemned, uint32_t maxgen, ScanContext* sc);
104104
void Ref_ScanDependentHandlesForRelocation(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
105+
void Ref_ScanWeakInteriorPointersForRelocation(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
105106
void Ref_ScanSizedRefHandles(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Ref_promote_func* fn);
106107

107108
void Ref_CheckReachable (uint32_t uCondemnedGeneration, uint32_t uMaxGeneration, ScanContext* sc);

src/coreclr/vm/appdomain.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,12 @@ class BaseDomain
10381038
return ::CreatePinningHandle(m_handleStore, object);
10391039
}
10401040

1041+
OBJECTHANDLE CreateWeakInteriorHandle(OBJECTREF object, void* pInteriorPointerLocation)
1042+
{
1043+
WRAPPER_NO_CONTRACT;
1044+
return ::CreateWeakInteriorHandle(m_handleStore, object, pInteriorPointerLocation);
1045+
}
1046+
10411047
OBJECTHANDLE CreateSizedRefHandle(OBJECTREF object)
10421048
{
10431049
WRAPPER_NO_CONTRACT;

src/coreclr/vm/gchandleutilities.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,18 @@ inline OBJECTHANDLE CreateDependentHandle(IGCHandleStore* store, OBJECTREF prima
147147
return hnd;
148148
}
149149

150+
inline OBJECTHANDLE CreateWeakInteriorHandle(IGCHandleStore* store, OBJECTREF primary, void* interiorPointerLocation)
151+
{
152+
OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(primary), HNDTYPE_WEAK_INTERIOR_POINTER, interiorPointerLocation);
153+
if (!hnd)
154+
{
155+
COMPlusThrowOM();
156+
}
157+
158+
DiagHandleCreated(hnd, primary);
159+
return hnd;
160+
}
161+
150162
// Global handle creation convenience functions
151163
inline OBJECTHANDLE CreateGlobalHandleCommon(OBJECTREF object, HandleType type)
152164
{
@@ -321,6 +333,11 @@ inline void DestroyGlobalRefcountedHandle(OBJECTHANDLE handle)
321333
DestroyHandleCommon(handle, HNDTYPE_REFCOUNTED);
322334
}
323335

336+
inline void DestroyWeakInteriorHandle(OBJECTHANDLE handle)
337+
{
338+
DestroyHandleCommon(handle, HNDTYPE_WEAK_INTERIOR_POINTER);
339+
}
340+
324341
inline void DestroyTypedHandle(OBJECTHANDLE handle)
325342
{
326343
DiagHandleDestroyed(handle);
@@ -338,6 +355,7 @@ typedef Wrapper<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyRefcountedHandle>
338355
typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyLongWeakHandle> LongWeakHandleHolder;
339356
typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyGlobalStrongHandle> GlobalStrongHandleHolder;
340357
typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyGlobalShortWeakHandle> GlobalShortWeakHandleHolder;
358+
typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, DestroyWeakInteriorHandle> WeakInteriorHandleHolder;
341359
typedef Holder<OBJECTHANDLE, DoNothing<OBJECTHANDLE>, ResetOBJECTHANDLE> ObjectInHandleHolder;
342360

343361
class RCOBJECTHANDLEHolder : public RefCountedOHWrapper

0 commit comments

Comments
 (0)