diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 9465e62cba063b..9274ae950245f9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -543,16 +543,28 @@ internal unsafe struct MethodTable private const int ParentMethodTableOffset = 0x10 + DebugClassNamePtr; + private const int DebugLastVerifedGCCnt = // adjust for m_dwLastVerifedGCCnt +#if DEBUG +#if TARGET_64BIT + 8 +#else + 4 +#endif +#else + 0 +#endif + ; + #if TARGET_64BIT - private const int ElementTypeOffset = 0x30 + DebugClassNamePtr; + private const int ElementTypeOffset = 0x38 + DebugClassNamePtr + DebugLastVerifedGCCnt; #else - private const int ElementTypeOffset = 0x20 + DebugClassNamePtr; + private const int ElementTypeOffset = 0x24 + DebugClassNamePtr + DebugLastVerifedGCCnt; #endif #if TARGET_64BIT - private const int InterfaceMapOffset = 0x38 + DebugClassNamePtr; + private const int InterfaceMapOffset = 0x40 + DebugClassNamePtr + DebugLastVerifedGCCnt; #else - private const int InterfaceMapOffset = 0x24 + DebugClassNamePtr; + private const int InterfaceMapOffset = 0x28 + DebugClassNamePtr + DebugLastVerifedGCCnt; #endif public bool HasComponentSize diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h index 4d49c4782aded3..3fa80858987b79 100644 --- a/src/coreclr/vm/amd64/asmconstants.h +++ b/src/coreclr/vm/amd64/asmconstants.h @@ -163,18 +163,18 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_wNumInterfaces ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pParentMethodTable == offsetof(MethodTable, m_pParentMethodTable)); -#define OFFSETOF__MethodTable__m_pEEClass DBG_FRE(0x30, 0x28) +#define OFFSETOF__MethodTable__m_pEEClass DBG_FRE(0x40, 0x30) ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pEEClass == offsetof(MethodTable, m_pEEClass)); -#define METHODTABLE_OFFSET_VTABLE DBG_FRE(0x48, 0x40) +#define METHODTABLE_OFFSET_VTABLE DBG_FRE(0x58, 0x48) ASMCONSTANTS_C_ASSERT(METHODTABLE_OFFSET_VTABLE == sizeof(MethodTable)); -#define OFFSETOF__MethodTable__m_ElementType DBG_FRE(0x38, 0x30) +#define OFFSETOF__MethodTable__m_ElementType DBG_FRE(0x48, 0x38) ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_ElementType == offsetof(MethodTable, m_pMultipurposeSlot1)); -#define OFFSETOF__MethodTable__m_pInterfaceMap DBG_FRE(0x40, 0x38) +#define OFFSETOF__MethodTable__m_pInterfaceMap DBG_FRE(0x50, 0x40) ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pInterfaceMap == offsetof(MethodTable, m_pMultipurposeSlot2)); diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index b80350d0562870..bff3f5f6d38e94 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -85,8 +85,6 @@ static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain"); -#define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020 - // Statics SPTR_IMPL(AppDomain, AppDomain, m_pTheAppDomain); @@ -109,7 +107,7 @@ CrstStatic SystemDomain::m_SystemDomainCrst; CrstStatic SystemDomain::m_DelayedUnloadCrst; // Constructor for the PinnedHeapHandleBucket class. -PinnedHeapHandleBucket::PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, PTRARRAYREF pinnedHandleArrayObj, DWORD size, BaseDomain *pDomain) +PinnedHeapHandleBucket::PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, PTRARRAYREF pinnedHandleArrayObj, DWORD size, LoaderAllocator *pLoaderAllocator) : m_pNext(pNext) , m_ArraySize(size) , m_CurrentPos(0) @@ -120,7 +118,7 @@ PinnedHeapHandleBucket::PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, PT THROWS; GC_NOTRIGGER; MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pDomain)); + PRECONDITION(CheckPointer(pLoaderAllocator)); INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END; @@ -130,10 +128,13 @@ PinnedHeapHandleBucket::PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, PT m_pArrayDataPtr = (OBJECTREF *)pinnedHandleArrayObj->GetDataPtr(); // Store the array in a strong handle to keep it alive. - m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)pinnedHandleArrayObj); + m_collectible = pLoaderAllocator->IsCollectible(); + if (m_collectible) + m_hndHandleArray = GetAppDomain()->CreateDependentHandle(ObjectFromHandle(pLoaderAllocator->GetLoaderAllocatorObjectHandle()), (OBJECTREF)pinnedHandleArrayObj); + else + m_hndHandleArray = GetAppDomain()->CreateStrongHandle((OBJECTREF)pinnedHandleArrayObj); } - // Destructor for the PinnedHeapHandleBucket class. PinnedHeapHandleBucket::~PinnedHeapHandleBucket() { @@ -146,7 +147,15 @@ PinnedHeapHandleBucket::~PinnedHeapHandleBucket() if (m_hndHandleArray) { - DestroyStrongHandle(m_hndHandleArray); + if (m_collectible) + { + DestroyStrongHandle(m_hndHandleArray); + } + else + { + DestroyDependentHandle(m_hndHandleArray); + } + m_hndHandleArray = NULL; } } @@ -164,8 +173,19 @@ OBJECTREF *PinnedHeapHandleBucket::AllocateHandles(DWORD nRequested) CONTRACTL_END; _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles()); - _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr()); - +#ifdef _DEBUG + OBJECTREF handleArrayObj; + if (m_collectible) + { + Object* handleArrayRawObj = GCHandleUtilities::GetGCHandleManager()->GetDependentHandleSecondary(m_hndHandleArray); + handleArrayObj = ObjectToOBJECTREF(handleArrayRawObj); + } + else + { + handleArrayObj = ObjectFromHandle(m_hndHandleArray); + } + _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)handleArrayObj)->GetDataPtr()); +#endif // Store the handles in the buffer that was passed in OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos]; m_CurrentPos += nRequested; @@ -220,9 +240,9 @@ void PinnedHeapHandleBucket::EnumStaticGCRefs(promote_func* fn, ScanContext* sc) #define MAX_BUCKETSIZE (16384 - 4) // Constructor for the PinnedHeapHandleTable class. -PinnedHeapHandleTable::PinnedHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize) +PinnedHeapHandleTable::PinnedHeapHandleTable(LoaderAllocator *pLoaderAllocator, DWORD InitialBucketSize) : m_pHead(NULL) -, m_pDomain(pDomain) +, m_pLoaderAllocator(pLoaderAllocator) , m_NextBucketSize(InitialBucketSize) , m_pFreeSearchHint(NULL) , m_cEmbeddedFree(0) @@ -232,7 +252,7 @@ PinnedHeapHandleTable::PinnedHeapHandleTable(BaseDomain *pDomain, DWORD InitialB THROWS; GC_TRIGGERS; MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pDomain)); + PRECONDITION(CheckPointer(pLoaderAllocator)); INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END; @@ -364,7 +384,7 @@ OBJECTREF* PinnedHeapHandleTable::AllocateHandles(DWORD nRequested) m_pHead->ConsumeRemaining(); } - m_pHead = new PinnedHeapHandleBucket(m_pHead, pinnedHandleArrayObj, newBucketSize, m_pDomain); + m_pHead = new PinnedHeapHandleBucket(m_pHead, pinnedHandleArrayObj, newBucketSize, m_pLoaderAllocator); // we already computed nextBucketSize to be double the previous size above, but it is possible that // other threads increased m_NextBucketSize while the lock was unheld. We want to ensure @@ -576,9 +596,6 @@ BaseDomain::BaseDomain() m_pDefaultBinder = NULL; - // Make sure the container is set to NULL so that it gets loaded when it is used. - m_pPinnedHeapHandleTable = NULL; - // Note that m_handleStore is overridden by app domains m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore(); @@ -799,33 +816,7 @@ OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF* } CONTRACTL_END; - if (ppLazyAllocate && *ppLazyAllocate) - { - // Allocation already happened - return *ppLazyAllocate; - } - - GCX_COOP(); - - // Make sure the large heap handle table is initialized. - if (!m_pPinnedHeapHandleTable) - InitPinnedHeapHandleTable(); - - // Allocate the handles. - OBJECTREF* result = m_pPinnedHeapHandleTable->AllocateHandles(nRequested); - if (ppLazyAllocate) - { - // race with other threads that might be doing the same concurrent allocation - if (InterlockedCompareExchangeT(ppLazyAllocate, result, NULL) != NULL) - { - // we lost the race, release our handles and use the handles from the - // winning thread - m_pPinnedHeapHandleTable->ReleaseHandles(result, nRequested); - result = *ppLazyAllocate; - } - } - - return result; + return GetLoaderAllocator()->AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate); } #endif // !DACCESS_COMPILE @@ -899,26 +890,6 @@ STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString) return GetLoaderAllocator()->GetOrInternString(pString); } -void BaseDomain::InitPinnedHeapHandleTable() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; - - PinnedHeapHandleTable* pTable = new PinnedHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE); - if(InterlockedCompareExchangeT(&m_pPinnedHeapHandleTable, pTable, NULL) != NULL) - { - // another thread beat us to initializing the field, delete our copy - delete pTable; - } -} - - //***************************************************************************** //***************************************************************************** //***************************************************************************** @@ -4229,26 +4200,32 @@ void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT) { if (pDynamicStatics == NULL) { - LoaderHeap * pLoaderAllocator = GetDomainAssembly()->GetLoaderAllocator()->GetHighFrequencyHeap(); + LoaderAllocator * pLoaderAllocator = GetDomainAssembly()->GetLoaderAllocator(); + + SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes; if (pMT->Collectible()) { - pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry))); + size_t alignment = TARGET_POINTER_SIZE; +#ifdef FEATURE_64BIT_ALIGNMENT + if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE) + alignment = MAX_PRIMITIVE_FIELD_SIZE; +#endif + pDynamicStatics = (DynamicEntry*)pLoaderAllocator->AllocateDataOnGCHeapWithLoaderAllocatorLifetime(dynamicEntrySize, alignment); } else { - SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes; - + LoaderHeap * pLoaderHeap = pLoaderAllocator->GetHighFrequencyHeap(); #ifdef FEATURE_64BIT_ALIGNMENT // Allocate memory with extra alignment only if it is really necessary if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE) { static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0); - pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE); + pDynamicStatics = (DynamicEntry*)(void*)pLoaderHeap->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE); } else #endif - pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize)); + pDynamicStatics = (DynamicEntry*)(void*)pLoaderHeap->AllocMem(S_SIZE_T(dynamicEntrySize)); } // Note: Memory allocated on loader heap is zero filled @@ -4256,37 +4233,10 @@ void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT) m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics; } - if (pMT->Collectible() && (dwStaticBytes != 0)) - { - GCX_COOP(); - OBJECTREF nongcStaticsArray = NULL; - GCPROTECT_BEGIN(nongcStaticsArray); -#ifdef FEATURE_64BIT_ALIGNMENT - // Allocate memory with extra alignment only if it is really necessary - if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE) - nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8))); - else -#endif - nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes); - ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray); - GCPROTECT_END(); - } if (dwNumHandleStatics > 0) { - if (!pMT->Collectible()) - { - GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics, - &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics); - } - else - { - GCX_COOP(); - OBJECTREF gcStaticsArray = NULL; - GCPROTECT_BEGIN(gcStaticsArray); - gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass); - ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray); - GCPROTECT_END(); - } + GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics, + &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics); } } } @@ -4591,10 +4541,7 @@ void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc) GCHeapUtilities::IsServerHeap() && IsGCSpecialThread()); - if (m_pPinnedHeapHandleTable != nullptr) - { - m_pPinnedHeapHandleTable->EnumStaticGCRefs(fn, sc); - } + GetLoaderAllocator()->EnumStaticGCRefs(fn, sc); RETURN; } diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 48481dd1c0b3f7..bf98736320715e 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -87,39 +87,14 @@ struct DomainLocalModule {\ DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast(dynamicClassInfoParam);\ DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast((DomainLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry.Load()); \ - if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \ - {\ - PTRARRAYREF objArray;\ - objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \ - (dac_cast(pDynamicEntry))->m_hGCStatics);\ - *(pGCStatics) = dac_cast(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\ - }\ - else\ - {\ - *(pGCStatics) = (dac_cast(pDynamicEntry))->GetGCStaticsBasePointer();\ - }\ + *(pGCStatics) = (dac_cast(pDynamicEntry))->GetGCStaticsBasePointer();\ }\ #define GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \ {\ DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast(dynamicClassInfoParam);\ DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast((DomainLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry.Load()); \ - if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \ - {\ - if ((dac_cast(pDynamicEntry))->m_hNonGCStatics != 0) \ - { \ - U1ARRAYREF objArray;\ - objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \ - (dac_cast(pDynamicEntry))->m_hNonGCStatics);\ - *(pNonGCStatics) = dac_cast(PTR_READ( \ - PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \ - objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \ - } else (*pNonGCStatics) = NULL; \ - }\ - else\ - {\ - *(pNonGCStatics) = dac_cast(pDynamicEntry)->GetNonGCStaticsBasePointer();\ - }\ + *(pNonGCStatics) = dac_cast(pDynamicEntry)->GetNonGCStaticsBasePointer();\ }\ struct DynamicEntry @@ -128,13 +103,6 @@ struct DomainLocalModule }; typedef DPTR(DynamicEntry) PTR_DynamicEntry; - struct CollectibleDynamicEntry : public DynamicEntry - { - LOADERHANDLE m_hGCStatics; - LOADERHANDLE m_hNonGCStatics; - }; - typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry; - struct NormalDynamicEntry : public DynamicEntry { PTR_OBJECTREF m_pGCStatics; @@ -337,11 +305,8 @@ struct DomainLocalModule { WRAPPER_NO_CONTRACT; - // m_aDynamicEntries is set last, it needs to be checked first - if (n >= m_aDynamicEntries) - { - return NULL; - } + _ASSERTE(n != (DWORD)-1); + _ASSERTE(n >= m_aDynamicEntries); // Types are initialized before being visible to code _ASSERTE(m_pDynamicClassTable.Load() != NULL); PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable.Load() + n); @@ -462,151 +427,7 @@ struct DomainLocalModule #pragma warning(pop) #endif - -// The pinned heap handle bucket class is used to contain handles allocated -// from an array contained in the pinned heap. -class PinnedHeapHandleBucket -{ -public: - // Constructor and desctructor. - PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, PTRARRAYREF pinnedHandleArrayObj, DWORD size, BaseDomain *pDomain); - ~PinnedHeapHandleBucket(); - - // This returns the next bucket. - PinnedHeapHandleBucket *GetNext() - { - LIMITED_METHOD_CONTRACT; - - return m_pNext; - } - - // This returns the number of remaining handle slots. - DWORD GetNumRemainingHandles() - { - LIMITED_METHOD_CONTRACT; - - return m_ArraySize - m_CurrentPos; - } - - void ConsumeRemaining() - { - LIMITED_METHOD_CONTRACT; - - m_CurrentPos = m_ArraySize; - } - - OBJECTREF *TryAllocateEmbeddedFreeHandle(); - - // Allocate handles from the bucket. - OBJECTREF* AllocateHandles(DWORD nRequested); - OBJECTREF* CurrentPos() - { - LIMITED_METHOD_CONTRACT; - return m_pArrayDataPtr + m_CurrentPos; - } - - void EnumStaticGCRefs(promote_func* fn, ScanContext* sc); - -private: - PinnedHeapHandleBucket *m_pNext; - int m_ArraySize; - int m_CurrentPos; - int m_CurrentEmbeddedFreePos; - OBJECTHANDLE m_hndHandleArray; - OBJECTREF *m_pArrayDataPtr; -}; - - - -// The pinned heap handle table is used to allocate handles that are pointers -// to objects stored in an array in the pinned object heap. -class PinnedHeapHandleTable -{ -public: - // Constructor and desctructor. - PinnedHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize); - ~PinnedHeapHandleTable(); - - // Allocate handles from the pinned heap handle table. - OBJECTREF* AllocateHandles(DWORD nRequested); - - // Release object handles allocated using AllocateHandles(). - void ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased); - - void EnumStaticGCRefs(promote_func* fn, ScanContext* sc); - -private: - void ReleaseHandlesLocked(OBJECTREF *pObjRef, DWORD nReleased); - - // The buckets of object handles. - // synchronized by m_Crst - PinnedHeapHandleBucket *m_pHead; - - // We need to know the containing domain so we know where to allocate handles - BaseDomain *m_pDomain; - - // The size of the PinnedHeapHandleBucket. - // synchronized by m_Crst - DWORD m_NextBucketSize; - - // for finding and re-using embedded free items in the list - // these fields are synchronized by m_Crst - PinnedHeapHandleBucket *m_pFreeSearchHint; - DWORD m_cEmbeddedFree; - - CrstExplicitInit m_Crst; -}; - -class PinnedHeapHandleBlockHolder; -void PinnedHeapHandleBlockHolder__StaticFree(PinnedHeapHandleBlockHolder*); - - -class PinnedHeapHandleBlockHolder:public Holder - -{ - PinnedHeapHandleTable* m_pTable; - DWORD m_Count; - OBJECTREF* m_Data; -public: - FORCEINLINE PinnedHeapHandleBlockHolder(PinnedHeapHandleTable* pOwner, DWORD nCount) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - m_Data = pOwner->AllocateHandles(nCount); - m_Count=nCount; - m_pTable=pOwner; - }; - - FORCEINLINE void FreeData() - { - WRAPPER_NO_CONTRACT; - for (DWORD i=0;i< m_Count;i++) - ClearObjectReference(m_Data+i); - m_pTable->ReleaseHandles(m_Data, m_Count); - }; - FORCEINLINE OBJECTREF* operator[] (DWORD idx) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(idxFreeData(); -}; - - - - +#include "pinnedheaphandles.h" // The large heap handle bucket class is used to contain handles allocated // from an array contained in the large heap. @@ -1095,10 +916,6 @@ class BaseDomain protected: - //**************************************************************************************** - // Helper method to initialize the large heap handle table. - void InitPinnedHeapHandleTable(); - // Critical sections & locks PEFileListLock m_FileLoadLock; // Protects the list of assemblies in the domain CrstExplicitInit m_DomainCrst; // General Protection for the Domain @@ -1120,9 +937,6 @@ class BaseDomain IGCHandleStore* m_handleStore; - // The pinned heap handle table. - PinnedHeapHandleTable *m_pPinnedHeapHandleTable; - #ifdef FEATURE_COMINTEROP // Information regarding the managed standard interfaces. MngStdInterfacesInfo *m_pMngStdInterfacesInfo; diff --git a/src/coreclr/vm/arm/asmconstants.h b/src/coreclr/vm/arm/asmconstants.h index 2aa29578aa3b91..f8ec205e396880 100644 --- a/src/coreclr/vm/arm/asmconstants.h +++ b/src/coreclr/vm/arm/asmconstants.h @@ -79,10 +79,10 @@ ASMCONSTANTS_C_ASSERT(MethodTable__m_dwFlags == offsetof(MethodTable, m_dwFlags) #define MethodTable__enum_flag_ContainsPointers 0x01000000 ASMCONSTANTS_C_ASSERT(MethodTable__enum_flag_ContainsPointers == MethodTable::enum_flag_ContainsPointers); -#define MethodTable__m_ElementType DBG_FRE(0x24, 0x20) +#define MethodTable__m_ElementType DBG_FRE(0x2C, 0x24) ASMCONSTANTS_C_ASSERT(MethodTable__m_ElementType == offsetof(MethodTable, m_pMultipurposeSlot1)); -#define SIZEOF__MethodTable DBG_FRE(0x2c, 0x28) +#define SIZEOF__MethodTable DBG_FRE(0x34, 0x2C) ASMCONSTANTS_C_ASSERT(SIZEOF__MethodTable == sizeof(MethodTable)); #define ArrayBase__m_NumComponents 0x4 diff --git a/src/coreclr/vm/arm64/asmconstants.h b/src/coreclr/vm/arm64/asmconstants.h index 5210438aad3deb..d81caac1f89a90 100644 --- a/src/coreclr/vm/arm64/asmconstants.h +++ b/src/coreclr/vm/arm64/asmconstants.h @@ -128,9 +128,6 @@ ASMCONSTANTS_C_ASSERT(MethodTable__m_dwFlags == offsetof(MethodTable, m_dwFlags) #define MethodTable__m_BaseSize 0x04 ASMCONSTANTS_C_ASSERT(MethodTable__m_BaseSize == offsetof(MethodTable, m_BaseSize)); -#define MethodTable__m_ElementType DBG_FRE(0x38, 0x30) -ASMCONSTANTS_C_ASSERT(MethodTable__m_ElementType == offsetof(MethodTable, m_pMultipurposeSlot1)); - #define ArrayBase__m_NumComponents 0x8 ASMCONSTANTS_C_ASSERT(ArrayBase__m_NumComponents == offsetof(ArrayBase, m_NumComponents)); diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index a137bf6b470e77..4b8c66b88e2d37 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -360,14 +360,9 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask); - // Allocate the private data block ("private" during runtime in the ngen'ed case). - MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *) - pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData)))); - pMT->SetWriteableData(pMTWriteableData); - // This also disables IBC logging until the type is sufficiently intitialized so // it needs to be done early - pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable(); + pMT->SetIsNotFullyLoadedForBuildMethodTable(); // Fill in pClass if (pClass != NULL) @@ -471,7 +466,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy // The type is sufficiently initialized for most general purpose accessor methods to work. // Mark the type as restored to avoid asserts. Note that this also enables IBC logging. - pMTWriteableData->SetIsRestoredForBuildArrayMethodTable(); + pMT->SetIsRestoredForBuildArrayMethodTable(); { // Fill out the vtable indirection slots diff --git a/src/coreclr/vm/binder.cpp b/src/coreclr/vm/binder.cpp index 71e57c9d5b4743..846223cee61239 100644 --- a/src/coreclr/vm/binder.cpp +++ b/src/coreclr/vm/binder.cpp @@ -230,7 +230,7 @@ NOINLINE PTR_MethodTable CoreLibBinder::LookupClassIfExist(BinderClassID id) const CoreLibClassDescription *d = (&g_CoreLib)->m_classDescriptions + (int)id; PTR_MethodTable pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), d->nameSpace, d->name, - ClassLoader::ReturnNullIfNotFound, ClassLoader::DontLoadTypes, CLASS_LOAD_UNRESTOREDTYPEKEY).AsMethodTable(); + ClassLoader::ReturnNullIfNotFound, ClassLoader::DontLoadTypes, CLASS_LOAD_APPROXPARENTS).AsMethodTable(); _ASSERTE((pMT == NULL) || (pMT->GetModule() == GetModule())); diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 04e65cbfbdbe1c..4f253202161e11 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -1704,7 +1704,7 @@ void Module::AllocateRegularStaticHandles(AppDomain* pDomain) _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointerAddress() != NULL); if (this->m_dwMaxGCRegularStaticHandles > 0) { - pDomain->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles, + GetLoaderAllocator()->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles, pModuleData->GetPrecomputedGCStaticsBasePointerAddress()); // We should throw if we fail to allocate and never hit this assert diff --git a/src/coreclr/vm/classloadlevel.h b/src/coreclr/vm/classloadlevel.h index f0702d62734e92..cb17d66da35b19 100644 --- a/src/coreclr/vm/classloadlevel.h +++ b/src/coreclr/vm/classloadlevel.h @@ -18,17 +18,9 @@ // // Placeholder level used before type has been created or located in ngen image // -// -// CLASS_LOAD_UNRESTOREDTYPEKEY -// -// Type lives in an ngen image and components of its type key need restoring: -// for methodtables: generic arguments, EEClass pointer, Module pointer in EEClass -// for typedescs: param type, template methodtable -// -// // CLASS_LOAD_UNRESTORED // -// Type lives in an ngen image and contains fields that need restoring +// Type is in the process of being loaded in MethodTableBuilder and many fields are not yet initialized // (e.g. parent, interfaces, param type) // // @@ -71,7 +63,6 @@ enum ClassLoadLevel { CLASS_LOAD_BEGIN, - CLASS_LOAD_UNRESTOREDTYPEKEY, CLASS_LOAD_UNRESTORED, CLASS_LOAD_APPROXPARENTS, CLASS_LOAD_EXACTPARENTS, diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index 4bca61bd623063..3837f84351f52c 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -2889,9 +2889,6 @@ TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, } break; - case CLASS_LOAD_UNRESTOREDTYPEKEY : - break; - // Attain level CLASS_LOAD_APPROXPARENTS, starting with unrestored class case CLASS_LOAD_UNRESTORED : break; diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index 6430970b87b6e1..ea25106849e620 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -142,6 +142,7 @@ typedef DPTR(class DelegateObject) PTR_DelegateObject; typedef DPTR(class ObjHeader) PTR_ObjHeader; typedef DPTR(class Precode) PTR_Precode; typedef VPTR(class ReflectionModule) PTR_ReflectionModule; +typedef VPTR(class ModuleBase) PTR_ModuleBase; typedef DPTR(class ReflectClassBaseObject) PTR_ReflectClassBaseObject; typedef DPTR(class ReflectMethodObject) PTR_ReflectMethodObject; typedef DPTR(class ReflectFieldObject) PTR_ReflectFieldObject; diff --git a/src/coreclr/vm/gchelpers.cpp b/src/coreclr/vm/gchelpers.cpp index 99954015166fbc..fca94ac9da24fd 100644 --- a/src/coreclr/vm/gchelpers.cpp +++ b/src/coreclr/vm/gchelpers.cpp @@ -729,7 +729,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, /* * Allocates a single dimensional array of primitive types. */ -OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements) +OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bAllocateInPinnedHeap) { CONTRACTL { @@ -754,7 +754,8 @@ OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements) TypeHandle typHnd = ClassLoader::LoadArrayTypeThrowing(elemType, ELEMENT_TYPE_SZARRAY, 0); g_pPredefinedArrayTypes[type] = typHnd; } - return AllocateSzArray(g_pPredefinedArrayTypes[type].AsMethodTable(), cElements); + GC_ALLOC_FLAGS flags = bAllocateInPinnedHeap ? GC_ALLOC_PINNED_OBJECT_HEAP : GC_ALLOC_NO_FLAGS; + return AllocateSzArray(g_pPredefinedArrayTypes[type].AsMethodTable(), cElements, flags); } // diff --git a/src/coreclr/vm/gchelpers.h b/src/coreclr/vm/gchelpers.h index bfebf554b0cbf8..0ddaed36802bc8 100644 --- a/src/coreclr/vm/gchelpers.h +++ b/src/coreclr/vm/gchelpers.h @@ -28,7 +28,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS); // Create a SD array of primitive types given an element type -OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements); +OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bAllocateInPinnedHeap = FALSE); // Allocate SD array of object types given an element type OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType, BOOL bAllocateInPinnedHeap = FALSE); diff --git a/src/coreclr/vm/generics.cpp b/src/coreclr/vm/generics.cpp index 55f1d274990c54..3553ae86383413 100644 --- a/src/coreclr/vm/generics.cpp +++ b/src/coreclr/vm/generics.cpp @@ -304,15 +304,9 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( // Copy of GC memcpy((BYTE*)pMT - cbGC, (BYTE*) pOldMT - cbGC, cbGC); - // Allocate the private data block ("private" during runtime in the ngen'ed case) - MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *) - pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData)))); - // Note: Memory allocated on loader heap is zero filled - pMT->SetWriteableData(pMTWriteableData); - // This also disables IBC logging until the type is sufficiently intitialized so // it needs to be done early - pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable(); + pMT->SetIsNotFullyLoadedForBuildMethodTable(); // this is incredibly fragile. We should just construct the MT all over agin. pMT->CopyFlags(pOldMT); @@ -505,6 +499,10 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( } pMT->SetupGenericsStaticsInfo(pStaticFieldDescs); } + else + { + pMT->SetupGenericsStaticsInfo(NULL); + } // VTS info doesn't depend on the exact instantiation but we make a copy @@ -537,7 +535,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( // We never have non-virtual slots in this method table (set SetNumVtableSlots and SetNumVirtuals above) _ASSERTE(!pMT->HasNonVirtualSlots()); - pMTWriteableData->SetIsRestoredForBuildMethodTable(); + pMT->SetIsRestoredForBuildMethodTable(); RETURN(TypeHandle(pMT)); } // ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation diff --git a/src/coreclr/vm/i386/asmconstants.h b/src/coreclr/vm/i386/asmconstants.h index 138f007a78868e..c2761fe2e52fd9 100644 --- a/src/coreclr/vm/i386/asmconstants.h +++ b/src/coreclr/vm/i386/asmconstants.h @@ -203,10 +203,10 @@ ASMCONSTANTS_C_ASSERT(MethodTable_m_wNumInterfaces == offsetof(MethodTable, m_wN #define MethodTable_m_dwFlags 0x0 ASMCONSTANTS_C_ASSERT(MethodTable_m_dwFlags == offsetof(MethodTable, m_dwFlags)) -#define MethodTable_m_pInterfaceMap DBG_FRE(0x28, 0x24) +#define MethodTable_m_pInterfaceMap DBG_FRE(0x30, 0x28) ASMCONSTANTS_C_ASSERT(MethodTable_m_pInterfaceMap == offsetof(MethodTable, m_pMultipurposeSlot2)) -#define SIZEOF_MethodTable DBG_FRE(0x2C, 0x28) +#define SIZEOF_MethodTable DBG_FRE(0x34, 0x2C) ASMCONSTANTS_C_ASSERT(SIZEOF_MethodTable == sizeof(MethodTable)) #define SIZEOF_InterfaceInfo_t 0x4 diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index b7eebd07afecb5..10c1023022a43e 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -81,6 +81,7 @@ LoaderAllocator::LoaderAllocator() #ifdef FEATURE_PGO m_pgoManager = NULL; #endif + m_pPinnedHeapHandleTable = NULL; } LoaderAllocator::~LoaderAllocator() @@ -721,7 +722,7 @@ extern "C" BOOL QCALLTYPE LoaderAllocator_Destroy(QCall::LoaderAllocatorHandle p #define MAX_LOADERALLOCATOR_HANDLE 0x40000000 // Returns NULL if the managed LoaderAllocator object was already collected. -LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value) +LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value, BOOL supportEfficientFreeOperation) { CONTRACTL { @@ -733,6 +734,10 @@ LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value) LOADERHANDLE retVal; + // Efficient free support is only provided for collectible loader allocator handles + // and is used only for implementation of TLS + _ASSERTE(!supportEfficientFreeOperation || IsCollectible()); + struct _gc { OBJECTREF value; @@ -748,7 +753,7 @@ LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value) gc.value = value; // The handle table is read locklessly, be careful - if (IsCollectible()) + if (supportEfficientFreeOperation) { gc.loaderAllocator = (LOADERALLOCATORREF)ObjectFromHandle(m_hLoaderAllocatorObjectHandle); if (gc.loaderAllocator == NULL) @@ -847,6 +852,43 @@ LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value) return retVal; } +void* LoaderAllocator::AllocateDataOnGCHeapWithLoaderAllocatorLifetime(size_t cb, size_t alignment) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + void* result = NULL; + GCX_COOP(); + BASEARRAYREF array = NULL; + GCPROTECT_BEGIN(array); + DWORD cbDWORD = (DWORD)cb; + if (((size_t)(cbDWORD + 8)) != cb) + { + ThrowOutOfMemory(); + } +#if defined(FEATURE_64BIT_ALIGNMENT) && (TARGET_POINTER_SIZE != 8) + if (alignment == 8) + { + array = (BASEARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_R8, (cbDWORD + (sizeof(CLR_R8)-1)) / (sizeof(CLR_R8)), TRUE); + } + else +#endif + { + array = (BASEARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_I, (cbDWORD + (sizeof(CLR_I)-1)) / (sizeof(CLR_I)), TRUE); + } + // Ensure the allocated memory lasts the lifetime of the LoaderAllocator + AllocateHandle(array); + result = array->GetDataPtr(); + + GCPROTECT_END(); + return result; +} + OBJECTREF LoaderAllocator::GetHandleValue(LOADERHANDLE handle) { CONTRACTL @@ -1058,6 +1100,10 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory) m_crstLoaderAllocator.Init(CrstLoaderAllocator, (CrstFlags)CRST_UNSAFE_COOPGC); m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY); + + // Pinned heap handle table CRST. + m_PinnedHeapHandleTableCrst.Init(CrstPinnedHeapHandleTable); + #ifdef FEATURE_COMINTEROP m_ComCallWrapperCrst.Init(CrstCOMCallWrapper); #endif @@ -1435,6 +1481,11 @@ void LoaderAllocator::Terminate() CleanupStringLiteralMap(); + if (m_pPinnedHeapHandleTable != NULL) + { + delete m_pPinnedHeapHandleTable; + m_pPinnedHeapHandleTable = NULL; + } LOG((LF_CLASSLOADER, LL_INFO100, "End LoaderAllocator::Terminate for loader allocator %p\n", reinterpret_cast(static_cast(this)))); } @@ -2182,3 +2233,87 @@ PTR_OnStackReplacementManager LoaderAllocator::GetOnStackReplacementManager() #endif // #endif // FEATURE_ON_STACK_REPLACEMENT +#ifndef DACCESS_COMPILE +OBJECTREF* LoaderAllocator::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION((nRequested > 0)); + INJECT_FAULT(COMPlusThrowOM();); + } + CONTRACTL_END; + + if (ppLazyAllocate && *ppLazyAllocate) + { + // Allocation already happened + return *ppLazyAllocate; + } + + GCX_COOP(); + + // Make sure the large heap handle table is initialized. + if (!m_pPinnedHeapHandleTable) + InitPinnedHeapHandleTable(); + + // Allocate the handles. + OBJECTREF* result = m_pPinnedHeapHandleTable->AllocateHandles(nRequested); + if (ppLazyAllocate) + { + // race with other threads that might be doing the same concurrent allocation + if (InterlockedCompareExchangeT(ppLazyAllocate, result, NULL) != NULL) + { + // we lost the race, release our handles and use the handles from the + // winning thread + m_pPinnedHeapHandleTable->ReleaseHandles(result, nRequested); + result = *ppLazyAllocate; + } + } + + return result; +} + +void LoaderAllocator::InitPinnedHeapHandleTable() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + INJECT_FAULT(COMPlusThrowOM();); + } + CONTRACTL_END; +#define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020 +#define COLLECTIBLE_STATIC_OBJECT_TABLE_BUCKET_SIZE 250 + + PinnedHeapHandleTable* pTable = new PinnedHeapHandleTable(this, IsCollectible() ? COLLECTIBLE_STATIC_OBJECT_TABLE_BUCKET_SIZE : STATIC_OBJECT_TABLE_BUCKET_SIZE); + if(InterlockedCompareExchangeT(&m_pPinnedHeapHandleTable, pTable, NULL) != NULL) + { + // another thread beat us to initializing the field, delete our copy + delete pTable; + } +} + +void LoaderAllocator::EnumStaticGCRefs(promote_func* fn, ScanContext* sc) +{ + CONTRACT_VOID + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACT_END; + + _ASSERTE(GCHeapUtilities::IsGCInProgress() && + GCHeapUtilities::IsServerHeap() && + IsGCSpecialThread()); + + if (m_pPinnedHeapHandleTable != nullptr) + { + m_pPinnedHeapHandleTable->EnumStaticGCRefs(fn, sc); + } + + RETURN; +} +#endif \ No newline at end of file diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 90311d3a01ca18..3171fdfc0c7490 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -25,6 +25,7 @@ class FuncPtrStubs; #include "onstackreplacement.h" #include "lockedrangelist.h" #include "pgo.h" +#include "pinnedheaphandles.h" #define VPTRU_LoaderAllocator 0x3200 @@ -202,6 +203,12 @@ class LoaderAllocator Volatile m_pgoManager; #endif // FEATURE_PGO + // The pinned heap handle table. + PinnedHeapHandleTable *m_pPinnedHeapHandleTable = NULL; + + // The pinned heap handle table critical section. + CrstExplicitInit m_PinnedHeapHandleTableCrst; + public: BYTE *GetVSDHeapInitialBlock(DWORD *pSize); BYTE *GetCodeHeapInitialBlock(const BYTE * loAddr, const BYTE * hiAddr, DWORD minimumSize, DWORD *pSize); @@ -486,7 +493,24 @@ class LoaderAllocator LOADERALLOCATORREF GetExposedObject(); #ifndef DACCESS_COMPILE - LOADERHANDLE AllocateHandle(OBJECTREF value); +#ifndef DACCESS_COMPILE + OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTREF** ppLazyAllocate = NULL) + { + WRAPPER_NO_CONTRACT; + + return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate); + } +#endif // DACCESS_COMPILE + + // Returns an array of OBJECTREF* that can be used to store domain specific data. + // Statics and reflection info (Types, MemberInfo,..) are stored this way + // If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation + // will be properly serialized) + OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate = NULL); + void EnumStaticGCRefs(promote_func* fn, ScanContext* sc); + + LOADERHANDLE AllocateHandle(OBJECTREF value, BOOL supportEfficientFreeOperation = FALSE); + void* AllocateDataOnGCHeapWithLoaderAllocatorLifetime(size_t cb, size_t alignment); void SetHandleValue(LOADERHANDLE handle, OBJECTREF value); OBJECTREF CompareExchangeValueInHandle(LOADERHANDLE handle, OBJECTREF value, OBJECTREF compare); @@ -628,6 +652,10 @@ class LoaderAllocator // Deletes marshaling data at shutdown (which contains cached factories that needs to be released) void DeleteMarshalingData(); + //**************************************************************************************** + // Helper method to initialize the large heap handle table. + void InitPinnedHeapHandleTable(); + public: #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 8b54c2dfe86231..149f4a419b6978 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -539,29 +539,6 @@ void MethodTable::SetClassInitError() GetDomainLocalModule()->SetClassInitError(this); } -//========================================================================================== -// mark the class as having been restored. -void MethodTable::SetIsRestored() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END - - PRECONDITION(!IsFullyLoaded()); - - InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_Unrestored); - -#ifndef DACCESS_COMPILE - if (ETW_PROVIDER_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER)) - { - ETW::MethodLog::MethodTableRestored(this); - } -#endif -} - //========================================================================================== // mark as COM object type (System.__ComObject and types deriving from it) void MethodTable::SetComObjectType() @@ -851,11 +828,6 @@ MethodTable* CreateMinimalMethodTable(Module* pContainingModule, // Note: Memory allocated on loader heap is zero filled // memset(pMT, 0, sizeof(MethodTable)); - // Allocate the private data block ("private" during runtime in the ngen'ed case). - BYTE* pMTWriteableData = (BYTE *) - pamTracker->Track(pCreationHeap->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData)))); - pMT->SetWriteableData((PTR_MethodTableWriteableData)pMTWriteableData); - // // Set up the EEClass // @@ -1173,19 +1145,23 @@ void MethodTable::SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs) // in the NGEN image it would be actively incorrect to do so. However // we still leave the optional member in the MethodTable holding the value -1 for the ID. - GenericsStaticsInfo *pInfo = GetGenericsStaticsInfo(); if (!ContainsGenericVariables() && !IsSharedByGenericInstantiations()) { + _ASSERTE(pStaticFieldDescs != NULL); + GenericsStaticsInfo *pInfo = GetGenericsStaticsInfo(); Module * pModuleForStatics = GetLoaderModule(); - pInfo->m_DynamicTypeID = pModuleForStatics->AllocateDynamicEntry(this); + m_dynamicTypeID = pModuleForStatics->AllocateDynamicEntry(this); } else { - pInfo->m_DynamicTypeID = (SIZE_T)-1; + m_dynamicTypeID = (DWORD)-1; } - pInfo->m_pFieldDescs = pStaticFieldDescs; + if (HasGenericsStaticsInfo()) + { + GetGenericsStaticsInfo()->m_pFieldDescs = pStaticFieldDescs; + } } #endif // !DACCESS_COMPILE @@ -4230,7 +4206,7 @@ OBJECTREF MethodTable::GetManagedClassObject() GC_TRIGGERS; MODE_COOPERATIVE; INJECT_FAULT(COMPlusThrowOM()); - POSTCONDITION(GetWriteableData()->m_hExposedClassObject != 0); + POSTCONDITION(m_hExposedClassObject != 0); //REENTRANT } CONTRACT_END; @@ -4240,7 +4216,7 @@ OBJECTREF MethodTable::GetManagedClassObject() GCStress::MaybeTrigger(); #endif // _DEBUG - if (GetWriteableData()->m_hExposedClassObject == NULL) + if (m_hExposedClassObject == NULL) { // Make sure that we have been restored CheckRestore(); @@ -4258,7 +4234,7 @@ OBJECTREF MethodTable::GetManagedClassObject() // Only the winner can set m_ExposedClassObject from NULL. LOADERHANDLE exposedClassObjectHandle = pLoaderAllocator->AllocateHandle(refClass); - if (InterlockedCompareExchangeT(&GetWriteableDataForWrite()->m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) + if (InterlockedCompareExchangeT(&m_hExposedClassObject, exposedClassObjectHandle, static_cast(NULL))) { pLoaderAllocator->FreeHandle(exposedClassObjectHandle); } @@ -6021,6 +5997,51 @@ MethodDesc * MethodTable::ReverseInterfaceMDLookup(UINT32 slotNumber) return NULL; } +//========================================================================================== +bool MethodTable::GetTypeIDOnFlags(UINT32 *typeID) +{ + UINT32 flags = VolatileLoadWithoutBarrier(&m_dwWriteableFlags); + flags &= enum_mask_TypeID; + *typeID = flags >> TypeIDShift; + static_assert_no_msg((0xFFFFFFFF << TypeIDShift) == enum_mask_TypeID); + if (*typeID == 0) + { + *typeID = TypeIDProvider::INVALID_TYPE_ID; + } + else if (*typeID == enum_mask_TypeID) + { + // TypeID was not able to be stored previously, and must be found elsewhere + *typeID = 0; + return false; + } + return true; +} + +//========================================================================================== +bool MethodTable::SetTypeIDOnFlags(UINT32 typeID) +{ +#ifdef _DEBUG + UINT32 oldTypeID; + GetTypeIDOnFlags(&oldTypeID); + _ASSERTE(oldTypeID == TypeIDProvider::INVALID_TYPE_ID); +#endif + + DWFLAGS_WRITEABLE_ENUM flagToSet; + bool returnValue; + if ((typeID == 0) || (typeID >= (enum_mask_TypeID >> TypeIDShift))) + { + flagToSet = enum_mask_TypeID; + returnValue = false; // Unable to set TypeID + } + else + { + flagToSet = (DWFLAGS_WRITEABLE_ENUM)(typeID << TypeIDShift); + returnValue = true; // Unable to set TypeID + } + SetFlag(flagToSet); + return returnValue; +} + //========================================================================================== UINT32 MethodTable::GetTypeID() { @@ -6688,7 +6709,7 @@ BOOL MethodTable::IsParentMethodTablePointerValid() // workaround: Type loader accesses partially initialized datastructures that interferes with IBC logging. // Once type loader is fixed to do not access partially initialized datastructures, this can go away. - if (!GetWriteableData_NoLogging()->IsParentMethodTablePointerValid()) + if (!GetFlag(enum_flag_ParentMethodTablePointerValid)) return FALSE; return TRUE; @@ -7915,12 +7936,6 @@ MethodTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) DacEnumMemoryRegion(dac_cast(it.GetIndirectionSlot()), it.GetSize()); } - PTR_MethodTableWriteableData pWriteableData = m_pWriteableData; - if (pWriteableData.IsValid()) - { - pWriteableData.EnumMem(); - } - if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE) { DispatchMap * pMap = GetDispatchMap(); @@ -8693,10 +8708,7 @@ BOOL MethodTable::Validate() ASSERT_AND_CHECK(SanityCheck()); #ifdef _DEBUG - ASSERT_AND_CHECK(m_pWriteableData != NULL); - - MethodTableWriteableData *pWriteableData = m_pWriteableData; - DWORD dwLastVerifiedGCCnt = pWriteableData->m_dwLastVerifedGCCnt; + DWORD dwLastVerifiedGCCnt = m_dwLastVerifedGCCnt; // Here we used to assert that (dwLastVerifiedGCCnt <= GCHeapUtilities::GetGCHeap()->GetGcCount()) but // this is no longer true because with background gc. Since the purpose of having // m_dwLastVerifedGCCnt is just to only verify the same method table once for each GC @@ -8722,7 +8734,7 @@ BOOL MethodTable::Validate() } #ifdef _DEBUG - pWriteableData->m_dwLastVerifedGCCnt = GCHeapUtilities::GetGCHeap()->GetGcCount(); + m_dwLastVerifedGCCnt = GCHeapUtilities::GetGCHeap()->GetGcCount(); #endif //_DEBUG return TRUE; diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 1cc4cb84a4d177..3ba3b2feb5bec7 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -248,135 +248,9 @@ struct GenericsStaticsInfo { // Pointer to field descs for statics PTR_FieldDesc m_pFieldDescs; - - // Method table ID for statics - SIZE_T m_DynamicTypeID; - }; // struct GenericsStaticsInfo typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo; -// -// This struct consolidates the writeable parts of the MethodTable -// so that we can layout a read-only MethodTable with a pointer -// to the writeable parts of the MethodTable in an ngen image -// -struct MethodTableWriteableData -{ - friend class MethodTable; -#if defined(DACCESS_COMPILE) - friend class NativeImageDumper; -#endif - - enum - { - // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS - // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS - // CARRY THE CORRECT INITIAL FLAGS. - - enum_flag_Unrestored = 0x00000004, - enum_flag_HasApproxParent = 0x00000010, - enum_flag_UnrestoredTypeKey = 0x00000020, - enum_flag_IsNotFullyLoaded = 0x00000040, - enum_flag_DependenciesLoaded = 0x00000080, // class and all dependencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED - - // enum_unused = 0x00000100, - - enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000200, // Is any field type or sub field type overrode Equals or GetHashCode - enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000400, // Whether we have checked the overridden Equals or GetHashCode - - // enum_unused = 0x00010000, - // enum_unused = 0x00020000, - // enum_unused = 0x00040000, - // enum_unused = 0x00080000, // enum_unused = 0x0010000, - // enum_unused = 0x0020000, - // enum_unused = 0x0040000, - // enum_unused = 0x0080000, - -#ifdef _DEBUG - enum_flag_ParentMethodTablePointerValid = 0x40000000, - enum_flag_HasInjectedInterfaceDuplicates = 0x80000000, -#endif - }; - DWORD m_dwFlags; // Lot of empty bits here. - - /* - * m_hExposedClassObject is LoaderAllocator slot index to - * a RuntimeType instance for this class. - */ - LOADERHANDLE m_hExposedClassObject; - -#ifdef _DEBUG - // to avoid verify same method table too many times when it's not changing, we cache the GC count - // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if - // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a - // GC (like AD unload) - Volatile m_dwLastVerifedGCCnt; - -#ifdef HOST_64BIT - DWORD m_dwPadding; // Just to keep the size a multiple of 8 -#endif - -#endif - -public: -#ifdef _DEBUG - inline BOOL IsParentMethodTablePointerValid() const - { - LIMITED_METHOD_DAC_CONTRACT; - - return (m_dwFlags & enum_flag_ParentMethodTablePointerValid); - } - inline void SetParentMethodTablePointerValid() - { - LIMITED_METHOD_CONTRACT; - - m_dwFlags |= enum_flag_ParentMethodTablePointerValid; - } -#endif - - - inline LOADERHANDLE GetExposedClassObjectHandle() const - { - LIMITED_METHOD_CONTRACT; - return m_hExposedClassObject; - } - - void SetIsNotFullyLoadedForBuildMethodTable() - { - LIMITED_METHOD_CONTRACT; - - // Used only during method table initialization - no need for logging or Interlocked Exchange. - m_dwFlags |= (MethodTableWriteableData::enum_flag_UnrestoredTypeKey | - MethodTableWriteableData::enum_flag_Unrestored | - MethodTableWriteableData::enum_flag_IsNotFullyLoaded | - MethodTableWriteableData::enum_flag_HasApproxParent); - } - - void SetIsRestoredForBuildMethodTable() - { - LIMITED_METHOD_CONTRACT; - - // Used only during method table initialization - no need for logging or Interlocked Exchange. - m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey | - MethodTableWriteableData::enum_flag_Unrestored); - } - - void SetIsRestoredForBuildArrayMethodTable() - { - LIMITED_METHOD_CONTRACT; - - // Used only during method table initialization - no need for logging or Interlocked Exchange. - SetIsRestoredForBuildMethodTable(); - - // Array's parent is always precise - m_dwFlags &= ~(MethodTableWriteableData::enum_flag_HasApproxParent); - - } -}; // struct MethodTableWriteableData - -typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData; -typedef DPTR(MethodTableWriteableData const) PTR_Const_MethodTableWriteableData; - #ifdef UNIX_AMD64_ABI_ITF inline SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType) @@ -837,23 +711,11 @@ class MethodTable void CheckRestore(); - inline BOOL HasUnrestoredTypeKey() const - { - LIMITED_METHOD_DAC_CONTRACT; - - return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0; - } - - // Actually do the restore actions on the method table - void Restore(); - - void SetIsRestored(); - inline BOOL IsRestored_NoLogging() { LIMITED_METHOD_DAC_CONTRACT; - return !(GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored); + return !GetFlag(enum_flag_Unrestored); } inline BOOL IsRestored() { @@ -887,7 +749,7 @@ class MethodTable PRECONDITION(!HasApproxParent()); PRECONDITION(IsRestored_NoLogging()); - InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_IsNotFullyLoaded); + ClearFlag(enum_flag_IsNotFullyLoaded); } // Equivalent to GetLoadLevel() == CLASS_LOADED @@ -895,13 +757,13 @@ class MethodTable { WRAPPER_NO_CONTRACT; - return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) == 0; + return GetFlag(enum_flag_IsNotFullyLoaded) == 0; } inline BOOL CanCompareBitsOrUseFastGetHashCode() { LIMITED_METHOD_CONTRACT; - return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode); + return GetFlag(enum_flag_CanCompareBitsOrUseFastGetHashCode); } // If canCompare is true, this method ensure an atomic operation for setting @@ -912,8 +774,7 @@ class MethodTable if (canCompare) { // Set checked and canCompare flags in one interlocked operation. - InterlockedOr((LONG*)&GetWriteableDataForWrite_NoLogging()->m_dwFlags, - MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode | MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode); + SetFlag((DWFLAGS_WRITEABLE_ENUM)(enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode | enum_flag_CanCompareBitsOrUseFastGetHashCode)); } else { @@ -924,13 +785,13 @@ class MethodTable inline BOOL HasCheckedCanCompareBitsOrUseFastGetHashCode() { LIMITED_METHOD_CONTRACT; - return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode); + return GetFlag(enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode); } inline void SetHasCheckedCanCompareBitsOrUseFastGetHashCode() { WRAPPER_NO_CONTRACT; - InterlockedOr((LONG*)&GetWriteableDataForWrite_NoLogging()->m_dwFlags, MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode); + SetFlag(enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode); } inline void SetIsDependenciesLoaded() @@ -946,27 +807,24 @@ class MethodTable PRECONDITION(!HasApproxParent()); PRECONDITION(IsRestored_NoLogging()); - InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags, MethodTableWriteableData::enum_flag_DependenciesLoaded); + SetFlag(enum_flag_DependenciesLoaded); } inline ClassLoadLevel GetLoadLevel() { LIMITED_METHOD_DAC_CONTRACT; - DWORD dwFlags = GetWriteableData()->m_dwFlags; + DWORD dwFlags = m_dwWriteableFlags; - if (dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) + if (dwFlags & enum_flag_IsNotFullyLoaded) { - if (dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) - return CLASS_LOAD_UNRESTOREDTYPEKEY; - - if (dwFlags & MethodTableWriteableData::enum_flag_Unrestored) + if (dwFlags & enum_flag_Unrestored) return CLASS_LOAD_UNRESTORED; - if (dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) + if (dwFlags & enum_flag_HasApproxParent) return CLASS_LOAD_APPROXPARENTS; - if (!(dwFlags & MethodTableWriteableData::enum_flag_DependenciesLoaded)) + if (!(dwFlags & enum_flag_DependenciesLoaded)) return CLASS_LOAD_EXACTPARENTS; return CLASS_DEPENDENCIES_LOADED; @@ -1418,7 +1276,7 @@ class MethodTable return pMTParent == NULL ? 0 : pMTParent->GetNumVirtuals(); } - #define SIZEOF__MethodTable_ (0x10 + (6 INDEBUG(+1)) * TARGET_POINTER_SIZE) + #define SIZEOF__MethodTable_ (0x10 + (7 INDEBUG(+2)) * TARGET_POINTER_SIZE) static inline DWORD GetVtableOffset() { @@ -1743,12 +1601,12 @@ class MethodTable BOOL HasApproxParent() { LIMITED_METHOD_DAC_CONTRACT; - return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) != 0; + return GetFlag(enum_flag_HasApproxParent); } inline void SetHasExactParent() { WRAPPER_NO_CONTRACT; - InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_HasApproxParent); + ClearFlag(enum_flag_HasApproxParent); } @@ -1787,7 +1645,7 @@ class MethodTable LIMITED_METHOD_CONTRACT; m_pParentMethodTable = pParentMethodTable; #ifdef _DEBUG - GetWriteableDataForWrite_NoLogging()->SetParentMethodTablePointerValid(); + SetFlag(enum_flag_ParentMethodTablePointerValid); #endif } #endif // !DACCESS_COMPILE @@ -2202,6 +2060,10 @@ class MethodTable // Lookup, will assign ID if not already done. UINT32 GetTypeID(); + // Functions used to optimize type id lookup by the TypeIDMap. + bool GetTypeIDOnFlags(UINT32 *typeID); + bool SetTypeIDOnFlags(UINT32 typeID); + // Will return either the dispatch map type. May trigger type loader in order to get // exact result. @@ -2328,12 +2190,6 @@ class MethodTable return GetGenericsStaticsInfo()->m_pFieldDescs; } - BOOL HasCrossModuleGenericStaticsInfo() - { - LIMITED_METHOD_DAC_CONTRACT; - return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics); - } - PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID); WORD GetNumHandleRegularStatics(); @@ -2720,39 +2576,42 @@ class MethodTable // Private part of MethodTable // ------------------------------------------------------------------ -#ifndef DACCESS_COMPILE - inline void SetWriteableData(PTR_MethodTableWriteableData pMTWriteableData) + inline LOADERHANDLE GetExposedClassObjectHandle() const { LIMITED_METHOD_CONTRACT; - _ASSERTE(pMTWriteableData); - m_pWriteableData = pMTWriteableData; + return m_hExposedClassObject; } -#endif - inline PTR_Const_MethodTableWriteableData GetWriteableData() const + void SetIsNotFullyLoadedForBuildMethodTable() { - LIMITED_METHOD_DAC_CONTRACT; - return GetWriteableData_NoLogging(); - } + LIMITED_METHOD_CONTRACT; - inline PTR_Const_MethodTableWriteableData GetWriteableData_NoLogging() const - { - LIMITED_METHOD_DAC_CONTRACT; - return MethodTable::m_pWriteableData; + // Used only during method table initialization - no need for logging or Interlocked Exchange. + m_dwWriteableFlags |= (enum_flag_Unrestored | + enum_flag_IsNotFullyLoaded | + enum_flag_HasApproxParent); } - inline PTR_MethodTableWriteableData GetWriteableDataForWrite() + void SetIsRestoredForBuildMethodTable() { - LIMITED_METHOD_DAC_CONTRACT; - return GetWriteableDataForWrite_NoLogging(); + LIMITED_METHOD_CONTRACT; + + // Used only during method table initialization - no need for logging or Interlocked Exchange. + m_dwWriteableFlags &= ~(enum_flag_Unrestored); } - inline PTR_MethodTableWriteableData GetWriteableDataForWrite_NoLogging() + void SetIsRestoredForBuildArrayMethodTable() { - LIMITED_METHOD_DAC_CONTRACT; - return MethodTable::m_pWriteableData; + LIMITED_METHOD_CONTRACT; + + // Used only during method table initialization - no need for logging or Interlocked Exchange. + SetIsRestoredForBuildMethodTable(); + + // Array's parent is always precise + m_dwWriteableFlags &= ~(enum_flag_HasApproxParent); } + //------------------------------------------------------------------- // The GUID Info // Used by COM interop to get GUIDs (IIDs and CLSIDs) @@ -2799,12 +2658,12 @@ public : inline BOOL Debug_HasInjectedInterfaceDuplicates() const { LIMITED_METHOD_CONTRACT; - return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates) != 0; + return GetFlag(enum_flag_HasInjectedInterfaceDuplicates); } inline void Debug_SetHasInjectedInterfaceDuplicates() { LIMITED_METHOD_CONTRACT; - GetWriteableDataForWrite()->m_dwFlags |= MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates; + SetFlag(enum_flag_HasInjectedInterfaceDuplicates); } #endif // _DEBUG @@ -3314,10 +3173,8 @@ public : enum_flag_StaticsMask_NonDynamic = 0x00000000, enum_flag_StaticsMask_Dynamic = 0x00000002, // dynamic statics (EnC, reflection.emit) enum_flag_StaticsMask_Generics = 0x00000004, // generics statics - enum_flag_StaticsMask_CrossModuleGenerics = 0x00000006, // cross module generics statics (NGen) - enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000002, // helper constant to get rid of unnecessary check - enum_flag_NotInPZM = 0x00000008, // True if this type is not in its PreferredZapModule + enum_flag_UNUSED_ComponentSize_2 = 0x00000008, enum_flag_GenericsMask = 0x00000030, enum_flag_GenericsMask_NonGeneric = 0x00000000, // no instantiation @@ -3361,7 +3218,6 @@ public : // to be up to date to reflect the default values of those flags for the // case where this MethodTable is for a String or Array enum_flag_StringArrayValues = SET_TRUE(enum_flag_StaticsMask_NonDynamic) | - SET_FALSE(enum_flag_NotInPZM) | SET_TRUE(enum_flag_GenericsMask_NonGeneric) | SET_FALSE(enum_flag_HasVariance) | SET_FALSE(enum_flag_HasDefaultCtor) | @@ -3483,6 +3339,47 @@ public : }; // enum WFLAGS2_ENUM + const static int TypeIDShift = 12; + enum DWFLAGS_WRITEABLE_ENUM + { + // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS + // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS + // CARRY THE CORRECT INITIAL FLAGS. + // The current implementation does not copy these flags, and sets most to 0 at start + // + // These flags are adjusted via FastInterlockedOr or FastInterlockedAnd + + enum_flag_Unrestored = 0x00000004, + enum_flag_HasApproxParent = 0x00000010, + enum_flag_IsNotFullyLoaded = 0x00000020, + enum_flag_DependenciesLoaded = 0x00000040, // class and all depedencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED + + enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000080, // Is any field type or sub field type overrode Equals or GetHashCode + enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000100, // Whether we have checked the overridden Equals or GetHashCode + +#ifdef _DEBUG + enum_flag_ParentMethodTablePointerValid = 0x00000200, + enum_flag_HasInjectedInterfaceDuplicates = 0x00000400, +#endif + + enum_mask_TypeID = 0xFFFFF000, // The logic that works with this assumes that this mask uses all the bits to the high bit of the enum + }; + + __forceinline void SetFlag(DWFLAGS_WRITEABLE_ENUM flag) + { + InterlockedOr((LONG*)&m_dwWriteableFlags, flag); + } + + __forceinline void ClearFlag(DWFLAGS_WRITEABLE_ENUM flag) + { + InterlockedAnd((LONG*)&m_dwWriteableFlags, ~flag); + } + + __forceinline BOOL GetFlag(DWFLAGS_WRITEABLE_ENUM flag) const + { + return m_dwWriteableFlags & flag; + } + __forceinline void ClearFlag(WFLAGS_LOW_ENUM flag) { _ASSERTE(!IsStringOrArray()); @@ -3574,7 +3471,25 @@ public : PTR_Module m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened images - PTR_MethodTableWriteableData m_pWriteableData; +#ifdef _DEBUG + // to avoid verify same method table too many times when it's not changing, we cache the GC count + // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if + // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a + // GC (like AD unload) + Volatile m_dwLastVerifedGCCnt; + +#if defined(HOST_64BIT) + DWORD m_dwDebuggingPadding; // Just to keep the size a multiple of 8 +#endif // HOST_64BIT + +#endif // _DEBUG + DWORD m_dwWriteableFlags; // Lot of empty bits here. + DWORD m_dynamicTypeID; // Just to keep the size a multiple of 8 + /* + * m_hExposedClassObject is LoaderAllocator slot index to + * a RuntimeType instance for this class. + */ + LOADERHANDLE m_hExposedClassObject; // The value of lowest two bits describe what the union contains enum LowBits { diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index adcdbd33469858..549d71b7eafe70 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1315,8 +1315,7 @@ FORCEINLINE PTR_Module MethodTable::GetGenericsStaticsModuleAndID(DWORD * pID) _ASSERTE(HasGenericsStaticsInfo()); - _ASSERTE(FitsIn(GetGenericsStaticsInfo()->m_DynamicTypeID) || GetGenericsStaticsInfo()->m_DynamicTypeID == (SIZE_T)-1); - *pID = static_cast(GetGenericsStaticsInfo()->m_DynamicTypeID); + *pID = m_dynamicTypeID; return GetLoaderModule(); } @@ -1333,7 +1332,7 @@ FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() LIMITED_METHOD_CONTRACT; // Logging will be done by the slow path - LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); + LOADERHANDLE handle = GetExposedClassObjectHandle(); OBJECTREF retVal; diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 7f623c659c7bb8..2fd03c09cd53c3 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -1854,6 +1854,7 @@ MethodTableBuilder::BuildMethodTableThrowing( } else { + pMT->SetupGenericsStaticsInfo(NULL); // Get an id for the dynamic class. We store it in the class because // no class that is persisted in ngen should have it (ie, if the class is ngened // The id is stored in an optional field so we need to ensure an optional field descriptor has @@ -10183,14 +10184,9 @@ MethodTable * MethodTableBuilder::AllocateNewMT( pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask); - MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *) - pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData)))); - // Note: Memory allocated on loader heap is zero filled - pMT->SetWriteableData(pMTWriteableData); - // This also disables IBC logging until the type is sufficiently intitialized so // it needs to be done early - pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable(); + pMT->SetIsNotFullyLoadedForBuildMethodTable(); #ifdef _DEBUG pClassLoader->m_dwGCSize += dwGCSize; @@ -10299,7 +10295,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT( } #ifdef _DEBUG - pMT->m_pWriteableData->m_dwLastVerifedGCCnt = (DWORD)-1; + pMT->m_dwLastVerifedGCCnt = (DWORD)-1; #endif // _DEBUG RETURN(pMT); @@ -10642,7 +10638,7 @@ MethodTableBuilder::SetupMethodTable2( // The type is sufficiently initialized for most general purpose accessor methods to work. // Mark the type as restored to avoid avoid asserts. Note that this also enables IBC logging. - pMT->GetWriteableDataForWrite_NoLogging()->SetIsRestoredForBuildMethodTable(); + pMT->SetIsRestoredForBuildMethodTable(); #ifdef _DEBUG // Store status if we tried to inject duplicate interfaces diff --git a/src/coreclr/vm/pinnedheaphandles.h b/src/coreclr/vm/pinnedheaphandles.h new file mode 100644 index 00000000000000..606b44a4f7b672 --- /dev/null +++ b/src/coreclr/vm/pinnedheaphandles.h @@ -0,0 +1,136 @@ +#pragma once + +// The pinned heap handle bucket class is used to contain handles allocated +// from an array contained in the pinned heap. +class PinnedHeapHandleBucket +{ +public: + // Constructor and desctructor. + PinnedHeapHandleBucket(PinnedHeapHandleBucket *pNext, PTRARRAYREF pinnedHandleArrayObj, DWORD Size, LoaderAllocator *pLoaderAllocator); + ~PinnedHeapHandleBucket(); + + // This returns the next bucket. + PinnedHeapHandleBucket *GetNext() + { + LIMITED_METHOD_CONTRACT; + + return m_pNext; + } + + // This returns the number of remaining handle slots. + DWORD GetNumRemainingHandles() + { + LIMITED_METHOD_CONTRACT; + + return m_ArraySize - m_CurrentPos; + } + + void ConsumeRemaining() + { + LIMITED_METHOD_CONTRACT; + + m_CurrentPos = m_ArraySize; + } + + OBJECTREF *TryAllocateEmbeddedFreeHandle(); + + // Allocate handles from the bucket. + OBJECTREF* AllocateHandles(DWORD nRequested); + OBJECTREF* CurrentPos() + { + LIMITED_METHOD_CONTRACT; + return m_pArrayDataPtr + m_CurrentPos; + } + + void EnumStaticGCRefs(promote_func* fn, ScanContext* sc); + +private: + PinnedHeapHandleBucket *m_pNext; + int m_ArraySize; + int m_CurrentPos; + int m_CurrentEmbeddedFreePos; + bool m_collectible; + OBJECTHANDLE m_hndHandleArray; + OBJECTREF *m_pArrayDataPtr; +}; + + + +// The pinned heap handle table is used to allocate handles that are pointers +// to objects stored in an array in the pinned object heap. +class PinnedHeapHandleTable +{ +public: + // Constructor and desctructor. + PinnedHeapHandleTable(LoaderAllocator *pDomain, DWORD InitialBucketSize); + ~PinnedHeapHandleTable(); + + // Allocate handles from the pinned heap handle table. + OBJECTREF* AllocateHandles(DWORD nRequested); + + // Release object handles allocated using AllocateHandles(). + void ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased); + + void EnumStaticGCRefs(promote_func* fn, ScanContext* sc); + +private: + void ReleaseHandlesLocked(OBJECTREF *pObjRef, DWORD nReleased); + + // The buckets of object handles. + // synchronized by m_Crst + PinnedHeapHandleBucket *m_pHead; + + // We need to know the containing LoaderAllocator so we know where to allocate handles + LoaderAllocator *m_pLoaderAllocator; + + // The size of the PinnedHeapHandleBucket. + // synchronized by m_Crst + DWORD m_NextBucketSize; + + // for finding and re-using embedded free items in the list + // these fields are synchronized by m_Crst + PinnedHeapHandleBucket *m_pFreeSearchHint; + DWORD m_cEmbeddedFree; + + CrstExplicitInit m_Crst; +}; + +class PinnedHeapHandleBlockHolder; +void PinnedHeapHandleBlockHolder__StaticFree(PinnedHeapHandleBlockHolder*); + + +class PinnedHeapHandleBlockHolder:public Holder + +{ + PinnedHeapHandleTable* m_pTable; + DWORD m_Count; + OBJECTREF* m_Data; +public: + FORCEINLINE PinnedHeapHandleBlockHolder(PinnedHeapHandleTable* pOwner, DWORD nCount) + { + WRAPPER_NO_CONTRACT; + m_Data = pOwner->AllocateHandles(nCount); + m_Count=nCount; + m_pTable=pOwner; + }; + + FORCEINLINE void FreeData() + { + WRAPPER_NO_CONTRACT; + for (DWORD i=0;i< m_Count;i++) + ClearObjectReference(m_Data+i); + m_pTable->ReleaseHandles(m_Data, m_Count); + }; + FORCEINLINE OBJECTREF* operator[] (DWORD idx) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(idxFreeData(); +}; \ No newline at end of file diff --git a/src/coreclr/vm/stringliteralmap.cpp b/src/coreclr/vm/stringliteralmap.cpp index 240b57bc73468a..ecd1706970be72 100644 --- a/src/coreclr/vm/stringliteralmap.cpp +++ b/src/coreclr/vm/stringliteralmap.cpp @@ -289,7 +289,7 @@ GlobalStringLiteralMap::GlobalStringLiteralMap() : m_StringToEntryHashTable(NULL) , m_MemoryPool(NULL) , m_HashTableCrstGlobal(CrstGlobalStrLiteralMap) -, m_PinnedHeapHandleTable(SystemDomain::System(), GLOBAL_STRING_TABLE_BUCKET_SIZE) +, m_PinnedHeapHandleTable(SystemDomain::System()->GetLoaderAllocator(), GLOBAL_STRING_TABLE_BUCKET_SIZE) { CONTRACTL { diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index f613addf1418cc..321ce6e474f1c1 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -537,7 +537,7 @@ BOOL TypeDesc::IsRestored_NoLogging() STATIC_CONTRACT_CANNOT_TAKE_LOCK; SUPPORTS_DAC; - return (m_typeAndFlags & TypeDesc::enum_flag_Unrestored) == 0; + return TRUE; } ClassLoadLevel TypeDesc::GetLoadLevel() @@ -547,15 +547,7 @@ ClassLoadLevel TypeDesc::GetLoadLevel() STATIC_CONTRACT_FORBID_FAULT; SUPPORTS_DAC; - if (m_typeAndFlags & TypeDesc::enum_flag_UnrestoredTypeKey) - { - return CLASS_LOAD_UNRESTOREDTYPEKEY; - } - else if (m_typeAndFlags & TypeDesc::enum_flag_Unrestored) - { - return CLASS_LOAD_UNRESTORED; - } - else if (m_typeAndFlags & TypeDesc::enum_flag_IsNotFullyLoaded) + if (m_typeAndFlags & TypeDesc::enum_flag_IsNotFullyLoaded) { if (m_typeAndFlags & TypeDesc::enum_flag_DependenciesLoaded) { diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index 19833eede708bb..888b45ee560569 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -121,14 +121,6 @@ class TypeDesc BOOL IsRestored_NoLogging(); void SetIsRestored(); - inline BOOL HasUnrestoredTypeKey() const - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - - return (m_typeAndFlags & TypeDesc::enum_flag_UnrestoredTypeKey) != 0; - } - BOOL HasTypeEquivalence() const { LIMITED_METHOD_CONTRACT; @@ -190,8 +182,8 @@ class TypeDesc { // unused = 0x00000100, // unused = 0x00000200, - enum_flag_Unrestored = 0x00000400, - enum_flag_UnrestoredTypeKey = 0x00000800, + // unused = 0x00000400, + // unused = 0x00000800, enum_flag_IsNotFullyLoaded = 0x00001000, enum_flag_DependenciesLoaded = 0x00002000, enum_flag_HasTypeEquivalence = 0x00004000 diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 115aae31543610..7a394a16e92d1e 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -998,17 +998,6 @@ BOOL TypeHandle::IsRestored() const } } -BOOL TypeHandle::HasUnrestoredTypeKey() const -{ - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - if (IsTypeDesc()) - return AsTypeDesc()->HasUnrestoredTypeKey(); - else - return AsMethodTable()->HasUnrestoredTypeKey(); -} - void TypeHandle::CheckRestore() const { CONTRACTL @@ -1558,7 +1547,6 @@ CHECK TypeHandle::CheckMatchesKey(TypeKey *pKey) const const char * const classLoadLevelName[] = { "BEGIN", - "UNRESTOREDTYPEKEY", "UNRESTORED", "APPROXPARENTS", "EXACTPARENTS", @@ -1586,7 +1574,6 @@ CHECK TypeHandle::CheckLoadLevel(ClassLoadLevel requiredLevel) // /* debugTypeName.GetUnicode(), */ actualLevel, requiredLevel /* classLoadLevelName[actualLevel], classLoadLevelName[requiredLevel] */)); } CONSISTENCY_CHECK((actualLevel > CLASS_LOAD_UNRESTORED) == IsRestored()); - CONSISTENCY_CHECK((actualLevel == CLASS_LOAD_UNRESTOREDTYPEKEY) == HasUnrestoredTypeKey()); CHECK_OK; } diff --git a/src/coreclr/vm/versionresilienthashcode.cpp b/src/coreclr/vm/versionresilienthashcode.cpp index b3ba764baac595..96321e85eb1ded 100644 --- a/src/coreclr/vm/versionresilienthashcode.cpp +++ b/src/coreclr/vm/versionresilienthashcode.cpp @@ -127,7 +127,7 @@ int GetVersionResilientTypeHashCode(TypeHandle type) IfFailThrow(pMT->GetMDImport()->GetNameOfTypeDef(pMT->GetCl(), &szName, &szNamespace)); int hashcode = ComputeNameHashCode(szNamespace, szName); - MethodTable *pMTEnclosing = pMT->LoadEnclosingMethodTable(CLASS_LOAD_UNRESTOREDTYPEKEY); + MethodTable *pMTEnclosing = pMT->LoadEnclosingMethodTable(CLASS_LOAD_APPROXPARENTS); if (pMTEnclosing != NULL) { hashcode = ComputeNestedTypeHashCode(GetVersionResilientTypeHashCode(TypeHandle(pMTEnclosing)), hashcode); diff --git a/src/coreclr/vm/zapsig.cpp b/src/coreclr/vm/zapsig.cpp index 139994d3acb950..b8cde9c72014d1 100644 --- a/src/coreclr/vm/zapsig.cpp +++ b/src/coreclr/vm/zapsig.cpp @@ -140,7 +140,7 @@ BOOL ZapSig::GetSignatureForTypeHandle(TypeHandle handle, PRECONDITION(CheckPointer(handle)); PRECONDITION(CheckPointer(this->context.pInfoModule)); - PRECONDITION(!handle.HasUnrestoredTypeKey()); + PRECONDITION(handle.IsRestored()); MODE_ANY; } CONTRACTL_END @@ -307,7 +307,7 @@ BOOL ZapSig::GetSignatureForTypeHandle(TypeHandle handle, PRECONDITION(CheckPointer(pZapSigContext->pInfoModule)); PRECONDITION(CheckPointer(handle)); PRECONDITION(CheckPointer(pSig)); - PRECONDITION(!handle.HasUnrestoredTypeKey()); + PRECONDITION(handle.IsRestored()); } CONTRACT_END