1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // File: METHODTABLEBUILDER.CPP
12 // ============================================================================
16 #include "methodtablebuilder.h"
18 #include "sigbuilder.h"
19 #include "dllimport.h"
20 #include "fieldmarshaler.h"
22 #include "mdaassistants.h"
24 #include "customattribute.h"
25 #include "typestring.h"
27 //*******************************************************************************
28 // Helper functions to sort GCdescs by offset (decending order)
29 int __cdecl compareCGCDescSeries(const void *arg1, const void *arg2)
31 STATIC_CONTRACT_NOTHROW;
32 STATIC_CONTRACT_GC_NOTRIGGER;
33 STATIC_CONTRACT_FORBID_FAULT;
35 CGCDescSeries* gcInfo1 = (CGCDescSeries*) arg1;
36 CGCDescSeries* gcInfo2 = (CGCDescSeries*) arg2;
38 return (int)(gcInfo2->GetSeriesOffset() - gcInfo1->GetSeriesOffset());
41 //*******************************************************************************
43 const char* FormatSig(MethodDesc* pMD, LoaderHeap *pHeap, AllocMemTracker *pamTracker);
46 unsigned g_dupMethods = 0;
49 //==========================================================================
50 // This function is very specific about how it constructs a EEClass. It first
51 // determines the necessary size of the vtable and the number of statics that
52 // this class requires. The necessary memory is then allocated for a EEClass
53 // and its vtable and statics. The class members are then initialized and
54 // the memory is then returned to the caller
56 // LPEEClass CreateClass()
59 // [in] scope - scope of the current class not the one requested to be opened
60 // [in] cl - class token of the class to be created.
61 // [out] ppEEClass - pointer to pointer to hold the address of the EEClass
62 // allocated in this function.
63 // Return : returns an HRESULT indicating the success of this function.
65 // This parameter has been removed but might need to be reinstated if the
66 // global for the metadata loader is removed.
67 // [in] pIMLoad - MetaDataLoader class/object for the current scope.
70 //==========================================================================
72 MethodTableBuilder::CreateClass( Module *pModule,
77 const MethodTableBuilder::bmtGenericsInfo *bmtGenericsInfo,
78 LoaderAllocator * pAllocator,
79 AllocMemTracker *pamTracker)
84 PRECONDITION(!(fHasLayout && fDelegate));
85 PRECONDITION(!(fHasLayout && fIsEnum));
86 PRECONDITION(CheckPointer(bmtGenericsInfo));
90 EEClass *pEEClass = NULL;
91 IMDInternalImport *pInternalImport;
93 //<TODO>============================================================================
94 // vtabsize and static size need to be converted from pointer sizes to #'s
95 // of bytes this will be very important for 64 bit NT!
96 // We will need to call on IMetaDataLoad to get these sizes and fill out the
99 // From the classref call on metadata to resolve the classref and check scope
100 // to make sure that this class is in the same scope otherwise we need to open
101 // a new scope and possibly file.
103 // if the scopes are different call the code to load a new file and get the new scope
105 // scopes are the same so we can use the existing scope to get the class info
107 // This method needs to be fleshed out.more it currently just returns enough
108 // space for the defined EEClass and the vtable and statics are not set.
109 //=============================================================================</TODO>
113 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) LayoutEEClass();
117 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) DelegateEEClass();
121 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) EEClass(sizeof(EEClass));
124 DWORD dwAttrClass = 0;
125 mdToken tkExtends = mdTokenNil;
127 // Set up variance info
128 if (bmtGenericsInfo->pVarianceInfo)
130 // Variance info is an optional field on EEClass, so ensure the optional field descriptor has been
132 EnsureOptionalFieldsAreAllocated(pEEClass, pamTracker, pAllocator->GetLowFrequencyHeap());
133 pEEClass->SetVarianceInfo((BYTE*) pamTracker->Track(
134 pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(bmtGenericsInfo->GetNumGenericArgs()))));
136 memcpy(pEEClass->GetVarianceInfo(), bmtGenericsInfo->pVarianceInfo, bmtGenericsInfo->GetNumGenericArgs());
139 pInternalImport = pModule->GetMDImport();
141 if (pInternalImport == NULL)
142 COMPlusThrowHR(COR_E_TYPELOAD);
144 IfFailThrow(pInternalImport->GetTypeDefProps(
149 pEEClass->m_dwAttrClass = dwAttrClass;
151 // MDVal check: can't be both tdSequentialLayout and tdExplicitLayout
152 if((dwAttrClass & tdLayoutMask) == tdLayoutMask)
153 COMPlusThrowHR(COR_E_TYPELOAD);
155 if (IsTdInterface(dwAttrClass))
157 // MDVal check: must have nil tkExtends and must be tdAbstract
158 if((tkExtends & 0x00FFFFFF)||(!IsTdAbstract(dwAttrClass)))
159 COMPlusThrowHR(COR_E_TYPELOAD);
163 pEEClass->SetHasLayout();
165 #ifdef FEATURE_COMINTEROP
166 if (IsTdWindowsRuntime(dwAttrClass))
168 Assembly *pAssembly = pModule->GetAssembly();
170 // On the desktop CLR, we do not allow non-FX assemblies to use/define WindowsRuntimeImport attribute.
172 // On CoreCLR, however, we do allow non-FX assemblies to have this attribute. This enables scenarios where we can
173 // activate 3rd-party WinRT components outside AppContainer - 1st party WinRT components are already allowed
174 // to be activated outside AppContainer (on both Desktop and CoreCLR).
176 pEEClass->SetProjectedFromWinRT();
179 if (pEEClass->IsProjectedFromWinRT())
181 if (IsTdInterface(dwAttrClass))
184 // Check for GuidAttribute
186 BOOL bHasGuid = FALSE;
189 HRESULT hr = pModule->GetMDImport()->GetItemGuid(cl, &guid);
192 if (IsEqualGUID(guid, GUID_NULL))
194 // A WinRT interface should have a GUID
195 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), cl, IDS_EE_WINRT_INTERFACE_WITHOUT_GUID);
200 WinMDAdapter::RedirectedTypeIndex redirectedTypeIndex;
201 redirectedTypeIndex = WinRTTypeNameConverter::GetRedirectedTypeIndexByName(pModule, cl);
202 if (redirectedTypeIndex != WinMDAdapter::RedirectedTypeIndex_Invalid)
204 EnsureOptionalFieldsAreAllocated(pEEClass, pamTracker, pAllocator->GetLowFrequencyHeap());
205 pEEClass->SetWinRTRedirectedTypeIndex(redirectedTypeIndex);
207 #endif // FEAUTRE_COMINTEROP
210 pModule->GetClassLoader()->m_dwDebugClasses++;
216 //*******************************************************************************
218 // Create a hash of all methods in this class. The hash is from method name to MethodDesc.
220 MethodTableBuilder::MethodNameHash *
221 MethodTableBuilder::CreateMethodChainHash(
224 STANDARD_VM_CONTRACT;
226 MethodNameHash *pHash = new (GetStackingAllocator()) MethodNameHash();
227 pHash->Init(pMT->GetNumVirtuals(), GetStackingAllocator());
229 unsigned numVirtuals = GetParentMethodTable()->GetNumVirtuals();
230 for (unsigned i = 0; i < numVirtuals; ++i)
232 bmtMethodSlot &slot = (*bmtParent->pSlotTable)[i];
233 bmtRTMethod * pMethod = slot.Decl().AsRTMethod();
234 const MethodSignature &sig = pMethod->GetMethodSignature();
235 pHash->Insert(sig.GetName(), pMethod);
242 //*******************************************************************************
244 // Find a method in this class hierarchy - used ONLY by the loader during layout. Do not use at runtime.
246 // *ppMemberSignature must be NULL on entry - it and *pcMemberSignature may or may not be filled out
248 // ppMethodDesc will be filled out with NULL if no matching method in the hierarchy is found.
250 // Returns FALSE if there was an error of some kind.
252 // pMethodConstraintsMatch receives the result of comparing the method constraints.
253 MethodTableBuilder::bmtRTMethod *
254 MethodTableBuilder::LoaderFindMethodInParentClass(
255 const MethodSignature & methodSig,
256 BOOL * pMethodConstraintsMatch)
261 PRECONDITION(CheckPointer(this));
262 PRECONDITION(CheckPointer(bmtParent));
263 PRECONDITION(CheckPointer(methodSig.GetModule()));
264 PRECONDITION(CheckPointer(methodSig.GetSignature()));
265 PRECONDITION(HasParent());
266 PRECONDITION(methodSig.GetSignatureLength() != 0);
271 MethodNameHash::HashEntry * pEntry;
273 // Have we created a hash of all the methods in the class chain?
274 if (bmtParent->pParentMethodHash == NULL)
276 // There may be such a method, so we will now create a hash table to reduce the pain for
279 // <TODO> Are we really sure that this is worth doing? </TODO>
280 bmtParent->pParentMethodHash = CreateMethodChainHash(GetParentMethodTable());
283 // We have a hash table, so use it
284 pEntry = bmtParent->pParentMethodHash->Lookup(methodSig.GetName());
286 // Traverse the chain of all methods with this name
287 while (pEntry != NULL)
289 bmtRTMethod * pEntryMethod = pEntry->m_data;
290 const MethodSignature & entrySig = pEntryMethod->GetMethodSignature();
292 // Note instantiation info
294 if (methodSig.Equivalent(entrySig))
296 if (pMethodConstraintsMatch != NULL)
298 // Check the constraints are consistent,
299 // and return the result to the caller.
300 // We do this here to avoid recalculating pSubst.
301 *pMethodConstraintsMatch = MetaSig::CompareMethodConstraints(
302 &methodSig.GetSubstitution(), methodSig.GetModule(), methodSig.GetToken(),
303 &entrySig.GetSubstitution(), entrySig.GetModule(), entrySig.GetToken());
310 // Advance to next item in the hash chain which has the same name
311 pEntry = bmtParent->pParentMethodHash->FindNext(pEntry);
315 //@TODO: Move to this code, as the use of a HashTable is broken; overriding semantics
316 //@TODO: require matching against the most-derived slot of a given name and signature,
317 //@TODO: (which deals specifically with newslot methods with identical name and sig), but
318 //@TODO: HashTables are by definition unordered and so we've only been getting by with the
319 //@TODO: implementation being compatible with the order in which methods were added to
320 //@TODO: the HashTable in CreateMethodChainHash.
322 bmtParentInfo::Iterator it(bmtParent->IterateSlots());
323 it.MoveTo(static_cast<size_t>(GetParentMethodTable()->GetNumVirtuals()));
326 bmtMethodHandle decl(it->Decl());
327 const MethodSignature &declSig(decl.GetMethodSignature());
328 if (declSig == methodSig)
330 if (pMethodConstraintsMatch != NULL)
332 // Check the constraints are consistent,
333 // and return the result to the caller.
334 // We do this here to avoid recalculating pSubst.
335 *pMethodConstraintsMatch = MetaSig::CompareMethodConstraints(
336 &methodSig.GetSubstitution(), methodSig.GetModule(), methodSig.GetToken(),
337 &declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken());
340 return decl.AsRTMethod();
348 //*******************************************************************************
350 // Given an interface map to fill out, expand pNewInterface (and its sub-interfaces) into it, increasing
351 // pdwInterfaceListSize as appropriate, and avoiding duplicates.
354 MethodTableBuilder::ExpandApproxInterface(
355 bmtInterfaceInfo * bmtInterface, // out parameter, various parts cumulatively written to.
356 const Substitution * pNewInterfaceSubstChain,
357 MethodTable * pNewInterface,
358 InterfaceDeclarationScope declScope
359 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
361 STANDARD_VM_CONTRACT;
363 //#ExpandingInterfaces
364 // We expand the tree of inherited interfaces into a set by adding the
365 // current node BEFORE expanding the parents of the current node.
366 // ****** This must be consistent with code:ExpandExactInterface *******
367 // ****** This must be consistent with code:ClassCompat::MethodTableBuilder::BuildInteropVTable_ExpandInterface *******
369 // The interface list contains the fully expanded set of interfaces from the parent then
370 // we start adding all the interfaces we declare. We need to know which interfaces
371 // we declare but do not need duplicates of the ones we declare. This means we can
372 // duplicate our parent entries.
374 // Is it already present in the list?
375 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
377 bmtInterfaceEntry * pItfEntry = &bmtInterface->pInterfaceMap[i];
378 bmtRTType * pItfType = pItfEntry->GetInterfaceType();
380 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
381 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
382 if (MetaSig::CompareTypeDefsUnderSubstitutions(pItfType->GetMethodTable(),
384 &pItfType->GetSubstitution(),
385 pNewInterfaceSubstChain,
388 if (declScope.fIsInterfaceDeclaredOnType)
390 pItfEntry->IsDeclaredOnType() = true;
393 //#InjectInterfaceDuplicates_ApproxInterfaces
394 // We can inject duplicate interfaces in check builds.
395 // Has to be in sync with code:#InjectInterfaceDuplicates_Main
396 if (((dbg_pClassMT == NULL) && bmtInterface->dbg_fShouldInjectInterfaceDuplicates) ||
397 ((dbg_pClassMT != NULL) && dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates()))
399 // The injected duplicate interface should have the same status 'ImplementedByParent' as
400 // the original interface (can be false if the interface is implemented indirectly twice)
401 declScope.fIsInterfaceDeclaredOnParent = pItfEntry->IsImplementedByParent();
402 // Just pretend we didn't find this match, but mark all duplicates as 'DeclaredOnType' if
407 return; // found it, don't add it again
411 bmtRTType * pNewItfType =
412 new (GetStackingAllocator()) bmtRTType(*pNewInterfaceSubstChain, pNewInterface);
414 if (bmtInterface->dwInterfaceMapSize >= bmtInterface->dwInterfaceMapAllocated)
417 // Grow the array of interfaces
419 S_UINT32 dwNewAllocated = S_UINT32(2) * S_UINT32(bmtInterface->dwInterfaceMapAllocated) + S_UINT32(5);
421 if (dwNewAllocated.IsOverflow())
423 BuildMethodTableThrowException(COR_E_OVERFLOW);
426 S_SIZE_T safeSize = S_SIZE_T(sizeof(bmtInterfaceEntry)) *
427 S_SIZE_T(dwNewAllocated.Value());
429 if (safeSize.IsOverflow())
431 BuildMethodTableThrowException(COR_E_OVERFLOW);
434 bmtInterfaceEntry * pNewMap = (bmtInterfaceEntry *)new (GetStackingAllocator()) BYTE[safeSize.Value()];
435 memcpy(pNewMap, bmtInterface->pInterfaceMap, sizeof(bmtInterfaceEntry) * bmtInterface->dwInterfaceMapAllocated);
437 bmtInterface->pInterfaceMap = pNewMap;
438 bmtInterface->dwInterfaceMapAllocated = dwNewAllocated.Value();
441 // The interface map memory was just allocated as an array of bytes, so we use
442 // in place new to init the new map entry. No need to do anything with the result,
444 CONSISTENCY_CHECK(bmtInterface->dwInterfaceMapSize < bmtInterface->dwInterfaceMapAllocated);
445 new ((void *)&bmtInterface->pInterfaceMap[bmtInterface->dwInterfaceMapSize])
446 bmtInterfaceEntry(pNewItfType, declScope);
448 bmtInterface->dwInterfaceMapSize++;
450 // Make sure to pass in the substitution from the new itf type created above as
451 // these methods assume that substitutions are allocated in the stacking heap,
453 InterfaceDeclarationScope declaredItfScope(declScope.fIsInterfaceDeclaredOnParent, false);
454 ExpandApproxDeclaredInterfaces(
456 bmtTypeHandle(pNewItfType),
458 COMMA_INDEBUG(dbg_pClassMT));
459 } // MethodTableBuilder::ExpandApproxInterface
461 //*******************************************************************************
463 // dbg_pClassMT - Class on which the interfaces are declared (either explicitly or implicitly).
464 // It will never be an interface. It may be NULL (if it is the type being built).
466 MethodTableBuilder::ExpandApproxDeclaredInterfaces(
467 bmtInterfaceInfo * bmtInterface, // out parameter, various parts cumulatively written to.
468 bmtTypeHandle thType,
469 InterfaceDeclarationScope declScope
470 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
472 STANDARD_VM_CONTRACT;
474 _ASSERTE((dbg_pClassMT == NULL) || !dbg_pClassMT->IsInterface());
477 // Iterate the list of interfaces declared by thType and add them to the map.
478 InterfaceImplEnum ie(thType.GetModule(), thType.GetTypeDefToken(), &thType.GetSubstitution());
479 while ((hr = ie.Next()) == S_OK)
481 MethodTable *pGenericIntf = ClassLoader::LoadApproxTypeThrowing(
482 thType.GetModule(), ie.CurrentToken(), NULL, NULL).GetMethodTable();
483 CONSISTENCY_CHECK(pGenericIntf->IsInterface());
485 ExpandApproxInterface(bmtInterface,
489 COMMA_INDEBUG(dbg_pClassMT));
493 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
495 } // MethodTableBuilder::ExpandApproxDeclaredInterfaces
497 //*******************************************************************************
499 MethodTableBuilder::ExpandApproxInheritedInterfaces(
500 bmtInterfaceInfo * bmtInterface,
501 bmtRTType * pParentType)
503 STANDARD_VM_CONTRACT;
505 // Expand interfaces in superclasses first. Interfaces inherited from parents
506 // must have identical indexes as in the parent.
507 bmtRTType * pParentOfParent = pParentType->GetParentType();
509 //#InterfaceMap_SupersetOfParent
510 // We have to load parent's interface map the same way the parent did it (as open type).
511 // Further code depends on this:
512 // code:#InterfaceMap_UseParentInterfaceImplementations
513 // We check that it is truth:
514 // code:#ApproxInterfaceMap_SupersetOfParent
515 // code:#ExactInterfaceMap_SupersetOfParent
517 //#InterfaceMap_CanonicalSupersetOfParent
518 // Note that canonical instantiation of parent can have different interface instantiations in the
519 // interface map than derived type:
520 // class MyClass<T> : MyBase<string, T>, I<T>
521 // class MyBase<U, V> : I<U>
522 // Type MyClass<_Canon> has MyBase<_Canon,_Canon> as parent. The interface maps are:
523 // MyBase<_Canon,_Canon> ... I<_Canon>
524 // MyClass<_Canon> ... I<string> (#1)
526 // The I's instantiation I<string> (#1) in MyClass and I<_Canon> from MyBase are not the same
529 // Backup parent substitution
530 Substitution parentSubstitution = pParentType->GetSubstitution();
531 // Make parent an open type
532 pParentType->SetSubstitution(Substitution());
534 if (pParentOfParent != NULL)
536 ExpandApproxInheritedInterfaces(bmtInterface, pParentOfParent);
539 InterfaceDeclarationScope declScope(true, false);
540 ExpandApproxDeclaredInterfaces(
542 bmtTypeHandle(pParentType),
544 COMMA_INDEBUG(pParentType->GetMethodTable()));
546 // Make sure we loaded the same number of interfaces as the parent type itself
547 CONSISTENCY_CHECK(pParentType->GetMethodTable()->GetNumInterfaces() == bmtInterface->dwInterfaceMapSize);
549 // Restore parent's substitution
550 pParentType->SetSubstitution(parentSubstitution);
551 } // MethodTableBuilder::ExpandApproxInheritedInterfaces
553 //*******************************************************************************
554 // Fill out a fully expanded interface map, such that if we are declared to
555 // implement I3, and I3 extends I1,I2, then I1,I2 are added to our list if
556 // they are not already present.
558 MethodTableBuilder::LoadApproxInterfaceMap()
560 STANDARD_VM_CONTRACT;
562 bmtInterface->dwInterfaceMapSize = 0;
565 //#InjectInterfaceDuplicates_Main
566 // We will inject duplicate interfaces in check builds if env. var.
567 // COMPLUS_INTERNAL_TypeLoader_InjectInterfaceDuplicates is set to TRUE for all types (incl. non-generic
569 // This should allow us better test coverage of duplicates in interface map.
571 // The duplicates are legal for some types:
573 // B<U,V> : A<U>, I<V>
575 // where the interface maps are:
576 // A<T> ... 1 item: I<T>
577 // A<int> ... 1 item: I<int>
578 // B<U,V> ... 2 items: I<U>, I<V>
579 // B<int,int> ... 2 items: I<int>, I<int>
580 // B<_Canon,_Canon> ... 2 items: I<_Canon>, I<_Canon>
581 // B<string,string> ... 2 items: I<string>, I<string>
582 // C ... 2 items: I<int>, I<int>
583 // Note: C had only 1 item (I<int>) in CLR 2.0 RTM/SP1/SP2 and early in CLR 4.0.
585 // We will create duplicate from every re-implemented interface (incl. non-generic):
586 // code:#InjectInterfaceDuplicates_ApproxInterfaces
587 // code:#InjectInterfaceDuplicates_LoadExactInterfaceMap
588 // code:#InjectInterfaceDuplicates_ExactInterfaces
590 // Note that we don't have to do anything for COM, because COM has its own interface map
591 // (code:InteropMethodTableData)which is independent on type's interface map and is created only from
592 // non-generic interfaces (see code:ClassCompat::MethodTableBuilder::BuildInteropVTable_InterfaceList)
594 // We need to keep track which interface duplicates were injected. Right now its either all interfaces
595 // (declared on the type being built, not inheritted) or none. In the future we could inject duplicates
596 // just for some of them.
597 bmtInterface->dbg_fShouldInjectInterfaceDuplicates =
598 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TypeLoader_InjectInterfaceDuplicates) != 0);
599 if (bmtGenerics->Debug_GetTypicalMethodTable() != NULL)
600 { // It's safer to require that all instantiations have the same injected interface duplicates.
601 // In future we could inject different duplicates for various non-shared instantiations.
603 // Use the same injection status as typical instantiation
604 bmtInterface->dbg_fShouldInjectInterfaceDuplicates =
605 bmtGenerics->Debug_GetTypicalMethodTable()->Debug_HasInjectedInterfaceDuplicates();
607 if (GetModule() == g_pObjectClass->GetModule())
608 { // mscorlib has some weird hardcoded information about interfaces (e.g.
609 // code:CEEPreloader::ApplyTypeDependencyForSZArrayHelper), so we don't inject duplicates into
611 bmtInterface->dbg_fShouldInjectInterfaceDuplicates = FALSE;
616 // First inherit all the parent's interfaces. This is important, because our interface map must
617 // list the interfaces in identical order to our parent.
619 // <NICE> we should document the reasons why. One reason is that DispatchMapTypeIDs can be indexes
620 // into the list </NICE>
623 ExpandApproxInheritedInterfaces(bmtInterface, GetParentType());
625 //#ApproxInterfaceMap_SupersetOfParent
626 // Check that parent's interface map is the same as what we just computed
627 // See code:#InterfaceMap_SupersetOfParent
629 MethodTable * pParentMT = GetParentMethodTable();
630 _ASSERTE(pParentMT->GetNumInterfaces() == bmtInterface->dwInterfaceMapSize);
632 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
633 UINT32 nInterfaceIndex = 0;
634 while (parentInterfacesIterator.Next())
636 // Compare TypeDefs of the parent's interface and this interface (full MT comparison is in
637 // code:#ExactInterfaceMap_SupersetOfParent)
638 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
639 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
640 bmtInterface->pInterfaceMap[nInterfaceIndex].GetInterfaceType()->GetMethodTable()));
643 _ASSERTE(nInterfaceIndex == bmtInterface->dwInterfaceMapSize);
648 // Now add in any freshly declared interfaces, possibly augmenting the flags
649 InterfaceDeclarationScope declScope(false, true);
650 ExpandApproxDeclaredInterfaces(
654 COMMA_INDEBUG(NULL));
655 } // MethodTableBuilder::LoadApproxInterfaceMap
657 //*******************************************************************************
658 // Fills array of TypeIDs with all duplicate occurences of pDeclIntfMT in the interface map.
661 // rg/c DispatchMapTypeIDs - Array of TypeIDs and its count of elements.
662 // pcIfaceDuplicates - Number of duplicate occurences of the interface in the interface map (ideally <=
663 // count of elements TypeIDs.
665 // Note: If the passed rgDispatchMapTypeIDs array is smaller than the number of duplicates, fills it
666 // with the duplicates that fit and returns number of all existing duplicates (not just those fileld in the
667 // array) in pcIfaceDuplicates.
670 MethodTableBuilder::ComputeDispatchMapTypeIDs(
671 MethodTable * pDeclInftMT,
672 const Substitution * pDeclIntfSubst,
673 DispatchMapTypeID * rgDispatchMapTypeIDs,
674 UINT32 cDispatchMapTypeIDs,
675 UINT32 * pcIfaceDuplicates)
677 STANDARD_VM_CONTRACT;
679 _ASSERTE(pDeclInftMT->IsInterface());
681 // Count of interface duplicates (also used as index into TypeIDs array)
682 *pcIfaceDuplicates = 0;
683 for (DWORD idx = 0; idx < bmtInterface->dwInterfaceMapSize; idx++)
685 bmtInterfaceEntry * pItfEntry = &bmtInterface->pInterfaceMap[idx];
686 bmtRTType * pItfType = pItfEntry->GetInterfaceType();
687 // Type Equivalence is forbidden in interface type ids.
688 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
689 if (MetaSig::CompareTypeDefsUnderSubstitutions(pItfType->GetMethodTable(),
691 &pItfType->GetSubstitution(),
694 { // We found another occurence of this interface
695 // Can we fit it into the TypeID array?
696 if (*pcIfaceDuplicates < cDispatchMapTypeIDs)
698 rgDispatchMapTypeIDs[*pcIfaceDuplicates] = DispatchMapTypeID::InterfaceClassID(idx);
700 // Increase number of duplicate interfaces
701 (*pcIfaceDuplicates)++;
704 } // MethodTableBuilder::ComputeDispatchMapTypeIDs
706 //*******************************************************************************
708 VOID DECLSPEC_NORETURN
709 MethodTableBuilder::BuildMethodTableThrowException(
711 const bmtErrorInfo & bmtError)
717 INJECT_FAULT(COMPlusThrowOM(););
721 LPCUTF8 pszClassName, pszNameSpace;
722 if (FAILED(bmtError.pModule->GetMDImport()->GetNameOfTypeDef(bmtError.cl, &pszClassName, &pszNameSpace)))
724 pszClassName = pszNameSpace = "Invalid TypeDef record";
727 if (IsNilToken(bmtError.dMethodDefInError) && (bmtError.szMethodNameForError == NULL))
729 if (hr == E_OUTOFMEMORY)
734 bmtError.pModule->GetAssembly()->ThrowTypeLoadException(
735 pszNameSpace, pszClassName, bmtError.resIDWhy);
739 LPCUTF8 szMethodName;
740 if (bmtError.szMethodNameForError == NULL)
742 if (FAILED((bmtError.pModule->GetMDImport())->GetNameOfMethodDef(bmtError.dMethodDefInError, &szMethodName)))
744 szMethodName = "Invalid MethodDef record";
749 szMethodName = bmtError.szMethodNameForError;
752 bmtError.pModule->GetAssembly()->ThrowTypeLoadException(
753 pszNameSpace, pszClassName, szMethodName, bmtError.resIDWhy);
755 } // MethodTableBuilder::BuildMethodTableThrowException
757 //*******************************************************************************
758 void MethodTableBuilder::SetBMTData(
759 LoaderAllocator *bmtAllocator,
760 bmtErrorInfo *bmtError,
761 bmtProperties *bmtProp,
763 bmtParentInfo *bmtParent,
764 bmtInterfaceInfo *bmtInterface,
765 bmtMetaDataInfo *bmtMetaData,
766 bmtMethodInfo *bmtMethod,
767 bmtMethAndFieldDescs *bmtMFDescs,
768 bmtFieldPlacement *bmtFP,
769 bmtInternalInfo *bmtInternal,
770 bmtGCSeriesInfo *bmtGCSeries,
771 bmtMethodImplInfo *bmtMethodImpl,
772 const bmtGenericsInfo *bmtGenerics,
773 bmtEnumFieldInfo *bmtEnumFields)
775 LIMITED_METHOD_CONTRACT;
776 this->bmtAllocator = bmtAllocator;
777 this->bmtError = bmtError;
778 this->bmtProp = bmtProp;
780 this->bmtParent = bmtParent;
781 this->bmtInterface = bmtInterface;
782 this->bmtMetaData = bmtMetaData;
783 this->bmtMethod = bmtMethod;
784 this->bmtMFDescs = bmtMFDescs;
786 this->bmtInternal = bmtInternal;
787 this->bmtGCSeries = bmtGCSeries;
788 this->bmtMethodImpl = bmtMethodImpl;
789 this->bmtGenerics = bmtGenerics;
790 this->bmtEnumFields = bmtEnumFields;
793 //*******************************************************************************
794 // Used by MethodTableBuilder
796 MethodTableBuilder::bmtRTType *
797 MethodTableBuilder::CreateTypeChain(
799 const Substitution & subst)
805 PRECONDITION(CheckPointer(GetStackingAllocator()));
806 PRECONDITION(CheckPointer(pMT));
809 pMT = pMT->GetCanonicalMethodTable();
811 bmtRTType * pType = new (GetStackingAllocator())
812 bmtRTType(subst, pMT);
814 MethodTable * pMTParent = pMT->GetParentMethodTable();
815 if (pMTParent != NULL)
817 pType->SetParentType(
820 pMT->GetSubstitutionForParent(&pType->GetSubstitution())));
826 //*******************************************************************************
828 MethodTableBuilder::bmtRTType *
829 MethodTableBuilder::bmtRTType::FindType(
831 MethodTable * pTargetMT)
835 PRECONDITION(CheckPointer(pType));
836 PRECONDITION(CheckPointer(pTargetMT));
839 pTargetMT = pTargetMT->GetCanonicalMethodTable();
840 while (pType != NULL &&
841 pType->GetMethodTable()->GetCanonicalMethodTable() != pTargetMT)
843 pType = pType->GetParentType();
849 //*******************************************************************************
851 MethodTableBuilder::bmtRTType::GetEnclosingTypeToken() const
853 STANDARD_VM_CONTRACT;
855 mdTypeDef tok = mdTypeDefNil;
858 { // This is guaranteed to succeed because the EEClass would not have been
859 // set as nested unless a valid token was stored in metadata.
860 if (FAILED(GetModule()->GetMDImport()->GetNestedClassProps(
861 GetTypeDefToken(), &tok)))
870 //*******************************************************************************
872 MethodTableBuilder::MethodSignature::NamesEqual(
873 const MethodSignature & sig1,
874 const MethodSignature & sig2)
876 STANDARD_VM_CONTRACT;
878 if (sig1.GetNameHash() != sig2.GetNameHash())
883 if (strcmp(sig1.GetName(), sig2.GetName()) != 0)
891 //*******************************************************************************
893 MethodTableBuilder::MethodSignature::SignaturesEquivalent(
894 const MethodSignature & sig1,
895 const MethodSignature & sig2)
897 STANDARD_VM_CONTRACT;
899 return !!MetaSig::CompareMethodSigs(
900 sig1.GetSignature(), static_cast<DWORD>(sig1.GetSignatureLength()), sig1.GetModule(), &sig1.GetSubstitution(),
901 sig2.GetSignature(), static_cast<DWORD>(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution());
904 //*******************************************************************************
906 MethodTableBuilder::MethodSignature::SignaturesExactlyEqual(
907 const MethodSignature & sig1,
908 const MethodSignature & sig2)
910 STANDARD_VM_CONTRACT;
912 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
913 return !!MetaSig::CompareMethodSigs(
914 sig1.GetSignature(), static_cast<DWORD>(sig1.GetSignatureLength()), sig1.GetModule(), &sig1.GetSubstitution(),
915 sig2.GetSignature(), static_cast<DWORD>(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution(),
919 //*******************************************************************************
921 MethodTableBuilder::MethodSignature::Equivalent(
922 const MethodSignature &rhs) const
924 STANDARD_VM_CONTRACT;
926 return NamesEqual(*this, rhs) && SignaturesEquivalent(*this, rhs);
929 //*******************************************************************************
931 MethodTableBuilder::MethodSignature::ExactlyEqual(
932 const MethodSignature &rhs) const
934 STANDARD_VM_CONTRACT;
936 return NamesEqual(*this, rhs) && SignaturesExactlyEqual(*this, rhs);
939 //*******************************************************************************
941 MethodTableBuilder::MethodSignature::GetMethodAttributes() const
943 STANDARD_VM_CONTRACT;
945 IMDInternalImport * pIMD = GetModule()->GetMDImport();
946 if (TypeFromToken(GetToken()) == mdtMethodDef)
949 if (FAILED(pIMD->GetNameAndSigOfMethodDef(GetToken(), &m_pSig, &cSig, &m_szName)))
950 { // We have empty name or signature on error, do nothing
952 m_cSig = static_cast<size_t>(cSig);
956 CONSISTENCY_CHECK(TypeFromToken(m_tok) == mdtMemberRef);
958 if (FAILED(pIMD->GetNameAndSigOfMemberRef(GetToken(), &m_pSig, &cSig, &m_szName)))
959 { // We have empty name or signature on error, do nothing
961 m_cSig = static_cast<size_t>(cSig);
965 //*******************************************************************************
967 MethodTableBuilder::MethodSignature::GetNameHash() const
969 STANDARD_VM_CONTRACT;
971 CheckGetMethodAttributes();
973 if (m_nameHash == INVALID_NAME_HASH)
975 ULONG nameHash = HashStringA(GetName());
976 if (nameHash == INVALID_NAME_HASH)
980 m_nameHash = nameHash;
986 //*******************************************************************************
987 MethodTableBuilder::bmtMDType::bmtMDType(
988 bmtRTType * pParentType,
991 const SigTypeContext & sigContext)
992 : m_pParentType(pParentType),
995 m_enclTok(mdTypeDefNil),
996 m_sigContext(sigContext),
1001 STANDARD_VM_CONTRACT;
1003 IfFailThrow(m_pModule->GetMDImport()->GetTypeDefProps(m_tok, &m_dwAttrs, NULL));
1005 HRESULT hr = m_pModule->GetMDImport()->GetNestedClassProps(m_tok, &m_enclTok);
1008 if (hr != CLDB_E_RECORD_NOTFOUND)
1012 // Just in case GetNestedClassProps sets the out param to some other value
1013 m_enclTok = mdTypeDefNil;
1017 //*******************************************************************************
1018 MethodTableBuilder::bmtRTMethod::bmtRTMethod(
1019 bmtRTType * pOwningType,
1021 : m_pOwningType(pOwningType),
1023 m_methodSig(pMD->GetModule(),
1024 pMD->GetMemberDef(),
1025 &pOwningType->GetSubstitution())
1036 //*******************************************************************************
1037 MethodTableBuilder::bmtMDMethod::bmtMDMethod(
1038 bmtMDType * pOwningType,
1044 METHOD_IMPL_TYPE implType)
1045 : m_pOwningType(pOwningType),
1046 m_dwDeclAttrs(dwDeclAttrs),
1047 m_dwImplAttrs(dwImplAttrs),
1050 m_implType(implType),
1051 m_methodSig(pOwningType->GetModule(),
1053 &pOwningType->GetSubstitution()),
1056 m_slotIndex(INVALID_SLOT_INDEX),
1057 m_unboxedSlotIndex(INVALID_SLOT_INDEX)
1067 //*******************************************************************************
1069 MethodTableBuilder::ImportParentMethods()
1071 STANDARD_VM_CONTRACT;
1074 { // If there's no parent, there's no methods to import
1078 SLOT_INDEX numMethods = static_cast<SLOT_INDEX>
1079 (GetParentMethodTable()->GetNumMethods());
1081 bmtParent->pSlotTable = new (GetStackingAllocator())
1082 bmtMethodSlotTable(numMethods, GetStackingAllocator());
1084 MethodTable::MethodIterator it(GetParentMethodTable());
1085 for (;it.IsValid(); it.Next())
1087 MethodDesc * pDeclDesc = NULL;
1088 MethodTable * pDeclMT = NULL;
1089 MethodDesc * pImplDesc = NULL;
1090 MethodTable * pImplMT = NULL;
1094 pDeclDesc = it.GetDeclMethodDesc();
1095 pDeclMT = pDeclDesc->GetMethodTable();
1096 pImplDesc = it.GetMethodDesc();
1097 pImplMT = pImplDesc->GetMethodTable();
1101 pDeclDesc = pImplDesc = it.GetMethodDesc();
1102 pDeclMT = pImplMT = it.GetMethodDesc()->GetMethodTable();
1105 CONSISTENCY_CHECK(CheckPointer(pDeclDesc));
1106 CONSISTENCY_CHECK(CheckPointer(pImplDesc));
1108 // Create and assign to each slot
1109 bmtMethodSlot newSlot;
1110 newSlot.Decl() = new (GetStackingAllocator())
1111 bmtRTMethod(bmtRTType::FindType(GetParentType(), pDeclMT), pDeclDesc);
1112 if (pDeclDesc == pImplDesc)
1114 newSlot.Impl() = newSlot.Decl();
1118 newSlot.Impl() = new (GetStackingAllocator())
1119 bmtRTMethod(bmtRTType::FindType(GetParentType(), pImplMT), pImplDesc);
1122 if (!bmtParent->pSlotTable->AddMethodSlot(newSlot))
1123 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1127 //*******************************************************************************
1129 MethodTableBuilder::CopyParentVtable()
1131 STANDARD_VM_CONTRACT;
1138 for (bmtParentInfo::Iterator it = bmtParent->IterateSlots();
1139 !it.AtEnd() && it.CurrentIndex() < GetParentMethodTable()->GetNumVirtuals();
1142 if (!bmtVT->pSlotTable->AddMethodSlot(*it))
1143 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1144 ++bmtVT->cVirtualSlots;
1145 ++bmtVT->cTotalSlots;
1149 //*******************************************************************************
1150 // Determine if this is the special SIMD type System.Numerics.Vector<T>, whose
1151 // size is determined dynamically based on the hardware and the presence of JIT
1154 // - Update the NumInstanceFieldBytes on the bmtFieldPlacement.
1155 // - Update the m_cbNativeSize and m_cbManagedSize if HasLayout() is true.
1156 // Return a BOOL result to indicate whether the size has been updated.
1158 // Will throw IDS_EE_SIMD_NGEN_DISALLOWED if the type is System.Numerics.Vector`1
1159 // and this is an ngen compilation process.
1161 BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize()
1163 STANDARD_VM_CONTRACT;
1165 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
1166 if (!(GetAssembly()->IsSIMDVectorAssembly() || bmtProp->fIsIntrinsicType))
1169 if (bmtFP->NumInstanceFieldBytes != 16)
1174 if (FAILED(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace)))
1177 if (strcmp(className, "Vector`1") != 0 || strcmp(nameSpace, "System.Numerics") != 0)
1180 if (IsCompilationProcess())
1182 COMPlusThrow(kTypeLoadException, IDS_EE_SIMD_NGEN_DISALLOWED);
1185 #ifndef CROSSGEN_COMPILE
1186 if (!TargetHasAVXSupport())
1189 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
1190 if (jitMgr->LoadJIT())
1192 CORJIT_FLAGS cpuCompileFlags = jitMgr->GetCPUCompileFlags();
1193 if (cpuCompileFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_FEATURE_SIMD))
1195 unsigned intrinsicSIMDVectorLength = jitMgr->m_jit->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags);
1196 if (intrinsicSIMDVectorLength != 0)
1198 bmtFP->NumInstanceFieldBytes = intrinsicSIMDVectorLength;
1201 GetLayoutInfo()->m_cbNativeSize = intrinsicSIMDVectorLength;
1202 GetLayoutInfo()->m_cbManagedSize = intrinsicSIMDVectorLength;
1208 #endif // !CROSSGEN_COMPILE
1209 #endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
1213 //*******************************************************************************
1215 MethodTableBuilder::bmtInterfaceEntry::CreateSlotTable(
1216 StackingAllocator * pStackingAllocator)
1218 STANDARD_VM_CONTRACT;
1220 CONSISTENCY_CHECK(m_pImplTable == NULL);
1222 SLOT_INDEX cSlots = (SLOT_INDEX)GetInterfaceType()->GetMethodTable()->GetNumVirtuals();
1223 bmtInterfaceSlotImpl * pST = new (pStackingAllocator) bmtInterfaceSlotImpl[cSlots];
1225 MethodTable::MethodIterator it(GetInterfaceType()->GetMethodTable());
1226 for (; it.IsValid(); it.Next())
1228 if (!it.IsVirtual())
1233 bmtRTMethod * pCurMethod = new (pStackingAllocator)
1234 bmtRTMethod(GetInterfaceType(), it.GetDeclMethodDesc());
1236 CONSISTENCY_CHECK(m_cImplTable == it.GetSlotNumber());
1237 pST[m_cImplTable++] = bmtInterfaceSlotImpl(pCurMethod, INVALID_SLOT_INDEX);
1244 #pragma warning(push)
1245 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1247 //---------------------------------------------------------------------------------------
1249 // Builds the method table, allocates MethodDesc, handles overloaded members, attempts to compress
1250 // interface storage. All dependent classes must already be resolved!
1253 MethodTableBuilder::BuildMethodTableThrowing(
1254 LoaderAllocator * pAllocator,
1255 Module * pLoaderModule,
1258 BuildingInterfaceInfo_t * pBuildingInterfaceList,
1259 const LayoutRawFieldInfo * pLayoutRawFieldInfos,
1260 MethodTable * pParentMethodTable,
1261 const bmtGenericsInfo * bmtGenericsInfo,
1262 SigPointer parentInst,
1263 WORD cBuildingInterfaceList)
1268 PRECONDITION(CheckPointer(GetHalfBakedClass()));
1269 PRECONDITION(CheckPointer(bmtGenericsInfo));
1273 pModule->EnsureLibraryLoaded();
1275 // The following structs, defined as private members of MethodTableBuilder, contain the necessary local
1276 // parameters needed for BuildMethodTable Look at the struct definitions for a detailed list of all
1277 // parameters available to BuildMethodTableThrowing.
1281 new (GetStackingAllocator()) bmtErrorInfo(),
1282 new (GetStackingAllocator()) bmtProperties(),
1283 new (GetStackingAllocator()) bmtVtable(),
1284 new (GetStackingAllocator()) bmtParentInfo(),
1285 new (GetStackingAllocator()) bmtInterfaceInfo(),
1286 new (GetStackingAllocator()) bmtMetaDataInfo(),
1287 new (GetStackingAllocator()) bmtMethodInfo(),
1288 new (GetStackingAllocator()) bmtMethAndFieldDescs(),
1289 new (GetStackingAllocator()) bmtFieldPlacement(),
1290 new (GetStackingAllocator()) bmtInternalInfo(),
1291 new (GetStackingAllocator()) bmtGCSeriesInfo(),
1292 new (GetStackingAllocator()) bmtMethodImplInfo(),
1294 new (GetStackingAllocator()) bmtEnumFieldInfo(pModule->GetMDImport()));
1296 //Initialize structs
1298 bmtError->resIDWhy = IDS_CLASSLOAD_GENERAL; // Set the reason and the offending method def. If the method information
1299 bmtError->pThrowable = NULL;
1300 bmtError->pModule = pModule;
1303 bmtInternal->pInternalImport = pModule->GetMDImport();
1304 bmtInternal->pModule = pModule;
1306 bmtInternal->pParentMT = pParentMethodTable;
1308 // Create the chain of bmtRTType for the parent types. This allows all imported
1309 // parent methods to be associated with their declaring types, and as such it is
1310 // easy to access the appropriate Substitution when comparing signatures.
1311 bmtRTType * pParent = NULL;
1312 if (pParentMethodTable != NULL)
1314 Substitution * pParentSubst =
1315 new (GetStackingAllocator()) Substitution(pModule, parentInst, NULL);
1316 pParent = CreateTypeChain(pParentMethodTable, *pParentSubst);
1319 // Now create the bmtMDType for the type being built.
1320 bmtInternal->pType = new (GetStackingAllocator())
1321 bmtMDType(pParent, pModule, cl, bmtGenericsInfo->typeContext);
1323 // If not NULL, it means there are some by-value fields, and this contains an entry for each inst
1326 // Set debug class name string for easier debugging.
1329 if (FAILED(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace)))
1331 className = nameSpace = "Invalid TypeDef record";
1335 S_SIZE_T safeLen = S_SIZE_T(sizeof(char))*(S_SIZE_T(strlen(className)) + S_SIZE_T(strlen(nameSpace)) + S_SIZE_T(2));
1336 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1338 size_t len = safeLen.Value();
1339 char *name = (char*) AllocateFromHighFrequencyHeap(safeLen);
1340 strcpy_s(name, len, nameSpace);
1341 if (strlen(nameSpace) > 0) {
1342 name[strlen(nameSpace)] = '.';
1343 name[strlen(nameSpace) + 1] = '\0';
1345 strcat_s(name, len, className);
1347 GetHalfBakedClass()->SetDebugClassName(name);
1350 if (g_pConfig->ShouldBreakOnClassBuild(className))
1352 CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassBuild: typename '%s' ", className));
1353 GetHalfBakedClass()->m_fDebuggingClass = TRUE;
1356 LPCUTF8 pszDebugName,pszDebugNamespace;
1357 if (FAILED(pModule->GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &pszDebugName, &pszDebugNamespace)))
1359 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
1362 StackSString debugName(SString::Utf8, pszDebugName);
1364 // If there is an instantiation, update the debug name to include instantiation type names.
1365 if (bmtGenerics->HasInstantiation())
1367 StackSString debugName(SString::Utf8, GetDebugClassName());
1368 TypeString::AppendInst(debugName, bmtGenerics->GetInstantiation(), TypeString::FormatBasic);
1369 StackScratchBuffer buff;
1370 const char* pDebugNameUTF8 = debugName.GetUTF8(buff);
1371 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8)) + S_SIZE_T(1);
1372 if(safeLen.IsOverflow())
1373 COMPlusThrowHR(COR_E_OVERFLOW);
1375 size_t len = safeLen.Value();
1376 char *name = (char*) AllocateFromLowFrequencyHeap(safeLen);
1377 strcpy_s(name, len, pDebugNameUTF8);
1378 GetHalfBakedClass()->SetDebugClassName(name);
1379 pszDebugName = (LPCUTF8)name;
1382 LOG((LF_CLASSLOADER, LL_INFO1000, "Loading class \"%s%s%S\" from module \"%ws\" in domain 0x%p %s\n",
1383 *pszDebugNamespace ? pszDebugNamespace : "",
1384 *pszDebugNamespace ? NAMESPACE_SEPARATOR_STR : "",
1385 debugName.GetUnicode(),
1386 pModule->GetDebugName(),
1387 pModule->GetDomain(),
1388 (pModule->IsSystem()) ? "System Domain" : ""
1392 // If this is mscorlib, then don't perform some sanity checks on the layout
1393 bmtProp->fNoSanityChecks = ((g_pObjectClass == NULL) || pModule == g_pObjectClass->GetModule()) ||
1394 #ifdef FEATURE_READYTORUN
1395 // No sanity checks for ready-to-run compiled images if possible
1396 (pModule->IsReadyToRun() && pModule->GetReadyToRunInfo()->SkipTypeValidation()) ||
1398 // No sanity checks for real generic instantiations
1399 !bmtGenerics->IsTypicalTypeDefinition();
1401 // Interfaces have a parent class of Object, but we don't really want to inherit all of
1402 // Object's virtual methods, so pretend we don't have a parent class - at the bottom of this
1403 // function we reset the parent class
1406 bmtInternal->pType->SetParentType(NULL);
1407 bmtInternal->pParentMT = NULL;
1410 unsigned totalDeclaredFieldSize=0;
1412 // Check to see if the class is a valuetype; but we don't want to mark System.Enum
1413 // as a ValueType. To accomplish this, the check takes advantage of the fact
1414 // that System.ValueType and System.Enum are loaded one immediately after the
1415 // other in that order, and so if the parent MethodTable is System.ValueType and
1416 // the System.Enum MethodTable is unset, then we must be building System.Enum and
1417 // so we don't mark it as a ValueType.
1419 ((g_pEnumClass != NULL && GetParentMethodTable() == g_pValueTypeClass) ||
1420 GetParentMethodTable() == g_pEnumClass))
1422 bmtProp->fIsValueClass = true;
1424 HRESULT hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
1425 g_CompilerServicesUnsafeValueTypeAttribute,
1430 SetUnsafeValueClass();
1433 hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
1434 g_CompilerServicesIsByRefLikeAttribute,
1439 bmtFP->fIsByRefLikeType = true;
1443 // Check to see if the class is an enumeration. No fancy checks like the one immediately
1444 // above for value types are necessary here.
1445 if(HasParent() && GetParentMethodTable() == g_pEnumClass)
1447 bmtProp->fIsEnum = true;
1449 // Ensure we don't have generic enums, or at least enums that have a
1450 // different number of type parameters from their enclosing class.
1451 // The goal is to ensure that the enum's values can't depend on the
1452 // type parameters in any way. And we don't see any need for an
1453 // enum to have additional type parameters.
1454 if (bmtGenerics->GetNumGenericArgs() != 0)
1456 // Nested enums can have generic type parameters from their enclosing class.
1457 // CLS rules require type parameters to be propogated to nested types.
1458 // Note that class G<T> { enum E { } } will produce "G`1+E<T>".
1459 // We want to disallow class G<T> { enum E<T, U> { } }
1460 // Perhaps the IL equivalent of class G<T> { enum E { } } should be legal.
1463 BuildMethodTableThrowException(IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM);
1466 mdTypeDef tdEnclosing = mdTypeDefNil;
1467 HRESULT hr = GetMDImport()->GetNestedClassProps(GetCl(), &tdEnclosing);
1469 ThrowHR(hr, BFA_UNABLE_TO_GET_NESTED_PROPS);
1471 HENUMInternalHolder hEnumGenericPars(GetMDImport());
1472 if (FAILED(hEnumGenericPars.EnumInitNoThrow(mdtGenericParam, tdEnclosing)))
1474 GetAssembly()->ThrowTypeLoadException(GetMDImport(), tdEnclosing, IDS_CLASSLOAD_BADFORMAT);
1477 if (hEnumGenericPars.EnumGetCount() != bmtGenerics->GetNumGenericArgs())
1479 BuildMethodTableThrowException(IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM);
1484 // If this type is marked by [Intrinsic] attribute, it may be specially treated by the runtime/compiler
1485 // SIMD types have [Intrinsic] attribute, for example
1487 // We check this here fairly early to ensure other downstream checks on these types can be slightly more efficient.
1488 if (GetModule()->IsSystem() || GetAssembly()->IsSIMDVectorAssembly())
1490 HRESULT hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
1491 g_CompilerServicesIntrinsicAttribute,
1497 bmtProp->fIsIntrinsicType = true;
1501 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1502 if (bmtProp->fIsIntrinsicType && !bmtGenerics->HasInstantiation())
1506 HRESULT hr = GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace);
1508 #if defined(_TARGET_ARM64_)
1509 // All the funtions in System.Runtime.Intrinsics.Arm.Arm64 are hardware intrinsics.
1510 if (hr == S_OK && strcmp(nameSpace, "System.Runtime.Intrinsics.Arm.Arm64") == 0)
1512 // All the funtions in System.Runtime.Intrinsics.X86 are hardware intrinsics.
1513 if (bmtInternal->pType->IsNested())
1515 IfFailThrow(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetEnclosingTypeToken(), NULL, &nameSpace));
1518 if (hr == S_OK && (strcmp(nameSpace, "System.Runtime.Intrinsics.X86") == 0))
1521 if (IsCompilationProcess())
1523 // Disable AOT compiling for managed implementation of hardware intrinsics in mscorlib.
1524 // We specially treat them here to ensure correct ISA features are set during compilation
1525 COMPlusThrow(kTypeLoadException, IDS_EE_HWINTRINSIC_NGEN_DISALLOWED);
1527 bmtProp->fIsHardwareIntrinsic = true;
1532 // Com Import classes are special. These types must derive from System.Object,
1533 // and we then substitute the parent with System._ComObject.
1534 if (IsComImport() && !IsEnum() && !IsInterface() && !IsValueClass() && !IsDelegate())
1536 #ifdef FEATURE_COMINTEROP
1537 // ComImport classes must either extend from Object or be a WinRT class
1538 // that extends from another WinRT class (and so form a chain of WinRT classes
1539 // that ultimately extend from object).
1540 MethodTable* pMTParent = GetParentMethodTable();
1541 if ((pMTParent == NULL) || !(
1542 // is the parent valid?
1543 (pMTParent == g_pObjectClass) ||
1544 (GetHalfBakedClass()->IsProjectedFromWinRT() && pMTParent->IsProjectedFromWinRT())
1547 BuildMethodTableThrowException(IDS_CLASSLOAD_CANTEXTEND);
1552 // ComImport classes cannot have layout information.
1553 BuildMethodTableThrowException(IDS_CLASSLOAD_COMIMPCANNOTHAVELAYOUT);
1556 if (pMTParent == g_pObjectClass)
1558 // ComImport classes ultimately extend from our __ComObject or RuntimeClass class
1559 MethodTable *pCOMMT = NULL;
1560 if (GetHalfBakedClass()->IsProjectedFromWinRT())
1561 pCOMMT = g_pBaseRuntimeClass;
1563 pCOMMT = g_pBaseCOMObject;
1567 // We could have had COM interop classes derive from System._ComObject,
1568 // but instead we have them derive from System.Object, have them set the
1569 // ComImport bit in the type attributes, and then we swap out the parent
1570 // type under the covers.
1571 bmtInternal->pType->SetParentType(CreateTypeChain(pCOMMT, Substitution()));
1572 bmtInternal->pParentMT = pCOMMT;
1575 // if the current class is imported
1576 bmtProp->fIsComObjectType = true;
1579 #ifdef FEATURE_COMINTEROP
1580 if (GetHalfBakedClass()->IsProjectedFromWinRT() && IsValueClass() && !IsEnum())
1582 // WinRT structures must have sequential layout
1583 if (!GetHalfBakedClass()->HasSequentialLayout())
1585 BuildMethodTableThrowException(IDS_EE_STRUCTLAYOUT_WINRT);
1589 // Check for special COM interop types.
1590 CheckForSpecialTypes();
1592 CheckForTypeEquivalence(cBuildingInterfaceList, pBuildingInterfaceList);
1595 { // Types that inherit from com object types are themselves com object types.
1596 if (GetParentMethodTable()->IsComObjectType())
1598 // if the parent class is of ComObjectType
1600 bmtProp->fIsComObjectType = true;
1603 #ifdef FEATURE_TYPEEQUIVALENCE
1604 // If your parent is type equivalent then so are you
1605 if (GetParentMethodTable()->HasTypeEquivalence())
1607 bmtProp->fHasTypeEquivalence = true;
1612 #endif // FEATURE_COMINTEROP
1614 if (!HasParent() && !IsInterface())
1616 if(g_pObjectClass != NULL)
1618 if(!IsGlobalClass())
1620 // Non object derived types that are not the global class are prohibited by spec
1621 BuildMethodTableThrowException(IDS_CLASSLOAD_PARENTNULL);
1626 // NOTE: This appears to be the earliest point during class loading that other classes MUST be loaded
1627 // resolve unresolved interfaces, determine an upper bound on the size of the interface map,
1628 // and determine the size of the largest interface (in # slots)
1629 ResolveInterfaces(cBuildingInterfaceList, pBuildingInterfaceList);
1631 // Enumerate this class's methodImpls
1632 EnumerateMethodImpls();
1634 // Enumerate this class's methods and fields
1635 EnumerateClassMethods();
1638 EnumerateClassFields();
1640 // Import the slots of the parent for use in placing this type's methods.
1641 ImportParentMethods();
1643 // This will allocate the working versions of the VTable and NonVTable in bmtVT
1644 AllocateWorkingSlotTables();
1646 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
1647 AllocateFieldDescs();
1649 // Copy the parent's vtable into the current type's vtable
1652 bmtVT->pDispatchMapBuilder = new (GetStackingAllocator()) DispatchMapBuilder(GetStackingAllocator());
1654 // Determine vtable placement for each member in this class
1655 PlaceVirtualMethods();
1656 PlaceNonVirtualMethods();
1658 // Allocate MethodDescs (expects methods placed methods)
1659 AllocAndInitMethodDescs();
1664 // We need to process/place method impls for default interface method overrides.
1665 // We won't build dispatch map for interfaces, though.
1667 ProcessMethodImpls();
1673 // If we are a class, then there may be some unplaced vtable methods (which are by definition
1674 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
1675 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
1676 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
1677 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
1678 // map for all interfaces as they are placed.
1680 // If we are an interface, then all methods are already placed. Fill out the interface map for
1681 // interfaces as they are placed.
1683 ComputeInterfaceMapEquivalenceSet();
1685 PlaceInterfaceMethods();
1687 ProcessMethodImpls();
1688 ProcessInexactMethodImpls();
1691 if (!bmtProp->fNoSanityChecks)
1693 // Now that interface method implementation have been fully resolved,
1694 // we need to make sure that type constraints are also met.
1695 ValidateInterfaceMethodConstraints();
1699 // Verify that we have not overflowed the number of slots.
1700 if (!FitsInU2((UINT64)bmtVT->pSlotTable->GetSlotCount()))
1702 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1705 // ensure we didn't overflow the temporary vtable
1706 _ASSERTE(bmtVT->pSlotTable->GetSlotCount() <= bmtVT->dwMaxVtableSize);
1708 // Allocate and initialize the dictionary for the type. This will be filled out later
1709 // with the final values.
1710 AllocAndInitDictionary();
1712 ////////////////////////////////////////////////////////////////////////////////////////////////
1716 // We decide here if we need a dynamic entry for our statics. We need it here because
1717 // the offsets of our fields will depend on this. For the dynamic case (which requires
1718 // an extra indirection (indirect depending of methodtable) we'll allocate the slot
1719 // in setupmethodtable
1720 if (((pAllocator->IsCollectible() || pModule->IsReflection() || bmtGenerics->HasInstantiation() || !pModule->IsStaticStoragePrepared(cl)) &&
1721 (bmtVT->GetClassCtorSlotIndex() != INVALID_SLOT_INDEX || bmtEnumFields->dwNumStaticFields !=0))
1722 #ifdef EnC_SUPPORTED
1723 // Classes in modules that have been edited (would do on class level if there were a
1724 // way to tell if the class had been edited) also have dynamic statics as the number
1725 // of statics might have changed, so can't use the static module-wide storage
1726 || (pModule->IsEditAndContinueEnabled() &&
1727 ((EditAndContinueModule*)pModule)->GetApplyChangesCount() > CorDB_DEFAULT_ENC_FUNCTION_VERSION)
1728 #endif // EnC_SUPPORTED
1731 // We will need a dynamic id
1732 bmtProp->fDynamicStatics = true;
1734 if (bmtGenerics->HasInstantiation())
1736 bmtProp->fGenericsStatics = true;
1740 // If not NULL, it means there are some by-value fields, and this contains an entry for each instance or static field,
1741 // which is NULL if not a by value field, and points to the EEClass of the field if a by value field. Instance fields
1742 // come first, statics come second.
1743 MethodTable ** pByValueClassCache = NULL;
1745 // Go thru all fields and initialize their FieldDescs.
1746 InitializeFieldDescs(GetApproxFieldDescListRaw(), pLayoutRawFieldInfos, bmtInternal, bmtGenerics,
1747 bmtMetaData, bmtEnumFields, bmtError,
1748 &pByValueClassCache, bmtMFDescs, bmtFP,
1749 &totalDeclaredFieldSize);
1751 // Place regular static fields
1752 PlaceRegularStaticFields();
1754 // Place thread static fields
1755 PlaceThreadStaticFields();
1757 LOG((LF_CODESHARING,
1759 "Placing %d statics (%d handles) for class %s.\n",
1760 GetNumStaticFields(), GetNumHandleRegularStatics() + GetNumHandleThreadStatics(),
1763 if (IsBlittable() || IsManagedSequential())
1765 bmtFP->NumGCPointerSeries = 0;
1766 bmtFP->NumInstanceGCPointerFields = 0;
1768 _ASSERTE(HasLayout());
1770 bmtFP->NumInstanceFieldBytes = IsBlittable() ? GetLayoutInfo()->m_cbNativeSize
1771 : GetLayoutInfo()->m_cbManagedSize;
1773 // For simple Blittable types we still need to check if they have any overlapping
1774 // fields and call the method SetHasOverLayedFields() when they are detected.
1776 if (HasExplicitFieldOffsetLayout())
1778 _ASSERTE(!bmtGenerics->fContainsGenericVariables); // A simple Blittable type can't ever be an open generic type.
1779 HandleExplicitLayout(pByValueClassCache);
1784 _ASSERTE(!IsBlittable());
1785 // HandleExplicitLayout fails for the GenericTypeDefinition when
1786 // it will succeed for some particular instantiations.
1787 // Thus we only do explicit layout for real instantiations, e.g. C<int>, not
1788 // the open types such as the GenericTypeDefinition C<!0> or any
1789 // of the "fake" types involving generic type variables which are
1790 // used for reflection and verification, e.g. C<List<!0>>.
1792 if (!bmtGenerics->fContainsGenericVariables && HasExplicitFieldOffsetLayout())
1794 HandleExplicitLayout(pByValueClassCache);
1798 // Place instance fields
1799 PlaceInstanceFields(pByValueClassCache);
1803 if (CheckIfSIMDAndUpdateSize())
1805 totalDeclaredFieldSize = bmtFP->NumInstanceFieldBytes;
1808 // We enforce that all value classes have non-zero size
1809 if (IsValueClass() && bmtFP->NumInstanceFieldBytes == 0)
1811 BuildMethodTableThrowException(IDS_CLASSLOAD_ZEROSIZE);
1814 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
1815 { // Verify self-referencing statics with RVA (now when the ValueType size is known)
1816 VerifySelfReferencingStaticValueTypeFields_WithRVA(pByValueClassCache);
1820 // Now setup the method table
1822 #ifdef FEATURE_PREJIT
1823 Module *pComputedPZM = pLoaderModule;
1825 if (bmtGenerics->GetNumGenericArgs() > 0)
1827 pComputedPZM = Module::ComputePreferredZapModule(pModule, bmtGenerics->GetInstantiation());
1830 SetupMethodTable2(pLoaderModule, pComputedPZM);
1831 #else // FEATURE_PREJIT
1832 SetupMethodTable2(pLoaderModule);
1833 #endif // FEATURE_PREJIT
1835 MethodTable * pMT = GetHalfBakedMethodTable();
1837 #ifdef FEATURE_64BIT_ALIGNMENT
1838 if (GetHalfBakedClass()->IsAlign8Candidate())
1839 pMT->SetRequiresAlign8();
1842 if (bmtGenerics->pVarianceInfo != NULL)
1844 pMT->SetHasVariance();
1847 if (bmtFP->NumRegularStaticGCBoxedFields != 0)
1849 pMT->SetHasBoxedRegularStatics();
1852 if (bmtFP->fIsByRefLikeType)
1854 pMT->SetIsByRefLike();
1859 if (bmtFP->NumInstanceFieldBytes != totalDeclaredFieldSize || HasOverLayedField())
1860 GetHalfBakedClass()->SetIsNotTightlyPacked();
1863 GetHalfBakedClass()->CheckForHFA(pByValueClassCache);
1865 #ifdef UNIX_AMD64_ABI
1867 #error Can't have FEATURE_HFA and UNIX_AMD64_ABI defined at the same time.
1868 #endif // FEATURE_HFA
1869 SystemVAmd64CheckForPassStructInRegister();
1870 #endif // UNIX_AMD64_ABI
1873 #ifdef UNIX_AMD64_ABI
1875 #error Can't have FEATURE_HFA and UNIX_AMD64_ABI defined at the same time.
1876 #endif // FEATURE_HFA
1879 SystemVAmd64CheckForPassNativeStructInRegister();
1881 #endif // UNIX_AMD64_ABI
1885 GetHalfBakedClass()->CheckForNativeHFA();
1890 pMT->SetDebugClassName(GetDebugClassName());
1893 #ifdef FEATURE_COMINTEROP
1896 GetCoClassAttribInfo();
1898 #endif // FEATURE_COMINTEROP
1900 if (HasExplicitFieldOffsetLayout())
1901 // Perform relevant GC calculations for tdexplicit
1902 HandleGCForExplicitLayout();
1904 // Perform relevant GC calculations for value classes
1905 HandleGCForValueClasses(pByValueClassCache);
1907 // GC reqires the series to be sorted.
1908 // TODO: fix it so that we emit them in the correct order in the first place.
1909 if (pMT->ContainsPointers())
1911 CGCDesc* gcDesc = CGCDesc::GetCGCDescFromMT(pMT);
1912 qsort(gcDesc->GetLowestSeries(), (int)gcDesc->GetNumSeries(), sizeof(CGCDescSeries), compareCGCDescSeries);
1915 SetFinalizationSemantics();
1917 // Allocate dynamic slot if necessary
1918 if (bmtProp->fDynamicStatics)
1920 if (bmtProp->fGenericsStatics)
1922 FieldDesc* pStaticFieldDescs = NULL;
1924 if (bmtEnumFields->dwNumStaticFields != 0)
1926 pStaticFieldDescs = pMT->GetApproxFieldDescListRaw() + bmtEnumFields->dwNumInstanceFields;
1929 pMT->SetupGenericsStaticsInfo(pStaticFieldDescs);
1933 // Get an id for the dynamic class. We store it in the class because
1934 // no class that is persisted in ngen should have it (ie, if the class is ngened
1935 // The id is stored in an optional field so we need to ensure an optional field descriptor has
1936 // been allocated for this EEClass instance.
1937 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, pAllocator->GetLowFrequencyHeap());
1938 SetModuleDynamicID(GetModule()->AllocateDynamicEntry(pMT));
1943 // if there are context or thread static set the info in the method table optional members
1946 // Check for the RemotingProxy Attribute
1947 // structs with GC pointers MUST be pointer sized aligned because the GC assumes it
1948 if (IsValueClass() && pMT->ContainsPointers() && (bmtFP->NumInstanceFieldBytes % TARGET_POINTER_SIZE != 0))
1950 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
1955 // Reset parent class
1956 pMT->SetParentMethodTable (g_pObjectClass);
1960 // Reset the debug method names for BoxedEntryPointStubs
1961 // so they reflect the very best debug information for the methods
1963 DeclaredMethodIterator methIt(*this);
1964 while (methIt.Next())
1966 if (methIt->GetUnboxedMethodDesc() != NULL)
1969 MethodDesc *pMD = methIt->GetUnboxedMethodDesc();
1970 StackSString name(SString::Utf8);
1971 TypeString::AppendMethodDebug(name, pMD);
1972 StackScratchBuffer buff;
1973 const char* pDebugNameUTF8 = name.GetUTF8(buff);
1974 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8)) + S_SIZE_T(1);
1975 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1976 size_t len = safeLen.Value();
1977 pMD->m_pszDebugMethodName = (char*) AllocateFromLowFrequencyHeap(safeLen);
1978 _ASSERTE(pMD->m_pszDebugMethodName);
1979 strcpy_s((char *) pMD->m_pszDebugMethodName, len, pDebugNameUTF8);
1983 MethodDesc *pMD = methIt->GetMethodDesc();
1985 StackSString name(SString::Utf8);
1986 TypeString::AppendMethodDebug(name, pMD);
1987 StackScratchBuffer buff;
1988 const char* pDebugNameUTF8 = name.GetUTF8(buff);
1989 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8))+S_SIZE_T(1);
1990 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1991 size_t len = safeLen.Value();
1992 pMD->m_pszDebugMethodName = (char*) AllocateFromLowFrequencyHeap(safeLen);
1993 _ASSERTE(pMD->m_pszDebugMethodName);
1994 strcpy_s((char *) pMD->m_pszDebugMethodName, len, pDebugNameUTF8);
2002 //If this is a value type, then propagate the UnsafeValueTypeAttribute from
2003 //its instance members to this type.
2004 if (IsValueClass() && !IsUnsafeValueClass())
2006 ApproxFieldDescIterator fields(GetHalfBakedMethodTable(),
2007 ApproxFieldDescIterator::INSTANCE_FIELDS );
2008 FieldDesc * current;
2009 while (NULL != (current = fields.Next()))
2011 CONSISTENCY_CHECK(!current->IsStatic());
2012 if (current->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
2014 TypeHandle th = current->LookupApproxFieldTypeHandle();
2015 CONSISTENCY_CHECK(!th.IsNull());
2016 if (th.AsMethodTable()->GetClass()->IsUnsafeValueClass())
2018 SetUnsafeValueClass();
2025 #ifdef FEATURE_ICASTABLE
2026 if (!IsValueClass() && g_pICastableInterface != NULL && pMT->CanCastToInterface(g_pICastableInterface))
2028 pMT->SetICastable();
2030 #endif // FEATURE_ICASTABLE
2032 // Grow the typedef ridmap in advance as we can't afford to
2033 // fail once we set the resolve bit
2034 pModule->EnsureTypeDefCanBeStored(bmtInternal->pType->GetTypeDefToken());
2036 // Grow the tables in advance so that RID map filling cannot fail
2037 // once we're past the commit point.
2038 EnsureRIDMapsCanBeFilled();
2041 // NOTE. NOTE!! the EEclass can now be accessed by other threads.
2042 // Do NOT place any initialization after this point.
2043 // You may NOT fail the call after this point.
2045 CANNOTTHROWCOMPLUSEXCEPTION();
2048 GetMemTracker()->SuppressRelease();
2053 if (g_pConfig->ShouldDumpOnClassLoad(pszDebugName))
2055 LOG((LF_ALWAYS, LL_ALWAYS, "Method table summary for '%s':\n", pszDebugName));
2056 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static fields: %d\n", bmtEnumFields->dwNumStaticFields));
2057 LOG((LF_ALWAYS, LL_ALWAYS, "Number of instance fields: %d\n", bmtEnumFields->dwNumInstanceFields));
2058 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static obj ref fields: %d\n", bmtEnumFields->dwNumStaticObjRefFields));
2059 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static boxed fields: %d\n", bmtEnumFields->dwNumStaticBoxedFields));
2060 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared fields: %d\n", NumDeclaredFields()));
2061 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared methods: %d\n", NumDeclaredMethods()));
2062 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared non-abstract methods: %d\n", bmtMethod->dwNumDeclaredNonAbstractMethods));
2063 pMT->Debug_DumpInterfaceMap("Approximate");
2064 pMT->DebugDumpVtable(pszDebugName, FALSE);
2065 pMT->DebugDumpFieldLayout(pszDebugName, FALSE);
2066 pMT->DebugDumpGCDesc(pszDebugName, FALSE);
2067 pMT->Debug_DumpDispatchMap();
2071 STRESS_LOG3(LF_CLASSLOADER, LL_INFO1000, "MethodTableBuilder: finished method table for module %p token %x = %pT \n",
2074 GetHalfBakedMethodTable());
2076 #ifdef FEATURE_PREJIT
2077 _ASSERTE(pComputedPZM == Module::GetPreferredZapModuleForMethodTable(pMT));
2078 #endif // FEATURE_PREJIT
2080 return GetHalfBakedMethodTable();
2081 } // MethodTableBuilder::BuildMethodTableThrowing
2083 #pragma warning(pop)
2087 //---------------------------------------------------------------------------------------
2089 // Resolve unresolved interfaces, determine an upper bound on the size of the interface map.
2092 MethodTableBuilder::ResolveInterfaces(
2093 WORD cBuildingInterfaceList,
2094 BuildingInterfaceInfo_t * pBuildingInterfaceList)
2099 PRECONDITION(CheckPointer(this));
2100 PRECONDITION(CheckPointer(bmtAllocator));
2101 PRECONDITION(CheckPointer(bmtInterface));
2102 PRECONDITION(CheckPointer(bmtVT));
2103 PRECONDITION(CheckPointer(bmtParent));
2107 // resolve unresolved interfaces and determine the size of the largest interface (in # slots)
2110 LoadApproxInterfaceMap();
2112 // Inherit parental slot counts
2113 //@TODO: This doesn't belong here.
2116 MethodTable * pParentClass = GetParentMethodTable();
2117 PREFIX_ASSUME(pParentClass != NULL);
2119 bmtParent->NumParentPointerSeries = pParentClass->ContainsPointers() ?
2120 (DWORD)CGCDesc::GetCGCDescFromMT(pParentClass)->GetNumSeries() : 0;
2122 if (pParentClass->HasFieldsWhichMustBeInited())
2124 SetHasFieldsWhichMustBeInited();
2126 #ifdef FEATURE_READYTORUN
2127 if (!(IsValueClass() || (pParentClass == g_pObjectClass)))
2129 CheckLayoutDependsOnOtherModules(pParentClass);
2135 bmtParent->NumParentPointerSeries = 0;
2137 } // MethodTableBuilder::ResolveInterfaces
2139 //*******************************************************************************
2141 int __cdecl MethodTableBuilder::bmtMetaDataInfo::MethodImplTokenPair::Compare(
2145 STATIC_CONTRACT_LEAF;
2146 MethodImplTokenPair *e1 = (MethodImplTokenPair *)elem1;
2147 MethodImplTokenPair *e2 = (MethodImplTokenPair *)elem2;
2148 if (e1->methodBody < e2->methodBody) return -1;
2149 else if (e1->methodBody > e2->methodBody) return 1;
2150 else if (e1->methodDecl < e2->methodDecl) return -1;
2151 else if (e1->methodDecl > e2->methodDecl) return 1;
2155 //*******************************************************************************
2157 BOOL MethodTableBuilder::bmtMetaDataInfo::MethodImplTokenPair::Equal(
2158 const MethodImplTokenPair *elem1,
2159 const MethodImplTokenPair *elem2)
2161 STATIC_CONTRACT_LEAF;
2162 return ((elem1->methodBody == elem2->methodBody) &&
2163 (elem1->methodDecl == elem2->methodDecl));
2166 //*******************************************************************************
2168 MethodTableBuilder::EnumerateMethodImpls()
2170 STANDARD_VM_CONTRACT;
2173 IMDInternalImport * pMDInternalImport = GetMDImport();
2174 DWORD rid, maxRidMD, maxRidMR;
2175 HENUMInternalMethodImplHolder hEnumMethodImpl(pMDInternalImport);
2176 hr = hEnumMethodImpl.EnumMethodImplInitNoThrow(GetCl());
2180 BuildMethodTableThrowException(hr, *bmtError);
2183 // This gets the count out of the metadata interface.
2184 bmtMethod->dwNumberMethodImpls = hEnumMethodImpl.EnumMethodImplGetCount();
2185 bmtMethod->dwNumberInexactMethodImplCandidates = 0;
2187 // This is the first pass. In this we will simply enumerate the token pairs and fill in
2188 // the data structures. In addition, we'll sort the list and eliminate duplicates.
2189 if (bmtMethod->dwNumberMethodImpls > 0)
2192 // Allocate the structures to keep track of the token pairs
2194 bmtMetaData->rgMethodImplTokens = new (GetStackingAllocator())
2195 bmtMetaDataInfo::MethodImplTokenPair[bmtMethod->dwNumberMethodImpls];
2197 // Iterate through each MethodImpl declared on this class
2198 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls; i++)
2200 hr = hEnumMethodImpl.EnumMethodImplNext(
2201 &bmtMetaData->rgMethodImplTokens[i].methodBody,
2202 &bmtMetaData->rgMethodImplTokens[i].methodDecl);
2203 bmtMetaData->rgMethodImplTokens[i].fConsiderDuringInexactMethodImplProcessing = false;
2204 bmtMetaData->rgMethodImplTokens[i].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
2205 bmtMetaData->rgMethodImplTokens[i].interfaceEquivalenceSet = 0;
2209 BuildMethodTableThrowException(hr, *bmtError);
2211 // Grab the next set of body/decl tokens
2214 // In the odd case that the enumerator fails before we've reached the total reported
2215 // entries, let's reset the count and just break out. (Should we throw?)
2216 bmtMethod->dwNumberMethodImpls = i;
2221 // No need to do any sorting or duplicate elimination if there's not two or more methodImpls
2222 if (bmtMethod->dwNumberMethodImpls > 1)
2225 qsort(bmtMetaData->rgMethodImplTokens,
2226 bmtMethod->dwNumberMethodImpls,
2227 sizeof(bmtMetaDataInfo::MethodImplTokenPair),
2228 &bmtMetaDataInfo::MethodImplTokenPair::Compare);
2230 // Now eliminate duplicates
2231 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls - 1; i++)
2233 CONSISTENCY_CHECK((i + 1) < bmtMethod->dwNumberMethodImpls);
2235 bmtMetaDataInfo::MethodImplTokenPair *e1 = &bmtMetaData->rgMethodImplTokens[i];
2236 bmtMetaDataInfo::MethodImplTokenPair *e2 = &bmtMetaData->rgMethodImplTokens[i + 1];
2238 // If the pair are equal, eliminate the first one, and reduce the total count by one.
2239 if (bmtMetaDataInfo::MethodImplTokenPair::Equal(e1, e2))
2241 DWORD dwCopyNum = bmtMethod->dwNumberMethodImpls - (i + 1);
2242 memcpy(e1, e2, dwCopyNum * sizeof(bmtMetaDataInfo::MethodImplTokenPair));
2243 bmtMethod->dwNumberMethodImpls--;
2244 CONSISTENCY_CHECK(bmtMethod->dwNumberMethodImpls > 0);
2250 if (bmtMethod->dwNumberMethodImpls != 0)
2253 // Allocate the structures to keep track of the impl matches
2255 bmtMetaData->pMethodDeclSubsts = new (GetStackingAllocator())
2256 Substitution[bmtMethod->dwNumberMethodImpls];
2258 // These are used for verification
2259 maxRidMD = pMDInternalImport->GetCountWithTokenKind(mdtMethodDef);
2260 maxRidMR = pMDInternalImport->GetCountWithTokenKind(mdtMemberRef);
2262 // Iterate through each MethodImpl declared on this class
2263 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls; i++)
2265 PCCOR_SIGNATURE pSigDecl = NULL;
2266 PCCOR_SIGNATURE pSigBody = NULL;
2271 mdToken theBody, theDecl;
2272 Substitution theDeclSubst(GetModule(), SigPointer(), NULL); // this can get updated later below.
2274 theBody = bmtMetaData->rgMethodImplTokens[i].methodBody;
2275 theDecl = bmtMetaData->rgMethodImplTokens[i].methodDecl;
2277 // IMPLEMENTATION LIMITATION: currently, we require that the body of a methodImpl
2278 // belong to the current type. This is because we need to allocate a different
2279 // type of MethodDesc for bodies that are part of methodImpls.
2280 if (TypeFromToken(theBody) != mdtMethodDef)
2282 hr = FindMethodDeclarationForMethodImpl(
2288 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_MI_ILLEGAL_BODY, mdMethodDefNil);
2291 // Make sure to update the stored token with the resolved token.
2292 bmtMetaData->rgMethodImplTokens[i].methodBody = theBody;
2295 if (TypeFromToken(theBody) != mdtMethodDef)
2297 BuildMethodTableThrowException(BFA_METHODDECL_NOT_A_METHODDEF);
2299 CONSISTENCY_CHECK(theBody == bmtMetaData->rgMethodImplTokens[i].methodBody);
2302 // Now that the tokens of Decl and Body are obtained, do the MD validation
2305 rid = RidFromToken(theDecl);
2307 // Perform initial rudimentary validation of the token. Full token verification
2308 // will be done in TestMethodImpl when placing the methodImpls.
2309 if (TypeFromToken(theDecl) == mdtMethodDef)
2311 // Decl must be valid token
2312 if ((rid == 0) || (rid > maxRidMD))
2314 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL);
2316 // Get signature and length
2317 if (FAILED(pMDInternalImport->GetSigOfMethodDef(theDecl, &cbSigDecl, &pSigDecl)))
2319 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2323 // The token is not a MethodDef (likely a MemberRef)
2326 // Decl must be valid token
2327 if ((TypeFromToken(theDecl) != mdtMemberRef) || (rid == 0) || (rid > maxRidMR))
2329 bmtError->resIDWhy = IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL;
2330 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL);
2333 // Get signature and length
2335 if (FAILED(pMDInternalImport->GetNameAndSigOfMemberRef(theDecl, &pSigDecl, &cbSigDecl, &szDeclName)))
2337 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2341 hr = pMDInternalImport->GetParentToken(theDecl,&tkParent);
2343 BuildMethodTableThrowException(hr, *bmtError);
2345 theDeclSubst = Substitution(tkParent, GetModule(), NULL);
2348 // Perform initial rudimentary validation of the token. Full token verification
2349 // will be done in TestMethodImpl when placing the methodImpls.
2351 // Body must be valid token
2352 rid = RidFromToken(theBody);
2353 if ((rid == 0)||(rid > maxRidMD))
2355 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_BODY);
2357 // Body's parent must be this class
2358 hr = pMDInternalImport->GetParentToken(theBody,&tkParent);
2360 BuildMethodTableThrowException(hr, *bmtError);
2361 if(tkParent != GetCl())
2363 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_BODY);
2366 // Decl's and Body's signatures must match
2367 if(pSigDecl && cbSigDecl)
2369 if (FAILED(pMDInternalImport->GetSigOfMethodDef(theBody, &cbSigBody, &pSigBody)) ||
2370 (pSigBody == NULL) ||
2373 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_BODY);
2375 // Can't use memcmp because there may be two AssemblyRefs
2376 // in this scope, pointing to the same assembly, etc.).
2377 if (!MetaSig::CompareMethodSigs(
2387 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH);
2392 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_DECL);
2395 bmtMetaData->pMethodDeclSubsts[i] = theDeclSubst;
2398 } // MethodTableBuilder::EnumerateMethodImpls
2400 //*******************************************************************************
2402 // Find a method declaration that must reside in the scope passed in. This method cannot be called if
2403 // the reference travels to another scope.
2405 // Protect against finding a declaration that lives within
2406 // us (the type being created)
2408 HRESULT MethodTableBuilder::FindMethodDeclarationForMethodImpl(
2409 mdToken pToken, // Token that is being located (MemberRef or MemberDef)
2410 mdToken* pDeclaration, // [OUT] Method definition for Member
2411 BOOL fSameClass) // Does the declaration need to be in this class
2413 STANDARD_VM_CONTRACT;
2417 IMDInternalImport *pMDInternalImport = GetMDImport();
2419 PCCOR_SIGNATURE pSig; // Signature of Member
2421 LPCUTF8 szMember = NULL;
2423 // The token should be a member ref or def. If it is a ref then we need to travel
2424 // back to us hopefully.
2425 if(TypeFromToken(pToken) == mdtMemberRef)
2429 if (FAILED(pMDInternalImport->GetParentOfMemberRef(pToken, &typeref)))
2431 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid MemberRef record");
2432 IfFailRet(COR_E_TYPELOAD);
2435 if (TypeFromToken(typeref) == mdtMethodDef)
2436 { // If parent is a method def then this is a varags method
2438 hr = pMDInternalImport->GetParentToken(typeref, &typeDef);
2440 if (TypeFromToken(typeDef) != mdtTypeDef)
2441 { // A mdtMethodDef must be parented by a mdtTypeDef
2442 BAD_FORMAT_NOTHROW_ASSERT(!"MethodDef without TypeDef as Parent");
2443 IfFailRet(COR_E_TYPELOAD);
2446 BAD_FORMAT_NOTHROW_ASSERT(typeDef == GetCl());
2448 // This is the real method we are overriding
2449 *pDeclaration = typeref;
2451 else if (TypeFromToken(typeref) == mdtTypeSpec)
2452 { // Added so that method impls can refer to instantiated interfaces or classes
2453 if (FAILED(pMDInternalImport->GetSigFromToken(typeref, &cSig, &pSig)))
2455 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid TypeSpec record");
2456 IfFailRet(COR_E_TYPELOAD);
2458 CorElementType elemType = (CorElementType) *pSig++;
2460 if (elemType == ELEMENT_TYPE_GENERICINST)
2461 { // If this is a generic inst, we expect that the next elem is ELEMENT_TYPE_CLASS,
2462 // which is handled in the case below.
2463 elemType = (CorElementType) *pSig++;
2464 BAD_FORMAT_NOTHROW_ASSERT(elemType == ELEMENT_TYPE_CLASS);
2467 if (elemType == ELEMENT_TYPE_CLASS)
2468 { // This covers E_T_GENERICINST and E_T_CLASS typespec formats. We don't expect
2469 // any other kinds to come through here.
2470 CorSigUncompressToken(pSig, &typeref);
2473 { // This is an unrecognized signature format.
2474 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2475 IDS_CLASSLOAD_MI_BAD_SIG,
2481 { // Verify that the ref points back to us
2482 mdToken tkDef = mdTokenNil;
2484 if (TypeFromToken(typeref) == mdtTypeRef)
2485 { // We only get here when we know the token does not reference a type in a different scope.
2486 LPCUTF8 pszNameSpace;
2487 LPCUTF8 pszClassName;
2489 if (FAILED(pMDInternalImport->GetNameOfTypeRef(typeref, &pszNameSpace, &pszClassName)))
2491 IfFailRet(COR_E_TYPELOAD);
2494 if (FAILED(pMDInternalImport->GetResolutionScopeOfTypeRef(typeref, &tkRes)))
2496 IfFailRet(COR_E_TYPELOAD);
2498 hr = pMDInternalImport->FindTypeDef(pszNameSpace,
2500 (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil,
2504 IfFailRet(COR_E_TYPELOAD);
2507 else if (TypeFromToken(typeref) == mdtTypeDef)
2508 { // We get a typedef when the parent of the token is a typespec to the type.
2513 CONSISTENCY_CHECK_MSGF(FALSE, ("Invalid methodimpl signature in class %s.", GetDebugClassName()));
2514 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2515 IDS_CLASSLOAD_MI_BAD_SIG,
2519 if (fSameClass && tkDef != GetCl())
2520 { // If we required that the typedef be the same type as the current class,
2521 // and it doesn't match, we need to return a failure result.
2522 IfFailRet(COR_E_TYPELOAD);
2525 IfFailRet(pMDInternalImport->GetNameAndSigOfMemberRef(pToken, &pSig, &cSig, &szMember));
2528 MetaSig::GetCallingConvention(GetModule(), Signature(pSig, cSig)),
2529 IMAGE_CEE_CS_CALLCONV_FIELD))
2531 return VLDTR_E_MR_BADCALLINGCONV;
2534 hr = pMDInternalImport->FindMethodDef(
2535 tkDef, szMember, pSig, cSig, pDeclaration);
2540 else if (TypeFromToken(pToken) == mdtMethodDef)
2544 // Verify that we are the parent
2545 hr = pMDInternalImport->GetParentToken(pToken, &typeDef);
2548 if(typeDef != GetCl())
2550 IfFailRet(COR_E_TYPELOAD);
2553 *pDeclaration = pToken;
2557 IfFailRet(COR_E_TYPELOAD);
2563 #pragma warning(push)
2564 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
2566 //---------------------------------------------------------------------------------------
2568 // Used by BuildMethodTable
2570 // Enumerate this class's members
2573 MethodTableBuilder::EnumerateClassMethods()
2578 PRECONDITION(CheckPointer(bmtInternal));
2579 PRECONDITION(CheckPointer(bmtEnumFields));
2580 PRECONDITION(CheckPointer(bmtMFDescs));
2581 PRECONDITION(CheckPointer(bmtProp));
2582 PRECONDITION(CheckPointer(bmtMetaData));
2583 PRECONDITION(CheckPointer(bmtVT));
2584 PRECONDITION(CheckPointer(bmtError));
2590 IMDInternalImport *pMDInternalImport = GetMDImport();
2592 DWORD dwMemberAttrs;
2593 BOOL fIsClassEnum = IsEnum();
2594 BOOL fIsClassInterface = IsInterface();
2595 BOOL fIsClassValueType = IsValueClass();
2596 BOOL fIsClassComImport = IsComImport();
2597 BOOL fIsClassNotAbstract = (IsTdAbstract(GetAttrClass()) == 0);
2598 PCCOR_SIGNATURE pMemberSignature;
2599 ULONG cMemberSignature;
2602 // Run through the method list and calculate the following:
2604 // # "other" methods (i.e. static or private)
2605 // # non-other methods
2608 HENUMInternalHolder hEnumMethod(pMDInternalImport);
2609 hr = hEnumMethod.EnumInitNoThrow(mdtMethodDef, GetCl());
2612 BuildMethodTableThrowException(hr, *bmtError);
2615 // Allocate an array to contain the method tokens as well as information about the methods.
2616 DWORD cMethAndGaps = hEnumMethod.EnumGetCount();
2618 if ((DWORD)MAX_SLOT_INDEX <= cMethAndGaps)
2619 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
2621 bmtMethod->m_cMaxDeclaredMethods = (SLOT_INDEX)cMethAndGaps;
2622 bmtMethod->m_cDeclaredMethods = 0;
2623 bmtMethod->m_rgDeclaredMethods = new (GetStackingAllocator())
2624 bmtMDMethod *[bmtMethod->m_cMaxDeclaredMethods];
2626 enum { SeenCtor = 1, SeenInvoke = 2, SeenBeginInvoke = 4, SeenEndInvoke = 8};
2627 unsigned delegateMethodsSeen = 0;
2629 for (i = 0; i < cMethAndGaps; i++)
2634 METHOD_IMPL_TYPE implType;
2635 LPSTR strMethodName;
2637 #ifdef FEATURE_TYPEEQUIVALENCE
2638 // TypeEquivalent structs must not have methods
2639 if (bmtProp->fIsTypeEquivalent && fIsClassValueType)
2641 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTMETHODS);
2646 // Go to the next method and retrieve its attributes.
2649 hEnumMethod.EnumNext(&tok);
2650 DWORD rid = RidFromToken(tok);
2651 if ((rid == 0)||(rid > pMDInternalImport->GetCountWithTokenKind(mdtMethodDef)))
2653 BuildMethodTableThrowException(BFA_METHOD_TOKEN_OUT_OF_RANGE);
2656 if (FAILED(pMDInternalImport->GetMethodDefProps(tok, &dwMemberAttrs)))
2658 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2660 if (IsMdRTSpecialName(dwMemberAttrs) || IsMdVirtual(dwMemberAttrs) || IsDelegate())
2662 if (FAILED(pMDInternalImport->GetNameOfMethodDef(tok, (LPCSTR *)&strMethodName)))
2664 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2666 if(IsStrLongerThan(strMethodName,MAX_CLASS_NAME))
2668 BuildMethodTableThrowException(BFA_METHOD_NAME_TOO_LONG);
2673 strMethodName = NULL;
2676 DWORD numGenericMethodArgs = 0;
2679 HENUMInternalHolder hEnumTyPars(pMDInternalImport);
2680 hr = hEnumTyPars.EnumInitNoThrow(mdtGenericParam, tok);
2683 BuildMethodTableThrowException(hr, *bmtError);
2686 numGenericMethodArgs = hEnumTyPars.EnumGetCount();
2688 // We do not want to support context-bound objects with generic methods.
2690 if (numGenericMethodArgs != 0)
2692 HENUMInternalHolder hEnumGenericPars(pMDInternalImport);
2694 hEnumGenericPars.EnumInit(mdtGenericParam, tok);
2696 for (unsigned methIdx = 0; methIdx < numGenericMethodArgs; methIdx++)
2698 mdGenericParam tkTyPar;
2699 pMDInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
2701 if (FAILED(pMDInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
2703 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2706 if (0 != (flags & ~(gpVarianceMask | gpSpecialConstraintMask)))
2708 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2710 switch (flags & gpVarianceMask)
2715 case gpCovariant: // intentional fallthru
2716 case gpContravariant:
2717 BuildMethodTableThrowException(VLDTR_E_GP_ILLEGAL_VARIANT_MVAR);
2721 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2729 // We need to check if there are any gaps in the vtable. These are
2730 // represented by methods with the mdSpecial flag and a name of the form
2731 // _VTblGap_nnn (to represent nnn empty slots) or _VTblGap (to represent a
2732 // single empty slot).
2735 if (IsMdRTSpecialName(dwMemberAttrs))
2737 PREFIX_ASSUME(strMethodName != NULL); // if we've gotten here we've called GetNameOfMethodDef
2739 // The slot is special, but it might not be a vtable spacer. To
2740 // determine that we must look at the name.
2741 if (strncmp(strMethodName, "_VtblGap", 8) == 0)
2744 // This slot doesn't really exist, don't add it to the method
2745 // table. Instead it represents one or more empty slots, encoded
2746 // in the method name. Locate the beginning of the count in the
2747 // name. There are these points to consider:
2748 // There may be no count present at all (in which case the
2749 // count is taken as one).
2750 // There may be an additional count just after Gap but before
2751 // the '_'. We ignore this.
2754 LPCSTR pos = strMethodName + 8;
2756 // Skip optional number.
2757 while (IS_DIGIT(*pos))
2762 // Check for presence of count.
2769 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2770 IDS_CLASSLOAD_BADSPECIALMETHOD,
2778 bool fReadAtLeastOneDigit = false;
2779 while (IS_DIGIT(*pos))
2783 n += DIGIT_TO_INT(*pos);
2785 fReadAtLeastOneDigit = true;
2788 // Check for end of name.
2789 if (*pos != '\0' || !fReadAtLeastOneDigit)
2791 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2792 IDS_CLASSLOAD_BADSPECIALMETHOD,
2797 #ifdef FEATURE_COMINTEROP
2798 // Record vtable gap in mapping list. The map is an optional field, so ensure we've allocated
2799 // these fields first.
2800 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
2801 if (GetHalfBakedClass()->GetSparseCOMInteropVTableMap() == NULL)
2802 GetHalfBakedClass()->SetSparseCOMInteropVTableMap(new SparseVTableMap());
2804 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->RecordGap((WORD)NumDeclaredMethods(), n);
2806 bmtProp->fSparse = true;
2807 #endif // FEATURE_COMINTEROP
2815 // This is a real method so add it to the enumeration of methods. We now need to retrieve
2816 // information on the method and store it for later use.
2818 if (FAILED(pMDInternalImport->GetMethodImplProps(tok, &dwMethodRVA, &dwImplFlags)))
2820 BuildMethodTableThrowException(
2821 COR_E_BADIMAGEFORMAT,
2822 IDS_CLASSLOAD_BADSPECIALMETHOD,
2826 // But first - minimal flags validity checks
2828 // No methods in Enums!
2831 BuildMethodTableThrowException(BFA_METHOD_IN_A_ENUM);
2834 if (dwMethodRVA != 0)
2836 if(fIsClassComImport)
2838 BuildMethodTableThrowException(BFA_METHOD_WITH_NONZERO_RVA);
2840 if(IsMdAbstract(dwMemberAttrs))
2842 BuildMethodTableThrowException(BFA_ABSTRACT_METHOD_WITH_RVA);
2844 if(IsMiRuntime(dwImplFlags))
2846 BuildMethodTableThrowException(BFA_RUNTIME_METHOD_WITH_RVA);
2848 if(IsMiInternalCall(dwImplFlags))
2850 BuildMethodTableThrowException(BFA_INTERNAL_METHOD_WITH_RVA);
2854 // Abstract / not abstract
2855 if(IsMdAbstract(dwMemberAttrs))
2857 if(fIsClassNotAbstract)
2859 BuildMethodTableThrowException(BFA_AB_METHOD_IN_AB_CLASS);
2861 if(!IsMdVirtual(dwMemberAttrs))
2863 BuildMethodTableThrowException(BFA_NONVIRT_AB_METHOD);
2866 else if(fIsClassInterface)
2868 if (IsMdRTSpecialName(dwMemberAttrs))
2870 CONSISTENCY_CHECK(CheckPointer(strMethodName));
2871 if (strcmp(strMethodName, COR_CCTOR_METHOD_NAME))
2873 BuildMethodTableThrowException(BFA_NONAB_NONCCTOR_METHOD_ON_INT);
2878 // Virtual / not virtual
2879 if(IsMdVirtual(dwMemberAttrs))
2881 if(IsMdPinvokeImpl(dwMemberAttrs))
2883 BuildMethodTableThrowException(BFA_VIRTUAL_PINVOKE_METHOD);
2885 if(IsMdStatic(dwMemberAttrs))
2887 BuildMethodTableThrowException(BFA_VIRTUAL_STATIC_METHOD);
2889 if(strMethodName && (0==strcmp(strMethodName, COR_CTOR_METHOD_NAME)))
2891 BuildMethodTableThrowException(BFA_VIRTUAL_INSTANCE_CTOR);
2895 #ifndef FEATURE_DEFAULT_INTERFACES
2896 // Some interface checks.
2897 if (fIsClassInterface)
2899 if (IsMdVirtual(dwMemberAttrs))
2901 if (!IsMdAbstract(dwMemberAttrs))
2903 BuildMethodTableThrowException(BFA_VIRTUAL_NONAB_INT_METHOD);
2908 // Instance field/method
2909 if (!IsMdStatic(dwMemberAttrs))
2911 BuildMethodTableThrowException(BFA_NONVIRT_INST_INT_METHOD);
2917 // No synchronized methods in ValueTypes
2918 if(fIsClassValueType && IsMiSynchronized(dwImplFlags))
2920 BuildMethodTableThrowException(BFA_SYNC_METHOD_IN_VT);
2926 if(!IsMdStatic(dwMemberAttrs))
2928 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_METHOD);
2930 if (strMethodName) //<TODO>@todo: investigate mc++ generating null name</TODO>
2932 if(0==strcmp(strMethodName, COR_CTOR_METHOD_NAME))
2934 BuildMethodTableThrowException(BFA_GLOBAL_INST_CTOR);
2939 // Generic methods or methods in generic classes
2940 // may not be part of a COM Import class (except for WinRT), PInvoke, internal call outside mscorlib.
2941 if ((bmtGenerics->GetNumGenericArgs() != 0 || numGenericMethodArgs != 0) &&
2943 #ifdef FEATURE_COMINTEROP
2944 fIsClassComImport ||
2945 bmtProp->fComEventItfType ||
2946 #endif // FEATURE_COMINTEROP
2947 IsMdPinvokeImpl(dwMemberAttrs) ||
2948 (IsMiInternalCall(dwImplFlags) && !GetModule()->IsSystem())))
2950 #ifdef FEATURE_COMINTEROP
2951 if (!GetHalfBakedClass()->IsProjectedFromWinRT())
2952 #endif // FEATURE_COMINTEROP
2954 BuildMethodTableThrowException(BFA_BAD_PLACE_FOR_GENERIC_METHOD);
2958 // Generic methods may not be marked "runtime". However note that
2959 // methods in generic delegate classes are, hence we don't apply this to
2960 // methods in generic classes in general.
2961 if (numGenericMethodArgs != 0 && IsMiRuntime(dwImplFlags))
2963 BuildMethodTableThrowException(BFA_GENERIC_METHOD_RUNTIME_IMPL);
2967 // Signature validation
2968 if (FAILED(pMDInternalImport->GetSigOfMethodDef(tok, &cMemberSignature, &pMemberSignature)))
2970 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2972 hr = validateTokenSig(tok,pMemberSignature,cMemberSignature,dwMemberAttrs,pMDInternalImport);
2975 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2978 // Check the appearance of covariant and contravariant in the method signature
2979 // Note that variance is only supported for interfaces
2980 if (bmtGenerics->pVarianceInfo != NULL)
2982 SigPointer sp(pMemberSignature, cMemberSignature);
2984 IfFailThrow(sp.GetCallingConvInfo(&callConv));
2986 if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2987 IfFailThrow(sp.GetData(NULL));
2990 IfFailThrow(sp.GetData(&numArgs));
2992 // Return type behaves covariantly
2993 if (!EEClass::CheckVarianceInSig(
2994 bmtGenerics->GetNumGenericArgs(),
2995 bmtGenerics->pVarianceInfo,
3000 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_RESULT, tok);
3002 IfFailThrow(sp.SkipExactlyOne());
3003 for (DWORD j = 0; j < numArgs; j++)
3005 // Argument types behave contravariantly
3006 if (!EEClass::CheckVarianceInSig(bmtGenerics->GetNumGenericArgs(),
3007 bmtGenerics->pVarianceInfo,
3012 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_ARG, tok);
3014 IfFailThrow(sp.SkipExactlyOne());
3019 // Determine the method's type
3022 if (IsReallyMdPinvokeImpl(dwMemberAttrs) || IsMiInternalCall(dwImplFlags))
3024 hr = NDirect::HasNAT_LAttribute(pMDInternalImport, tok, dwMemberAttrs);
3026 // There was a problem querying for the attribute
3029 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_BADPINVOKE, tok);
3032 // The attribute is not present
3035 #ifdef FEATURE_COMINTEROP
3036 if (fIsClassComImport
3037 || GetHalfBakedClass()->IsProjectedFromWinRT()
3038 || bmtProp->fComEventItfType
3041 // ComImport classes have methods which are just used
3042 // for implementing all interfaces the class supports
3043 type = METHOD_TYPE_COMINTEROP;
3045 // constructor is special
3046 if (IsMdRTSpecialName(dwMemberAttrs))
3048 // Note: Method name (.ctor) will be checked in code:ValidateMethods
3050 // WinRT ctors are interop calls via stubs
3051 if (!GetHalfBakedClass()->IsProjectedFromWinRT())
3053 // Ctor on a non-WinRT class
3054 type = METHOD_TYPE_FCALL;
3059 #endif //FEATURE_COMINTEROP
3060 if (dwMethodRVA == 0)
3062 type = METHOD_TYPE_FCALL;
3066 type = METHOD_TYPE_NDIRECT;
3069 // The NAT_L attribute is present, marking this method as NDirect
3072 CONSISTENCY_CHECK(hr == S_OK);
3073 type = METHOD_TYPE_NDIRECT;
3076 else if (IsMiRuntime(dwImplFlags))
3078 // currently the only runtime implemented functions are delegate instance methods
3079 if (!IsDelegate() || IsMdStatic(dwMemberAttrs) || IsMdAbstract(dwMemberAttrs))
3081 BuildMethodTableThrowException(BFA_BAD_RUNTIME_IMPL);
3084 unsigned newDelegateMethodSeen = 0;
3086 if (IsMdRTSpecialName(dwMemberAttrs)) // .ctor
3088 if (strcmp(strMethodName, COR_CTOR_METHOD_NAME) != 0 || IsMdVirtual(dwMemberAttrs))
3090 BuildMethodTableThrowException(BFA_BAD_FLAGS_ON_DELEGATE);
3092 newDelegateMethodSeen = SeenCtor;
3093 type = METHOD_TYPE_FCALL;
3097 if (strcmp(strMethodName, "Invoke") == 0)
3098 newDelegateMethodSeen = SeenInvoke;
3099 else if (strcmp(strMethodName, "BeginInvoke") == 0)
3100 newDelegateMethodSeen = SeenBeginInvoke;
3101 else if (strcmp(strMethodName, "EndInvoke") == 0)
3102 newDelegateMethodSeen = SeenEndInvoke;
3105 BuildMethodTableThrowException(BFA_UNKNOWN_DELEGATE_METHOD);
3107 type = METHOD_TYPE_EEIMPL;
3110 // If we get here we have either set newDelegateMethodSeen or we have thrown a BMT exception
3111 _ASSERTE(newDelegateMethodSeen != 0);
3113 if ((delegateMethodsSeen & newDelegateMethodSeen) != 0)
3115 BuildMethodTableThrowException(BFA_DUPLICATE_DELEGATE_METHOD);
3118 delegateMethodsSeen |= newDelegateMethodSeen;
3120 else if (numGenericMethodArgs != 0)
3122 //We use an instantiated method desc to represent a generic method
3123 type = METHOD_TYPE_INSTANTIATED;
3125 else if (fIsClassInterface)
3127 #ifdef FEATURE_COMINTEROP
3128 if (IsMdStatic(dwMemberAttrs))
3130 // Static methods in interfaces need nothing special.
3131 type = METHOD_TYPE_NORMAL;
3133 else if (bmtGenerics->GetNumGenericArgs() != 0 &&
3134 (bmtGenerics->fSharedByGenericInstantiations || (!bmtProp->fIsRedirectedInterface && !GetHalfBakedClass()->IsProjectedFromWinRT())))
3136 // Methods in instantiated interfaces need nothing special - they are not visible from COM etc.
3137 // mcComInterop is only useful for unshared instantiated WinRT interfaces. If the interface is
3138 // shared by multiple instantiations, the MD would be useless for interop anyway.
3139 type = METHOD_TYPE_NORMAL;
3141 else if (bmtProp->fIsMngStandardItf)
3143 // If the interface is a standard managed interface then allocate space for an FCall method desc.
3144 type = METHOD_TYPE_FCALL;
3146 else if (IsMdAbstract(dwMemberAttrs))
3148 // If COM interop is supported then all other interface MDs may be
3149 // accessed via COM interop. mcComInterop MDs have an additional
3150 // pointer-sized field pointing to COM interop data which are
3151 // allocated lazily when/if the MD actually gets used for interop.
3152 type = METHOD_TYPE_COMINTEROP;
3155 #endif // !FEATURE_COMINTEROP
3157 // This codepath is used by remoting
3158 type = METHOD_TYPE_NORMAL;
3163 type = METHOD_TYPE_NORMAL;
3166 // Generic methods should always be METHOD_TYPE_INSTANTIATED
3167 if ((numGenericMethodArgs != 0) && (type != METHOD_TYPE_INSTANTIATED))
3169 BuildMethodTableThrowException(BFA_GENERIC_METHODS_INST);
3172 // count how many overrides this method does All methods bodies are defined
3173 // on this type so we can just compare the tok with the body token found
3174 // from the overrides.
3175 implType = METHOD_IMPL_NOT;
3176 for (DWORD impls = 0; impls < bmtMethod->dwNumberMethodImpls; impls++)
3178 if (bmtMetaData->rgMethodImplTokens[impls].methodBody == tok)
3180 implType = METHOD_IMPL;
3185 // For delegates we don't allow any non-runtime implemented bodies
3186 // for any of the four special methods
3187 if (IsDelegate() && !IsMiRuntime(dwImplFlags))
3189 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
3190 (strcmp(strMethodName, "Invoke") == 0) ||
3191 (strcmp(strMethodName, "BeginInvoke") == 0) ||
3192 (strcmp(strMethodName, "EndInvoke") == 0) )
3194 BuildMethodTableThrowException(BFA_ILLEGAL_DELEGATE_METHOD);
3199 // Create a new bmtMDMethod representing this method and add it to the
3200 // declared method list.
3203 bmtMDMethod * pNewMethod = new (GetStackingAllocator()) bmtMDMethod(
3212 bmtMethod->AddDeclaredMethod(pNewMethod);
3215 // Update the count of the various types of methods.
3218 bmtVT->dwMaxVtableSize++;
3220 // Increment the number of non-abstract declared methods
3221 if (!IsMdAbstract(dwMemberAttrs))
3223 bmtMethod->dwNumDeclaredNonAbstractMethods++;
3227 // Check to see that we have all of the required delegate methods (ECMA 13.6 Delegates)
3230 // Do we have all four special delegate methods
3231 // or just the two special delegate methods
3232 if ((delegateMethodsSeen != (SeenCtor | SeenInvoke | SeenBeginInvoke | SeenEndInvoke)) &&
3233 (delegateMethodsSeen != (SeenCtor | SeenInvoke)) )
3235 BuildMethodTableThrowException(BFA_MISSING_DELEGATE_METHOD);
3239 if (i != cMethAndGaps)
3241 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_METHOD_COUNT, mdTokenNil);
3244 #ifdef FEATURE_COMINTEROP
3246 // If the interface is sparse, we need to finalize the mapping list by
3247 // telling it how many real methods we found.
3250 if (bmtProp->fSparse)
3252 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->FinalizeMapping(NumDeclaredMethods());
3254 #endif // FEATURE_COMINTEROP
3255 } // MethodTableBuilder::EnumerateClassMethods
3257 #pragma warning(pop)
3260 //*******************************************************************************
3262 // Run through the field list and calculate the following:
3264 // # static fields that contain object refs.
3265 // # instance fields
3268 MethodTableBuilder::EnumerateClassFields()
3270 STANDARD_VM_CONTRACT;
3274 IMDInternalImport *pMDInternalImport = GetMDImport();
3276 DWORD dwMemberAttrs;
3278 bmtEnumFields->dwNumStaticFields = 0;
3279 bmtEnumFields->dwNumStaticObjRefFields = 0;
3280 bmtEnumFields->dwNumStaticBoxedFields = 0;
3282 bmtEnumFields->dwNumThreadStaticFields = 0;
3283 bmtEnumFields->dwNumThreadStaticObjRefFields = 0;
3284 bmtEnumFields->dwNumThreadStaticBoxedFields = 0;
3286 bmtEnumFields->dwNumInstanceFields = 0;
3288 HENUMInternalHolder hEnumField(pMDInternalImport);
3289 hr = hEnumField.EnumInitNoThrow(mdtFieldDef, GetCl());
3292 BuildMethodTableThrowException(hr, *bmtError);
3295 bmtMetaData->cFields = hEnumField.EnumGetCount();
3297 // Retrieve the fields and store them in a temp array.
3298 bmtMetaData->pFields = new (GetStackingAllocator()) mdToken[bmtMetaData->cFields];
3299 bmtMetaData->pFieldAttrs = new (GetStackingAllocator()) DWORD[bmtMetaData->cFields];
3301 DWORD dwFieldLiteralInitOnly = fdLiteral | fdInitOnly;
3302 DWORD dwMaxFieldDefRid = pMDInternalImport->GetCountWithTokenKind(mdtFieldDef);
3304 for (i = 0; hEnumField.EnumNext(&tok); i++)
3307 // Retrieve the attributes of the field.
3309 DWORD rid = RidFromToken(tok);
3310 if ((rid == 0)||(rid > dwMaxFieldDefRid))
3312 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, mdTokenNil);
3315 if (FAILED(pMDInternalImport->GetFieldDefProps(tok, &dwMemberAttrs)))
3317 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, tok);
3321 // Store the field and its attributes in the bmtMetaData structure for later use.
3324 bmtMetaData->pFields[i] = tok;
3325 bmtMetaData->pFieldAttrs[i] = dwMemberAttrs;
3327 if((dwMemberAttrs & fdFieldAccessMask)==fdFieldAccessMask)
3329 BuildMethodTableThrowException(BFA_INVALID_FIELD_ACC_FLAGS);
3331 if((dwMemberAttrs & dwFieldLiteralInitOnly)==dwFieldLiteralInitOnly)
3333 BuildMethodTableThrowException(BFA_FIELD_LITERAL_AND_INIT);
3336 // can only have static global fields
3339 if(!IsFdStatic(dwMemberAttrs))
3341 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_FIELD);
3346 // Update the count of the various types of fields.
3349 if (IsFdStatic(dwMemberAttrs))
3351 if (!IsFdLiteral(dwMemberAttrs))
3353 #ifdef FEATURE_TYPEEQUIVALENCE
3354 if (bmtProp->fIsTypeEquivalent)
3356 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3360 bmtEnumFields->dwNumStaticFields++;
3362 // If this static field is thread static, then we need
3363 // to increment bmtEnumFields->dwNumThreadStaticFields
3364 hr = pMDInternalImport->GetCustomAttributeByName(tok,
3365 g_ThreadStaticAttributeClassName,
3370 // It's a thread static, so increment the count
3371 bmtEnumFields->dwNumThreadStaticFields++;
3377 #ifdef FEATURE_TYPEEQUIVALENCE
3378 if (!IsFdPublic(dwMemberAttrs) && bmtProp->fIsTypeEquivalent)
3380 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3384 if (!IsFdLiteral(dwMemberAttrs))
3386 bmtEnumFields->dwNumInstanceFields++;
3390 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_INT);
3395 if (i != bmtMetaData->cFields)
3397 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD_COUNT, mdTokenNil);
3400 if(IsEnum() && (bmtEnumFields->dwNumInstanceFields==0))
3402 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_ENUM);
3405 bmtEnumFields->dwNumDeclaredFields = bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields;
3408 //*******************************************************************************
3410 // Used by BuildMethodTable
3412 // Determines the maximum size of the vtable and allocates the temporary storage arrays
3413 // Also copies the parent's vtable into the working vtable.
3415 VOID MethodTableBuilder::AllocateWorkingSlotTables()
3420 PRECONDITION(CheckPointer(this));
3421 PRECONDITION(CheckPointer(bmtAllocator));
3422 PRECONDITION(CheckPointer(bmtMFDescs));
3423 PRECONDITION(CheckPointer(bmtMetaData));
3424 PRECONDITION(CheckPointer(bmtVT));
3425 PRECONDITION(CheckPointer(bmtEnumFields));
3426 PRECONDITION(CheckPointer(bmtInterface));
3427 PRECONDITION(CheckPointer(bmtFP));
3428 PRECONDITION(CheckPointer(bmtParent));
3433 // Allocate a FieldDesc* for each field
3434 bmtMFDescs->ppFieldDescList = new (GetStackingAllocator()) FieldDesc*[bmtMetaData->cFields];
3435 ZeroMemory(bmtMFDescs->ppFieldDescList, bmtMetaData->cFields * sizeof(FieldDesc *));
3437 // Create a temporary function table (we don't know how large the vtable will be until the very end,
3438 // since we don't yet know how many declared methods are overrides vs. newslots).
3441 { // ValueClass virtuals are converted into non-virtual methods and the virtual slots
3442 // become unboxing stubs that forward to these new non-virtual methods. This has the
3443 // side effect of doubling the number of slots introduced by newslot virtuals.
3444 bmtVT->dwMaxVtableSize += NumDeclaredMethods();
3447 _ASSERTE(!HasParent() || (bmtInterface->dwInterfaceMapSize - GetParentMethodTable()->GetNumInterfaces()) >= 0);
3450 { // Add parent vtable size. <TODO> This should actually be the parent's virtual method count. </TODO>
3451 bmtVT->dwMaxVtableSize += bmtParent->pSlotTable->GetSlotCount();
3454 S_SLOT_INDEX cMaxSlots = AsClrSafeInt(bmtVT->dwMaxVtableSize) + AsClrSafeInt(NumDeclaredMethods());
3456 if (cMaxSlots.IsOverflow() || MAX_SLOT_INDEX < cMaxSlots.Value())
3457 cMaxSlots = S_SLOT_INDEX(MAX_SLOT_INDEX);
3459 // Allocate the temporary vtable
3460 bmtVT->pSlotTable = new (GetStackingAllocator())
3461 bmtMethodSlotTable(cMaxSlots.Value(), GetStackingAllocator());
3466 // @<TODO>todo: Figure out the right way to override Equals for value
3469 // This is broken because
3470 // (a) g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool); will return
3471 // the EqualsValue method
3472 // (b) When mscorlib has been preloaded (and thus the munge already done
3473 // ahead of time), we cannot easily find both methods
3474 // to compute EqualsAddr & EqualsSlot
3476 // For now, the Equals method has a runtime check to see if it's
3477 // comparing value types.
3480 // If it is a value type, over ride a few of the base class methods.
3483 static WORD EqualsSlot;
3485 // If we haven't been through here yet, get some stuff from the Object class definition.
3486 if (EqualsSlot == NULL)
3488 // Get the slot of the Equals method.
3489 MethodDesc *pEqualsMD = g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool);
3490 THROW_BAD_FORMAT_MAYBE(pEqualsMD != NULL, 0, this);
3491 EqualsSlot = pEqualsMD->GetSlot();
3493 // Get the address of the EqualsValue method.
3494 MethodDesc *pEqualsValueMD = g_pObjectClass->FindMethod("EqualsValue", &gsig_IM_Obj_RetBool);
3495 THROW_BAD_FORMAT_MAYBE(pEqualsValueMD != NULL, 0, this);
3497 // Patch the EqualsValue method desc in a dangerous way to
3498 // look like the Equals method desc.
3499 pEqualsValueMD->SetSlot(EqualsSlot);
3500 pEqualsValueMD->SetMemberDef(pEqualsMD->GetMemberDef());
3503 // Override the valuetype "Equals" with "EqualsValue".
3504 bmtVT->SetMethodDescForSlot(EqualsSlot, EqualsSlot);
3509 S_UINT32 cEntries = S_UINT32(2) * S_UINT32(NumDeclaredMethods());
3510 if (cEntries.IsOverflow())
3512 ThrowHR(COR_E_OVERFLOW);
3516 //*******************************************************************************
3518 // Used by BuildMethodTable
3520 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
3522 VOID MethodTableBuilder::AllocateFieldDescs()
3527 PRECONDITION(CheckPointer(this));
3528 PRECONDITION(CheckPointer(bmtAllocator));
3529 PRECONDITION(CheckPointer(bmtMFDescs));
3530 PRECONDITION(CheckPointer(bmtMetaData));
3531 PRECONDITION(CheckPointer(bmtVT));
3532 PRECONDITION(CheckPointer(bmtEnumFields));
3533 PRECONDITION(CheckPointer(bmtFP));
3534 PRECONDITION(CheckPointer(bmtParent));
3539 // We'll be counting the # fields of each size as we go along
3540 for (DWORD i = 0; i <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++)
3542 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
3543 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
3544 bmtFP->NumInstanceFieldsOfSize[i] = 0;
3548 // Allocate blocks of MethodDescs and FieldDescs for all declared methods and fields
3550 // In order to avoid allocating a field pointing back to the method
3551 // table in every single method desc, we allocate memory in the
3552 // following manner:
3553 // o Field descs get a single contiguous block.
3554 // o Method descs of different sizes (normal vs NDirect) are
3555 // allocated in different MethodDescChunks.
3556 // o Each method desc chunk starts with a header, and has
3557 // at most MAX_ method descs (if there are more
3558 // method descs of a given size, multiple chunks are allocated).
3559 // This way method descs can use an 8-bit offset field to locate the
3560 // pointer to their method table.
3563 /////////////////////////////////////////////////////////////////
3565 if (NumDeclaredFields() > 0)
3567 GetHalfBakedClass()->SetFieldDescList((FieldDesc *)
3568 AllocateFromHighFrequencyHeap(S_SIZE_T(NumDeclaredFields()) * S_SIZE_T(sizeof(FieldDesc))));
3569 INDEBUG(GetClassLoader()->m_dwDebugFieldDescs += NumDeclaredFields();)
3570 INDEBUG(GetClassLoader()->m_dwFieldDescData += (NumDeclaredFields() * sizeof(FieldDesc));)
3574 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
3575 //*******************************************************************************
3577 // Heuristic to determine if we should have instances of this class 8 byte aligned
3579 BOOL MethodTableBuilder::ShouldAlign8(DWORD dwR8Fields, DWORD dwTotalFields)
3581 LIMITED_METHOD_CONTRACT;
3583 return dwR8Fields*2>dwTotalFields && dwR8Fields>=2;
3587 //*******************************************************************************
3588 BOOL MethodTableBuilder::IsSelfReferencingStaticValueTypeField(mdToken dwByValueClassToken,
3589 bmtInternalInfo* bmtInternal,
3590 const bmtGenericsInfo *bmtGenerics,
3591 PCCOR_SIGNATURE pMemberSignature,
3592 DWORD cMemberSignature)
3594 STANDARD_VM_CONTRACT;
3596 if (dwByValueClassToken != this->GetCl())
3601 if (!bmtGenerics->HasInstantiation())
3606 // The value class is generic. Check that the signature of the field
3607 // is _exactly_ equivalent to VC<!0, !1, !2, ...>. Do this by consing up a fake
3609 DWORD nGenericArgs = bmtGenerics->GetNumGenericArgs();
3610 CONSISTENCY_CHECK(nGenericArgs != 0);
3612 SigBuilder sigBuilder;
3614 sigBuilder.AppendElementType(ELEMENT_TYPE_GENERICINST);
3615 sigBuilder.AppendElementType(ELEMENT_TYPE_VALUETYPE);
3616 sigBuilder.AppendToken(dwByValueClassToken);
3617 sigBuilder.AppendData(nGenericArgs);
3618 for (unsigned int typearg = 0; typearg < nGenericArgs; typearg++)
3620 sigBuilder.AppendElementType(ELEMENT_TYPE_VAR);
3621 sigBuilder.AppendData(typearg);
3625 PCCOR_SIGNATURE pFakeSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cFakeSig);
3627 PCCOR_SIGNATURE pFieldSig = pMemberSignature + 1; // skip the CALLCONV_FIELD
3629 return MetaSig::CompareElementType(pFakeSig, pFieldSig,
3630 pFakeSig + cFakeSig, pMemberSignature + cMemberSignature,
3631 GetModule(), GetModule(),
3636 //*******************************************************************************
3638 // Used pByValueClass cache to mark self-references
3640 static BOOL IsSelfRef(MethodTable * pMT)
3642 return pMT == (MethodTable *)-1;
3645 //*******************************************************************************
3647 // Used by BuildMethodTable
3649 // Go thru all fields and initialize their FieldDescs.
3652 #pragma warning(push)
3653 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3656 VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
3657 const LayoutRawFieldInfo* pLayoutRawFieldInfos,
3658 bmtInternalInfo* bmtInternal,
3659 const bmtGenericsInfo* bmtGenerics,
3660 bmtMetaDataInfo* bmtMetaData,
3661 bmtEnumFieldInfo* bmtEnumFields,
3662 bmtErrorInfo* bmtError,
3663 MethodTable *** pByValueClassCache,
3664 bmtMethAndFieldDescs* bmtMFDescs,
3665 bmtFieldPlacement* bmtFP,
3666 unsigned* totalDeclaredSize)
3671 PRECONDITION(CheckPointer(this));
3672 PRECONDITION(CheckPointer(bmtInternal));
3673 PRECONDITION(CheckPointer(bmtGenerics));
3674 PRECONDITION(CheckPointer(bmtMetaData));
3675 PRECONDITION(CheckPointer(bmtEnumFields));
3676 PRECONDITION(CheckPointer(bmtError));
3677 PRECONDITION(CheckPointer(pByValueClassCache));
3678 PRECONDITION(CheckPointer(bmtMFDescs));
3679 PRECONDITION(CheckPointer(bmtFP));
3680 PRECONDITION(CheckPointer(totalDeclaredSize));
3685 IMDInternalImport * pInternalImport = GetMDImport(); // to avoid multiple dereferencings
3687 FieldMarshaler * pNextFieldMarshaler = NULL;
3690 pNextFieldMarshaler = (FieldMarshaler*)(GetLayoutInfo()->GetFieldMarshalers());
3694 //========================================================================
3696 // Go thru all fields and initialize their FieldDescs.
3697 //========================================================================
3699 DWORD dwCurrentDeclaredField = 0;
3700 DWORD dwCurrentStaticField = 0;
3701 DWORD dwCurrentThreadStaticField = 0;
3704 DWORD dwR8Fields = 0; // Number of R8's the class has
3706 #ifdef FEATURE_64BIT_ALIGNMENT
3707 // Track whether any field in this type requires 8-byte alignment
3708 BOOL fFieldRequiresAlign8 = HasParent() ? GetParentMethodTable()->RequiresAlign8() : FALSE;
3711 for (i = 0; i < bmtMetaData->cFields; i++)
3713 PCCOR_SIGNATURE pMemberSignature;
3714 DWORD cMemberSignature;
3715 DWORD dwMemberAttrs;
3717 dwMemberAttrs = bmtMetaData->pFieldAttrs[i];
3719 BOOL fIsStatic = IsFdStatic(dwMemberAttrs);
3721 // We don't store static final primitive fields in the class layout
3722 if (IsFdLiteral(dwMemberAttrs))
3725 if (!IsFdPublic(dwMemberAttrs))
3726 SetHasNonPublicFields();
3728 if (IsFdNotSerialized(dwMemberAttrs))
3729 SetCannotBeBlittedByObjectCloner();
3731 IfFailThrow(pInternalImport->GetSigOfFieldDef(bmtMetaData->pFields[i], &cMemberSignature, &pMemberSignature));
3732 // Signature validation
3733 IfFailThrow(validateTokenSig(bmtMetaData->pFields[i],pMemberSignature,cMemberSignature,dwMemberAttrs,pInternalImport));
3736 DWORD dwLog2FieldSize = 0;
3737 BOOL bCurrentFieldIsGCPointer = FALSE;
3738 mdToken dwByValueClassToken = 0;
3739 MethodTable * pByValueClass = NULL;
3740 BOOL fIsByValue = FALSE;
3741 BOOL fIsThreadStatic = FALSE;
3742 BOOL fHasRVA = FALSE;
3744 MetaSig fsig(pMemberSignature,
3747 &bmtGenerics->typeContext,
3749 CorElementType ElementType = fsig.NextArg();
3753 if (!isCallConv(fsig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_FIELD))
3755 IfFailThrow(COR_E_TYPELOAD);
3758 // Determine if a static field is special i.e. RVA based, local to
3759 // a thread or a context
3762 if (IsFdHasFieldRVA(dwMemberAttrs))
3769 hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
3770 g_ThreadStaticAttributeClassName,
3775 fIsThreadStatic = TRUE;
3779 if (ElementType == ELEMENT_TYPE_VALUETYPE)
3781 hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
3782 g_CompilerServicesFixedAddressValueTypeAttribute,
3787 bmtFP->fHasFixedAddressValueTypes = true;
3792 // Do some sanity checks that we are not mixing context and thread
3793 // relative statics.
3794 if (fHasRVA && fIsThreadStatic)
3796 IfFailThrow(COR_E_TYPELOAD);
3799 if (bmtFP->fHasFixedAddressValueTypes && GetAssembly()->IsCollectible())
3801 BuildMethodTableThrowException(IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR);
3807 // Type to store in FieldDesc - we don't want to have extra case statements for
3808 // ELEMENT_TYPE_STRING, SDARRAY etc., so we convert all object types to CLASS.
3809 // Also, BOOLEAN, CHAR are converted to U1, I2.
3810 CorElementType FieldDescElementType = ElementType;
3812 switch (ElementType)
3814 case ELEMENT_TYPE_I1:
3815 case ELEMENT_TYPE_U1:
3817 dwLog2FieldSize = 0;
3821 case ELEMENT_TYPE_I2:
3822 case ELEMENT_TYPE_U2:
3824 dwLog2FieldSize = 1;
3828 case ELEMENT_TYPE_I4:
3829 case ELEMENT_TYPE_U4:
3830 IN_TARGET_32BIT(case ELEMENT_TYPE_I:)
3831 IN_TARGET_32BIT(case ELEMENT_TYPE_U:)
3832 case ELEMENT_TYPE_R4:
3834 dwLog2FieldSize = 2;
3838 case ELEMENT_TYPE_BOOLEAN:
3840 // FieldDescElementType = ELEMENT_TYPE_U1;
3841 dwLog2FieldSize = 0;
3845 case ELEMENT_TYPE_CHAR:
3847 // FieldDescElementType = ELEMENT_TYPE_U2;
3848 dwLog2FieldSize = 1;
3852 case ELEMENT_TYPE_R8:
3856 // Deliberate fall through...
3859 case ELEMENT_TYPE_I8:
3860 case ELEMENT_TYPE_U8:
3861 IN_TARGET_64BIT(case ELEMENT_TYPE_I:)
3862 IN_TARGET_64BIT(case ELEMENT_TYPE_U:)
3864 #ifdef FEATURE_64BIT_ALIGNMENT
3865 // Record that this field requires alignment for Int64/UInt64.
3867 fFieldRequiresAlign8 = true;
3869 dwLog2FieldSize = 3;
3873 case ELEMENT_TYPE_FNPTR:
3874 case ELEMENT_TYPE_PTR: // ptrs are unmanaged scalars, for layout
3876 dwLog2FieldSize = LOG2_PTRSIZE;
3880 // Class type variable (method type variables aren't allowed in fields)
3881 // These only occur in open types used for verification/reflection.
3882 case ELEMENT_TYPE_VAR:
3883 case ELEMENT_TYPE_MVAR:
3884 // deliberate drop through - do fake field layout
3885 case ELEMENT_TYPE_STRING:
3886 case ELEMENT_TYPE_SZARRAY: // single dim, zero
3887 case ELEMENT_TYPE_ARRAY: // all other arrays
3888 case ELEMENT_TYPE_CLASS: // objectrefs
3889 case ELEMENT_TYPE_OBJECT:
3891 dwLog2FieldSize = LOG2_PTRSIZE;
3892 bCurrentFieldIsGCPointer = TRUE;
3893 FieldDescElementType = ELEMENT_TYPE_CLASS;
3897 SetHasFieldsWhichMustBeInited();
3898 if (ElementType != ELEMENT_TYPE_STRING)
3899 SetCannotBeBlittedByObjectCloner();
3902 { // EnumerateFieldDescs already counted the total number of static vs. instance
3903 // fields, now we're further subdividing the static field count by GC and non-GC.
3904 bmtEnumFields->dwNumStaticObjRefFields++;
3905 if (fIsThreadStatic)
3906 bmtEnumFields->dwNumThreadStaticObjRefFields++;
3911 case ELEMENT_TYPE_VALUETYPE: // a byvalue class field
3913 Module * pTokenModule;
3914 dwByValueClassToken = fsig.GetArgProps().PeekValueTypeTokenClosed(GetModule(), &bmtGenerics->typeContext, &pTokenModule);
3918 BAD_FORMAT_NOTHROW_ASSERT(dwByValueClassToken != 0);
3920 if (this->IsValueClass() && (pTokenModule == GetModule()))
3922 if (TypeFromToken(dwByValueClassToken) == mdtTypeRef)
3924 // It's a typeref - check if it's a class that has a static field of itself
3925 LPCUTF8 pszNameSpace;
3926 LPCUTF8 pszClassName;
3927 if (FAILED(pInternalImport->GetNameOfTypeRef(dwByValueClassToken, &pszNameSpace, &pszClassName)))
3929 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
3932 if (IsStrLongerThan((char *)pszClassName, MAX_CLASS_NAME)
3933 || IsStrLongerThan((char *)pszNameSpace, MAX_CLASS_NAME)
3934 || (strlen(pszClassName) + strlen(pszNameSpace) + 1 >= MAX_CLASS_NAME))
3936 BuildMethodTableThrowException(BFA_TYPEREG_NAME_TOO_LONG, mdMethodDefNil);
3940 if (FAILED(pInternalImport->GetResolutionScopeOfTypeRef(dwByValueClassToken, &tkRes)))
3942 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, dwByValueClassToken);
3945 if (TypeFromToken(tkRes) == mdtTypeRef)
3947 if (!pInternalImport->IsValidToken(tkRes))
3949 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, mdMethodDefNil);
3957 if (FAILED(pInternalImport->FindTypeDef(pszNameSpace,
3960 &dwByValueClassToken)))
3962 dwByValueClassToken = mdTokenNil;
3964 } // If field is static typeref
3966 BOOL selfref = IsSelfReferencingStaticValueTypeField(dwByValueClassToken,
3973 { // immediately self-referential fields must be static.
3976 BuildMethodTableThrowException(IDS_CLASSLOAD_VALUEINSTANCEFIELD, mdMethodDefNil);
3979 if (!IsValueClass())
3981 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_MUST_BE_BYVAL, mdTokenNil);
3984 pByValueClass = (MethodTable *)-1;
3986 } // If 'this' is a value class
3988 // It's not self-referential so try to load it
3989 if (pByValueClass == NULL)
3991 // Loading a non-self-ref valuetype field.
3992 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
3993 // We load the approximate type of the field to avoid recursion problems.
3994 // MethodTable::DoFullyLoad() will later load it fully
3995 pByValueClass = fsig.GetArgProps().GetTypeHandleThrowing(GetModule(),
3996 &bmtGenerics->typeContext,
3997 ClassLoader::LoadTypes,
3998 CLASS_LOAD_APPROXPARENTS,
4003 // #FieldDescTypeMorph IF it is an enum, strip it down to its underlying type
4004 if (IsSelfRef(pByValueClass) ? IsEnum() : pByValueClass->IsEnum())
4006 if (IsSelfRef(pByValueClass))
4007 { // It is self-referencing enum (ValueType) static field - it is forbidden in the ECMA spec, but supported by CLR since v1
4008 // Note: literal static fields are skipped early in this loop
4009 if (bmtMFDescs->ppFieldDescList[0] == NULL)
4010 { // The field is defined before (the only) instance field
4011 // AppCompat with 3.5 SP1 and 4.0 RTM behavior
4012 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4014 // We will treat the field type as if it was its underlying type (we know its size and will check correctly RVA with the size
4015 // later in this method)
4016 // Therefore we do not have to run code:VerifySelfReferencingStaticValueTypeFields_WithRVA or code:#SelfReferencingStaticValueTypeField_Checks
4018 BAD_FORMAT_NOTHROW_ASSERT((IsSelfRef(pByValueClass) ?
4019 bmtEnumFields->dwNumInstanceFields : pByValueClass->GetNumInstanceFields())
4020 == 1); // enums must have exactly one field
4021 FieldDesc * enumField = IsSelfRef(pByValueClass) ?
4022 bmtMFDescs->ppFieldDescList[0] : pByValueClass->GetApproxFieldDescListRaw();
4023 BAD_FORMAT_NOTHROW_ASSERT(!enumField->IsStatic()); // no real static fields on enums
4024 ElementType = enumField->GetFieldType();
4025 BAD_FORMAT_NOTHROW_ASSERT(ElementType != ELEMENT_TYPE_VALUETYPE);
4026 fIsByValue = FALSE; // we're going to treat it as the underlying type now
4027 goto GOT_ELEMENT_TYPE;
4030 // Check ByRefLike fields
4031 if (!IsSelfRef(pByValueClass) && pByValueClass->IsByRefLike())
4035 // Byref-like types cannot be used for static fields
4036 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_STATICFIELD);
4038 if (!bmtFP->fIsByRefLikeType)
4040 // Non-byref-like types cannot contain byref-like instance fields
4041 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_INSTANCEFIELD);
4045 if (!IsSelfRef(pByValueClass) && pByValueClass->GetClass()->HasNonPublicFields())
4046 { // If a class has a field of type ValueType with non-public fields in it,
4047 // the class must "inherit" this characteristic
4048 SetHasNonPublicFields();
4055 // Inherit instance attributes
4056 EEClass * pFieldClass = pByValueClass->GetClass();
4058 #ifdef FEATURE_64BIT_ALIGNMENT
4059 // If a value type requires 8-byte alignment this requirement must be inherited by any
4060 // class/struct that embeds it as a field.
4061 if (pFieldClass->IsAlign8Candidate())
4062 fFieldRequiresAlign8 = true;
4064 if (pFieldClass->HasNonPublicFields())
4065 SetHasNonPublicFields();
4066 if (pFieldClass->HasFieldsWhichMustBeInited())
4067 SetHasFieldsWhichMustBeInited();
4069 #ifdef FEATURE_READYTORUN
4070 if (!(pByValueClass->IsTruePrimitive() || pByValueClass->IsEnum()))
4072 CheckLayoutDependsOnOtherModules(pByValueClass);
4077 { // Increment the number of static fields that contain object references.
4078 bmtEnumFields->dwNumStaticBoxedFields++;
4079 if (fIsThreadStatic)
4080 bmtEnumFields->dwNumThreadStaticBoxedFields++;
4084 if (*pByValueClassCache == NULL)
4086 DWORD dwNumFields = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields;
4088 *pByValueClassCache = new (GetStackingAllocator()) MethodTable * [dwNumFields];
4089 memset (*pByValueClassCache, 0, dwNumFields * sizeof(MethodTable **));
4092 // Thread static fields come after instance fields and regular static fields in this list
4093 if (fIsThreadStatic)
4095 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField] = pByValueClass;
4096 // make sure to record the correct size for static field
4098 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4100 // Regular static fields come after instance fields in this list
4103 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField] = pByValueClass;
4104 // make sure to record the correct size for static field
4106 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4110 (*pByValueClassCache)[dwCurrentDeclaredField] = pByValueClass;
4111 dwLog2FieldSize = 0; // unused
4118 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4124 pFD = &pFieldDescList[dwCurrentDeclaredField];
4125 *totalDeclaredSize += (1 << dwLog2FieldSize);
4127 else /* (dwMemberAttrs & mdStatic) */
4129 if (fIsThreadStatic)
4131 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField];
4135 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField];
4139 bmtMFDescs->ppFieldDescList[i] = pFD;
4141 const LayoutRawFieldInfo *pLayoutFieldInfo = NULL;
4145 const LayoutRawFieldInfo *pwalk = pLayoutRawFieldInfos;
4146 while (pwalk->m_MD != mdFieldDefNil)
4148 if (pwalk->m_MD == bmtMetaData->pFields[i])
4150 pLayoutFieldInfo = pwalk;
4152 const FieldMarshaler *pSrcFieldMarshaler = (const FieldMarshaler *) &pwalk->m_FieldMarshaler;
4154 pSrcFieldMarshaler->CopyTo(pNextFieldMarshaler, MAXFIELDMARSHALERSIZE);
4156 pNextFieldMarshaler->SetFieldDesc(pFD);
4157 pNextFieldMarshaler->SetExternalOffset(pwalk->m_offset);
4159 ((BYTE*&)pNextFieldMarshaler) += MAXFIELDMARSHALERSIZE;
4166 LPCSTR pszFieldName = NULL;
4168 if (FAILED(pInternalImport->GetNameOfFieldDef(bmtMetaData->pFields[i], &pszFieldName)))
4170 pszFieldName = "Invalid FieldDef record";
4173 // #InitCall Initialize contents of the field descriptor called from
4175 bmtMetaData->pFields[i],
4176 FieldDescElementType,
4184 // We're using FieldDesc::m_pMTOfEnclosingClass to temporarily store the field's size.
4189 (IsBlittable() || HasExplicitFieldOffsetLayout()))
4191 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4192 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4194 if (pLayoutFieldInfo)
4195 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
4197 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4199 else if (!fIsStatic && IsManagedSequential())
4201 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4202 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4204 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
4208 // static value class fields hold a handle, which is ptr sized
4209 // (instance field layout ignores this value)
4210 (DWORD_PTR&)(pFD->m_pMTOfEnclosingClass) = LOG2_PTRSIZE;
4211 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4216 (DWORD_PTR &)(pFD->m_pMTOfEnclosingClass) = (size_t)dwLog2FieldSize;
4218 // -1 (FIELD_OFFSET_UNPLACED) means that this is a non-GC field that has not yet been placed
4219 // -2 (FIELD_OFFSET_UNPLACED_GC_PTR) means that this is a GC pointer field that has not yet been placed
4221 // If there is any kind of explicit layout information for this field, use it. If not, then
4222 // mark it as either GC or non-GC and as unplaced; it will get placed later on in an optimized way.
4224 if ((IsBlittable() || HasExplicitFieldOffsetLayout()) && !fIsStatic)
4225 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
4226 else if (IsManagedSequential() && !fIsStatic)
4227 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
4228 else if (bCurrentFieldIsGCPointer)
4229 pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR);
4231 pFD->SetOffset(FIELD_OFFSET_UNPLACED);
4238 if (++bmtFP->NumInstanceFieldsOfSize[dwLog2FieldSize] == 1)
4239 bmtFP->FirstInstanceFieldOfSize[dwLog2FieldSize] = dwCurrentDeclaredField;
4242 dwCurrentDeclaredField++;
4244 if (bCurrentFieldIsGCPointer)
4246 bmtFP->NumInstanceGCPointerFields++;
4249 else /* static fields */
4251 // Static fields are stored in the vtable after the vtable and interface slots. We don't
4252 // know how large the vtable will be, so we will have to fixup the slot number by
4253 // <vtable + interface size> later.
4255 if (fIsThreadStatic)
4257 dwCurrentThreadStaticField++;
4261 dwCurrentStaticField++;
4266 if (FieldDescElementType == ELEMENT_TYPE_CLASS)
4267 { // RVA fields are not allowed to have GC pointers.
4268 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4269 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4271 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4273 if (IsSelfRef(pByValueClass))
4274 { // We will verify self-referencing statics after the loop through all fields - see code:#SelfReferencingStaticValueTypeField_Checks
4275 bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA = TRUE;
4279 if (pByValueClass->GetClass()->HasFieldsWhichMustBeInited())
4280 { // RVA fields are not allowed to have GC pointers.
4281 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4282 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4287 // Set the field offset
4289 IfFailThrow(pInternalImport->GetFieldRVA(pFD->GetMemberDef(), &rva));
4291 // Ensure that the IL image is loaded. Note that this assembly may
4292 // have an ngen image, but this type may have failed to load during ngen.
4293 GetModule()->GetFile()->LoadLibrary(FALSE);
4296 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4298 if (IsSelfRef(pByValueClass))
4300 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4302 // We do not known the size yet
4303 _ASSERTE(bmtFP->NumInstanceFieldBytes == 0);
4304 // We will check just the RVA with size 0 now, the full size verification will happen in code:VerifySelfReferencingStaticValueTypeFields_WithRVA
4309 fldSize = pByValueClass->GetNumInstanceFieldBytes();
4314 fldSize = GetSizeForCorElementType(FieldDescElementType);
4317 pFD->SetOffsetRVA(rva);
4319 else if (fIsThreadStatic)
4321 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
4323 if (bCurrentFieldIsGCPointer)
4324 bmtFP->NumThreadStaticGCPointerFields++;
4327 bmtFP->NumThreadStaticGCBoxedFields++;
4331 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
4333 if (bCurrentFieldIsGCPointer)
4334 bmtFP->NumRegularStaticGCPointerFields++;
4337 bmtFP->NumRegularStaticGCBoxedFields++;
4341 // We processed all fields
4343 //#SelfReferencingStaticValueTypeField_Checks
4344 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
4345 { // The type has self-referencing static ValueType field with RVA, do more checks now that depend on all fields being processed
4347 // For enums we already checked its underlying type, we should not get here
4348 _ASSERTE(!IsEnum());
4350 if (HasFieldsWhichMustBeInited())
4351 { // RVA fields are not allowed to have GC pointers.
4352 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA self-referencing static field");
4353 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4357 DWORD dwNumInstanceFields = dwCurrentDeclaredField + (HasParent() ? GetParentMethodTable()->GetNumInstanceFields() : 0);
4358 DWORD dwNumStaticFields = bmtEnumFields->dwNumStaticFields;
4359 DWORD dwNumThreadStaticFields = bmtEnumFields->dwNumThreadStaticFields;
4361 if (!FitsIn<WORD>(dwNumInstanceFields) ||
4362 !FitsIn<WORD>(dwNumStaticFields))
4363 { // An implementation limitation means that it's an error if there are greater that MAX_WORD fields.
4364 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
4367 GetHalfBakedClass()->SetNumInstanceFields((WORD)dwNumInstanceFields);
4368 GetHalfBakedClass()->SetNumStaticFields((WORD)dwNumStaticFields);
4369 GetHalfBakedClass()->SetNumThreadStaticFields((WORD)dwNumThreadStaticFields);
4371 if (bmtFP->fHasFixedAddressValueTypes)
4373 // To make things simpler, if the class has any field with this requirement, we'll set
4374 // all the statics to have this property. This allows us to only need to persist one bit
4375 // for the ngen case.
4376 GetHalfBakedClass()->SetHasFixedAddressVTStatics();
4379 #ifdef FEATURE_64BIT_ALIGNMENT
4380 // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8
4381 // bytes (this mimics what the native compiler does and ensures we match up calling conventions during
4383 if (HasLayout() && GetLayoutInfo()->GetPackingSize() < 8)
4385 fFieldRequiresAlign8 = false;
4388 if (fFieldRequiresAlign8)
4390 SetAlign8Candidate();
4392 #endif // FEATURE_64BIT_ALIGNMENT
4394 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
4395 if (ShouldAlign8(dwR8Fields, dwNumInstanceFields))
4397 SetAlign8Candidate();
4399 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
4402 //========================================================================
4404 // Go thru all fields and initialize their FieldDescs.
4405 //========================================================================
4408 } // MethodTableBuilder::InitializeFieldDescs
4411 #pragma warning(pop)
4414 //*******************************************************************************
4415 // Verify self-referencing static ValueType fields with RVA (when the size of the ValueType is known).
4417 MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA(
4418 MethodTable ** pByValueClassCache)
4420 STANDARD_VM_CONTRACT;
4422 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4423 // Enum's static self-referencing fields have been verified as the underlying type of the enum, we should not get here for them
4424 _ASSERTE(!IsEnum());
4425 // The size of the ValueType should be known at this point (the caller throws if it is 0)
4426 _ASSERTE(bmtFP->NumInstanceFieldBytes != 0);
4428 FieldDesc * pFieldDescList = GetApproxFieldDescListRaw();
4429 DWORD nFirstThreadStaticFieldIndex = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields;
4430 for (DWORD i = bmtEnumFields->dwNumInstanceFields; i < nFirstThreadStaticFieldIndex; i++)
4432 FieldDesc * pFD = &pFieldDescList[i];
4433 _ASSERTE(pFD->IsStatic());
4435 if (pFD->IsRVA() && pFD->IsByValue())
4437 _ASSERTE(pByValueClassCache[i] != NULL);
4439 if (IsSelfRef(pByValueClassCache[i]))
4442 IfFailThrow(GetMDImport()->GetFieldRVA(pFD->GetMemberDef(), &rva));
4446 } // MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA
4448 //*******************************************************************************
4449 // Returns true if hEnclosingTypeCandidate encloses, at any arbitrary depth,
4450 // hNestedTypeCandidate; returns false otherwise.
4452 bool MethodTableBuilder::IsEnclosingNestedTypePair(
4453 bmtTypeHandle hEnclosingTypeCandidate,
4454 bmtTypeHandle hNestedTypeCandidate)
4456 STANDARD_VM_CONTRACT;
4458 CONSISTENCY_CHECK(!hEnclosingTypeCandidate.IsNull());
4459 CONSISTENCY_CHECK(!hNestedTypeCandidate.IsNull());
4460 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hEnclosingTypeCandidate, hNestedTypeCandidate));
4462 Module * pModule = hEnclosingTypeCandidate.GetModule();
4464 if (pModule != hNestedTypeCandidate.GetModule())
4465 { // If the modules aren't the same, then there's no way
4466 // hBase could be an enclosing type of hChild. We make
4467 // this check early so that the code can deal with only
4468 // one Module and IMDInternalImport instance and can avoid
4473 IMDInternalImport * pMDImport = pModule->GetMDImport();
4475 mdTypeDef tkEncl = hEnclosingTypeCandidate.GetTypeDefToken();
4476 mdTypeDef tkNest = hNestedTypeCandidate.GetTypeDefToken();
4478 while (tkEncl != tkNest)
4479 { // Do this using the metadata APIs because MethodTableBuilder does
4480 // not construct type representations for enclosing type chains.
4481 if (FAILED(pMDImport->GetNestedClassProps(tkNest, &tkNest)))
4482 { // tokNest is not a nested type.
4487 // tkNest's enclosing type is tkEncl, so we've shown that
4488 // hEnclosingTypeCandidate encloses hNestedTypeCandidate
4492 //*******************************************************************************
4493 // Given an arbitrary nesting+subclassing pattern like this:
4496 // private virtual void Foo() { ... }
4499 // class CN : CN-1 {
4500 // private override void Foo() { ... }
4506 // this method will return true, where hChild == N and hBase == C1
4508 // Note that there is no requirement that a type derive from its immediately
4509 // enclosing type, but can skip a level, such as this example:
4513 // private virtual void Foo() { }
4516 // public class C : A
4518 // private override void Foo() { }
4523 // NOTE: IMPORTANT: This code assumes that hBase is indeed a base type of hChild,
4524 // and behaviour is undefined if this is not the case.
4526 bool MethodTableBuilder::IsBaseTypeAlsoEnclosingType(
4527 bmtTypeHandle hBase,
4528 bmtTypeHandle hChild)
4530 STANDARD_VM_CONTRACT;
4532 CONSISTENCY_CHECK(!hBase.IsNull());
4533 CONSISTENCY_CHECK(!hChild.IsNull());
4534 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hBase, hChild));
4536 // The idea of this algorithm is that if we climb the inheritance chain
4537 // starting at hChild then we'll eventually hit hBase. If we check that
4538 // for every (hParent, hChild) pair in the chain that hParent encloses
4539 // hChild, then we've shown that hBase encloses hChild.
4541 while (!bmtTypeHandle::Equal(hBase, hChild))
4543 CONSISTENCY_CHECK(!hChild.GetParentType().IsNull());
4544 bmtTypeHandle hParent(hChild.GetParentType());
4546 if (!IsEnclosingNestedTypePair(hParent, hChild))
4547 { // First, the parent type must enclose the child type.
4548 // If this is not the case we fail immediately.
4552 // Move up one in the inheritance chain, and try again.
4556 // If the loop worked itself from the original hChild all the way
4557 // up to hBase, then we know that for every (hParent, hChild)
4558 // pair in the chain that hParent enclosed hChild, and so we know
4559 // that hBase encloses the original hChild
4563 //*******************************************************************************
4564 BOOL MethodTableBuilder::TestOverrideForAccessibility(
4565 bmtMethodHandle hParentMethod,
4566 bmtTypeHandle hChildType)
4568 STANDARD_VM_CONTRACT;
4570 bmtTypeHandle hParentType(hParentMethod.GetOwningType());
4572 Module * pParentModule = hParentType.GetModule();
4573 Module * pChildModule = hChildType.GetModule();
4575 Assembly * pParentAssembly = pParentModule->GetAssembly();
4576 Assembly * pChildAssembly = pChildModule->GetAssembly();
4578 BOOL isSameAssembly = (pChildAssembly == pParentAssembly);
4580 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4582 // AKA "strict bit". This means that overridability is tightly bound to accessibility.
4583 if (IsMdCheckAccessOnOverride(dwParentAttrs))
4586 if (isSameAssembly || pParentAssembly->GrantsFriendAccessTo(pChildAssembly, hParentMethod.GetMethodDesc())
4587 || pChildAssembly->IgnoresAccessChecksTo(pParentAssembly))
4589 // Can always override any method that has accessibility greater than mdPrivate
4590 if ((dwParentAttrs & mdMemberAccessMask) > mdPrivate)
4593 // Generally, types cannot override inherited mdPrivate methods, except:
4594 // Types can access enclosing type's private members, so it can
4595 // override them if the nested type extends its enclosing type.
4596 else if ((dwParentAttrs & mdMemberAccessMask) == mdPrivate &&
4597 IsBaseTypeAlsoEnclosingType(hParentType, hChildType))
4608 // If the method marks itself as check visibility the the method must be
4609 // public, FamORAssem, or family
4610 if((dwParentAttrs & mdMemberAccessMask) <= mdAssem)
4619 //*******************************************************************************
4620 VOID MethodTableBuilder::TestOverRide(bmtMethodHandle hParentMethod,
4621 bmtMethodHandle hChildMethod)
4625 PRECONDITION(IsMdVirtual(hParentMethod.GetDeclAttrs()));
4626 PRECONDITION(IsMdVirtual(hChildMethod.GetDeclAttrs()));
4629 DWORD dwAttrs = hChildMethod.GetDeclAttrs();
4630 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4632 Module *pModule = hChildMethod.GetOwningType().GetModule();
4633 Module *pParentModule = hParentMethod.GetOwningType().GetModule();
4635 Assembly *pAssembly = pModule->GetAssembly();
4636 Assembly *pParentAssembly = pParentModule->GetAssembly();
4638 BOOL isSameModule = (pModule == pParentModule);
4639 BOOL isSameAssembly = (pAssembly == pParentAssembly);
4641 if (!TestOverrideForAccessibility(hParentMethod, hChildMethod.GetOwningType()))
4643 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, hChildMethod.GetMethodSignature().GetToken());
4647 // Refer to Partition II, 9.3.3 for more information on what is permitted.
4650 enum WIDENING_STATUS
4654 e_SA, // YES, but only when same assembly
4655 e_NSA, // YES, but only when NOT same assembly
4656 e_SM, // YES, but only when same module
4659 static_assert_no_msg(mdPrivateScope == 0x00);
4660 static_assert_no_msg(mdPrivate == 0x01);
4661 static_assert_no_msg(mdFamANDAssem == 0x02);
4662 static_assert_no_msg(mdAssem == 0x03);
4663 static_assert_no_msg(mdFamily == 0x04);
4664 static_assert_no_msg(mdFamORAssem == 0x05);
4665 static_assert_no_msg(mdPublic == 0x06);
4667 static const DWORD dwCount = mdPublic - mdPrivateScope + 1;
4668 static const WIDENING_STATUS rgWideningTable[dwCount][dwCount] =
4671 // Subtype | mdPrivateScope mdPrivate mdFamANDAssem mdAssem mdFamily mdFamORAssem mdPublic
4672 // --------------+-------------------------------------------------------------------------------------------------------
4673 /*mdPrivateScope | */ { { e_SM, e_NO, e_NO, e_NO, e_NO, e_NO, e_NO },
4674 /*mdPrivate | */ { e_SM, e_YES, e_NO, e_NO, e_NO, e_NO, e_NO },
4675 /*mdFamANDAssem | */ { e_SM, e_YES, e_SA, e_NO, e_NO, e_NO, e_NO },
4676 /*mdAssem | */ { e_SM, e_YES, e_SA, e_SA, e_NO, e_NO, e_NO },
4677 /*mdFamily | */ { e_SM, e_YES, e_YES, e_NO, e_YES, e_NSA, e_NO },
4678 /*mdFamORAssem | */ { e_SM, e_YES, e_YES, e_SA, e_YES, e_YES, e_NO },
4679 /*mdPublic | */ { e_SM, e_YES, e_YES, e_YES, e_YES, e_YES, e_YES } };
4681 DWORD idxParent = (dwParentAttrs & mdMemberAccessMask) - mdPrivateScope;
4682 DWORD idxMember = (dwAttrs & mdMemberAccessMask) - mdPrivateScope;
4683 CONSISTENCY_CHECK(idxParent < dwCount);
4684 CONSISTENCY_CHECK(idxMember < dwCount);
4686 WIDENING_STATUS entry = rgWideningTable[idxMember][idxParent];
4688 if (entry == e_NO ||
4689 (entry == e_SA && !isSameAssembly && !pParentAssembly->GrantsFriendAccessTo(pAssembly, hParentMethod.GetMethodDesc())
4690 && !pAssembly->IgnoresAccessChecksTo(pParentAssembly)) ||
4691 (entry == e_NSA && isSameAssembly) ||
4692 (entry == e_SM && !isSameModule)
4695 BuildMethodTableThrowException(IDS_CLASSLOAD_REDUCEACCESS, hChildMethod.GetMethodSignature().GetToken());
4701 //*******************************************************************************
4702 VOID MethodTableBuilder::TestMethodImpl(
4703 bmtMethodHandle hDeclMethod,
4704 bmtMethodHandle hImplMethod)
4709 PRECONDITION(!hDeclMethod.IsNull());
4710 PRECONDITION(!hImplMethod.IsNull());
4714 Module * pDeclModule = hDeclMethod.GetOwningType().GetModule();
4715 Module * pImplModule = hImplMethod.GetOwningType().GetModule();
4717 mdTypeDef tokDecl = hDeclMethod.GetMethodSignature().GetToken();
4718 mdTypeDef tokImpl = hImplMethod.GetMethodSignature().GetToken();
4720 BOOL isSameModule = pDeclModule->Equals(pImplModule);
4722 IMDInternalImport *pIMDDecl = pDeclModule->GetMDImport();
4723 IMDInternalImport *pIMDImpl = pImplModule->GetMDImport();
4726 if (FAILED(pIMDDecl->GetMethodDefProps(tokDecl, &dwDeclAttrs)))
4728 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4731 if (FAILED(pIMDImpl->GetMethodDefProps(tokImpl, &dwImplAttrs)))
4733 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4736 HRESULT hr = COR_E_TYPELOAD;
4738 if (!IsMdVirtual(dwDeclAttrs))
4740 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NONVIRTUAL_DECL);
4742 if (!IsMdVirtual(dwImplAttrs))
4744 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL);
4746 // Virtual methods cannot be static
4747 if (IsMdStatic(dwDeclAttrs))
4749 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4751 if (IsMdStatic(dwImplAttrs))
4753 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4755 if (IsMdFinal(dwDeclAttrs))
4757 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL);
4760 // Interface method body that has methodimpl should always be final
4761 if (IsInterface() && !IsMdFinal(dwImplAttrs))
4763 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_IMPL);
4766 // Since MethodImpl's do not affect the visibility of the Decl method, there's
4767 // no need to check.
4769 // If Decl's parent is other than this class, Decl must not be private
4770 mdTypeDef tkImplParent = mdTypeDefNil;
4771 mdTypeDef tkDeclParent = mdTypeDefNil;
4773 if (FAILED(hr = pIMDDecl->GetParentToken(tokDecl, &tkDeclParent)))
4775 BuildMethodTableThrowException(hr, *bmtError);
4777 if (FAILED(hr = pIMDImpl->GetParentToken(tokImpl, &tkImplParent)))
4779 BuildMethodTableThrowException(hr, *bmtError);
4782 // Make sure that we test for accessibility restrictions only if the decl is
4783 // not within our own type, as we are allowed to methodImpl a private with the
4784 // strict bit set if it is in our own type.
4785 if (!isSameModule || tkDeclParent != tkImplParent)
4787 if (!TestOverrideForAccessibility(hDeclMethod, hImplMethod.GetOwningType()))
4789 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, tokImpl);
4792 // Decl's parent must not be tdSealed
4793 mdToken tkGrandParentDummyVar;
4794 DWORD dwDeclTypeAttrs;
4795 if (FAILED(hr = pIMDDecl->GetTypeDefProps(tkDeclParent, &dwDeclTypeAttrs, &tkGrandParentDummyVar)))
4797 BuildMethodTableThrowException(hr, *bmtError);
4799 if (IsTdSealed(dwDeclTypeAttrs))
4801 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_SEALED_DECL);
4809 //*******************************************************************************
4811 // Used by BuildMethodTable
4814 MethodTableBuilder::ValidateMethods()
4820 PRECONDITION(CheckPointer(this));
4821 PRECONDITION(CheckPointer(bmtInternal));
4822 PRECONDITION(CheckPointer(bmtMetaData));
4823 PRECONDITION(CheckPointer(bmtError));
4824 PRECONDITION(CheckPointer(bmtProp));
4825 PRECONDITION(CheckPointer(bmtInterface));
4826 PRECONDITION(CheckPointer(bmtParent));
4827 PRECONDITION(CheckPointer(bmtMFDescs));
4828 PRECONDITION(CheckPointer(bmtEnumFields));
4829 PRECONDITION(CheckPointer(bmtMethodImpl));
4830 PRECONDITION(CheckPointer(bmtVT));
4834 // Used to keep track of located default and type constructors.
4835 CONSISTENCY_CHECK(bmtVT->pCCtor == NULL);
4836 CONSISTENCY_CHECK(bmtVT->pDefaultCtor == NULL);
4838 // Fetch the hard-coded signatures for the type constructor and the
4839 // default constructor and create MethodSignature objects for both at
4840 // the method level so this does not happen for every specialname
4845 sig = MscorlibBinder::GetSignature(&gsig_SM_RetVoid);
4847 MethodSignature cctorSig(MscorlibBinder::GetModule(),
4848 COR_CCTOR_METHOD_NAME,
4849 sig.GetRawSig(), sig.GetRawSigLen());
4851 sig = MscorlibBinder::GetSignature(&gsig_IM_RetVoid);
4853 MethodSignature defaultCtorSig(MscorlibBinder::GetModule(),
4854 COR_CTOR_METHOD_NAME,
4855 sig.GetRawSig(), sig.GetRawSigLen());
4857 Module * pModule = GetModule();
4858 DeclaredMethodIterator it(*this);
4861 // The RVA is only valid/testable if it has not been overwritten
4862 // for something like edit-and-continue
4863 // Complete validation of non-zero RVAs is done later inside MethodDesc::GetILHeader.
4864 if ((it.RVA() == 0) && (pModule->GetDynamicIL(it.Token(), FALSE) == NULL))
4866 // for IL code that is implemented here must have a valid code RVA
4867 // this came up due to a linker bug where the ImplFlags/DescrOffset were
4868 // being set to null and we weren't coping with it
4869 if((IsMiIL(it.ImplFlags()) || IsMiOPTIL(it.ImplFlags())) &&
4870 !IsMdAbstract(it.Attrs()) &&
4871 !IsReallyMdPinvokeImpl(it.Attrs()) &&
4872 !IsMiInternalCall(it.ImplFlags()))
4874 BuildMethodTableThrowException(IDS_CLASSLOAD_MISSINGMETHODRVA, it.Token());
4878 if (IsMdRTSpecialName(it.Attrs()))
4880 if (IsMdVirtual(it.Attrs()))
4881 { // Virtual specialname methods are illegal
4882 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4885 // Constructors (.ctor) and class initialisers (.cctor) are special
4886 const MethodSignature &curSig(it->GetMethodSignature());
4888 if (IsMdStatic(it.Attrs()))
4889 { // The only rtSpecialName static method allowed is the .cctor
4890 if (!curSig.ExactlyEqual(cctorSig))
4892 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4895 // Remember it for later
4896 bmtVT->pCCtor = *it;
4900 if(!MethodSignature::NamesEqual(curSig, defaultCtorSig))
4901 { // The only rtSpecialName instance methods allowed are .ctors
4902 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4905 // .ctor must return void
4906 MetaSig methodMetaSig(curSig.GetSignature(),
4907 static_cast<DWORD>(curSig.GetSignatureLength()),
4911 if (methodMetaSig.GetReturnType() != ELEMENT_TYPE_VOID)
4912 { // All constructors must have a void return type
4913 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4916 // See if this is a default constructor. If so, remember it for later.
4917 if (curSig.ExactlyEqual(defaultCtorSig))
4919 bmtVT->pDefaultCtor = *it;
4924 // Make sure that fcalls have a 0 rva. This is assumed by the prejit fixup logic
4925 if (it.MethodType() == METHOD_TYPE_FCALL && it.RVA() != 0)
4927 BuildMethodTableThrowException(BFA_ECALLS_MUST_HAVE_ZERO_RVA, it.Token());
4930 // check for proper use of the Managed and native flags
4931 if (IsMiManaged(it.ImplFlags()))
4933 if (IsMiIL(it.ImplFlags()) || IsMiRuntime(it.ImplFlags())) // IsMiOPTIL(it.ImplFlags()) no longer supported
4935 // No need to set code address, pre stub used automatically.
4939 if (IsMiNative(it.ImplFlags()))
4941 // For now simply disallow managed native code if you turn this on you have to at least
4942 // insure that we have SkipVerificationPermission or equivalent
4943 BuildMethodTableThrowException(BFA_MANAGED_NATIVE_NYI, it.Token());
4947 BuildMethodTableThrowException(BFA_BAD_IMPL_FLAGS, it.Token());
4953 if (IsMiNative(it.ImplFlags()) && IsGlobalClass())
4955 // global function unmanaged entrypoint via IJW thunk was handled
4960 BuildMethodTableThrowException(IDS_CLASSLOAD_BAD_UNMANAGED_RVA, it.Token());
4962 if (it.MethodType() != METHOD_TYPE_NDIRECT)
4964 BuildMethodTableThrowException(BFA_BAD_UNMANAGED_ENTRY_POINT);
4968 // Vararg methods are not allowed inside generic classes
4969 // and nor can they be generic methods.
4970 if (bmtGenerics->GetNumGenericArgs() > 0 || (it.MethodType() == METHOD_TYPE_INSTANTIATED) )
4972 DWORD cMemberSignature;
4973 PCCOR_SIGNATURE pMemberSignature = it.GetSig(&cMemberSignature);
4974 // We've been trying to avoid asking for the signature - now we need it
4975 if (pMemberSignature == NULL)
4977 pMemberSignature = it.GetSig(&cMemberSignature);
4980 if (MetaSig::IsVarArg(pModule, Signature(pMemberSignature, cMemberSignature)))
4982 BuildMethodTableThrowException(BFA_GENCODE_NOT_BE_VARARG);
4986 if (IsMdVirtual(it.Attrs()) && IsMdPublic(it.Attrs()) && it.Name() == NULL)
4988 BuildMethodTableThrowException(IDS_CLASSLOAD_NOMETHOD_NAME);
4991 if (it.IsMethodImpl())
4993 if (!IsMdVirtual(it.Attrs()))
4994 { // Non-virtual methods cannot participate in a methodImpl pair.
4995 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
4999 // Virtual static methods are not allowed.
5000 if (IsMdStatic(it.Attrs()) && IsMdVirtual(it.Attrs()))
5002 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL, it.Token());
5007 //*******************************************************************************
5008 // Essentially, this is a helper method that combines calls to InitMethodDesc and
5009 // SetSecurityFlagsOnMethod. It then assigns the newly initialized MethodDesc to
5012 MethodTableBuilder::InitNewMethodDesc(
5013 bmtMDMethod * pMethod,
5014 MethodDesc * pNewMD)
5016 STANDARD_VM_CONTRACT;
5019 // First, set all flags that control layout of optional slots
5021 pNewMD->SetClassification(GetMethodClassification(pMethod->GetMethodType()));
5023 if (pMethod->GetMethodImplType() == METHOD_IMPL)
5024 pNewMD->SetHasMethodImplSlot();
5026 if (pMethod->GetSlotIndex() >= bmtVT->cVtableSlots)
5027 pNewMD->SetHasNonVtableSlot();
5029 if (NeedsNativeCodeSlot(pMethod))
5030 pNewMD->SetHasNativeCodeSlot();
5032 // Now we know the classification we can allocate the correct type of
5033 // method desc and perform any classification specific initialization.
5035 LPCSTR pName = pMethod->GetMethodSignature().GetName();
5038 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pName)))
5040 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5045 LPCUTF8 pszDebugMethodName;
5046 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pszDebugMethodName)))
5048 pszDebugMethodName = "Invalid MethodDef record";
5050 S_SIZE_T safeLen = S_SIZE_T(strlen(pszDebugMethodName)) + S_SIZE_T(1);
5051 if(safeLen.IsOverflow())
5052 COMPlusThrowHR(COR_E_OVERFLOW);
5054 size_t len = safeLen.Value();
5055 LPCUTF8 pszDebugMethodNameCopy = (char*) AllocateFromLowFrequencyHeap(safeLen);
5056 strcpy_s((char *) pszDebugMethodNameCopy, len, pszDebugMethodName);
5059 // Do the init specific to each classification of MethodDesc & assign some common fields
5060 InitMethodDesc(pNewMD,
5061 GetMethodClassification(pMethod->GetMethodType()),
5062 pMethod->GetMethodSignature().GetToken(),
5063 pMethod->GetImplAttrs(),
5064 pMethod->GetDeclAttrs(),
5069 COMMA_INDEBUG(pszDebugMethodNameCopy)
5070 COMMA_INDEBUG(GetDebugClassName())
5071 COMMA_INDEBUG("") // FIX this happens on global methods, give better info
5074 pMethod->SetMethodDesc(pNewMD);
5076 bmtRTMethod * pParentMethod = NULL;
5080 SLOT_INDEX idx = pMethod->GetSlotIndex();
5081 CONSISTENCY_CHECK(idx != INVALID_SLOT_INDEX);
5083 if (idx < GetParentMethodTable()->GetNumVirtuals())
5085 pParentMethod = (*bmtParent->pSlotTable)[idx].Decl().AsRTMethod();
5089 // Turn off inlining for any calls
5090 // that are marked in the metadata as not being inlineable.
5091 if(IsMiNoInlining(pMethod->GetImplAttrs()))
5093 pNewMD->SetNotInline(true);
5096 // Check for methods marked as [Intrinsic]
5097 if (GetModule()->IsSystem() || GetAssembly()->IsSIMDVectorAssembly())
5099 HRESULT hr = GetMDImport()->GetCustomAttributeByName(pMethod->GetMethodSignature().GetToken(),
5100 g_CompilerServicesIntrinsicAttribute,
5104 if (hr == S_OK || bmtProp->fIsHardwareIntrinsic)
5106 pNewMD->SetIsJitIntrinsic();
5111 pNewMD->SetSlot(pMethod->GetSlotIndex());
5114 //*******************************************************************************
5115 // Determine vtable placement for each non-virtual in the class, while also
5116 // looking for default and type constructors.
5118 MethodTableBuilder::PlaceNonVirtualMethods()
5124 PRECONDITION(CheckPointer(this));
5125 PRECONDITION(CheckPointer(bmtInternal));
5126 PRECONDITION(CheckPointer(bmtMetaData));
5127 PRECONDITION(CheckPointer(bmtError));
5128 PRECONDITION(CheckPointer(bmtProp));
5129 PRECONDITION(CheckPointer(bmtInterface));
5130 PRECONDITION(CheckPointer(bmtParent));
5131 PRECONDITION(CheckPointer(bmtMFDescs));
5132 PRECONDITION(CheckPointer(bmtEnumFields));
5133 PRECONDITION(CheckPointer(bmtMethodImpl));
5134 PRECONDITION(CheckPointer(bmtVT));
5138 INDEBUG(bmtVT->SealVirtualSlotSection();)
5141 // For each non-virtual method, place the method in the next available non-virtual method slot.
5144 // Place the cctor and default ctor first. code::MethodTableGetCCtorSlot and code:MethodTable::GetDefaultCtorSlot
5146 if (bmtVT->pCCtor != NULL)
5148 if (!bmtVT->AddNonVirtualMethod(bmtVT->pCCtor))
5149 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5152 if (bmtVT->pDefaultCtor != NULL)
5154 if (!bmtVT->AddNonVirtualMethod(bmtVT->pDefaultCtor))
5155 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5158 // We use slot during remoting and to map methods between generic instantiations
5159 // (see MethodTable::GetParallelMethodDesc). The current implementation
5160 // of this mechanism requires real slots.
5161 BOOL fCanHaveNonVtableSlots = (bmtGenerics->GetNumGenericArgs() == 0) && !IsInterface();
5163 // Flag to avoid second pass when possible
5164 BOOL fHasNonVtableSlots = FALSE;
5167 // Place all methods that require real vtable slot first. This is necessary so
5168 // that they get consequitive slot numbers right after virtual slots.
5171 DeclaredMethodIterator it(*this);
5174 // Skip methods that are placed already
5175 if (it->GetSlotIndex() != INVALID_SLOT_INDEX)
5179 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5180 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5183 if (!fCanHaveNonVtableSlots ||
5184 it->GetMethodType() == METHOD_TYPE_INSTANTIATED)
5186 // We use slot during remoting and to map methods between generic instantiations
5187 // (see MethodTable::GetParallelMethodDesc). The current implementation
5188 // of this mechanism requires real slots.
5192 // This method does not need real vtable slot
5193 fHasNonVtableSlots = TRUE;
5197 // This will update slot index in bmtMDMethod
5198 if (!bmtVT->AddNonVirtualMethod(*it))
5199 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5202 // Remeber last real vtable slot
5203 bmtVT->cVtableSlots = bmtVT->cTotalSlots;
5205 // Are there any Non-vtable slots to place?
5206 if (!fHasNonVtableSlots)
5210 // Now, place the remaining methods. They will get non-vtable slot.
5213 DeclaredMethodIterator it2(*this);
5216 // Skip methods that are placed already
5217 if (it2->GetSlotIndex() != INVALID_SLOT_INDEX)
5220 if (!bmtVT->AddNonVirtualMethod(*it2))
5221 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5226 //*******************************************************************************
5227 // Determine vtable placement for each virtual member in this class.
5229 MethodTableBuilder::PlaceVirtualMethods()
5235 PRECONDITION(CheckPointer(this));
5236 PRECONDITION(CheckPointer(bmtInternal));
5237 PRECONDITION(CheckPointer(bmtMetaData));
5238 PRECONDITION(CheckPointer(bmtError));
5239 PRECONDITION(CheckPointer(bmtProp));
5240 PRECONDITION(CheckPointer(bmtInterface));
5241 PRECONDITION(CheckPointer(bmtParent));
5242 PRECONDITION(CheckPointer(bmtMFDescs));
5243 PRECONDITION(CheckPointer(bmtEnumFields));
5244 PRECONDITION(CheckPointer(bmtMethodImpl));
5245 PRECONDITION(CheckPointer(bmtVT));
5250 LPCUTF8 pszDebugName, pszDebugNamespace;
5251 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &pszDebugName, &pszDebugNamespace)))
5253 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
5258 // For each virtual method
5259 // - If the method is not declared as newslot, search all virtual methods in the parent
5260 // type for an override candidate.
5261 // - If such a candidate is found, test to see if the override is valid. If
5262 // the override is not valid, throw TypeLoadException
5263 // - If a candidate is found above, place the method in the inherited slot as both
5264 // the Decl and the Impl.
5265 // - Else, place the method in the next available empty vtable slot.
5268 DeclaredMethodIterator it(*this);
5271 if (!IsMdVirtual(it.Attrs()))
5272 { // Only processing declared virtual methods
5277 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5278 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5281 // If this member is a method which overrides a parent method, it will be set to non-NULL
5282 bmtRTMethod * pParentMethod = NULL;
5284 // Hash that a method with this name exists in this class
5285 // Note that ctors and static ctors are not added to the table
5286 BOOL fMethodConstraintsMatch = FALSE;
5288 // If the member is marked with a new slot we do not need to find it in the parent
5289 if (HasParent() && !IsMdNewSlot(it.Attrs()))
5291 // Attempt to find the method with this name and signature in the parent class.
5292 // This method may or may not create pParentMethodHash (if it does not already exist).
5293 // It also may or may not fill in pMemberSignature/cMemberSignature.
5294 // An error is only returned when we can not create the hash.
5295 // NOTE: This operation touches metadata
5296 pParentMethod = LoaderFindMethodInParentClass(
5297 it->GetMethodSignature(), bmtProp->fNoSanityChecks ? NULL : &fMethodConstraintsMatch);
5299 if (pParentMethod != NULL)
5300 { // Found an override candidate
5301 DWORD dwParentAttrs = pParentMethod->GetDeclAttrs();
5303 if (!IsMdVirtual(dwParentAttrs))
5304 { // Can't override a non-virtual methods
5305 BuildMethodTableThrowException(BFA_NONVIRT_NO_SEARCH, it.Token());
5308 if(IsMdFinal(dwParentAttrs))
5309 { // Can't override a final methods
5310 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL, it.Token());
5313 if(!bmtProp->fNoSanityChecks)
5315 TestOverRide(bmtMethodHandle(pParentMethod),
5316 bmtMethodHandle(*it));
5318 if (!fMethodConstraintsMatch)
5320 BuildMethodTableThrowException(
5321 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_OVERRIDE,
5331 CONSISTENCY_CHECK(pParentMethod == NULL);
5332 // Also sets new slot number on bmtRTMethod and MethodDesc
5333 if (!bmtVT->AddVirtualMethod(*it))
5334 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5336 else if (pParentMethod != NULL)
5338 bmtVT->SetVirtualMethodOverride(pParentMethod->GetSlotIndex(), *it);
5342 if (!bmtVT->AddVirtualMethod(*it))
5343 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5348 // Given an interface map entry, and a name+signature, compute the method on the interface
5349 // that the name+signature corresponds to. Used by ProcessMethodImpls and ProcessInexactMethodImpls
5350 // Always returns the first match that it finds. Affects the ambiguities in code:#ProcessInexactMethodImpls_Ambiguities
5351 MethodTableBuilder::bmtMethodHandle
5352 MethodTableBuilder::FindDeclMethodOnInterfaceEntry(bmtInterfaceEntry *pItfEntry, MethodSignature &declSig)
5354 STANDARD_VM_CONTRACT;
5356 bmtMethodHandle declMethod;
5358 bmtInterfaceEntry::InterfaceSlotIterator slotIt =
5359 pItfEntry->IterateInterfaceSlots(GetStackingAllocator());
5360 // Check for exact match
5361 for (; !slotIt.AtEnd(); slotIt.Next())
5363 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5365 if (declSig.ExactlyEqual(pCurDeclMethod->GetMethodSignature()))
5367 declMethod = slotIt->Decl();
5371 slotIt.ResetToStart();
5373 // Check for equivalent match if exact match wasn't found
5374 if (declMethod.IsNull())
5376 for (; !slotIt.AtEnd(); slotIt.Next())
5378 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5380 // Type Equivalence is forbidden in MethodImpl MemberRefs
5381 if (declSig.Equivalent(pCurDeclMethod->GetMethodSignature()))
5383 declMethod = slotIt->Decl();
5392 //*******************************************************************************
5394 // Used by BuildMethodTable
5395 // Process the list of inexact method impls generated during ProcessMethodImpls.
5396 // This list is used to cause a methodImpl to an interface to override
5397 // methods on several equivalent interfaces in the interface map. This logic is necessary
5398 // so that in the presence of an embedded interface the behavior appears to mimic
5399 // the behavior if the interface was not embedded.
5401 // In particular, the logic here is to handle cases such as
5404 // [TypeIdentifier("x","y")]
5406 // { void Method(); }
5407 // interface IOther : I' {}
5410 // [TypeIdentifier("x","y")]
5412 // { void Method(); }
5413 // class Test : I, IOther
5419 // In this case, there is one method, and one methodimpl, but there are 2 interfaces on the class that both
5420 // require an implementation of their method. The correct semantic for type equivalence, is that any
5421 // methodimpl directly targeting a method on an interface must be respected, and if it also applies to a type
5422 // equivalent interface method, then if that method was not methodimpl'd directly, then the methodimpl should apply
5423 // there as well. The ProcessInexactMethodImpls function does this secondary MethodImpl mapping.
5425 //#ProcessInexactMethodImpls_Ambiguities
5426 // In the presence of ambiguities, such as there are 3 equivalent interfaces implemented on a class and 2 methodimpls,
5427 // we will apply the 2 method impls exactly to appropriate interface methods, and arbitrarily pick one to apply to the
5428 // other interface. This is clearly ambiguous, but tricky to detect in the type loader efficiently, and should hopefully
5429 // not cause too many problems.
5432 MethodTableBuilder::ProcessInexactMethodImpls()
5434 STANDARD_VM_CONTRACT;
5436 if (bmtMethod->dwNumberInexactMethodImplCandidates == 0)
5439 DeclaredMethodIterator it(*this);
5442 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5443 // error before reaching this point.
5444 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5446 if (!IsMdVirtual(it.Attrs()))
5447 { // Only virtual methods can participate in methodImpls
5451 if(!it.IsMethodImpl())
5453 // Skip methods which are not the bodies of MethodImpl specifications
5457 // If this method serves as the BODY of a MethodImpl specification, then
5458 // we should iterate all the MethodImpl's for this class and see just how many
5459 // of them this method participates in as the BODY.
5460 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5462 // Inexact matching logic only works on MethodImpls that have been opted into inexactness by ProcessMethodImpls.
5463 if (!bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing)
5468 // If the methodimpl we are working with does not match this method, continue to next methodimpl
5469 if(it.Token() != bmtMetaData->rgMethodImplTokens[m].methodBody)
5474 bool fMatchFound = false;
5476 LPCUTF8 szName = NULL;
5477 PCCOR_SIGNATURE pSig = NULL;
5480 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5482 if (TypeFromToken(mdDecl) == mdtMethodDef)
5483 { // Different methods are aused to access MethodDef and MemberRef
5484 // names and signatures.
5485 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5486 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5488 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5493 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5495 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5499 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5500 MethodSignature declSig(GetModule(), szName, pSig, cbSig, pDeclSubst);
5501 bmtInterfaceEntry * pItfEntry = NULL;
5503 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5505 if (bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet() != bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet)
5508 bmtMethodHandle declMethod;
5509 pItfEntry = &bmtInterface->pInterfaceMap[i];
5511 // Search for declmethod on this interface
5512 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5514 // If we didn't find a match, continue on to next interface in the equivalence set
5515 if (declMethod.IsNull())
5518 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5519 { // Make sure the decl is virtual
5520 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5525 bool fPreexistingImplFound = false;
5527 // Check to ensure there isn't already a matching declMethod in the method impl list
5528 for (DWORD iMethodImpl = 0; iMethodImpl < bmtMethodImpl->pIndex; iMethodImpl++)
5530 if (bmtMethodImpl->GetDeclarationMethod(iMethodImpl) == declMethod)
5532 fPreexistingImplFound = true;
5537 // Search for other matches
5538 if (fPreexistingImplFound)
5541 // Otherwise, record the method impl discovery if the match is
5542 bmtMethodImpl->AddMethodImpl(*it, declMethod, bmtMetaData->rgMethodImplTokens[m].methodDecl, GetStackingAllocator());
5545 if (!fMatchFound && bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing)
5547 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5553 //*******************************************************************************
5555 // Used by BuildMethodTable
5558 MethodTableBuilder::ProcessMethodImpls()
5560 STANDARD_VM_CONTRACT;
5562 if (bmtMethod->dwNumberMethodImpls == 0)
5567 DeclaredMethodIterator it(*this);
5570 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5571 // error before reaching this point.
5572 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5574 if (!IsMdVirtual(it.Attrs()))
5575 { // Only virtual methods can participate in methodImpls
5579 // If this method serves as the BODY of a MethodImpl specification, then
5580 // we should iterate all the MethodImpl's for this class and see just how many
5581 // of them this method participates in as the BODY.
5582 if(it.IsMethodImpl())
5584 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5586 if(it.Token() == bmtMetaData->rgMethodImplTokens[m].methodBody)
5588 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5589 bmtMethodHandle declMethod;
5591 // Get the parent token for the decl method token
5592 mdToken tkParent = mdTypeDefNil;
5593 if (TypeFromToken(mdDecl) == mdtMethodDef || TypeFromToken(mdDecl) == mdtMemberRef)
5595 if (FAILED(hr = GetMDImport()->GetParentToken(mdDecl,&tkParent)))
5597 BuildMethodTableThrowException(hr, *bmtError);
5601 if (GetCl() == tkParent)
5602 { // The DECL has been declared within the class that we're currently building.
5605 if(bmtError->pThrowable != NULL)
5607 *(bmtError->pThrowable) = NULL;
5610 if(TypeFromToken(mdDecl) != mdtMethodDef)
5612 if (FAILED(hr = FindMethodDeclarationForMethodImpl(
5613 mdDecl, &mdDecl, TRUE)))
5615 BuildMethodTableThrowException(hr, *bmtError);
5619 CONSISTENCY_CHECK(TypeFromToken(mdDecl) == mdtMethodDef);
5620 declMethod = bmtMethod->FindDeclaredMethodByToken(mdDecl);
5623 { // We can't call GetDescFromMemberDefOrRef here because this
5624 // method depends on a fully-loaded type, including parent types,
5625 // which is not always guaranteed. In particular, it requires that
5626 // the instantiation dictionary be filled. The solution is the following:
5627 // 1. Load the approximate type that the method belongs to.
5628 // 2. Get or create the correct substitution for the type involved
5629 // 3. Iterate the introduced methods on that type looking for a matching
5632 LPCUTF8 szName = NULL;
5633 PCCOR_SIGNATURE pSig = NULL;
5635 if (TypeFromToken(mdDecl) == mdtMethodDef)
5636 { // Different methods are aused to access MethodDef and MemberRef
5637 // names and signatures.
5638 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5639 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5641 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5646 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5648 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5652 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5653 MethodTable * pDeclMT = NULL;
5654 MethodSignature declSig(GetModule(), szName, pSig, cbSig, pDeclSubst);
5656 { // 1. Load the approximate type.
5657 // Block for the LoadsTypeViolation.
5658 CONTRACT_VIOLATION(LoadsTypeViolation);
5659 pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
5662 &bmtGenerics->typeContext,
5663 ClassLoader::ThrowIfNotFound,
5664 ClassLoader::PermitUninstDefOrRef,
5665 ClassLoader::LoadTypes,
5666 CLASS_LOAD_APPROXPARENTS,
5667 TRUE).GetMethodTable()->GetCanonicalMethodTable();
5670 { // 2. Get or create the correct substitution
5671 bmtRTType * pDeclType = NULL;
5673 if (pDeclMT->IsInterface())
5674 { // If the declaration method is a part of an interface, search through
5675 // the interface map to find the matching interface so we can provide
5676 // the correct substitution chain.
5679 bmtInterfaceEntry * pItfEntry = NULL;
5680 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5682 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5683 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
5684 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5685 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5686 pCurItf->GetMethodTable(), pDeclMT,
5687 &pCurItf->GetSubstitution(), pDeclSubst,
5690 pItfEntry = &bmtInterface->pInterfaceMap[i];
5691 pDeclType = pCurItf;
5698 if (pDeclType == NULL)
5700 // Interface is not implemented by this type.
5701 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5706 if (pDeclType == NULL)
5708 DWORD equivalenceSet = 0;
5710 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5712 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5713 // Type Equivalence is respected for this comparision as we just need to find an
5714 // equivalent interface, the particular interface is unimportant
5715 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5716 pCurItf->GetMethodTable(), pDeclMT,
5717 &pCurItf->GetSubstitution(), pDeclSubst,
5720 equivalenceSet = bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet();
5721 pItfEntry = &bmtInterface->pInterfaceMap[i];
5726 if (equivalenceSet == 0)
5728 // Interface is not implemented by this type.
5729 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5732 // Interface is not implemented by this type exactly. We need to consider this MethodImpl on non exact interface matches,
5733 // as the only match may be one of the non-exact matches
5734 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5735 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = true;
5736 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = equivalenceSet;
5737 bmtMethod->dwNumberInexactMethodImplCandidates++;
5738 continue; // Move on to other MethodImpls
5742 // This method impl may need to match other methods during inexact processing
5743 if (pItfEntry->InEquivalenceSetWithMultipleEntries())
5745 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5746 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
5747 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = pItfEntry->GetInterfaceEquivalenceSet();
5748 bmtMethod->dwNumberInexactMethodImplCandidates++;
5753 // 3. Find the matching method.
5754 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5757 { // Assume the MethodTable is a parent of the current type,
5758 // and create the substitution chain to match it.
5762 for (bmtRTType *pCur = GetParentType();
5764 pCur = pCur->GetParentType())
5766 if (pCur->GetMethodTable() == pDeclMT)
5773 if (pDeclType == NULL)
5774 { // Method's type is not a parent.
5775 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5778 // 3. Find the matching method.
5779 bmtRTType *pCurDeclType = pDeclType;
5782 // two pass algorithm. search for exact matches followed
5783 // by equivalent matches.
5784 for (int iPass = 0; (iPass < 2) && (declMethod.IsNull()); iPass++)
5786 MethodTable *pCurDeclMT = pCurDeclType->GetMethodTable();
5788 MethodTable::IntroducedMethodIterator methIt(pCurDeclMT);
5789 for(; methIt.IsValid(); methIt.Next())
5791 MethodDesc * pCurMD = methIt.GetMethodDesc();
5793 if (pCurDeclMT != pDeclMT)
5795 // If the method isn't on the declaring type, then it must be virtual.
5796 if (!pCurMD->IsVirtual())
5799 if (strcmp(szName, pCurMD->GetName()) == 0)
5801 PCCOR_SIGNATURE pCurMDSig;
5803 pCurMD->GetSig(&pCurMDSig, &cbCurMDSig);
5805 // First pass searches for declaration methods should not use type equivalence
5806 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5808 if (MetaSig::CompareMethodSigs(
5809 declSig.GetSignature(),
5810 static_cast<DWORD>(declSig.GetSignatureLength()),
5811 declSig.GetModule(),
5812 &declSig.GetSubstitution(),
5815 pCurMD->GetModule(),
5816 &pCurDeclType->GetSubstitution(),
5817 iPass == 0 ? &newVisited : NULL))
5819 declMethod = (*bmtParent->pSlotTable)[pCurMD->GetSlot()].Decl();
5826 pCurDeclType = pCurDeclType->GetParentType();
5827 } while ((pCurDeclType != NULL) && (declMethod.IsNull()));
5830 if (declMethod.IsNull())
5831 { // Would prefer to let this fall out to the BuildMethodTableThrowException
5832 // below, but due to v2.0 and earlier behaviour throwing a MissingMethodException,
5833 // primarily because this code used to be a simple call to
5834 // MemberLoader::GetDescFromMemberDefOrRef (see above for reason why),
5835 // we must continue to do the same.
5836 MemberLoader::ThrowMissingMethodException(
5839 declSig.GetModule(),
5840 declSig.GetSignature(),
5841 static_cast<DWORD>(declSig.GetSignatureLength()),
5842 &bmtGenerics->typeContext);
5847 if (declMethod.IsNull())
5848 { // Method not found, throw.
5849 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5852 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5853 { // Make sure the decl is virtual
5854 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5857 bmtMethodImpl->AddMethodImpl(*it, declMethod, mdDecl, GetStackingAllocator());
5861 } /* end ... for each member */
5864 //*******************************************************************************
5865 // InitMethodDesc takes a pointer to space that's already allocated for the
5866 // particular type of MethodDesc, and initializes based on the other info.
5867 // This factors logic between PlaceMembers (the regular code path) & AddMethod
5868 // (Edit & Continue (EnC) code path) so we don't have to maintain separate copies.
5870 MethodTableBuilder::InitMethodDesc(
5871 MethodDesc * pNewMD, // This is should actually be of the correct sub-type, based on Classification
5872 DWORD Classification,
5875 DWORD dwMemberAttrs,
5877 DWORD RVA, // Only needed for NDirect case
5878 IMDInternalImport * pIMDII, // Needed for NDirect, EEImpl(Delegate) cases
5879 LPCSTR pMethodName // Only needed for mcEEImpl (Delegate) case
5880 COMMA_INDEBUG(LPCUTF8 pszDebugMethodName)
5881 COMMA_INDEBUG(LPCUTF8 pszDebugClassName)
5882 COMMA_INDEBUG(LPCUTF8 pszDebugMethodSignature)
5888 if (fEnC) { GC_NOTRIGGER; } else { GC_TRIGGERS; }
5893 LOG((LF_CORDB, LL_EVERYTHING, "EEC::IMD: pNewMD:0x%x for tok:0x%x (%s::%s)\n",
5894 pNewMD, tok, pszDebugClassName, pszDebugMethodName));
5896 // Now we know the classification we can perform any classification specific initialization.
5898 // The method desc is zero inited by the caller.
5900 switch (Classification)
5904 // NDirect specific initialization.
5905 NDirectMethodDesc *pNewNMD = (NDirectMethodDesc*)pNewMD;
5907 // Allocate writeable data
5908 pNewNMD->ndirect.m_pWriteableData.SetValue((NDirectWriteableData*)
5909 AllocateFromHighFrequencyHeap(S_SIZE_T(sizeof(NDirectWriteableData))));
5911 #ifdef HAS_NDIRECT_IMPORT_PRECODE
5912 pNewNMD->ndirect.m_pImportThunkGlue.SetValue(Precode::Allocate(PRECODE_NDIRECT_IMPORT, pNewMD,
5913 GetLoaderAllocator(), GetMemTracker())->AsNDirectImportPrecode());
5914 #else // !HAS_NDIRECT_IMPORT_PRECODE
5915 pNewNMD->GetNDirectImportThunkGlue()->Init(pNewNMD);
5916 #endif // !HAS_NDIRECT_IMPORT_PRECODE
5918 #if defined(_TARGET_X86_)
5919 pNewNMD->ndirect.m_cbStackArgumentSize = 0xFFFF;
5920 #endif // defined(_TARGET_X86_)
5922 // If the RVA of a native method is set, this is an early-bound IJW call
5923 if (RVA != 0 && IsMiUnmanaged(dwImplFlags) && IsMiNative(dwImplFlags))
5925 // Note that we cannot initialize the stub directly now in the general case,
5926 // as LoadLibrary may not have been performed yet.
5927 pNewNMD->SetIsEarlyBound();
5930 pNewNMD->GetWriteableData()->m_pNDirectTarget = pNewNMD->GetNDirectImportThunkGlue()->GetEntrypoint();
5938 // For the Invoke method we will set a standard invoke method.
5939 BAD_FORMAT_NOTHROW_ASSERT(IsDelegate());
5941 // For the asserts, either the pointer is NULL (since the class hasn't
5942 // been constructed yet), or we're in EnC mode, meaning that the class
5943 // does exist, but we may be re-assigning the field to point to an
5944 // updated MethodDesc
5946 // It is not allowed for EnC to replace one of the runtime builtin methods
5948 if (strcmp(pMethodName, "Invoke") == 0)
5950 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod.IsNull());
5951 ((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod.SetValue(pNewMD);
5953 else if (strcmp(pMethodName, "BeginInvoke") == 0)
5955 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod.IsNull());
5956 ((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod.SetValue(pNewMD);
5958 else if (strcmp(pMethodName, "EndInvoke") == 0)
5960 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod.IsNull());
5961 ((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod.SetValue(pNewMD);
5965 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
5968 // StoredSig specific intialization
5970 StoredSigMethodDesc *pNewSMD = (StoredSigMethodDesc*) pNewMD;;
5972 PCCOR_SIGNATURE pSig;
5973 if (FAILED(pIMDII->GetSigOfMethodDef(tok, &cSig, &pSig)))
5975 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5977 pNewSMD->SetStoredMethodSig(pSig, cSig);
5981 #ifdef FEATURE_COMINTEROP
5983 #endif // FEATURE_COMINTEROP
5987 case mcInstantiated:
5988 #ifdef EnC_SUPPORTED
5991 // We reuse the instantiated methoddescs to get the slot
5992 InstantiatedMethodDesc* pNewIMD = (InstantiatedMethodDesc*) pNewMD;
5993 pNewIMD->SetupEnCAddedMethod();
5996 #endif // EnC_SUPPORTED
5998 // Initialize the typical instantiation.
5999 InstantiatedMethodDesc* pNewIMD = (InstantiatedMethodDesc*) pNewMD;
6000 //data has the same lifetime as method table, use our allocator
6001 pNewIMD->SetupGenericMethodDefinition(pIMDII, GetLoaderAllocator(), GetMemTracker(), GetModule(),
6007 BAD_FORMAT_NOTHROW_ASSERT(!"Failed to set a method desc classification");
6010 // Check the method desc's classification.
6011 _ASSERTE(pNewMD->GetClassification() == Classification);
6013 pNewMD->SetMemberDef(tok);
6015 if (IsMdStatic(dwMemberAttrs))
6016 pNewMD->SetStatic();
6018 // Set suppress unmanaged code access permission attribute
6020 if (pNewMD->IsNDirect())
6021 pNewMD->ComputeSuppressUnmanagedCodeAccessAttr(pIMDII);
6024 // Mark as many methods as synchronized as possible.
6026 // Note that this can easily cause programs to deadlock, and that
6027 // should not be treated as a bug in the program.
6029 static ConfigDWORD stressSynchronized;
6030 DWORD stressSynchronizedVal = stressSynchronized.val(CLRConfig::INTERNAL_stressSynchronized);
6032 bool isStressSynchronized = stressSynchronizedVal &&
6033 pNewMD->IsIL() && // Synchronized is not supported on Ecalls, NDirect method, etc
6034 // IsValueClass() and IsEnum() do not work for System.ValueType and System.Enum themselves
6035 ((g_pValueTypeClass != NULL && g_pEnumClass != NULL &&
6036 !IsValueClass()) || // Can not synchronize on byref "this"
6037 IsMdStatic(dwMemberAttrs)) && // IsStatic() blows up in _DEBUG as pNewMD is not fully inited
6038 g_pObjectClass != NULL; // Ignore Object:* since "this" could be a boxed object
6040 // stressSynchronized=1 turns off the stress in the system domain to reduce
6041 // the chances of spurious deadlocks. Deadlocks in user code can still occur.
6042 // stressSynchronized=2 will probably cause more deadlocks, and is not recommended
6043 if (stressSynchronizedVal == 1 && GetAssembly()->IsSystem())
6044 isStressSynchronized = false;
6046 if (IsMiSynchronized(dwImplFlags) || isStressSynchronized)
6048 if (IsMiSynchronized(dwImplFlags))
6050 pNewMD->SetSynchronized();
6053 pNewMD->m_pszDebugMethodName = (LPUTF8)pszDebugMethodName;
6054 pNewMD->m_pszDebugClassName = (LPUTF8)pszDebugClassName;
6055 pNewMD->m_pDebugMethodTable.SetValue(GetHalfBakedMethodTable());
6057 if (pszDebugMethodSignature == NULL)
6058 pNewMD->m_pszDebugMethodSignature = FormatSig(pNewMD,pNewMD->GetLoaderAllocator()->GetLowFrequencyHeap(),GetMemTracker());
6060 pNewMD->m_pszDebugMethodSignature = pszDebugMethodSignature;
6062 } // MethodTableBuilder::InitMethodDesc
6064 //*******************************************************************************
6066 // Used by BuildMethodTable
6069 MethodTableBuilder::AddMethodImplDispatchMapping(
6070 DispatchMapTypeID typeID,
6071 SLOT_INDEX slotNumber,
6072 bmtMDMethod * pImplMethod)
6074 STANDARD_VM_CONTRACT;
6076 MethodDesc * pMDImpl = pImplMethod->GetMethodDesc();
6078 // Look for an existing entry in the map.
6079 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6080 if (bmtVT->pDispatchMapBuilder->Find(typeID, slotNumber, it))
6082 // Throw if this entry has already previously been MethodImpl'd.
6083 if (it.IsMethodImpl())
6085 // NOTE: This is where we check for duplicate overrides. This is the easiest place to check
6086 // because duplicate overrides could in fact have separate MemberRefs to the same
6087 // member and so just comparing tokens at the very start would not be enough.
6088 if (it.GetTargetMD() != pMDImpl)
6090 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, pMDImpl->GetMemberDef());
6093 // This is the first MethodImpl. That's ok.
6096 it.SetTarget(pMDImpl);
6097 it.SetIsMethodImpl();
6100 // A mapping for this interface method does not exist, so insert it.
6103 bmtVT->pDispatchMapBuilder->InsertMDMapping(
6110 // Save the entry into the vtable as well, if it isn't an interface methodImpl
6111 if (typeID == DispatchMapTypeID::ThisClassID())
6113 bmtVT->SetVirtualMethodImpl(slotNumber, pImplMethod);
6115 } // MethodTableBuilder::AddMethodImplDispatchMapping
6117 //*******************************************************************************
6119 MethodTableBuilder::MethodImplCompareSignatures(
6120 bmtMethodHandle hDecl,
6121 bmtMethodHandle hImpl,
6122 DWORD dwConstraintErrorCode)
6126 PRECONDITION(!hDecl.IsNull());
6127 PRECONDITION(!hImpl.IsNull());
6128 PRECONDITION(TypeFromToken(hDecl.GetMethodSignature().GetToken()) == mdtMethodDef);
6129 PRECONDITION(TypeFromToken(hImpl.GetMethodSignature().GetToken()) == mdtMethodDef);
6132 const MethodSignature &declSig(hDecl.GetMethodSignature());
6133 const MethodSignature &implSig(hImpl.GetMethodSignature());
6135 if (!MethodSignature::SignaturesEquivalent(declSig, implSig))
6137 LOG((LF_CLASSLOADER, LL_INFO1000, "BADSIG placing MethodImpl: %x\n", declSig.GetToken()));
6138 BuildMethodTableThrowException(COR_E_TYPELOAD, IDS_CLASSLOAD_MI_BADSIGNATURE, declSig.GetToken());
6141 //now compare the method constraints
6142 if (!MetaSig::CompareMethodConstraints(&implSig.GetSubstitution(), implSig.GetModule(), implSig.GetToken(),
6143 &declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken()))
6145 BuildMethodTableThrowException(dwConstraintErrorCode, implSig.GetToken());
6149 //*******************************************************************************
6150 // We should have collected all the method impls. Cycle through them creating the method impl
6151 // structure that holds the information about which slots are overridden.
6153 MethodTableBuilder::PlaceMethodImpls()
6155 STANDARD_VM_CONTRACT;
6157 if(bmtMethodImpl->pIndex == 0)
6162 // Allocate some temporary storage. The number of overrides for a single method impl
6163 // cannot be greater then the number of vtable slots for classes. But for interfaces
6164 // it might contain overrides for other interface methods.
6165 DWORD dwMaxSlotSize = IsInterface() ? bmtMethod->dwNumberMethodImpls : bmtVT->cVirtualSlots;
6167 DWORD * slots = new (&GetThread()->m_MarshalAlloc) DWORD[dwMaxSlotSize];
6168 mdToken * tokens = new (&GetThread()->m_MarshalAlloc) mdToken[dwMaxSlotSize];
6169 RelativePointer<MethodDesc *> * replaced = new (&GetThread()->m_MarshalAlloc) RelativePointer<MethodDesc*>[dwMaxSlotSize];
6172 bmtMDMethod * pCurImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6174 DWORD slotIndex = 0;
6176 // The impls are sorted according to the method descs for the body of the method impl.
6177 // Loop through the impls until the next body is found. When a single body
6178 // has been done move the slots implemented and method descs replaced into the storage
6179 // found on the body method desc.
6181 { // collect information until we reach the next body
6183 tokens[slotIndex] = bmtMethodImpl->GetDeclarationToken(iEntry);
6185 // Get the declaration part of the method impl. It will either be a token
6186 // (declaration is on this type) or a method desc.
6187 bmtMethodHandle hDeclMethod = bmtMethodImpl->GetDeclarationMethod(iEntry);
6188 if(hDeclMethod.IsMDMethod())
6190 // The declaration is on the type being built
6191 bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod();
6193 mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken();
6194 if (bmtMethodImpl->IsBody(mdef))
6195 { // A method declared on this class cannot be both a decl and an impl
6196 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
6202 PlaceInterfaceDeclarationOnInterface(
6205 slots, // Adds override to the slot and replaced arrays.
6208 dwMaxSlotSize); // Increments count
6213 PlaceLocalDeclarationOnClass(
6216 slots, // Adds override to the slot and replaced arrays.
6219 dwMaxSlotSize); // Increments count
6224 bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();
6229 PlaceInterfaceDeclarationOnInterface(
6232 slots, // Adds override to the slot and replaced arrays.
6235 dwMaxSlotSize); // Increments count
6239 // Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
6240 if (pCurDeclMethod->GetOwningType()->IsInterface())
6243 PlaceInterfaceDeclarationOnClass(
6250 PlaceParentDeclarationOnClass(
6256 dwMaxSlotSize); // Increments count
6263 if(iEntry == bmtMethodImpl->pIndex)
6265 // We hit the end of the list so dump the current data and leave
6266 WriteMethodImplData(pCurImplMethod, slotIndex, slots, tokens, replaced);
6271 bmtMDMethod * pNextImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6273 if (pNextImplMethod != pCurImplMethod)
6275 // If we're moving on to a new body, dump the current data and reset the counter
6276 WriteMethodImplData(pCurImplMethod, slotIndex, slots, tokens, replaced);
6280 pCurImplMethod = pNextImplMethod;
6282 } // while(next != NULL)
6283 } // MethodTableBuilder::PlaceMethodImpls
6285 //*******************************************************************************
6287 MethodTableBuilder::WriteMethodImplData(
6288 bmtMDMethod * pImplMethod,
6292 RelativePointer<MethodDesc *> * rgDeclMD)
6294 STANDARD_VM_CONTRACT;
6296 // Use the number of overrides to
6297 // push information on to the method desc. We store the slots that
6298 // are overridden and the method desc that is replaced. That way
6299 // when derived classes need to determine if the method is to be
6300 // overridden then it can check the name against the replaced
6301 // method desc not the bodies name.
6304 //@TODO:NEWVTWORK: Determine methodImpl status so that we don't need this workaround.
6305 //@TODO:NEWVTWORK: This occurs when only interface decls are involved, since
6306 //@TODO:NEWVTWORK: these are stored in the dispatch map and not on the methoddesc.
6310 MethodImpl * pImpl = pImplMethod->GetMethodDesc()->GetMethodImpl();
6312 // Set the size of the info the MethodImpl needs to keep track of.
6313 pImpl->SetSize(GetLoaderAllocator()->GetHighFrequencyHeap(), GetMemTracker(), cSlots);
6317 // If we are currently builting an interface, the slots here has no meaning and we can skip it
6318 // Sort the two arrays in slot index order
6319 // This is required in MethodImpl::FindSlotIndex and MethodImpl::Iterator as we'll be using
6320 // binary search later
6321 for (DWORD i = 0; i < cSlots; i++)
6324 for (DWORD j = i + 1; j < cSlots; j++)
6326 if (rgSlots[j] < rgSlots[min])
6334 MethodDesc * mTmp = rgDeclMD[i].GetValue();
6335 rgDeclMD[i].SetValue(rgDeclMD[min].GetValue());
6336 rgDeclMD[min].SetValue(mTmp);
6338 DWORD sTmp = rgSlots[i];
6339 rgSlots[i] = rgSlots[min];
6340 rgSlots[min] = sTmp;
6342 mdToken tTmp = rgTokens[i];
6343 rgTokens[i] = rgTokens[min];
6344 rgTokens[min] = tTmp;
6349 // Go and set the method impl
6350 pImpl->SetData(rgSlots, rgTokens, rgDeclMD);
6352 GetHalfBakedClass()->SetContainsMethodImpls();
6354 } // MethodTableBuilder::WriteMethodImplData
6356 //*******************************************************************************
6358 MethodTableBuilder::PlaceLocalDeclarationOnClass(
6359 bmtMDMethod * pDecl,
6360 bmtMDMethod * pImpl,
6362 RelativePointer<MethodDesc *> * replaced,
6364 DWORD dwMaxSlotSize)
6369 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6370 PRECONDITION(CheckPointer(pDecl));
6371 PRECONDITION(CheckPointer(pImpl));
6375 if (!bmtProp->fNoSanityChecks)
6377 ///////////////////////////////
6378 // Verify the signatures match
6380 MethodImplCompareSignatures(
6383 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_LOCAL_METHOD_IMPL);
6385 ///////////////////////////////
6386 // Validate the method impl.
6389 bmtMethodHandle(pDecl),
6390 bmtMethodHandle(pImpl));
6393 // Don't allow overrides for any of the four special runtime implemented delegate methods
6396 LPCUTF8 strMethodName = pDecl->GetMethodSignature().GetName();
6397 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
6398 (strcmp(strMethodName, "Invoke") == 0) ||
6399 (strcmp(strMethodName, "BeginInvoke") == 0) ||
6400 (strcmp(strMethodName, "EndInvoke") == 0))
6402 BuildMethodTableThrowException(
6403 IDS_CLASSLOAD_MI_CANNOT_OVERRIDE,
6404 pDecl->GetMethodSignature().GetToken());
6411 // Call helper to add it. Will throw if decl is already MethodImpl'd
6412 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6413 AddMethodImplDispatchMapping(
6414 DispatchMapTypeID::ThisClassID(),
6415 pDecl->GetSlotIndex(),
6418 // We implement this slot, record it
6419 ASSERT(*pSlotIndex < dwMaxSlotSize);
6420 slots[*pSlotIndex] = pDecl->GetSlotIndex();
6421 replaced[*pSlotIndex].SetValue(pDecl->GetMethodDesc());
6423 // increment the counter
6425 } // MethodTableBuilder::PlaceLocalDeclarationOnClass
6427 //*******************************************************************************
6428 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnClass(
6429 bmtRTMethod * pDecl,
6430 bmtMDMethod * pImpl)
6434 PRECONDITION(CheckPointer(pDecl));
6435 PRECONDITION(CheckPointer(pImpl));
6436 PRECONDITION(pDecl->GetMethodDesc()->IsInterface());
6437 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6440 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6441 MethodTable * pDeclMT = pDeclMD->GetMethodTable();
6443 // Note that the fact that pDecl is non-NULL means that we found the
6444 // declaration token to be owned by a declared interface for this type.
6446 if (!bmtProp->fNoSanityChecks)
6448 ///////////////////////////////
6449 // Verify the signatures match
6451 MethodImplCompareSignatures(
6454 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6456 ///////////////////////////////
6457 // Validate the method impl.
6460 bmtMethodHandle(pDecl),
6461 bmtMethodHandle(pImpl));
6467 // Note that we need only one DispatchMapTypeID for this interface (though there might be more if there
6468 // are duplicates). The first one is easy to get, but we could (in theory) use the last one or a random
6470 // Q: Why don't we have to place this method for all duplicate interfaces? Because VSD knows about
6471 // duplicates and finds the right (latest) implementation for us - see
6472 // code:MethodTable::MethodDataInterfaceImpl::PopulateNextLevel#ProcessAllDuplicates.
6473 UINT32 cInterfaceDuplicates;
6474 DispatchMapTypeID firstDispatchMapTypeID;
6475 ComputeDispatchMapTypeIDs(
6477 &pDecl->GetMethodSignature().GetSubstitution(),
6478 &firstDispatchMapTypeID,
6480 &cInterfaceDuplicates);
6481 CONSISTENCY_CHECK(cInterfaceDuplicates >= 1);
6482 CONSISTENCY_CHECK(firstDispatchMapTypeID.IsImplementedInterface());
6484 // Call helper to add it. Will throw if decl is already MethodImpl'd
6485 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6486 AddMethodImplDispatchMapping(
6487 firstDispatchMapTypeID,
6488 pDecl->GetSlotIndex(),
6491 #ifdef FEATURE_PREJIT
6492 if (IsCompilationProcess())
6495 // Mark this interface as overridable. It is used to skip generation of
6496 // CCWs stubs during NGen (see code:MethodNeedsReverseComStub)
6498 if (!IsMdFinal(pImpl->GetDeclAttrs()))
6500 pDeclMT->GetWriteableDataForWrite()->SetIsOverridingInterface();
6506 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
6507 { // We injected interface duplicates
6509 // We have to MethodImpl all interface duplicates as all duplicates are 'declared on type' (see
6510 // code:#InjectInterfaceDuplicates_ApproxInterfaces)
6511 DispatchMapTypeID * rgDispatchMapTypeIDs = (DispatchMapTypeID *)_alloca(sizeof(DispatchMapTypeID) * cInterfaceDuplicates);
6512 ComputeDispatchMapTypeIDs(
6514 &pDecl->GetMethodSignature().GetSubstitution(),
6515 rgDispatchMapTypeIDs,
6516 cInterfaceDuplicates,
6517 &cInterfaceDuplicates);
6518 for (UINT32 nInterfaceDuplicate = 1; nInterfaceDuplicate < cInterfaceDuplicates; nInterfaceDuplicate++)
6520 // Add MethodImpl record for each injected interface duplicate
6521 AddMethodImplDispatchMapping(
6522 rgDispatchMapTypeIDs[nInterfaceDuplicate],
6523 pDecl->GetSlotIndex(),
6528 } // MethodTableBuilder::PlaceInterfaceDeclarationOnClass
6530 //*******************************************************************************
6531 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnInterface(
6532 bmtMethodHandle hDecl,
6535 RelativePointer<MethodDesc *> * replaced,
6537 DWORD dwMaxSlotSize)
6541 PRECONDITION(CheckPointer(pImpl));
6542 PRECONDITION(IsInterface());
6543 PRECONDITION(hDecl.GetMethodDesc()->IsInterface());
6546 MethodDesc * pDeclMD = hDecl.GetMethodDesc();
6548 if (!bmtProp->fNoSanityChecks)
6550 ///////////////////////////////
6551 // Verify the signatures match
6553 MethodImplCompareSignatures(
6555 bmtMethodHandle(pImpl),
6556 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6558 ///////////////////////////////
6559 // Validate the method impl.
6561 TestMethodImpl(hDecl, bmtMethodHandle(pImpl));
6564 // We implement this slot, record it
6565 ASSERT(*pSlotIndex < dwMaxSlotSize);
6566 slots[*pSlotIndex] = hDecl.GetSlotIndex();
6567 replaced[*pSlotIndex].SetValue(pDeclMD);
6569 // increment the counter
6571 } // MethodTableBuilder::PlaceInterfaceDeclarationOnInterface
6573 //*******************************************************************************
6575 MethodTableBuilder::PlaceParentDeclarationOnClass(
6576 bmtRTMethod * pDecl,
6577 bmtMDMethod * pImpl,
6579 RelativePointer<MethodDesc *> * replaced,
6581 DWORD dwMaxSlotSize)
6585 PRECONDITION(CheckPointer(pDecl));
6586 PRECONDITION(CheckPointer(pImpl));
6587 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6588 PRECONDITION(CheckPointer(GetParentMethodTable()));
6591 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6593 // Note that the fact that pDecl is non-NULL means that we found the
6594 // declaration token to be owned by a parent type.
6596 if (!bmtProp->fNoSanityChecks)
6598 /////////////////////////////////////////
6599 // Verify that the signatures match
6601 MethodImplCompareSignatures(
6604 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_PARENT_METHOD_IMPL);
6606 ////////////////////////////////
6607 // Verify rules of method impls
6610 bmtMethodHandle(pDecl),
6611 bmtMethodHandle(pImpl));
6617 // Call helper to add it. Will throw if DECL is already MethodImpl'd
6618 AddMethodImplDispatchMapping(
6619 DispatchMapTypeID::ThisClassID(),
6623 // We implement this slot, record it
6624 ASSERT(*pSlotIndex < dwMaxSlotSize);
6625 slots[*pSlotIndex] = pDeclMD->GetSlot();
6626 replaced[*pSlotIndex].SetValue(pDeclMD);
6628 // increment the counter
6630 } // MethodTableBuilder::PlaceParentDeclarationOnClass
6632 //*******************************************************************************
6633 // This will validate that all interface methods that were matched during
6634 // layout also validate against type constraints.
6636 VOID MethodTableBuilder::ValidateInterfaceMethodConstraints()
6638 STANDARD_VM_CONTRACT;
6640 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6641 for (; it.IsValid(); it.Next())
6643 if (it.GetTypeID() != DispatchMapTypeID::ThisClassID())
6645 bmtRTType * pItf = bmtInterface->pInterfaceMap[it.GetTypeID().GetInterfaceNum()].GetInterfaceType();
6647 // Grab the method token
6648 MethodTable * pMTItf = pItf->GetMethodTable();
6649 CONSISTENCY_CHECK(CheckPointer(pMTItf->GetMethodDescForSlot(it.GetSlotNumber())));
6650 mdMethodDef mdTok = pItf->GetMethodTable()->GetMethodDescForSlot(it.GetSlotNumber())->GetMemberDef();
6652 // Default to the current module. The code immediately below determines if this
6653 // assumption is incorrect.
6654 Module * pTargetModule = GetModule();
6656 // Get the module of the target method. Get it through the chunk to
6657 // avoid triggering the assert that MethodTable is non-NULL. It may
6658 // be null since it may belong to the type we're building right now.
6659 MethodDesc * pTargetMD = it.GetTargetMD();
6661 // If pTargetMT is null, this indicates that the target MethodDesc belongs
6662 // to the current type. Otherwise, the MethodDesc MUST be owned by a parent
6663 // of the type we're building.
6664 BOOL fTargetIsOwnedByParent = !pTargetMD->GetMethodTablePtr()->IsNull();
6666 // If the method is owned by a parent, we need to use the parent's module,
6667 // and we must construct the substitution chain all the way up to the parent.
6668 const Substitution *pSubstTgt = NULL;
6669 if (fTargetIsOwnedByParent)
6671 CONSISTENCY_CHECK(CheckPointer(GetParentType()));
6672 bmtRTType *pTargetType = bmtRTType::FindType(GetParentType(), pTargetMD->GetMethodTable());
6673 pSubstTgt = &pTargetType->GetSubstitution();
6674 pTargetModule = pTargetType->GetModule();
6677 // Now compare the method constraints.
6678 if (!MetaSig::CompareMethodConstraints(pSubstTgt,
6680 pTargetMD->GetMemberDef(),
6681 &pItf->GetSubstitution(),
6682 pMTItf->GetModule(),
6685 LOG((LF_CLASSLOADER, LL_INFO1000,
6686 "BADCONSTRAINTS on interface method implementation: %x\n", pTargetMD));
6687 // This exception will be due to an implicit implementation, since explicit errors
6688 // will be detected in MethodImplCompareSignatures (for now, anyway).
6689 CONSISTENCY_CHECK(!it.IsMethodImpl());
6690 DWORD idsError = it.IsMethodImpl() ?
6691 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL :
6692 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_IMPLEMENTATION;
6693 if (fTargetIsOwnedByParent)
6695 DefineFullyQualifiedNameForClass();
6696 LPCUTF8 szClassName = GetFullyQualifiedNameForClassNestedAware(pTargetMD->GetMethodTable());
6697 LPCUTF8 szMethodName = pTargetMD->GetName();
6700 // allocate enough room for "<class>.<method>\0"
6701 size_t cchFullName = strlen(szClassName) + 1 + strlen(szMethodName) + 1;
6702 LPUTF8 szFullName = (LPUTF8) qb.AllocThrows(cchFullName);
6703 strcpy_s(szFullName, cchFullName, szClassName);
6704 strcat_s(szFullName, cchFullName, ".");
6705 strcat_s(szFullName, cchFullName, szMethodName);
6707 BuildMethodTableThrowException(idsError, szFullName);
6711 BuildMethodTableThrowException(idsError, pTargetMD->GetMemberDef());
6716 } // MethodTableBuilder::ValidateInterfaceMethodConstraints
6718 //*******************************************************************************
6719 // Used to allocate and initialize MethodDescs (both the boxed and unboxed entrypoints)
6720 VOID MethodTableBuilder::AllocAndInitMethodDescs()
6722 STANDARD_VM_CONTRACT;
6725 // Go over all MethodDescs and create smallest number of MethodDescChunks possible.
6727 // Iterate over all methods and start a new chunk only if:
6728 // - Token range (upper 24 bits of the method token) has changed.
6729 // - The maximum size of the chunk has been reached.
6732 int currentTokenRange = -1; // current token range
6733 SIZE_T sizeOfMethodDescs = 0; // current running size of methodDesc chunk
6734 int startIndex = 0; // start of the current chunk (index into bmtMethod array)
6736 DeclaredMethodIterator it(*this);
6739 int tokenRange = GetTokenRange(it.Token());
6741 // This code assumes that iterator returns tokens in ascending order. If this assumption does not hold,
6742 // the code will still work with small performance penalty (method desc chunk layout will be less efficient).
6743 _ASSERTE(tokenRange >= currentTokenRange);
6745 SIZE_T size = MethodDesc::GetBaseSize(GetMethodClassification(it->GetMethodType()));
6747 // Add size of optional slots
6749 if (it->GetMethodImplType() == METHOD_IMPL)
6750 size += sizeof(MethodImpl);
6752 if (it->GetSlotIndex() >= bmtVT->cVtableSlots)
6753 size += sizeof(MethodDesc::NonVtableSlot); // slot
6755 if (NeedsNativeCodeSlot(*it))
6756 size += sizeof(MethodDesc::NativeCodeSlot);
6758 // See comment in AllocAndInitMethodDescChunk
6759 if (NeedsTightlyBoundUnboxingStub(*it))
6763 if (bmtGenerics->GetNumGenericArgs() == 0) {
6764 size += sizeof(MethodDesc::NonVtableSlot);
6767 bmtVT->cVtableSlots++;
6771 #ifndef CROSSGEN_COMPILE
6772 if (tokenRange != currentTokenRange ||
6773 sizeOfMethodDescs + size > MethodDescChunk::MaxSizeOfMethodDescs)
6774 #endif // CROSSGEN_COMPILE
6776 if (sizeOfMethodDescs != 0)
6778 AllocAndInitMethodDescChunk(startIndex, it.CurrentIndex() - startIndex, sizeOfMethodDescs);
6779 startIndex = it.CurrentIndex();
6782 currentTokenRange = tokenRange;
6783 sizeOfMethodDescs = 0;
6786 sizeOfMethodDescs += size;
6789 if (sizeOfMethodDescs != 0)
6791 AllocAndInitMethodDescChunk(startIndex, NumDeclaredMethods() - startIndex, sizeOfMethodDescs);
6795 //*******************************************************************************
6796 // Allocates and initializes one method desc chunk.
6799 // startIndex - index of first method in bmtMethod array.
6800 // count - number of methods in this chunk (contiguous region from startIndex)
6801 // sizeOfMethodDescs - total expected size of MethodDescs in this chunk
6803 // Used by AllocAndInitMethodDescs.
6805 VOID MethodTableBuilder::AllocAndInitMethodDescChunk(COUNT_T startIndex, COUNT_T count, SIZE_T sizeOfMethodDescs)
6809 PRECONDITION(sizeOfMethodDescs <= MethodDescChunk::MaxSizeOfMethodDescs);
6812 void * pMem = GetMemTracker()->Track(
6813 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TADDR) + sizeof(MethodDescChunk) + sizeOfMethodDescs)));
6815 // Skip pointer to temporary entrypoints
6816 MethodDescChunk * pChunk = (MethodDescChunk *)((BYTE*)pMem + sizeof(TADDR));
6818 COUNT_T methodDescCount = 0;
6820 SIZE_T offset = sizeof(MethodDescChunk);
6823 #pragma warning(push)
6824 #pragma warning(disable:22019) // Suppress PREFast warning about integer underflow
6826 for (COUNT_T i = 0; i < count; i++)
6828 #pragma warning(pop)
6832 bmtMDMethod * pMDMethod = (*bmtMethod)[static_cast<SLOT_INDEX>(startIndex + i)];
6834 MethodDesc * pMD = (MethodDesc *)((BYTE *)pChunk + offset);
6836 pMD->SetChunkIndex(pChunk);
6838 InitNewMethodDesc(pMDMethod, pMD);
6841 #pragma warning(push)
6842 #pragma warning(disable:22018) // Suppress PREFast warning about integer underflow
6844 offset += pMD->SizeOf();
6846 #pragma warning(pop)
6851 // If we're a value class, we want to create duplicate slots
6852 // and MethodDescs for all methods in the vtable
6853 // section (i.e. not non-virtual instance methods or statics).
6854 // In the name of uniformity it would be much nicer
6855 // if we created _all_ value class BoxedEntryPointStubs at this point.
6856 // However, non-virtual instance methods only require unboxing
6857 // stubs in the rare case that we create a delegate to such a
6858 // method, and thus it would be inefficient to create them on
6859 // loading: after all typical structs will have many non-virtual
6860 // instance methods.
6862 // Unboxing stubs for non-virtual instance methods are created
6863 // in code:MethodDesc::FindOrCreateAssociatedMethodDesc.
6865 if (NeedsTightlyBoundUnboxingStub(pMDMethod))
6867 MethodDesc * pUnboxedMD = (MethodDesc *)((BYTE *)pChunk + offset);
6869 //////////////////////////////////
6870 // Initialize the new MethodDesc
6872 // <NICE> memcpy operations on data structures like MethodDescs are extremely fragile
6873 // and should not be used. We should go to the effort of having proper constructors
6874 // in the MethodDesc class. </NICE>
6876 memcpy(pUnboxedMD, pMD, pMD->SizeOf());
6878 // Reset the chunk index
6879 pUnboxedMD->SetChunkIndex(pChunk);
6881 if (bmtGenerics->GetNumGenericArgs() == 0) {
6882 pUnboxedMD->SetHasNonVtableSlot();
6885 //////////////////////////////////////////////////////////
6886 // Modify the original MethodDesc to be an unboxing stub
6888 pMD->SetIsUnboxingStub();
6890 ////////////////////////////////////////////////////////////////////
6891 // Add the new MethodDesc to the non-virtual portion of the vtable
6893 if (!bmtVT->AddUnboxedMethod(pMDMethod))
6894 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
6896 pUnboxedMD->SetSlot(pMDMethod->GetUnboxedSlotIndex());
6897 pMDMethod->SetUnboxedMethodDesc(pUnboxedMD);
6899 offset += pUnboxedMD->SizeOf();
6903 _ASSERTE(offset == sizeof(MethodDescChunk) + sizeOfMethodDescs);
6905 pChunk->SetSizeAndCount((ULONG)sizeOfMethodDescs, methodDescCount);
6907 GetHalfBakedClass()->AddChunk(pChunk);
6910 //*******************************************************************************
6912 MethodTableBuilder::NeedsTightlyBoundUnboxingStub(bmtMDMethod * pMDMethod)
6914 STANDARD_VM_CONTRACT;
6916 return IsValueClass() &&
6917 !IsMdStatic(pMDMethod->GetDeclAttrs()) &&
6918 IsMdVirtual(pMDMethod->GetDeclAttrs()) &&
6919 (pMDMethod->GetMethodType() != METHOD_TYPE_INSTANTIATED) &&
6920 !IsMdRTSpecialName(pMDMethod->GetDeclAttrs());
6923 //*******************************************************************************
6925 MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
6927 LIMITED_METHOD_CONTRACT;
6930 #ifdef FEATURE_TIERED_COMPILATION
6931 // Keep in-sync with MethodDesc::DetermineAndSetIsEligibleForTieredCompilation()
6932 if (g_pConfig->TieredCompilation() &&
6933 (pMDMethod->GetMethodType() == METHOD_TYPE_NORMAL || pMDMethod->GetMethodType() == METHOD_TYPE_INSTANTIATED))
6939 #if defined(FEATURE_JIT_PITCHING)
6940 if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchEnabled) != 0) &&
6941 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchMemThreshold) != 0))
6945 return GetModule()->IsEditAndContinueEnabled();
6948 //*******************************************************************************
6950 MethodTableBuilder::AllocAndInitDictionary()
6952 STANDARD_VM_CONTRACT;
6954 // Allocate dictionary layout used by all compatible instantiations
6956 if (bmtGenerics->fSharedByGenericInstantiations && !bmtGenerics->fContainsGenericVariables)
6958 // We use the number of methods as a heuristic for the number of slots in the dictionary
6959 // attached to shared class method tables.
6960 // If there are no declared methods then we have no slots, and we will never do any token lookups
6963 // - Classes with a small number of methods (2-3) tend to be more likely to use new slots,
6964 // i.e. further methods tend to reuse slots from previous methods.
6965 // = treat all classes with only 2-3 methods as if they have an extra method.
6966 // - Classes with more generic parameters tend to use more slots.
6967 // = multiply by 1.5 for 2 params or more
6969 DWORD numMethodsAdjusted =
6970 (bmtMethod->dwNumDeclaredNonAbstractMethods == 0)
6972 : (bmtMethod->dwNumDeclaredNonAbstractMethods < 3)
6974 : bmtMethod->dwNumDeclaredNonAbstractMethods;
6976 _ASSERTE(bmtGenerics->GetNumGenericArgs() != 0);
6977 DWORD nTypeFactorBy2 = (bmtGenerics->GetNumGenericArgs() == 1)
6981 DWORD estNumTypeSlots = (numMethodsAdjusted * nTypeFactorBy2 + 2) / 3;
6982 // estNumTypeSlots should fit in a WORD as long as we maintain the current
6983 // limit on the number of methods in a type (approx 2^16).
6984 _ASSERTE(FitsIn<WORD>(estNumTypeSlots));
6985 WORD numTypeSlots = static_cast<WORD>(estNumTypeSlots);
6987 if (numTypeSlots > 0)
6989 // Dictionary layout is an optional field on EEClass, so ensure the optional field descriptor has
6991 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
6992 GetHalfBakedClass()->SetDictionaryLayout(DictionaryLayout::Allocate(numTypeSlots, bmtAllocator, m_pAllocMemTracker));
6998 //*******************************************************************************
7000 // Used by BuildMethodTable
7002 // Compute the set of interfaces which are equivalent. Duplicates in the interface map
7003 // will be placed into different equivalence sets unless they participate in type equivalence.
7004 // This is a bit odd, but it turns out we only need to know about equivalence classes if
7005 // there is type equivalence involved in the interface, and not detecting, or detecting equivalence
7006 // in other cases does not result in differing behavior.
7008 // By restricting the reasons for having equivalence matches, we reduce the algorithm from one which
7009 // is O(n*n) best case to an algorithm which will typically execute something more like O(m*n) best case time
7010 // where m is the number of generic interface (although still n*n in worst case). The assumption is that equivalent
7011 // and generic interfaces are relatively rare.
7013 MethodTableBuilder::ComputeInterfaceMapEquivalenceSet()
7015 STANDARD_VM_CONTRACT;
7017 UINT32 nextEquivalenceSet = 1;
7019 for (DWORD dwCurInterface = 0;
7020 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7023 // Keep track of the current interface we are trying to calculate the equivalence set of
7024 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7025 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7026 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7027 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7029 UINT32 currentEquivalenceSet = 0;
7031 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7032 if (pCurItfMT->HasTypeEquivalence() || pCurItfMT->HasInstantiation())
7034 for (DWORD dwCurInterfaceCompare = 0;
7035 dwCurInterfaceCompare < dwCurInterface;
7036 dwCurInterfaceCompare++)
7038 // Keep track of the current interface we are trying to calculate the equivalence set of
7039 bmtInterfaceEntry * pCompareItfEntry = &bmtInterface->pInterfaceMap[dwCurInterfaceCompare];
7040 bmtRTType * pCompareItf = pCompareItfEntry->GetInterfaceType();
7041 MethodTable * pCompareItfMT = pCompareItf->GetMethodTable();
7042 const Substitution * pCompareItfSubst = &pCompareItf->GetSubstitution();
7044 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7045 if (pCompareItfMT->HasTypeEquivalence() || pCompareItfMT->HasInstantiation())
7047 if (MetaSig::CompareTypeDefsUnderSubstitutions(pCurItfMT,
7053 currentEquivalenceSet = pCompareItfEntry->GetInterfaceEquivalenceSet();
7054 // Use the equivalence set of the interface map entry we just found
7055 pCurItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7056 // Update the interface map entry we just found to indicate that it is part of an equivalence
7057 // set with multiple entries.
7058 pCompareItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7065 // If we did not find an equivalent interface above, use the next available equivalence set indicator
7066 if (currentEquivalenceSet == 0)
7068 pCurItfEntry->SetInterfaceEquivalenceSet(nextEquivalenceSet, false);
7069 nextEquivalenceSet++;
7074 //*******************************************************************************
7076 // Used by PlaceInterfaceMethods
7078 // Given an interface in our interface map, and a particular method on that interface, place
7079 // a method from the parent types implementation of an equivalent interface into that method
7080 // slot. Used by PlaceInterfaceMethods to make equivalent interface implementations have the
7081 // same behavior as if the parent interface was implemented on this type instead of an equivalent interface.
7083 // This logic is used in situations such as below. I and I' are equivalent interfaces
7087 // {void I.Method() { } }
7088 // interface IOther : I' {}
7089 // class Derived : IOther
7090 // { virtual void Method() {}}
7092 // We should Map I'.Method to Base.Method, not Derived.Method
7096 // { virtual void Method() }
7097 // interface IOther : I' {}
7098 // class Derived : IOther
7099 // { virtual void Method() {}}
7101 // We should map I'.Method to Base.Method, not Derived.Method
7104 // {void I.Method() { } }
7105 // class Derived : I'
7108 // We should Map I'.Method to Base.Method, and not throw TypeLoadException
7110 #ifdef FEATURE_COMINTEROP
7112 MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(
7113 bmtInterfaceEntry::InterfaceSlotIterator & itfSlotIt,
7114 bmtInterfaceEntry * pCurItfEntry,
7115 DispatchMapTypeID ** prgInterfaceDispatchMapTypeIDs,
7116 DWORD dwCurInterface)
7118 STANDARD_VM_CONTRACT;
7120 bmtRTMethod * pCurItfMethod = itfSlotIt->Decl().AsRTMethod();
7122 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7127 // For every equivalent interface entry that was actually implemented by parent, then look at equivalent method slot on that entry
7128 // and if it matches and has a slot implementation, then record and continue
7129 for (DWORD dwEquivalentInterface = 0;
7130 (dwEquivalentInterface < bmtInterface->dwInterfaceMapSize) && (itfSlotIt->Impl() == INVALID_SLOT_INDEX);
7131 dwEquivalentInterface++)
7133 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7134 bmtRTType * pEquivItf = pEquivItfEntry->GetInterfaceType();
7135 MethodTable * pEquivItfMT = pEquivItf->GetMethodTable();
7136 const Substitution * pEquivItfSubst = &pEquivItf->GetSubstitution();
7137 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7142 if (!pEquivItfEntry->IsImplementedByParent())
7144 // Not implemented by parent
7148 WORD slot = static_cast<WORD>(itfSlotIt.CurrentIndex());
7149 BOOL fFound = FALSE;
7151 // Determine which slot on the equivalent interface would map to the slot we are attempting to fill
7152 // in with an implementation.
7153 WORD otherMTSlot = GetEquivalentMethodSlot(pCurItfEntry->GetInterfaceType()->GetMethodTable(),
7154 pEquivItfEntry->GetInterfaceType()->GetMethodTable(),
7160 UINT32 cInterfaceDuplicates;
7161 if (*prgInterfaceDispatchMapTypeIDs == NULL)
7163 *prgInterfaceDispatchMapTypeIDs =
7164 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7167 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7168 ComputeDispatchMapTypeIDs(
7171 *prgInterfaceDispatchMapTypeIDs,
7172 bmtInterface->dwInterfaceMapSize,
7173 &cInterfaceDuplicates);
7174 // There cannot be more duplicates than number of interfaces
7175 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7176 _ASSERTE(cInterfaceDuplicates > 0);
7178 // NOTE: This override does not cache the resulting MethodData object
7179 MethodTable::MethodDataWrapper hParentData;
7180 hParentData = MethodTable::GetMethodData(
7181 *prgInterfaceDispatchMapTypeIDs,
7182 cInterfaceDuplicates,
7184 GetParentMethodTable());
7186 SLOT_INDEX slotIndex = static_cast<SLOT_INDEX>
7187 (hParentData->GetImplSlotNumber(static_cast<UINT32>(otherMTSlot)));
7189 // Interface is implemented on parent abstract type and this particular slot was not implemented
7190 if (slotIndex == INVALID_SLOT_INDEX)
7195 bmtMethodSlot & parentSlotImplementation = (*bmtParent->pSlotTable)[slotIndex];
7196 bmtMethodHandle & parentImplementation = parentSlotImplementation.Impl();
7198 // Check to verify that the equivalent slot on the equivalent interface actually matches the method
7199 // on the current interface. If not, then the slot is not a match, and we should search other interfaces
7200 // for an implementation of the method.
7201 if (!MethodSignature::SignaturesEquivalent(pCurItfMethod->GetMethodSignature(), parentImplementation.GetMethodSignature()))
7206 itfSlotIt->Impl() = slotIndex;
7208 MethodDesc * pMD = hParentData->GetImplMethodDesc(static_cast<UINT32>(otherMTSlot));
7210 DispatchMapTypeID dispatchMapTypeID =
7211 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7212 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7214 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7219 } // MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot
7220 #endif // FEATURE_COMINTEROP
7222 //*******************************************************************************
7224 // Used by BuildMethodTable
7227 // If we are a class, then there may be some unplaced vtable methods (which are by definition
7228 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
7229 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
7230 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
7231 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
7232 // map for all interfaces as they are placed.
7234 // If we are an interface, then all methods are already placed. Fill out the interface map for
7235 // interfaces as they are placed.
7237 // BEHAVIOUR (based on Partition II: 11.2, not including MethodImpls)
7238 // C is current class, P is a parent class, I is the interface being implemented
7240 // FOREACH interface I implemented by this class C
7241 // FOREACH method I::M
7242 // IF I is EXPLICITLY implemented by C
7243 // IF some method C::M matches I::M
7244 // USE C::M as implementation for I::M
7245 // ELIF we inherit a method P::M that matches I::M
7246 // USE P::M as implementation for I::M
7249 // IF I::M lacks implementation
7250 // IF some method C::M matches I::M
7251 // USE C::M as implementation for I::M
7252 // ELIF we inherit a method P::M that matches I::M
7253 // USE P::M as implementation for I::M
7254 // ELIF I::M was implemented by the parent type with method Parent::M
7255 // USE Parent::M for the implementation of I::M // VSD does this by default if we really
7256 // // implemented I on the parent type, but
7257 // // equivalent interfaces need to make this
7267 MethodTableBuilder::PlaceInterfaceMethods()
7269 STANDARD_VM_CONTRACT;
7271 BOOL fParentInterface;
7272 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs = NULL;
7274 for (DWORD dwCurInterface = 0;
7275 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7278 // Default to being implemented by the current class
7279 fParentInterface = FALSE;
7281 // Keep track of the current interface we are trying to place
7282 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7283 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7284 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7285 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7288 // There are three reasons why an interface could be in the implementation list
7289 // 1. Inherited from parent
7290 // 2. Explicitly declared in the implements list
7291 // 3. Implicitly declared through the implements list of an explicitly declared interface
7293 // The reason these cases need to be distinguished is that an inherited interface that is
7294 // also explicitly redeclared in the implements list must be fully reimplemented using the
7295 // virtual methods of this type (thereby using matching methods in this type that may have
7296 // a different slot than an inherited method, but hidden it by name & sig); however all
7297 // implicitly redeclared interfaces should not be fully reimplemented if they were also
7298 // inherited from the parent.
7301 // interface I1 : I2
7305 // In this example I1 must be fully reimplemented on B, but B can inherit the implementation
7309 if (pCurItfEntry->IsImplementedByParent())
7311 if (!pCurItfEntry->IsDeclaredOnType())
7313 fParentInterface = TRUE;
7317 bool fEquivalentInterfaceImplementedByParent = pCurItfEntry->IsImplementedByParent();
7318 bool fEquivalentInterfaceDeclaredOnType = pCurItfEntry->IsDeclaredOnType();
7320 if (pCurItfEntry->InEquivalenceSetWithMultipleEntries())
7322 for (DWORD dwEquivalentInterface = 0;
7323 dwEquivalentInterface < bmtInterface->dwInterfaceMapSize;
7324 dwEquivalentInterface++)
7326 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7327 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7332 if (pEquivItfEntry->IsImplementedByParent())
7334 fEquivalentInterfaceImplementedByParent = true;
7336 if (pEquivItfEntry->IsDeclaredOnType())
7338 fEquivalentInterfaceDeclaredOnType = true;
7341 if (fEquivalentInterfaceDeclaredOnType && fEquivalentInterfaceImplementedByParent)
7346 bool fParentInterfaceEquivalent = fEquivalentInterfaceImplementedByParent && !fEquivalentInterfaceDeclaredOnType;
7348 CONSISTENCY_CHECK(!fParentInterfaceEquivalent || HasParent());
7350 if (fParentInterfaceEquivalent)
7352 // In the case the fParentInterface is TRUE, virtual overrides are enough and the interface
7353 // does not have to be explicitly (re)implemented. The only exception is if the parent is
7354 // abstract, in which case an inherited interface may not be fully implemented yet.
7355 // This is an optimization that allows us to skip the more expensive slot filling in below.
7356 // Note that the check here is for fParentInterface and not for fParentInterfaceEquivalent.
7357 // This is necessary as if the interface is not actually implemented on the parent type we will
7358 // need to fill in the slot table below.
7359 if (fParentInterface && !GetParentMethodTable()->IsAbstract())
7365 // We will reach here in two cases.
7366 // 1 .The parent is abstract and the interface has been declared on the parent,
7367 // and possibly partially implemented, so we need to populate the
7368 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7370 // 2 .The the interface has not been declared on the parent,
7371 // but an equivalent interface has been. So we need to populate the
7372 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7373 // information from one of the parent equivalent interfaces. We may or may not
7374 // find implementations for all of the methods on the interface on the parent type.
7375 // The parent type may or may not be abstract.
7377 MethodTable::MethodDataWrapper hParentData;
7378 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
7380 if (rgInterfaceDispatchMapTypeIDs == NULL)
7382 rgInterfaceDispatchMapTypeIDs =
7383 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7386 if (pCurItfEntry->IsImplementedByParent())
7388 UINT32 cInterfaceDuplicates;
7389 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7390 ComputeDispatchMapTypeIDs(
7393 rgInterfaceDispatchMapTypeIDs,
7394 bmtInterface->dwInterfaceMapSize,
7395 &cInterfaceDuplicates);
7396 // There cannot be more duplicates than number of interfaces
7397 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7398 _ASSERTE(cInterfaceDuplicates > 0);
7400 //#InterfaceMap_UseParentInterfaceImplementations
7401 // We rely on the fact that interface map of parent type is subset of this type (incl.
7402 // duplicates), see code:#InterfaceMap_SupersetOfParent
7403 // NOTE: This override does not cache the resulting MethodData object
7404 hParentData = MethodTable::GetMethodData(
7405 rgInterfaceDispatchMapTypeIDs,
7406 cInterfaceDuplicates,
7408 GetParentMethodTable());
7410 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7411 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7412 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7414 itfSlotIt->Impl() = static_cast<SLOT_INDEX>
7415 (hParentData->GetImplSlotNumber(static_cast<UINT32>(itfSlotIt.CurrentIndex())));
7418 #ifdef FEATURE_COMINTEROP
7421 // Iterate through the methods on the interface, and if they have a slot which was filled in
7422 // on an equivalent interface inherited from the parent fill in the appropriate slot.
7423 // This code path is only used when there is an implicit implementation of an interface
7424 // that was not implemented on a parent type, but there was an equivalent interface implemented
7425 // on a parent type.
7426 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7427 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7428 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7430 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7433 #endif // FEATURE_COMINTEROP
7437 #ifdef FEATURE_COMINTEROP
7438 // WinRT types always use methodimpls to line up methods with interface implementations, so we do not want to allow implicit
7439 // interface implementations to kick in. This can especially cause problems with redirected interfaces, where the underlying
7440 // runtimeclass doesn't actually implement the interfaces we claim it does. For example, a WinRT class which implements both
7441 // IVector<int> and ICalculator will be projected as implementing IList<int> and ICalculator. In this case, we do not want the
7442 // ICalculator Add(int) method to get lined up with the ICollection<int> Add method, since that will cause us to dispatch to the
7443 // wrong underlying COM interface.
7445 // There are a special WinRT types in mscorlib (notably DisposableRuntimeClass) which do implement interfaces in the normal way
7446 // so we skip this check for them. (Note that we can't use a methodimpl directly in mscorlib, since ComImport classes are
7447 // forbidden from having implementation code by the C# compiler).
7448 if (GetHalfBakedClass()->IsProjectedFromWinRT() && !GetModule()->IsSystem())
7452 #endif // FEATURE_COMINTEROP
7454 // For each method declared in this interface
7455 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7456 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7457 for (; !itfSlotIt.AtEnd(); ++itfSlotIt)
7459 if (fParentInterfaceEquivalent)
7461 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7462 { // If this interface is not explicitly declared on this class, and the interface slot has already been
7463 // given an implementation, then the only way to provide a new implementation is through an override
7464 // or through a MethodImpl. This is necessary in addition to the continue statement before this for
7465 // loop because an abstract interface can still have a partial implementation and it is necessary to
7466 // skip those interface slots that have already been satisfied.
7471 BOOL fFoundMatchInBuildingClass = FALSE;
7472 bmtInterfaceSlotImpl & curItfSlot = *itfSlotIt;
7473 bmtRTMethod * pCurItfMethod = curItfSlot.Decl().AsRTMethod();
7474 const MethodSignature & curItfMethodSig = pCurItfMethod->GetMethodSignature();
7477 // First, try to find the method explicitly declared in our class
7480 DeclaredMethodIterator methIt(*this);
7481 while (methIt.Next())
7483 // Note that non-publics can legally be exposed via an interface, but only
7484 // through methodImpls.
7485 if (IsMdVirtual(methIt.Attrs()) && IsMdPublic(methIt.Attrs()))
7488 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(methIt.Name()))
7489 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", methIt.Name()));
7492 if (pCurItfMethod->GetMethodSignature().Equivalent(methIt->GetMethodSignature()))
7494 fFoundMatchInBuildingClass = TRUE;
7495 curItfSlot.Impl() = methIt->GetSlotIndex();
7497 DispatchMapTypeID dispatchMapTypeID =
7498 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7499 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7501 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7502 methIt->GetMethodDesc(),
7508 } // end ... try to find method
7511 // The ECMA CLR spec states that a type will inherit interface implementations
7512 // and that explicit re-declaration of an inherited interface will try to match
7513 // only newslot methods with methods in the re-declared interface (note that
7514 // this also takes care of matching against unsatisfied interface methods in
7515 // the abstract parent type scenario).
7517 // So, if the interface was not declared on a parent and we haven't found a
7518 // newslot method declared on this type as a match, search all remaining
7519 // public virtual methods (including overrides declared on this type) for a
7522 // Please see bug VSW577403 and VSW593884 for details of this breaking change.
7524 if (!fFoundMatchInBuildingClass &&
7525 !fEquivalentInterfaceImplementedByParent)
7529 // Iterate backward through the parent's method table. This is important to
7530 // find the most derived method.
7531 bmtParentInfo::Iterator parentMethodIt = bmtParent->IterateSlots();
7532 parentMethodIt.ResetToEnd();
7533 while (parentMethodIt.Prev())
7535 bmtRTMethod * pCurParentMethod = parentMethodIt->Decl().AsRTMethod();
7536 DWORD dwAttrs = pCurParentMethod->GetDeclAttrs();
7537 if (!IsMdVirtual(dwAttrs) || !IsMdPublic(dwAttrs))
7538 { // Only match mdPublic mdVirtual methods for interface implementation
7542 if (curItfMethodSig.Equivalent(pCurParentMethod->GetMethodSignature()))
7544 fFoundMatchInBuildingClass = TRUE;
7545 curItfSlot.Impl() = pCurParentMethod->GetSlotIndex();
7547 DispatchMapTypeID dispatchMapTypeID =
7548 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7549 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7551 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7552 pCurParentMethod->GetMethodDesc(),
7557 } // end ... try to find parent method
7561 // For type equivalent interfaces that had an equivalent interface implemented by their parent
7562 // and where the previous logic to fill in the method based on the virtual mappings on the type have
7563 // failed, we should attempt to get the mappings from the equivalent interfaces declared on parent types
7564 // of the type we are currently building.
7565 #ifdef FEATURE_COMINTEROP
7566 if (!fFoundMatchInBuildingClass && fEquivalentInterfaceImplementedByParent && !pCurItfEntry->IsImplementedByParent())
7568 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7573 } // MethodTableBuilder::PlaceInterfaceMethods
7576 //*******************************************************************************
7578 // Used by BuildMethodTable
7580 // Place static fields
7582 VOID MethodTableBuilder::PlaceRegularStaticFields()
7584 STANDARD_VM_CONTRACT;
7588 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing statics for %s\n", this->GetDebugClassName()));
7591 // Place gc refs and value types first, as they need to have handles created for them.
7592 // (Placing them together allows us to easily create the handles when Restoring the class,
7593 // and when initializing new DLS for the class.)
7596 DWORD dwCumulativeStaticFieldPos = 0 ;
7597 DWORD dwCumulativeStaticGCFieldPos = 0;
7598 DWORD dwCumulativeStaticBoxFieldPos = 0;
7600 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7601 // guaranteed to be aligned in ModuleStaticsInfo
7602 bmtFP->NumRegularStaticFieldsOfSize[LOG2_PTRSIZE] -=
7603 bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7605 // Place fields, largest first, padding so that each group is aligned to its natural size
7606 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7608 // Fields of this size start at the next available location
7609 bmtFP->RegularStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7610 dwCumulativeStaticFieldPos += (bmtFP->NumRegularStaticFieldsOfSize[i] << i);
7612 // Reset counters for the loop after this one
7613 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
7617 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7618 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7620 DWORD dwNumHandleStatics = bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7621 if (!FitsIn<WORD>(dwNumHandleStatics))
7623 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7625 SetNumHandleRegularStatics(static_cast<WORD>(dwNumHandleStatics));
7627 if (!FitsIn<WORD>(bmtFP->NumRegularStaticGCBoxedFields))
7629 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7631 SetNumBoxedRegularStatics(static_cast<WORD>(bmtFP->NumRegularStaticGCBoxedFields));
7633 // Tell the module to give us the offsets we'll be using and commit space for us
7635 DWORD dwNonGCOffset, dwGCOffset;
7636 GetModule()->GetOffsetsForRegularStaticData(bmtInternal->pType->GetTypeDefToken(),
7637 bmtProp->fDynamicStatics,
7638 GetNumHandleRegularStatics(), dwCumulativeStaticFieldPos,
7639 &dwGCOffset, &dwNonGCOffset);
7641 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7642 dwCumulativeStaticGCFieldPos = bmtFP->NumRegularStaticGCBoxedFields<<LOG2_PTRSIZE;
7644 FieldDesc *pFieldDescList = GetApproxFieldDescListRaw();
7645 // Place static fields
7646 for (i = 0; i < bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields; i++)
7648 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields+i];
7649 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7650 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7654 case FIELD_OFFSET_UNPLACED_GC_PTR:
7655 // Place GC reference static field
7656 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7657 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7658 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7662 case FIELD_OFFSET_VALUE_CLASS:
7663 // Place boxed GC reference static field
7664 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7665 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7666 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7670 case FIELD_OFFSET_UNPLACED:
7671 // Place non-GC static field
7672 pCurField->SetOffset(bmtFP->RegularStaticFieldStart[dwLog2FieldSize] +
7673 (bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7675 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
7676 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7684 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset_NoLogging()));
7687 if (bmtProp->fDynamicStatics)
7689 _ASSERTE(dwNonGCOffset == 0 || // no statics at all
7690 dwNonGCOffset == OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob); // We need space to point to the GC statics
7691 bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos;
7695 bmtProp->dwNonGCRegularStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7697 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCRegularStaticFieldBytes));
7701 VOID MethodTableBuilder::PlaceThreadStaticFields()
7703 STANDARD_VM_CONTRACT;
7707 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing ThreadStatics for %s\n", this->GetDebugClassName()));
7710 // Place gc refs and value types first, as they need to have handles created for them.
7711 // (Placing them together allows us to easily create the handles when Restoring the class,
7712 // and when initializing new DLS for the class.)
7715 DWORD dwCumulativeStaticFieldPos = 0 ;
7716 DWORD dwCumulativeStaticGCFieldPos = 0;
7717 DWORD dwCumulativeStaticBoxFieldPos = 0;
7719 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7720 // guaranteed to be aligned in ModuleStaticsInfo
7721 bmtFP->NumThreadStaticFieldsOfSize[LOG2_PTRSIZE] -=
7722 bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7724 // Place fields, largest first, padding so that each group is aligned to its natural size
7725 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7727 // Fields of this size start at the next available location
7728 bmtFP->ThreadStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7729 dwCumulativeStaticFieldPos += (bmtFP->NumThreadStaticFieldsOfSize[i] << i);
7731 // Reset counters for the loop after this one
7732 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
7736 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7737 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7739 DWORD dwNumHandleStatics = bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7740 if (!FitsIn<WORD>(dwNumHandleStatics))
7742 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7745 SetNumHandleThreadStatics(static_cast<WORD>(dwNumHandleStatics));
7747 if (!FitsIn<WORD>(bmtFP->NumThreadStaticGCBoxedFields))
7749 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7752 SetNumBoxedThreadStatics(static_cast<WORD>(bmtFP->NumThreadStaticGCBoxedFields));
7754 // Tell the module to give us the offsets we'll be using and commit space for us
7756 DWORD dwNonGCOffset, dwGCOffset;
7758 GetModule()->GetOffsetsForThreadStaticData(bmtInternal->pType->GetTypeDefToken(),
7759 bmtProp->fDynamicStatics,
7760 GetNumHandleThreadStatics(), dwCumulativeStaticFieldPos,
7761 &dwGCOffset, &dwNonGCOffset);
7763 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7764 dwCumulativeStaticGCFieldPos = bmtFP->NumThreadStaticGCBoxedFields<<LOG2_PTRSIZE;
7766 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
7767 // Place static fields
7768 for (i = 0; i < bmtEnumFields->dwNumThreadStaticFields; i++)
7770 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + i];
7771 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7772 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7776 case FIELD_OFFSET_UNPLACED_GC_PTR:
7777 // Place GC reference static field
7778 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7779 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7780 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7784 case FIELD_OFFSET_VALUE_CLASS:
7785 // Place boxed GC reference static field
7786 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7787 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7788 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7792 case FIELD_OFFSET_UNPLACED:
7793 // Place non-GC static field
7794 pCurField->SetOffset(bmtFP->ThreadStaticFieldStart[dwLog2FieldSize] +
7795 (bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7797 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
7798 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7806 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset_NoLogging()));
7809 if (bmtProp->fDynamicStatics)
7811 _ASSERTE(dwNonGCOffset == 0 || // no thread statics at all
7812 dwNonGCOffset == OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob); // We need space to point to the GC statics
7813 bmtProp->dwNonGCThreadStaticFieldBytes = dwCumulativeStaticFieldPos;
7817 bmtProp->dwNonGCThreadStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7819 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: ThreadStatic field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCThreadStaticFieldBytes));
7822 //*******************************************************************************
7824 // Used by BuildMethodTable
7826 // Place instance fields
7828 VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCache)
7830 STANDARD_VM_CONTRACT;
7835 //===============================================================
7836 // BEGIN: Place instance fields
7837 //===============================================================
7839 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
7840 DWORD dwCumulativeInstanceFieldPos;
7842 // Instance fields start right after the parent
7843 dwCumulativeInstanceFieldPos = HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0;
7845 DWORD dwOffsetBias = 0;
7846 #ifdef FEATURE_64BIT_ALIGNMENT
7847 // On platforms where the alignment of 64-bit primitives is a requirement (but we're not guaranteed
7848 // this implicitly by the GC) field offset 0 is actually not 8-byte aligned in reference classes.
7849 // That's because all such platforms are currently 32-bit and the 4-byte MethodTable pointer pushes us
7850 // out of alignment. Ideally we'd solve this by arranging to have the object header allocated at a
7851 // 4-byte offset from an 8-byte boundary, but this is difficult to achieve for objects allocated on
7852 // the large object heap (which actually requires headers to be 8-byte aligned).
7854 // So we adjust dwCumulativeInstanceFieldPos to account for the MethodTable* and our alignment
7855 // calculations will automatically adjust and add padding as necessary. We need to remove this
7856 // adjustment when setting the field offset in the field desc, however, since the rest of the system
7857 // expects that value to not include the MethodTable*.
7859 // This happens only for reference classes: value type field 0 really does lie at offset 0 for unboxed
7860 // value types. We deal with boxed value types by allocating their headers mis-aligned (luckily for us
7861 // value types can never get large enough to allocate on the LOH).
7862 if (!IsValueClass())
7864 dwOffsetBias = TARGET_POINTER_SIZE;
7865 dwCumulativeInstanceFieldPos += dwOffsetBias;
7867 #endif // FEATURE_64BIT_ALIGNMENT
7869 #ifdef FEATURE_READYTORUN
7870 if (NeedsAlignedBaseOffset())
7872 // READYTORUN: FUTURE: Use the minimum possible alignment, reduce padding when inheriting within same bubble
7873 DWORD dwAlignment = DATA_ALIGNMENT;
7874 #ifdef FEATURE_64BIT_ALIGNMENT
7875 if (GetHalfBakedClass()->IsAlign8Candidate())
7878 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
7880 #endif // FEATURE_READYTORUN
7882 // place small fields first if the parent have a number of field bytes that is not aligned
7883 if (!IS_ALIGNED(dwCumulativeInstanceFieldPos, DATA_ALIGNMENT))
7885 for (i = 0; i < MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++) {
7888 if (IS_ALIGNED(dwCumulativeInstanceFieldPos, size_t{ 1 } << (i + 1)))
7891 // check whether there are any bigger fields
7892 for (j = i + 1; j <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; j++) {
7893 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
7896 // nothing to gain if there are no bigger fields
7897 // (the subsequent loop will place fields from large to small fields)
7898 if (j > MAX_LOG2_PRIMITIVE_FIELD_SIZE)
7901 // check whether there are any small enough fields
7902 for (j = i; (signed int) j >= 0; j--) {
7903 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
7905 // TODO: since we will refuse to place GC references we should filter them out here.
7906 // otherwise the "back-filling" process stops completely.
7907 // (PlaceInstanceFields)
7908 // the following code would fix the issue (a replacement for the code above this comment):
7909 // if (bmtFP->NumInstanceFieldsOfSize[j] != 0 &&
7910 // (j != LOG2SLOT || bmtFP->NumInstanceFieldsOfSize[j] > bmtFP->NumInstanceGCPointerFields))
7916 // nothing to play with if there are no smaller fields
7917 if ((signed int) j < 0)
7919 // eventually go back and use the smaller field as filling
7922 CONSISTENCY_CHECK(bmtFP->NumInstanceFieldsOfSize[i] != 0);
7924 j = bmtFP->FirstInstanceFieldOfSize[i];
7926 // Avoid reordering of gcfields
7927 if (i == LOG2SLOT) {
7928 for ( ; j < bmtEnumFields->dwNumInstanceFields; j++) {
7929 if ((pFieldDescList[j].GetOffset_NoLogging() == FIELD_OFFSET_UNPLACED) &&
7930 ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i))
7934 // out of luck - can't reorder gc fields
7935 if (j >= bmtEnumFields->dwNumInstanceFields)
7940 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, size_t{ 1 } << i);
7942 pFieldDescList[j].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
7943 dwCumulativeInstanceFieldPos += (1 << i);
7945 // We've placed this field now, so there is now one less of this size field to place
7946 if (--bmtFP->NumInstanceFieldsOfSize[i] == 0)
7949 // We are done in this round if we haven't picked the first field
7950 if (bmtFP->FirstInstanceFieldOfSize[i] != j)
7953 // Update FirstInstanceFieldOfSize[i] to point to the next such field
7954 for (j = j+1; j < bmtEnumFields->dwNumInstanceFields; j++)
7956 // The log of the field size is stored in the method table
7957 if ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i)
7959 bmtFP->FirstInstanceFieldOfSize[i] = j;
7963 _ASSERTE(j < bmtEnumFields->dwNumInstanceFields);
7967 // Place fields, largest first
7968 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7970 if (bmtFP->NumInstanceFieldsOfSize[i] == 0)
7973 // Align instance fields if we aren't already
7974 #ifdef FEATURE_64BIT_ALIGNMENT
7975 DWORD dwDataAlignment = 1 << i;
7977 DWORD dwDataAlignment = min(1 << i, DATA_ALIGNMENT);
7979 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwDataAlignment);
7981 // Fields of this size start at the next available location
7982 bmtFP->InstanceFieldStart[i] = dwCumulativeInstanceFieldPos;
7983 dwCumulativeInstanceFieldPos += (bmtFP->NumInstanceFieldsOfSize[i] << i);
7985 // Reset counters for the loop after this one
7986 bmtFP->NumInstanceFieldsOfSize[i] = 0;
7990 // Make corrections to reserve space for GC Pointer Fields
7992 // The GC Pointers simply take up the top part of the region associated
7993 // with fields of that size (GC pointers can be 64 bit on certain systems)
7994 if (bmtFP->NumInstanceGCPointerFields)
7996 bmtFP->GCPointerFieldStart = bmtFP->InstanceFieldStart[LOG2SLOT] - dwOffsetBias;
7997 bmtFP->InstanceFieldStart[LOG2SLOT] = bmtFP->InstanceFieldStart[LOG2SLOT] + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT);
7998 bmtFP->NumInstanceGCPointerFields = 0; // reset to zero here, counts up as pointer slots are assigned below
8001 // Place instance fields - be careful not to place any already-placed fields
8002 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8004 DWORD dwFieldSize = (DWORD)(DWORD_PTR&)pFieldDescList[i].m_pMTOfEnclosingClass;
8007 dwOffset = pFieldDescList[i].GetOffset_NoLogging();
8009 // Don't place already-placed fields
8010 if ((dwOffset == FIELD_OFFSET_UNPLACED || dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR || dwOffset == FIELD_OFFSET_VALUE_CLASS))
8012 if (dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR)
8014 pFieldDescList[i].SetOffset(bmtFP->GCPointerFieldStart + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT));
8015 bmtFP->NumInstanceGCPointerFields++;
8017 else if (pFieldDescList[i].IsByValue() == FALSE) // it's a regular field
8019 pFieldDescList[i].SetOffset(bmtFP->InstanceFieldStart[dwFieldSize] + (bmtFP->NumInstanceFieldsOfSize[dwFieldSize] << dwFieldSize) - dwOffsetBias);
8020 bmtFP->NumInstanceFieldsOfSize[dwFieldSize]++;
8025 DWORD dwNumGCPointerSeries;
8026 // Save Number of pointer series
8027 if (bmtFP->NumInstanceGCPointerFields)
8028 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries + 1;
8030 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries;
8032 // Place by value class fields last
8033 // Update the number of GC pointer series
8034 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8036 if (pFieldDescList[i].IsByValue())
8038 MethodTable * pByValueMT = pByValueClassCache[i];
8040 // value classes could have GC pointers in them, which need to be pointer-size aligned
8041 // so do this if it has not been done already
8043 #if !defined(_TARGET_64BIT_) && (DATA_ALIGNMENT > 4)
8044 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos,
8045 (pByValueMT->GetNumInstanceFieldBytes() >= DATA_ALIGNMENT) ? DATA_ALIGNMENT : TARGET_POINTER_SIZE);
8046 #else // !(!defined(_TARGET_64BIT_) && (DATA_ALIGNMENT > 4))
8047 #ifdef FEATURE_64BIT_ALIGNMENT
8048 if (pByValueMT->RequiresAlign8())
8049 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, 8);
8051 #endif // FEATURE_64BIT_ALIGNMENT
8052 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, TARGET_POINTER_SIZE);
8053 #endif // !(!defined(_TARGET_64BIT_) && (DATA_ALIGNMENT > 4))
8055 pFieldDescList[i].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
8056 dwCumulativeInstanceFieldPos += pByValueMT->GetAlignedNumInstanceFieldBytes();
8058 // Add pointer series for by-value classes
8059 dwNumGCPointerSeries += pByValueMT->ContainsPointers() ?
8060 (DWORD)CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries() : 0;
8065 DWORD dwNumInstanceFieldBytes = dwCumulativeInstanceFieldPos - dwOffsetBias;
8069 // Like C++ we enforce that there can be no 0 length structures.
8070 // Thus for a value class with no fields, we 'pad' the length to be 1
8071 if (dwNumInstanceFieldBytes == 0)
8072 dwNumInstanceFieldBytes = 1;
8074 // The JITs like to copy full machine words,
8075 // so if the size is bigger than a void* round it up to minAlign
8076 // and if the size is smaller than void* round it up to next power of two
8079 #ifdef FEATURE_64BIT_ALIGNMENT
8080 if (GetHalfBakedClass()->IsAlign8Candidate()) {
8084 #endif // FEATURE_64BIT_ALIGNMENT
8085 if (dwNumInstanceFieldBytes > TARGET_POINTER_SIZE) {
8086 minAlign = TARGET_POINTER_SIZE;
8090 while (minAlign < dwNumInstanceFieldBytes)
8094 dwNumInstanceFieldBytes = (dwNumInstanceFieldBytes + minAlign-1) & ~(minAlign-1);
8097 if (dwNumInstanceFieldBytes > FIELD_OFFSET_LAST_REAL_OFFSET) {
8098 BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
8101 bmtFP->NumInstanceFieldBytes = dwNumInstanceFieldBytes;
8103 bmtFP->NumGCPointerSeries = dwNumGCPointerSeries;
8105 //===============================================================
8106 // END: Place instance fields
8107 //===============================================================
8110 //*******************************************************************************
8111 // this accesses the field size which is temporarily stored in m_pMTOfEnclosingClass
8112 // during class loading. Don't use any other time
8113 DWORD MethodTableBuilder::GetFieldSize(FieldDesc *pFD)
8115 STATIC_CONTRACT_NOTHROW;
8116 STATIC_CONTRACT_GC_NOTRIGGER;
8117 STATIC_CONTRACT_FORBID_FAULT;
8119 // We should only be calling this while this class is being built.
8120 _ASSERTE(GetHalfBakedMethodTable() == 0);
8121 BAD_FORMAT_NOTHROW_ASSERT(! pFD->IsByValue() || HasExplicitFieldOffsetLayout());
8123 if (pFD->IsByValue())
8124 return (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass);
8125 return (1 << (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass));
8128 #ifdef UNIX_AMD64_ABI
8129 // checks whether the struct is enregisterable.
8130 void MethodTableBuilder::SystemVAmd64CheckForPassStructInRegister()
8132 STANDARD_VM_CONTRACT;
8134 // This method should be called for valuetypes only
8135 _ASSERTE(IsValueClass());
8137 TypeHandle th(GetHalfBakedMethodTable());
8139 if (th.IsTypeDesc())
8141 // Not an enregisterable managed structure.
8145 DWORD totalStructSize = bmtFP->NumInstanceFieldBytes;
8147 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8148 // pass through stack
8149 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8151 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8152 this->GetDebugClassName(), totalStructSize));
8156 const bool useNativeLayout = false;
8157 // Iterate through the fields and make sure they meet requirements to pass in registers
8158 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8159 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout))
8161 // All the above tests passed. It's registers passed struct!
8162 GetHalfBakedMethodTable()->SetRegPassedStruct();
8164 StoreEightByteClassification(&helper);
8168 // checks whether the struct is enregisterable.
8169 void MethodTableBuilder::SystemVAmd64CheckForPassNativeStructInRegister()
8171 STANDARD_VM_CONTRACT;
8172 DWORD totalStructSize = 0;
8174 // If not a native value type, return.
8175 if (!IsValueClass())
8180 totalStructSize = GetLayoutInfo()->GetNativeSize();
8182 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8183 // pass through stack
8184 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8186 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassNativeStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8187 this->GetDebugClassName(), totalStructSize));
8191 _ASSERTE(HasLayout());
8193 // Classify the native layout for this struct.
8194 const bool useNativeLayout = true;
8195 // Iterate through the fields and make sure they meet requirements to pass in registers
8196 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8197 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout))
8199 GetLayoutInfo()->SetNativeStructPassedInRegisters();
8203 // Store the eightbyte classification into the EEClass
8204 void MethodTableBuilder::StoreEightByteClassification(SystemVStructRegisterPassingHelper* helper)
8206 EEClass* eeClass = GetHalfBakedMethodTable()->GetClass();
8207 LoaderAllocator* pAllocator = MethodTableBuilder::GetLoaderAllocator();
8208 AllocMemTracker* pamTracker = MethodTableBuilder::GetMemTracker();
8209 EnsureOptionalFieldsAreAllocated(eeClass, pamTracker, pAllocator->GetLowFrequencyHeap());
8210 eeClass->SetEightByteClassification(helper->eightByteCount, helper->eightByteClassifications, helper->eightByteSizes);
8213 #endif // UNIX_AMD64_ABI
8215 //---------------------------------------------------------------------------------------
8217 // make sure that no object fields are overlapped incorrectly and define the
8218 // GC pointer series for the class. We are assuming that this class will always be laid out within
8219 // its enclosing class by the compiler in such a way that offset 0 will be the correct alignment
8220 // for object ref fields so we don't need to try to align it
8223 MethodTableBuilder::HandleExplicitLayout(
8224 MethodTable ** pByValueClassCache)
8226 STANDARD_VM_CONTRACT;
8229 // Instance slice size is the total size of an instance, and is calculated as
8230 // the field whose offset and size add to the greatest number.
8231 UINT instanceSliceSize = 0;
8232 DWORD firstObjectOverlapOffset = ((DWORD)(-1));
8236 for (i = 0; i < bmtMetaData->cFields; i++)
8238 FieldDesc *pFD = bmtMFDescs->ppFieldDescList[i];
8239 if (pFD == NULL || pFD->IsStatic())
8244 UINT fieldExtent = 0;
8245 if (!ClrSafeInt<UINT>::addition(pFD->GetOffset_NoLogging(), GetFieldSize(pFD), fieldExtent))
8247 BuildMethodTableThrowException(COR_E_OVERFLOW);
8250 if (fieldExtent > instanceSliceSize)
8252 instanceSliceSize = fieldExtent;
8257 PREFIX_ASSUME(sizeof(BYTE) == 1);
8258 BYTE *pFieldLayout = (BYTE*) qb.AllocThrows(instanceSliceSize * sizeof(BYTE));
8259 for (i=0; i < instanceSliceSize; i++)
8261 pFieldLayout[i] = empty;
8264 // go through each field and look for invalid layout
8265 // (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to
8266 // close security holes.)
8268 // This is what we implment:
8270 // 1. Verify that every OREF is on a valid alignment
8271 // 2. Verify that OREFs only overlap with other OREFs.
8272 // 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
8273 // 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
8275 char emptyObject[TARGET_POINTER_SIZE];
8276 char isObject[TARGET_POINTER_SIZE];
8277 for (i = 0; i < TARGET_POINTER_SIZE; i++)
8279 emptyObject[i] = empty;
8284 ExplicitClassTrust explicitClassTrust;
8286 UINT valueClassCacheIndex = ((UINT)(-1));
8288 FieldDesc * pFD = NULL;
8289 for (i = 0; i < bmtMetaData->cFields; i++)
8291 // Note about this loop body:
8293 // This loop is coded to make it as hard as possible to allow a field to be trusted when it shouldn't.
8295 // Every path in this loop body must lead to an explicit decision as to whether the field nonoverlaps,
8296 // overlaps in a verifiable fashion, overlaps in a nonverifiable fashion or overlaps in a completely illegal fashion.
8298 // It must call fieldTrust.SetTrust() with the appropriate result. If you don't call it, fieldTrust's destructor
8299 // will intentionally default to kNone and mark the entire class illegal.
8301 // If your result is anything but kNone (class is illegal), you must also explicitly "continue" the loop.
8302 // There is a "break" at end of this loop body that will abort the loop if you don't do this. And
8303 // if you don't finish iterating through all the fields, this function will automatically mark the entire
8304 // class illegal. This rule is a vestige of an earlier version of this function.
8306 // This object's dtor will aggregate the trust decision for this field into the trust level for the class as a whole.
8307 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8309 pFD = bmtMFDescs->ppFieldDescList[i];
8310 if (pFD == NULL || pFD->IsStatic())
8312 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8316 // "i" indexes all fields, valueClassCacheIndex indexes non-static fields only. Don't get them confused!
8317 valueClassCacheIndex++;
8319 if (CorTypeInfo::IsObjRef(pFD->GetFieldType()))
8321 // Check that the ref offset is pointer aligned
8322 if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
8324 badOffset = pFD->GetOffset_NoLogging();
8325 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8327 // If we got here, OREF field was not pointer aligned. THROW.
8330 // check if overlaps another object
8331 if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
8333 // If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
8334 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8336 if (firstObjectOverlapOffset == ((DWORD)(-1)))
8338 firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
8343 // check if is empty at this point
8344 if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
8346 // If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
8347 memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
8348 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8352 // If we got here, the OREF overlaps a non-OREF. THROW.
8353 badOffset = pFD->GetOffset_NoLogging();
8354 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8360 if (pFD->IsByValue())
8362 MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
8363 if (pByValueMT->ContainsPointers())
8365 if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
8367 ExplicitFieldTrust::TrustLevel trust;
8368 DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
8369 trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
8370 fieldTrust.SetTrust(trust);
8371 if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
8373 if (firstObjectOverlapOffset == ((DWORD)(-1)))
8375 firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
8379 if (trust != ExplicitFieldTrust::kNone)
8385 // If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
8386 badOffset = pFD->GetOffset_NoLogging();
8390 // If we got here, then a valuetype containing an OREF was misaligned.
8391 badOffset = pFD->GetOffset_NoLogging();
8392 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8395 // no pointers so fall through to do standard checking
8396 fieldSize = pByValueMT->GetNumInstanceFieldBytes();
8400 // field size temporarily stored in pInterface field
8401 fieldSize = GetFieldSize(pFD);
8404 // If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
8405 // Look for any orefs under this field
8407 if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
8409 // If we have a nonoref in the range then we are doing an overlay
8410 if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
8412 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8416 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8418 memset((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize);
8422 // If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
8423 // on top of an OREF. THROW.
8424 badOffset = (UINT)(loc - pFieldLayout);
8425 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8427 // anything else is an error
8430 // We have to comment out this assert because otherwise, the compiler refuses to build because the _ASSERT is unreachable
8431 // (Thanks for nothing, compiler, that's what the assert is trying to enforce!) But the intent of the assert is correct.
8432 //_ASSERTE(!"You aren't supposed to be here. Some path inside the loop body did not execute an explicit break or continue.");
8435 // If we got here, some code above failed to execute an explicit "break" or "continue." This is a bug! To be safe,
8436 // we will put a catchall "break" here which will cause the typeload to abort (albeit with a probably misleading
8441 // We only break out of the loop above if we detected an error.
8442 if (i < bmtMetaData->cFields || !explicitClassTrust.IsLegal())
8444 ThrowFieldLayoutError(GetCl(),
8447 IDS_CLASSLOAD_EXPLICIT_LAYOUT);
8450 if (!explicitClassTrust.IsNonOverLayed())
8452 SetHasOverLayedFields();
8455 if (IsBlittable() || IsManagedSequential())
8457 // Bug 849333: We shouldn't update "bmtFP->NumInstanceFieldBytes"
8458 // for Blittable/ManagedSequential types. As this will break backward compatiblity
8459 // for the size of types that return true for HasExplicitFieldOffsetLayout()
8464 FindPointerSeriesExplicit(instanceSliceSize, pFieldLayout);
8466 // Fixup the offset to include parent as current offsets are relative to instance slice
8467 // Could do this earlier, but it's just easier to assume instance relative for most
8468 // of the earlier calculations
8470 // Instance fields start right after the parent
8471 S_UINT32 dwInstanceSliceOffset = S_UINT32(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0);
8472 if (bmtGCSeries->numSeries != 0)
8474 dwInstanceSliceOffset.AlignUp(TARGET_POINTER_SIZE);
8476 if (dwInstanceSliceOffset.IsOverflow())
8478 // addition overflow or cast truncation
8479 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8482 S_UINT32 numInstanceFieldBytes = dwInstanceSliceOffset + S_UINT32(instanceSliceSize);
8487 if (FAILED(GetMDImport()->GetClassTotalSize(GetCl(), &clstotalsize)))
8492 if (clstotalsize != 0)
8494 // size must be large enough to accomodate layout. If not, we use the layout size instead.
8495 if (!numInstanceFieldBytes.IsOverflow() && clstotalsize >= numInstanceFieldBytes.Value())
8497 numInstanceFieldBytes = S_UINT32(clstotalsize);
8502 // The GC requires that all valuetypes containing orefs be sized to a multiple of TARGET_POINTER_SIZE.
8503 if (bmtGCSeries->numSeries != 0)
8505 numInstanceFieldBytes.AlignUp(TARGET_POINTER_SIZE);
8507 if (numInstanceFieldBytes.IsOverflow())
8509 // addition overflow or cast truncation
8510 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8513 // Set the total size
8514 bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes.Value();
8516 for (i = 0; i < bmtMetaData->cFields; i++)
8518 FieldDesc * pTempFD = bmtMFDescs->ppFieldDescList[i];
8519 if ((pTempFD == NULL) || pTempFD->IsStatic())
8523 HRESULT hr = pTempFD->SetOffset(pTempFD->GetOffset_NoLogging() + dwInstanceSliceOffset.Value());
8526 BuildMethodTableThrowException(hr, *bmtError);
8529 } // MethodTableBuilder::HandleExplicitLayout
8531 //*******************************************************************************
8532 // make sure that no object fields are overlapped incorrectly, returns S_FALSE if
8533 // there overlap but nothing illegal, S_OK if there is no overlap
8534 /*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
8536 STANDARD_VM_CONTRACT;
8539 *pFirstObjectOverlapOffset = (DWORD)(-1);
8541 // Build a layout of the value class. Don't know the sizes of all the fields easily, but
8542 // do know a) vc is already consistent so don't need to check it's overlaps and
8543 // b) size and location of all objectrefs. So build it by setting all non-oref
8544 // then fill in the orefs later
8545 UINT fieldSize = pMT->GetNumInstanceFieldBytes();
8547 BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));
8549 memset((void*)vcLayout, nonoref, fieldSize);
8551 // use pointer series to locate the orefs
8553 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
8554 CGCDescSeries *pSeries = map->GetLowestSeries();
8556 for (SIZE_T j = 0; j < map->GetNumSeries(); j++)
8558 CONSISTENCY_CHECK(pSeries <= map->GetHighestSeries());
8560 memset((void*)&vcLayout[pSeries->GetSeriesOffset() - OBJECT_SIZE], oref, pSeries->GetSeriesSize() + pMT->GetBaseSize());
8565 ExplicitClassTrust explicitClassTrust;
8567 for (UINT i=0; i < fieldSize; i++) {
8569 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8571 if (vcLayout[i] == oref) {
8572 switch (pFieldLayout[i]) {
8575 pFieldLayout[i] = oref;
8576 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8579 // oref <--> nonoref
8581 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8586 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8587 if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
8589 *pFirstObjectOverlapOffset = (DWORD)i;
8594 _ASSERTE(!"Can't get here.");
8596 } else if (vcLayout[i] == nonoref) {
8597 switch (pFieldLayout[i]) {
8598 // nonoref <--> empty
8600 pFieldLayout[i] = nonoref;
8601 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8604 // nonoref <--> nonoref
8606 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8609 // nonoref <--> oref
8611 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8615 _ASSERTE(!"Can't get here.");
8618 _ASSERTE(!"Can't get here.");
8622 return explicitClassTrust.GetTrustLevel();
8631 //*******************************************************************************
8632 void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
8635 STANDARD_VM_CONTRACT;
8638 // Allocate a structure to track the series. We know that the worst case is a
8639 // ref-non-ref-non, and since only ref series are recorded and non-ref series
8640 // are skipped, the max number of series is total instance size / 2 / sizeof(ref).
8641 // But watch out for the case where we have e.g. an instanceSlizeSize of 4.
8642 DWORD sz = (instanceSliceSize + (2 * TARGET_POINTER_SIZE) - 1);
8643 bmtGCSeries->pSeries = new bmtGCSeriesInfo::Series[sz/2/ TARGET_POINTER_SIZE];
8645 BYTE *loc = pFieldLayout;
8646 BYTE *layoutEnd = pFieldLayout + instanceSliceSize;
8647 while (loc < layoutEnd)
8649 // Find the next OREF entry.
8650 loc = (BYTE*)memchr((void*)loc, oref, layoutEnd-loc);
8656 // Find the next non-OREF entry
8658 while(cur < layoutEnd && *cur == oref)
8663 // so we have a GC series at loc for cur-loc bytes
8664 bmtGCSeries->pSeries[bmtGCSeries->numSeries].offset = (DWORD)(loc - pFieldLayout);
8665 bmtGCSeries->pSeries[bmtGCSeries->numSeries].len = (DWORD)(cur - loc);
8667 CONSISTENCY_CHECK(IS_ALIGNED(cur - loc, TARGET_POINTER_SIZE));
8669 bmtGCSeries->numSeries++;
8673 // Calculate the total series count including the parent, if a parent exists.
8675 bmtFP->NumGCPointerSeries = bmtParent->NumParentPointerSeries + bmtGCSeries->numSeries;
8679 //*******************************************************************************
8681 MethodTableBuilder::HandleGCForExplicitLayout()
8683 STANDARD_VM_CONTRACT;
8685 MethodTable *pMT = GetHalfBakedMethodTable();
8687 #ifdef FEATURE_COLLECTIBLE_TYPES
8688 if (bmtFP->NumGCPointerSeries == 0 && pMT->Collectible())
8690 // For collectible types, insert empty gc series
8691 CGCDescSeries *pSeries;
8693 CGCDesc::Init( (PVOID) pMT, 1);
8694 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
8695 pSeries->SetSeriesSize( (size_t) (0) - (size_t) pMT->GetBaseSize());
8696 pSeries->SetSeriesOffset(OBJECT_SIZE);
8699 #endif // FEATURE_COLLECTIBLE_TYPES
8700 if (bmtFP->NumGCPointerSeries != 0)
8702 pMT->SetContainsPointers();
8704 // Copy the pointer series map from the parent
8705 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
8706 if (bmtParent->NumParentPointerSeries != 0)
8708 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
8709 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize), (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize), ParentGCSize - sizeof(UINT) );
8713 UINT32 dwInstanceSliceOffset = AlignUp(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0, TARGET_POINTER_SIZE);
8715 // Build the pointer series map for this pointers in this instance
8716 CGCDescSeries *pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
8717 for (UINT i=0; i < bmtGCSeries->numSeries; i++) {
8718 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
8719 BAD_FORMAT_NOTHROW_ASSERT(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
8721 pSeries->SetSeriesSize( (size_t) bmtGCSeries->pSeries[i].len - (size_t) pMT->GetBaseSize() );
8722 pSeries->SetSeriesOffset(bmtGCSeries->pSeries[i].offset + OBJECT_SIZE + dwInstanceSliceOffset);
8727 delete [] bmtGCSeries->pSeries;
8728 bmtGCSeries->pSeries = NULL;
8729 } // MethodTableBuilder::HandleGCForExplicitLayout
8735 MethodTable **pArray,
8736 DWORD nArraySizeMax,
8737 DWORD *pNumAssigned)
8739 LIMITED_METHOD_CONTRACT;
8741 for (DWORD j = 0; j < (*pNumAssigned); j++)
8743 if (pNew == pArray[j])
8746 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found duplicate interface %s (%p) at position %d out of %d\n", pNew->GetDebugClassName(), pNew, j, *pNumAssigned));
8748 return pNew->HasInstantiation(); // bail out - we found a duplicate instantiated interface
8753 LOG((LF_CLASSLOADER, LL_INFO1000, " GENERICS: InsertMethodTable ignored interface %s (%p) at position %d out of %d\n", pArray[j]->GetDebugClassName(), pArray[j], j, *pNumAssigned));
8757 if (*pNumAssigned >= nArraySizeMax)
8759 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found interface %s (%p) exceeding size %d of interface array\n", pNew->GetDebugClassName(), pNew, nArraySizeMax));
8762 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Inserting interface %s (%p) at position %d\n", pNew->GetDebugClassName(), pNew, *pNumAssigned));
8763 pArray[(*pNumAssigned)++] = pNew;
8765 } // InsertMethodTable
8768 //*******************************************************************************
8769 // --------------------------------------------------------------------------------------------
8770 // Copy virtual slots inherited from parent:
8772 // In types created at runtime, inherited virtual slots are initialized using approximate parent
8773 // during method table building. This method will update them based on the exact parent.
8774 // In types loaded from NGen image, inherited virtual slots from cross-module parents are not
8775 // initialized. This method will initialize them based on the actually loaded exact parent
8778 void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT, MethodTable *pApproxParentMT)
8783 PRECONDITION(CheckPointer(pMT));
8787 if (pMT->IsZapped())
8790 DWORD nParentVirtuals = pMT->GetNumParentVirtuals();
8791 if (nParentVirtuals == 0)
8794 _ASSERTE(nParentVirtuals == pApproxParentMT->GetNumVirtuals());
8797 // Update all inherited virtual slots to match exact parent
8800 if (!pMT->IsCanonicalMethodTable())
8803 // Copy all slots for non-canonical methodtables to avoid touching methoddescs.
8805 MethodTable * pCanonMT = pMT->GetCanonicalMethodTable();
8807 // Do not write into vtable chunks shared with parent. It would introduce race
8808 // with code:MethodDesc::SetStableEntryPointInterlocked.
8810 // Non-canonical method tables either share everything or nothing so it is sufficient to check
8811 // just the first indirection to detect sharing.
8812 if (pMT->GetVtableIndirections()[0].GetValueMaybeNull() != pCanonMT->GetVtableIndirections()[0].GetValueMaybeNull())
8814 MethodTable::MethodDataWrapper hCanonMTData(MethodTable::GetMethodData(pCanonMT, FALSE));
8815 for (DWORD i = 0; i < nParentVirtuals; i++)
8817 pMT->CopySlotFrom(i, hCanonMTData, pCanonMT);
8823 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
8825 MethodTable * pParentMT = pMT->GetParentMethodTable();
8826 MethodTable::MethodDataWrapper hParentMTData(MethodTable::GetMethodData(pParentMT, FALSE));
8828 for (DWORD i = 0; i < nParentVirtuals; i++)
8830 // fix up wrongly-inherited method descriptors
8831 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
8832 CONSISTENCY_CHECK(CheckPointer(pMD));
8833 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
8835 if (pMD->GetMethodTable() == pMT)
8838 // We need to re-inherit this slot from the exact parent.
8840 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(i);
8841 if (pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() == pApproxParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull())
8843 // The slot lives in a chunk shared from the approximate parent MT
8844 // If so, we need to change to share the chunk from the exact parent MT
8846 #ifdef FEATURE_PREJIT
8847 _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule(), Module::GetPreferredZapModuleForMethodTable(pMT)));
8849 _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule()));
8852 pMT->GetVtableIndirections()[indirectionIndex].SetValueMaybeNull(pParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull());
8854 i = MethodTable::GetEndSlotForVtableIndirection(indirectionIndex, nParentVirtuals) - 1;
8858 // The slot lives in an unshared chunk. We need to update the slot contents
8859 pMT->CopySlotFrom(i, hParentMTData, pParentMT);
8862 } // MethodTableBuilder::CopyExactParentSlots
8864 //*******************************************************************************
8867 MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
8872 PRECONDITION(CheckPointer(pMT));
8876 BOOL hasInstantiatedInterfaces = FALSE;
8877 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
8880 if (it.GetInterface()->HasInstantiation())
8882 hasInstantiatedInterfaces = TRUE;
8887 // If we have some instantiated interfaces, then we have lots more work to do...
8889 // In the worst case we have to use the metadata to
8890 // (a) load the exact interfaces and determine the order in which they
8891 // go. We do those by re-running the interface layout algorithm
8892 // and using metadata-comparisons to place interfaces in the list.
8893 // (b) do a check to see if any ambiguity in the interface dispatch map is introduced
8894 // by the instantiation
8895 // See code:#LoadExactInterfaceMap_Algorithm2
8897 // However, we can do something simpler: we just use
8898 // the loaded interface method tables to determine ordering. This can be done
8899 // if there are no duplicate instantiated interfaces in the interface
8901 // See code:#LoadExactInterfaceMap_Algorithm1.
8903 if (!hasInstantiatedInterfaces)
8909 TypeHandle thisTH(pMT);
8910 SigTypeContext typeContext(thisTH);
8911 MethodTable *pParentMT = pMT->GetParentMethodTable();
8913 //#LoadExactInterfaceMap_Algorithm1
8914 // Exact interface instantiation loading TECHNIQUE 1.
8915 // (a) For interfaces inherited from an instantiated parent class, just copy down from exact parent
8916 // (b) Grab newly declared interfaces by loading and then copying down all their inherited parents
8917 // (c) But check for any exact duplicates along the way
8918 // (d) If no duplicates then we can use the computed interface map we've created
8919 // (e) If duplicates found then use the slow metadata-based technique code:#LoadExactInterfaceMap_Algorithm2
8920 DWORD nInterfacesCount = pMT->GetNumInterfaces();
8921 MethodTable **pExactMTs = (MethodTable**) _alloca(sizeof(MethodTable *) * nInterfacesCount);
8922 DWORD nAssigned = 0;
8923 BOOL duplicates = false;
8924 if (pParentMT != NULL)
8926 MethodTable::InterfaceMapIterator parentIt = pParentMT->IterateInterfaceMap();
8927 while (parentIt.Next())
8929 duplicates |= InsertMethodTable(parentIt.GetInterface(), pExactMTs, nInterfacesCount, &nAssigned);
8932 InterfaceImplEnum ie(pMT->GetModule(), pMT->GetCl(), NULL);
8933 while ((hr = ie.Next()) == S_OK)
8935 MethodTable *pNewIntfMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(),
8938 ClassLoader::ThrowIfNotFound,
8939 ClassLoader::FailIfUninstDefOrRef,
8940 ClassLoader::LoadTypes,
8941 CLASS_LOAD_EXACTPARENTS,
8942 TRUE).GetMethodTable();
8944 duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);
8945 MethodTable::InterfaceMapIterator intIt = pNewIntfMT->IterateInterfaceMap();
8946 while (intIt.Next())
8948 duplicates |= InsertMethodTable(intIt.GetInterface(), pExactMTs, nInterfacesCount, &nAssigned);
8953 pMT->GetAssembly()->ThrowTypeLoadException(pMT->GetMDImport(), pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
8956 duplicates |= EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AlwaysUseMetadataInterfaceMapLayout, FALSE);
8958 //#InjectInterfaceDuplicates_LoadExactInterfaceMap
8959 // If we are injecting duplicates also for non-generic interfaces in check builds, we have to use
8960 // algorithm code:#LoadExactInterfaceMap_Algorithm2.
8961 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
8962 duplicates |= pMT->Debug_HasInjectedInterfaceDuplicates();
8964 CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces()));
8967 //#LoadExactInterfaceMap_Algorithm2
8968 // Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to
8969 // appear in the interface map! This may not be an error: if the duplicates
8970 // were ones that arose because because of inheritance from
8971 // a parent type then we accept that. For example
8972 // class C<T> : I<T>
8973 // class D<T> : C<T>, I<string>
8974 // is acceptable even when loading D<string>. Note that in such a case
8975 // there will be two entries for I<string> in the final interface map for D<string>.
8976 // For dispatch the mappings in D take precedence.
8978 // However we consider it an error if there is real ambiguity within
8979 // the interface definitions within the one class, e.g.
8980 // class E<T> : I<T>, I<string>
8981 // In this situation it is not defined how to dispatch calls to I<string>: would
8982 // we use the bindings for I<T> or I<string>?
8984 // Because we may had duplicates the interface map we created above may not
8985 // be the correct one: for example for D<string> above we would have computed
8986 // a map with only one entry. This is incorrect: an exact instantiation's interface
8987 // map must have entries that match the ordering of the interface map in the generic case
8988 // (this is because code:#InterfaceMap_SupersetOfParent).
8990 // So, in order to determine how to place the interfaces we need go back to
8991 // the metadata. We also do this to check if the presence of duplicates
8992 // has caused any potential ambiguity, i.e. the E<string> case above.
8994 // First we do a GetCheckpoint for the thread-based allocator. ExpandExactInheritedInterfaces allocates substitution chains
8995 // on the thread allocator rather than on the stack.
8996 Thread * pThread = GetThread();
8997 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
8999 // ***********************************************************
9000 // ****** This must be consistent with code:ExpandApproxInterface etc. *******
9002 // The correlation to ExpandApproxInterfaces etc. simply drops out by how we
9003 // traverse interfaces.
9004 // ***********************************************************
9006 bmtExactInterfaceInfo bmtExactInterface;
9007 bmtExactInterface.pInterfaceSubstitution = new (&pThread->m_MarshalAlloc) Substitution[pMT->GetNumInterfaces()];
9008 bmtExactInterface.pExactMTs = pExactMTs;
9009 bmtExactInterface.nAssigned = 0;
9010 bmtExactInterface.typeContext = typeContext;
9012 // Do the interfaces inherited from a parent class
9013 if ((pParentMT != NULL) && (pParentMT->GetNumInterfaces() > 0))
9015 Substitution * pParentSubstForTypeLoad = new (&pThread->m_MarshalAlloc) Substitution(
9016 pMT->GetSubstitutionForParent(NULL));
9017 Substitution * pParentSubstForComparing = new (&pThread->m_MarshalAlloc) Substitution(
9018 pMT->GetSubstitutionForParent(NULL));
9019 ExpandExactInheritedInterfaces(
9022 pParentSubstForTypeLoad,
9023 pParentSubstForComparing);
9026 //#ExactInterfaceMap_SupersetOfParent
9027 // Check that parent's interface map is subset of this interface map
9028 // See code:#InterfaceMap_SupersetOfParent
9030 _ASSERTE(pParentMT->GetNumInterfaces() == bmtExactInterface.nAssigned);
9032 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
9033 UINT32 nInterfaceIndex = 0;
9034 while (parentInterfacesIterator.Next())
9036 if (pMT->IsSharedByGenericInstantiations())
9037 { // The type is a canonical instantiation (contains _Canon)
9038 // The interface instantiations of parent can be different (see
9039 // code:#InterfaceMap_CanonicalSupersetOfParent), therefore we cannot compare
9041 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
9042 bmtExactInterface.pExactMTs[nInterfaceIndex]));
9045 { // It is not canonical instantiation, we can compare MethodTables
9046 _ASSERTE(parentInterfacesIterator.GetInterface() == bmtExactInterface.pExactMTs[nInterfaceIndex]);
9050 _ASSERTE(nInterfaceIndex == bmtExactInterface.nAssigned);
9054 // If there are any __Canon instances in the type argument list, then we defer the
9055 // ambiguity checking until an exact instantiation.
9056 if (!pMT->IsSharedByGenericInstantiations())
9058 // There are no __Canon types in the instantiation, so do ambiguity check.
9059 bmtInterfaceAmbiguityCheckInfo bmtCheckInfo;
9060 bmtCheckInfo.pMT = pMT;
9061 bmtCheckInfo.ppInterfaceSubstitutionChains = new (&pThread->m_MarshalAlloc) Substitution *[pMT->GetNumInterfaces()];
9062 bmtCheckInfo.ppExactDeclaredInterfaces = new (&pThread->m_MarshalAlloc) MethodTable *[pMT->GetNumInterfaces()];
9063 bmtCheckInfo.nAssigned = 0;
9064 bmtCheckInfo.typeContext = typeContext;
9065 MethodTableBuilder::InterfacesAmbiguityCheck(&bmtCheckInfo, pMT->GetModule(), pMT->GetCl(), NULL);
9068 // OK, there is no ambiguity amongst the instantiated interfaces declared on this class.
9069 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9075 COMMA_INDEBUG(pMT));
9076 CONSISTENCY_CHECK(bmtExactInterface.nAssigned == pMT->GetNumInterfaces());
9078 // We cannot process interface duplicates on types with __Canon. The duplicates are processed on
9080 if (!pMT->IsSharedByGenericInstantiations())
9082 // Process all pairs of duplicates in the interface map:
9083 // i.e. If there are 3 duplicates of the same interface at indexes: i1, i2 and i3, then
9084 // process pairs of indexes [i1,i2], [i1,i3] and [i2,i3].
9085 // - Update 'declared on type' flag for those interfaces which duplicate is 'declared on type'
9086 // - Check interface method implementation ambiguity code:#DuplicateInterface_MethodAmbiguity
9087 for (DWORD nOriginalIndex = 0; nOriginalIndex < nInterfacesCount; nOriginalIndex++)
9089 // Search for duplicates further in the interface map
9090 for (DWORD nDuplicateIndex = nOriginalIndex + 1; nDuplicateIndex < nInterfacesCount; nDuplicateIndex++)
9092 if (pExactMTs[nOriginalIndex] != pExactMTs[nDuplicateIndex])
9093 { // It's not a duplicate of original interface, skip it
9096 // We found a duplicate
9098 // Set 'declared on type' flag if either original or duplicate interface is
9099 // 'declared on type'
9100 if (pMT->IsInterfaceDeclaredOnClass(nOriginalIndex) ||
9101 pMT->IsInterfaceDeclaredOnClass(nDuplicateIndex))
9104 // Note that both checks are needed:
9106 // B<T,U> : A<T>, I<U>
9107 // C<T,U> : B<T,U>, I<T> // Reimplements interface from A<T>
9108 // After code:BuildMethodTableThrowing algorithm, this will happen:
9109 // B<int,int> will have interface map similar to B<T,U>:
9110 // I<int> ... not 'declared on type'
9111 // I<int> ... 'declared on type'
9112 // C<int,int> will have interface map similar to C<T,U>:
9113 // I<int> ... 'declared on type'
9114 // I<int> ... not 'declared on type'
9117 pMT->SetInterfaceDeclaredOnClass(nOriginalIndex);
9118 pMT->SetInterfaceDeclaredOnClass(nDuplicateIndex);
9121 //#DuplicateInterface_MethodAmbiguity
9123 // In the ideal world we would now check for interface method implementation
9124 // ambiguity in the instantiation, but that would be a technical breaking change
9125 // (against 2.0 RTM/SP1).
9126 // Therefore we ALLOW when interface method is implemented twice through this
9127 // original and duplicate interface.
9129 // This ambiguity pattern is therefore ALLOWED (can be expressed only in IL, not in C#):
9132 // A<T> : I<T> // abstract class
9133 // B<T,U> : A<T>, I<U>
9134 // void Print(T t) { ... }
9135 // void Print(U u) { ... }
9136 // Now B<int,int> has 2 implementations of I<int>.Print(int), while B<int,char> is
9137 // fine. Therefore an instantiation can introduce ambiguity.
9139 #if 0 // Removing this code for now as it is a technical breaking change (against CLR 2.0 RTM/SP1).
9140 // We might decide later that we want to take this breaking change.
9142 // Note that dispatch map entries are sorted by interface index and then interface
9143 // method slot index.
9145 DispatchMapTypeID originalTypeID = DispatchMapTypeID::InterfaceClassID(nOriginalIndex);
9146 DispatchMap::EncodedMapIterator originalIt(pMT);
9147 // Find first entry for original interface
9148 while (originalIt.IsValid())
9150 DispatchMapEntry *pEntry = originalIt.Entry();
9151 if (pEntry->GetTypeID().ToUINT32() >= originalTypeID.ToUINT32())
9152 { // Found the place where original interface entries should be (dispatch map is
9159 DispatchMapTypeID duplicateTypeID = DispatchMapTypeID::InterfaceClassID(nDuplicateIndex);
9160 DispatchMap::EncodedMapIterator duplicateIt(pMT);
9161 // Find first entry for duplicate interface
9162 while (duplicateIt.IsValid())
9164 DispatchMapEntry *pEntry = duplicateIt.Entry();
9165 if (pEntry->GetTypeID().ToUINT32() >= duplicateTypeID.ToUINT32())
9166 { // Found the place where original interface entries should be (dispatch map is
9173 // Compare original and duplicate interface entries in the dispatch map if they contain
9174 // different implementation for the same interface method
9177 if (!originalIt.IsValid() || !duplicateIt.IsValid())
9178 { // We reached end of one dispatch map iterator
9181 DispatchMapEntry *pOriginalEntry = originalIt.Entry();
9182 if (pOriginalEntry->GetTypeID().ToUINT32() != originalTypeID.ToUINT32())
9183 { // We reached behind original interface entries
9186 DispatchMapEntry *pDuplicateEntry = duplicateIt.Entry();
9187 if (pDuplicateEntry->GetTypeID().ToUINT32() != duplicateTypeID.ToUINT32())
9188 { // We reached behind duplicate interface entries
9192 if (pOriginalEntry->GetSlotNumber() == pDuplicateEntry->GetSlotNumber())
9193 { // Found duplicate implementation of interface method
9194 if (pOriginalEntry->GetTargetSlotNumber() != pDuplicateEntry->GetTargetSlotNumber())
9195 { // Implementation of the slots is different
9196 bmtErrorInfo bmtError;
9198 bmtError.pModule = pMT->GetModule();
9199 bmtError.cl = pMT->GetCl();
9200 bmtError.resIDWhy = IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES;
9201 bmtError.szMethodNameForError = NULL;
9202 bmtError.pThrowable = NULL;
9204 MethodDesc *pMD = pMT->GetMethodDescForSlot(pDuplicateEntry->GetTargetSlotNumber());
9205 bmtError.dMethodDefInError = pMD->GetMemberDef();
9207 BuildMethodTableThrowException(COR_E_TYPELOAD, bmtError);
9209 // The method is implemented by the same slot on both interfaces (original and
9212 // Process next dispatch map entry
9217 // Move iterator representing smaller interface method slot index (the dispatch map
9218 // is sorted by slot indexes)
9219 if (pOriginalEntry->GetSlotNumber() < pDuplicateEntry->GetSlotNumber())
9224 _ASSERTE(pOriginalEntry->GetSlotNumber() > pDuplicateEntry->GetSlotNumber());
9229 // All duplicates of this original interface were processed
9231 // All pairs of duplicates in the interface map are processed
9234 // Duplicates in the interface map are resolved
9236 // OK, if we've got this far then pExactMTs should now hold the array of exact instantiated interfaces.
9237 MethodTable::InterfaceMapIterator thisIt = pMT->IterateInterfaceMap();
9239 while (thisIt.Next())
9242 MethodTable*pOldMT = thisIt.GetInterface();
9243 MethodTable *pNewMT = pExactMTs[i];
9244 CONSISTENCY_CHECK(pOldMT->HasSameTypeDefAs(pNewMT));
9246 thisIt.SetInterface(pExactMTs[i]);
9250 } // MethodTableBuilder::LoadExactInterfaceMap
9252 //*******************************************************************************
9254 MethodTableBuilder::ExpandExactInheritedInterfaces(
9255 bmtExactInterfaceInfo * bmtInfo,
9257 const Substitution * pSubstForTypeLoad,
9258 Substitution * pSubstForComparing)
9260 STANDARD_VM_CONTRACT;
9262 MethodTable *pParentMT = pMT->GetParentMethodTable();
9264 // Backup type's substitution chain for comparing interfaces
9265 Substitution substForComparingBackup = *pSubstForComparing;
9266 // Make type an open type for comparing interfaces
9267 *pSubstForComparing = Substitution();
9271 // Chain parent's substitution for exact type load
9272 Substitution * pParentSubstForTypeLoad = new (&GetThread()->m_MarshalAlloc) Substitution(
9273 pMT->GetSubstitutionForParent(pSubstForTypeLoad));
9275 // Chain parent's substitution for comparing interfaces (note that this type is temporarily
9276 // considered as open type)
9277 Substitution * pParentSubstForComparing = new (&GetThread()->m_MarshalAlloc) Substitution(
9278 pMT->GetSubstitutionForParent(pSubstForComparing));
9280 ExpandExactInheritedInterfaces(
9283 pParentSubstForTypeLoad,
9284 pParentSubstForComparing);
9286 ExpandExactDeclaredInterfaces(
9292 COMMA_INDEBUG(pMT));
9294 // Restore type's subsitution chain for comparing interfaces
9295 *pSubstForComparing = substForComparingBackup;
9296 } // MethodTableBuilder::ExpandExactInheritedInterfaces
9298 //*******************************************************************************
9301 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9302 bmtExactInterfaceInfo * bmtInfo,
9305 const Substitution * pSubstForTypeLoad,
9306 Substitution * pSubstForComparing
9307 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9309 STANDARD_VM_CONTRACT;
9312 InterfaceImplEnum ie(pModule, typeDef, NULL);
9313 while ((hr = ie.Next()) == S_OK)
9315 MethodTable * pInterface = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
9318 &bmtInfo->typeContext,
9319 ClassLoader::ThrowIfNotFound,
9320 ClassLoader::FailIfUninstDefOrRef,
9321 ClassLoader::LoadTypes,
9322 CLASS_LOAD_EXACTPARENTS,
9324 pSubstForTypeLoad).GetMethodTable();
9326 Substitution ifaceSubstForTypeLoad(ie.CurrentToken(), pModule, pSubstForTypeLoad);
9327 Substitution ifaceSubstForComparing(ie.CurrentToken(), pModule, pSubstForComparing);
9328 ExpandExactInterface(
9331 &ifaceSubstForTypeLoad,
9332 &ifaceSubstForComparing
9333 COMMA_INDEBUG(dbg_pClassMT));
9337 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9339 } // MethodTableBuilder::ExpandExactDeclaredInterfaces
9341 //*******************************************************************************
9343 MethodTableBuilder::ExpandExactInterface(
9344 bmtExactInterfaceInfo * bmtInfo,
9345 MethodTable * pIntf,
9346 const Substitution * pSubstForTypeLoad_OnStack, // Allocated on stack!
9347 const Substitution * pSubstForComparing_OnStack // Allocated on stack!
9348 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9350 STANDARD_VM_CONTRACT;
9352 // ****** This must be consistent with code:MethodTableBuilder::ExpandApproxInterface ******
9354 // Is it already present according to the "generic" layout of the interfaces.
9355 // Note we use exactly the same algorithm as when we
9356 // determined the layout of the interface map for the "generic" version of the class.
9357 for (DWORD i = 0; i < bmtInfo->nAssigned; i++)
9359 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
9360 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9361 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtInfo->pExactMTs[i],
9363 &bmtInfo->pInterfaceSubstitution[i],
9364 pSubstForComparing_OnStack,
9368 //#InjectInterfaceDuplicates_ExactInterfaces
9369 // We will inject duplicate interfaces in check builds.
9370 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
9371 if (dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates())
9372 { // Just pretend we didn't find this match
9376 return; // found it, don't add it again
9380 // Add the interface and its sub-interfaces
9381 DWORD n = bmtInfo->nAssigned;
9382 bmtInfo->pExactMTs[n] = pIntf;
9383 bmtInfo->pInterfaceSubstitution[n] = *pSubstForComparing_OnStack;
9384 bmtInfo->nAssigned++;
9386 Substitution * pSubstForTypeLoad = new (&GetThread()->m_MarshalAlloc) Substitution(*pSubstForTypeLoad_OnStack);
9388 ExpandExactDeclaredInterfaces(
9393 &bmtInfo->pInterfaceSubstitution[n]
9394 COMMA_INDEBUG(dbg_pClassMT));
9395 } // MethodTableBuilder::ExpandExactInterface
9397 //*******************************************************************************
9399 void MethodTableBuilder::InterfacesAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9402 const Substitution *pSubstChain)
9404 STANDARD_VM_CONTRACT;
9407 InterfaceImplEnum ie(pModule, typeDef, pSubstChain);
9408 while ((hr = ie.Next()) == S_OK)
9410 MethodTable *pInterface =
9411 ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, ie.CurrentToken(),
9412 &bmtCheckInfo->typeContext,
9413 ClassLoader::ThrowIfNotFound,
9414 ClassLoader::FailIfUninstDefOrRef,
9415 ClassLoader::LoadTypes,
9416 CLASS_LOAD_EXACTPARENTS,
9418 pSubstChain).GetMethodTable();
9419 InterfaceAmbiguityCheck(bmtCheckInfo, ie.CurrentSubst(), pInterface);
9423 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9427 //*******************************************************************************
9428 void MethodTableBuilder::InterfaceAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9429 const Substitution *pItfSubstChain,
9432 STANDARD_VM_CONTRACT;
9434 // Is it already in the generic version of the freshly declared interfaces. We
9435 // do this based on metadata, i.e. via the substitution chains.
9436 // Note we use exactly the same algorithm as when we
9437 // determined the layout of the interface map for the "generic" version of the class.
9438 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9440 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
9441 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9442 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtCheckInfo->ppExactDeclaredInterfaces[i],
9444 bmtCheckInfo->ppInterfaceSubstitutionChains[i],
9447 return; // found it, don't add it again
9450 // OK, so it isn't a duplicate based on the generic IL, now check if the instantiation
9451 // makes it a duplicate.
9452 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9454 if (bmtCheckInfo->ppExactDeclaredInterfaces[i] == pIntf)
9456 bmtCheckInfo->pMT->GetModule()->GetAssembly()->ThrowTypeLoadException(bmtCheckInfo->pMT->GetMDImport(),
9457 bmtCheckInfo->pMT->GetCl(),
9458 IDS_CLASSLOAD_OVERLAPPING_INTERFACES);
9462 DWORD n = bmtCheckInfo->nAssigned;
9463 bmtCheckInfo->ppExactDeclaredInterfaces[n] = pIntf;
9464 bmtCheckInfo->ppInterfaceSubstitutionChains[n] = new (&GetThread()->m_MarshalAlloc) Substitution[pItfSubstChain->GetLength()];
9465 pItfSubstChain->CopyToArray(bmtCheckInfo->ppInterfaceSubstitutionChains[n]);
9467 bmtCheckInfo->nAssigned++;
9468 InterfacesAmbiguityCheck(bmtCheckInfo,pIntf->GetModule(),pIntf->GetCl(),pItfSubstChain);
9472 //*******************************************************************************
9473 void MethodTableBuilder::CheckForSystemTypes()
9475 STANDARD_VM_CONTRACT;
9477 LPCUTF8 name, nameSpace;
9479 MethodTable * pMT = GetHalfBakedMethodTable();
9480 EEClass * pClass = GetHalfBakedClass();
9482 // We can exit early for generic types - there are just a few cases to check for.
9483 if (bmtGenerics->HasInstantiation())
9485 if (pMT->IsIntrinsicType() && pClass->HasLayout())
9487 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9489 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9492 if (strcmp(nameSpace, g_IntrinsicsNS) == 0)
9494 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
9496 // The SIMD Hardware Intrinsic types correspond to fundamental data types in the underlying ABIs:
9497 // * Vector64<T>: __m64
9498 // * Vector128<T>: __m128
9499 // * Vector256<T>: __m256
9501 // These __m128 and __m256 types, among other requirements, are special in that they must always
9502 // be aligned properly.
9504 if (IsCompilationProcess())
9506 // Disable AOT compiling for the SIMD hardware intrinsic types. These types require special
9507 // ABI handling as they represent fundamental data types (__m64, __m128, and __m256) and not
9508 // aggregate or union types. See https://github.com/dotnet/coreclr/issues/15943
9510 // Once they are properly handled according to the ABI requirements, we can remove this check
9511 // and allow them to be used in crossgen/AOT scenarios.
9512 COMPlusThrow(kTypeLoadException, IDS_EE_HWINTRINSIC_NGEN_DISALLOWED);
9515 if (strcmp(name, g_Vector64Name) == 0)
9517 // The System V ABI for i386 defaults to 8-byte alignment for __m64, except for parameter passing,
9518 // where it has an alignment of 4.
9520 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
9521 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
9523 else if (strcmp(name, g_Vector128Name) == 0)
9526 // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128
9528 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8;
9529 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
9531 pLayout->m_LargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
9532 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
9533 #endif // _TARGET_ARM_
9535 else if (strcmp(name, g_Vector256Name) == 0)
9538 // No such type exists for the Procedure Call Standard for ARM. We will default
9539 // to the same alignment as __m128, which is supported by the ABI.
9541 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8;
9542 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
9543 #elif defined(_TARGET_ARM64_)
9544 // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to
9545 // 16-byte alignment for __m256.
9547 pLayout->m_LargestAlignmentRequirementOfAllMembers = 16;
9548 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
9550 pLayout->m_LargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
9551 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
9552 #endif // _TARGET_ARM_ elif _TARGET_ARM64_
9556 // These types should be handled or explicitly skipped below to ensure that we don't
9557 // miss adding required ABI support for future types.
9559 _ASSERTE_MSG(FALSE, "Unhandled Hardware Intrinsic Type.");
9566 if (g_pNullableClass != NULL)
9568 _ASSERTE(g_pByReferenceClass != NULL);
9569 _ASSERTE(g_pByReferenceClass->IsByRefLike());
9572 if (GetCl() == g_pByReferenceClass->GetCl())
9574 // x86 by default treats the type of ByReference<T> as the actual type of its IntPtr field, see calls to
9575 // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be
9576 // treated as a value type so that its field can be considered as a byref pointer.
9577 _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType);
9578 pMT->ClearFlag(MethodTable::enum_flag_Category_Mask);
9579 pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE);
9584 _ASSERTE(g_pNullableClass->IsNullable());
9586 // Pre-compute whether the class is a Nullable<T> so that code:Nullable::IsNullableType is efficient
9587 // This is useful to the performance of boxing/unboxing a Nullable
9588 if (GetCl() == g_pNullableClass->GetCl())
9589 pMT->SetIsNullable();
9595 if (IsNested() || IsEnum())
9598 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9600 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9609 // All special value types are in the system namespace
9610 if (strcmp(nameSpace, g_SystemNS) != 0)
9613 // Check if it is a primitive type
9614 CorElementType type = CorTypeInfo::FindPrimitiveType(name);
9615 if (type != ELEMENT_TYPE_END)
9617 pMT->SetInternalCorElementType(type);
9618 pMT->SetIsTruePrimitive();
9620 #if defined(_TARGET_X86_) && defined(UNIX_X86_ABI)
9623 // The System V ABI for i386 defines different packing for these types.
9625 case ELEMENT_TYPE_I8:
9626 case ELEMENT_TYPE_U8:
9627 case ELEMENT_TYPE_R8:
9629 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
9630 pLayout->m_LargestAlignmentRequirementOfAllMembers = 4;
9631 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 4;
9638 #endif // _TARGET_X86_ && UNIX_X86_ABI
9641 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9643 name = nameSpace = "Invalid TypeDef record";
9645 LOG((LF_CLASSLOADER, LL_INFO10000, "%s::%s marked as primitive type %i\n", nameSpace, name, type));
9648 else if (strcmp(name, g_NullableName) == 0)
9650 pMT->SetIsNullable();
9653 else if (strcmp(name, g_ByReferenceName) == 0)
9655 // x86 by default treats the type of ByReference<T> as the actual type of its IntPtr field, see calls to
9656 // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be
9657 // treated as a value type so that its field can be considered as a byref pointer.
9658 _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType);
9659 pMT->ClearFlag(MethodTable::enum_flag_Category_Mask);
9660 pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE);
9663 #ifndef _TARGET_X86_
9664 else if (strcmp(name, g_RuntimeArgumentHandleName) == 0)
9666 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
9668 else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0)
9670 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
9673 #if defined(ALIGN_ACCESS) || defined(FEATURE_64BIT_ALIGNMENT)
9674 else if (strcmp(name, g_DecimalName) == 0)
9676 // This is required because native layout of System.Decimal causes it to be aligned
9677 // differently to the layout of the native DECIMAL structure, which will cause
9678 // data misalignent exceptions if Decimal is embedded in another type.
9680 EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo();
9681 pLayout->m_LargestAlignmentRequirementOfAllMembers = sizeof(ULONGLONG);
9682 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = sizeof(ULONGLONG);
9684 #ifdef FEATURE_64BIT_ALIGNMENT
9685 // Also need to mark the type so it will be allocated on a 64-bit boundary for
9686 // platforms that won't do this naturally.
9687 SetAlign8Candidate();
9690 #endif // ALIGN_ACCESS || FEATURE_64BIT_ALIGNMENT
9697 if (strcmp(name, g_StringName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9699 // Strings are not "normal" objects, so we need to mess with their method table a bit
9700 // so that the GC can figure out how big each string is...
9701 DWORD baseSize = StringObject::GetBaseSize();
9702 pMT->SetBaseSize(baseSize);
9704 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
9706 pMT->SetComponentSize(2);
9708 else if (strcmp(name, g_CriticalFinalizerObjectName) == 0 && strcmp(nameSpace, g_ConstrainedExecutionNS) == 0)
9710 // To introduce a class with a critical finalizer,
9711 // we'll set the bit here.
9712 pMT->SetHasCriticalFinalizer();
9714 #ifdef FEATURE_COMINTEROP
9717 bool bIsComObject = false;
9718 bool bIsRuntimeClass = false;
9720 if (strcmp(name, g_ComObjectName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9721 bIsComObject = true;
9723 if (strcmp(name, g_RuntimeClassName) == 0 && strcmp(nameSpace, g_WinRTNS) == 0)
9724 bIsRuntimeClass = true;
9726 if (bIsComObject || bIsRuntimeClass)
9728 // Make System.__ComObject/System.Runtime.InteropServices.WindowsRuntime.RuntimeClass a ComImport type
9729 // We can't do it using attribute as C# won't allow putting code in ComImport types
9730 pMT->SetComObjectType();
9732 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
9733 // the optional field descriptor.
9734 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
9737 if (bIsRuntimeClass)
9739 // Note that we set it here to avoid type loader considering RuntimeClass as a normal WindowsImportType
9740 // as functions in RuntimeClass doesn't go through COM interop
9741 GetHalfBakedClass()->SetProjectedFromWinRT();
9744 #endif // FEATURE_COMINTEROP
9748 //==========================================================================================
9749 // Helper to create a new method table. This is the only
9750 // way to allocate a new MT. Don't try calling new / ctor.
9751 // Called from SetupMethodTable
9752 // This needs to be kept consistent with MethodTable::GetSavedExtent()
9753 MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule,
9754 DWORD dwVtableSlots,
9757 DWORD dwNumInterfaces,
9759 DWORD cbInstAndDict,
9760 MethodTable *pMTParent,
9761 ClassLoader *pClassLoader,
9762 LoaderAllocator *pAllocator,
9764 BOOL fDynamicStatics,
9765 BOOL fHasGenericsStaticsInfo,
9766 BOOL fNeedsRCWPerTypeData
9767 #ifdef FEATURE_COMINTEROP
9768 , BOOL fHasDynamicInterfaceMap
9770 #ifdef FEATURE_PREJIT
9771 , Module *pComputedPZM
9772 #endif // FEATURE_PREJIT
9773 , AllocMemTracker *pamTracker
9776 CONTRACT (MethodTable*)
9781 POSTCONDITION(CheckPointer(RETVAL));
9785 DWORD dwNonVirtualSlots = dwVtableSlots - dwVirtuals;
9787 // GCSize must be aligned
9788 _ASSERTE(IS_ALIGNED(dwGCSize, sizeof(void*)));
9790 // size without the interface map
9791 S_SIZE_T cbTotalSize = S_SIZE_T(dwGCSize) + S_SIZE_T(sizeof(MethodTable));
9794 cbTotalSize += MethodTable::GetNumVtableIndirections(dwVirtuals) * sizeof(MethodTable::VTableIndir_t);
9797 DWORD dwMultipurposeSlotsMask = 0;
9798 if (dwNumInterfaces != 0)
9799 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasInterfaceMap;
9800 if (dwNumDicts != 0)
9801 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasPerInstInfo;
9802 if (bmtVT->pDispatchMapBuilder->Count() > 0)
9803 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasDispatchMapSlot;
9804 if (dwNonVirtualSlots != 0)
9805 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasNonVirtualSlots;
9806 if (pLoaderModule != GetModule())
9807 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasModuleOverride;
9809 // Add space for optional members here. Same as GetOptionalMembersSize()
9810 cbTotalSize += MethodTable::GetOptionalMembersAllocationSize(dwMultipurposeSlotsMask,
9811 fHasGenericsStaticsInfo,
9812 FALSE, // no GuidInfo needed for canonical instantiations
9813 FALSE, // no CCW template needed for canonical instantiations
9814 fNeedsRCWPerTypeData,
9815 RidFromToken(GetCl()) >= METHODTABLE_TOKEN_OVERFLOW);
9817 // Interface map starts here
9818 S_SIZE_T offsetOfInterfaceMap = cbTotalSize;
9820 cbTotalSize += S_SIZE_T(dwNumInterfaces) * S_SIZE_T(sizeof(InterfaceInfo_t));
9822 #ifdef FEATURE_COMINTEROP
9823 // DynamicInterfaceMap have an extra DWORD added to the end of the normal interface
9824 // map. This will be used to store the count of dynamically added interfaces
9825 // (the ones that are not in the metadata but are QI'ed for at runtime).
9826 cbTotalSize += S_SIZE_T(fHasDynamicInterfaceMap ? sizeof(DWORD_PTR) : 0);
9829 // Dictionary pointers start here
9830 S_SIZE_T offsetOfInstAndDict = cbTotalSize;
9832 if (dwNumDicts != 0)
9834 cbTotalSize += sizeof(GenericsDictInfo);
9835 cbTotalSize += S_SIZE_T(dwNumDicts) * S_SIZE_T(sizeof(MethodTable::PerInstInfoElem_t));
9836 cbTotalSize += cbInstAndDict;
9839 S_SIZE_T offsetOfUnsharedVtableChunks = cbTotalSize;
9841 BOOL canShareVtableChunks = pMTParent && MethodTable::CanShareVtableChunksFrom(pMTParent, pLoaderModule
9842 #ifdef FEATURE_PREJIT
9844 #endif //FEATURE_PREJIT
9847 // If pMTParent has a generic instantiation, we cannot share its vtable chunks
9848 // This is because pMTParent is only approximate at this point, and MethodTableBuilder::CopyExactParentSlots
9849 // may swap in an exact parent that does not satisfy CanShareVtableChunksFrom
9850 if (pMTParent && pMTParent->HasInstantiation())
9852 canShareVtableChunks = FALSE;
9855 // We will share any parent vtable chunk that does not contain a method we overrode (or introduced)
9856 // For the rest, we need to allocate space
9857 for (DWORD i = 0; i < dwVirtuals; i++)
9859 if (!canShareVtableChunks || ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
9861 DWORD chunkStart = MethodTable::GetStartSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
9862 DWORD chunkEnd = MethodTable::GetEndSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
9864 cbTotalSize += S_SIZE_T(chunkEnd - chunkStart) * S_SIZE_T(sizeof(PCODE));
9870 // Add space for the non-virtual slots array (pointed to by an optional member) if required
9871 // If there is only one non-virtual slot, we store it directly in the optional member and need no array
9872 S_SIZE_T offsetOfNonVirtualSlots = cbTotalSize;
9873 if (dwNonVirtualSlots > 1)
9875 cbTotalSize += S_SIZE_T(dwNonVirtualSlots) * S_SIZE_T(sizeof(PCODE));
9878 BYTE *pData = (BYTE *)pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(cbTotalSize));
9880 _ASSERTE(IS_ALIGNED(pData, TARGET_POINTER_SIZE));
9882 // There should be no overflows if we have allocated the memory succesfully
9883 _ASSERTE(!cbTotalSize.IsOverflow());
9885 MethodTable* pMT = (MethodTable*)(pData + dwGCSize);
9887 pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask);
9889 MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *)
9890 pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData))));
9891 // Note: Memory allocated on loader heap is zero filled
9892 pMT->SetWriteableData(pMTWriteableData);
9894 // This also disables IBC logging until the type is sufficiently intitialized so
9895 // it needs to be done early
9896 pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable();
9899 pClassLoader->m_dwGCSize += dwGCSize;
9900 pClassLoader->m_dwInterfaceMapSize += (dwNumInterfaces * sizeof(InterfaceInfo_t));
9901 pClassLoader->m_dwMethodTableSize += (DWORD)cbTotalSize.Value();
9902 pClassLoader->m_dwVtableData += (dwVtableSlots * sizeof(PCODE));
9905 // There should be no overflows if we have allocated the memory succesfully
9906 _ASSERTE(!offsetOfUnsharedVtableChunks.IsOverflow());
9907 _ASSERTE(!offsetOfNonVirtualSlots.IsOverflow());
9908 _ASSERTE(!offsetOfInterfaceMap.IsOverflow());
9909 _ASSERTE(!offsetOfInstAndDict.IsOverflow());
9911 // initialize the total number of slots
9912 pMT->SetNumVirtuals(static_cast<WORD>(dwVirtuals));
9914 pMT->SetParentMethodTable(pMTParent);
9916 // Fill out the vtable indirection slots
9917 SIZE_T dwCurrentUnsharedSlotOffset = offsetOfUnsharedVtableChunks.Value();
9918 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
9921 BOOL shared = canShareVtableChunks;
9923 // Recalculate whether we will share this chunk
9924 if (canShareVtableChunks)
9926 for (DWORD i = it.GetStartSlot(); i < it.GetEndSlot(); i++)
9928 if (ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
9938 // Share the parent chunk
9939 _ASSERTE(it.GetEndSlot() <= pMTParent->GetNumVirtuals());
9940 it.SetIndirectionSlot(pMTParent->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull());
9944 // Use the locally allocated chunk
9945 it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pData+dwCurrentUnsharedSlotOffset));
9946 dwCurrentUnsharedSlotOffset += it.GetSize();
9950 #ifdef FEATURE_COMINTEROP
9951 // Extensible RCW's are prefixed with the count of dynamic interfaces.
9952 if (fHasDynamicInterfaceMap)
9954 _ASSERTE (dwNumInterfaces > 0);
9955 pMT->SetInterfaceMap ((WORD) (dwNumInterfaces), (InterfaceInfo_t*)(pData+offsetOfInterfaceMap.Value()+sizeof(DWORD_PTR)));
9957 *(((DWORD_PTR *)pMT->GetInterfaceMap()) - 1) = 0;
9960 #endif // FEATURE_COMINTEROP
9962 // interface map is at the end of the vtable
9963 pMT->SetInterfaceMap ((WORD) dwNumInterfaces, (InterfaceInfo_t *)(pData+offsetOfInterfaceMap.Value()));
9966 _ASSERTE(((WORD) dwNumInterfaces) == dwNumInterfaces);
9968 if (fDynamicStatics)
9970 pMT->SetDynamicStatics(fHasGenericsStaticsInfo);
9973 if (dwNonVirtualSlots > 0)
9975 if (dwNonVirtualSlots > 1)
9977 pMT->SetNonVirtualSlotsArray((PTR_PCODE)(pData+offsetOfNonVirtualSlots.Value()));
9981 pMT->SetHasSingleNonVirtualSlot();
9985 // the dictionary pointers follow the interface map
9988 MethodTable::PerInstInfoElem_t *pPerInstInfo = (MethodTable::PerInstInfoElem_t *)(pData + offsetOfInstAndDict.Value() + sizeof(GenericsDictInfo));
9990 pMT->SetPerInstInfo ( pPerInstInfo);
9992 // Fill in the dictionary for this type, if it's instantiated
9995 MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *)(pPerInstInfo + (dwNumDicts-1));
9996 pPInstInfo->SetValueMaybeNull((Dictionary*) (pPerInstInfo + dwNumDicts));
10001 pMT->m_pWriteableData.GetValue()->m_dwLastVerifedGCCnt = (DWORD)-1;
10008 //*******************************************************************************
10010 // Used by BuildMethodTable
10012 // Setup the method table
10015 #pragma warning(push)
10016 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
10017 #endif // _PREFAST_
10020 MethodTableBuilder::SetupMethodTable2(
10021 Module * pLoaderModule
10022 #ifdef FEATURE_PREJIT
10023 , Module * pComputedPZM
10024 #endif // FEATURE_PREJIT
10030 PRECONDITION(CheckPointer(this));
10031 PRECONDITION(CheckPointer(bmtVT));
10032 PRECONDITION(CheckPointer(bmtInterface));
10033 PRECONDITION(CheckPointer(bmtInternal));
10034 PRECONDITION(CheckPointer(bmtProp));
10035 PRECONDITION(CheckPointer(bmtMFDescs));
10036 PRECONDITION(CheckPointer(bmtEnumFields));
10037 PRECONDITION(CheckPointer(bmtError));
10038 PRECONDITION(CheckPointer(bmtMetaData));
10039 PRECONDITION(CheckPointer(bmtParent));
10040 PRECONDITION(CheckPointer(bmtGenerics));
10046 #ifdef FEATURE_COMINTEROP
10047 BOOL fHasDynamicInterfaceMap = bmtInterface->dwInterfaceMapSize > 0 &&
10048 bmtProp->fIsComObjectType &&
10049 (GetParentMethodTable() != g_pObjectClass);
10050 BOOL fNeedsRCWPerTypeData = bmtProp->fNeedsRCWPerTypeData;
10051 #else // FEATURE_COMINTEROP
10052 BOOL fNeedsRCWPerTypeData = FALSE;
10053 #endif // FEATURE_COMINTEROP
10055 EEClass *pClass = GetHalfBakedClass();
10057 DWORD cbDict = bmtGenerics->HasInstantiation()
10058 ? DictionaryLayout::GetFirstDictionaryBucketSize(
10059 bmtGenerics->GetNumGenericArgs(), pClass->GetDictionaryLayout())
10062 #ifdef FEATURE_COLLECTIBLE_TYPES
10063 BOOL fCollectible = pLoaderModule->IsCollectible();
10064 #endif // FEATURE_COLLECTIBLE_TYPES
10068 if (bmtFP->NumGCPointerSeries > 0)
10070 dwGCSize = (DWORD)CGCDesc::ComputeSize(bmtFP->NumGCPointerSeries);
10074 #ifdef FEATURE_COLLECTIBLE_TYPES
10076 dwGCSize = (DWORD)CGCDesc::ComputeSize(1);
10078 #endif // FEATURE_COLLECTIBLE_TYPES
10082 pClass->SetNumMethods(bmtVT->cTotalSlots);
10083 pClass->SetNumNonVirtualSlots(bmtVT->cVtableSlots - bmtVT->cVirtualSlots);
10085 // Now setup the method table
10086 // interface map is allocated along with the method table
10087 MethodTable *pMT = AllocateNewMT(pLoaderModule,
10088 bmtVT->cVtableSlots,
10089 bmtVT->cVirtualSlots,
10091 bmtInterface->dwInterfaceMapSize,
10092 bmtGenerics->numDicts,
10094 GetParentMethodTable(),
10098 bmtProp->fDynamicStatics,
10099 bmtProp->fGenericsStatics,
10100 fNeedsRCWPerTypeData,
10101 #ifdef FEATURE_COMINTEROP
10102 fHasDynamicInterfaceMap,
10104 #ifdef FEATURE_PREJIT
10106 #endif //FEATURE_PREJIT
10109 pMT->SetClass(pClass);
10110 pClass->m_pMethodTable.SetValue(pMT);
10111 m_pHalfBakedMT = pMT;
10114 pMT->SetDebugClassName(GetDebugClassName());
10117 #ifdef FEATURE_COMINTEROP
10118 if (fNeedsRCWPerTypeData)
10119 pMT->SetHasRCWPerTypeData();
10120 #endif // FEATURE_COMINTEROP
10124 pMT->SetIsInterface();
10126 if (GetParentMethodTable() != NULL)
10128 if (GetParentMethodTable()->HasModuleDependencies())
10130 pMT->SetHasModuleDependencies();
10134 Module * pModule = GetModule();
10135 Module * pParentModule = GetParentMethodTable()->GetModule();
10136 if (pModule != pParentModule)
10138 pMT->SetHasModuleDependencies();
10142 if (GetParentMethodTable()->HasPreciseInitCctors() || !pClass->IsBeforeFieldInit())
10144 pMT->SetHasPreciseInitCctors();
10148 // Must be done early because various methods test HasInstantiation() and ContainsGenericVariables()
10149 if (bmtGenerics->GetNumGenericArgs() != 0)
10151 pMT->SetHasInstantiation(bmtGenerics->fTypicalInstantiation, bmtGenerics->fSharedByGenericInstantiations);
10153 if (bmtGenerics->fContainsGenericVariables)
10154 pMT->SetContainsGenericVariables();
10157 if (bmtGenerics->numDicts != 0)
10159 if (!FitsIn<WORD>(bmtGenerics->GetNumGenericArgs()))
10161 BuildMethodTableThrowException(IDS_CLASSLOAD_TOOMANYGENERICARGS);
10164 pMT->SetDictInfo(bmtGenerics->numDicts,
10165 static_cast<WORD>(bmtGenerics->GetNumGenericArgs()));
10168 CONSISTENCY_CHECK(pMT->GetNumGenericArgs() == bmtGenerics->GetNumGenericArgs());
10169 CONSISTENCY_CHECK(pMT->GetNumDicts() == bmtGenerics->numDicts);
10170 CONSISTENCY_CHECK(pMT->HasInstantiation() == bmtGenerics->HasInstantiation());
10171 CONSISTENCY_CHECK(pMT->HasInstantiation() == !pMT->GetInstantiation().IsEmpty());
10173 pMT->SetLoaderModule(pLoaderModule);
10174 pMT->SetLoaderAllocator(bmtAllocator);
10176 pMT->SetModule(GetModule());
10178 pMT->SetInternalCorElementType (ELEMENT_TYPE_CLASS);
10180 SetNonGCRegularStaticFieldBytes (bmtProp->dwNonGCRegularStaticFieldBytes);
10181 SetNonGCThreadStaticFieldBytes (bmtProp->dwNonGCThreadStaticFieldBytes);
10183 #ifdef FEATURE_TYPEEQUIVALENCE
10184 if (bmtProp->fHasTypeEquivalence)
10186 pMT->SetHasTypeEquivalence();
10188 #endif //FEATURE_TYPEEQUIVALENCE
10190 #ifdef FEATURE_COMINTEROP
10191 if (bmtProp->fSparse)
10192 pClass->SetSparseForCOMInterop();
10194 if (IsInterface() && IsComImport())
10196 // Determine if we are creating an interface methodtable that may be used to dispatch through VSD
10197 // on an object that has the methodtable of __ComObject.
10199 // This is done to allow COM tearoff interfaces, but as a side-effect of this feature,
10200 // we end up using a domain-shared type (__ComObject) with a domain-specific dispatch token.
10201 // This is a problem because the same domain-specific dispatch token value can appear in
10202 // multiple unshared domains (VSD takes advantage of the fact that in general a shared type
10203 // cannot implement an unshared interface). This means that the same <token, __ComObject> pair
10204 // value can mean different things in different domains (since the token could represent
10205 // IFoo in one domain and IBar in another). This is a problem because the
10206 // VSD polymorphic lookup mechanism relies on a process-wide cache table, and as a result
10207 // these duplicate values would collide if we didn't use fat dispatch token to ensure uniqueness
10208 // and the interface methodtable is not in the shared domain.
10210 pMT->SetRequiresFatDispatchTokens();
10212 #endif // FEATURE_COMINTEROP
10214 if (bmtVT->pCCtor != NULL)
10216 pMT->SetHasClassConstructor();
10217 CONSISTENCY_CHECK(pMT->GetClassConstructorSlot() == bmtVT->pCCtor->GetSlotIndex());
10219 if (bmtVT->pDefaultCtor != NULL)
10221 pMT->SetHasDefaultConstructor();
10222 CONSISTENCY_CHECK(pMT->GetDefaultConstructorSlot() == bmtVT->pDefaultCtor->GetSlotIndex());
10225 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10227 pChunk->SetMethodTable(pMT);
10232 // disable ibc logging because we can assert in ComputerPreferredZapModule for partially constructed
10234 IBCLoggingDisabler disableLogging;
10236 DeclaredMethodIterator it(*this);
10239 MethodDesc *pMD = it->GetMethodDesc();
10242 pMD->m_pDebugMethodTable.SetValue(pMT);
10243 pMD->m_pszDebugMethodSignature = FormatSig(pMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10245 MethodDesc *pUnboxedMD = it->GetUnboxedMethodDesc();
10246 if (pUnboxedMD != NULL)
10248 pUnboxedMD->m_pDebugMethodTable.SetValue(pMT);
10249 pUnboxedMD->m_pszDebugMethodSignature = FormatSig(pUnboxedMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10255 // Note that for value classes, the following calculation is only appropriate
10256 // when the instance is in its "boxed" state.
10257 if (!IsInterface())
10259 DWORD baseSize = Max<DWORD>(bmtFP->NumInstanceFieldBytes + OBJECT_BASESIZE, MIN_OBJECT_SIZE);
10260 baseSize = (baseSize + ALLOC_ALIGN_CONSTANT) & ~ALLOC_ALIGN_CONSTANT; // m_BaseSize must be aligned
10261 pMT->SetBaseSize(baseSize);
10263 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
10265 if (bmtProp->fIsComObjectType)
10266 { // Propagate the com specific info
10267 pMT->SetComObjectType();
10268 #ifdef FEATURE_COMINTEROP
10269 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
10270 // the optional field descriptor.
10271 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10272 #endif // FEATURE_COMINTEROP
10275 #ifdef FEATURE_COMINTEROP
10276 if (pMT->GetAssembly()->IsManagedWinMD())
10278 // We need to mark classes that are implementations of managed WinRT runtime classes with
10279 // the "exported to WinRT" flag. It's not quite possible to tell which ones these are by
10280 // reading metadata so we ask the adapter.
10282 IWinMDImport *pWinMDImport = pMT->GetAssembly()->GetManifestWinMDImport();
10283 _ASSERTE(pWinMDImport != NULL);
10286 IfFailThrow(pWinMDImport->IsRuntimeClassImplementation(GetCl(), &bResult));
10290 pClass->SetExportedToWinRT();
10292 // We need optional fields for activation from WinRT.
10293 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10297 if (pClass->IsProjectedFromWinRT() || pClass->IsExportedToWinRT())
10301 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), g_WindowsFoundationMarshalingBehaviorAttributeClassName, (const void **) &pVal, &cbVal);
10304 CustomAttributeParser cap(pVal, cbVal);
10305 IfFailThrow(cap.SkipProlog());
10307 IfFailThrow(cap.GetU4(&u));
10309 pClass->SetMarshalingType(u);
10312 #endif // FEATURE_COMINTEROP
10316 #ifdef FEATURE_COMINTEROP
10317 // If this is an interface then we need to set the ComInterfaceType to
10318 // -1 to indicate we have not yet determined the interface type.
10319 pClass->SetComInterfaceType((CorIfaceAttr)-1);
10321 // If this is a special COM event interface, then mark the MT as such.
10322 if (bmtProp->fComEventItfType)
10324 pClass->SetComEventItfType();
10326 #endif // FEATURE_COMINTEROP
10328 _ASSERTE((pMT->IsInterface() == 0) == (IsInterface() == 0));
10332 pClass->SetNativeSize(GetLayoutInfo()->GetNativeSize());
10335 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
10336 // Set all field slots to point to the newly created MethodTable
10337 for (i = 0; i < (bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields); i++)
10339 pFieldDescList[i].m_pMTOfEnclosingClass.SetValue(pMT);
10342 // Fill in type parameters before looking up exact parent or fetching the types of any field descriptors!
10343 // This must come before the use of GetFieldType in the value class representation optimization below.
10344 if (bmtGenerics->GetNumGenericArgs() != 0)
10346 // Space has already been allocated for the instantiation but the parameters haven't been filled in
10347 Instantiation destInst = pMT->GetInstantiation();
10348 Instantiation inst = bmtGenerics->GetInstantiation();
10350 // So fill them in...
10351 TypeHandle * pInstDest = (TypeHandle *)destInst.GetRawArgs();
10352 for (DWORD j = 0; j < bmtGenerics->GetNumGenericArgs(); j++)
10354 pInstDest[j] = inst[j];
10358 CorElementType normalizedType = ELEMENT_TYPE_CLASS;
10359 if (IsValueClass())
10363 if (GetNumInstanceFields() != 1 ||
10364 !CorTypeInfo::IsPrimitiveType(pFieldDescList[0].GetFieldType()))
10366 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
10368 CONSISTENCY_CHECK(!pFieldDescList[0].IsStatic());
10369 normalizedType = pFieldDescList->GetFieldType();
10373 #ifdef _TARGET_X86_
10374 // JIT64 is not aware of normalized value types and this
10375 // optimization (return small value types by value in registers)
10376 // is already done in JIT64.
10377 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10378 normalizedType = EEClass::ComputeInternalCorElementTypeForValueType(pMT);
10380 normalizedType = ELEMENT_TYPE_VALUETYPE;
10384 pMT->SetInternalCorElementType(normalizedType);
10386 if (bmtProp->fIsIntrinsicType)
10388 pMT->SetIsIntrinsicType();
10391 if (GetModule()->IsSystem())
10393 // we are in mscorlib
10394 CheckForSystemTypes();
10397 // Now fill in the real interface map with the approximate interfaces
10398 if (bmtInterface->dwInterfaceMapSize > 0)
10400 // First ensure we have enough space to record extra flag information for each interface (we don't
10401 // record this directly into each interface map entry since these flags don't pack well due to
10403 PVOID pExtraInterfaceInfo = NULL;
10404 SIZE_T cbExtraInterfaceInfo = MethodTable::GetExtraInterfaceInfoSize(bmtInterface->dwInterfaceMapSize);
10405 if (cbExtraInterfaceInfo)
10406 pExtraInterfaceInfo = GetMemTracker()->Track(GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbExtraInterfaceInfo)));
10408 // Call this even in the case where pExtraInterfaceInfo == NULL (certain cases are optimized and don't
10409 // require extra buffer space).
10410 pMT->InitializeExtraInterfaceInfo(pExtraInterfaceInfo);
10412 InterfaceInfo_t *pInterfaces = pMT->GetInterfaceMap();
10414 CONSISTENCY_CHECK(CheckPointer(pInterfaces));
10416 // Copy the interface map member by member so there is no junk in the padding.
10417 for (i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
10419 bmtInterfaceEntry * pEntry = &bmtInterface->pInterfaceMap[i];
10421 if (pEntry->IsDeclaredOnType())
10422 pMT->SetInterfaceDeclaredOnClass(i);
10423 _ASSERTE(!!pEntry->IsDeclaredOnType() == !!pMT->IsInterfaceDeclaredOnClass(i));
10425 pInterfaces[i].SetMethodTable(pEntry->GetInterfaceType()->GetMethodTable());
10429 pMT->SetCl(GetCl());
10431 // The type is sufficiently initialized for most general purpose accessor methods to work.
10432 // Mark the type as restored to avoid avoid asserts. Note that this also enables IBC logging.
10433 pMT->GetWriteableDataForWrite_NoLogging()->SetIsRestoredForBuildMethodTable();
10436 // Store status if we tried to inject duplicate interfaces
10437 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
10438 pMT->Debug_SetHasInjectedInterfaceDuplicates();
10441 // Keep bmtInterface data around since we no longer write the flags (IsDeclaredOnType and
10442 // IsImplementedByParent) into the interface map (these flags are only required during type loading).
10445 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10447 // Make sure that temporary entrypoints are create for methods. NGEN uses temporary
10448 // entrypoints as surrogate keys for precodes.
10449 pChunk->EnsureTemporaryEntryPointsCreated(GetLoaderAllocator(), GetMemTracker());
10453 { // copy onto the real vtable (methods only)
10454 //@GENERICS: Because we sometimes load an inexact parent (see ClassLoader::GetParent) the inherited slots might
10455 // come from the wrong place and need fixing up once we know the exact parent
10457 for (bmtVtable::Iterator slotIt = bmtVT->IterateSlots(); !slotIt.AtEnd(); ++slotIt)
10459 SLOT_INDEX iCurSlot = static_cast<SLOT_INDEX>(slotIt.CurrentIndex());
10461 // We want the unboxed MethodDesc if we're out of the virtual method range
10462 // and the method we're dealing with has an unboxing method. If so, then
10463 // the unboxing method was placed in the virtual section of the vtable and
10464 // we now need to place the unboxed version.
10465 MethodDesc * pMD = NULL;
10466 if (iCurSlot < bmtVT->cVirtualSlots || !slotIt->Impl().AsMDMethod()->IsUnboxing())
10468 pMD = slotIt->Impl().GetMethodDesc();
10469 CONSISTENCY_CHECK(slotIt->Decl().GetSlotIndex() == iCurSlot);
10473 pMD = slotIt->Impl().AsMDMethod()->GetUnboxedMethodDesc();
10474 CONSISTENCY_CHECK(pMD->GetSlot() == iCurSlot);
10477 CONSISTENCY_CHECK(CheckPointer(pMD));
10479 if (pMD->GetMethodTable() != pMT)
10484 // Do not write into vtable chunks shared with parent. It would introduce race
10485 // with code:MethodDesc::SetStableEntryPointInterlocked.
10487 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(iCurSlot);
10488 if (GetParentMethodTable()->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() != pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull())
10489 pMT->SetSlot(iCurSlot, pMD->GetInitialEntryPointForCopiedSlot());
10496 _ASSERTE(iCurSlot >= bmtVT->cVirtualSlots || ChangesImplementationOfVirtualSlot(iCurSlot));
10498 PCODE addr = pMD->GetTemporaryEntryPoint();
10499 _ASSERTE(addr != NULL);
10501 if (pMD->HasNonVtableSlot())
10503 *((PCODE *)pMD->GetAddrOfSlot()) = addr;
10507 pMT->SetSlot(iCurSlot, addr);
10510 if (pMD->GetSlot() == iCurSlot && pMD->RequiresStableEntryPoint())
10512 // The rest of the system assumes that certain methods always have stable entrypoints.
10513 // Create them now.
10514 pMD->GetOrCreatePrecode();
10520 // If we have any entries, then finalize them and allocate the object in class loader heap
10521 DispatchMap *pDispatchMap = NULL;
10522 DispatchMapBuilder *pDispatchMapBuilder = bmtVT->pDispatchMapBuilder;
10523 CONSISTENCY_CHECK(CheckPointer(pDispatchMapBuilder));
10525 if (pDispatchMapBuilder->Count() > 0)
10527 // Create a map in stacking memory.
10530 DispatchMap::CreateEncodedMapping(
10532 pDispatchMapBuilder,
10533 pDispatchMapBuilder->GetAllocator(),
10537 // Now finalize the impltable and allocate the block in the low frequency loader heap
10538 size_t objSize = (size_t) DispatchMap::GetObjectSize(cbMap);
10539 void * pv = AllocateFromLowFrequencyHeap(S_SIZE_T(objSize));
10540 _ASSERTE(pv != NULL);
10542 // Use placement new
10543 pDispatchMap = new (pv) DispatchMap(pbMap, cbMap);
10544 pMT->SetDispatchMap(pDispatchMap);
10547 g_sdStats.m_cDispatchMap++;
10548 g_sdStats.m_cbDispatchMap += (UINT32) objSize;
10549 LOG((LF_LOADER, LL_INFO1000, "SD: Dispatch map for %s: %d bytes for map, %d bytes total for object.\n",
10550 pMT->GetDebugClassName(), cbMap, objSize));
10555 // GetMethodData by default will cache its result. However, in the case that we're
10556 // building a MethodTable, we aren't guaranteed that this type is going to successfully
10557 // load and so caching it would result in errors down the road since the memory and
10558 // type occupying the same memory location would very likely be incorrect. The second
10559 // argument specifies that GetMethodData should not cache the returned object.
10560 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
10562 if (!IsInterface())
10564 // Propagate inheritance.
10566 // NOTE: In the world of unfolded interface this was used to propagate overrides into
10567 // the unfolded interface vtables to make sure that overrides of virtual methods
10568 // also overrode the interface methods that they contributed to. This had the
10569 // unfortunate side-effect of also overwriting regular vtable slots that had been
10570 // methodimpl'd and as a result changed the meaning of methodimpl from "substitute
10571 // the body of method A with the body of method B" to "unify the slots of methods
10572 // A and B". But now compilers have come to rely on this side-effect and it can
10573 // not be brought back to its originally intended behaviour.
10575 // For every slot whose body comes from another slot (determined by getting the MethodDesc
10576 // for a slot and seeing if MethodDesc::GetSlot returns a different value than the slot
10577 // from which the MethodDesc was recovered), copy the value of the slot stated by the
10578 // MethodDesc over top of the current slot.
10580 // Because of the way slot unification works, we need to iterate the enture vtable until
10581 // no slots need updated. To understand this, imagine the following:
10582 // C1::M1 is overridden by C2::M2
10583 // C1::M2 is methodImpled by C1::M3
10584 // C1::M3 is overridden by C2::M3
10585 // This should mean that C1::M1 is implemented by C2::M3, but if we didn't run the below
10586 // for loop a second time, this would not be propagated properly - it would only be placed
10587 // into the slot for C1::M2 and never make its way up to C1::M1.
10592 fChangeMade = FALSE;
10593 for (i = 0; i < pMT->GetNumVirtuals(); i++)
10595 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
10597 CONSISTENCY_CHECK(CheckPointer(pMD));
10598 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
10600 // This indicates that the method body in this slot was copied here through a methodImpl.
10601 // Thus, copy the value of the slot from which the body originally came, in case it was
10602 // overridden, to make sure the two slots stay in sync.
10603 DWORD originalIndex = pMD->GetSlot();
10604 if (originalIndex != i)
10606 MethodDesc *pOriginalMD = hMTData->GetImplMethodDesc(originalIndex);
10607 CONSISTENCY_CHECK(CheckPointer(pOriginalMD));
10608 CONSISTENCY_CHECK(pOriginalMD == pMT->GetMethodDescForSlot(originalIndex));
10609 if (pMD != pOriginalMD)
10611 // Copy the slot value in the method's original slot.
10612 pMT->SetSlot(i, pOriginalMD->GetInitialEntryPointForCopiedSlot());
10613 hMTData->InvalidateCachedVirtualSlot(i);
10615 // Update the pMD to the new method desc we just copied over ourselves with. This will
10616 // be used in the check for missing method block below.
10619 // This method is now duplicate
10620 pMD->SetDuplicate();
10621 INDEBUG(g_dupMethods++;)
10622 fChangeMade = TRUE;
10627 while (fChangeMade);
10630 if (!bmtProp->fNoSanityChecks)
10631 VerifyVirtualMethodsImplemented(hMTData);
10635 for (bmtVtable::Iterator i = bmtVT->IterateSlots();
10638 _ASSERTE(i->Impl().GetMethodDesc() != NULL);
10644 #ifdef FEATURE_COMINTEROP
10645 // for ComObject types, i.e. if the class extends from a COM Imported
10647 // make sure any interface implementated by the COM Imported class
10648 // is overridden fully, (OR) not overridden at all..
10649 // We relax this for WinRT where we want to be able to override individual methods.
10650 if (bmtProp->fIsComObjectType && !pMT->IsWinRTObjectType())
10652 MethodTable::InterfaceMapIterator intIt = pMT->IterateInterfaceMap();
10653 while (intIt.Next())
10655 MethodTable* pIntfMT = intIt.GetInterface();
10656 if (pIntfMT->GetNumVirtuals() != 0)
10658 BOOL hasComImportMethod = FALSE;
10659 BOOL hasManagedMethod = FALSE;
10661 // NOTE: Avoid caching the MethodData object for the type being built.
10662 MethodTable::MethodDataWrapper hItfImplData(MethodTable::GetMethodData(pIntfMT, pMT, FALSE));
10663 MethodTable::MethodIterator it(hItfImplData);
10664 for (;it.IsValid(); it.Next())
10666 MethodDesc *pClsMD = NULL;
10667 // If we fail to find an _IMPLEMENTATION_ for the interface MD, then
10668 // we are a ComImportMethod, otherwise we still be a ComImportMethod or
10669 // we can be a ManagedMethod.
10670 DispatchSlot impl(it.GetTarget());
10671 if (!impl.IsNull())
10673 pClsMD = it.GetMethodDesc();
10675 CONSISTENCY_CHECK(!pClsMD->IsInterface());
10676 if (pClsMD->GetClass()->IsComImport())
10678 hasComImportMethod = TRUE;
10682 hasManagedMethod = TRUE;
10687 // Need to set the pClsMD for the error reporting below.
10688 pClsMD = it.GetDeclMethodDesc();
10689 CONSISTENCY_CHECK(CheckPointer(pClsMD));
10690 hasComImportMethod = TRUE;
10693 // One and only one of the two must be set.
10694 if ((hasComImportMethod && hasManagedMethod) ||
10695 (!hasComImportMethod && !hasManagedMethod))
10697 BuildMethodTableThrowException(IDS_EE_BAD_COMEXTENDS_CLASS, pClsMD->GetNameOnNonArrayClass());
10704 // For COM event interfaces, we need to make sure that all the methods are
10705 // methods to add or remove events. This means that they all need to take
10706 // a delegate derived class and have a void return type.
10707 if (bmtProp->fComEventItfType)
10709 // COM event interfaces had better be interfaces.
10710 CONSISTENCY_CHECK(IsInterface());
10712 // Go through all the methods and check the validity of the signature.
10713 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
10714 MethodTable::MethodIterator it(hMTData);
10715 for (;it.IsValid(); it.Next())
10717 MethodDesc* pMD = it.GetMethodDesc();
10723 CONTRACT_VIOLATION(LoadsTypeViolation);
10724 if (Sig.GetReturnType() != ELEMENT_TYPE_VOID ||
10725 Sig.NumFixedArgs() != 1 ||
10726 Sig.NextArg() != ELEMENT_TYPE_CLASS ||
10727 !Sig.GetLastTypeHandleThrowing().CanCastTo(TypeHandle(g_pDelegateClass)))
10729 BuildMethodTableThrowException(IDS_EE_BAD_COMEVENTITF_CLASS, pMD->GetNameOnNonArrayClass());
10734 #endif // FEATURE_COMINTEROP
10736 // If this class uses any VTS (Version Tolerant Serialization) features
10737 // (event callbacks or OptionalField attributes) we've previously cached the
10738 // additional information in the bmtMFDescs structure. Now it's time to add
10739 // this information as an optional extension to the MethodTable.
10742 #pragma warning(pop)
10745 // Returns true if there is at least one default implementation for this interface method
10746 // We don't care about conflicts at this stage in order to avoid impact type load performance
10747 BOOL MethodTableBuilder::HasDefaultInterfaceImplementation(bmtRTType *pDeclType, MethodDesc *pDeclMD)
10749 STANDARD_VM_CONTRACT;
10751 #ifdef FEATURE_DEFAULT_INTERFACES
10752 // If the interface method is already non-abstract, we are done
10753 if (!pDeclMD->IsAbstract())
10756 int targetSlot = pDeclMD->GetSlot();
10758 // Iterate over all the interfaces this type implements
10759 bmtInterfaceEntry * pItfEntry = NULL;
10760 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
10762 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
10764 Module * pCurIntfModule = pCurItf->GetMethodTable()->GetModule();
10766 // Go over the methods on the interface
10767 MethodTable::IntroducedMethodIterator methIt(pCurItf->GetMethodTable());
10768 for (; methIt.IsValid(); methIt.Next())
10770 MethodDesc * pPotentialImpl = methIt.GetMethodDesc();
10772 // If this interface method is not a MethodImpl, it can't possibly implement
10773 // the interface method we are looking for
10774 if (!pPotentialImpl->IsMethodImpl())
10777 // Go over all the decls this MethodImpl is implementing
10778 MethodImpl::Iterator it(pPotentialImpl);
10779 for (; it.IsValid(); it.Next())
10781 MethodDesc *pPotentialDecl = it.GetMethodDesc();
10783 // Check this is a decl with the right slot
10784 if (pPotentialDecl->GetSlot() != targetSlot)
10787 // Find out what interface this default implementation is implementing
10789 IfFailThrow(pCurIntfModule->GetMDImport()->GetParentToken(it.GetToken(), &tkParent));
10791 // We can only load the approximate interface at this point
10792 MethodTable * pPotentialInterfaceMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
10795 &bmtGenerics->typeContext,
10796 ClassLoader::ThrowIfNotFound,
10797 ClassLoader::PermitUninstDefOrRef,
10798 ClassLoader::LoadTypes,
10799 CLASS_LOAD_APPROXPARENTS,
10800 TRUE).GetMethodTable()->GetCanonicalMethodTable();
10802 // Is this a default implementation for the interface we are looking for?
10803 if (pDeclType->GetMethodTable()->HasSameTypeDefAs(pPotentialInterfaceMT))
10805 // If the type is not generic, matching defs are all we need
10806 if (!pDeclType->GetMethodTable()->HasInstantiation())
10809 // If this is generic, we need to compare under substitutions
10810 Substitution curItfSubs(tkParent, pCurIntfModule, &pCurItf->GetSubstitution());
10812 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
10813 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
10814 if (MetaSig::CompareTypeDefsUnderSubstitutions(
10815 pPotentialInterfaceMT, pDeclType->GetMethodTable(),
10816 &curItfSubs, &pDeclType->GetSubstitution(),
10825 #endif // FEATURE_DEFAULT_INTERFACES
10830 void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData * hMTData)
10832 STANDARD_VM_CONTRACT;
10835 // This verification is not applicable or required in many cases
10838 if (IsAbstract() || IsInterface())
10841 #ifdef FEATURE_COMINTEROP
10842 // Note that this is important for WinRT where redirected .NET interfaces appear on the interface
10843 // impl list but their methods are not implemented (the adapter only hides the WinRT methods, it
10844 // does not make up the .NET ones).
10845 if (bmtProp->fIsComObjectType)
10847 #endif // FEATURE_COMINTEROP
10849 // Since interfaces aren't laid out in the vtable for stub dispatch, what we need to do
10850 // is try to find an implementation for every interface contract by iterating through
10851 // the interfaces not declared on a parent.
10852 BOOL fParentIsAbstract = FALSE;
10855 fParentIsAbstract = GetParentMethodTable()->IsAbstract();
10858 // If the parent is abstract, we need to check that each virtual method is implemented
10859 if (fParentIsAbstract)
10861 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
10862 MethodTable::MethodIterator it(hMTData);
10863 for (; it.IsValid() && it.IsVirtual(); it.Next())
10865 MethodDesc *pMD = it.GetMethodDesc();
10866 if (pMD->IsAbstract())
10868 MethodDesc *pDeclMD = it.GetDeclMethodDesc();
10869 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pDeclMD->GetNameOnNonArrayClass());
10874 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs =
10875 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
10877 bmtInterfaceInfo::MapIterator intIt = bmtInterface->IterateInterfaceMap();
10878 for (; !intIt.AtEnd(); intIt.Next())
10880 if (fParentIsAbstract || !intIt->IsImplementedByParent())
10882 // Compute all TypeIDs for this interface (all duplicates in the interface map)
10883 UINT32 cInterfaceDuplicates;
10884 ComputeDispatchMapTypeIDs(
10885 intIt->GetInterfaceType()->GetMethodTable(),
10886 &intIt->GetInterfaceType()->GetSubstitution(),
10887 rgInterfaceDispatchMapTypeIDs,
10888 bmtInterface->dwInterfaceMapSize,
10889 &cInterfaceDuplicates);
10890 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
10891 _ASSERTE(cInterfaceDuplicates > 0);
10893 // NOTE: This override does not cache the resulting MethodData object.
10894 MethodTable::MethodDataWrapper hData(MethodTable::GetMethodData(
10895 rgInterfaceDispatchMapTypeIDs,
10896 cInterfaceDuplicates,
10897 intIt->GetInterfaceType()->GetMethodTable(),
10898 GetHalfBakedMethodTable()));
10899 MethodTable::MethodIterator it(hData);
10900 for (; it.IsValid() && it.IsVirtual(); it.Next())
10902 if (it.GetTarget().IsNull())
10904 MethodDesc *pMD = it.GetDeclMethodDesc();
10906 if (!HasDefaultInterfaceImplementation(intIt->GetInterfaceType(), pMD))
10907 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass());
10914 INT32 __stdcall IsDefined(Module *pModule, mdToken token, TypeHandle attributeClass)
10923 BOOL isDefined = FALSE;
10925 IMDInternalImport *pInternalImport = pModule->GetMDImport();
10926 BOOL isSealed = FALSE;
10928 HENUMInternalHolder hEnum(pInternalImport);
10931 // Get the enum first but don't get any values
10932 hEnum.EnumInit(mdtCustomAttribute, token);
10934 ULONG cMax = pInternalImport->EnumGetCount(&hEnum);
10937 // we have something to look at
10940 if (!attributeClass.IsNull())
10941 isSealed = attributeClass.GetMethodTable()->IsSealed();
10943 // Loop through the Attributes and look for the requested one
10944 mdCustomAttribute cv;
10945 while (pInternalImport->EnumNext(&hEnum, &cv))
10950 IfFailThrow(pInternalImport->GetCustomAttributeProps(cv, &tkCtor));
10952 mdToken tkType = TypeFromToken(tkCtor);
10953 if(tkType != mdtMemberRef && tkType != mdtMethodDef)
10954 continue; // we only deal with the ctor case
10957 // get the info to load the type, so we can check whether the current
10958 // attribute is a subtype of the requested attribute
10959 IfFailThrow(pInternalImport->GetParentToken(tkCtor, &tkType));
10961 _ASSERTE(TypeFromToken(tkType) == mdtTypeRef || TypeFromToken(tkType) == mdtTypeDef);
10965 caTH=ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
10966 ClassLoader::ReturnNullIfNotFound,
10967 ClassLoader::FailIfUninstDefOrRef,
10968 TypeFromToken(tkType) == mdtTypeDef ? tdAllTypes : tdNoTypes);
10972 caTH = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
10973 ClassLoader::ReturnNullIfNotFound,
10974 ClassLoader::FailIfUninstDefOrRef);
10979 // a null class implies all custom attribute
10980 if (!attributeClass.IsNull())
10984 if (attributeClass != caTH)
10989 if (!caTH.CanCastTo(attributeClass))
10995 // if we are here we got one
11004 //*******************************************************************************
11005 VOID MethodTableBuilder::CheckForRemotingProxyAttrib()
11007 STANDARD_VM_CONTRACT;
11012 //*******************************************************************************
11013 // Checks for a bunch of special interface names and if it matches then it sets
11014 // bmtProp->fIsMngStandardItf to TRUE. Additionally, it checks to see if the
11015 // type is an interface and if it has ComEventInterfaceAttribute custom attribute
11016 // set, then it sets bmtProp->fComEventItfType to true.
11018 // NOTE: This only does anything when COM interop is enabled.
11020 VOID MethodTableBuilder::CheckForSpecialTypes()
11022 #ifdef FEATURE_COMINTEROP
11023 STANDARD_VM_CONTRACT;
11026 Module *pModule = GetModule();
11027 IMDInternalImport *pMDImport = pModule->GetMDImport();
11029 // Check to see if this type is a managed standard interface. All the managed
11030 // standard interfaces live in mscorlib.dll so checking for that first
11031 // makes the strcmp that comes afterwards acceptable.
11032 if (pModule->IsSystem())
11036 LPCUTF8 pszClassName;
11037 LPCUTF8 pszClassNamespace;
11038 if (FAILED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11040 pszClassName = pszClassNamespace = NULL;
11042 if ((pszClassName != NULL) && (pszClassNamespace != NULL))
11044 LPUTF8 pszFullyQualifiedName = NULL;
11045 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11047 // This is just to give us a scope to break out of.
11051 #define MNGSTDITF_BEGIN_INTERFACE(FriendlyName, strMngItfName, strUCOMMngItfName, strCustomMarshalerName, strCustomMarshalerCookie, strManagedViewName, NativeItfIID, bCanCastOnNativeItfQI) \
11052 if (strcmp(strMngItfName, pszFullyQualifiedName) == 0) \
11054 bmtProp->fIsMngStandardItf = true; \
11058 #define MNGSTDITF_DEFINE_METH_IMPL(FriendlyName, ECallMethName, MethName, MethSig, FcallDecl)
11060 #define MNGSTDITF_END_INTERFACE(FriendlyName)
11062 #include "mngstditflist.h"
11064 #undef MNGSTDITF_BEGIN_INTERFACE
11065 #undef MNGSTDITF_DEFINE_METH_IMPL
11066 #undef MNGSTDITF_END_INTERFACE
11070 if (strcmp(pszFullyQualifiedName, g_CollectionsGenericCollectionItfName) == 0 ||
11071 strcmp(pszFullyQualifiedName, g_CollectionsGenericReadOnlyCollectionItfName) == 0 ||
11072 strcmp(pszFullyQualifiedName, g_CollectionsCollectionItfName) == 0)
11074 // ICollection`1, ICollection and IReadOnlyCollection`1 are special cases the adapter is unaware of
11075 bmtProp->fIsRedirectedInterface = true;
11079 if (strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IEnumerable)) == 0 ||
11080 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IList)) == 0 ||
11081 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IDictionary)) == 0 ||
11082 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyList)) == 0 ||
11083 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyDictionary)) == 0 ||
11084 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_IEnumerable)) == 0 ||
11085 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_IList)) == 0 ||
11086 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_IDisposable)) == 0)
11088 bmtProp->fIsRedirectedInterface = true;
11092 // We want to allocate the per-type RCW data optional MethodTable field for
11093 // 1. Redirected interfaces
11094 // 2. Mscorlib-declared [WindowsRuntimeImport] interfaces
11095 bmtProp->fNeedsRCWPerTypeData = (bmtProp->fIsRedirectedInterface || GetHalfBakedClass()->IsProjectedFromWinRT());
11097 if (!bmtProp->fNeedsRCWPerTypeData)
11099 // 3. Non-generic IEnumerable
11100 if (strcmp(pszFullyQualifiedName, g_CollectionsEnumerableItfName) == 0)
11102 bmtProp->fNeedsRCWPerTypeData = true;
11107 else if (IsDelegate() && bmtGenerics->HasInstantiation())
11109 // 4. Redirected delegates
11110 if (GetHalfBakedClass()->GetWinRTRedirectedTypeIndex()
11111 != WinMDAdapter::RedirectedTypeIndex_Invalid)
11113 bmtProp->fNeedsRCWPerTypeData = true;
11117 else if (bmtGenerics->HasInstantiation() && pModule->GetAssembly()->IsWinMD())
11119 // 5. WinRT types with variance
11120 if (bmtGenerics->pVarianceInfo != NULL)
11122 bmtProp->fNeedsRCWPerTypeData = true;
11124 else if (IsInterface())
11126 // 6. Windows.Foundation.Collections.IIterator`1
11127 LPCUTF8 pszClassName;
11128 LPCUTF8 pszClassNamespace;
11129 if (SUCCEEDED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11131 LPUTF8 pszFullyQualifiedName = NULL;
11132 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11134 if (strcmp(pszFullyQualifiedName, g_WinRTIIteratorClassName) == 0)
11136 bmtProp->fNeedsRCWPerTypeData = true;
11141 else if ((IsInterface() || IsDelegate()) &&
11142 IsTdPublic(GetHalfBakedClass()->GetAttrClass()) &&
11143 GetHalfBakedClass()->GetWinRTRedirectedTypeIndex() != WinMDAdapter::RedirectedTypeIndex_Invalid)
11145 // 7. System.Collections.Specialized.INotifyCollectionChanged
11146 // 8. System.Collections.Specialized.NotifyCollectionChangedEventHandler
11147 // 9. System.ComponentModel.INotifyPropertyChanged
11148 // 10. System.ComponentModel.PropertyChangedEventHandler
11149 // 11. System.Windows.Input.ICommand
11150 LPCUTF8 pszClassName;
11151 LPCUTF8 pszClassNamespace;
11152 if (SUCCEEDED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11154 LPUTF8 pszFullyQualifiedName = NULL;
11155 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11157 if (strcmp(pszFullyQualifiedName, g_INotifyCollectionChangedName) == 0 ||
11158 strcmp(pszFullyQualifiedName, g_NotifyCollectionChangedEventHandlerName) == 0 ||
11159 strcmp(pszFullyQualifiedName, g_INotifyPropertyChangedName) == 0 ||
11160 strcmp(pszFullyQualifiedName, g_PropertyChangedEventHandlerName) == 0 ||
11161 strcmp(pszFullyQualifiedName, g_ICommandName) == 0)
11163 bmtProp->fNeedsRCWPerTypeData = true;
11168 // Check to see if the type is a COM event interface (classic COM interop only).
11169 if (IsInterface() && !GetHalfBakedClass()->IsProjectedFromWinRT())
11171 HRESULT hr = pMDImport->GetCustomAttributeByName(GetCl(), INTEROP_COMEVENTINTERFACE_TYPE, NULL, NULL);
11174 bmtProp->fComEventItfType = true;
11177 #endif // FEATURE_COMINTEROP
11180 #ifdef FEATURE_READYTORUN
11181 //*******************************************************************************
11182 VOID MethodTableBuilder::CheckLayoutDependsOnOtherModules(MethodTable * pDependencyMT)
11184 STANDARD_VM_CONTRACT;
11186 // These cases are expected to be handled by the caller
11187 _ASSERTE(!(pDependencyMT == g_pObjectClass || pDependencyMT->IsTruePrimitive() || ((g_pEnumClass != NULL) && pDependencyMT->IsEnum())));
11190 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11192 // Track whether field layout of this type depend on information outside its containing module
11194 // It is a stronger condition than MethodTable::IsInheritanceChainLayoutFixedInCurrentVersionBubble().
11195 // It has to remain fixed accross versioning changes in the module dependencies. In particular, it does
11196 // not take into account NonVersionable attribute. Otherwise, adding NonVersionable attribute to existing
11197 // type would be ReadyToRun incompatible change.
11199 if (pDependencyMT->GetModule() == GetModule())
11201 if (!pDependencyMT->GetClass()->HasLayoutDependsOnOtherModules())
11205 GetHalfBakedClass()->SetHasLayoutDependsOnOtherModules();
11208 BOOL MethodTableBuilder::NeedsAlignedBaseOffset()
11210 STANDARD_VM_CONTRACT;
11213 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11215 // This method returns whether the type needs aligned base offset in order to have layout resilient to
11216 // base class layout changes.
11218 if (IsValueClass())
11221 // Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on
11222 // whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching
11223 // ReadyToRun images with NGen.
11224 if (!GetModule()->GetFile()->IsILImageReadyToRun())
11226 // Always use ReadyToRun field layout algorithm to produce ReadyToRun images
11227 if (!IsReadyToRunCompilation())
11231 MethodTable * pParentMT = GetParentMethodTable();
11234 if (pParentMT == NULL || pParentMT == g_pObjectClass)
11237 if (pParentMT->GetModule() == GetModule())
11239 if (!pParentMT->GetClass()->HasLayoutDependsOnOtherModules())
11245 #endif // FEATURE_READYTORUN
11247 //*******************************************************************************
11249 // Used by BuildMethodTable
11251 // Set the HasFinalizer and HasCriticalFinalizer flags
11253 VOID MethodTableBuilder::SetFinalizationSemantics()
11255 STANDARD_VM_CONTRACT;
11257 if (g_pObjectFinalizerMD && !IsInterface() && !IsValueClass())
11259 WORD slot = g_pObjectFinalizerMD->GetSlot();
11261 // Objects not derived from Object will get marked as having a finalizer, if they have
11262 // sufficient virtual methods. This will only be an issue if they can be allocated
11263 // in the GC heap (which will cause all sorts of other problems).
11264 if (slot < bmtVT->cVirtualSlots && (*bmtVT)[slot].Impl().GetMethodDesc() != g_pObjectFinalizerMD)
11266 GetHalfBakedMethodTable()->SetHasFinalizer();
11268 // The need for a critical finalizer can be inherited from a parent.
11269 // Since we set this automatically for CriticalFinalizerObject
11270 // elsewhere, the code below is the means by which any derived class
11271 // picks up the attribute.
11272 if (HasParent() && GetParentMethodTable()->HasCriticalFinalizer())
11274 GetHalfBakedMethodTable()->SetHasCriticalFinalizer();
11280 //*******************************************************************************
11282 // Used by BuildMethodTable
11284 // Perform relevant GC calculations for value classes
11286 VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCache)
11288 STANDARD_VM_CONTRACT;
11292 EEClass *pClass = GetHalfBakedClass();
11293 MethodTable *pMT = GetHalfBakedMethodTable();
11295 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
11297 // Note that for value classes, the following calculation is only appropriate
11298 // when the instance is in its "boxed" state.
11299 #ifdef FEATURE_COLLECTIBLE_TYPES
11300 if (bmtFP->NumGCPointerSeries == 0 && pMT->Collectible())
11302 // For collectible types, insert empty gc series
11303 CGCDescSeries *pSeries;
11305 CGCDesc::Init( (PVOID) pMT, 1);
11306 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11307 pSeries->SetSeriesSize( (size_t) (0) - (size_t) pMT->GetBaseSize());
11308 pSeries->SetSeriesOffset(OBJECT_SIZE);
11311 #endif // FEATURE_COLLECTIBLE_TYPES
11312 if (bmtFP->NumGCPointerSeries != 0)
11314 CGCDescSeries *pSeries;
11315 CGCDescSeries *pHighest;
11317 pMT->SetContainsPointers();
11319 // Copy the pointer series map from the parent
11320 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
11321 if (bmtParent->NumParentPointerSeries != 0)
11323 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
11324 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize),
11325 (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize),
11326 ParentGCSize - sizeof(size_t) // sizeof(size_t) is the NumSeries count
11331 // Build the pointer series map for this pointers in this instance
11332 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11333 if (bmtFP->NumInstanceGCPointerFields)
11335 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
11336 pSeries->SetSeriesSize( (size_t) (bmtFP->NumInstanceGCPointerFields * TARGET_POINTER_SIZE) - (size_t) pMT->GetBaseSize());
11337 pSeries->SetSeriesOffset(bmtFP->GCPointerFieldStart + OBJECT_SIZE);
11341 // Insert GC info for fields which are by-value classes
11342 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
11344 if (pFieldDescList[i].IsByValue())
11346 MethodTable *pByValueMT = pByValueClassCache[i];
11348 if (pByValueMT->ContainsPointers())
11350 // Offset of the by value class in the class we are building, does NOT include Object
11351 DWORD dwCurrentOffset = pFieldDescList[i].GetOffset_NoLogging();
11353 // The by value class may have more than one pointer series
11354 CGCDescSeries * pByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetLowestSeries();
11355 SIZE_T dwNumByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
11357 for (SIZE_T j = 0; j < dwNumByValueSeries; j++)
11359 size_t cbSeriesSize;
11360 size_t cbSeriesOffset;
11362 _ASSERTE(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11364 cbSeriesSize = pByValueSeries->GetSeriesSize();
11366 // Add back the base size of the by value class, since it's being transplanted to this class
11367 cbSeriesSize += pByValueMT->GetBaseSize();
11369 // Subtract the base size of the class we're building
11370 cbSeriesSize -= pMT->GetBaseSize();
11372 // Set current series we're building
11373 pSeries->SetSeriesSize(cbSeriesSize);
11375 // Get offset into the value class of the first pointer field (includes a +Object)
11376 cbSeriesOffset = pByValueSeries->GetSeriesOffset();
11378 // Add it to the offset of the by value class in our class
11379 cbSeriesOffset += dwCurrentOffset;
11381 pSeries->SetSeriesOffset(cbSeriesOffset); // Offset of field
11389 // Adjust the inherited series - since the base size has increased by "# new field instance bytes", we need to
11390 // subtract that from all the series (since the series always has BaseSize subtracted for it - see gcdesc.h)
11391 pHighest = CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries();
11392 while (pSeries <= pHighest)
11394 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
11395 pSeries->SetSeriesSize( pSeries->GetSeriesSize() - ((size_t) pMT->GetBaseSize() - (size_t) GetParentMethodTable()->GetBaseSize()) );
11399 _ASSERTE(pSeries-1 <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11404 //*******************************************************************************
11406 // Used by BuildMethodTable
11408 // Check for the presence of type equivalence. If present, make sure
11409 // it is permitted to be on this type.
11412 void MethodTableBuilder::CheckForTypeEquivalence(
11413 WORD cBuildingInterfaceList,
11414 BuildingInterfaceInfo_t *pBuildingInterfaceList)
11416 STANDARD_VM_CONTRACT;
11418 #ifdef FEATURE_TYPEEQUIVALENCE
11419 bmtProp->fIsTypeEquivalent = !!IsTypeDefEquivalent(GetCl(), GetModule());
11421 if (bmtProp->fIsTypeEquivalent)
11423 BOOL comImportOrEventInterface = IsComImport();
11424 #ifdef FEATURE_COMINTEROP
11425 comImportOrEventInterface = comImportOrEventInterface || bmtProp->fComEventItfType;
11426 #endif // FEATURE_COMINTEROP
11428 BOOL fTypeEquivalentNotPermittedDueToType = !((comImportOrEventInterface && IsInterface()) || IsValueClass() || IsDelegate());
11429 BOOL fTypeEquivalentNotPermittedDueToGenerics = bmtGenerics->HasInstantiation();
11431 if (fTypeEquivalentNotPermittedDueToType || fTypeEquivalentNotPermittedDueToGenerics)
11433 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTBADTYPE);
11436 GetHalfBakedClass()->SetIsEquivalentType();
11439 bmtProp->fHasTypeEquivalence = bmtProp->fIsTypeEquivalent;
11441 if (!bmtProp->fHasTypeEquivalence)
11443 // fHasTypeEquivalence flag is inherited from interfaces so we can quickly detect
11444 // types that implement type equivalent interfaces
11445 for (WORD i = 0; i < cBuildingInterfaceList; i++)
11447 MethodTable *pItfMT = pBuildingInterfaceList[i].m_pMethodTable;
11448 if (pItfMT->HasTypeEquivalence())
11450 bmtProp->fHasTypeEquivalence = true;
11456 if (!bmtProp->fHasTypeEquivalence)
11458 // fHasTypeEquivalence flag is "inherited" from generic arguments so we can quickly detect
11459 // types like List<Str> where Str is a structure with the TypeIdentifierAttribute.
11460 if (bmtGenerics->HasInstantiation() && !bmtGenerics->IsTypicalTypeDefinition())
11462 Instantiation inst = bmtGenerics->GetInstantiation();
11463 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
11465 if (inst[i].HasTypeEquivalence())
11467 bmtProp->fHasTypeEquivalence = true;
11473 #endif //FEATURE_TYPEEQUIVALENCE
11476 //*******************************************************************************
11478 // Used by BuildMethodTable
11480 // Before we make the final leap, make sure we've allocated all memory needed to
11481 // fill out the RID maps.
11483 VOID MethodTableBuilder::EnsureRIDMapsCanBeFilled()
11485 STANDARD_VM_CONTRACT;
11491 // Rather than call Ensure***CanBeStored() hundreds of times, we
11492 // will call it once on the largest token we find. This relies
11493 // on an invariant that RidMaps don't use some kind of sparse
11497 mdMethodDef largest = mdMethodDefNil;
11499 DeclaredMethodIterator it(*this);
11502 if (it.Token() > largest)
11504 largest = it.Token();
11507 if ( largest != mdMethodDefNil )
11509 GetModule()->EnsureMethodDefCanBeStored(largest);
11514 mdFieldDef largest = mdFieldDefNil;
11516 for (i = 0; i < bmtMetaData->cFields; i++)
11518 if (bmtMetaData->pFields[i] > largest)
11520 largest = bmtMetaData->pFields[i];
11523 if ( largest != mdFieldDefNil )
11525 GetModule()->EnsureFieldDefCanBeStored(largest);
11530 #ifdef FEATURE_COMINTEROP
11531 //*******************************************************************************
11532 void MethodTableBuilder::GetCoClassAttribInfo()
11534 STANDARD_VM_CONTRACT;
11536 if (!GetHalfBakedClass()->IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT interfaces
11538 // Retrieve the CoClassAttribute CA.
11539 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COCLASS_TYPE, NULL, NULL);
11542 // COM class interfaces may lazily populate the m_pCoClassForIntf field of EEClass. This field is
11543 // optional so we must ensure the optional field descriptor has been allocated.
11544 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
11545 SetIsComClassInterface();
11549 #endif // FEATURE_COMINTEROP
11551 //*******************************************************************************
11552 void MethodTableBuilder::bmtMethodImplInfo::AddMethodImpl(
11553 bmtMDMethod * pImplMethod, bmtMethodHandle declMethod, mdToken declToken,
11554 StackingAllocator * pStackingAllocator)
11556 STANDARD_VM_CONTRACT;
11558 CONSISTENCY_CHECK(CheckPointer(pImplMethod));
11559 CONSISTENCY_CHECK(!declMethod.IsNull());
11560 if (pIndex >= cMaxIndex)
11562 DWORD newEntriesCount = 0;
11564 if (!ClrSafeInt<DWORD>::multiply(cMaxIndex, 2, newEntriesCount))
11565 ThrowHR(COR_E_OVERFLOW);
11567 if (newEntriesCount == 0)
11568 newEntriesCount = 10;
11570 // If we have to grow this array, we will not free the old array before we clean up the BuildMethodTable operation
11571 // because this is a stacking allocator. However, the old array will get freed when all the stack allocator is freed.
11572 Entry *rgEntriesNew = new (pStackingAllocator) Entry[newEntriesCount];
11573 memcpy(rgEntriesNew, rgEntries, sizeof(Entry) * cMaxIndex);
11575 // Start using newly allocated array.
11576 rgEntries = rgEntriesNew;
11577 cMaxIndex = newEntriesCount;
11579 rgEntries[pIndex++] = Entry(pImplMethod, declMethod, declToken);
11582 //*******************************************************************************
11583 // Returns TRUE if tok acts as a body for any methodImpl entry. FALSE, otherwise.
11584 BOOL MethodTableBuilder::bmtMethodImplInfo::IsBody(mdToken tok)
11586 LIMITED_METHOD_CONTRACT;
11587 CONSISTENCY_CHECK(TypeFromToken(tok) == mdtMethodDef);
11588 for (DWORD i = 0; i < pIndex; i++)
11590 if (GetBodyMethodDesc(i)->GetMemberDef() == tok)
11598 //*******************************************************************************
11600 MethodTableBuilder::AllocateFromHighFrequencyHeap(S_SIZE_T cbMem)
11609 return (BYTE *)GetMemTracker()->Track(
11610 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(cbMem));
11613 //*******************************************************************************
11615 MethodTableBuilder::AllocateFromLowFrequencyHeap(S_SIZE_T cbMem)
11624 return (BYTE *)GetMemTracker()->Track(
11625 GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(cbMem));
11628 //-------------------------------------------------------------------------------
11629 // Make best-case effort to obtain an image name for use in an error message.
11631 // This routine must expect to be called before the this object is fully loaded.
11632 // It can return an empty if the name isn't available or the object isn't initialized
11633 // enough to get a name, but it mustn't crash.
11634 //-------------------------------------------------------------------------------
11635 LPCWSTR MethodTableBuilder::GetPathForErrorMessages()
11637 STANDARD_VM_CONTRACT;
11639 return GetModule()->GetPathForErrorMessages();
11642 BOOL MethodTableBuilder::ChangesImplementationOfVirtualSlot(SLOT_INDEX idx)
11644 STANDARD_VM_CONTRACT;
11646 BOOL fChangesImplementation = TRUE;
11648 _ASSERTE(idx < bmtVT->cVirtualSlots);
11650 if (HasParent() && idx < GetParentMethodTable()->GetNumVirtuals())
11652 _ASSERTE(idx < bmtParent->pSlotTable->GetSlotCount());
11653 bmtMethodHandle VTImpl = (*bmtVT)[idx].Impl();
11654 bmtMethodHandle ParentImpl = (*bmtParent)[idx].Impl();
11656 fChangesImplementation = VTImpl != ParentImpl;
11658 // See code:MethodTableBuilder::SetupMethodTable2 and its logic
11659 // for handling MethodImpl's on parent classes which affect non interface
11661 if (!fChangesImplementation && (ParentImpl.GetSlotIndex() != idx))
11662 fChangesImplementation = TRUE;
11665 return fChangesImplementation;
11668 // Must be called prior to setting the value of any optional field on EEClass (on a debug build an assert will
11669 // fire if this invariant is violated).
11670 void MethodTableBuilder::EnsureOptionalFieldsAreAllocated(EEClass *pClass, AllocMemTracker *pamTracker, LoaderHeap *pHeap)
11672 STANDARD_VM_CONTRACT;
11674 if (pClass->HasOptionalFields())
11677 EEClassOptionalFields *pOptFields = (EEClassOptionalFields*)
11678 pamTracker->Track(pHeap->AllocMem(S_SIZE_T(sizeof(EEClassOptionalFields))));
11680 // Initialize default values for all optional fields.
11681 pOptFields->Init();
11683 // Attach optional fields to the class.
11684 pClass->AttachOptionalFields(pOptFields);
11687 //---------------------------------------------------------------------------------------
11689 // Gather information about a generic type
11690 // - number of parameters
11691 // - variance annotations
11697 MethodTableBuilder::GatherGenericsInfo(
11700 Instantiation inst,
11701 bmtGenericsInfo * bmtGenericsInfo)
11706 PRECONDITION(GetThread() != NULL);
11707 PRECONDITION(CheckPointer(pModule));
11708 PRECONDITION(CheckPointer(bmtGenericsInfo));
11712 IMDInternalImport * pInternalImport = pModule->GetMDImport();
11714 // Enumerate the formal type parameters
11715 HENUMInternal hEnumGenericPars;
11716 HRESULT hr = pInternalImport->EnumInit(mdtGenericParam, cl, &hEnumGenericPars);
11718 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11720 DWORD numGenericArgs = pInternalImport->EnumGetCount(&hEnumGenericPars);
11722 // Work out what kind of EEClass we're creating w.r.t. generics. If there
11723 // are no generics involved this will be a VMFLAG_NONGENERIC.
11724 BOOL fHasVariance = FALSE;
11725 if (numGenericArgs > 0)
11727 // Generic type verification
11731 if (FAILED(pInternalImport->GetTypeDefProps(cl, &dwAttr, &tkParent)))
11733 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11735 // A generic with explicit layout is not allowed.
11736 if (IsTdExplicitLayout(dwAttr))
11738 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_EXPLICIT_GENERIC);
11742 bmtGenericsInfo->numDicts = 1;
11744 mdGenericParam tkTyPar;
11745 bmtGenericsInfo->pVarianceInfo = new (&GetThread()->m_MarshalAlloc) BYTE[numGenericArgs];
11747 // If it has generic arguments but none have been specified, then load the instantiation at the formals
11748 if (inst.IsEmpty())
11750 bmtGenericsInfo->fTypicalInstantiation = TRUE;
11751 S_UINT32 scbAllocSize = S_UINT32(numGenericArgs) * S_UINT32(sizeof(TypeHandle));
11752 TypeHandle * genericArgs = (TypeHandle *) GetThread()->m_MarshalAlloc.Alloc(scbAllocSize);
11754 inst = Instantiation(genericArgs, numGenericArgs);
11756 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
11760 bmtGenericsInfo->fTypicalInstantiation = FALSE;
11762 bmtGenericsInfo->fSharedByGenericInstantiations = TypeHandle::IsCanonicalSubtypeInstantiation(inst);
11763 _ASSERTE(bmtGenericsInfo->fSharedByGenericInstantiations == ClassLoader::IsSharableInstantiation(inst));
11766 // Set typical instantiation MethodTable
11768 MethodTable * pTypicalInstantiationMT = pModule->LookupTypeDef(cl).AsMethodTable();
11769 // Typical instantiation was already loaded by code:ClassLoader::LoadApproxTypeThrowing
11770 _ASSERTE(pTypicalInstantiationMT != NULL);
11771 bmtGenericsInfo->dbg_pTypicalInstantiationMT = pTypicalInstantiationMT;
11776 TypeHandle * pDestInst = (TypeHandle *)inst.GetRawArgs();
11777 for (unsigned int i = 0; i < numGenericArgs; i++)
11779 pInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
11781 if (FAILED(pInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
11783 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11786 if (bmtGenericsInfo->fTypicalInstantiation)
11788 // code:Module.m_GenericParamToDescMap maps generic parameter RIDs to TypeVarTypeDesc
11789 // instances so that we do not leak by allocating them all over again, if the type
11790 // repeatedly fails to load.
11791 TypeVarTypeDesc *pTypeVarTypeDesc = pModule->LookupGenericParam(tkTyPar);
11792 if (pTypeVarTypeDesc == NULL)
11794 // Do NOT use the alloc tracker for this memory as we need it stay allocated even if the load fails.
11795 void *mem = (void *)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TypeVarTypeDesc)));
11796 pTypeVarTypeDesc = new (mem) TypeVarTypeDesc(pModule, cl, i, tkTyPar);
11798 // No race here - the row in GenericParam table is owned exclusively by this type and we
11799 // are holding a lock preventing other threads from concurrently loading it.
11800 pModule->StoreGenericParamThrowing(tkTyPar, pTypeVarTypeDesc);
11802 pDestInst[i] = TypeHandle(pTypeVarTypeDesc);
11805 DWORD varianceAnnotation = flags & gpVarianceMask;
11806 bmtGenericsInfo->pVarianceInfo[i] = static_cast<BYTE>(varianceAnnotation);
11807 if (varianceAnnotation != gpNonVariant)
11809 if (varianceAnnotation != gpContravariant && varianceAnnotation != gpCovariant)
11811 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADVARIANCE);
11815 fHasVariance = TRUE;
11821 bmtGenericsInfo->pVarianceInfo = NULL;
11825 bmtGenericsInfo->fTypicalInstantiation = FALSE;
11826 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
11827 bmtGenericsInfo->numDicts = 0;
11830 bmtGenericsInfo->fContainsGenericVariables = MethodTable::ComputeContainsGenericVariables(inst);
11832 SigTypeContext typeContext(inst, Instantiation());
11833 bmtGenericsInfo->typeContext = typeContext;
11834 } // MethodTableBuilder::GatherGenericsInfo
11836 //---------------------------------------------------------------------------------------
11838 // This service is called for normal classes -- and for the pseudo class we invent to
11839 // hold the module's public members.
11843 ClassLoader::CreateTypeHandleForTypeDefThrowing(
11846 Instantiation inst,
11847 AllocMemTracker * pamTracker)
11849 CONTRACT(TypeHandle)
11852 PRECONDITION(GetThread() != NULL);
11853 PRECONDITION(CheckPointer(pModule));
11854 POSTCONDITION(!RETVAL.IsNull());
11855 POSTCONDITION(CheckPointer(RETVAL.GetMethodTable()));
11859 MethodTable * pMT = NULL;
11861 Thread * pThread = GetThread();
11863 MethodTable * pParentMethodTable = NULL;
11864 SigPointer parentInst;
11865 mdTypeDef tdEnclosing = mdTypeDefNil;
11867 BuildingInterfaceInfo_t * pInterfaceBuildInfo = NULL;
11868 IMDInternalImport * pInternalImport = NULL;
11869 LayoutRawFieldInfo * pLayoutRawFieldInfos = NULL;
11870 MethodTableBuilder::bmtGenericsInfo genericsInfo;
11872 Assembly * pAssembly = pModule->GetAssembly();
11873 pInternalImport = pModule->GetMDImport();
11875 if (TypeFromToken(cl) != mdtTypeDef || !pInternalImport->IsValidToken(cl))
11877 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11880 // GetCheckpoint for the thread-based allocator
11881 // This checkpoint provides a scope for all transient allocations of data structures
11882 // used during class loading.
11883 // <NICE> Ideally a debug/checked build should pass around tokens indicating the Checkpoint
11884 // being used and check these dynamically </NICE>
11885 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
11887 // Gather up generics info
11888 MethodTableBuilder::GatherGenericsInfo(pModule, cl, inst, &genericsInfo);
11890 Module * pLoaderModule = pModule;
11891 if (!inst.IsEmpty())
11893 pLoaderModule = ClassLoader::ComputeLoaderModuleWorker(
11898 pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(pModule, inst);
11901 LoaderAllocator * pAllocator = pLoaderModule->GetLoaderAllocator();
11904 // As this is loading a parent type, we are allowed to override the load type limit.
11905 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
11906 pParentMethodTable = LoadApproxParentThrowing(pModule, cl, &parentInst, &genericsInfo.typeContext);
11909 if (pParentMethodTable != NULL)
11911 // Since methods on System.Array assume the layout of arrays, we can not allow
11912 // subclassing of arrays, it is sealed from the users point of view.
11913 // Value types and enums should be sealed - disable inheritting from them (we cannot require sealed
11914 // flag because of AppCompat)
11915 if (pParentMethodTable->IsSealed() ||
11916 (pParentMethodTable == g_pArrayClass) ||
11917 pParentMethodTable->IsValueType())
11919 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_SEALEDPARENT);
11922 DWORD dwTotalDicts = genericsInfo.numDicts + pParentMethodTable->GetNumDicts();
11923 if (!FitsIn<WORD>(dwTotalDicts))
11925 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_TOOMANYGENERICARGS);
11927 genericsInfo.numDicts = static_cast<WORD>(dwTotalDicts);
11930 GetEnclosingClassThrowing(pInternalImport, pModule, cl, &tdEnclosing);
11932 BYTE nstructPackingSize = 0, nstructNLT = 0;
11933 BOOL fExplicitOffsets = FALSE;
11934 // NOTE: HasLayoutMetadata does not load classes
11936 !genericsInfo.fContainsGenericVariables &&
11938 pModule->GetAssembly(),
11941 pParentMethodTable,
11942 &nstructPackingSize,
11944 &fExplicitOffsets);
11946 BOOL fIsEnum = ((g_pEnumClass != NULL) && (pParentMethodTable == g_pEnumClass));
11948 // enums may not have layout because they derive from g_pEnumClass and that has no layout
11949 // this is enforced by HasLayoutMetadata above
11950 _ASSERTE(!(fIsEnum && fHasLayout));
11952 // This is a delegate class if it derives from MulticastDelegate (we do not allow single cast delegates)
11953 BOOL fIsDelegate = pParentMethodTable && pParentMethodTable == g_pMulticastDelegateClass;
11955 // Create a EEClass entry for it, filling out a few fields, such as the parent class token
11956 // (and the generic type should we be creating an instantiation)
11957 EEClass * pClass = MethodTableBuilder::CreateClass(
11967 if ((pParentMethodTable != NULL) && (pParentMethodTable == g_pDelegateClass))
11969 // Note we do not allow single cast delegates
11970 if (pModule->GetAssembly() != SystemDomain::SystemAssembly())
11972 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_CANNOT_INHERIT_FROM_DELEGATE);
11976 // Only MultiCastDelegate should inherit from Delegate
11979 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
11981 className = nameSpace = "Invalid TypeDef record";
11983 BAD_FORMAT_NOTHROW_ASSERT(strcmp(className, "MulticastDelegate") == 0);
11989 if (!pClass->IsSealed())
11991 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_DELEGATE_CLASS_NOTSEALED);
11994 pClass->SetIsDelegate();
11997 if (tdEnclosing != mdTypeDefNil)
11999 pClass->SetIsNested();
12000 THROW_BAD_FORMAT_MAYBE(IsTdNested(pClass->GetProtection()), VLDTR_E_TD_ENCLNOTNESTED, pModule);
12002 else if (IsTdNested(pClass->GetProtection()))
12004 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12007 // We only permit generic interfaces and delegates to have variant type parameters
12008 if (genericsInfo.pVarianceInfo != NULL && !pClass->IsInterface() && !fIsDelegate)
12010 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_CLASS);
12013 // Now load all the interfaces
12014 HENUMInternalHolder hEnumInterfaceImpl(pInternalImport);
12015 hEnumInterfaceImpl.EnumInit(mdtInterfaceImpl, cl);
12017 cInterfaces = pInternalImport->EnumGetCount(&hEnumInterfaceImpl);
12019 if (cInterfaces != 0)
12023 // Allocate the BuildingInterfaceList table
12024 pInterfaceBuildInfo = new (&GetThread()->m_MarshalAlloc) BuildingInterfaceInfo_t[cInterfaces];
12026 mdInterfaceImpl ii;
12027 for (i = 0; pInternalImport->EnumNext(&hEnumInterfaceImpl, &ii); i++)
12029 // Get properties on this interface
12030 mdTypeRef crInterface;
12031 if (FAILED(pInternalImport->GetTypeOfInterfaceImpl(ii, &crInterface)))
12033 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12035 // validate the token
12036 mdToken crIntType =
12037 (RidFromToken(crInterface) && pInternalImport->IsValidToken(crInterface)) ?
12038 TypeFromToken(crInterface) :
12047 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12050 TypeHandle intType;
12053 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
12054 intType = LoadApproxTypeThrowing(pModule, crInterface, NULL, &genericsInfo.typeContext);
12057 pInterfaceBuildInfo[i].m_pMethodTable = intType.AsMethodTable();
12058 if (pInterfaceBuildInfo[i].m_pMethodTable == NULL)
12060 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12063 // Ensure this is an interface
12064 if (!pInterfaceBuildInfo[i].m_pMethodTable->IsInterface())
12066 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_NOTINTERFACE);
12069 // Check interface for use of variant type parameters
12070 if ((genericsInfo.pVarianceInfo != NULL) && (TypeFromToken(crInterface) == mdtTypeSpec))
12073 PCCOR_SIGNATURE pSig;
12074 if (FAILED(pInternalImport->GetTypeSpecFromToken(crInterface, &pSig, &cSig)))
12076 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12078 // Interfaces behave covariantly
12079 if (!EEClass::CheckVarianceInSig(
12080 genericsInfo.GetNumGenericArgs(),
12081 genericsInfo.pVarianceInfo,
12083 SigPointer(pSig, cSig),
12086 pAssembly->ThrowTypeLoadException(
12089 IDS_CLASSLOAD_VARIANCE_IN_INTERFACE);
12093 _ASSERTE(i == cInterfaces);
12097 /* Variant delegates should not have any instance fields of the variant.
12098 type parameter. For now, we just completely disallow all fields even
12099 if they are non-variant or static, as it is not a useful scenario.
12100 @TODO: A more logical place for this check would be in
12101 MethodTableBuilder::EnumerateClassMembers() */
12102 (fIsDelegate && genericsInfo.pVarianceInfo))
12104 // check for fields and variance
12106 HENUMInternalHolder hEnumField(pInternalImport);
12107 hEnumField.EnumInit(mdtFieldDef, cl);
12109 cFields = pInternalImport->EnumGetCount(&hEnumField);
12111 if ((cFields != 0) && fIsDelegate && (genericsInfo.pVarianceInfo != NULL))
12113 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_IN_DELEGATE);
12118 // Though we fail on this condition, we should never run into it.
12119 CONSISTENCY_CHECK(nstructPackingSize != 0);
12120 // MD Val check: PackingSize
12121 if((nstructPackingSize == 0) ||
12122 (nstructPackingSize > 128) ||
12123 (nstructPackingSize & (nstructPackingSize-1)))
12125 THROW_BAD_FORMAT_MAYBE(!"ClassLayout:Invalid PackingSize", BFA_BAD_PACKING_SIZE, pModule);
12126 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12129 pLayoutRawFieldInfos = (LayoutRawFieldInfo *)GetThread()->m_MarshalAlloc.Alloc(
12130 (S_UINT32(1) + S_UINT32(cFields)) * S_UINT32(sizeof(LayoutRawFieldInfo)));
12133 // Warning: this can load classes
12134 CONTRACT_VIOLATION(LoadsTypeViolation);
12136 // Set a flag that allows us to break dead-locks that are result of the LoadsTypeViolation
12137 ThreadStateNCStackHolder tsNC(TRUE, Thread::TSNC_LoadsTypeViolation);
12139 EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
12141 nstructPackingSize,
12143 #ifdef FEATURE_COMINTEROP
12144 pClass->IsProjectedFromWinRT(),
12145 #endif // FEATURE_COMINTEROP
12147 pParentMethodTable,
12151 &genericsInfo.typeContext,
12152 &(((LayoutEEClass *)pClass)->m_LayoutInfo),
12153 pLayoutRawFieldInfos,
12160 // Resolve this class, given that we know now that all of its dependencies are loaded and resolved.
12161 // !!! This must be the last thing in this TRY block: if MethodTableBuilder succeeds, it has published the class
12162 // and there is no going back.
12163 MethodTableBuilder builder(
12166 &GetThread()->m_MarshalAlloc,
12169 pMT = builder.BuildMethodTableThrowing(
12174 pInterfaceBuildInfo,
12175 pLayoutRawFieldInfos,
12176 pParentMethodTable,
12179 (WORD)cInterfaces);
12181 RETURN(TypeHandle(pMT));
12182 } // ClassLoader::CreateTypeHandleForTypeDefThrowing