Address slowdowns in type loader performance (#39841)
authorDavid Wrighton <davidwr@microsoft.com>
Sat, 25 Jul 2020 18:30:34 +0000 (11:30 -0700)
committerGitHub <noreply@github.com>
Sat, 25 Jul 2020 18:30:34 +0000 (11:30 -0700)
src/coreclr/src/debug/daccess/nidump.cpp
src/coreclr/src/vm/class.cpp
src/coreclr/src/vm/class.h
src/coreclr/src/vm/method.cpp
src/coreclr/src/vm/method.hpp
src/coreclr/src/vm/method.inl
src/coreclr/src/vm/methodtablebuilder.cpp
src/coreclr/src/vm/methodtablebuilder.h
src/coreclr/src/vm/methodtablebuilder.inl
src/coreclr/src/vm/siginfo.cpp

index 5a0bbfd..06a6fff 100644 (file)
@@ -7996,7 +7996,7 @@ void NativeImageDumper::DumpMethodDesc( PTR_MethodDesc md, PTR_Module module )
                               InstantiatedMethodDesc, METHODDESCS );
 
 #ifdef FEATURE_COMINTEROP
-        if (imd->IMD_HasComPlusCallInfo())
+        if (imd->IsGenericComPlusCall())
         {
             PTR_ComPlusCallInfo compluscall = imd->IMD_GetComPlusCallInfo();
             DumpComPlusCallInfo( compluscall, METHODDESCS );
index 8e18a47..7a243ca 100644 (file)
@@ -1184,107 +1184,127 @@ void ClassLoader::ValidateMethodsWithCovariantReturnTypes(MethodTable* pMT)
         return;
 
     // Step 1: Validate compatibility of return types on overriding methods
-
-    for (WORD i = 0; i < pParentMT->GetNumVirtuals(); i++)
+    if (pMT->GetClass()->HasCovariantOverride() && (!pMT->GetModule()->IsReadyToRun() || !pMT->GetModule()->GetReadyToRunInfo()->SkipTypeValidation()))
     {
-        MethodDesc* pMD = pMT->GetMethodDescForSlot(i);
-        MethodDesc* pParentMD = pParentMT->GetMethodDescForSlot(i);
+        for (WORD i = 0; i < pParentMT->GetNumVirtuals(); i++)
+        {
+            if (pMT->GetRestoredSlot(i) == pParentMT->GetRestoredSlot(i))
+            {
+                // The real check is that the MethodDesc's must not match, but a simple VTable check will
+                // work most of the time, and is far faster than the GetMethodDescForSlot method.
+                _ASSERTE(pMT->GetMethodDescForSlot(i) == pParentMT->GetMethodDescForSlot(i));
+                continue;
+            }
+            MethodDesc* pMD = pMT->GetMethodDescForSlot(i);
+            MethodDesc* pParentMD = pParentMT->GetMethodDescForSlot(i);
 
-        if (pMD == pParentMD)
-            continue;
+            if (pMD == pParentMD)
+                continue;
 
-        if (!pMD->RequiresCovariantReturnTypeChecking() && !pParentMD->RequiresCovariantReturnTypeChecking())
-            continue;
+            if (!pMD->RequiresCovariantReturnTypeChecking() && !pParentMD->RequiresCovariantReturnTypeChecking())
+                continue;
 
-        // If the bit is not set on this method, but we reach here because it's been set on the method at the same slot on
-        // the base type, set the bit for the current method to ensure any future overriding method down the chain gets checked.
-        if (!pMD->RequiresCovariantReturnTypeChecking())
-            pMD->SetRequiresCovariantReturnTypeChecking();
+            // If the bit is not set on this method, but we reach here because it's been set on the method at the same slot on
+            // the base type, set the bit for the current method to ensure any future overriding method down the chain gets checked.
+            if (!pMD->RequiresCovariantReturnTypeChecking())
+                pMD->SetRequiresCovariantReturnTypeChecking();
 
-        // The context used to load the return type of the parent method has to use the generic method arguments
-        // of the overriding method, otherwise the type comparison below will not work correctly
-        SigTypeContext context1(pParentMD->GetClassInstantiation(), pMD->GetMethodInstantiation());
-        MetaSig methodSig1(pParentMD);
-        TypeHandle hType1 = methodSig1.GetReturnProps().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS);
+            // The context used to load the return type of the parent method has to use the generic method arguments
+            // of the overriding method, otherwise the type comparison below will not work correctly
+            SigTypeContext context1(pParentMD->GetClassInstantiation(), pMD->GetMethodInstantiation());
+            MetaSig methodSig1(pParentMD);
+            TypeHandle hType1 = methodSig1.GetReturnProps().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS);
 
-        SigTypeContext context2(pMD);
-        MetaSig methodSig2(pMD);
-        TypeHandle hType2 = methodSig2.GetReturnProps().GetTypeHandleThrowing(pMD->GetModule(), &context2, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS);
+            SigTypeContext context2(pMD);
+            MetaSig methodSig2(pMD);
+            TypeHandle hType2 = methodSig2.GetReturnProps().GetTypeHandleThrowing(pMD->GetModule(), &context2, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS);
 
-        if (!IsCompatibleWith(hType1, hType2))
-        {
-            SString strAssemblyName;
-            pMD->GetAssembly()->GetDisplayName(strAssemblyName);
+            if (!IsCompatibleWith(hType1, hType2))
+            {
+                SString strAssemblyName;
+                pMD->GetAssembly()->GetDisplayName(strAssemblyName);
 
-            SString strInvalidTypeName;
-            TypeString::AppendType(strInvalidTypeName, TypeHandle(pMD->GetMethodTable()));
+                SString strInvalidTypeName;
+                TypeString::AppendType(strInvalidTypeName, TypeHandle(pMD->GetMethodTable()));
 
-            SString strInvalidMethodName;
-            TypeString::AppendMethod(strInvalidMethodName, pMD, pMD->GetMethodInstantiation());
+                SString strInvalidMethodName;
+                TypeString::AppendMethod(strInvalidMethodName, pMD, pMD->GetMethodInstantiation());
 
-            SString strParentMethodName;
-            TypeString::AppendMethod(strParentMethodName, pParentMD, pParentMD->GetMethodInstantiation());
+                SString strParentMethodName;
+                TypeString::AppendMethod(strParentMethodName, pParentMD, pParentMD->GetMethodInstantiation());
 
-            COMPlusThrow(
-                kTypeLoadException,
-                IDS_CLASSLOAD_MI_BADRETURNTYPE,
-                strInvalidMethodName,
-                strInvalidTypeName,
-                strAssemblyName,
-                strParentMethodName);
+                COMPlusThrow(
+                    kTypeLoadException,
+                    IDS_CLASSLOAD_MI_BADRETURNTYPE,
+                    strInvalidMethodName,
+                    strInvalidTypeName,
+                    strAssemblyName,
+                    strParentMethodName);
+            }
         }
     }
 
     // Step 2: propate overriding MethodImpls to applicable vtable slots if the declaring method has the attribute
 
-    MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
-
-    for (WORD i = 0; i < pParentMT->GetNumVirtuals(); i++)
+    if (pMT->GetClass()->HasVTableMethodImpl())
     {
-        MethodDesc* pMD = pMT->GetMethodDescForSlot(i);
-        MethodDesc* pParentMD = pParentMT->GetMethodDescForSlot(i);
-        if (pMD == pParentMD)
-            continue;
-
-        // The attribute is only applicable to MethodImpls. For anything else, it will be treated as a no-op
-        if (!pMD->IsMethodImpl())
-            continue;
+        MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
 
-        // Search if the attribute has been applied on this vtable slot, either by the current MethodImpl, or by a previous
-        // MethodImpl somewhere in the base type hierarchy.
-        bool foundAttribute = false;
-        MethodTable* pCurrentMT = pMT;
-        while (!foundAttribute && pCurrentMT != NULL && i < pCurrentMT->GetNumVirtuals())
+        for (WORD i = 0; i < pParentMT->GetNumVirtuals(); i++)
         {
-            MethodDesc* pCurrentMD = pCurrentMT->GetMethodDescForSlot(i);
+            if (pMT->GetRestoredSlot(i) == pParentMT->GetRestoredSlot(i))
+            {
+                // The real check is that the MethodDesc's must not match, but a simple VTable check will
+                // work most of the time, and is far faster than the GetMethodDescForSlot method.
+                _ASSERTE(pMT->GetMethodDescForSlot(i) == pParentMT->GetMethodDescForSlot(i));
+                continue;
+            }
+
+            MethodDesc* pMD = pMT->GetMethodDescForSlot(i);
+            MethodDesc* pParentMD = pParentMT->GetMethodDescForSlot(i);
+            if (pMD == pParentMD)
+                continue;
 
             // The attribute is only applicable to MethodImpls. For anything else, it will be treated as a no-op
-            if (pCurrentMD->IsMethodImpl())
+            if (!pMD->IsMethodImpl())
+                continue;
+
+            // Search if the attribute has been applied on this vtable slot, either by the current MethodImpl, or by a previous
+            // MethodImpl somewhere in the base type hierarchy.
+            bool foundAttribute = false;
+            MethodTable* pCurrentMT = pMT;
+            while (!foundAttribute && pCurrentMT != NULL && i < pCurrentMT->GetNumVirtuals())
             {
-                BYTE* pVal = NULL;
-                ULONG cbVal = 0;
-                if (pCurrentMD->GetCustomAttribute(WellKnownAttribute::PreserveBaseOverridesAttribute, (const void**)&pVal, &cbVal) == S_OK)
-                    foundAttribute = true;
-            }
+                MethodDesc* pCurrentMD = pCurrentMT->GetMethodDescForSlot(i);
 
-            pCurrentMT = pCurrentMT->GetParentMethodTable();
-        }
+                // The attribute is only applicable to MethodImpls. For anything else, it will be treated as a no-op
+                if (pCurrentMD->IsMethodImpl())
+                {
+                    BYTE* pVal = NULL;
+                    ULONG cbVal = 0;
+                    if (pCurrentMD->GetCustomAttribute(WellKnownAttribute::PreserveBaseOverridesAttribute, (const void**)&pVal, &cbVal) == S_OK)
+                        foundAttribute = true;
+                }
 
-        if (!foundAttribute)
-            continue;
+                pCurrentMT = pCurrentMT->GetParentMethodTable();
+            }
 
-        // Search for any vtable slot still pointing at the parent method, and update it with the current overriding method
-        for (WORD j = i; j < pParentMT->GetNumVirtuals(); j++)
-        {
-            MethodDesc* pCurrentMD = pMT->GetMethodDescForSlot(j);
-            if (pCurrentMD == pParentMD)
+            if (!foundAttribute)
+                continue;
+
+            // Search for any vtable slot still pointing at the parent method, and update it with the current overriding method
+            for (WORD j = i; j < pParentMT->GetNumVirtuals(); j++)
             {
-                // This is a vtable slot that needs to be updated to the new overriding method because of the
-                // presence of the attribute.
-                pMT->SetSlot(j, pMT->GetSlot(i));
-                _ASSERT(pMT->GetMethodDescForSlot(j) == pMD);
+                MethodDesc* pCurrentMD = pMT->GetMethodDescForSlot(j);
+                if (pCurrentMD == pParentMD)
+                {
+                    // This is a vtable slot that needs to be updated to the new overriding method because of the
+                    // presence of the attribute.
+                    pMT->SetSlot(j, pMT->GetSlot(i));
+                    _ASSERT(pMT->GetMethodDescForSlot(j) == pMD);
 
-                hMTData->UpdateImplMethodDesc(pMD, j);
+                    hMTData->UpdateImplMethodDesc(pMD, j);
+                }
             }
         }
     }
index 98a59db..179a082 100644 (file)
@@ -1158,6 +1158,30 @@ public:
     }
 #endif // FEATURE_COMINTEROP
 
+    inline void SetHasVTableMethodImpl()
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_VMFlags |= VMFLAG_VTABLEMETHODIMPL;
+    }
+
+    inline BOOL HasVTableMethodImpl()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_VMFlags & VMFLAG_VTABLEMETHODIMPL);
+    }
+
+    inline void SetHasCovariantOverride()
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_VMFlags |= VMFLAG_COVARIANTOVERRIDE;
+    }
+
+    inline BOOL HasCovariantOverride()
+    {
+        LIMITED_METHOD_CONTRACT;
+        return (m_VMFlags & VMFLAG_COVARIANTOVERRIDE);
+    }
+
 #ifdef _DEBUG
     inline DWORD IsDestroyed()
     {
@@ -1691,8 +1715,8 @@ public:
         VMFLAG_HASCOCLASSATTRIB                = 0x01000000,
         VMFLAG_COMEVENTITFMASK                 = 0x02000000, // class is a special COM event interface
 #endif // FEATURE_COMINTEROP
-        // unused                              = 0x04000000,
-        // unused                              = 0x08000000,
+        VMFLAG_VTABLEMETHODIMPL                = 0x04000000, // class uses MethodImpl to override virtual function defined on class
+        VMFLAG_COVARIANTOVERRIDE               = 0x08000000, // class has a covariant override
 
         // This one indicates that the fields of the valuetype are
         // not tightly packed and is used to check whether we can
index 9c247d6..72d0159 100644 (file)
@@ -83,7 +83,7 @@ static_assert_no_msg((sizeof(DynamicMethodDesc)     & MethodDesc::ALIGNMENT_MASK
     adjustment + sizeof(ComPlusCallMethodDesc),      /* mcComInterOp    */  \
     adjustment + sizeof(DynamicMethodDesc)           /* mcDynamic       */
 
-const SIZE_T MethodDesc::s_ClassificationSizeTable[] = {
+const BYTE MethodDesc::s_ClassificationSizeTable[] = {
     // This is the raw
     METHOD_DESC_SIZES(0),
 
@@ -91,7 +91,24 @@ const SIZE_T MethodDesc::s_ClassificationSizeTable[] = {
     // We index using optional slot flags into it
     METHOD_DESC_SIZES(sizeof(NonVtableSlot)),
     METHOD_DESC_SIZES(sizeof(MethodImpl)),
-    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(MethodImpl))
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(MethodImpl)),
+
+    METHOD_DESC_SIZES(sizeof(NativeCodeSlot)),
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(NativeCodeSlot)),
+    METHOD_DESC_SIZES(sizeof(MethodImpl) + sizeof(NativeCodeSlot)),
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(MethodImpl) + sizeof(NativeCodeSlot)),
+
+#ifdef FEATURE_COMINTEROP
+    METHOD_DESC_SIZES(sizeof(ComPlusCallInfo)),
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(ComPlusCallInfo)),
+    METHOD_DESC_SIZES(sizeof(MethodImpl) + sizeof(ComPlusCallInfo)),
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(MethodImpl) + sizeof(ComPlusCallInfo)),
+
+    METHOD_DESC_SIZES(sizeof(NativeCodeSlot) + sizeof(ComPlusCallInfo)),
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(NativeCodeSlot) + sizeof(ComPlusCallInfo)),
+    METHOD_DESC_SIZES(sizeof(MethodImpl) + sizeof(NativeCodeSlot) + sizeof(ComPlusCallInfo)),
+    METHOD_DESC_SIZES(sizeof(NonVtableSlot) + sizeof(MethodImpl) + sizeof(NativeCodeSlot) + sizeof(ComPlusCallInfo))
+#endif
 };
 
 #ifndef FEATURE_COMINTEROP
@@ -122,18 +139,22 @@ SIZE_T MethodDesc::SizeOf()
 {
     LIMITED_METHOD_DAC_CONTRACT;
 
-    SIZE_T size = s_ClassificationSizeTable[m_wFlags & (mdcClassification | mdcHasNonVtableSlot | mdcMethodImpl)];
+    SIZE_T size = s_ClassificationSizeTable[m_wFlags & 
+        (mdcClassification 
+        | mdcHasNonVtableSlot 
+        | mdcMethodImpl 
+#ifdef FEATURE_COMINTEROP
+        | mdcHasComPlusCallInfo
+#endif
+        | mdcHasNativeCodeSlot)];
 
+#ifdef FEATURE_PREJIT
     if (HasNativeCodeSlot())
     {
-        size += (*dac_cast<PTR_TADDR>(dac_cast<TADDR>(this) + size) & FIXUP_LIST_MASK) ?
-            (sizeof(NativeCodeSlot) + sizeof(FixupListSlot)) : sizeof(NativeCodeSlot);
+        size += (*dac_cast<PTR_TADDR>(GetAddrOfNativeCodeSlot()) & FIXUP_LIST_MASK) ? 
+            sizeof(FixupListSlot) : 0;
     }
-
-#ifdef FEATURE_COMINTEROP
-    if (IsGenericComPlusCall())
-        size += sizeof(ComPlusCallInfo);
-#endif // FEATURE_COMINTEROP
+#endif
 
     return size;
 }
@@ -3696,11 +3717,11 @@ void MethodDesc::SaveChunk::SaveOneChunk(COUNT_T start, COUNT_T count, ULONG siz
 
         if (pMethodInfo->m_fHasNativeCodeSlot)
         {
-            pNewMD->m_bFlags2 |= enum_flag2_HasNativeCodeSlot;
+            pNewMD->m_wFlags |= mdcHasNativeCodeSlot;
         }
         else
         {
-            pNewMD->m_bFlags2 &= ~enum_flag2_HasNativeCodeSlot;
+            pNewMD->m_wFlags &= ~mdcHasNativeCodeSlot;
         }
 
 #ifdef FEATURE_COMINTEROP
index 4103ec6..c19dcc7 100644 (file)
@@ -139,11 +139,18 @@ enum MethodDescClassification
     // where the function explicitly implements IInterface.foo() instead of foo().
     mdcMethodImpl                       = 0x0010,
 
-    // Method is static
-    mdcStatic                           = 0x0020,
+    // Has slot for native code
+    mdcHasNativeCodeSlot                = 0x0020,
 
+#ifdef FEATURE_COMINTEROP
+    mdcHasComPlusCallInfo               = 0x0040,
+#else
     // unused                           = 0x0040,
-    // unused                           = 0x0080,
+#endif
+
+    // Method is static
+    mdcStatic                           = 0x0080,
+
     // unused                           = 0x0100,
     // unused                           = 0x0200,
 
@@ -1832,7 +1839,7 @@ protected:
         enum_flag2_HasPrecode                           = 0x02,   // Precode has been allocated for this method
 
         enum_flag2_IsUnboxingStub                       = 0x04,
-        enum_flag2_HasNativeCodeSlot                    = 0x08,   // Has slot for native code
+        // unused                                       = 0x08,
 
         enum_flag2_IsJitIntrinsic                       = 0x10,   // Jit may expand method as an intrinsic
 
@@ -1881,13 +1888,13 @@ public:
     inline BOOL HasNativeCodeSlot()
     {
         LIMITED_METHOD_DAC_CONTRACT;
-        return (m_bFlags2 & enum_flag2_HasNativeCodeSlot) != 0;
+        return (m_wFlags & mdcHasNativeCodeSlot) != 0;
     }
 
     inline void SetHasNativeCodeSlot()
     {
         LIMITED_METHOD_CONTRACT;
-        m_bFlags2 |= enum_flag2_HasNativeCodeSlot;
+        m_wFlags |= mdcHasNativeCodeSlot;
     }
 
     inline BOOL IsJitIntrinsic()
@@ -1915,7 +1922,7 @@ public:
         m_bFlags2 |= enum_flag2_RequiresCovariantReturnTypeChecking;
     }
 
-    static const SIZE_T s_ClassificationSizeTable[];
+    static const BYTE s_ClassificationSizeTable[];
 
     static SIZE_T GetBaseSize(DWORD classification)
     {
@@ -3537,18 +3544,10 @@ public:
     }
 
 #ifdef FEATURE_COMINTEROP
-    BOOL IMD_HasComPlusCallInfo()
-    {
-        LIMITED_METHOD_CONTRACT;
-        return ((m_wFlags2 & HasComPlusCallInfo) != 0);
-    }
-
     void IMD_SetupGenericComPlusCall()
     {
         LIMITED_METHOD_CONTRACT;
 
-        m_wFlags2 |= InstantiatedMethodDesc::HasComPlusCallInfo;
-
         IMD_GetComPlusCallInfo()->InitStackArgumentSize();
     }
 
@@ -3556,14 +3555,16 @@ public:
     {
         LIMITED_METHOD_CONTRACT;
 
-        _ASSERTE(IMD_HasComPlusCallInfo());
-        SIZE_T size = s_ClassificationSizeTable[m_wFlags & (mdcClassification | mdcHasNonVtableSlot | mdcMethodImpl)];
+        _ASSERTE(IsGenericComPlusCall());
+        SIZE_T size = s_ClassificationSizeTable[m_wFlags & (mdcClassification | mdcHasNonVtableSlot | mdcMethodImpl | mdcHasNativeCodeSlot)];
 
+#ifdef FEATURE_PREJIT
         if (HasNativeCodeSlot())
         {
-            size += (*dac_cast<PTR_TADDR>(dac_cast<TADDR>(this) + size) & FIXUP_LIST_MASK) ?
-                (sizeof(NativeCodeSlot) + sizeof(FixupListSlot)) : sizeof(NativeCodeSlot);
+            size += (*dac_cast<PTR_TADDR>(GetAddrOfNativeCodeSlot()) & FIXUP_LIST_MASK) ? 
+                sizeof(FixupListSlot) : 0;
         }
+#endif
 
         return dac_cast<PTR_ComPlusCallInfo>(dac_cast<TADDR>(this) + size);
     }
index d0d944d..1175d2b 100644 (file)
@@ -133,11 +133,14 @@ inline BOOL MethodDesc::IsQCall()
 FORCEINLINE DWORD MethodDesc::IsGenericComPlusCall()
 {
     LIMITED_METHOD_CONTRACT;
-    return (mcInstantiated == GetClassification() && AsInstantiatedMethodDesc()->IMD_HasComPlusCallInfo());
+    return m_wFlags & mdcHasComPlusCallInfo;
 }
+
 inline void MethodDesc::SetupGenericComPlusCall()
 {
     LIMITED_METHOD_CONTRACT;
+    m_wFlags |= mdcHasComPlusCallInfo;
+
     AsInstantiatedMethodDesc()->IMD_SetupGenericComPlusCall();
 }
 #endif // FEATURE_COMINTEROP
index 2197632..82a4b50 100644 (file)
@@ -2410,6 +2410,7 @@ MethodTableBuilder::EnumerateMethodImpls()
 
                         compatibleSignatures = TRUE;
                         bmtMetaData->rgMethodImplTokens[i].fRequiresCovariantReturnTypeChecking = true;
+                        bmtMetaData->fHasCovariantOverride = true;
                     }
                 }
 
@@ -5589,6 +5590,19 @@ MethodTableBuilder::ProcessMethodImpls()
 {
     STANDARD_VM_CONTRACT;
 
+    if (bmtMetaData->fHasCovariantOverride)
+    {
+        GetHalfBakedClass()->SetHasCovariantOverride();
+    }
+    if (GetParentMethodTable() != NULL)
+    {
+        EEClass* parentClass = GetParentMethodTable()->GetClass();
+        if (parentClass->HasCovariantOverride())
+            GetHalfBakedClass()->SetHasCovariantOverride();
+        if (parentClass->HasVTableMethodImpl())
+            GetHalfBakedClass()->SetHasVTableMethodImpl();
+    }
+
     if (bmtMethod->dwNumberMethodImpls == 0)
         return;
 
@@ -5680,6 +5694,7 @@ MethodTableBuilder::ProcessMethodImpls()
                         }
 
                         Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
+                        
                         MethodTable * pDeclMT = NULL;
                         MethodSignature declSig(GetModule(), szName, pSig, cbSig, NULL);
 
@@ -5784,6 +5799,7 @@ MethodTableBuilder::ProcessMethodImpls()
                             }
                             else
                             {
+                                GetHalfBakedClass()->SetHasVTableMethodImpl();
                                 declMethod = FindDeclMethodOnClassInHierarchy(it, pDeclMT, declSig);
                             }
 
index 34a040c..def6ab9 100644 (file)
@@ -2006,6 +2006,8 @@ private:
         MethodImplTokenPair *rgMethodImplTokens;
         Substitution *pMethodDeclSubsts;    // Used to interpret generic variables in the interface of the declaring type
 
+        bool fHasCovariantOverride;
+
         //-----------------------------------------------------------------------------------------
         inline bmtMetaDataInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); }
     };  // struct bmtMetaDataInfo
@@ -2282,10 +2284,11 @@ private:
     class DeclaredMethodIterator
     {
       private:
-        MethodTableBuilder &m_mtb;
-        int                 m_idx; // not SLOT_INDEX?
+        const int            m_numDeclaredMethods;
+        bmtMDMethod ** const m_declaredMethods;
+        int                  m_idx; // not SLOT_INDEX?
 #ifdef _DEBUG
-        bmtMDMethod *       m_debug_pMethod;
+        bmtMDMethod *        m_debug_pMethod;
 #endif
 
       public:
index 2d13e78..78424be 100644 (file)
 
 //***************************************************************************************
 inline MethodTableBuilder::DeclaredMethodIterator::DeclaredMethodIterator(
-            MethodTableBuilder &mtb) : m_mtb(mtb), m_idx(-1)
+            MethodTableBuilder &mtb) : 
+                m_numDeclaredMethods((int)mtb.NumDeclaredMethods()),
+                m_declaredMethods(mtb.bmtMethod->m_rgDeclaredMethods),
+                m_idx(-1)
 {
     LIMITED_METHOD_CONTRACT;
 }
@@ -24,7 +27,7 @@ inline MethodTableBuilder::DeclaredMethodIterator::DeclaredMethodIterator(
 inline int MethodTableBuilder::DeclaredMethodIterator::CurrentIndex()
 {
     LIMITED_METHOD_CONTRACT;
-    CONSISTENCY_CHECK_MSG(0 <= m_idx && m_idx < (int)m_mtb.NumDeclaredMethods(),
+    CONSISTENCY_CHECK_MSG(0 <= m_idx && m_idx < m_numDeclaredMethods,
                           "Invalid iterator state.");
     return m_idx;
 }
@@ -33,7 +36,7 @@ inline int MethodTableBuilder::DeclaredMethodIterator::CurrentIndex()
 inline BOOL MethodTableBuilder::DeclaredMethodIterator::Next()
 {
     LIMITED_METHOD_CONTRACT;
-    if (m_idx + 1 >= (int)m_mtb.NumDeclaredMethods())
+    if (m_idx + 1 >= m_numDeclaredMethods)
         return FALSE;
     m_idx++;
     INDEBUG(m_debug_pMethod = GetMDMethod();)
@@ -55,7 +58,7 @@ inline BOOL MethodTableBuilder::DeclaredMethodIterator::Prev()
 inline void MethodTableBuilder::DeclaredMethodIterator::ResetToEnd()
 {
     LIMITED_METHOD_CONTRACT;
-    m_idx = (int)m_mtb.NumDeclaredMethods();
+    m_idx = m_numDeclaredMethods;
 }
 
 //***************************************************************************************
@@ -130,7 +133,7 @@ MethodTableBuilder::DeclaredMethodIterator::GetMDMethod() const
 {
     LIMITED_METHOD_CONTRACT;
     _ASSERTE(FitsIn<SLOT_INDEX>(m_idx)); // Review: m_idx should probably _be_ a SLOT_INDEX, but that asserts.
-    return (*m_mtb.bmtMethod)[static_cast<SLOT_INDEX>(m_idx)];
+    return m_declaredMethods[m_idx];
 }
 
 //*******************************************************************************
index ba2906f..61bbbb8 100644 (file)
@@ -1288,7 +1288,7 @@ TypeHandle SigPointer::GetTypeHandleThrowing(
                 pGenericTypeModule = pModule;
             }
 
-            TypeHandle genericType = psig.GetGenericInstType(pModule, fLoadTypes, level, pZapSigContext);
+            TypeHandle genericType = psig.GetGenericInstType(pModule, fLoadTypes, level < CLASS_LOAD_APPROXPARENTS ? level : CLASS_LOAD_APPROXPARENTS, pZapSigContext);
 
             if (genericType.IsNull())
             {