From 8df01f50ca980ab8840124c74037782f75702032 Mon Sep 17 00:00:00 2001 From: Sean Gillespie Date: Tue, 12 Dec 2017 19:04:07 -0800 Subject: [PATCH] Revert "[Local GC] Move knowledge of overlapped I/O objects to the EE through four callbacks (#14982)" This reverts commit c755e3b7f5d597c8d192675dbaaa337268d93f1c. --- src/gc/env/common.h | 1 - src/gc/env/gcenv.base.h | 5 --- src/gc/env/gcenv.ee.h | 2 -- src/gc/gcenv.ee.standalone.inl | 11 ------ src/gc/gchandletable.cpp | 4 +-- src/gc/gchandletableimpl.h | 2 +- src/gc/gcinterface.ee.h | 32 ----------------- src/gc/gcinterface.h | 31 ++++++---------- src/gc/handletable.cpp | 64 +++++++++++++++++++-------------- src/gc/handletablecore.cpp | 64 ++++++++++++++++++++++----------- src/gc/handletablepriv.h | 2 +- src/gc/handletablescan.cpp | 69 ++++++++++++++++++++++++++--------- src/gc/objecthandle.cpp | 55 ++++++++++++++++++---------- src/gc/objecthandle.h | 2 +- src/gc/sample/gcenv.ee.cpp | 8 ----- src/vm/appdomain.cpp | 38 +------------------- src/vm/gcenv.ee.cpp | 81 ++---------------------------------------- src/vm/gcenv.ee.h | 2 -- src/vm/gcenv.ee.standalone.cpp | 3 +- src/vm/gcenv.ee.static.cpp | 3 +- 20 files changed, 192 insertions(+), 287 deletions(-) diff --git a/src/gc/env/common.h b/src/gc/env/common.h index 1c2f75c..32c0d93 100644 --- a/src/gc/env/common.h +++ b/src/gc/env/common.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/src/gc/env/gcenv.base.h b/src/gc/env/gcenv.base.h index e1d40d6..734b46f 100644 --- a/src/gc/env/gcenv.base.h +++ b/src/gc/env/gcenv.base.h @@ -320,11 +320,6 @@ inline void* ALIGN_DOWN(void* ptr, size_t alignment) return reinterpret_cast(ALIGN_DOWN(as_size_t, alignment)); } -inline int GetRandomInt(int max) -{ - return rand() % max; -} - typedef struct _PROCESSOR_NUMBER { uint16_t Group; uint8_t Number; diff --git a/src/gc/env/gcenv.ee.h b/src/gc/env/gcenv.ee.h index 44828b7..d747a5b 100644 --- a/src/gc/env/gcenv.ee.h +++ b/src/gc/env/gcenv.ee.h @@ -80,8 +80,6 @@ public: static bool IsGCThread(); static bool WasCurrentThreadCreatedByGC(); static bool CreateThread(void (*threadStart)(void*), void* arg, bool is_suspendable, const char* name); - static void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback); - static void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)); }; #endif // __GCENV_EE_H__ diff --git a/src/gc/gcenv.ee.standalone.inl b/src/gc/gcenv.ee.standalone.inl index c114b33..a9e45c9 100644 --- a/src/gc/gcenv.ee.standalone.inl +++ b/src/gc/gcenv.ee.standalone.inl @@ -258,16 +258,5 @@ inline bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, return g_theGCToCLR->CreateThread(threadStart, arg, is_suspendable, name); } -inline void GCToEEInterface::WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) -{ - assert(g_theGCToCLR != nullptr); - return g_theGCToCLR->WalkAsyncPinnedForPromotion(object, sc, callback); -} - -inline void GCToEEInterface::WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)) -{ - assert(g_theGCToCLR != nullptr); - return g_theGCToCLR->WalkAsyncPinned(object, context, callback); -} #endif // __GCTOENV_EE_STANDALONE_INL__ diff --git a/src/gc/gchandletable.cpp b/src/gc/gchandletable.cpp index 7389706..03464b2 100644 --- a/src/gc/gchandletable.cpp +++ b/src/gc/gchandletable.cpp @@ -57,11 +57,11 @@ OBJECTHANDLE GCHandleStore::CreateDependentHandle(Object* primary, Object* secon return handle; } -void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)) +void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget) { // assumption - the IGCHandleStore is an instance of GCHandleStore GCHandleStore* other = static_cast(pTarget); - ::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket, clearIfComplete, setHandle); + ::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket); } bool GCHandleStore::EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context) diff --git a/src/gc/gchandletableimpl.h b/src/gc/gchandletableimpl.h index 77af352..f336a3b 100644 --- a/src/gc/gchandletableimpl.h +++ b/src/gc/gchandletableimpl.h @@ -23,7 +23,7 @@ public: virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary); - virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfCompleteCallback)(Object* object), void (*setHandle)(Object* object, OBJECTHANDLE handle)); + virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget); virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context); diff --git a/src/gc/gcinterface.ee.h b/src/gc/gcinterface.ee.h index 113af9d..84578b6 100644 --- a/src/gc/gcinterface.ee.h +++ b/src/gc/gcinterface.ee.h @@ -219,38 +219,6 @@ public: // or a server GC thread. virtual bool WasCurrentThreadCreatedByGC() = 0; - - // Given an object, if this object is an instance of `System.Threading.OverlappedData`, - // and the runtime treats instances of this class specially, traverses the objects that - // are directly or (once) indirectly pinned by this object and reports them to the GC for - // the purposes of relocation and promotion. - // - // Overlapped objects are very special and as such the objects they wrap can't be promoted in - // the same manner as normal objects. This callback gives the EE the opportunity to hide these - // details, if they are implemented at all. - // - // This function is a no-op if "object" is not an OverlappedData object. - virtual - void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) = 0; - - // Given an object, if this object is an instance of `System.Threading.OverlappedData` and the - // runtime treats instances of this class specially, traverses the objects that are directly - // or once indirectly pinned by this object and invokes the given callback on them. The callback - // is passed the following arguments: - // Object* "from" - The object that "caused" the "to" object to be pinned. If a single object - // is pinned directly by this OverlappedData, this object will be the - // OverlappedData object itself. If an array is pinned by this OverlappedData, - // this object will be the pinned array. - // Object* "to" - The object that is pinned by the "from" object. If a single object is pinned - // by an OverlappedData, "to" will be that single object. If an array is pinned - // by an OverlappedData, the callback will be invoked on all elements of that - // array and each element will be a "to" object. - // void* "context" - Passed verbatim from "WalkOverlappedObject" to the callback function. - // The "context" argument will be passed directly to the callback without modification or inspection. - // - // This function is a no-op if "object" is not an OverlappedData object. - virtual - void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)) = 0; }; #endif // _GCINTERFACE_EE_H_ diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h index 138251c..b1d6b80 100644 --- a/src/gc/gcinterface.h +++ b/src/gc/gcinterface.h @@ -111,17 +111,6 @@ struct WriteBarrierParameters uint8_t* write_watch_table; }; -// Opaque type for tracking object pointers -#ifndef DACCESS_COMPILE -struct OBJECTHANDLE__ -{ - void* unused; -}; -typedef struct OBJECTHANDLE__* OBJECTHANDLE; -#else -typedef uintptr_t OBJECTHANDLE; -#endif - /* * Scanning callback. */ @@ -404,7 +393,16 @@ typedef void (* fq_scan_fn)(Object** ppObject, ScanContext *pSC, uint32_t dwFlag typedef void (* handle_scan_fn)(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, bool isDependent); typedef bool (* async_pin_enum_fn)(Object* object, void* context); - +// Opaque type for tracking object pointers +#ifndef DACCESS_COMPILE +struct OBJECTHANDLE__ +{ + void* unused; +}; +typedef struct OBJECTHANDLE__* OBJECTHANDLE; +#else +typedef uintptr_t OBJECTHANDLE; +#endif class IGCHandleStore { public: @@ -421,14 +419,7 @@ public: virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary) = 0; - // Relocates async pinned handles from a condemned handle store to the default domain's handle store. - // - // The two callbacks are called when: - // 1. clearIfComplete is called whenever the handle table observes an async pin that is still live. - // The callback gives a chance for the EE to unpin the referents if the overlapped operation is complete. - // 2. setHandle is called whenever the GC has relocated the async pin to a new handle table. The passed-in - // handle is the newly-allocated handle in the default domain that should be assigned to the overlapped object. - virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)) = 0; + virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget) = 0; virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context) = 0; diff --git a/src/gc/handletable.cpp b/src/gc/handletable.cpp index 48b763d..64d51d1 100644 --- a/src/gc/handletable.cpp +++ b/src/gc/handletable.cpp @@ -20,6 +20,10 @@ #include "objecthandle.h" #include "handletablepriv.h" +#ifndef FEATURE_REDHAWK +#include "nativeoverlapped.h" +#endif + /**************************************************************************** * * FORWARD DECLARATIONS @@ -622,31 +626,34 @@ void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value) FireEtwSetGCHandle((void*) handle, value, hndType, generation, (int64_t) pAppDomain, GetClrInstanceId()); FireEtwPrvSetGCHandle((void*) handle, value, hndType, generation, (int64_t) pAppDomain, GetClrInstanceId()); +#ifndef FEATURE_REDHAWK // Also fire the things pinned by Async pinned handles if (hndType == HNDTYPE_ASYNCPINNED) { - // the closure passed to "WalkOverlappedObject" is not permitted to implicitly - // capture any variables in this scope, since WalkForOverlappedObject takes a bare - // function pointer and context pointer as arguments. We can still /explicitly/ - // close over values in this scope by doing what the compiler would do and introduce - // a structure that contains all of the things we closed over, while passing a pointer - // to this structure as our closure's context pointer. - struct ClosureCapture + if (value->GetMethodTable() == g_pOverlappedDataClass) { - AppDomain* pAppDomain; - Object* overlapped; - }; - - ClosureCapture captured; - captured.pAppDomain = pAppDomain; - captured.overlapped = value; - GCToEEInterface::WalkAsyncPinned(value, &captured, [](Object*, Object* to, void* ctx) - { - ClosureCapture* captured = reinterpret_cast(ctx); - uint32_t generation = to != nullptr ? g_theGCHeap->WhichGeneration(to) : 0; - FireEtwSetGCHandle(captured->overlapped, to, HNDTYPE_PINNED, generation, (int64_t) captured->pAppDomain, GetClrInstanceId()); - }); + OverlappedDataObject* overlapped = (OverlappedDataObject*) value; + if (overlapped->m_isArray) + { + ArrayBase* pUserObject = (ArrayBase*)OBJECTREFToObject(overlapped->m_userObject); + Object **ppObj = (Object**)pUserObject->GetDataPtr(TRUE); + size_t num = pUserObject->GetNumComponents(); + for (size_t i = 0; i < num; i ++) + { + value = ppObj[i]; + uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0; + FireEtwSetGCHandle(overlapped, value, HNDTYPE_PINNED, generation, (int64_t) pAppDomain, GetClrInstanceId()); + } + } + else + { + value = OBJECTREF_TO_UNCHECKED_OBJECTREF(overlapped->m_userObject); + uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0; + FireEtwSetGCHandle(overlapped, value, HNDTYPE_PINNED, generation, (int64_t) pAppDomain, GetClrInstanceId()); + } + } } +#endif // FEATURE_REDHAWK } #else UNREFERENCED_PARAMETER(handle); @@ -702,12 +709,14 @@ void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF objref) int generation = g_theGCHeap->WhichGeneration(value); uint32_t uType = HandleFetchType(handle); +#ifndef FEATURE_REDHAWK //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) + if (uType == HNDTYPE_ASYNCPINNED && objref->GetGCSafeMethodTable () == g_pOverlappedDataClass) { generation = 0; } +#endif // !FEATURE_REDHAWK if (uType == HNDTYPE_DEPENDENT) { @@ -1156,6 +1165,7 @@ uint32_t HndCountAllHandles(BOOL fUseLocks) BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* context) { +#ifndef FEATURE_REDHAWK CONTRACTL { NOTHROW; @@ -1176,13 +1186,14 @@ BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* contex } return result; +#else + return true; +#endif // !FEATURE_REDHAWK } -void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, - HandleTableBucket *pTarget, - void (*clearIfComplete)(Object* object), - void (*setHandle)(Object* object, OBJECTHANDLE handle)) +void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget) { +#ifndef FEATURE_REDHAWK CONTRACTL { NOTHROW; @@ -1193,8 +1204,9 @@ void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, int limit = getNumberOfSlots(); for (int n = 0; n < limit; n ++ ) { - TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]), clearIfComplete, setHandle); + TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n])); } +#endif // !FEATURE_REDHAWK } /*--------------------------------------------------------------------------*/ diff --git a/src/gc/handletablecore.cpp b/src/gc/handletablecore.cpp index 8fbdbe9..2a69afc 100644 --- a/src/gc/handletablecore.cpp +++ b/src/gc/handletablecore.cpp @@ -16,6 +16,11 @@ #include "gcenv.h" #include "gcenv.inl" #include "gc.h" + +#ifndef FEATURE_REDHAWK +#include "nativeoverlapped.h" +#endif // FEATURE_REDHAWK + #include "handletablepriv.h" /**************************************************************************** @@ -661,9 +666,10 @@ __inline void SegmentUnMarkFreeMask(TableSegment *pSegment, _UNCHECKED_OBJECTREF pSegment->rgFreeMask[uMask] &= ~(1<GetMethodTable() == g_pOverlappedDataClass); + OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)(value))); + if (overlapped->HasCompleted()) + { + // IO has finished. We don't need to pin the user buffer any longer. + overlapped->m_userObject = NULL; + } + BashMTForPinnedObject(ObjectToOBJECTREF(value)); } else { @@ -829,7 +842,7 @@ BOOL SegmentCopyAsyncPinHandle(TableSegment *pSegment, _UNCHECKED_OBJECTREF *h) return TRUE; } -void SegmentCompactAsyncPinHandles(TableSegment *pSegment, TableSegment **ppWorkerSegment, void (*clearIfComplete)(Object*)) +void SegmentCompactAsyncPinHandles(TableSegment *pSegment, TableSegment **ppWorkerSegment) { CONTRACTL { @@ -863,7 +876,14 @@ void SegmentCompactAsyncPinHandles(TableSegment *pSegment, TableSegment **ppWork _UNCHECKED_OBJECTREF value = *pValue; if (!HndIsNullOrDestroyedHandle(value)) { - clearIfComplete((Object*)value); + _ASSERTE (value->GetMethodTable() == g_pOverlappedDataClass); + OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)value)); + if (overlapped->HasCompleted()) + { + // IO has finished. We don't need to pin the user buffer any longer. + overlapped->m_userObject = NULL; + } + BashMTForPinnedObject(ObjectToOBJECTREF(value)); fNeedNewSegment = !SegmentCopyAsyncPinHandle(*ppWorkerSegment,pValue); } if (fNeedNewSegment) @@ -871,7 +891,7 @@ void SegmentCompactAsyncPinHandles(TableSegment *pSegment, TableSegment **ppWork _ASSERTE ((*ppWorkerSegment)->rgFreeCount[HNDTYPE_ASYNCPINNED] == 0 && (*ppWorkerSegment)->bFreeList == BLOCK_INVALID); TableSegment *pNextSegment = (*ppWorkerSegment)->pNextSegment; - SegmentPreCompactAsyncPinHandles(pNextSegment, clearIfComplete); + SegmentPreCompactAsyncPinHandles(pNextSegment); *ppWorkerSegment = pNextSegment; if (pNextSegment == pSegment) { @@ -941,10 +961,7 @@ BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment, const AsyncPinCallbac } // Replace an async pin handle with one from default domain -bool SegmentRelocateAsyncPinHandles (TableSegment *pSegment, - HandleTable *pTargetTable, - void (*clearIfComplete)(Object*), - void (*setHandle)(Object*, OBJECTHANDLE)) +bool SegmentRelocateAsyncPinHandles (TableSegment *pSegment, HandleTable *pTargetTable) { CONTRACTL { @@ -978,15 +995,22 @@ bool SegmentRelocateAsyncPinHandles (TableSegment *pSegment, _UNCHECKED_OBJECTREF value = *pValue; if (!HndIsNullOrDestroyedHandle(value)) { - clearIfComplete((Object*)value); - OBJECTHANDLE selfHandle = HndCreateHandle((HHANDLETABLE)pTargetTable, HNDTYPE_ASYNCPINNED, ObjectToOBJECTREF(value)); - if (!selfHandle) + _ASSERTE (value->GetMethodTable() == g_pOverlappedDataClass); + OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)value)); + if (overlapped->HasCompleted()) + { + // IO has finished. We don't need to pin the user buffer any longer. + overlapped->m_userObject = NULL; + } + BashMTForPinnedObject(ObjectToOBJECTREF(value)); + + overlapped->m_pinSelf = HndCreateHandle((HHANDLETABLE)pTargetTable, HNDTYPE_ASYNCPINNED, ObjectToOBJECTREF(value)); + if (!overlapped->m_pinSelf) { // failed to allocate a new handle - callers have to handle this. return false; } - setHandle((Object*)value, selfHandle); *pValue = NULL; } pValue ++; @@ -1010,6 +1034,8 @@ BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackConte } CONTRACTL_END; + _ASSERTE (pTable->uADIndex.m_dwIndex == DefaultADID); + BOOL result = FALSE; TableSegment *pSegment = pTable->pSegmentList; @@ -1036,10 +1062,7 @@ BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackConte // from a again. // c. After copying all handles to worker segments, move the segments to default domain. // It is very important that in step 2, we should not fail for OOM, which means no memory allocation. -void TableRelocateAsyncPinHandles(HandleTable *pTable, - HandleTable *pTargetTable, - void (*clearIfComplete)(Object*), - void (*setHandle)(Object*, OBJECTHANDLE)) +void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable) { CONTRACTL { @@ -1064,7 +1087,7 @@ void TableRelocateAsyncPinHandles(HandleTable *pTable, // Step 1: replace pinning handles with ones from default domain while (pSegment) { - wasSuccessful = wasSuccessful && SegmentRelocateAsyncPinHandles (pSegment, pTargetTable, clearIfComplete, setHandle); + wasSuccessful = wasSuccessful && SegmentRelocateAsyncPinHandles (pSegment, pTargetTable); if (!wasSuccessful) { break; @@ -1116,12 +1139,12 @@ SLOW_PATH: // Compact async pinning handles into the smallest number of leading segments we can (the worker // segments). TableSegment *pWorkerSegment = pTable->pSegmentList; - SegmentPreCompactAsyncPinHandles (pWorkerSegment, clearIfComplete); + SegmentPreCompactAsyncPinHandles (pWorkerSegment); pSegment = pWorkerSegment->pNextSegment; while (pSegment) { - SegmentCompactAsyncPinHandles (pSegment, &pWorkerSegment, clearIfComplete); + SegmentCompactAsyncPinHandles (pSegment, &pWorkerSegment); pSegment= pSegment->pNextSegment; } @@ -1170,6 +1193,7 @@ SLOW_PATH: break; } } +#endif // !FEATURE_REDHAWK /* * Check if a handle is part of a HandleTable diff --git a/src/gc/handletablepriv.h b/src/gc/handletablepriv.h index e0ed4b8..f33a547 100644 --- a/src/gc/handletablepriv.h +++ b/src/gc/handletablepriv.h @@ -795,7 +795,7 @@ BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackConte * Replaces async pin handles with ones in default domain. * */ -void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)); +void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable); /* * Check if a handle is part of a HandleTable diff --git a/src/gc/handletablescan.cpp b/src/gc/handletablescan.cpp index fb08d37..b071f33 100644 --- a/src/gc/handletablescan.cpp +++ b/src/gc/handletablescan.cpp @@ -20,6 +20,10 @@ #include "objecthandle.h" #include "handletablepriv.h" +#ifndef FEATURE_REDHAWK +#include "nativeoverlapped.h" +#endif // FEATURE_REDHAWK + /**************************************************************************** * @@ -818,17 +822,33 @@ void BlockResetAgeMapForBlocksWorker(uint32_t *pdwGen, uint32_t dwClumpMask, Sca if (minAge > thisAge) minAge = thisAge; - GCToEEInterface::WalkAsyncPinned(*pValue, &minAge, - [](Object*, Object* to, void* ctx) +#ifndef FEATURE_REDHAWK + if ((*pValue)->GetGCSafeMethodTable() == g_pOverlappedDataClass) + { + // reporting the pinned user objects + OverlappedDataObject *pOverlapped = (OverlappedDataObject *)(*pValue); + if (pOverlapped->m_userObject != NULL) { - int* minAge = reinterpret_cast(ctx); - int generation = g_theGCHeap->WhichGeneration(to); - if (*minAge > generation) + Object * pUserObject = OBJECTREFToObject(pOverlapped->m_userObject); + thisAge = g_theGCHeap->WhichGeneration(pUserObject); + if (minAge > thisAge) + minAge = thisAge; + if (pOverlapped->m_isArray) { - *minAge = generation; - } - }); - } + ArrayBase* pUserArrayObject = (ArrayBase*)pUserObject; + Object **pObj = (Object**)pUserArrayObject->GetDataPtr(TRUE); + size_t num = pUserArrayObject->GetNumComponents(); + for (size_t i = 0; i < num; i ++) + { + thisAge = g_theGCHeap->WhichGeneration(pObj[i]); + if (minAge > thisAge) + minAge = thisAge; + } + } + } + } +#endif // !FEATURE_REDHAWK + } } _ASSERTE(FitsInU1(minAge)); ((uint8_t *)pSegment->rgGeneration)[uClump] = static_cast(minAge); @@ -900,8 +920,9 @@ static void VerifyObject(_UNCHECKED_OBJECTREF from, _UNCHECKED_OBJECTREF obj) #endif // FEATURE_REDHAWK } -static void VerifyObjectAndAge(_UNCHECKED_OBJECTREF from, _UNCHECKED_OBJECTREF obj, uint8_t minAge) +static void VerifyObjectAndAge(_UNCHECKED_OBJECTREF *pValue, _UNCHECKED_OBJECTREF from, _UNCHECKED_OBJECTREF obj, uint8_t minAge) { + UNREFERENCED_PARAMETER(pValue); VerifyObject(from, obj); int thisAge = g_theGCHeap->WhichGeneration(obj); @@ -968,13 +989,29 @@ void BlockVerifyAgeMapForBlocksWorker(uint32_t *pdwGen, uint32_t dwClumpMask, Sc { if (!HndIsNullOrDestroyedHandle(*pValue)) { - VerifyObjectAndAge((*pValue), (*pValue), minAge); - GCToEEInterface::WalkAsyncPinned(*pValue, &minAge, - [](Object* from, Object* object, void* age) + VerifyObjectAndAge(pValue, (*pValue), (*pValue), minAge); +#ifndef FEATURE_REDHAWK + if ((*pValue)->GetGCSafeMethodTable() == g_pOverlappedDataClass) + { + // reporting the pinned user objects + OverlappedDataObject *pOverlapped = (OverlappedDataObject *)(*pValue); + if (pOverlapped->m_userObject != NULL) { - uint8_t* minAge = reinterpret_cast(age); - VerifyObjectAndAge(from, object, *minAge); - }); + Object * pUserObject = OBJECTREFToObject(pOverlapped->m_userObject); + VerifyObjectAndAge(pValue, (*pValue), pUserObject, minAge); + if (pOverlapped->m_isArray) + { + ArrayBase* pUserArrayObject = (ArrayBase*)pUserObject; + Object **pObj = (Object**)pUserArrayObject->GetDataPtr(TRUE); + size_t num = pUserArrayObject->GetNumComponents(); + for (size_t i = 0; i < num; i ++) + { + VerifyObjectAndAge(pValue, pUserObject, pObj[i], minAge); + } + } + } + } +#endif // !FEATURE_REDHAWK if (uType == HNDTYPE_DEPENDENT) { diff --git a/src/gc/objecthandle.cpp b/src/gc/objecthandle.cpp index de30757..24db07d 100644 --- a/src/gc/objecthandle.cpp +++ b/src/gc/objecthandle.cpp @@ -25,6 +25,9 @@ #ifdef FEATURE_COMINTEROP #include "comcallablewrapper.h" #endif // FEATURE_COMINTEROP +#ifndef FEATURE_REDHAWK +#include "nativeoverlapped.h" +#endif // FEATURE_REDHAWK #endif // BUILD_AS_STANDALONE HandleTableMap g_HandleTableMap; @@ -274,23 +277,40 @@ void CALLBACK PinObject(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo, ui _ASSERTE(lp2); promote_func* callback = (promote_func*) lp2; callback(pRef, (ScanContext *)lp1, GC_CALL_PINNED); -} - -void CALLBACK AsyncPinObject(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo, uintptr_t lp1, uintptr_t lp2) -{ - UNREFERENCED_PARAMETER(pExtraInfo); - LOG((LF_GC, LL_WARNING, LOG_HANDLE_OBJECT_CLASS("WARNING: ", pObjRef, "causes (async) pinning of ", *pObjRef))); +#ifndef FEATURE_REDHAWK + Object * pPinnedObj = *pRef; - Object **pRef = (Object **)pObjRef; - _ASSERTE(lp2); - promote_func* callback = (promote_func*)lp2; - callback(pRef, (ScanContext *)lp2, GC_CALL_PINNED); - Object* pPinnedObj = *pRef; - if (!HndIsNullOrDestroyedHandle(pPinnedObj)) + if (!HndIsNullOrDestroyedHandle(pPinnedObj) && pPinnedObj->GetGCSafeMethodTable() == g_pOverlappedDataClass) { - GCToEEInterface::WalkAsyncPinnedForPromotion(pPinnedObj, (ScanContext *)lp1, callback); + // reporting the pinned user objects + OverlappedDataObject *pOverlapped = (OverlappedDataObject *)pPinnedObj; + if (pOverlapped->m_userObject != NULL) + { + //callback(OBJECTREF_TO_UNCHECKED_OBJECTREF(pOverlapped->m_userObject), (ScanContext *)lp1, GC_CALL_PINNED); + if (pOverlapped->m_isArray) + { + pOverlapped->m_userObjectInternal = static_cast(OBJECTREFToObject(pOverlapped->m_userObject)); + ArrayBase* pUserObject = (ArrayBase*)OBJECTREFToObject(pOverlapped->m_userObject); + Object **ppObj = (Object**)pUserObject->GetDataPtr(TRUE); + size_t num = pUserObject->GetNumComponents(); + for (size_t i = 0; i < num; i ++) + { + callback(ppObj + i, (ScanContext *)lp1, GC_CALL_PINNED); + } + } + else + { + callback(&OBJECTREF_TO_UNCHECKED_OBJECTREF(pOverlapped->m_userObject), (ScanContext *)lp1, GC_CALL_PINNED); + } + } + + if (pOverlapped->GetAppDomainId() != DefaultADID && pOverlapped->GetAppDomainIndex().m_dwIndex == DefaultADID) + { + OverlappedDataObject::MarkCleanupNeededFromGC(); + } } +#endif // !FEATURE_REDHAWK } @@ -404,12 +424,14 @@ void CALLBACK UpdatePointer(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo */ void CALLBACK ScanPointerForProfilerAndETW(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtraInfo, uintptr_t lp1, uintptr_t lp2) { +#ifndef FEATURE_REDHAWK CONTRACTL { NOTHROW; GC_NOTRIGGER; } CONTRACTL_END; +#endif // FEATURE_REDHAWK UNREFERENCED_PARAMETER(pExtraInfo); handle_scan_fn fn = (handle_scan_fn)lp2; @@ -1073,12 +1095,7 @@ void Ref_TracePinningRoots(uint32_t condemned, uint32_t maxgen, ScanContext* sc, sc->pCurrentDomain = SystemDomain::GetAppDomainAtIndex(HndGetHandleTableADIndex(hTable)); } #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING - - // Pinned handles and async pinned handles are scanned in separate passes, since async pinned - // handles may require a callback into the EE in order to fully trace an async pinned - // object's object graph. - HndScanHandlesForGC(hTable, PinObject, uintptr_t(sc), uintptr_t(fn), &types[0], 1, condemned, maxgen, flags); - HndScanHandlesForGC(hTable, AsyncPinObject, uintptr_t(sc), uintptr_t(fn), &types[1], 1, condemned, maxgen, flags); + HndScanHandlesForGC(hTable, PinObject, uintptr_t(sc), uintptr_t(fn), types, _countof(types), condemned, maxgen, flags); } } walk = walk->pNext; diff --git a/src/gc/objecthandle.h b/src/gc/objecthandle.h index 6563d96..a6d2259 100644 --- a/src/gc/objecthandle.h +++ b/src/gc/objecthandle.h @@ -81,7 +81,7 @@ void Ref_Shutdown(); HandleTableBucket* Ref_CreateHandleTableBucket(void* context); bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket, void* context); BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn callback, void* context); -void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)); +void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget); void Ref_RemoveHandleTableBucket(HandleTableBucket *pBucket); void Ref_DestroyHandleTableBucket(HandleTableBucket *pBucket); diff --git a/src/gc/sample/gcenv.ee.cpp b/src/gc/sample/gcenv.ee.cpp index 3d03032..72ef9b5 100644 --- a/src/gc/sample/gcenv.ee.cpp +++ b/src/gc/sample/gcenv.ee.cpp @@ -329,11 +329,3 @@ bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, bool i { return false; } - -void GCToEEInterface::WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) -{ -} - -void GCToEEInterface::WalkAsyncPinned(Object* object, void* context, void (*callback)(Object*, Object*, void*)) -{ -} diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index 07e3280..370847c 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -9053,43 +9053,7 @@ void AppDomain::HandleAsyncPinHandles() // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN. IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore; - auto clearIfComplete = [](Object* object) - { - LIMITED_METHOD_CONTRACT; - - assert(object != nullptr); - if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass) - { - return; - } - - OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)object)); - if (overlapped->HasCompleted()) - { - // IO has finished. We don't need to pin the user buffer any longer. - overlapped->m_userObject = NULL; - } - - BashMTForPinnedObject(ObjectToOBJECTREF(object)); - }; - - auto setHandle = [](Object* object, OBJECTHANDLE handle) - { - LIMITED_METHOD_CONTRACT; - - assert(object != nullptr); - assert(handle); - - if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass) - { - return; - } - - OverlappedDataObject* overlapped = (OverlappedDataObject*)object; - overlapped->m_pinSelf = handle; - }; - - pBucket->RelocateAsyncPinnedHandles(pBucketInDefault, clearIfComplete, setHandle); + pBucket->RelocateAsyncPinnedHandles(pBucketInDefault); OverlappedDataObject::RequestCleanup(); } diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index a880fdb..e5da889 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -1201,7 +1201,7 @@ namespace }; InlineSString wideName; - const WCHAR* namePtr = nullptr; + const WCHAR* namePtr; EX_TRY { if (name != nullptr) @@ -1214,6 +1214,7 @@ namespace { // we're not obligated to provide a name - if it's not valid, // just report nullptr as the name. + namePtr = nullptr; } EX_END_CATCH(SwallowAllExceptions) @@ -1306,81 +1307,3 @@ bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, bool i return CreateNonSuspendableThread(threadStart, arg, name); } } - -void GCToEEInterface::WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) -{ - LIMITED_METHOD_CONTRACT; - - assert(object != nullptr); - assert(sc != nullptr); - assert(callback != nullptr); - if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass) - { - // not an overlapped data object - nothing to do. - return; - } - - // reporting the pinned user objects - OverlappedDataObject *pOverlapped = (OverlappedDataObject *)object; - if (pOverlapped->m_userObject != NULL) - { - //callback(OBJECTREF_TO_UNCHECKED_OBJECTREF(pOverlapped->m_userObject), (ScanContext *)lp1, GC_CALL_PINNED); - if (pOverlapped->m_isArray) - { - // OverlappedDataObject is very special. An async pin handle keeps it alive. - // During GC, we also make sure - // 1. m_userObject itself does not move if m_userObject is not array - // 2. Every object pointed by m_userObject does not move if m_userObject is array - // We do not want to pin m_userObject if it is array. But m_userObject may be updated - // during relocation phase before OverlappedDataObject is doing relocation. - // m_userObjectInternal is used to track the location of the m_userObject before it is updated. - pOverlapped->m_userObjectInternal = static_cast(OBJECTREFToObject(pOverlapped->m_userObject)); - ArrayBase* pUserObject = (ArrayBase*)OBJECTREFToObject(pOverlapped->m_userObject); - Object **ppObj = (Object**)pUserObject->GetDataPtr(TRUE); - size_t num = pUserObject->GetNumComponents(); - for (size_t i = 0; i < num; i++) - { - callback(ppObj + i, sc, GC_CALL_PINNED); - } - } - else - { - callback(&OBJECTREF_TO_UNCHECKED_OBJECTREF(pOverlapped->m_userObject), (ScanContext *)sc, GC_CALL_PINNED); - } - } - - if (pOverlapped->GetAppDomainId() != DefaultADID && pOverlapped->GetAppDomainIndex().m_dwIndex == DefaultADID) - { - OverlappedDataObject::MarkCleanupNeededFromGC(); - } -} - -void GCToEEInterface::WalkAsyncPinned(Object* object, void* context, void (*callback)(Object*, Object*, void*)) -{ - LIMITED_METHOD_CONTRACT; - - assert(object != nullptr); - assert(callback != nullptr); - - if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass) - { - return; - } - - OverlappedDataObject *pOverlapped = (OverlappedDataObject *)(object); - if (pOverlapped->m_userObject != NULL) - { - Object * pUserObject = OBJECTREFToObject(pOverlapped->m_userObject); - callback(object, pUserObject, context); - if (pOverlapped->m_isArray) - { - ArrayBase* pUserArrayObject = (ArrayBase*)pUserObject; - Object **pObj = (Object**)pUserArrayObject->GetDataPtr(TRUE); - size_t num = pUserArrayObject->GetNumComponents(); - for (size_t i = 0; i < num; i ++) - { - callback(pUserObject, pObj[i], context); - } - } - } -} diff --git a/src/vm/gcenv.ee.h b/src/vm/gcenv.ee.h index e3867b7..b2ada36 100644 --- a/src/vm/gcenv.ee.h +++ b/src/vm/gcenv.ee.h @@ -60,8 +60,6 @@ public: bool IsGCThread(); bool WasCurrentThreadCreatedByGC(); bool CreateThread(void (*threadStart)(void*), void* arg, bool is_suspendable, const char* name); - void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback); - void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)); }; } // namespace standalone diff --git a/src/vm/gcenv.ee.standalone.cpp b/src/vm/gcenv.ee.standalone.cpp index be8ceca..5ba2aca 100644 --- a/src/vm/gcenv.ee.standalone.cpp +++ b/src/vm/gcenv.ee.standalone.cpp @@ -6,7 +6,6 @@ #include "gcenv.h" #include "gcenv.ee.h" #include "threadsuspend.h" -#include "nativeoverlapped.h" #ifdef FEATURE_COMINTEROP #include "runtimecallablewrapper.h" @@ -28,4 +27,4 @@ namespace standalone #include "gcenv.ee.cpp" -} // namespace standalone +} // namespace standalone \ No newline at end of file diff --git a/src/vm/gcenv.ee.static.cpp b/src/vm/gcenv.ee.static.cpp index 975deca..240e325 100644 --- a/src/vm/gcenv.ee.static.cpp +++ b/src/vm/gcenv.ee.static.cpp @@ -6,7 +6,6 @@ #include "gcenv.h" #include "../gc/env/gcenv.ee.h" #include "threadsuspend.h" -#include "nativeoverlapped.h" #ifdef FEATURE_COMINTEROP #include "runtimecallablewrapper.h" @@ -23,4 +22,4 @@ extern MethodTable* pWeakReferenceOfTCanonMT; // Finalizes a weak reference directly. extern void FinalizeWeakReference(Object* obj); -#include "gcenv.ee.cpp" +#include "gcenv.ee.cpp" \ No newline at end of file -- 2.7.4