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 // Some interface checks.
2896 // We only need them if default interface method support is disabled or if this is fragile crossgen
2897 #if !defined(FEATURE_DEFAULT_INTERFACES) || defined(FEATURE_NATIVE_IMAGE_GENERATION)
2898 if (fIsClassInterface
2899 #if defined(FEATURE_DEFAULT_INTERFACES)
2900 // Only fragile crossgen wasn't upgraded to deal with default interface methods.
2901 && !IsReadyToRunCompilation()
2905 if (IsMdVirtual(dwMemberAttrs))
2907 if (!IsMdAbstract(dwMemberAttrs))
2909 BuildMethodTableThrowException(BFA_VIRTUAL_NONAB_INT_METHOD);
2915 if (!IsMdStatic(dwMemberAttrs))
2917 BuildMethodTableThrowException(BFA_NONVIRT_INST_INT_METHOD);
2921 #endif // !defined(FEATURE_DEFAULT_INTERFACES) || defined(FEATURE_NATIVE_IMAGE_GENERATION)
2923 // No synchronized methods in ValueTypes
2924 if(fIsClassValueType && IsMiSynchronized(dwImplFlags))
2926 BuildMethodTableThrowException(BFA_SYNC_METHOD_IN_VT);
2932 if(!IsMdStatic(dwMemberAttrs))
2934 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_METHOD);
2936 if (strMethodName) //<TODO>@todo: investigate mc++ generating null name</TODO>
2938 if(0==strcmp(strMethodName, COR_CTOR_METHOD_NAME))
2940 BuildMethodTableThrowException(BFA_GLOBAL_INST_CTOR);
2945 // Generic methods or methods in generic classes
2946 // may not be part of a COM Import class (except for WinRT), PInvoke, internal call outside mscorlib.
2947 if ((bmtGenerics->GetNumGenericArgs() != 0 || numGenericMethodArgs != 0) &&
2949 #ifdef FEATURE_COMINTEROP
2950 fIsClassComImport ||
2951 bmtProp->fComEventItfType ||
2952 #endif // FEATURE_COMINTEROP
2953 IsMdPinvokeImpl(dwMemberAttrs) ||
2954 (IsMiInternalCall(dwImplFlags) && !GetModule()->IsSystem())))
2956 #ifdef FEATURE_COMINTEROP
2957 if (!GetHalfBakedClass()->IsProjectedFromWinRT())
2958 #endif // FEATURE_COMINTEROP
2960 BuildMethodTableThrowException(BFA_BAD_PLACE_FOR_GENERIC_METHOD);
2964 // Generic methods may not be marked "runtime". However note that
2965 // methods in generic delegate classes are, hence we don't apply this to
2966 // methods in generic classes in general.
2967 if (numGenericMethodArgs != 0 && IsMiRuntime(dwImplFlags))
2969 BuildMethodTableThrowException(BFA_GENERIC_METHOD_RUNTIME_IMPL);
2973 // Signature validation
2974 if (FAILED(pMDInternalImport->GetSigOfMethodDef(tok, &cMemberSignature, &pMemberSignature)))
2976 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2978 hr = validateTokenSig(tok,pMemberSignature,cMemberSignature,dwMemberAttrs,pMDInternalImport);
2981 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2984 // Check the appearance of covariant and contravariant in the method signature
2985 // Note that variance is only supported for interfaces
2986 if (bmtGenerics->pVarianceInfo != NULL)
2988 SigPointer sp(pMemberSignature, cMemberSignature);
2990 IfFailThrow(sp.GetCallingConvInfo(&callConv));
2992 if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2993 IfFailThrow(sp.GetData(NULL));
2996 IfFailThrow(sp.GetData(&numArgs));
2998 // Return type behaves covariantly
2999 if (!EEClass::CheckVarianceInSig(
3000 bmtGenerics->GetNumGenericArgs(),
3001 bmtGenerics->pVarianceInfo,
3006 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_RESULT, tok);
3008 IfFailThrow(sp.SkipExactlyOne());
3009 for (DWORD j = 0; j < numArgs; j++)
3011 // Argument types behave contravariantly
3012 if (!EEClass::CheckVarianceInSig(bmtGenerics->GetNumGenericArgs(),
3013 bmtGenerics->pVarianceInfo,
3018 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_ARG, tok);
3020 IfFailThrow(sp.SkipExactlyOne());
3025 // Determine the method's type
3028 if (IsReallyMdPinvokeImpl(dwMemberAttrs) || IsMiInternalCall(dwImplFlags))
3030 hr = NDirect::HasNAT_LAttribute(pMDInternalImport, tok, dwMemberAttrs);
3032 // There was a problem querying for the attribute
3035 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_BADPINVOKE, tok);
3038 // The attribute is not present
3041 #ifdef FEATURE_COMINTEROP
3042 if (fIsClassComImport
3043 || GetHalfBakedClass()->IsProjectedFromWinRT()
3044 || bmtProp->fComEventItfType
3047 // ComImport classes have methods which are just used
3048 // for implementing all interfaces the class supports
3049 type = METHOD_TYPE_COMINTEROP;
3051 // constructor is special
3052 if (IsMdRTSpecialName(dwMemberAttrs))
3054 // Note: Method name (.ctor) will be checked in code:ValidateMethods
3056 // WinRT ctors are interop calls via stubs
3057 if (!GetHalfBakedClass()->IsProjectedFromWinRT())
3059 // Ctor on a non-WinRT class
3060 type = METHOD_TYPE_FCALL;
3065 #endif //FEATURE_COMINTEROP
3066 if (dwMethodRVA == 0)
3068 type = METHOD_TYPE_FCALL;
3072 type = METHOD_TYPE_NDIRECT;
3075 // The NAT_L attribute is present, marking this method as NDirect
3078 CONSISTENCY_CHECK(hr == S_OK);
3079 type = METHOD_TYPE_NDIRECT;
3082 else if (IsMiRuntime(dwImplFlags))
3084 // currently the only runtime implemented functions are delegate instance methods
3085 if (!IsDelegate() || IsMdStatic(dwMemberAttrs) || IsMdAbstract(dwMemberAttrs))
3087 BuildMethodTableThrowException(BFA_BAD_RUNTIME_IMPL);
3090 unsigned newDelegateMethodSeen = 0;
3092 if (IsMdRTSpecialName(dwMemberAttrs)) // .ctor
3094 if (strcmp(strMethodName, COR_CTOR_METHOD_NAME) != 0 || IsMdVirtual(dwMemberAttrs))
3096 BuildMethodTableThrowException(BFA_BAD_FLAGS_ON_DELEGATE);
3098 newDelegateMethodSeen = SeenCtor;
3099 type = METHOD_TYPE_FCALL;
3103 if (strcmp(strMethodName, "Invoke") == 0)
3104 newDelegateMethodSeen = SeenInvoke;
3105 else if (strcmp(strMethodName, "BeginInvoke") == 0)
3106 newDelegateMethodSeen = SeenBeginInvoke;
3107 else if (strcmp(strMethodName, "EndInvoke") == 0)
3108 newDelegateMethodSeen = SeenEndInvoke;
3111 BuildMethodTableThrowException(BFA_UNKNOWN_DELEGATE_METHOD);
3113 type = METHOD_TYPE_EEIMPL;
3116 // If we get here we have either set newDelegateMethodSeen or we have thrown a BMT exception
3117 _ASSERTE(newDelegateMethodSeen != 0);
3119 if ((delegateMethodsSeen & newDelegateMethodSeen) != 0)
3121 BuildMethodTableThrowException(BFA_DUPLICATE_DELEGATE_METHOD);
3124 delegateMethodsSeen |= newDelegateMethodSeen;
3126 else if (numGenericMethodArgs != 0)
3128 //We use an instantiated method desc to represent a generic method
3129 type = METHOD_TYPE_INSTANTIATED;
3131 else if (fIsClassInterface)
3133 #ifdef FEATURE_COMINTEROP
3134 if (IsMdStatic(dwMemberAttrs))
3136 // Static methods in interfaces need nothing special.
3137 type = METHOD_TYPE_NORMAL;
3139 else if (bmtGenerics->GetNumGenericArgs() != 0 &&
3140 (bmtGenerics->fSharedByGenericInstantiations || (!bmtProp->fIsRedirectedInterface && !GetHalfBakedClass()->IsProjectedFromWinRT())))
3142 // Methods in instantiated interfaces need nothing special - they are not visible from COM etc.
3143 // mcComInterop is only useful for unshared instantiated WinRT interfaces. If the interface is
3144 // shared by multiple instantiations, the MD would be useless for interop anyway.
3145 type = METHOD_TYPE_NORMAL;
3147 else if (bmtProp->fIsMngStandardItf)
3149 // If the interface is a standard managed interface then allocate space for an FCall method desc.
3150 type = METHOD_TYPE_FCALL;
3152 else if (IsMdAbstract(dwMemberAttrs))
3154 // If COM interop is supported then all other interface MDs may be
3155 // accessed via COM interop. mcComInterop MDs have an additional
3156 // pointer-sized field pointing to COM interop data which are
3157 // allocated lazily when/if the MD actually gets used for interop.
3158 type = METHOD_TYPE_COMINTEROP;
3161 #endif // !FEATURE_COMINTEROP
3163 // This codepath is used by remoting
3164 type = METHOD_TYPE_NORMAL;
3169 type = METHOD_TYPE_NORMAL;
3172 // Generic methods should always be METHOD_TYPE_INSTANTIATED
3173 if ((numGenericMethodArgs != 0) && (type != METHOD_TYPE_INSTANTIATED))
3175 BuildMethodTableThrowException(BFA_GENERIC_METHODS_INST);
3178 // count how many overrides this method does All methods bodies are defined
3179 // on this type so we can just compare the tok with the body token found
3180 // from the overrides.
3181 implType = METHOD_IMPL_NOT;
3182 for (DWORD impls = 0; impls < bmtMethod->dwNumberMethodImpls; impls++)
3184 if (bmtMetaData->rgMethodImplTokens[impls].methodBody == tok)
3186 implType = METHOD_IMPL;
3191 // For delegates we don't allow any non-runtime implemented bodies
3192 // for any of the four special methods
3193 if (IsDelegate() && !IsMiRuntime(dwImplFlags))
3195 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
3196 (strcmp(strMethodName, "Invoke") == 0) ||
3197 (strcmp(strMethodName, "BeginInvoke") == 0) ||
3198 (strcmp(strMethodName, "EndInvoke") == 0) )
3200 BuildMethodTableThrowException(BFA_ILLEGAL_DELEGATE_METHOD);
3205 // Create a new bmtMDMethod representing this method and add it to the
3206 // declared method list.
3209 bmtMDMethod * pNewMethod = new (GetStackingAllocator()) bmtMDMethod(
3218 bmtMethod->AddDeclaredMethod(pNewMethod);
3221 // Update the count of the various types of methods.
3224 bmtVT->dwMaxVtableSize++;
3226 // Increment the number of non-abstract declared methods
3227 if (!IsMdAbstract(dwMemberAttrs))
3229 bmtMethod->dwNumDeclaredNonAbstractMethods++;
3233 // Check to see that we have all of the required delegate methods (ECMA 13.6 Delegates)
3236 // Do we have all four special delegate methods
3237 // or just the two special delegate methods
3238 if ((delegateMethodsSeen != (SeenCtor | SeenInvoke | SeenBeginInvoke | SeenEndInvoke)) &&
3239 (delegateMethodsSeen != (SeenCtor | SeenInvoke)) )
3241 BuildMethodTableThrowException(BFA_MISSING_DELEGATE_METHOD);
3245 if (i != cMethAndGaps)
3247 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_METHOD_COUNT, mdTokenNil);
3250 #ifdef FEATURE_COMINTEROP
3252 // If the interface is sparse, we need to finalize the mapping list by
3253 // telling it how many real methods we found.
3256 if (bmtProp->fSparse)
3258 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->FinalizeMapping(NumDeclaredMethods());
3260 #endif // FEATURE_COMINTEROP
3261 } // MethodTableBuilder::EnumerateClassMethods
3263 #pragma warning(pop)
3266 //*******************************************************************************
3268 // Run through the field list and calculate the following:
3270 // # static fields that contain object refs.
3271 // # instance fields
3274 MethodTableBuilder::EnumerateClassFields()
3276 STANDARD_VM_CONTRACT;
3280 IMDInternalImport *pMDInternalImport = GetMDImport();
3282 DWORD dwMemberAttrs;
3284 bmtEnumFields->dwNumStaticFields = 0;
3285 bmtEnumFields->dwNumStaticObjRefFields = 0;
3286 bmtEnumFields->dwNumStaticBoxedFields = 0;
3288 bmtEnumFields->dwNumThreadStaticFields = 0;
3289 bmtEnumFields->dwNumThreadStaticObjRefFields = 0;
3290 bmtEnumFields->dwNumThreadStaticBoxedFields = 0;
3292 bmtEnumFields->dwNumInstanceFields = 0;
3294 HENUMInternalHolder hEnumField(pMDInternalImport);
3295 hr = hEnumField.EnumInitNoThrow(mdtFieldDef, GetCl());
3298 BuildMethodTableThrowException(hr, *bmtError);
3301 bmtMetaData->cFields = hEnumField.EnumGetCount();
3303 // Retrieve the fields and store them in a temp array.
3304 bmtMetaData->pFields = new (GetStackingAllocator()) mdToken[bmtMetaData->cFields];
3305 bmtMetaData->pFieldAttrs = new (GetStackingAllocator()) DWORD[bmtMetaData->cFields];
3307 DWORD dwFieldLiteralInitOnly = fdLiteral | fdInitOnly;
3308 DWORD dwMaxFieldDefRid = pMDInternalImport->GetCountWithTokenKind(mdtFieldDef);
3310 for (i = 0; hEnumField.EnumNext(&tok); i++)
3313 // Retrieve the attributes of the field.
3315 DWORD rid = RidFromToken(tok);
3316 if ((rid == 0)||(rid > dwMaxFieldDefRid))
3318 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, mdTokenNil);
3321 if (FAILED(pMDInternalImport->GetFieldDefProps(tok, &dwMemberAttrs)))
3323 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, tok);
3327 // Store the field and its attributes in the bmtMetaData structure for later use.
3330 bmtMetaData->pFields[i] = tok;
3331 bmtMetaData->pFieldAttrs[i] = dwMemberAttrs;
3333 if((dwMemberAttrs & fdFieldAccessMask)==fdFieldAccessMask)
3335 BuildMethodTableThrowException(BFA_INVALID_FIELD_ACC_FLAGS);
3337 if((dwMemberAttrs & dwFieldLiteralInitOnly)==dwFieldLiteralInitOnly)
3339 BuildMethodTableThrowException(BFA_FIELD_LITERAL_AND_INIT);
3342 // can only have static global fields
3345 if(!IsFdStatic(dwMemberAttrs))
3347 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_FIELD);
3352 // Update the count of the various types of fields.
3355 if (IsFdStatic(dwMemberAttrs))
3357 if (!IsFdLiteral(dwMemberAttrs))
3359 #ifdef FEATURE_TYPEEQUIVALENCE
3360 if (bmtProp->fIsTypeEquivalent)
3362 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3366 bmtEnumFields->dwNumStaticFields++;
3368 // If this static field is thread static, then we need
3369 // to increment bmtEnumFields->dwNumThreadStaticFields
3370 hr = pMDInternalImport->GetCustomAttributeByName(tok,
3371 g_ThreadStaticAttributeClassName,
3376 // It's a thread static, so increment the count
3377 bmtEnumFields->dwNumThreadStaticFields++;
3383 #ifdef FEATURE_TYPEEQUIVALENCE
3384 if (!IsFdPublic(dwMemberAttrs) && bmtProp->fIsTypeEquivalent)
3386 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3390 if (!IsFdLiteral(dwMemberAttrs))
3392 bmtEnumFields->dwNumInstanceFields++;
3396 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_INT);
3401 if (i != bmtMetaData->cFields)
3403 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD_COUNT, mdTokenNil);
3406 if(IsEnum() && (bmtEnumFields->dwNumInstanceFields==0))
3408 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_ENUM);
3411 bmtEnumFields->dwNumDeclaredFields = bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields;
3414 //*******************************************************************************
3416 // Used by BuildMethodTable
3418 // Determines the maximum size of the vtable and allocates the temporary storage arrays
3419 // Also copies the parent's vtable into the working vtable.
3421 VOID MethodTableBuilder::AllocateWorkingSlotTables()
3426 PRECONDITION(CheckPointer(this));
3427 PRECONDITION(CheckPointer(bmtAllocator));
3428 PRECONDITION(CheckPointer(bmtMFDescs));
3429 PRECONDITION(CheckPointer(bmtMetaData));
3430 PRECONDITION(CheckPointer(bmtVT));
3431 PRECONDITION(CheckPointer(bmtEnumFields));
3432 PRECONDITION(CheckPointer(bmtInterface));
3433 PRECONDITION(CheckPointer(bmtFP));
3434 PRECONDITION(CheckPointer(bmtParent));
3439 // Allocate a FieldDesc* for each field
3440 bmtMFDescs->ppFieldDescList = new (GetStackingAllocator()) FieldDesc*[bmtMetaData->cFields];
3441 ZeroMemory(bmtMFDescs->ppFieldDescList, bmtMetaData->cFields * sizeof(FieldDesc *));
3443 // Create a temporary function table (we don't know how large the vtable will be until the very end,
3444 // since we don't yet know how many declared methods are overrides vs. newslots).
3447 { // ValueClass virtuals are converted into non-virtual methods and the virtual slots
3448 // become unboxing stubs that forward to these new non-virtual methods. This has the
3449 // side effect of doubling the number of slots introduced by newslot virtuals.
3450 bmtVT->dwMaxVtableSize += NumDeclaredMethods();
3453 _ASSERTE(!HasParent() || (bmtInterface->dwInterfaceMapSize - GetParentMethodTable()->GetNumInterfaces()) >= 0);
3456 { // Add parent vtable size. <TODO> This should actually be the parent's virtual method count. </TODO>
3457 bmtVT->dwMaxVtableSize += bmtParent->pSlotTable->GetSlotCount();
3460 S_SLOT_INDEX cMaxSlots = AsClrSafeInt(bmtVT->dwMaxVtableSize) + AsClrSafeInt(NumDeclaredMethods());
3462 if (cMaxSlots.IsOverflow() || MAX_SLOT_INDEX < cMaxSlots.Value())
3463 cMaxSlots = S_SLOT_INDEX(MAX_SLOT_INDEX);
3465 // Allocate the temporary vtable
3466 bmtVT->pSlotTable = new (GetStackingAllocator())
3467 bmtMethodSlotTable(cMaxSlots.Value(), GetStackingAllocator());
3472 // @<TODO>todo: Figure out the right way to override Equals for value
3475 // This is broken because
3476 // (a) g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool); will return
3477 // the EqualsValue method
3478 // (b) When mscorlib has been preloaded (and thus the munge already done
3479 // ahead of time), we cannot easily find both methods
3480 // to compute EqualsAddr & EqualsSlot
3482 // For now, the Equals method has a runtime check to see if it's
3483 // comparing value types.
3486 // If it is a value type, over ride a few of the base class methods.
3489 static WORD EqualsSlot;
3491 // If we haven't been through here yet, get some stuff from the Object class definition.
3492 if (EqualsSlot == NULL)
3494 // Get the slot of the Equals method.
3495 MethodDesc *pEqualsMD = g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool);
3496 THROW_BAD_FORMAT_MAYBE(pEqualsMD != NULL, 0, this);
3497 EqualsSlot = pEqualsMD->GetSlot();
3499 // Get the address of the EqualsValue method.
3500 MethodDesc *pEqualsValueMD = g_pObjectClass->FindMethod("EqualsValue", &gsig_IM_Obj_RetBool);
3501 THROW_BAD_FORMAT_MAYBE(pEqualsValueMD != NULL, 0, this);
3503 // Patch the EqualsValue method desc in a dangerous way to
3504 // look like the Equals method desc.
3505 pEqualsValueMD->SetSlot(EqualsSlot);
3506 pEqualsValueMD->SetMemberDef(pEqualsMD->GetMemberDef());
3509 // Override the valuetype "Equals" with "EqualsValue".
3510 bmtVT->SetMethodDescForSlot(EqualsSlot, EqualsSlot);
3515 S_UINT32 cEntries = S_UINT32(2) * S_UINT32(NumDeclaredMethods());
3516 if (cEntries.IsOverflow())
3518 ThrowHR(COR_E_OVERFLOW);
3522 //*******************************************************************************
3524 // Used by BuildMethodTable
3526 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
3528 VOID MethodTableBuilder::AllocateFieldDescs()
3533 PRECONDITION(CheckPointer(this));
3534 PRECONDITION(CheckPointer(bmtAllocator));
3535 PRECONDITION(CheckPointer(bmtMFDescs));
3536 PRECONDITION(CheckPointer(bmtMetaData));
3537 PRECONDITION(CheckPointer(bmtVT));
3538 PRECONDITION(CheckPointer(bmtEnumFields));
3539 PRECONDITION(CheckPointer(bmtFP));
3540 PRECONDITION(CheckPointer(bmtParent));
3545 // We'll be counting the # fields of each size as we go along
3546 for (DWORD i = 0; i <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++)
3548 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
3549 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
3550 bmtFP->NumInstanceFieldsOfSize[i] = 0;
3554 // Allocate blocks of MethodDescs and FieldDescs for all declared methods and fields
3556 // In order to avoid allocating a field pointing back to the method
3557 // table in every single method desc, we allocate memory in the
3558 // following manner:
3559 // o Field descs get a single contiguous block.
3560 // o Method descs of different sizes (normal vs NDirect) are
3561 // allocated in different MethodDescChunks.
3562 // o Each method desc chunk starts with a header, and has
3563 // at most MAX_ method descs (if there are more
3564 // method descs of a given size, multiple chunks are allocated).
3565 // This way method descs can use an 8-bit offset field to locate the
3566 // pointer to their method table.
3569 /////////////////////////////////////////////////////////////////
3571 if (NumDeclaredFields() > 0)
3573 GetHalfBakedClass()->SetFieldDescList((FieldDesc *)
3574 AllocateFromHighFrequencyHeap(S_SIZE_T(NumDeclaredFields()) * S_SIZE_T(sizeof(FieldDesc))));
3575 INDEBUG(GetClassLoader()->m_dwDebugFieldDescs += NumDeclaredFields();)
3576 INDEBUG(GetClassLoader()->m_dwFieldDescData += (NumDeclaredFields() * sizeof(FieldDesc));)
3580 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
3581 //*******************************************************************************
3583 // Heuristic to determine if we should have instances of this class 8 byte aligned
3585 BOOL MethodTableBuilder::ShouldAlign8(DWORD dwR8Fields, DWORD dwTotalFields)
3587 LIMITED_METHOD_CONTRACT;
3589 return dwR8Fields*2>dwTotalFields && dwR8Fields>=2;
3593 //*******************************************************************************
3594 BOOL MethodTableBuilder::IsSelfReferencingStaticValueTypeField(mdToken dwByValueClassToken,
3595 bmtInternalInfo* bmtInternal,
3596 const bmtGenericsInfo *bmtGenerics,
3597 PCCOR_SIGNATURE pMemberSignature,
3598 DWORD cMemberSignature)
3600 STANDARD_VM_CONTRACT;
3602 if (dwByValueClassToken != this->GetCl())
3607 if (!bmtGenerics->HasInstantiation())
3612 // The value class is generic. Check that the signature of the field
3613 // is _exactly_ equivalent to VC<!0, !1, !2, ...>. Do this by consing up a fake
3615 DWORD nGenericArgs = bmtGenerics->GetNumGenericArgs();
3616 CONSISTENCY_CHECK(nGenericArgs != 0);
3618 SigBuilder sigBuilder;
3620 sigBuilder.AppendElementType(ELEMENT_TYPE_GENERICINST);
3621 sigBuilder.AppendElementType(ELEMENT_TYPE_VALUETYPE);
3622 sigBuilder.AppendToken(dwByValueClassToken);
3623 sigBuilder.AppendData(nGenericArgs);
3624 for (unsigned int typearg = 0; typearg < nGenericArgs; typearg++)
3626 sigBuilder.AppendElementType(ELEMENT_TYPE_VAR);
3627 sigBuilder.AppendData(typearg);
3631 PCCOR_SIGNATURE pFakeSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cFakeSig);
3633 PCCOR_SIGNATURE pFieldSig = pMemberSignature + 1; // skip the CALLCONV_FIELD
3635 return MetaSig::CompareElementType(pFakeSig, pFieldSig,
3636 pFakeSig + cFakeSig, pMemberSignature + cMemberSignature,
3637 GetModule(), GetModule(),
3642 //*******************************************************************************
3644 // Used pByValueClass cache to mark self-references
3646 static BOOL IsSelfRef(MethodTable * pMT)
3648 return pMT == (MethodTable *)-1;
3651 //*******************************************************************************
3653 // Used by BuildMethodTable
3655 // Go thru all fields and initialize their FieldDescs.
3658 #pragma warning(push)
3659 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3662 VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
3663 const LayoutRawFieldInfo* pLayoutRawFieldInfos,
3664 bmtInternalInfo* bmtInternal,
3665 const bmtGenericsInfo* bmtGenerics,
3666 bmtMetaDataInfo* bmtMetaData,
3667 bmtEnumFieldInfo* bmtEnumFields,
3668 bmtErrorInfo* bmtError,
3669 MethodTable *** pByValueClassCache,
3670 bmtMethAndFieldDescs* bmtMFDescs,
3671 bmtFieldPlacement* bmtFP,
3672 unsigned* totalDeclaredSize)
3677 PRECONDITION(CheckPointer(this));
3678 PRECONDITION(CheckPointer(bmtInternal));
3679 PRECONDITION(CheckPointer(bmtGenerics));
3680 PRECONDITION(CheckPointer(bmtMetaData));
3681 PRECONDITION(CheckPointer(bmtEnumFields));
3682 PRECONDITION(CheckPointer(bmtError));
3683 PRECONDITION(CheckPointer(pByValueClassCache));
3684 PRECONDITION(CheckPointer(bmtMFDescs));
3685 PRECONDITION(CheckPointer(bmtFP));
3686 PRECONDITION(CheckPointer(totalDeclaredSize));
3691 IMDInternalImport * pInternalImport = GetMDImport(); // to avoid multiple dereferencings
3693 FieldMarshaler * pNextFieldMarshaler = NULL;
3696 pNextFieldMarshaler = (FieldMarshaler*)(GetLayoutInfo()->GetFieldMarshalers());
3700 //========================================================================
3702 // Go thru all fields and initialize their FieldDescs.
3703 //========================================================================
3705 DWORD dwCurrentDeclaredField = 0;
3706 DWORD dwCurrentStaticField = 0;
3707 DWORD dwCurrentThreadStaticField = 0;
3710 DWORD dwR8Fields = 0; // Number of R8's the class has
3712 #ifdef FEATURE_64BIT_ALIGNMENT
3713 // Track whether any field in this type requires 8-byte alignment
3714 BOOL fFieldRequiresAlign8 = HasParent() ? GetParentMethodTable()->RequiresAlign8() : FALSE;
3717 for (i = 0; i < bmtMetaData->cFields; i++)
3719 PCCOR_SIGNATURE pMemberSignature;
3720 DWORD cMemberSignature;
3721 DWORD dwMemberAttrs;
3723 dwMemberAttrs = bmtMetaData->pFieldAttrs[i];
3725 BOOL fIsStatic = IsFdStatic(dwMemberAttrs);
3727 // We don't store static final primitive fields in the class layout
3728 if (IsFdLiteral(dwMemberAttrs))
3731 if (!IsFdPublic(dwMemberAttrs))
3732 SetHasNonPublicFields();
3734 if (IsFdNotSerialized(dwMemberAttrs))
3735 SetCannotBeBlittedByObjectCloner();
3737 IfFailThrow(pInternalImport->GetSigOfFieldDef(bmtMetaData->pFields[i], &cMemberSignature, &pMemberSignature));
3738 // Signature validation
3739 IfFailThrow(validateTokenSig(bmtMetaData->pFields[i],pMemberSignature,cMemberSignature,dwMemberAttrs,pInternalImport));
3742 DWORD dwLog2FieldSize = 0;
3743 BOOL bCurrentFieldIsGCPointer = FALSE;
3744 mdToken dwByValueClassToken = 0;
3745 MethodTable * pByValueClass = NULL;
3746 BOOL fIsByValue = FALSE;
3747 BOOL fIsThreadStatic = FALSE;
3748 BOOL fHasRVA = FALSE;
3750 MetaSig fsig(pMemberSignature,
3753 &bmtGenerics->typeContext,
3755 CorElementType ElementType = fsig.NextArg();
3759 if (!isCallConv(fsig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_FIELD))
3761 IfFailThrow(COR_E_TYPELOAD);
3764 // Determine if a static field is special i.e. RVA based, local to
3765 // a thread or a context
3768 if (IsFdHasFieldRVA(dwMemberAttrs))
3775 hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
3776 g_ThreadStaticAttributeClassName,
3781 fIsThreadStatic = TRUE;
3785 if (ElementType == ELEMENT_TYPE_VALUETYPE)
3787 hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
3788 g_CompilerServicesFixedAddressValueTypeAttribute,
3793 bmtFP->fHasFixedAddressValueTypes = true;
3798 // Do some sanity checks that we are not mixing context and thread
3799 // relative statics.
3800 if (fHasRVA && fIsThreadStatic)
3802 IfFailThrow(COR_E_TYPELOAD);
3805 if (bmtFP->fHasFixedAddressValueTypes && GetAssembly()->IsCollectible())
3807 BuildMethodTableThrowException(IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR);
3813 // Type to store in FieldDesc - we don't want to have extra case statements for
3814 // ELEMENT_TYPE_STRING, SDARRAY etc., so we convert all object types to CLASS.
3815 // Also, BOOLEAN, CHAR are converted to U1, I2.
3816 CorElementType FieldDescElementType = ElementType;
3818 switch (ElementType)
3820 case ELEMENT_TYPE_I1:
3821 case ELEMENT_TYPE_U1:
3823 dwLog2FieldSize = 0;
3827 case ELEMENT_TYPE_I2:
3828 case ELEMENT_TYPE_U2:
3830 dwLog2FieldSize = 1;
3834 case ELEMENT_TYPE_I4:
3835 case ELEMENT_TYPE_U4:
3836 IN_TARGET_32BIT(case ELEMENT_TYPE_I:)
3837 IN_TARGET_32BIT(case ELEMENT_TYPE_U:)
3838 case ELEMENT_TYPE_R4:
3840 dwLog2FieldSize = 2;
3844 case ELEMENT_TYPE_BOOLEAN:
3846 // FieldDescElementType = ELEMENT_TYPE_U1;
3847 dwLog2FieldSize = 0;
3851 case ELEMENT_TYPE_CHAR:
3853 // FieldDescElementType = ELEMENT_TYPE_U2;
3854 dwLog2FieldSize = 1;
3858 case ELEMENT_TYPE_R8:
3862 // Deliberate fall through...
3865 case ELEMENT_TYPE_I8:
3866 case ELEMENT_TYPE_U8:
3867 IN_TARGET_64BIT(case ELEMENT_TYPE_I:)
3868 IN_TARGET_64BIT(case ELEMENT_TYPE_U:)
3870 #ifdef FEATURE_64BIT_ALIGNMENT
3871 // Record that this field requires alignment for Int64/UInt64.
3873 fFieldRequiresAlign8 = true;
3875 dwLog2FieldSize = 3;
3879 case ELEMENT_TYPE_FNPTR:
3880 case ELEMENT_TYPE_PTR: // ptrs are unmanaged scalars, for layout
3882 dwLog2FieldSize = LOG2_PTRSIZE;
3886 // Class type variable (method type variables aren't allowed in fields)
3887 // These only occur in open types used for verification/reflection.
3888 case ELEMENT_TYPE_VAR:
3889 case ELEMENT_TYPE_MVAR:
3890 // deliberate drop through - do fake field layout
3891 case ELEMENT_TYPE_STRING:
3892 case ELEMENT_TYPE_SZARRAY: // single dim, zero
3893 case ELEMENT_TYPE_ARRAY: // all other arrays
3894 case ELEMENT_TYPE_CLASS: // objectrefs
3895 case ELEMENT_TYPE_OBJECT:
3897 dwLog2FieldSize = LOG2_PTRSIZE;
3898 bCurrentFieldIsGCPointer = TRUE;
3899 FieldDescElementType = ELEMENT_TYPE_CLASS;
3903 SetHasFieldsWhichMustBeInited();
3904 if (ElementType != ELEMENT_TYPE_STRING)
3905 SetCannotBeBlittedByObjectCloner();
3908 { // EnumerateFieldDescs already counted the total number of static vs. instance
3909 // fields, now we're further subdividing the static field count by GC and non-GC.
3910 bmtEnumFields->dwNumStaticObjRefFields++;
3911 if (fIsThreadStatic)
3912 bmtEnumFields->dwNumThreadStaticObjRefFields++;
3917 case ELEMENT_TYPE_VALUETYPE: // a byvalue class field
3919 Module * pTokenModule;
3920 dwByValueClassToken = fsig.GetArgProps().PeekValueTypeTokenClosed(GetModule(), &bmtGenerics->typeContext, &pTokenModule);
3924 BAD_FORMAT_NOTHROW_ASSERT(dwByValueClassToken != 0);
3926 if (this->IsValueClass() && (pTokenModule == GetModule()))
3928 if (TypeFromToken(dwByValueClassToken) == mdtTypeRef)
3930 // It's a typeref - check if it's a class that has a static field of itself
3931 LPCUTF8 pszNameSpace;
3932 LPCUTF8 pszClassName;
3933 if (FAILED(pInternalImport->GetNameOfTypeRef(dwByValueClassToken, &pszNameSpace, &pszClassName)))
3935 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
3938 if (IsStrLongerThan((char *)pszClassName, MAX_CLASS_NAME)
3939 || IsStrLongerThan((char *)pszNameSpace, MAX_CLASS_NAME)
3940 || (strlen(pszClassName) + strlen(pszNameSpace) + 1 >= MAX_CLASS_NAME))
3942 BuildMethodTableThrowException(BFA_TYPEREG_NAME_TOO_LONG, mdMethodDefNil);
3946 if (FAILED(pInternalImport->GetResolutionScopeOfTypeRef(dwByValueClassToken, &tkRes)))
3948 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, dwByValueClassToken);
3951 if (TypeFromToken(tkRes) == mdtTypeRef)
3953 if (!pInternalImport->IsValidToken(tkRes))
3955 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, mdMethodDefNil);
3963 if (FAILED(pInternalImport->FindTypeDef(pszNameSpace,
3966 &dwByValueClassToken)))
3968 dwByValueClassToken = mdTokenNil;
3970 } // If field is static typeref
3972 BOOL selfref = IsSelfReferencingStaticValueTypeField(dwByValueClassToken,
3979 { // immediately self-referential fields must be static.
3982 BuildMethodTableThrowException(IDS_CLASSLOAD_VALUEINSTANCEFIELD, mdMethodDefNil);
3985 if (!IsValueClass())
3987 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_MUST_BE_BYVAL, mdTokenNil);
3990 pByValueClass = (MethodTable *)-1;
3992 } // If 'this' is a value class
3994 // It's not self-referential so try to load it
3995 if (pByValueClass == NULL)
3997 // Loading a non-self-ref valuetype field.
3998 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
3999 // We load the approximate type of the field to avoid recursion problems.
4000 // MethodTable::DoFullyLoad() will later load it fully
4001 pByValueClass = fsig.GetArgProps().GetTypeHandleThrowing(GetModule(),
4002 &bmtGenerics->typeContext,
4003 ClassLoader::LoadTypes,
4004 CLASS_LOAD_APPROXPARENTS,
4009 // #FieldDescTypeMorph IF it is an enum, strip it down to its underlying type
4010 if (IsSelfRef(pByValueClass) ? IsEnum() : pByValueClass->IsEnum())
4012 if (IsSelfRef(pByValueClass))
4013 { // It is self-referencing enum (ValueType) static field - it is forbidden in the ECMA spec, but supported by CLR since v1
4014 // Note: literal static fields are skipped early in this loop
4015 if (bmtMFDescs->ppFieldDescList[0] == NULL)
4016 { // The field is defined before (the only) instance field
4017 // AppCompat with 3.5 SP1 and 4.0 RTM behavior
4018 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4020 // 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
4021 // later in this method)
4022 // Therefore we do not have to run code:VerifySelfReferencingStaticValueTypeFields_WithRVA or code:#SelfReferencingStaticValueTypeField_Checks
4024 BAD_FORMAT_NOTHROW_ASSERT((IsSelfRef(pByValueClass) ?
4025 bmtEnumFields->dwNumInstanceFields : pByValueClass->GetNumInstanceFields())
4026 == 1); // enums must have exactly one field
4027 FieldDesc * enumField = IsSelfRef(pByValueClass) ?
4028 bmtMFDescs->ppFieldDescList[0] : pByValueClass->GetApproxFieldDescListRaw();
4029 BAD_FORMAT_NOTHROW_ASSERT(!enumField->IsStatic()); // no real static fields on enums
4030 ElementType = enumField->GetFieldType();
4031 BAD_FORMAT_NOTHROW_ASSERT(ElementType != ELEMENT_TYPE_VALUETYPE);
4032 fIsByValue = FALSE; // we're going to treat it as the underlying type now
4033 goto GOT_ELEMENT_TYPE;
4036 // Check ByRefLike fields
4037 if (!IsSelfRef(pByValueClass) && pByValueClass->IsByRefLike())
4041 // Byref-like types cannot be used for static fields
4042 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_STATICFIELD);
4044 if (!bmtFP->fIsByRefLikeType)
4046 // Non-byref-like types cannot contain byref-like instance fields
4047 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_INSTANCEFIELD);
4051 if (!IsSelfRef(pByValueClass) && pByValueClass->GetClass()->HasNonPublicFields())
4052 { // If a class has a field of type ValueType with non-public fields in it,
4053 // the class must "inherit" this characteristic
4054 SetHasNonPublicFields();
4061 // Inherit instance attributes
4062 EEClass * pFieldClass = pByValueClass->GetClass();
4064 #ifdef FEATURE_64BIT_ALIGNMENT
4065 // If a value type requires 8-byte alignment this requirement must be inherited by any
4066 // class/struct that embeds it as a field.
4067 if (pFieldClass->IsAlign8Candidate())
4068 fFieldRequiresAlign8 = true;
4070 if (pFieldClass->HasNonPublicFields())
4071 SetHasNonPublicFields();
4072 if (pFieldClass->HasFieldsWhichMustBeInited())
4073 SetHasFieldsWhichMustBeInited();
4075 #ifdef FEATURE_READYTORUN
4076 if (!(pByValueClass->IsTruePrimitive() || pByValueClass->IsEnum()))
4078 CheckLayoutDependsOnOtherModules(pByValueClass);
4083 { // Increment the number of static fields that contain object references.
4084 bmtEnumFields->dwNumStaticBoxedFields++;
4085 if (fIsThreadStatic)
4086 bmtEnumFields->dwNumThreadStaticBoxedFields++;
4090 if (*pByValueClassCache == NULL)
4092 DWORD dwNumFields = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields;
4094 *pByValueClassCache = new (GetStackingAllocator()) MethodTable * [dwNumFields];
4095 memset (*pByValueClassCache, 0, dwNumFields * sizeof(MethodTable **));
4098 // Thread static fields come after instance fields and regular static fields in this list
4099 if (fIsThreadStatic)
4101 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField] = pByValueClass;
4102 // make sure to record the correct size for static field
4104 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4106 // Regular static fields come after instance fields in this list
4109 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField] = pByValueClass;
4110 // make sure to record the correct size for static field
4112 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4116 (*pByValueClassCache)[dwCurrentDeclaredField] = pByValueClass;
4117 dwLog2FieldSize = 0; // unused
4124 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4130 pFD = &pFieldDescList[dwCurrentDeclaredField];
4131 *totalDeclaredSize += (1 << dwLog2FieldSize);
4133 else /* (dwMemberAttrs & mdStatic) */
4135 if (fIsThreadStatic)
4137 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField];
4141 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField];
4145 bmtMFDescs->ppFieldDescList[i] = pFD;
4147 const LayoutRawFieldInfo *pLayoutFieldInfo = NULL;
4151 const LayoutRawFieldInfo *pwalk = pLayoutRawFieldInfos;
4152 while (pwalk->m_MD != mdFieldDefNil)
4154 if (pwalk->m_MD == bmtMetaData->pFields[i])
4156 pLayoutFieldInfo = pwalk;
4158 const FieldMarshaler *pSrcFieldMarshaler = (const FieldMarshaler *) &pwalk->m_FieldMarshaler;
4160 pSrcFieldMarshaler->CopyTo(pNextFieldMarshaler, MAXFIELDMARSHALERSIZE);
4162 pNextFieldMarshaler->SetFieldDesc(pFD);
4163 pNextFieldMarshaler->SetExternalOffset(pwalk->m_offset);
4165 ((BYTE*&)pNextFieldMarshaler) += MAXFIELDMARSHALERSIZE;
4172 LPCSTR pszFieldName = NULL;
4174 if (FAILED(pInternalImport->GetNameOfFieldDef(bmtMetaData->pFields[i], &pszFieldName)))
4176 pszFieldName = "Invalid FieldDef record";
4179 // #InitCall Initialize contents of the field descriptor called from
4181 bmtMetaData->pFields[i],
4182 FieldDescElementType,
4190 // We're using FieldDesc::m_pMTOfEnclosingClass to temporarily store the field's size.
4195 (IsBlittable() || HasExplicitFieldOffsetLayout()))
4197 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4198 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4200 if (pLayoutFieldInfo)
4201 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
4203 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4205 else if (!fIsStatic && IsManagedSequential())
4207 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4208 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4210 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
4214 // static value class fields hold a handle, which is ptr sized
4215 // (instance field layout ignores this value)
4216 (DWORD_PTR&)(pFD->m_pMTOfEnclosingClass) = LOG2_PTRSIZE;
4217 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4222 (DWORD_PTR &)(pFD->m_pMTOfEnclosingClass) = (size_t)dwLog2FieldSize;
4224 // -1 (FIELD_OFFSET_UNPLACED) means that this is a non-GC field that has not yet been placed
4225 // -2 (FIELD_OFFSET_UNPLACED_GC_PTR) means that this is a GC pointer field that has not yet been placed
4227 // If there is any kind of explicit layout information for this field, use it. If not, then
4228 // mark it as either GC or non-GC and as unplaced; it will get placed later on in an optimized way.
4230 if ((IsBlittable() || HasExplicitFieldOffsetLayout()) && !fIsStatic)
4231 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
4232 else if (IsManagedSequential() && !fIsStatic)
4233 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
4234 else if (bCurrentFieldIsGCPointer)
4235 pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR);
4237 pFD->SetOffset(FIELD_OFFSET_UNPLACED);
4244 if (++bmtFP->NumInstanceFieldsOfSize[dwLog2FieldSize] == 1)
4245 bmtFP->FirstInstanceFieldOfSize[dwLog2FieldSize] = dwCurrentDeclaredField;
4248 dwCurrentDeclaredField++;
4250 if (bCurrentFieldIsGCPointer)
4252 bmtFP->NumInstanceGCPointerFields++;
4255 else /* static fields */
4257 // Static fields are stored in the vtable after the vtable and interface slots. We don't
4258 // know how large the vtable will be, so we will have to fixup the slot number by
4259 // <vtable + interface size> later.
4261 if (fIsThreadStatic)
4263 dwCurrentThreadStaticField++;
4267 dwCurrentStaticField++;
4272 if (FieldDescElementType == ELEMENT_TYPE_CLASS)
4273 { // RVA fields are not allowed to have GC pointers.
4274 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4275 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4277 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4279 if (IsSelfRef(pByValueClass))
4280 { // We will verify self-referencing statics after the loop through all fields - see code:#SelfReferencingStaticValueTypeField_Checks
4281 bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA = TRUE;
4285 if (pByValueClass->GetClass()->HasFieldsWhichMustBeInited())
4286 { // RVA fields are not allowed to have GC pointers.
4287 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4288 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4293 // Set the field offset
4295 IfFailThrow(pInternalImport->GetFieldRVA(pFD->GetMemberDef(), &rva));
4297 // Ensure that the IL image is loaded. Note that this assembly may
4298 // have an ngen image, but this type may have failed to load during ngen.
4299 GetModule()->GetFile()->LoadLibrary(FALSE);
4302 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4304 if (IsSelfRef(pByValueClass))
4306 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4308 // We do not known the size yet
4309 _ASSERTE(bmtFP->NumInstanceFieldBytes == 0);
4310 // We will check just the RVA with size 0 now, the full size verification will happen in code:VerifySelfReferencingStaticValueTypeFields_WithRVA
4315 fldSize = pByValueClass->GetNumInstanceFieldBytes();
4320 fldSize = GetSizeForCorElementType(FieldDescElementType);
4323 pFD->SetOffsetRVA(rva);
4325 else if (fIsThreadStatic)
4327 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
4329 if (bCurrentFieldIsGCPointer)
4330 bmtFP->NumThreadStaticGCPointerFields++;
4333 bmtFP->NumThreadStaticGCBoxedFields++;
4337 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
4339 if (bCurrentFieldIsGCPointer)
4340 bmtFP->NumRegularStaticGCPointerFields++;
4343 bmtFP->NumRegularStaticGCBoxedFields++;
4347 // We processed all fields
4349 //#SelfReferencingStaticValueTypeField_Checks
4350 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
4351 { // The type has self-referencing static ValueType field with RVA, do more checks now that depend on all fields being processed
4353 // For enums we already checked its underlying type, we should not get here
4354 _ASSERTE(!IsEnum());
4356 if (HasFieldsWhichMustBeInited())
4357 { // RVA fields are not allowed to have GC pointers.
4358 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA self-referencing static field");
4359 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4363 DWORD dwNumInstanceFields = dwCurrentDeclaredField + (HasParent() ? GetParentMethodTable()->GetNumInstanceFields() : 0);
4364 DWORD dwNumStaticFields = bmtEnumFields->dwNumStaticFields;
4365 DWORD dwNumThreadStaticFields = bmtEnumFields->dwNumThreadStaticFields;
4367 if (!FitsIn<WORD>(dwNumInstanceFields) ||
4368 !FitsIn<WORD>(dwNumStaticFields))
4369 { // An implementation limitation means that it's an error if there are greater that MAX_WORD fields.
4370 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
4373 GetHalfBakedClass()->SetNumInstanceFields((WORD)dwNumInstanceFields);
4374 GetHalfBakedClass()->SetNumStaticFields((WORD)dwNumStaticFields);
4375 GetHalfBakedClass()->SetNumThreadStaticFields((WORD)dwNumThreadStaticFields);
4377 if (bmtFP->fHasFixedAddressValueTypes)
4379 // To make things simpler, if the class has any field with this requirement, we'll set
4380 // all the statics to have this property. This allows us to only need to persist one bit
4381 // for the ngen case.
4382 GetHalfBakedClass()->SetHasFixedAddressVTStatics();
4385 #ifdef FEATURE_64BIT_ALIGNMENT
4386 // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8
4387 // bytes (this mimics what the native compiler does and ensures we match up calling conventions during
4389 if (HasLayout() && GetLayoutInfo()->GetPackingSize() < 8)
4391 fFieldRequiresAlign8 = false;
4394 if (fFieldRequiresAlign8)
4396 SetAlign8Candidate();
4398 #endif // FEATURE_64BIT_ALIGNMENT
4400 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
4401 if (ShouldAlign8(dwR8Fields, dwNumInstanceFields))
4403 SetAlign8Candidate();
4405 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
4408 //========================================================================
4410 // Go thru all fields and initialize their FieldDescs.
4411 //========================================================================
4414 } // MethodTableBuilder::InitializeFieldDescs
4417 #pragma warning(pop)
4420 //*******************************************************************************
4421 // Verify self-referencing static ValueType fields with RVA (when the size of the ValueType is known).
4423 MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA(
4424 MethodTable ** pByValueClassCache)
4426 STANDARD_VM_CONTRACT;
4428 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4429 // Enum's static self-referencing fields have been verified as the underlying type of the enum, we should not get here for them
4430 _ASSERTE(!IsEnum());
4431 // The size of the ValueType should be known at this point (the caller throws if it is 0)
4432 _ASSERTE(bmtFP->NumInstanceFieldBytes != 0);
4434 FieldDesc * pFieldDescList = GetApproxFieldDescListRaw();
4435 DWORD nFirstThreadStaticFieldIndex = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields;
4436 for (DWORD i = bmtEnumFields->dwNumInstanceFields; i < nFirstThreadStaticFieldIndex; i++)
4438 FieldDesc * pFD = &pFieldDescList[i];
4439 _ASSERTE(pFD->IsStatic());
4441 if (pFD->IsRVA() && pFD->IsByValue())
4443 _ASSERTE(pByValueClassCache[i] != NULL);
4445 if (IsSelfRef(pByValueClassCache[i]))
4448 IfFailThrow(GetMDImport()->GetFieldRVA(pFD->GetMemberDef(), &rva));
4452 } // MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA
4454 //*******************************************************************************
4455 // Returns true if hEnclosingTypeCandidate encloses, at any arbitrary depth,
4456 // hNestedTypeCandidate; returns false otherwise.
4458 bool MethodTableBuilder::IsEnclosingNestedTypePair(
4459 bmtTypeHandle hEnclosingTypeCandidate,
4460 bmtTypeHandle hNestedTypeCandidate)
4462 STANDARD_VM_CONTRACT;
4464 CONSISTENCY_CHECK(!hEnclosingTypeCandidate.IsNull());
4465 CONSISTENCY_CHECK(!hNestedTypeCandidate.IsNull());
4466 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hEnclosingTypeCandidate, hNestedTypeCandidate));
4468 Module * pModule = hEnclosingTypeCandidate.GetModule();
4470 if (pModule != hNestedTypeCandidate.GetModule())
4471 { // If the modules aren't the same, then there's no way
4472 // hBase could be an enclosing type of hChild. We make
4473 // this check early so that the code can deal with only
4474 // one Module and IMDInternalImport instance and can avoid
4479 IMDInternalImport * pMDImport = pModule->GetMDImport();
4481 mdTypeDef tkEncl = hEnclosingTypeCandidate.GetTypeDefToken();
4482 mdTypeDef tkNest = hNestedTypeCandidate.GetTypeDefToken();
4484 while (tkEncl != tkNest)
4485 { // Do this using the metadata APIs because MethodTableBuilder does
4486 // not construct type representations for enclosing type chains.
4487 if (FAILED(pMDImport->GetNestedClassProps(tkNest, &tkNest)))
4488 { // tokNest is not a nested type.
4493 // tkNest's enclosing type is tkEncl, so we've shown that
4494 // hEnclosingTypeCandidate encloses hNestedTypeCandidate
4498 //*******************************************************************************
4499 // Given an arbitrary nesting+subclassing pattern like this:
4502 // private virtual void Foo() { ... }
4505 // class CN : CN-1 {
4506 // private override void Foo() { ... }
4512 // this method will return true, where hChild == N and hBase == C1
4514 // Note that there is no requirement that a type derive from its immediately
4515 // enclosing type, but can skip a level, such as this example:
4519 // private virtual void Foo() { }
4522 // public class C : A
4524 // private override void Foo() { }
4529 // NOTE: IMPORTANT: This code assumes that hBase is indeed a base type of hChild,
4530 // and behaviour is undefined if this is not the case.
4532 bool MethodTableBuilder::IsBaseTypeAlsoEnclosingType(
4533 bmtTypeHandle hBase,
4534 bmtTypeHandle hChild)
4536 STANDARD_VM_CONTRACT;
4538 CONSISTENCY_CHECK(!hBase.IsNull());
4539 CONSISTENCY_CHECK(!hChild.IsNull());
4540 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hBase, hChild));
4542 // The idea of this algorithm is that if we climb the inheritance chain
4543 // starting at hChild then we'll eventually hit hBase. If we check that
4544 // for every (hParent, hChild) pair in the chain that hParent encloses
4545 // hChild, then we've shown that hBase encloses hChild.
4547 while (!bmtTypeHandle::Equal(hBase, hChild))
4549 CONSISTENCY_CHECK(!hChild.GetParentType().IsNull());
4550 bmtTypeHandle hParent(hChild.GetParentType());
4552 if (!IsEnclosingNestedTypePair(hParent, hChild))
4553 { // First, the parent type must enclose the child type.
4554 // If this is not the case we fail immediately.
4558 // Move up one in the inheritance chain, and try again.
4562 // If the loop worked itself from the original hChild all the way
4563 // up to hBase, then we know that for every (hParent, hChild)
4564 // pair in the chain that hParent enclosed hChild, and so we know
4565 // that hBase encloses the original hChild
4569 //*******************************************************************************
4570 BOOL MethodTableBuilder::TestOverrideForAccessibility(
4571 bmtMethodHandle hParentMethod,
4572 bmtTypeHandle hChildType)
4574 STANDARD_VM_CONTRACT;
4576 bmtTypeHandle hParentType(hParentMethod.GetOwningType());
4578 Module * pParentModule = hParentType.GetModule();
4579 Module * pChildModule = hChildType.GetModule();
4581 Assembly * pParentAssembly = pParentModule->GetAssembly();
4582 Assembly * pChildAssembly = pChildModule->GetAssembly();
4584 BOOL isSameAssembly = (pChildAssembly == pParentAssembly);
4586 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4588 // AKA "strict bit". This means that overridability is tightly bound to accessibility.
4589 if (IsMdCheckAccessOnOverride(dwParentAttrs))
4592 if (isSameAssembly || pParentAssembly->GrantsFriendAccessTo(pChildAssembly, hParentMethod.GetMethodDesc())
4593 || pChildAssembly->IgnoresAccessChecksTo(pParentAssembly))
4595 // Can always override any method that has accessibility greater than mdPrivate
4596 if ((dwParentAttrs & mdMemberAccessMask) > mdPrivate)
4599 // Generally, types cannot override inherited mdPrivate methods, except:
4600 // Types can access enclosing type's private members, so it can
4601 // override them if the nested type extends its enclosing type.
4602 else if ((dwParentAttrs & mdMemberAccessMask) == mdPrivate &&
4603 IsBaseTypeAlsoEnclosingType(hParentType, hChildType))
4614 // If the method marks itself as check visibility the the method must be
4615 // public, FamORAssem, or family
4616 if((dwParentAttrs & mdMemberAccessMask) <= mdAssem)
4625 //*******************************************************************************
4626 VOID MethodTableBuilder::TestOverRide(bmtMethodHandle hParentMethod,
4627 bmtMethodHandle hChildMethod)
4631 PRECONDITION(IsMdVirtual(hParentMethod.GetDeclAttrs()));
4632 PRECONDITION(IsMdVirtual(hChildMethod.GetDeclAttrs()));
4635 DWORD dwAttrs = hChildMethod.GetDeclAttrs();
4636 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4638 Module *pModule = hChildMethod.GetOwningType().GetModule();
4639 Module *pParentModule = hParentMethod.GetOwningType().GetModule();
4641 Assembly *pAssembly = pModule->GetAssembly();
4642 Assembly *pParentAssembly = pParentModule->GetAssembly();
4644 BOOL isSameModule = (pModule == pParentModule);
4645 BOOL isSameAssembly = (pAssembly == pParentAssembly);
4647 if (!TestOverrideForAccessibility(hParentMethod, hChildMethod.GetOwningType()))
4649 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, hChildMethod.GetMethodSignature().GetToken());
4653 // Refer to Partition II, 9.3.3 for more information on what is permitted.
4656 enum WIDENING_STATUS
4660 e_SA, // YES, but only when same assembly
4661 e_NSA, // YES, but only when NOT same assembly
4662 e_SM, // YES, but only when same module
4665 static_assert_no_msg(mdPrivateScope == 0x00);
4666 static_assert_no_msg(mdPrivate == 0x01);
4667 static_assert_no_msg(mdFamANDAssem == 0x02);
4668 static_assert_no_msg(mdAssem == 0x03);
4669 static_assert_no_msg(mdFamily == 0x04);
4670 static_assert_no_msg(mdFamORAssem == 0x05);
4671 static_assert_no_msg(mdPublic == 0x06);
4673 static const DWORD dwCount = mdPublic - mdPrivateScope + 1;
4674 static const WIDENING_STATUS rgWideningTable[dwCount][dwCount] =
4677 // Subtype | mdPrivateScope mdPrivate mdFamANDAssem mdAssem mdFamily mdFamORAssem mdPublic
4678 // --------------+-------------------------------------------------------------------------------------------------------
4679 /*mdPrivateScope | */ { { e_SM, e_NO, e_NO, e_NO, e_NO, e_NO, e_NO },
4680 /*mdPrivate | */ { e_SM, e_YES, e_NO, e_NO, e_NO, e_NO, e_NO },
4681 /*mdFamANDAssem | */ { e_SM, e_YES, e_SA, e_NO, e_NO, e_NO, e_NO },
4682 /*mdAssem | */ { e_SM, e_YES, e_SA, e_SA, e_NO, e_NO, e_NO },
4683 /*mdFamily | */ { e_SM, e_YES, e_YES, e_NO, e_YES, e_NSA, e_NO },
4684 /*mdFamORAssem | */ { e_SM, e_YES, e_YES, e_SA, e_YES, e_YES, e_NO },
4685 /*mdPublic | */ { e_SM, e_YES, e_YES, e_YES, e_YES, e_YES, e_YES } };
4687 DWORD idxParent = (dwParentAttrs & mdMemberAccessMask) - mdPrivateScope;
4688 DWORD idxMember = (dwAttrs & mdMemberAccessMask) - mdPrivateScope;
4689 CONSISTENCY_CHECK(idxParent < dwCount);
4690 CONSISTENCY_CHECK(idxMember < dwCount);
4692 WIDENING_STATUS entry = rgWideningTable[idxMember][idxParent];
4694 if (entry == e_NO ||
4695 (entry == e_SA && !isSameAssembly && !pParentAssembly->GrantsFriendAccessTo(pAssembly, hParentMethod.GetMethodDesc())
4696 && !pAssembly->IgnoresAccessChecksTo(pParentAssembly)) ||
4697 (entry == e_NSA && isSameAssembly) ||
4698 (entry == e_SM && !isSameModule)
4701 BuildMethodTableThrowException(IDS_CLASSLOAD_REDUCEACCESS, hChildMethod.GetMethodSignature().GetToken());
4707 //*******************************************************************************
4708 VOID MethodTableBuilder::TestMethodImpl(
4709 bmtMethodHandle hDeclMethod,
4710 bmtMethodHandle hImplMethod)
4715 PRECONDITION(!hDeclMethod.IsNull());
4716 PRECONDITION(!hImplMethod.IsNull());
4720 Module * pDeclModule = hDeclMethod.GetOwningType().GetModule();
4721 Module * pImplModule = hImplMethod.GetOwningType().GetModule();
4723 mdTypeDef tokDecl = hDeclMethod.GetMethodSignature().GetToken();
4724 mdTypeDef tokImpl = hImplMethod.GetMethodSignature().GetToken();
4726 BOOL isSameModule = pDeclModule->Equals(pImplModule);
4728 IMDInternalImport *pIMDDecl = pDeclModule->GetMDImport();
4729 IMDInternalImport *pIMDImpl = pImplModule->GetMDImport();
4732 if (FAILED(pIMDDecl->GetMethodDefProps(tokDecl, &dwDeclAttrs)))
4734 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4737 if (FAILED(pIMDImpl->GetMethodDefProps(tokImpl, &dwImplAttrs)))
4739 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4742 HRESULT hr = COR_E_TYPELOAD;
4744 if (!IsMdVirtual(dwDeclAttrs))
4746 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NONVIRTUAL_DECL);
4748 if (!IsMdVirtual(dwImplAttrs))
4750 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL);
4752 // Virtual methods cannot be static
4753 if (IsMdStatic(dwDeclAttrs))
4755 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4757 if (IsMdStatic(dwImplAttrs))
4759 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4761 if (IsMdFinal(dwDeclAttrs))
4763 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL);
4766 // Interface method body that has methodimpl should always be final
4767 if (IsInterface() && !IsMdFinal(dwImplAttrs))
4769 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_IMPL);
4772 // Since MethodImpl's do not affect the visibility of the Decl method, there's
4773 // no need to check.
4775 // If Decl's parent is other than this class, Decl must not be private
4776 mdTypeDef tkImplParent = mdTypeDefNil;
4777 mdTypeDef tkDeclParent = mdTypeDefNil;
4779 if (FAILED(hr = pIMDDecl->GetParentToken(tokDecl, &tkDeclParent)))
4781 BuildMethodTableThrowException(hr, *bmtError);
4783 if (FAILED(hr = pIMDImpl->GetParentToken(tokImpl, &tkImplParent)))
4785 BuildMethodTableThrowException(hr, *bmtError);
4788 // Make sure that we test for accessibility restrictions only if the decl is
4789 // not within our own type, as we are allowed to methodImpl a private with the
4790 // strict bit set if it is in our own type.
4791 if (!isSameModule || tkDeclParent != tkImplParent)
4793 if (!TestOverrideForAccessibility(hDeclMethod, hImplMethod.GetOwningType()))
4795 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, tokImpl);
4798 // Decl's parent must not be tdSealed
4799 mdToken tkGrandParentDummyVar;
4800 DWORD dwDeclTypeAttrs;
4801 if (FAILED(hr = pIMDDecl->GetTypeDefProps(tkDeclParent, &dwDeclTypeAttrs, &tkGrandParentDummyVar)))
4803 BuildMethodTableThrowException(hr, *bmtError);
4805 if (IsTdSealed(dwDeclTypeAttrs))
4807 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_SEALED_DECL);
4815 //*******************************************************************************
4817 // Used by BuildMethodTable
4820 MethodTableBuilder::ValidateMethods()
4826 PRECONDITION(CheckPointer(this));
4827 PRECONDITION(CheckPointer(bmtInternal));
4828 PRECONDITION(CheckPointer(bmtMetaData));
4829 PRECONDITION(CheckPointer(bmtError));
4830 PRECONDITION(CheckPointer(bmtProp));
4831 PRECONDITION(CheckPointer(bmtInterface));
4832 PRECONDITION(CheckPointer(bmtParent));
4833 PRECONDITION(CheckPointer(bmtMFDescs));
4834 PRECONDITION(CheckPointer(bmtEnumFields));
4835 PRECONDITION(CheckPointer(bmtMethodImpl));
4836 PRECONDITION(CheckPointer(bmtVT));
4840 // Used to keep track of located default and type constructors.
4841 CONSISTENCY_CHECK(bmtVT->pCCtor == NULL);
4842 CONSISTENCY_CHECK(bmtVT->pDefaultCtor == NULL);
4844 // Fetch the hard-coded signatures for the type constructor and the
4845 // default constructor and create MethodSignature objects for both at
4846 // the method level so this does not happen for every specialname
4851 sig = MscorlibBinder::GetSignature(&gsig_SM_RetVoid);
4853 MethodSignature cctorSig(MscorlibBinder::GetModule(),
4854 COR_CCTOR_METHOD_NAME,
4855 sig.GetRawSig(), sig.GetRawSigLen());
4857 sig = MscorlibBinder::GetSignature(&gsig_IM_RetVoid);
4859 MethodSignature defaultCtorSig(MscorlibBinder::GetModule(),
4860 COR_CTOR_METHOD_NAME,
4861 sig.GetRawSig(), sig.GetRawSigLen());
4863 Module * pModule = GetModule();
4864 DeclaredMethodIterator it(*this);
4867 // The RVA is only valid/testable if it has not been overwritten
4868 // for something like edit-and-continue
4869 // Complete validation of non-zero RVAs is done later inside MethodDesc::GetILHeader.
4870 if ((it.RVA() == 0) && (pModule->GetDynamicIL(it.Token(), FALSE) == NULL))
4872 // for IL code that is implemented here must have a valid code RVA
4873 // this came up due to a linker bug where the ImplFlags/DescrOffset were
4874 // being set to null and we weren't coping with it
4875 if((IsMiIL(it.ImplFlags()) || IsMiOPTIL(it.ImplFlags())) &&
4876 !IsMdAbstract(it.Attrs()) &&
4877 !IsReallyMdPinvokeImpl(it.Attrs()) &&
4878 !IsMiInternalCall(it.ImplFlags()))
4880 BuildMethodTableThrowException(IDS_CLASSLOAD_MISSINGMETHODRVA, it.Token());
4884 if (IsMdRTSpecialName(it.Attrs()))
4886 if (IsMdVirtual(it.Attrs()))
4887 { // Virtual specialname methods are illegal
4888 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4891 // Constructors (.ctor) and class initialisers (.cctor) are special
4892 const MethodSignature &curSig(it->GetMethodSignature());
4894 if (IsMdStatic(it.Attrs()))
4895 { // The only rtSpecialName static method allowed is the .cctor
4896 if (!curSig.ExactlyEqual(cctorSig))
4898 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4901 // Remember it for later
4902 bmtVT->pCCtor = *it;
4906 if(!MethodSignature::NamesEqual(curSig, defaultCtorSig))
4907 { // The only rtSpecialName instance methods allowed are .ctors
4908 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4911 // .ctor must return void
4912 MetaSig methodMetaSig(curSig.GetSignature(),
4913 static_cast<DWORD>(curSig.GetSignatureLength()),
4917 if (methodMetaSig.GetReturnType() != ELEMENT_TYPE_VOID)
4918 { // All constructors must have a void return type
4919 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4922 // See if this is a default constructor. If so, remember it for later.
4923 if (curSig.ExactlyEqual(defaultCtorSig))
4925 bmtVT->pDefaultCtor = *it;
4930 // Make sure that fcalls have a 0 rva. This is assumed by the prejit fixup logic
4931 if (it.MethodType() == METHOD_TYPE_FCALL && it.RVA() != 0)
4933 BuildMethodTableThrowException(BFA_ECALLS_MUST_HAVE_ZERO_RVA, it.Token());
4936 // check for proper use of the Managed and native flags
4937 if (IsMiManaged(it.ImplFlags()))
4939 if (IsMiIL(it.ImplFlags()) || IsMiRuntime(it.ImplFlags())) // IsMiOPTIL(it.ImplFlags()) no longer supported
4941 // No need to set code address, pre stub used automatically.
4945 if (IsMiNative(it.ImplFlags()))
4947 // For now simply disallow managed native code if you turn this on you have to at least
4948 // insure that we have SkipVerificationPermission or equivalent
4949 BuildMethodTableThrowException(BFA_MANAGED_NATIVE_NYI, it.Token());
4953 BuildMethodTableThrowException(BFA_BAD_IMPL_FLAGS, it.Token());
4959 if (IsMiNative(it.ImplFlags()) && IsGlobalClass())
4961 // global function unmanaged entrypoint via IJW thunk was handled
4966 BuildMethodTableThrowException(IDS_CLASSLOAD_BAD_UNMANAGED_RVA, it.Token());
4968 if (it.MethodType() != METHOD_TYPE_NDIRECT)
4970 BuildMethodTableThrowException(BFA_BAD_UNMANAGED_ENTRY_POINT);
4974 // Vararg methods are not allowed inside generic classes
4975 // and nor can they be generic methods.
4976 if (bmtGenerics->GetNumGenericArgs() > 0 || (it.MethodType() == METHOD_TYPE_INSTANTIATED) )
4978 DWORD cMemberSignature;
4979 PCCOR_SIGNATURE pMemberSignature = it.GetSig(&cMemberSignature);
4980 // We've been trying to avoid asking for the signature - now we need it
4981 if (pMemberSignature == NULL)
4983 pMemberSignature = it.GetSig(&cMemberSignature);
4986 if (MetaSig::IsVarArg(pModule, Signature(pMemberSignature, cMemberSignature)))
4988 BuildMethodTableThrowException(BFA_GENCODE_NOT_BE_VARARG);
4992 if (IsMdVirtual(it.Attrs()) && IsMdPublic(it.Attrs()) && it.Name() == NULL)
4994 BuildMethodTableThrowException(IDS_CLASSLOAD_NOMETHOD_NAME);
4997 if (it.IsMethodImpl())
4999 if (!IsMdVirtual(it.Attrs()))
5000 { // Non-virtual methods cannot participate in a methodImpl pair.
5001 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5005 // Virtual static methods are not allowed.
5006 if (IsMdStatic(it.Attrs()) && IsMdVirtual(it.Attrs()))
5008 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL, it.Token());
5013 //*******************************************************************************
5014 // Essentially, this is a helper method that combines calls to InitMethodDesc and
5015 // SetSecurityFlagsOnMethod. It then assigns the newly initialized MethodDesc to
5018 MethodTableBuilder::InitNewMethodDesc(
5019 bmtMDMethod * pMethod,
5020 MethodDesc * pNewMD)
5022 STANDARD_VM_CONTRACT;
5025 // First, set all flags that control layout of optional slots
5027 pNewMD->SetClassification(GetMethodClassification(pMethod->GetMethodType()));
5029 if (pMethod->GetMethodImplType() == METHOD_IMPL)
5030 pNewMD->SetHasMethodImplSlot();
5032 if (pMethod->GetSlotIndex() >= bmtVT->cVtableSlots)
5033 pNewMD->SetHasNonVtableSlot();
5035 if (NeedsNativeCodeSlot(pMethod))
5036 pNewMD->SetHasNativeCodeSlot();
5038 // Now we know the classification we can allocate the correct type of
5039 // method desc and perform any classification specific initialization.
5041 LPCSTR pName = pMethod->GetMethodSignature().GetName();
5044 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pName)))
5046 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5051 LPCUTF8 pszDebugMethodName;
5052 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pszDebugMethodName)))
5054 pszDebugMethodName = "Invalid MethodDef record";
5056 S_SIZE_T safeLen = S_SIZE_T(strlen(pszDebugMethodName)) + S_SIZE_T(1);
5057 if(safeLen.IsOverflow())
5058 COMPlusThrowHR(COR_E_OVERFLOW);
5060 size_t len = safeLen.Value();
5061 LPCUTF8 pszDebugMethodNameCopy = (char*) AllocateFromLowFrequencyHeap(safeLen);
5062 strcpy_s((char *) pszDebugMethodNameCopy, len, pszDebugMethodName);
5065 // Do the init specific to each classification of MethodDesc & assign some common fields
5066 InitMethodDesc(pNewMD,
5067 GetMethodClassification(pMethod->GetMethodType()),
5068 pMethod->GetMethodSignature().GetToken(),
5069 pMethod->GetImplAttrs(),
5070 pMethod->GetDeclAttrs(),
5075 COMMA_INDEBUG(pszDebugMethodNameCopy)
5076 COMMA_INDEBUG(GetDebugClassName())
5077 COMMA_INDEBUG("") // FIX this happens on global methods, give better info
5080 pMethod->SetMethodDesc(pNewMD);
5082 bmtRTMethod * pParentMethod = NULL;
5086 SLOT_INDEX idx = pMethod->GetSlotIndex();
5087 CONSISTENCY_CHECK(idx != INVALID_SLOT_INDEX);
5089 if (idx < GetParentMethodTable()->GetNumVirtuals())
5091 pParentMethod = (*bmtParent->pSlotTable)[idx].Decl().AsRTMethod();
5095 // Turn off inlining for any calls
5096 // that are marked in the metadata as not being inlineable.
5097 if(IsMiNoInlining(pMethod->GetImplAttrs()))
5099 pNewMD->SetNotInline(true);
5102 // Check for methods marked as [Intrinsic]
5103 if (GetModule()->IsSystem() || GetAssembly()->IsSIMDVectorAssembly())
5105 HRESULT hr = GetMDImport()->GetCustomAttributeByName(pMethod->GetMethodSignature().GetToken(),
5106 g_CompilerServicesIntrinsicAttribute,
5110 if (hr == S_OK || bmtProp->fIsHardwareIntrinsic)
5112 pNewMD->SetIsJitIntrinsic();
5117 pNewMD->SetSlot(pMethod->GetSlotIndex());
5120 //*******************************************************************************
5121 // Determine vtable placement for each non-virtual in the class, while also
5122 // looking for default and type constructors.
5124 MethodTableBuilder::PlaceNonVirtualMethods()
5130 PRECONDITION(CheckPointer(this));
5131 PRECONDITION(CheckPointer(bmtInternal));
5132 PRECONDITION(CheckPointer(bmtMetaData));
5133 PRECONDITION(CheckPointer(bmtError));
5134 PRECONDITION(CheckPointer(bmtProp));
5135 PRECONDITION(CheckPointer(bmtInterface));
5136 PRECONDITION(CheckPointer(bmtParent));
5137 PRECONDITION(CheckPointer(bmtMFDescs));
5138 PRECONDITION(CheckPointer(bmtEnumFields));
5139 PRECONDITION(CheckPointer(bmtMethodImpl));
5140 PRECONDITION(CheckPointer(bmtVT));
5144 INDEBUG(bmtVT->SealVirtualSlotSection();)
5147 // For each non-virtual method, place the method in the next available non-virtual method slot.
5150 // Place the cctor and default ctor first. code::MethodTableGetCCtorSlot and code:MethodTable::GetDefaultCtorSlot
5152 if (bmtVT->pCCtor != NULL)
5154 if (!bmtVT->AddNonVirtualMethod(bmtVT->pCCtor))
5155 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5158 if (bmtVT->pDefaultCtor != NULL)
5160 if (!bmtVT->AddNonVirtualMethod(bmtVT->pDefaultCtor))
5161 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5164 // We use slot during remoting and to map methods between generic instantiations
5165 // (see MethodTable::GetParallelMethodDesc). The current implementation
5166 // of this mechanism requires real slots.
5167 BOOL fCanHaveNonVtableSlots = (bmtGenerics->GetNumGenericArgs() == 0) && !IsInterface();
5169 // Flag to avoid second pass when possible
5170 BOOL fHasNonVtableSlots = FALSE;
5173 // Place all methods that require real vtable slot first. This is necessary so
5174 // that they get consequitive slot numbers right after virtual slots.
5177 DeclaredMethodIterator it(*this);
5180 // Skip methods that are placed already
5181 if (it->GetSlotIndex() != INVALID_SLOT_INDEX)
5185 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5186 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5189 if (!fCanHaveNonVtableSlots ||
5190 it->GetMethodType() == METHOD_TYPE_INSTANTIATED)
5192 // We use slot during remoting and to map methods between generic instantiations
5193 // (see MethodTable::GetParallelMethodDesc). The current implementation
5194 // of this mechanism requires real slots.
5198 // This method does not need real vtable slot
5199 fHasNonVtableSlots = TRUE;
5203 // This will update slot index in bmtMDMethod
5204 if (!bmtVT->AddNonVirtualMethod(*it))
5205 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5208 // Remeber last real vtable slot
5209 bmtVT->cVtableSlots = bmtVT->cTotalSlots;
5211 // Are there any Non-vtable slots to place?
5212 if (!fHasNonVtableSlots)
5216 // Now, place the remaining methods. They will get non-vtable slot.
5219 DeclaredMethodIterator it2(*this);
5222 // Skip methods that are placed already
5223 if (it2->GetSlotIndex() != INVALID_SLOT_INDEX)
5226 if (!bmtVT->AddNonVirtualMethod(*it2))
5227 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5232 //*******************************************************************************
5233 // Determine vtable placement for each virtual member in this class.
5235 MethodTableBuilder::PlaceVirtualMethods()
5241 PRECONDITION(CheckPointer(this));
5242 PRECONDITION(CheckPointer(bmtInternal));
5243 PRECONDITION(CheckPointer(bmtMetaData));
5244 PRECONDITION(CheckPointer(bmtError));
5245 PRECONDITION(CheckPointer(bmtProp));
5246 PRECONDITION(CheckPointer(bmtInterface));
5247 PRECONDITION(CheckPointer(bmtParent));
5248 PRECONDITION(CheckPointer(bmtMFDescs));
5249 PRECONDITION(CheckPointer(bmtEnumFields));
5250 PRECONDITION(CheckPointer(bmtMethodImpl));
5251 PRECONDITION(CheckPointer(bmtVT));
5256 LPCUTF8 pszDebugName, pszDebugNamespace;
5257 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &pszDebugName, &pszDebugNamespace)))
5259 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
5264 // For each virtual method
5265 // - If the method is not declared as newslot, search all virtual methods in the parent
5266 // type for an override candidate.
5267 // - If such a candidate is found, test to see if the override is valid. If
5268 // the override is not valid, throw TypeLoadException
5269 // - If a candidate is found above, place the method in the inherited slot as both
5270 // the Decl and the Impl.
5271 // - Else, place the method in the next available empty vtable slot.
5274 DeclaredMethodIterator it(*this);
5277 if (!IsMdVirtual(it.Attrs()))
5278 { // Only processing declared virtual methods
5283 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5284 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5287 // If this member is a method which overrides a parent method, it will be set to non-NULL
5288 bmtRTMethod * pParentMethod = NULL;
5290 // Hash that a method with this name exists in this class
5291 // Note that ctors and static ctors are not added to the table
5292 BOOL fMethodConstraintsMatch = FALSE;
5294 // If the member is marked with a new slot we do not need to find it in the parent
5295 if (HasParent() && !IsMdNewSlot(it.Attrs()))
5297 // Attempt to find the method with this name and signature in the parent class.
5298 // This method may or may not create pParentMethodHash (if it does not already exist).
5299 // It also may or may not fill in pMemberSignature/cMemberSignature.
5300 // An error is only returned when we can not create the hash.
5301 // NOTE: This operation touches metadata
5302 pParentMethod = LoaderFindMethodInParentClass(
5303 it->GetMethodSignature(), bmtProp->fNoSanityChecks ? NULL : &fMethodConstraintsMatch);
5305 if (pParentMethod != NULL)
5306 { // Found an override candidate
5307 DWORD dwParentAttrs = pParentMethod->GetDeclAttrs();
5309 if (!IsMdVirtual(dwParentAttrs))
5310 { // Can't override a non-virtual methods
5311 BuildMethodTableThrowException(BFA_NONVIRT_NO_SEARCH, it.Token());
5314 if(IsMdFinal(dwParentAttrs))
5315 { // Can't override a final methods
5316 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL, it.Token());
5319 if(!bmtProp->fNoSanityChecks)
5321 TestOverRide(bmtMethodHandle(pParentMethod),
5322 bmtMethodHandle(*it));
5324 if (!fMethodConstraintsMatch)
5326 BuildMethodTableThrowException(
5327 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_OVERRIDE,
5337 CONSISTENCY_CHECK(pParentMethod == NULL);
5338 // Also sets new slot number on bmtRTMethod and MethodDesc
5339 if (!bmtVT->AddVirtualMethod(*it))
5340 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5342 else if (pParentMethod != NULL)
5344 bmtVT->SetVirtualMethodOverride(pParentMethod->GetSlotIndex(), *it);
5348 if (!bmtVT->AddVirtualMethod(*it))
5349 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5354 // Given an interface map entry, and a name+signature, compute the method on the interface
5355 // that the name+signature corresponds to. Used by ProcessMethodImpls and ProcessInexactMethodImpls
5356 // Always returns the first match that it finds. Affects the ambiguities in code:#ProcessInexactMethodImpls_Ambiguities
5357 MethodTableBuilder::bmtMethodHandle
5358 MethodTableBuilder::FindDeclMethodOnInterfaceEntry(bmtInterfaceEntry *pItfEntry, MethodSignature &declSig)
5360 STANDARD_VM_CONTRACT;
5362 bmtMethodHandle declMethod;
5364 bmtInterfaceEntry::InterfaceSlotIterator slotIt =
5365 pItfEntry->IterateInterfaceSlots(GetStackingAllocator());
5366 // Check for exact match
5367 for (; !slotIt.AtEnd(); slotIt.Next())
5369 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5371 if (declSig.ExactlyEqual(pCurDeclMethod->GetMethodSignature()))
5373 declMethod = slotIt->Decl();
5377 slotIt.ResetToStart();
5379 // Check for equivalent match if exact match wasn't found
5380 if (declMethod.IsNull())
5382 for (; !slotIt.AtEnd(); slotIt.Next())
5384 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5386 // Type Equivalence is forbidden in MethodImpl MemberRefs
5387 if (declSig.Equivalent(pCurDeclMethod->GetMethodSignature()))
5389 declMethod = slotIt->Decl();
5398 //*******************************************************************************
5400 // Used by BuildMethodTable
5401 // Process the list of inexact method impls generated during ProcessMethodImpls.
5402 // This list is used to cause a methodImpl to an interface to override
5403 // methods on several equivalent interfaces in the interface map. This logic is necessary
5404 // so that in the presence of an embedded interface the behavior appears to mimic
5405 // the behavior if the interface was not embedded.
5407 // In particular, the logic here is to handle cases such as
5410 // [TypeIdentifier("x","y")]
5412 // { void Method(); }
5413 // interface IOther : I' {}
5416 // [TypeIdentifier("x","y")]
5418 // { void Method(); }
5419 // class Test : I, IOther
5425 // In this case, there is one method, and one methodimpl, but there are 2 interfaces on the class that both
5426 // require an implementation of their method. The correct semantic for type equivalence, is that any
5427 // methodimpl directly targeting a method on an interface must be respected, and if it also applies to a type
5428 // equivalent interface method, then if that method was not methodimpl'd directly, then the methodimpl should apply
5429 // there as well. The ProcessInexactMethodImpls function does this secondary MethodImpl mapping.
5431 //#ProcessInexactMethodImpls_Ambiguities
5432 // In the presence of ambiguities, such as there are 3 equivalent interfaces implemented on a class and 2 methodimpls,
5433 // we will apply the 2 method impls exactly to appropriate interface methods, and arbitrarily pick one to apply to the
5434 // other interface. This is clearly ambiguous, but tricky to detect in the type loader efficiently, and should hopefully
5435 // not cause too many problems.
5438 MethodTableBuilder::ProcessInexactMethodImpls()
5440 STANDARD_VM_CONTRACT;
5442 if (bmtMethod->dwNumberInexactMethodImplCandidates == 0)
5445 DeclaredMethodIterator it(*this);
5448 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5449 // error before reaching this point.
5450 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5452 if (!IsMdVirtual(it.Attrs()))
5453 { // Only virtual methods can participate in methodImpls
5457 if(!it.IsMethodImpl())
5459 // Skip methods which are not the bodies of MethodImpl specifications
5463 // If this method serves as the BODY of a MethodImpl specification, then
5464 // we should iterate all the MethodImpl's for this class and see just how many
5465 // of them this method participates in as the BODY.
5466 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5468 // Inexact matching logic only works on MethodImpls that have been opted into inexactness by ProcessMethodImpls.
5469 if (!bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing)
5474 // If the methodimpl we are working with does not match this method, continue to next methodimpl
5475 if(it.Token() != bmtMetaData->rgMethodImplTokens[m].methodBody)
5480 bool fMatchFound = false;
5482 LPCUTF8 szName = NULL;
5483 PCCOR_SIGNATURE pSig = NULL;
5486 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5488 if (TypeFromToken(mdDecl) == mdtMethodDef)
5489 { // Different methods are aused to access MethodDef and MemberRef
5490 // names and signatures.
5491 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5492 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5494 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5499 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5501 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5505 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5506 MethodSignature declSig(GetModule(), szName, pSig, cbSig, pDeclSubst);
5507 bmtInterfaceEntry * pItfEntry = NULL;
5509 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5511 if (bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet() != bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet)
5514 bmtMethodHandle declMethod;
5515 pItfEntry = &bmtInterface->pInterfaceMap[i];
5517 // Search for declmethod on this interface
5518 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5520 // If we didn't find a match, continue on to next interface in the equivalence set
5521 if (declMethod.IsNull())
5524 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5525 { // Make sure the decl is virtual
5526 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5531 bool fPreexistingImplFound = false;
5533 // Check to ensure there isn't already a matching declMethod in the method impl list
5534 for (DWORD iMethodImpl = 0; iMethodImpl < bmtMethodImpl->pIndex; iMethodImpl++)
5536 if (bmtMethodImpl->GetDeclarationMethod(iMethodImpl) == declMethod)
5538 fPreexistingImplFound = true;
5543 // Search for other matches
5544 if (fPreexistingImplFound)
5547 // Otherwise, record the method impl discovery if the match is
5548 bmtMethodImpl->AddMethodImpl(*it, declMethod, bmtMetaData->rgMethodImplTokens[m].methodDecl, GetStackingAllocator());
5551 if (!fMatchFound && bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing)
5553 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5559 //*******************************************************************************
5561 // Used by BuildMethodTable
5564 MethodTableBuilder::ProcessMethodImpls()
5566 STANDARD_VM_CONTRACT;
5568 if (bmtMethod->dwNumberMethodImpls == 0)
5573 DeclaredMethodIterator it(*this);
5576 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5577 // error before reaching this point.
5578 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5580 if (!IsMdVirtual(it.Attrs()))
5581 { // Only virtual methods can participate in methodImpls
5585 // If this method serves as the BODY of a MethodImpl specification, then
5586 // we should iterate all the MethodImpl's for this class and see just how many
5587 // of them this method participates in as the BODY.
5588 if(it.IsMethodImpl())
5590 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5592 if(it.Token() == bmtMetaData->rgMethodImplTokens[m].methodBody)
5594 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5595 bmtMethodHandle declMethod;
5597 // Get the parent token for the decl method token
5598 mdToken tkParent = mdTypeDefNil;
5599 if (TypeFromToken(mdDecl) == mdtMethodDef || TypeFromToken(mdDecl) == mdtMemberRef)
5601 if (FAILED(hr = GetMDImport()->GetParentToken(mdDecl,&tkParent)))
5603 BuildMethodTableThrowException(hr, *bmtError);
5607 if (GetCl() == tkParent)
5608 { // The DECL has been declared within the class that we're currently building.
5611 if(bmtError->pThrowable != NULL)
5613 *(bmtError->pThrowable) = NULL;
5616 if(TypeFromToken(mdDecl) != mdtMethodDef)
5618 if (FAILED(hr = FindMethodDeclarationForMethodImpl(
5619 mdDecl, &mdDecl, TRUE)))
5621 BuildMethodTableThrowException(hr, *bmtError);
5625 CONSISTENCY_CHECK(TypeFromToken(mdDecl) == mdtMethodDef);
5626 declMethod = bmtMethod->FindDeclaredMethodByToken(mdDecl);
5629 { // We can't call GetDescFromMemberDefOrRef here because this
5630 // method depends on a fully-loaded type, including parent types,
5631 // which is not always guaranteed. In particular, it requires that
5632 // the instantiation dictionary be filled. The solution is the following:
5633 // 1. Load the approximate type that the method belongs to.
5634 // 2. Get or create the correct substitution for the type involved
5635 // 3. Iterate the introduced methods on that type looking for a matching
5638 LPCUTF8 szName = NULL;
5639 PCCOR_SIGNATURE pSig = NULL;
5641 if (TypeFromToken(mdDecl) == mdtMethodDef)
5642 { // Different methods are aused to access MethodDef and MemberRef
5643 // names and signatures.
5644 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5645 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5647 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5652 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5654 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5658 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5659 MethodTable * pDeclMT = NULL;
5660 MethodSignature declSig(GetModule(), szName, pSig, cbSig, pDeclSubst);
5662 { // 1. Load the approximate type.
5663 // Block for the LoadsTypeViolation.
5664 CONTRACT_VIOLATION(LoadsTypeViolation);
5665 pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
5668 &bmtGenerics->typeContext,
5669 ClassLoader::ThrowIfNotFound,
5670 ClassLoader::PermitUninstDefOrRef,
5671 ClassLoader::LoadTypes,
5672 CLASS_LOAD_APPROXPARENTS,
5673 TRUE).GetMethodTable()->GetCanonicalMethodTable();
5676 { // 2. Get or create the correct substitution
5677 bmtRTType * pDeclType = NULL;
5679 if (pDeclMT->IsInterface())
5680 { // If the declaration method is a part of an interface, search through
5681 // the interface map to find the matching interface so we can provide
5682 // the correct substitution chain.
5685 bmtInterfaceEntry * pItfEntry = NULL;
5686 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5688 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5689 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
5690 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5691 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5692 pCurItf->GetMethodTable(), pDeclMT,
5693 &pCurItf->GetSubstitution(), pDeclSubst,
5696 pItfEntry = &bmtInterface->pInterfaceMap[i];
5697 pDeclType = pCurItf;
5704 if (pDeclType == NULL)
5706 // Interface is not implemented by this type.
5707 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5712 if (pDeclType == NULL)
5714 DWORD equivalenceSet = 0;
5716 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5718 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5719 // Type Equivalence is respected for this comparision as we just need to find an
5720 // equivalent interface, the particular interface is unimportant
5721 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5722 pCurItf->GetMethodTable(), pDeclMT,
5723 &pCurItf->GetSubstitution(), pDeclSubst,
5726 equivalenceSet = bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet();
5727 pItfEntry = &bmtInterface->pInterfaceMap[i];
5732 if (equivalenceSet == 0)
5734 // Interface is not implemented by this type.
5735 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5738 // Interface is not implemented by this type exactly. We need to consider this MethodImpl on non exact interface matches,
5739 // as the only match may be one of the non-exact matches
5740 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5741 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = true;
5742 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = equivalenceSet;
5743 bmtMethod->dwNumberInexactMethodImplCandidates++;
5744 continue; // Move on to other MethodImpls
5748 // This method impl may need to match other methods during inexact processing
5749 if (pItfEntry->InEquivalenceSetWithMultipleEntries())
5751 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5752 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
5753 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = pItfEntry->GetInterfaceEquivalenceSet();
5754 bmtMethod->dwNumberInexactMethodImplCandidates++;
5759 // 3. Find the matching method.
5760 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5763 { // Assume the MethodTable is a parent of the current type,
5764 // and create the substitution chain to match it.
5768 for (bmtRTType *pCur = GetParentType();
5770 pCur = pCur->GetParentType())
5772 if (pCur->GetMethodTable() == pDeclMT)
5779 if (pDeclType == NULL)
5780 { // Method's type is not a parent.
5781 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5784 // 3. Find the matching method.
5785 bmtRTType *pCurDeclType = pDeclType;
5788 // two pass algorithm. search for exact matches followed
5789 // by equivalent matches.
5790 for (int iPass = 0; (iPass < 2) && (declMethod.IsNull()); iPass++)
5792 MethodTable *pCurDeclMT = pCurDeclType->GetMethodTable();
5794 MethodTable::IntroducedMethodIterator methIt(pCurDeclMT);
5795 for(; methIt.IsValid(); methIt.Next())
5797 MethodDesc * pCurMD = methIt.GetMethodDesc();
5799 if (pCurDeclMT != pDeclMT)
5801 // If the method isn't on the declaring type, then it must be virtual.
5802 if (!pCurMD->IsVirtual())
5805 if (strcmp(szName, pCurMD->GetName()) == 0)
5807 PCCOR_SIGNATURE pCurMDSig;
5809 pCurMD->GetSig(&pCurMDSig, &cbCurMDSig);
5811 // First pass searches for declaration methods should not use type equivalence
5812 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5814 if (MetaSig::CompareMethodSigs(
5815 declSig.GetSignature(),
5816 static_cast<DWORD>(declSig.GetSignatureLength()),
5817 declSig.GetModule(),
5818 &declSig.GetSubstitution(),
5821 pCurMD->GetModule(),
5822 &pCurDeclType->GetSubstitution(),
5823 iPass == 0 ? &newVisited : NULL))
5825 declMethod = (*bmtParent->pSlotTable)[pCurMD->GetSlot()].Decl();
5832 pCurDeclType = pCurDeclType->GetParentType();
5833 } while ((pCurDeclType != NULL) && (declMethod.IsNull()));
5836 if (declMethod.IsNull())
5837 { // Would prefer to let this fall out to the BuildMethodTableThrowException
5838 // below, but due to v2.0 and earlier behaviour throwing a MissingMethodException,
5839 // primarily because this code used to be a simple call to
5840 // MemberLoader::GetDescFromMemberDefOrRef (see above for reason why),
5841 // we must continue to do the same.
5842 MemberLoader::ThrowMissingMethodException(
5845 declSig.GetModule(),
5846 declSig.GetSignature(),
5847 static_cast<DWORD>(declSig.GetSignatureLength()),
5848 &bmtGenerics->typeContext);
5853 if (declMethod.IsNull())
5854 { // Method not found, throw.
5855 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5858 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5859 { // Make sure the decl is virtual
5860 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5863 bmtMethodImpl->AddMethodImpl(*it, declMethod, mdDecl, GetStackingAllocator());
5867 } /* end ... for each member */
5870 //*******************************************************************************
5871 // InitMethodDesc takes a pointer to space that's already allocated for the
5872 // particular type of MethodDesc, and initializes based on the other info.
5873 // This factors logic between PlaceMembers (the regular code path) & AddMethod
5874 // (Edit & Continue (EnC) code path) so we don't have to maintain separate copies.
5876 MethodTableBuilder::InitMethodDesc(
5877 MethodDesc * pNewMD, // This is should actually be of the correct sub-type, based on Classification
5878 DWORD Classification,
5881 DWORD dwMemberAttrs,
5883 DWORD RVA, // Only needed for NDirect case
5884 IMDInternalImport * pIMDII, // Needed for NDirect, EEImpl(Delegate) cases
5885 LPCSTR pMethodName // Only needed for mcEEImpl (Delegate) case
5886 COMMA_INDEBUG(LPCUTF8 pszDebugMethodName)
5887 COMMA_INDEBUG(LPCUTF8 pszDebugClassName)
5888 COMMA_INDEBUG(LPCUTF8 pszDebugMethodSignature)
5894 if (fEnC) { GC_NOTRIGGER; } else { GC_TRIGGERS; }
5899 LOG((LF_CORDB, LL_EVERYTHING, "EEC::IMD: pNewMD:0x%x for tok:0x%x (%s::%s)\n",
5900 pNewMD, tok, pszDebugClassName, pszDebugMethodName));
5902 // Now we know the classification we can perform any classification specific initialization.
5904 // The method desc is zero inited by the caller.
5906 switch (Classification)
5910 // NDirect specific initialization.
5911 NDirectMethodDesc *pNewNMD = (NDirectMethodDesc*)pNewMD;
5913 // Allocate writeable data
5914 pNewNMD->ndirect.m_pWriteableData.SetValue((NDirectWriteableData*)
5915 AllocateFromHighFrequencyHeap(S_SIZE_T(sizeof(NDirectWriteableData))));
5917 #ifdef HAS_NDIRECT_IMPORT_PRECODE
5918 pNewNMD->ndirect.m_pImportThunkGlue.SetValue(Precode::Allocate(PRECODE_NDIRECT_IMPORT, pNewMD,
5919 GetLoaderAllocator(), GetMemTracker())->AsNDirectImportPrecode());
5920 #else // !HAS_NDIRECT_IMPORT_PRECODE
5921 pNewNMD->GetNDirectImportThunkGlue()->Init(pNewNMD);
5922 #endif // !HAS_NDIRECT_IMPORT_PRECODE
5924 #if defined(_TARGET_X86_)
5925 pNewNMD->ndirect.m_cbStackArgumentSize = 0xFFFF;
5926 #endif // defined(_TARGET_X86_)
5928 // If the RVA of a native method is set, this is an early-bound IJW call
5929 if (RVA != 0 && IsMiUnmanaged(dwImplFlags) && IsMiNative(dwImplFlags))
5931 // Note that we cannot initialize the stub directly now in the general case,
5932 // as LoadLibrary may not have been performed yet.
5933 pNewNMD->SetIsEarlyBound();
5936 pNewNMD->GetWriteableData()->m_pNDirectTarget = pNewNMD->GetNDirectImportThunkGlue()->GetEntrypoint();
5944 // For the Invoke method we will set a standard invoke method.
5945 BAD_FORMAT_NOTHROW_ASSERT(IsDelegate());
5947 // For the asserts, either the pointer is NULL (since the class hasn't
5948 // been constructed yet), or we're in EnC mode, meaning that the class
5949 // does exist, but we may be re-assigning the field to point to an
5950 // updated MethodDesc
5952 // It is not allowed for EnC to replace one of the runtime builtin methods
5954 if (strcmp(pMethodName, "Invoke") == 0)
5956 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod.IsNull());
5957 ((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod.SetValue(pNewMD);
5959 else if (strcmp(pMethodName, "BeginInvoke") == 0)
5961 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod.IsNull());
5962 ((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod.SetValue(pNewMD);
5964 else if (strcmp(pMethodName, "EndInvoke") == 0)
5966 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod.IsNull());
5967 ((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod.SetValue(pNewMD);
5971 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
5974 // StoredSig specific intialization
5976 StoredSigMethodDesc *pNewSMD = (StoredSigMethodDesc*) pNewMD;;
5978 PCCOR_SIGNATURE pSig;
5979 if (FAILED(pIMDII->GetSigOfMethodDef(tok, &cSig, &pSig)))
5981 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5983 pNewSMD->SetStoredMethodSig(pSig, cSig);
5987 #ifdef FEATURE_COMINTEROP
5989 #endif // FEATURE_COMINTEROP
5993 case mcInstantiated:
5994 #ifdef EnC_SUPPORTED
5997 // We reuse the instantiated methoddescs to get the slot
5998 InstantiatedMethodDesc* pNewIMD = (InstantiatedMethodDesc*) pNewMD;
5999 pNewIMD->SetupEnCAddedMethod();
6002 #endif // EnC_SUPPORTED
6004 // Initialize the typical instantiation.
6005 InstantiatedMethodDesc* pNewIMD = (InstantiatedMethodDesc*) pNewMD;
6006 //data has the same lifetime as method table, use our allocator
6007 pNewIMD->SetupGenericMethodDefinition(pIMDII, GetLoaderAllocator(), GetMemTracker(), GetModule(),
6013 BAD_FORMAT_NOTHROW_ASSERT(!"Failed to set a method desc classification");
6016 // Check the method desc's classification.
6017 _ASSERTE(pNewMD->GetClassification() == Classification);
6019 pNewMD->SetMemberDef(tok);
6021 if (IsMdStatic(dwMemberAttrs))
6022 pNewMD->SetStatic();
6024 // Set suppress unmanaged code access permission attribute
6026 if (pNewMD->IsNDirect())
6027 pNewMD->ComputeSuppressUnmanagedCodeAccessAttr(pIMDII);
6030 // Mark as many methods as synchronized as possible.
6032 // Note that this can easily cause programs to deadlock, and that
6033 // should not be treated as a bug in the program.
6035 static ConfigDWORD stressSynchronized;
6036 DWORD stressSynchronizedVal = stressSynchronized.val(CLRConfig::INTERNAL_stressSynchronized);
6038 bool isStressSynchronized = stressSynchronizedVal &&
6039 pNewMD->IsIL() && // Synchronized is not supported on Ecalls, NDirect method, etc
6040 // IsValueClass() and IsEnum() do not work for System.ValueType and System.Enum themselves
6041 ((g_pValueTypeClass != NULL && g_pEnumClass != NULL &&
6042 !IsValueClass()) || // Can not synchronize on byref "this"
6043 IsMdStatic(dwMemberAttrs)) && // IsStatic() blows up in _DEBUG as pNewMD is not fully inited
6044 g_pObjectClass != NULL; // Ignore Object:* since "this" could be a boxed object
6046 // stressSynchronized=1 turns off the stress in the system domain to reduce
6047 // the chances of spurious deadlocks. Deadlocks in user code can still occur.
6048 // stressSynchronized=2 will probably cause more deadlocks, and is not recommended
6049 if (stressSynchronizedVal == 1 && GetAssembly()->IsSystem())
6050 isStressSynchronized = false;
6052 if (IsMiSynchronized(dwImplFlags) || isStressSynchronized)
6054 if (IsMiSynchronized(dwImplFlags))
6056 pNewMD->SetSynchronized();
6059 pNewMD->m_pszDebugMethodName = (LPUTF8)pszDebugMethodName;
6060 pNewMD->m_pszDebugClassName = (LPUTF8)pszDebugClassName;
6061 pNewMD->m_pDebugMethodTable.SetValue(GetHalfBakedMethodTable());
6063 if (pszDebugMethodSignature == NULL)
6064 pNewMD->m_pszDebugMethodSignature = FormatSig(pNewMD,pNewMD->GetLoaderAllocator()->GetLowFrequencyHeap(),GetMemTracker());
6066 pNewMD->m_pszDebugMethodSignature = pszDebugMethodSignature;
6068 } // MethodTableBuilder::InitMethodDesc
6070 //*******************************************************************************
6072 // Used by BuildMethodTable
6075 MethodTableBuilder::AddMethodImplDispatchMapping(
6076 DispatchMapTypeID typeID,
6077 SLOT_INDEX slotNumber,
6078 bmtMDMethod * pImplMethod)
6080 STANDARD_VM_CONTRACT;
6082 MethodDesc * pMDImpl = pImplMethod->GetMethodDesc();
6084 // Look for an existing entry in the map.
6085 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6086 if (bmtVT->pDispatchMapBuilder->Find(typeID, slotNumber, it))
6088 // Throw if this entry has already previously been MethodImpl'd.
6089 if (it.IsMethodImpl())
6091 // NOTE: This is where we check for duplicate overrides. This is the easiest place to check
6092 // because duplicate overrides could in fact have separate MemberRefs to the same
6093 // member and so just comparing tokens at the very start would not be enough.
6094 if (it.GetTargetMD() != pMDImpl)
6096 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, pMDImpl->GetMemberDef());
6099 // This is the first MethodImpl. That's ok.
6102 it.SetTarget(pMDImpl);
6103 it.SetIsMethodImpl();
6106 // A mapping for this interface method does not exist, so insert it.
6109 bmtVT->pDispatchMapBuilder->InsertMDMapping(
6116 // Save the entry into the vtable as well, if it isn't an interface methodImpl
6117 if (typeID == DispatchMapTypeID::ThisClassID())
6119 bmtVT->SetVirtualMethodImpl(slotNumber, pImplMethod);
6121 } // MethodTableBuilder::AddMethodImplDispatchMapping
6123 //*******************************************************************************
6125 MethodTableBuilder::MethodImplCompareSignatures(
6126 bmtMethodHandle hDecl,
6127 bmtMethodHandle hImpl,
6128 DWORD dwConstraintErrorCode)
6132 PRECONDITION(!hDecl.IsNull());
6133 PRECONDITION(!hImpl.IsNull());
6134 PRECONDITION(TypeFromToken(hDecl.GetMethodSignature().GetToken()) == mdtMethodDef);
6135 PRECONDITION(TypeFromToken(hImpl.GetMethodSignature().GetToken()) == mdtMethodDef);
6138 const MethodSignature &declSig(hDecl.GetMethodSignature());
6139 const MethodSignature &implSig(hImpl.GetMethodSignature());
6141 if (!MethodSignature::SignaturesEquivalent(declSig, implSig))
6143 LOG((LF_CLASSLOADER, LL_INFO1000, "BADSIG placing MethodImpl: %x\n", declSig.GetToken()));
6144 BuildMethodTableThrowException(COR_E_TYPELOAD, IDS_CLASSLOAD_MI_BADSIGNATURE, declSig.GetToken());
6147 //now compare the method constraints
6148 if (!MetaSig::CompareMethodConstraints(&implSig.GetSubstitution(), implSig.GetModule(), implSig.GetToken(),
6149 &declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken()))
6151 BuildMethodTableThrowException(dwConstraintErrorCode, implSig.GetToken());
6155 //*******************************************************************************
6156 // We should have collected all the method impls. Cycle through them creating the method impl
6157 // structure that holds the information about which slots are overridden.
6159 MethodTableBuilder::PlaceMethodImpls()
6161 STANDARD_VM_CONTRACT;
6163 if(bmtMethodImpl->pIndex == 0)
6168 // Allocate some temporary storage. The number of overrides for a single method impl
6169 // cannot be greater then the number of vtable slots for classes. But for interfaces
6170 // it might contain overrides for other interface methods.
6171 DWORD dwMaxSlotSize = IsInterface() ? bmtMethod->dwNumberMethodImpls : bmtVT->cVirtualSlots;
6173 DWORD * slots = new (&GetThread()->m_MarshalAlloc) DWORD[dwMaxSlotSize];
6174 mdToken * tokens = new (&GetThread()->m_MarshalAlloc) mdToken[dwMaxSlotSize];
6175 RelativePointer<MethodDesc *> * replaced = new (&GetThread()->m_MarshalAlloc) RelativePointer<MethodDesc*>[dwMaxSlotSize];
6178 bmtMDMethod * pCurImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6180 DWORD slotIndex = 0;
6182 // The impls are sorted according to the method descs for the body of the method impl.
6183 // Loop through the impls until the next body is found. When a single body
6184 // has been done move the slots implemented and method descs replaced into the storage
6185 // found on the body method desc.
6187 { // collect information until we reach the next body
6189 tokens[slotIndex] = bmtMethodImpl->GetDeclarationToken(iEntry);
6191 // Get the declaration part of the method impl. It will either be a token
6192 // (declaration is on this type) or a method desc.
6193 bmtMethodHandle hDeclMethod = bmtMethodImpl->GetDeclarationMethod(iEntry);
6194 if(hDeclMethod.IsMDMethod())
6196 // The declaration is on the type being built
6197 bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod();
6199 mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken();
6200 if (bmtMethodImpl->IsBody(mdef))
6201 { // A method declared on this class cannot be both a decl and an impl
6202 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
6208 PlaceInterfaceDeclarationOnInterface(
6211 slots, // Adds override to the slot and replaced arrays.
6214 dwMaxSlotSize); // Increments count
6219 PlaceLocalDeclarationOnClass(
6222 slots, // Adds override to the slot and replaced arrays.
6225 dwMaxSlotSize); // Increments count
6230 bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();
6235 PlaceInterfaceDeclarationOnInterface(
6238 slots, // Adds override to the slot and replaced arrays.
6241 dwMaxSlotSize); // Increments count
6245 // Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
6246 if (pCurDeclMethod->GetOwningType()->IsInterface())
6249 PlaceInterfaceDeclarationOnClass(
6256 PlaceParentDeclarationOnClass(
6262 dwMaxSlotSize); // Increments count
6269 if(iEntry == bmtMethodImpl->pIndex)
6271 // We hit the end of the list so dump the current data and leave
6272 WriteMethodImplData(pCurImplMethod, slotIndex, slots, tokens, replaced);
6277 bmtMDMethod * pNextImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6279 if (pNextImplMethod != pCurImplMethod)
6281 // If we're moving on to a new body, dump the current data and reset the counter
6282 WriteMethodImplData(pCurImplMethod, slotIndex, slots, tokens, replaced);
6286 pCurImplMethod = pNextImplMethod;
6288 } // while(next != NULL)
6289 } // MethodTableBuilder::PlaceMethodImpls
6291 //*******************************************************************************
6293 MethodTableBuilder::WriteMethodImplData(
6294 bmtMDMethod * pImplMethod,
6298 RelativePointer<MethodDesc *> * rgDeclMD)
6300 STANDARD_VM_CONTRACT;
6302 // Use the number of overrides to
6303 // push information on to the method desc. We store the slots that
6304 // are overridden and the method desc that is replaced. That way
6305 // when derived classes need to determine if the method is to be
6306 // overridden then it can check the name against the replaced
6307 // method desc not the bodies name.
6310 //@TODO:NEWVTWORK: Determine methodImpl status so that we don't need this workaround.
6311 //@TODO:NEWVTWORK: This occurs when only interface decls are involved, since
6312 //@TODO:NEWVTWORK: these are stored in the dispatch map and not on the methoddesc.
6316 MethodImpl * pImpl = pImplMethod->GetMethodDesc()->GetMethodImpl();
6318 // Set the size of the info the MethodImpl needs to keep track of.
6319 pImpl->SetSize(GetLoaderAllocator()->GetHighFrequencyHeap(), GetMemTracker(), cSlots);
6323 // If we are currently builting an interface, the slots here has no meaning and we can skip it
6324 // Sort the two arrays in slot index order
6325 // This is required in MethodImpl::FindSlotIndex and MethodImpl::Iterator as we'll be using
6326 // binary search later
6327 for (DWORD i = 0; i < cSlots; i++)
6329 unsigned int min = i;
6330 for (DWORD j = i + 1; j < cSlots; j++)
6332 if (rgSlots[j] < rgSlots[min])
6340 MethodDesc * mTmp = rgDeclMD[i].GetValue();
6341 rgDeclMD[i].SetValue(rgDeclMD[min].GetValue());
6342 rgDeclMD[min].SetValue(mTmp);
6344 DWORD sTmp = rgSlots[i];
6345 rgSlots[i] = rgSlots[min];
6346 rgSlots[min] = sTmp;
6348 mdToken tTmp = rgTokens[i];
6349 rgTokens[i] = rgTokens[min];
6350 rgTokens[min] = tTmp;
6355 // Go and set the method impl
6356 pImpl->SetData(rgSlots, rgTokens, rgDeclMD);
6358 GetHalfBakedClass()->SetContainsMethodImpls();
6360 } // MethodTableBuilder::WriteMethodImplData
6362 //*******************************************************************************
6364 MethodTableBuilder::PlaceLocalDeclarationOnClass(
6365 bmtMDMethod * pDecl,
6366 bmtMDMethod * pImpl,
6368 RelativePointer<MethodDesc *> * replaced,
6370 DWORD dwMaxSlotSize)
6375 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6376 PRECONDITION(CheckPointer(pDecl));
6377 PRECONDITION(CheckPointer(pImpl));
6381 if (!bmtProp->fNoSanityChecks)
6383 ///////////////////////////////
6384 // Verify the signatures match
6386 MethodImplCompareSignatures(
6389 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_LOCAL_METHOD_IMPL);
6391 ///////////////////////////////
6392 // Validate the method impl.
6395 bmtMethodHandle(pDecl),
6396 bmtMethodHandle(pImpl));
6399 // Don't allow overrides for any of the four special runtime implemented delegate methods
6402 LPCUTF8 strMethodName = pDecl->GetMethodSignature().GetName();
6403 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
6404 (strcmp(strMethodName, "Invoke") == 0) ||
6405 (strcmp(strMethodName, "BeginInvoke") == 0) ||
6406 (strcmp(strMethodName, "EndInvoke") == 0))
6408 BuildMethodTableThrowException(
6409 IDS_CLASSLOAD_MI_CANNOT_OVERRIDE,
6410 pDecl->GetMethodSignature().GetToken());
6417 // Call helper to add it. Will throw if decl is already MethodImpl'd
6418 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6419 AddMethodImplDispatchMapping(
6420 DispatchMapTypeID::ThisClassID(),
6421 pDecl->GetSlotIndex(),
6424 // We implement this slot, record it
6425 ASSERT(*pSlotIndex < dwMaxSlotSize);
6426 slots[*pSlotIndex] = pDecl->GetSlotIndex();
6427 replaced[*pSlotIndex].SetValue(pDecl->GetMethodDesc());
6429 // increment the counter
6431 } // MethodTableBuilder::PlaceLocalDeclarationOnClass
6433 //*******************************************************************************
6434 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnClass(
6435 bmtRTMethod * pDecl,
6436 bmtMDMethod * pImpl)
6440 PRECONDITION(CheckPointer(pDecl));
6441 PRECONDITION(CheckPointer(pImpl));
6442 PRECONDITION(pDecl->GetMethodDesc()->IsInterface());
6443 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6446 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6447 MethodTable * pDeclMT = pDeclMD->GetMethodTable();
6449 // Note that the fact that pDecl is non-NULL means that we found the
6450 // declaration token to be owned by a declared interface for this type.
6452 if (!bmtProp->fNoSanityChecks)
6454 ///////////////////////////////
6455 // Verify the signatures match
6457 MethodImplCompareSignatures(
6460 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6462 ///////////////////////////////
6463 // Validate the method impl.
6466 bmtMethodHandle(pDecl),
6467 bmtMethodHandle(pImpl));
6473 // Note that we need only one DispatchMapTypeID for this interface (though there might be more if there
6474 // are duplicates). The first one is easy to get, but we could (in theory) use the last one or a random
6476 // Q: Why don't we have to place this method for all duplicate interfaces? Because VSD knows about
6477 // duplicates and finds the right (latest) implementation for us - see
6478 // code:MethodTable::MethodDataInterfaceImpl::PopulateNextLevel#ProcessAllDuplicates.
6479 UINT32 cInterfaceDuplicates;
6480 DispatchMapTypeID firstDispatchMapTypeID;
6481 ComputeDispatchMapTypeIDs(
6483 &pDecl->GetMethodSignature().GetSubstitution(),
6484 &firstDispatchMapTypeID,
6486 &cInterfaceDuplicates);
6487 CONSISTENCY_CHECK(cInterfaceDuplicates >= 1);
6488 CONSISTENCY_CHECK(firstDispatchMapTypeID.IsImplementedInterface());
6490 // Call helper to add it. Will throw if decl is already MethodImpl'd
6491 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6492 AddMethodImplDispatchMapping(
6493 firstDispatchMapTypeID,
6494 pDecl->GetSlotIndex(),
6497 #ifdef FEATURE_PREJIT
6498 if (IsCompilationProcess())
6501 // Mark this interface as overridable. It is used to skip generation of
6502 // CCWs stubs during NGen (see code:MethodNeedsReverseComStub)
6504 if (!IsMdFinal(pImpl->GetDeclAttrs()))
6506 pDeclMT->GetWriteableDataForWrite()->SetIsOverridingInterface();
6512 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
6513 { // We injected interface duplicates
6515 // We have to MethodImpl all interface duplicates as all duplicates are 'declared on type' (see
6516 // code:#InjectInterfaceDuplicates_ApproxInterfaces)
6517 DispatchMapTypeID * rgDispatchMapTypeIDs = (DispatchMapTypeID *)_alloca(sizeof(DispatchMapTypeID) * cInterfaceDuplicates);
6518 ComputeDispatchMapTypeIDs(
6520 &pDecl->GetMethodSignature().GetSubstitution(),
6521 rgDispatchMapTypeIDs,
6522 cInterfaceDuplicates,
6523 &cInterfaceDuplicates);
6524 for (UINT32 nInterfaceDuplicate = 1; nInterfaceDuplicate < cInterfaceDuplicates; nInterfaceDuplicate++)
6526 // Add MethodImpl record for each injected interface duplicate
6527 AddMethodImplDispatchMapping(
6528 rgDispatchMapTypeIDs[nInterfaceDuplicate],
6529 pDecl->GetSlotIndex(),
6534 } // MethodTableBuilder::PlaceInterfaceDeclarationOnClass
6536 //*******************************************************************************
6537 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnInterface(
6538 bmtMethodHandle hDecl,
6541 RelativePointer<MethodDesc *> * replaced,
6543 DWORD dwMaxSlotSize)
6547 PRECONDITION(CheckPointer(pImpl));
6548 PRECONDITION(IsInterface());
6549 PRECONDITION(hDecl.GetMethodDesc()->IsInterface());
6552 MethodDesc * pDeclMD = hDecl.GetMethodDesc();
6554 if (!bmtProp->fNoSanityChecks)
6556 ///////////////////////////////
6557 // Verify the signatures match
6559 MethodImplCompareSignatures(
6561 bmtMethodHandle(pImpl),
6562 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6564 ///////////////////////////////
6565 // Validate the method impl.
6567 TestMethodImpl(hDecl, bmtMethodHandle(pImpl));
6570 // We implement this slot, record it
6571 ASSERT(*pSlotIndex < dwMaxSlotSize);
6572 slots[*pSlotIndex] = hDecl.GetSlotIndex();
6573 replaced[*pSlotIndex].SetValue(pDeclMD);
6575 // increment the counter
6577 } // MethodTableBuilder::PlaceInterfaceDeclarationOnInterface
6579 //*******************************************************************************
6581 MethodTableBuilder::PlaceParentDeclarationOnClass(
6582 bmtRTMethod * pDecl,
6583 bmtMDMethod * pImpl,
6585 RelativePointer<MethodDesc *> * replaced,
6587 DWORD dwMaxSlotSize)
6591 PRECONDITION(CheckPointer(pDecl));
6592 PRECONDITION(CheckPointer(pImpl));
6593 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6594 PRECONDITION(CheckPointer(GetParentMethodTable()));
6597 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6599 // Note that the fact that pDecl is non-NULL means that we found the
6600 // declaration token to be owned by a parent type.
6602 if (!bmtProp->fNoSanityChecks)
6604 /////////////////////////////////////////
6605 // Verify that the signatures match
6607 MethodImplCompareSignatures(
6610 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_PARENT_METHOD_IMPL);
6612 ////////////////////////////////
6613 // Verify rules of method impls
6616 bmtMethodHandle(pDecl),
6617 bmtMethodHandle(pImpl));
6623 // Call helper to add it. Will throw if DECL is already MethodImpl'd
6624 AddMethodImplDispatchMapping(
6625 DispatchMapTypeID::ThisClassID(),
6629 // We implement this slot, record it
6630 ASSERT(*pSlotIndex < dwMaxSlotSize);
6631 slots[*pSlotIndex] = pDeclMD->GetSlot();
6632 replaced[*pSlotIndex].SetValue(pDeclMD);
6634 // increment the counter
6636 } // MethodTableBuilder::PlaceParentDeclarationOnClass
6638 //*******************************************************************************
6639 // This will validate that all interface methods that were matched during
6640 // layout also validate against type constraints.
6642 VOID MethodTableBuilder::ValidateInterfaceMethodConstraints()
6644 STANDARD_VM_CONTRACT;
6646 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6647 for (; it.IsValid(); it.Next())
6649 if (it.GetTypeID() != DispatchMapTypeID::ThisClassID())
6651 bmtRTType * pItf = bmtInterface->pInterfaceMap[it.GetTypeID().GetInterfaceNum()].GetInterfaceType();
6653 // Grab the method token
6654 MethodTable * pMTItf = pItf->GetMethodTable();
6655 CONSISTENCY_CHECK(CheckPointer(pMTItf->GetMethodDescForSlot(it.GetSlotNumber())));
6656 mdMethodDef mdTok = pItf->GetMethodTable()->GetMethodDescForSlot(it.GetSlotNumber())->GetMemberDef();
6658 // Default to the current module. The code immediately below determines if this
6659 // assumption is incorrect.
6660 Module * pTargetModule = GetModule();
6662 // Get the module of the target method. Get it through the chunk to
6663 // avoid triggering the assert that MethodTable is non-NULL. It may
6664 // be null since it may belong to the type we're building right now.
6665 MethodDesc * pTargetMD = it.GetTargetMD();
6667 // If pTargetMT is null, this indicates that the target MethodDesc belongs
6668 // to the current type. Otherwise, the MethodDesc MUST be owned by a parent
6669 // of the type we're building.
6670 BOOL fTargetIsOwnedByParent = !pTargetMD->GetMethodTablePtr()->IsNull();
6672 // If the method is owned by a parent, we need to use the parent's module,
6673 // and we must construct the substitution chain all the way up to the parent.
6674 const Substitution *pSubstTgt = NULL;
6675 if (fTargetIsOwnedByParent)
6677 CONSISTENCY_CHECK(CheckPointer(GetParentType()));
6678 bmtRTType *pTargetType = bmtRTType::FindType(GetParentType(), pTargetMD->GetMethodTable());
6679 pSubstTgt = &pTargetType->GetSubstitution();
6680 pTargetModule = pTargetType->GetModule();
6683 // Now compare the method constraints.
6684 if (!MetaSig::CompareMethodConstraints(pSubstTgt,
6686 pTargetMD->GetMemberDef(),
6687 &pItf->GetSubstitution(),
6688 pMTItf->GetModule(),
6691 LOG((LF_CLASSLOADER, LL_INFO1000,
6692 "BADCONSTRAINTS on interface method implementation: %x\n", pTargetMD));
6693 // This exception will be due to an implicit implementation, since explicit errors
6694 // will be detected in MethodImplCompareSignatures (for now, anyway).
6695 CONSISTENCY_CHECK(!it.IsMethodImpl());
6696 DWORD idsError = it.IsMethodImpl() ?
6697 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL :
6698 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_IMPLEMENTATION;
6699 if (fTargetIsOwnedByParent)
6701 DefineFullyQualifiedNameForClass();
6702 LPCUTF8 szClassName = GetFullyQualifiedNameForClassNestedAware(pTargetMD->GetMethodTable());
6703 LPCUTF8 szMethodName = pTargetMD->GetName();
6706 // allocate enough room for "<class>.<method>\0"
6707 size_t cchFullName = strlen(szClassName) + 1 + strlen(szMethodName) + 1;
6708 LPUTF8 szFullName = (LPUTF8) qb.AllocThrows(cchFullName);
6709 strcpy_s(szFullName, cchFullName, szClassName);
6710 strcat_s(szFullName, cchFullName, ".");
6711 strcat_s(szFullName, cchFullName, szMethodName);
6713 BuildMethodTableThrowException(idsError, szFullName);
6717 BuildMethodTableThrowException(idsError, pTargetMD->GetMemberDef());
6722 } // MethodTableBuilder::ValidateInterfaceMethodConstraints
6724 //*******************************************************************************
6725 // Used to allocate and initialize MethodDescs (both the boxed and unboxed entrypoints)
6726 VOID MethodTableBuilder::AllocAndInitMethodDescs()
6728 STANDARD_VM_CONTRACT;
6731 // Go over all MethodDescs and create smallest number of MethodDescChunks possible.
6733 // Iterate over all methods and start a new chunk only if:
6734 // - Token range (upper 24 bits of the method token) has changed.
6735 // - The maximum size of the chunk has been reached.
6738 int currentTokenRange = -1; // current token range
6739 SIZE_T sizeOfMethodDescs = 0; // current running size of methodDesc chunk
6740 int startIndex = 0; // start of the current chunk (index into bmtMethod array)
6742 DeclaredMethodIterator it(*this);
6745 int tokenRange = GetTokenRange(it.Token());
6747 // This code assumes that iterator returns tokens in ascending order. If this assumption does not hold,
6748 // the code will still work with small performance penalty (method desc chunk layout will be less efficient).
6749 _ASSERTE(tokenRange >= currentTokenRange);
6751 SIZE_T size = MethodDesc::GetBaseSize(GetMethodClassification(it->GetMethodType()));
6753 // Add size of optional slots
6755 if (it->GetMethodImplType() == METHOD_IMPL)
6756 size += sizeof(MethodImpl);
6758 if (it->GetSlotIndex() >= bmtVT->cVtableSlots)
6759 size += sizeof(MethodDesc::NonVtableSlot); // slot
6761 if (NeedsNativeCodeSlot(*it))
6762 size += sizeof(MethodDesc::NativeCodeSlot);
6764 // See comment in AllocAndInitMethodDescChunk
6765 if (NeedsTightlyBoundUnboxingStub(*it))
6769 if (bmtGenerics->GetNumGenericArgs() == 0) {
6770 size += sizeof(MethodDesc::NonVtableSlot);
6773 bmtVT->cVtableSlots++;
6777 #ifndef CROSSGEN_COMPILE
6778 if (tokenRange != currentTokenRange ||
6779 sizeOfMethodDescs + size > MethodDescChunk::MaxSizeOfMethodDescs)
6780 #endif // CROSSGEN_COMPILE
6782 if (sizeOfMethodDescs != 0)
6784 AllocAndInitMethodDescChunk(startIndex, it.CurrentIndex() - startIndex, sizeOfMethodDescs);
6785 startIndex = it.CurrentIndex();
6788 currentTokenRange = tokenRange;
6789 sizeOfMethodDescs = 0;
6792 sizeOfMethodDescs += size;
6795 if (sizeOfMethodDescs != 0)
6797 AllocAndInitMethodDescChunk(startIndex, NumDeclaredMethods() - startIndex, sizeOfMethodDescs);
6801 //*******************************************************************************
6802 // Allocates and initializes one method desc chunk.
6805 // startIndex - index of first method in bmtMethod array.
6806 // count - number of methods in this chunk (contiguous region from startIndex)
6807 // sizeOfMethodDescs - total expected size of MethodDescs in this chunk
6809 // Used by AllocAndInitMethodDescs.
6811 VOID MethodTableBuilder::AllocAndInitMethodDescChunk(COUNT_T startIndex, COUNT_T count, SIZE_T sizeOfMethodDescs)
6815 PRECONDITION(sizeOfMethodDescs <= MethodDescChunk::MaxSizeOfMethodDescs);
6818 void * pMem = GetMemTracker()->Track(
6819 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TADDR) + sizeof(MethodDescChunk) + sizeOfMethodDescs)));
6821 // Skip pointer to temporary entrypoints
6822 MethodDescChunk * pChunk = (MethodDescChunk *)((BYTE*)pMem + sizeof(TADDR));
6824 COUNT_T methodDescCount = 0;
6826 SIZE_T offset = sizeof(MethodDescChunk);
6829 #pragma warning(push)
6830 #pragma warning(disable:22019) // Suppress PREFast warning about integer underflow
6832 for (COUNT_T i = 0; i < count; i++)
6834 #pragma warning(pop)
6838 bmtMDMethod * pMDMethod = (*bmtMethod)[static_cast<SLOT_INDEX>(startIndex + i)];
6840 MethodDesc * pMD = (MethodDesc *)((BYTE *)pChunk + offset);
6842 pMD->SetChunkIndex(pChunk);
6844 InitNewMethodDesc(pMDMethod, pMD);
6847 #pragma warning(push)
6848 #pragma warning(disable:22018) // Suppress PREFast warning about integer underflow
6850 offset += pMD->SizeOf();
6852 #pragma warning(pop)
6857 // If we're a value class, we want to create duplicate slots
6858 // and MethodDescs for all methods in the vtable
6859 // section (i.e. not non-virtual instance methods or statics).
6860 // In the name of uniformity it would be much nicer
6861 // if we created _all_ value class BoxedEntryPointStubs at this point.
6862 // However, non-virtual instance methods only require unboxing
6863 // stubs in the rare case that we create a delegate to such a
6864 // method, and thus it would be inefficient to create them on
6865 // loading: after all typical structs will have many non-virtual
6866 // instance methods.
6868 // Unboxing stubs for non-virtual instance methods are created
6869 // in code:MethodDesc::FindOrCreateAssociatedMethodDesc.
6871 if (NeedsTightlyBoundUnboxingStub(pMDMethod))
6873 MethodDesc * pUnboxedMD = (MethodDesc *)((BYTE *)pChunk + offset);
6875 //////////////////////////////////
6876 // Initialize the new MethodDesc
6878 // <NICE> memcpy operations on data structures like MethodDescs are extremely fragile
6879 // and should not be used. We should go to the effort of having proper constructors
6880 // in the MethodDesc class. </NICE>
6882 memcpy(pUnboxedMD, pMD, pMD->SizeOf());
6884 // Reset the chunk index
6885 pUnboxedMD->SetChunkIndex(pChunk);
6887 if (bmtGenerics->GetNumGenericArgs() == 0) {
6888 pUnboxedMD->SetHasNonVtableSlot();
6891 //////////////////////////////////////////////////////////
6892 // Modify the original MethodDesc to be an unboxing stub
6894 pMD->SetIsUnboxingStub();
6896 ////////////////////////////////////////////////////////////////////
6897 // Add the new MethodDesc to the non-virtual portion of the vtable
6899 if (!bmtVT->AddUnboxedMethod(pMDMethod))
6900 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
6902 pUnboxedMD->SetSlot(pMDMethod->GetUnboxedSlotIndex());
6903 pMDMethod->SetUnboxedMethodDesc(pUnboxedMD);
6905 offset += pUnboxedMD->SizeOf();
6909 _ASSERTE(offset == sizeof(MethodDescChunk) + sizeOfMethodDescs);
6911 pChunk->SetSizeAndCount((ULONG)sizeOfMethodDescs, methodDescCount);
6913 GetHalfBakedClass()->AddChunk(pChunk);
6916 //*******************************************************************************
6918 MethodTableBuilder::NeedsTightlyBoundUnboxingStub(bmtMDMethod * pMDMethod)
6920 STANDARD_VM_CONTRACT;
6922 return IsValueClass() &&
6923 !IsMdStatic(pMDMethod->GetDeclAttrs()) &&
6924 IsMdVirtual(pMDMethod->GetDeclAttrs()) &&
6925 (pMDMethod->GetMethodType() != METHOD_TYPE_INSTANTIATED) &&
6926 !IsMdRTSpecialName(pMDMethod->GetDeclAttrs());
6929 //*******************************************************************************
6931 MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
6933 LIMITED_METHOD_CONTRACT;
6936 #ifdef FEATURE_TIERED_COMPILATION
6937 // Keep in-sync with MethodDesc::DetermineAndSetIsEligibleForTieredCompilation()
6938 if (g_pConfig->TieredCompilation() &&
6939 (pMDMethod->GetMethodType() == METHOD_TYPE_NORMAL || pMDMethod->GetMethodType() == METHOD_TYPE_INSTANTIATED))
6945 #if defined(FEATURE_JIT_PITCHING)
6946 if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchEnabled) != 0) &&
6947 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchMemThreshold) != 0))
6951 return GetModule()->IsEditAndContinueEnabled();
6954 //*******************************************************************************
6956 MethodTableBuilder::AllocAndInitDictionary()
6958 STANDARD_VM_CONTRACT;
6960 // Allocate dictionary layout used by all compatible instantiations
6962 if (bmtGenerics->fSharedByGenericInstantiations && !bmtGenerics->fContainsGenericVariables)
6964 // We use the number of methods as a heuristic for the number of slots in the dictionary
6965 // attached to shared class method tables.
6966 // If there are no declared methods then we have no slots, and we will never do any token lookups
6969 // - Classes with a small number of methods (2-3) tend to be more likely to use new slots,
6970 // i.e. further methods tend to reuse slots from previous methods.
6971 // = treat all classes with only 2-3 methods as if they have an extra method.
6972 // - Classes with more generic parameters tend to use more slots.
6973 // = multiply by 1.5 for 2 params or more
6975 DWORD numMethodsAdjusted =
6976 (bmtMethod->dwNumDeclaredNonAbstractMethods == 0)
6978 : (bmtMethod->dwNumDeclaredNonAbstractMethods < 3)
6980 : bmtMethod->dwNumDeclaredNonAbstractMethods;
6982 _ASSERTE(bmtGenerics->GetNumGenericArgs() != 0);
6983 DWORD nTypeFactorBy2 = (bmtGenerics->GetNumGenericArgs() == 1)
6987 DWORD estNumTypeSlots = (numMethodsAdjusted * nTypeFactorBy2 + 2) / 3;
6988 // estNumTypeSlots should fit in a WORD as long as we maintain the current
6989 // limit on the number of methods in a type (approx 2^16).
6990 _ASSERTE(FitsIn<WORD>(estNumTypeSlots));
6991 WORD numTypeSlots = static_cast<WORD>(estNumTypeSlots);
6993 if (numTypeSlots > 0)
6995 // Dictionary layout is an optional field on EEClass, so ensure the optional field descriptor has
6997 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
6998 GetHalfBakedClass()->SetDictionaryLayout(DictionaryLayout::Allocate(numTypeSlots, bmtAllocator, m_pAllocMemTracker));
7004 //*******************************************************************************
7006 // Used by BuildMethodTable
7008 // Compute the set of interfaces which are equivalent. Duplicates in the interface map
7009 // will be placed into different equivalence sets unless they participate in type equivalence.
7010 // This is a bit odd, but it turns out we only need to know about equivalence classes if
7011 // there is type equivalence involved in the interface, and not detecting, or detecting equivalence
7012 // in other cases does not result in differing behavior.
7014 // By restricting the reasons for having equivalence matches, we reduce the algorithm from one which
7015 // is O(n*n) best case to an algorithm which will typically execute something more like O(m*n) best case time
7016 // where m is the number of generic interface (although still n*n in worst case). The assumption is that equivalent
7017 // and generic interfaces are relatively rare.
7019 MethodTableBuilder::ComputeInterfaceMapEquivalenceSet()
7021 STANDARD_VM_CONTRACT;
7023 UINT32 nextEquivalenceSet = 1;
7025 for (DWORD dwCurInterface = 0;
7026 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7029 // Keep track of the current interface we are trying to calculate the equivalence set of
7030 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7031 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7032 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7033 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7035 UINT32 currentEquivalenceSet = 0;
7037 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7038 if (pCurItfMT->HasTypeEquivalence() || pCurItfMT->HasInstantiation())
7040 for (DWORD dwCurInterfaceCompare = 0;
7041 dwCurInterfaceCompare < dwCurInterface;
7042 dwCurInterfaceCompare++)
7044 // Keep track of the current interface we are trying to calculate the equivalence set of
7045 bmtInterfaceEntry * pCompareItfEntry = &bmtInterface->pInterfaceMap[dwCurInterfaceCompare];
7046 bmtRTType * pCompareItf = pCompareItfEntry->GetInterfaceType();
7047 MethodTable * pCompareItfMT = pCompareItf->GetMethodTable();
7048 const Substitution * pCompareItfSubst = &pCompareItf->GetSubstitution();
7050 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7051 if (pCompareItfMT->HasTypeEquivalence() || pCompareItfMT->HasInstantiation())
7053 if (MetaSig::CompareTypeDefsUnderSubstitutions(pCurItfMT,
7059 currentEquivalenceSet = pCompareItfEntry->GetInterfaceEquivalenceSet();
7060 // Use the equivalence set of the interface map entry we just found
7061 pCurItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7062 // Update the interface map entry we just found to indicate that it is part of an equivalence
7063 // set with multiple entries.
7064 pCompareItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7071 // If we did not find an equivalent interface above, use the next available equivalence set indicator
7072 if (currentEquivalenceSet == 0)
7074 pCurItfEntry->SetInterfaceEquivalenceSet(nextEquivalenceSet, false);
7075 nextEquivalenceSet++;
7080 //*******************************************************************************
7082 // Used by PlaceInterfaceMethods
7084 // Given an interface in our interface map, and a particular method on that interface, place
7085 // a method from the parent types implementation of an equivalent interface into that method
7086 // slot. Used by PlaceInterfaceMethods to make equivalent interface implementations have the
7087 // same behavior as if the parent interface was implemented on this type instead of an equivalent interface.
7089 // This logic is used in situations such as below. I and I' are equivalent interfaces
7093 // {void I.Method() { } }
7094 // interface IOther : I' {}
7095 // class Derived : IOther
7096 // { virtual void Method() {}}
7098 // We should Map I'.Method to Base.Method, not Derived.Method
7102 // { virtual void Method() }
7103 // interface IOther : I' {}
7104 // class Derived : IOther
7105 // { virtual void Method() {}}
7107 // We should map I'.Method to Base.Method, not Derived.Method
7110 // {void I.Method() { } }
7111 // class Derived : I'
7114 // We should Map I'.Method to Base.Method, and not throw TypeLoadException
7116 #ifdef FEATURE_COMINTEROP
7118 MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(
7119 bmtInterfaceEntry::InterfaceSlotIterator & itfSlotIt,
7120 bmtInterfaceEntry * pCurItfEntry,
7121 DispatchMapTypeID ** prgInterfaceDispatchMapTypeIDs,
7122 DWORD dwCurInterface)
7124 STANDARD_VM_CONTRACT;
7126 bmtRTMethod * pCurItfMethod = itfSlotIt->Decl().AsRTMethod();
7128 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7133 // For every equivalent interface entry that was actually implemented by parent, then look at equivalent method slot on that entry
7134 // and if it matches and has a slot implementation, then record and continue
7135 for (DWORD dwEquivalentInterface = 0;
7136 (dwEquivalentInterface < bmtInterface->dwInterfaceMapSize) && (itfSlotIt->Impl() == INVALID_SLOT_INDEX);
7137 dwEquivalentInterface++)
7139 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7140 bmtRTType * pEquivItf = pEquivItfEntry->GetInterfaceType();
7141 MethodTable * pEquivItfMT = pEquivItf->GetMethodTable();
7142 const Substitution * pEquivItfSubst = &pEquivItf->GetSubstitution();
7143 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7148 if (!pEquivItfEntry->IsImplementedByParent())
7150 // Not implemented by parent
7154 WORD slot = static_cast<WORD>(itfSlotIt.CurrentIndex());
7155 BOOL fFound = FALSE;
7157 // Determine which slot on the equivalent interface would map to the slot we are attempting to fill
7158 // in with an implementation.
7159 WORD otherMTSlot = GetEquivalentMethodSlot(pCurItfEntry->GetInterfaceType()->GetMethodTable(),
7160 pEquivItfEntry->GetInterfaceType()->GetMethodTable(),
7166 UINT32 cInterfaceDuplicates;
7167 if (*prgInterfaceDispatchMapTypeIDs == NULL)
7169 *prgInterfaceDispatchMapTypeIDs =
7170 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7173 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7174 ComputeDispatchMapTypeIDs(
7177 *prgInterfaceDispatchMapTypeIDs,
7178 bmtInterface->dwInterfaceMapSize,
7179 &cInterfaceDuplicates);
7180 // There cannot be more duplicates than number of interfaces
7181 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7182 _ASSERTE(cInterfaceDuplicates > 0);
7184 // NOTE: This override does not cache the resulting MethodData object
7185 MethodTable::MethodDataWrapper hParentData;
7186 hParentData = MethodTable::GetMethodData(
7187 *prgInterfaceDispatchMapTypeIDs,
7188 cInterfaceDuplicates,
7190 GetParentMethodTable());
7192 SLOT_INDEX slotIndex = static_cast<SLOT_INDEX>
7193 (hParentData->GetImplSlotNumber(static_cast<UINT32>(otherMTSlot)));
7195 // Interface is implemented on parent abstract type and this particular slot was not implemented
7196 if (slotIndex == INVALID_SLOT_INDEX)
7201 bmtMethodSlot & parentSlotImplementation = (*bmtParent->pSlotTable)[slotIndex];
7202 bmtMethodHandle & parentImplementation = parentSlotImplementation.Impl();
7204 // Check to verify that the equivalent slot on the equivalent interface actually matches the method
7205 // on the current interface. If not, then the slot is not a match, and we should search other interfaces
7206 // for an implementation of the method.
7207 if (!MethodSignature::SignaturesEquivalent(pCurItfMethod->GetMethodSignature(), parentImplementation.GetMethodSignature()))
7212 itfSlotIt->Impl() = slotIndex;
7214 MethodDesc * pMD = hParentData->GetImplMethodDesc(static_cast<UINT32>(otherMTSlot));
7216 DispatchMapTypeID dispatchMapTypeID =
7217 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7218 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7220 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7225 } // MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot
7226 #endif // FEATURE_COMINTEROP
7228 //*******************************************************************************
7230 // Used by BuildMethodTable
7233 // If we are a class, then there may be some unplaced vtable methods (which are by definition
7234 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
7235 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
7236 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
7237 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
7238 // map for all interfaces as they are placed.
7240 // If we are an interface, then all methods are already placed. Fill out the interface map for
7241 // interfaces as they are placed.
7243 // BEHAVIOUR (based on Partition II: 11.2, not including MethodImpls)
7244 // C is current class, P is a parent class, I is the interface being implemented
7246 // FOREACH interface I implemented by this class C
7247 // FOREACH method I::M
7248 // IF I is EXPLICITLY implemented by C
7249 // IF some method C::M matches I::M
7250 // USE C::M as implementation for I::M
7251 // ELIF we inherit a method P::M that matches I::M
7252 // USE P::M as implementation for I::M
7255 // IF I::M lacks implementation
7256 // IF some method C::M matches I::M
7257 // USE C::M as implementation for I::M
7258 // ELIF we inherit a method P::M that matches I::M
7259 // USE P::M as implementation for I::M
7260 // ELIF I::M was implemented by the parent type with method Parent::M
7261 // USE Parent::M for the implementation of I::M // VSD does this by default if we really
7262 // // implemented I on the parent type, but
7263 // // equivalent interfaces need to make this
7273 MethodTableBuilder::PlaceInterfaceMethods()
7275 STANDARD_VM_CONTRACT;
7277 BOOL fParentInterface;
7278 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs = NULL;
7280 for (DWORD dwCurInterface = 0;
7281 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7284 // Default to being implemented by the current class
7285 fParentInterface = FALSE;
7287 // Keep track of the current interface we are trying to place
7288 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7289 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7290 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7291 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7294 // There are three reasons why an interface could be in the implementation list
7295 // 1. Inherited from parent
7296 // 2. Explicitly declared in the implements list
7297 // 3. Implicitly declared through the implements list of an explicitly declared interface
7299 // The reason these cases need to be distinguished is that an inherited interface that is
7300 // also explicitly redeclared in the implements list must be fully reimplemented using the
7301 // virtual methods of this type (thereby using matching methods in this type that may have
7302 // a different slot than an inherited method, but hidden it by name & sig); however all
7303 // implicitly redeclared interfaces should not be fully reimplemented if they were also
7304 // inherited from the parent.
7307 // interface I1 : I2
7311 // In this example I1 must be fully reimplemented on B, but B can inherit the implementation
7315 if (pCurItfEntry->IsImplementedByParent())
7317 if (!pCurItfEntry->IsDeclaredOnType())
7319 fParentInterface = TRUE;
7323 bool fEquivalentInterfaceImplementedByParent = pCurItfEntry->IsImplementedByParent();
7324 bool fEquivalentInterfaceDeclaredOnType = pCurItfEntry->IsDeclaredOnType();
7326 if (pCurItfEntry->InEquivalenceSetWithMultipleEntries())
7328 for (DWORD dwEquivalentInterface = 0;
7329 dwEquivalentInterface < bmtInterface->dwInterfaceMapSize;
7330 dwEquivalentInterface++)
7332 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7333 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7338 if (pEquivItfEntry->IsImplementedByParent())
7340 fEquivalentInterfaceImplementedByParent = true;
7342 if (pEquivItfEntry->IsDeclaredOnType())
7344 fEquivalentInterfaceDeclaredOnType = true;
7347 if (fEquivalentInterfaceDeclaredOnType && fEquivalentInterfaceImplementedByParent)
7352 bool fParentInterfaceEquivalent = fEquivalentInterfaceImplementedByParent && !fEquivalentInterfaceDeclaredOnType;
7354 CONSISTENCY_CHECK(!fParentInterfaceEquivalent || HasParent());
7356 if (fParentInterfaceEquivalent)
7358 // In the case the fParentInterface is TRUE, virtual overrides are enough and the interface
7359 // does not have to be explicitly (re)implemented. The only exception is if the parent is
7360 // abstract, in which case an inherited interface may not be fully implemented yet.
7361 // This is an optimization that allows us to skip the more expensive slot filling in below.
7362 // Note that the check here is for fParentInterface and not for fParentInterfaceEquivalent.
7363 // This is necessary as if the interface is not actually implemented on the parent type we will
7364 // need to fill in the slot table below.
7365 if (fParentInterface && !GetParentMethodTable()->IsAbstract())
7371 // We will reach here in two cases.
7372 // 1 .The parent is abstract and the interface has been declared on the parent,
7373 // and possibly partially implemented, so we need to populate the
7374 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7376 // 2 .The the interface has not been declared on the parent,
7377 // but an equivalent interface has been. So we need to populate the
7378 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7379 // information from one of the parent equivalent interfaces. We may or may not
7380 // find implementations for all of the methods on the interface on the parent type.
7381 // The parent type may or may not be abstract.
7383 MethodTable::MethodDataWrapper hParentData;
7384 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
7386 if (rgInterfaceDispatchMapTypeIDs == NULL)
7388 rgInterfaceDispatchMapTypeIDs =
7389 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7392 if (pCurItfEntry->IsImplementedByParent())
7394 UINT32 cInterfaceDuplicates;
7395 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7396 ComputeDispatchMapTypeIDs(
7399 rgInterfaceDispatchMapTypeIDs,
7400 bmtInterface->dwInterfaceMapSize,
7401 &cInterfaceDuplicates);
7402 // There cannot be more duplicates than number of interfaces
7403 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7404 _ASSERTE(cInterfaceDuplicates > 0);
7406 //#InterfaceMap_UseParentInterfaceImplementations
7407 // We rely on the fact that interface map of parent type is subset of this type (incl.
7408 // duplicates), see code:#InterfaceMap_SupersetOfParent
7409 // NOTE: This override does not cache the resulting MethodData object
7410 hParentData = MethodTable::GetMethodData(
7411 rgInterfaceDispatchMapTypeIDs,
7412 cInterfaceDuplicates,
7414 GetParentMethodTable());
7416 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7417 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7418 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7420 itfSlotIt->Impl() = static_cast<SLOT_INDEX>
7421 (hParentData->GetImplSlotNumber(static_cast<UINT32>(itfSlotIt.CurrentIndex())));
7424 #ifdef FEATURE_COMINTEROP
7427 // Iterate through the methods on the interface, and if they have a slot which was filled in
7428 // on an equivalent interface inherited from the parent fill in the appropriate slot.
7429 // This code path is only used when there is an implicit implementation of an interface
7430 // that was not implemented on a parent type, but there was an equivalent interface implemented
7431 // on a parent type.
7432 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7433 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7434 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7436 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7439 #endif // FEATURE_COMINTEROP
7443 #ifdef FEATURE_COMINTEROP
7444 // WinRT types always use methodimpls to line up methods with interface implementations, so we do not want to allow implicit
7445 // interface implementations to kick in. This can especially cause problems with redirected interfaces, where the underlying
7446 // runtimeclass doesn't actually implement the interfaces we claim it does. For example, a WinRT class which implements both
7447 // IVector<int> and ICalculator will be projected as implementing IList<int> and ICalculator. In this case, we do not want the
7448 // ICalculator Add(int) method to get lined up with the ICollection<int> Add method, since that will cause us to dispatch to the
7449 // wrong underlying COM interface.
7451 // There are a special WinRT types in mscorlib (notably DisposableRuntimeClass) which do implement interfaces in the normal way
7452 // so we skip this check for them. (Note that we can't use a methodimpl directly in mscorlib, since ComImport classes are
7453 // forbidden from having implementation code by the C# compiler).
7454 if (GetHalfBakedClass()->IsProjectedFromWinRT() && !GetModule()->IsSystem())
7458 #endif // FEATURE_COMINTEROP
7460 // For each method declared in this interface
7461 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7462 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7463 for (; !itfSlotIt.AtEnd(); ++itfSlotIt)
7465 if (fParentInterfaceEquivalent)
7467 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7468 { // If this interface is not explicitly declared on this class, and the interface slot has already been
7469 // given an implementation, then the only way to provide a new implementation is through an override
7470 // or through a MethodImpl. This is necessary in addition to the continue statement before this for
7471 // loop because an abstract interface can still have a partial implementation and it is necessary to
7472 // skip those interface slots that have already been satisfied.
7477 BOOL fFoundMatchInBuildingClass = FALSE;
7478 bmtInterfaceSlotImpl & curItfSlot = *itfSlotIt;
7479 bmtRTMethod * pCurItfMethod = curItfSlot.Decl().AsRTMethod();
7480 const MethodSignature & curItfMethodSig = pCurItfMethod->GetMethodSignature();
7483 // First, try to find the method explicitly declared in our class
7486 DeclaredMethodIterator methIt(*this);
7487 while (methIt.Next())
7489 // Note that non-publics can legally be exposed via an interface, but only
7490 // through methodImpls.
7491 if (IsMdVirtual(methIt.Attrs()) && IsMdPublic(methIt.Attrs()))
7494 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(methIt.Name()))
7495 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", methIt.Name()));
7498 if (pCurItfMethod->GetMethodSignature().Equivalent(methIt->GetMethodSignature()))
7500 fFoundMatchInBuildingClass = TRUE;
7501 curItfSlot.Impl() = methIt->GetSlotIndex();
7503 DispatchMapTypeID dispatchMapTypeID =
7504 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7505 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7507 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7508 methIt->GetMethodDesc(),
7514 } // end ... try to find method
7517 // The ECMA CLR spec states that a type will inherit interface implementations
7518 // and that explicit re-declaration of an inherited interface will try to match
7519 // only newslot methods with methods in the re-declared interface (note that
7520 // this also takes care of matching against unsatisfied interface methods in
7521 // the abstract parent type scenario).
7523 // So, if the interface was not declared on a parent and we haven't found a
7524 // newslot method declared on this type as a match, search all remaining
7525 // public virtual methods (including overrides declared on this type) for a
7528 // Please see bug VSW577403 and VSW593884 for details of this breaking change.
7530 if (!fFoundMatchInBuildingClass &&
7531 !fEquivalentInterfaceImplementedByParent)
7535 // Iterate backward through the parent's method table. This is important to
7536 // find the most derived method.
7537 bmtParentInfo::Iterator parentMethodIt = bmtParent->IterateSlots();
7538 parentMethodIt.ResetToEnd();
7539 while (parentMethodIt.Prev())
7541 bmtRTMethod * pCurParentMethod = parentMethodIt->Decl().AsRTMethod();
7542 DWORD dwAttrs = pCurParentMethod->GetDeclAttrs();
7543 if (!IsMdVirtual(dwAttrs) || !IsMdPublic(dwAttrs))
7544 { // Only match mdPublic mdVirtual methods for interface implementation
7548 if (curItfMethodSig.Equivalent(pCurParentMethod->GetMethodSignature()))
7550 fFoundMatchInBuildingClass = TRUE;
7551 curItfSlot.Impl() = pCurParentMethod->GetSlotIndex();
7553 DispatchMapTypeID dispatchMapTypeID =
7554 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7555 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7557 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7558 pCurParentMethod->GetMethodDesc(),
7563 } // end ... try to find parent method
7567 // For type equivalent interfaces that had an equivalent interface implemented by their parent
7568 // and where the previous logic to fill in the method based on the virtual mappings on the type have
7569 // failed, we should attempt to get the mappings from the equivalent interfaces declared on parent types
7570 // of the type we are currently building.
7571 #ifdef FEATURE_COMINTEROP
7572 if (!fFoundMatchInBuildingClass && fEquivalentInterfaceImplementedByParent && !pCurItfEntry->IsImplementedByParent())
7574 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7579 } // MethodTableBuilder::PlaceInterfaceMethods
7582 //*******************************************************************************
7584 // Used by BuildMethodTable
7586 // Place static fields
7588 VOID MethodTableBuilder::PlaceRegularStaticFields()
7590 STANDARD_VM_CONTRACT;
7594 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing statics for %s\n", this->GetDebugClassName()));
7597 // Place gc refs and value types first, as they need to have handles created for them.
7598 // (Placing them together allows us to easily create the handles when Restoring the class,
7599 // and when initializing new DLS for the class.)
7602 DWORD dwCumulativeStaticFieldPos = 0 ;
7603 DWORD dwCumulativeStaticGCFieldPos = 0;
7604 DWORD dwCumulativeStaticBoxFieldPos = 0;
7606 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7607 // guaranteed to be aligned in ModuleStaticsInfo
7608 bmtFP->NumRegularStaticFieldsOfSize[LOG2_PTRSIZE] -=
7609 bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7611 // Place fields, largest first, padding so that each group is aligned to its natural size
7612 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7614 // Fields of this size start at the next available location
7615 bmtFP->RegularStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7616 dwCumulativeStaticFieldPos += (bmtFP->NumRegularStaticFieldsOfSize[i] << i);
7618 // Reset counters for the loop after this one
7619 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
7623 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7624 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7626 DWORD dwNumHandleStatics = bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7627 if (!FitsIn<WORD>(dwNumHandleStatics))
7629 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7631 SetNumHandleRegularStatics(static_cast<WORD>(dwNumHandleStatics));
7633 if (!FitsIn<WORD>(bmtFP->NumRegularStaticGCBoxedFields))
7635 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7637 SetNumBoxedRegularStatics(static_cast<WORD>(bmtFP->NumRegularStaticGCBoxedFields));
7639 // Tell the module to give us the offsets we'll be using and commit space for us
7641 DWORD dwNonGCOffset, dwGCOffset;
7642 GetModule()->GetOffsetsForRegularStaticData(bmtInternal->pType->GetTypeDefToken(),
7643 bmtProp->fDynamicStatics,
7644 GetNumHandleRegularStatics(), dwCumulativeStaticFieldPos,
7645 &dwGCOffset, &dwNonGCOffset);
7647 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7648 dwCumulativeStaticGCFieldPos = bmtFP->NumRegularStaticGCBoxedFields<<LOG2_PTRSIZE;
7650 FieldDesc *pFieldDescList = GetApproxFieldDescListRaw();
7651 // Place static fields
7652 for (i = 0; i < bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields; i++)
7654 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields+i];
7655 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7656 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7660 case FIELD_OFFSET_UNPLACED_GC_PTR:
7661 // Place GC reference static field
7662 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7663 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7664 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7668 case FIELD_OFFSET_VALUE_CLASS:
7669 // Place boxed GC reference static field
7670 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7671 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7672 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7676 case FIELD_OFFSET_UNPLACED:
7677 // Place non-GC static field
7678 pCurField->SetOffset(bmtFP->RegularStaticFieldStart[dwLog2FieldSize] +
7679 (bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7681 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
7682 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7690 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset_NoLogging()));
7693 if (bmtProp->fDynamicStatics)
7695 _ASSERTE(dwNonGCOffset == 0 || // no statics at all
7696 dwNonGCOffset == OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob); // We need space to point to the GC statics
7697 bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos;
7701 bmtProp->dwNonGCRegularStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7703 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCRegularStaticFieldBytes));
7707 VOID MethodTableBuilder::PlaceThreadStaticFields()
7709 STANDARD_VM_CONTRACT;
7713 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing ThreadStatics for %s\n", this->GetDebugClassName()));
7716 // Place gc refs and value types first, as they need to have handles created for them.
7717 // (Placing them together allows us to easily create the handles when Restoring the class,
7718 // and when initializing new DLS for the class.)
7721 DWORD dwCumulativeStaticFieldPos = 0 ;
7722 DWORD dwCumulativeStaticGCFieldPos = 0;
7723 DWORD dwCumulativeStaticBoxFieldPos = 0;
7725 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7726 // guaranteed to be aligned in ModuleStaticsInfo
7727 bmtFP->NumThreadStaticFieldsOfSize[LOG2_PTRSIZE] -=
7728 bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7730 // Place fields, largest first, padding so that each group is aligned to its natural size
7731 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7733 // Fields of this size start at the next available location
7734 bmtFP->ThreadStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7735 dwCumulativeStaticFieldPos += (bmtFP->NumThreadStaticFieldsOfSize[i] << i);
7737 // Reset counters for the loop after this one
7738 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
7742 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7743 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7745 DWORD dwNumHandleStatics = bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7746 if (!FitsIn<WORD>(dwNumHandleStatics))
7748 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7751 SetNumHandleThreadStatics(static_cast<WORD>(dwNumHandleStatics));
7753 if (!FitsIn<WORD>(bmtFP->NumThreadStaticGCBoxedFields))
7755 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7758 SetNumBoxedThreadStatics(static_cast<WORD>(bmtFP->NumThreadStaticGCBoxedFields));
7760 // Tell the module to give us the offsets we'll be using and commit space for us
7762 DWORD dwNonGCOffset, dwGCOffset;
7764 GetModule()->GetOffsetsForThreadStaticData(bmtInternal->pType->GetTypeDefToken(),
7765 bmtProp->fDynamicStatics,
7766 GetNumHandleThreadStatics(), dwCumulativeStaticFieldPos,
7767 &dwGCOffset, &dwNonGCOffset);
7769 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7770 dwCumulativeStaticGCFieldPos = bmtFP->NumThreadStaticGCBoxedFields<<LOG2_PTRSIZE;
7772 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
7773 // Place static fields
7774 for (i = 0; i < bmtEnumFields->dwNumThreadStaticFields; i++)
7776 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + i];
7777 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7778 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7782 case FIELD_OFFSET_UNPLACED_GC_PTR:
7783 // Place GC reference static field
7784 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7785 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7786 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7790 case FIELD_OFFSET_VALUE_CLASS:
7791 // Place boxed GC reference static field
7792 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7793 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7794 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7798 case FIELD_OFFSET_UNPLACED:
7799 // Place non-GC static field
7800 pCurField->SetOffset(bmtFP->ThreadStaticFieldStart[dwLog2FieldSize] +
7801 (bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7803 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
7804 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7812 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset_NoLogging()));
7815 if (bmtProp->fDynamicStatics)
7817 _ASSERTE(dwNonGCOffset == 0 || // no thread statics at all
7818 dwNonGCOffset == OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob); // We need space to point to the GC statics
7819 bmtProp->dwNonGCThreadStaticFieldBytes = dwCumulativeStaticFieldPos;
7823 bmtProp->dwNonGCThreadStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7825 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: ThreadStatic field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCThreadStaticFieldBytes));
7828 //*******************************************************************************
7830 // Used by BuildMethodTable
7832 // Place instance fields
7834 VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCache)
7836 STANDARD_VM_CONTRACT;
7841 //===============================================================
7842 // BEGIN: Place instance fields
7843 //===============================================================
7845 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
7846 DWORD dwCumulativeInstanceFieldPos;
7848 // Instance fields start right after the parent
7849 dwCumulativeInstanceFieldPos = HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0;
7851 DWORD dwOffsetBias = 0;
7852 #ifdef FEATURE_64BIT_ALIGNMENT
7853 // On platforms where the alignment of 64-bit primitives is a requirement (but we're not guaranteed
7854 // this implicitly by the GC) field offset 0 is actually not 8-byte aligned in reference classes.
7855 // That's because all such platforms are currently 32-bit and the 4-byte MethodTable pointer pushes us
7856 // out of alignment. Ideally we'd solve this by arranging to have the object header allocated at a
7857 // 4-byte offset from an 8-byte boundary, but this is difficult to achieve for objects allocated on
7858 // the large object heap (which actually requires headers to be 8-byte aligned).
7860 // So we adjust dwCumulativeInstanceFieldPos to account for the MethodTable* and our alignment
7861 // calculations will automatically adjust and add padding as necessary. We need to remove this
7862 // adjustment when setting the field offset in the field desc, however, since the rest of the system
7863 // expects that value to not include the MethodTable*.
7865 // This happens only for reference classes: value type field 0 really does lie at offset 0 for unboxed
7866 // value types. We deal with boxed value types by allocating their headers mis-aligned (luckily for us
7867 // value types can never get large enough to allocate on the LOH).
7868 if (!IsValueClass())
7870 dwOffsetBias = TARGET_POINTER_SIZE;
7871 dwCumulativeInstanceFieldPos += dwOffsetBias;
7873 #endif // FEATURE_64BIT_ALIGNMENT
7875 #ifdef FEATURE_READYTORUN
7876 if (NeedsAlignedBaseOffset())
7878 // READYTORUN: FUTURE: Use the minimum possible alignment, reduce padding when inheriting within same bubble
7879 DWORD dwAlignment = DATA_ALIGNMENT;
7880 #ifdef FEATURE_64BIT_ALIGNMENT
7881 if (GetHalfBakedClass()->IsAlign8Candidate())
7884 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
7886 #endif // FEATURE_READYTORUN
7888 // place small fields first if the parent have a number of field bytes that is not aligned
7889 if (!IS_ALIGNED(dwCumulativeInstanceFieldPos, DATA_ALIGNMENT))
7891 for (i = 0; i < MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++) {
7894 if (IS_ALIGNED(dwCumulativeInstanceFieldPos, size_t{ 1 } << (i + 1)))
7897 // check whether there are any bigger fields
7898 for (j = i + 1; j <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; j++) {
7899 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
7902 // nothing to gain if there are no bigger fields
7903 // (the subsequent loop will place fields from large to small fields)
7904 if (j > MAX_LOG2_PRIMITIVE_FIELD_SIZE)
7907 // check whether there are any small enough fields
7908 for (j = i; (signed int) j >= 0; j--) {
7909 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
7911 // TODO: since we will refuse to place GC references we should filter them out here.
7912 // otherwise the "back-filling" process stops completely.
7913 // (PlaceInstanceFields)
7914 // the following code would fix the issue (a replacement for the code above this comment):
7915 // if (bmtFP->NumInstanceFieldsOfSize[j] != 0 &&
7916 // (j != LOG2SLOT || bmtFP->NumInstanceFieldsOfSize[j] > bmtFP->NumInstanceGCPointerFields))
7922 // nothing to play with if there are no smaller fields
7923 if ((signed int) j < 0)
7925 // eventually go back and use the smaller field as filling
7928 CONSISTENCY_CHECK(bmtFP->NumInstanceFieldsOfSize[i] != 0);
7930 j = bmtFP->FirstInstanceFieldOfSize[i];
7932 // Avoid reordering of gcfields
7933 if (i == LOG2SLOT) {
7934 for ( ; j < bmtEnumFields->dwNumInstanceFields; j++) {
7935 if ((pFieldDescList[j].GetOffset_NoLogging() == FIELD_OFFSET_UNPLACED) &&
7936 ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i))
7940 // out of luck - can't reorder gc fields
7941 if (j >= bmtEnumFields->dwNumInstanceFields)
7946 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, size_t{ 1 } << i);
7948 pFieldDescList[j].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
7949 dwCumulativeInstanceFieldPos += (1 << i);
7951 // We've placed this field now, so there is now one less of this size field to place
7952 if (--bmtFP->NumInstanceFieldsOfSize[i] == 0)
7955 // We are done in this round if we haven't picked the first field
7956 if (bmtFP->FirstInstanceFieldOfSize[i] != j)
7959 // Update FirstInstanceFieldOfSize[i] to point to the next such field
7960 for (j = j+1; j < bmtEnumFields->dwNumInstanceFields; j++)
7962 // The log of the field size is stored in the method table
7963 if ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i)
7965 bmtFP->FirstInstanceFieldOfSize[i] = j;
7969 _ASSERTE(j < bmtEnumFields->dwNumInstanceFields);
7973 // Place fields, largest first
7974 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7976 if (bmtFP->NumInstanceFieldsOfSize[i] == 0)
7979 // Align instance fields if we aren't already
7980 #ifdef FEATURE_64BIT_ALIGNMENT
7981 DWORD dwDataAlignment = 1 << i;
7983 DWORD dwDataAlignment = min(1 << i, DATA_ALIGNMENT);
7985 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwDataAlignment);
7987 // Fields of this size start at the next available location
7988 bmtFP->InstanceFieldStart[i] = dwCumulativeInstanceFieldPos;
7989 dwCumulativeInstanceFieldPos += (bmtFP->NumInstanceFieldsOfSize[i] << i);
7991 // Reset counters for the loop after this one
7992 bmtFP->NumInstanceFieldsOfSize[i] = 0;
7996 // Make corrections to reserve space for GC Pointer Fields
7998 // The GC Pointers simply take up the top part of the region associated
7999 // with fields of that size (GC pointers can be 64 bit on certain systems)
8000 if (bmtFP->NumInstanceGCPointerFields)
8002 bmtFP->GCPointerFieldStart = bmtFP->InstanceFieldStart[LOG2SLOT] - dwOffsetBias;
8003 bmtFP->InstanceFieldStart[LOG2SLOT] = bmtFP->InstanceFieldStart[LOG2SLOT] + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT);
8004 bmtFP->NumInstanceGCPointerFields = 0; // reset to zero here, counts up as pointer slots are assigned below
8007 // Place instance fields - be careful not to place any already-placed fields
8008 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8010 DWORD dwFieldSize = (DWORD)(DWORD_PTR&)pFieldDescList[i].m_pMTOfEnclosingClass;
8013 dwOffset = pFieldDescList[i].GetOffset_NoLogging();
8015 // Don't place already-placed fields
8016 if ((dwOffset == FIELD_OFFSET_UNPLACED || dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR || dwOffset == FIELD_OFFSET_VALUE_CLASS))
8018 if (dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR)
8020 pFieldDescList[i].SetOffset(bmtFP->GCPointerFieldStart + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT));
8021 bmtFP->NumInstanceGCPointerFields++;
8023 else if (pFieldDescList[i].IsByValue() == FALSE) // it's a regular field
8025 pFieldDescList[i].SetOffset(bmtFP->InstanceFieldStart[dwFieldSize] + (bmtFP->NumInstanceFieldsOfSize[dwFieldSize] << dwFieldSize) - dwOffsetBias);
8026 bmtFP->NumInstanceFieldsOfSize[dwFieldSize]++;
8031 DWORD dwNumGCPointerSeries;
8032 // Save Number of pointer series
8033 if (bmtFP->NumInstanceGCPointerFields)
8034 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries + 1;
8036 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries;
8038 // Place by value class fields last
8039 // Update the number of GC pointer series
8040 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8042 if (pFieldDescList[i].IsByValue())
8044 MethodTable * pByValueMT = pByValueClassCache[i];
8046 // value classes could have GC pointers in them, which need to be pointer-size aligned
8047 // so do this if it has not been done already
8049 #if !defined(_TARGET_64BIT_) && (DATA_ALIGNMENT > 4)
8050 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos,
8051 (pByValueMT->GetNumInstanceFieldBytes() >= DATA_ALIGNMENT) ? DATA_ALIGNMENT : TARGET_POINTER_SIZE);
8052 #else // !(!defined(_TARGET_64BIT_) && (DATA_ALIGNMENT > 4))
8053 #ifdef FEATURE_64BIT_ALIGNMENT
8054 if (pByValueMT->RequiresAlign8())
8055 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, 8);
8057 #endif // FEATURE_64BIT_ALIGNMENT
8058 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, TARGET_POINTER_SIZE);
8059 #endif // !(!defined(_TARGET_64BIT_) && (DATA_ALIGNMENT > 4))
8061 pFieldDescList[i].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
8062 dwCumulativeInstanceFieldPos += pByValueMT->GetAlignedNumInstanceFieldBytes();
8064 // Add pointer series for by-value classes
8065 dwNumGCPointerSeries += pByValueMT->ContainsPointers() ?
8066 (DWORD)CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries() : 0;
8071 DWORD dwNumInstanceFieldBytes = dwCumulativeInstanceFieldPos - dwOffsetBias;
8075 // Like C++ we enforce that there can be no 0 length structures.
8076 // Thus for a value class with no fields, we 'pad' the length to be 1
8077 if (dwNumInstanceFieldBytes == 0)
8078 dwNumInstanceFieldBytes = 1;
8080 // The JITs like to copy full machine words,
8081 // so if the size is bigger than a void* round it up to minAlign
8082 // and if the size is smaller than void* round it up to next power of two
8085 #ifdef FEATURE_64BIT_ALIGNMENT
8086 if (GetHalfBakedClass()->IsAlign8Candidate()) {
8090 #endif // FEATURE_64BIT_ALIGNMENT
8091 if (dwNumInstanceFieldBytes > TARGET_POINTER_SIZE) {
8092 minAlign = TARGET_POINTER_SIZE;
8096 while (minAlign < dwNumInstanceFieldBytes)
8100 dwNumInstanceFieldBytes = (dwNumInstanceFieldBytes + minAlign-1) & ~(minAlign-1);
8103 if (dwNumInstanceFieldBytes > FIELD_OFFSET_LAST_REAL_OFFSET) {
8104 BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
8107 bmtFP->NumInstanceFieldBytes = dwNumInstanceFieldBytes;
8109 bmtFP->NumGCPointerSeries = dwNumGCPointerSeries;
8111 //===============================================================
8112 // END: Place instance fields
8113 //===============================================================
8116 //*******************************************************************************
8117 // this accesses the field size which is temporarily stored in m_pMTOfEnclosingClass
8118 // during class loading. Don't use any other time
8119 DWORD MethodTableBuilder::GetFieldSize(FieldDesc *pFD)
8121 STATIC_CONTRACT_NOTHROW;
8122 STATIC_CONTRACT_GC_NOTRIGGER;
8123 STATIC_CONTRACT_FORBID_FAULT;
8125 // We should only be calling this while this class is being built.
8126 _ASSERTE(GetHalfBakedMethodTable() == 0);
8127 BAD_FORMAT_NOTHROW_ASSERT(! pFD->IsByValue() || HasExplicitFieldOffsetLayout());
8129 if (pFD->IsByValue())
8130 return (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass);
8131 return (1 << (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass));
8134 #ifdef UNIX_AMD64_ABI
8135 // checks whether the struct is enregisterable.
8136 void MethodTableBuilder::SystemVAmd64CheckForPassStructInRegister()
8138 STANDARD_VM_CONTRACT;
8140 // This method should be called for valuetypes only
8141 _ASSERTE(IsValueClass());
8143 TypeHandle th(GetHalfBakedMethodTable());
8145 if (th.IsTypeDesc())
8147 // Not an enregisterable managed structure.
8151 DWORD totalStructSize = bmtFP->NumInstanceFieldBytes;
8153 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8154 // pass through stack
8155 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8157 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8158 this->GetDebugClassName(), totalStructSize));
8162 const bool useNativeLayout = false;
8163 // Iterate through the fields and make sure they meet requirements to pass in registers
8164 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8165 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout))
8167 // All the above tests passed. It's registers passed struct!
8168 GetHalfBakedMethodTable()->SetRegPassedStruct();
8170 StoreEightByteClassification(&helper);
8174 // checks whether the struct is enregisterable.
8175 void MethodTableBuilder::SystemVAmd64CheckForPassNativeStructInRegister()
8177 STANDARD_VM_CONTRACT;
8178 DWORD totalStructSize = 0;
8180 // If not a native value type, return.
8181 if (!IsValueClass())
8186 totalStructSize = GetLayoutInfo()->GetNativeSize();
8188 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8189 // pass through stack
8190 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8192 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassNativeStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8193 this->GetDebugClassName(), totalStructSize));
8197 _ASSERTE(HasLayout());
8199 // Classify the native layout for this struct.
8200 const bool useNativeLayout = true;
8201 // Iterate through the fields and make sure they meet requirements to pass in registers
8202 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8203 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout))
8205 GetLayoutInfo()->SetNativeStructPassedInRegisters();
8209 // Store the eightbyte classification into the EEClass
8210 void MethodTableBuilder::StoreEightByteClassification(SystemVStructRegisterPassingHelper* helper)
8212 EEClass* eeClass = GetHalfBakedMethodTable()->GetClass();
8213 LoaderAllocator* pAllocator = MethodTableBuilder::GetLoaderAllocator();
8214 AllocMemTracker* pamTracker = MethodTableBuilder::GetMemTracker();
8215 EnsureOptionalFieldsAreAllocated(eeClass, pamTracker, pAllocator->GetLowFrequencyHeap());
8216 eeClass->SetEightByteClassification(helper->eightByteCount, helper->eightByteClassifications, helper->eightByteSizes);
8219 #endif // UNIX_AMD64_ABI
8221 //---------------------------------------------------------------------------------------
8223 // make sure that no object fields are overlapped incorrectly and define the
8224 // GC pointer series for the class. We are assuming that this class will always be laid out within
8225 // its enclosing class by the compiler in such a way that offset 0 will be the correct alignment
8226 // for object ref fields so we don't need to try to align it
8229 MethodTableBuilder::HandleExplicitLayout(
8230 MethodTable ** pByValueClassCache)
8232 STANDARD_VM_CONTRACT;
8235 // Instance slice size is the total size of an instance, and is calculated as
8236 // the field whose offset and size add to the greatest number.
8237 UINT instanceSliceSize = 0;
8238 DWORD firstObjectOverlapOffset = ((DWORD)(-1));
8242 for (i = 0; i < bmtMetaData->cFields; i++)
8244 FieldDesc *pFD = bmtMFDescs->ppFieldDescList[i];
8245 if (pFD == NULL || pFD->IsStatic())
8250 UINT fieldExtent = 0;
8251 if (!ClrSafeInt<UINT>::addition(pFD->GetOffset_NoLogging(), GetFieldSize(pFD), fieldExtent))
8253 BuildMethodTableThrowException(COR_E_OVERFLOW);
8256 if (fieldExtent > instanceSliceSize)
8258 instanceSliceSize = fieldExtent;
8263 PREFIX_ASSUME(sizeof(BYTE) == 1);
8264 BYTE *pFieldLayout = (BYTE*) qb.AllocThrows(instanceSliceSize * sizeof(BYTE));
8265 for (i=0; i < instanceSliceSize; i++)
8267 pFieldLayout[i] = empty;
8270 // go through each field and look for invalid layout
8271 // (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to
8272 // close security holes.)
8274 // This is what we implment:
8276 // 1. Verify that every OREF is on a valid alignment
8277 // 2. Verify that OREFs only overlap with other OREFs.
8278 // 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
8279 // 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
8281 char emptyObject[TARGET_POINTER_SIZE];
8282 char isObject[TARGET_POINTER_SIZE];
8283 for (i = 0; i < TARGET_POINTER_SIZE; i++)
8285 emptyObject[i] = empty;
8290 ExplicitClassTrust explicitClassTrust;
8292 UINT valueClassCacheIndex = ((UINT)(-1));
8294 FieldDesc * pFD = NULL;
8295 for (i = 0; i < bmtMetaData->cFields; i++)
8297 // Note about this loop body:
8299 // This loop is coded to make it as hard as possible to allow a field to be trusted when it shouldn't.
8301 // Every path in this loop body must lead to an explicit decision as to whether the field nonoverlaps,
8302 // overlaps in a verifiable fashion, overlaps in a nonverifiable fashion or overlaps in a completely illegal fashion.
8304 // It must call fieldTrust.SetTrust() with the appropriate result. If you don't call it, fieldTrust's destructor
8305 // will intentionally default to kNone and mark the entire class illegal.
8307 // If your result is anything but kNone (class is illegal), you must also explicitly "continue" the loop.
8308 // There is a "break" at end of this loop body that will abort the loop if you don't do this. And
8309 // if you don't finish iterating through all the fields, this function will automatically mark the entire
8310 // class illegal. This rule is a vestige of an earlier version of this function.
8312 // This object's dtor will aggregate the trust decision for this field into the trust level for the class as a whole.
8313 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8315 pFD = bmtMFDescs->ppFieldDescList[i];
8316 if (pFD == NULL || pFD->IsStatic())
8318 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8322 // "i" indexes all fields, valueClassCacheIndex indexes non-static fields only. Don't get them confused!
8323 valueClassCacheIndex++;
8325 if (CorTypeInfo::IsObjRef(pFD->GetFieldType()))
8327 // Check that the ref offset is pointer aligned
8328 if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
8330 badOffset = pFD->GetOffset_NoLogging();
8331 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8333 // If we got here, OREF field was not pointer aligned. THROW.
8336 // check if overlaps another object
8337 if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
8339 // If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
8340 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8342 if (firstObjectOverlapOffset == ((DWORD)(-1)))
8344 firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
8349 // check if is empty at this point
8350 if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
8352 // If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
8353 memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
8354 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8358 // If we got here, the OREF overlaps a non-OREF. THROW.
8359 badOffset = pFD->GetOffset_NoLogging();
8360 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8366 if (pFD->IsByValue())
8368 MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
8369 if (pByValueMT->ContainsPointers())
8371 if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
8373 ExplicitFieldTrust::TrustLevel trust;
8374 DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
8375 trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
8376 fieldTrust.SetTrust(trust);
8377 if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
8379 if (firstObjectOverlapOffset == ((DWORD)(-1)))
8381 firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
8385 if (trust != ExplicitFieldTrust::kNone)
8391 // If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
8392 badOffset = pFD->GetOffset_NoLogging();
8396 // If we got here, then a valuetype containing an OREF was misaligned.
8397 badOffset = pFD->GetOffset_NoLogging();
8398 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8401 // no pointers so fall through to do standard checking
8402 fieldSize = pByValueMT->GetNumInstanceFieldBytes();
8406 // field size temporarily stored in pInterface field
8407 fieldSize = GetFieldSize(pFD);
8410 // If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
8411 // Look for any orefs under this field
8413 if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
8415 // If we have a nonoref in the range then we are doing an overlay
8416 if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
8418 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8422 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8424 memset((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize);
8428 // If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
8429 // on top of an OREF. THROW.
8430 badOffset = (UINT)(loc - pFieldLayout);
8431 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8433 // anything else is an error
8436 // We have to comment out this assert because otherwise, the compiler refuses to build because the _ASSERT is unreachable
8437 // (Thanks for nothing, compiler, that's what the assert is trying to enforce!) But the intent of the assert is correct.
8438 //_ASSERTE(!"You aren't supposed to be here. Some path inside the loop body did not execute an explicit break or continue.");
8441 // If we got here, some code above failed to execute an explicit "break" or "continue." This is a bug! To be safe,
8442 // we will put a catchall "break" here which will cause the typeload to abort (albeit with a probably misleading
8447 // We only break out of the loop above if we detected an error.
8448 if (i < bmtMetaData->cFields || !explicitClassTrust.IsLegal())
8450 ThrowFieldLayoutError(GetCl(),
8453 IDS_CLASSLOAD_EXPLICIT_LAYOUT);
8456 if (!explicitClassTrust.IsNonOverLayed())
8458 SetHasOverLayedFields();
8461 if (IsBlittable() || IsManagedSequential())
8463 // Bug 849333: We shouldn't update "bmtFP->NumInstanceFieldBytes"
8464 // for Blittable/ManagedSequential types. As this will break backward compatiblity
8465 // for the size of types that return true for HasExplicitFieldOffsetLayout()
8470 FindPointerSeriesExplicit(instanceSliceSize, pFieldLayout);
8472 // Fixup the offset to include parent as current offsets are relative to instance slice
8473 // Could do this earlier, but it's just easier to assume instance relative for most
8474 // of the earlier calculations
8476 // Instance fields start right after the parent
8477 S_UINT32 dwInstanceSliceOffset = S_UINT32(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0);
8478 if (bmtGCSeries->numSeries != 0)
8480 dwInstanceSliceOffset.AlignUp(TARGET_POINTER_SIZE);
8482 if (dwInstanceSliceOffset.IsOverflow())
8484 // addition overflow or cast truncation
8485 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8488 S_UINT32 numInstanceFieldBytes = dwInstanceSliceOffset + S_UINT32(instanceSliceSize);
8493 if (FAILED(GetMDImport()->GetClassTotalSize(GetCl(), &clstotalsize)))
8498 if (clstotalsize != 0)
8500 // size must be large enough to accomodate layout. If not, we use the layout size instead.
8501 if (!numInstanceFieldBytes.IsOverflow() && clstotalsize >= numInstanceFieldBytes.Value())
8503 numInstanceFieldBytes = S_UINT32(clstotalsize);
8508 // The GC requires that all valuetypes containing orefs be sized to a multiple of TARGET_POINTER_SIZE.
8509 if (bmtGCSeries->numSeries != 0)
8511 numInstanceFieldBytes.AlignUp(TARGET_POINTER_SIZE);
8513 if (numInstanceFieldBytes.IsOverflow())
8515 // addition overflow or cast truncation
8516 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8519 // Set the total size
8520 bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes.Value();
8522 for (i = 0; i < bmtMetaData->cFields; i++)
8524 FieldDesc * pTempFD = bmtMFDescs->ppFieldDescList[i];
8525 if ((pTempFD == NULL) || pTempFD->IsStatic())
8529 HRESULT hr = pTempFD->SetOffset(pTempFD->GetOffset_NoLogging() + dwInstanceSliceOffset.Value());
8532 BuildMethodTableThrowException(hr, *bmtError);
8535 } // MethodTableBuilder::HandleExplicitLayout
8537 //*******************************************************************************
8538 // make sure that no object fields are overlapped incorrectly, returns S_FALSE if
8539 // there overlap but nothing illegal, S_OK if there is no overlap
8540 /*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
8542 STANDARD_VM_CONTRACT;
8545 *pFirstObjectOverlapOffset = (DWORD)(-1);
8547 // Build a layout of the value class. Don't know the sizes of all the fields easily, but
8548 // do know a) vc is already consistent so don't need to check it's overlaps and
8549 // b) size and location of all objectrefs. So build it by setting all non-oref
8550 // then fill in the orefs later
8551 UINT fieldSize = pMT->GetNumInstanceFieldBytes();
8553 BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));
8555 memset((void*)vcLayout, nonoref, fieldSize);
8557 // use pointer series to locate the orefs
8559 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
8560 CGCDescSeries *pSeries = map->GetLowestSeries();
8562 for (SIZE_T j = 0; j < map->GetNumSeries(); j++)
8564 CONSISTENCY_CHECK(pSeries <= map->GetHighestSeries());
8566 memset((void*)&vcLayout[pSeries->GetSeriesOffset() - OBJECT_SIZE], oref, pSeries->GetSeriesSize() + pMT->GetBaseSize());
8571 ExplicitClassTrust explicitClassTrust;
8573 for (UINT i=0; i < fieldSize; i++) {
8575 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8577 if (vcLayout[i] == oref) {
8578 switch (pFieldLayout[i]) {
8581 pFieldLayout[i] = oref;
8582 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8585 // oref <--> nonoref
8587 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8592 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8593 if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
8595 *pFirstObjectOverlapOffset = (DWORD)i;
8600 _ASSERTE(!"Can't get here.");
8602 } else if (vcLayout[i] == nonoref) {
8603 switch (pFieldLayout[i]) {
8604 // nonoref <--> empty
8606 pFieldLayout[i] = nonoref;
8607 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8610 // nonoref <--> nonoref
8612 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8615 // nonoref <--> oref
8617 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8621 _ASSERTE(!"Can't get here.");
8624 _ASSERTE(!"Can't get here.");
8628 return explicitClassTrust.GetTrustLevel();
8637 //*******************************************************************************
8638 void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
8641 STANDARD_VM_CONTRACT;
8644 // Allocate a structure to track the series. We know that the worst case is a
8645 // ref-non-ref-non, and since only ref series are recorded and non-ref series
8646 // are skipped, the max number of series is total instance size / 2 / sizeof(ref).
8647 // But watch out for the case where we have e.g. an instanceSlizeSize of 4.
8648 DWORD sz = (instanceSliceSize + (2 * TARGET_POINTER_SIZE) - 1);
8649 bmtGCSeries->pSeries = new bmtGCSeriesInfo::Series[sz/2/ TARGET_POINTER_SIZE];
8651 BYTE *loc = pFieldLayout;
8652 BYTE *layoutEnd = pFieldLayout + instanceSliceSize;
8653 while (loc < layoutEnd)
8655 // Find the next OREF entry.
8656 loc = (BYTE*)memchr((void*)loc, oref, layoutEnd-loc);
8662 // Find the next non-OREF entry
8664 while(cur < layoutEnd && *cur == oref)
8669 // so we have a GC series at loc for cur-loc bytes
8670 bmtGCSeries->pSeries[bmtGCSeries->numSeries].offset = (DWORD)(loc - pFieldLayout);
8671 bmtGCSeries->pSeries[bmtGCSeries->numSeries].len = (DWORD)(cur - loc);
8673 CONSISTENCY_CHECK(IS_ALIGNED(cur - loc, TARGET_POINTER_SIZE));
8675 bmtGCSeries->numSeries++;
8679 // Calculate the total series count including the parent, if a parent exists.
8681 bmtFP->NumGCPointerSeries = bmtParent->NumParentPointerSeries + bmtGCSeries->numSeries;
8685 //*******************************************************************************
8687 MethodTableBuilder::HandleGCForExplicitLayout()
8689 STANDARD_VM_CONTRACT;
8691 MethodTable *pMT = GetHalfBakedMethodTable();
8693 #ifdef FEATURE_COLLECTIBLE_TYPES
8694 if (bmtFP->NumGCPointerSeries == 0 && pMT->Collectible())
8696 // For collectible types, insert empty gc series
8697 CGCDescSeries *pSeries;
8699 CGCDesc::Init( (PVOID) pMT, 1);
8700 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
8701 pSeries->SetSeriesSize( (size_t) (0) - (size_t) pMT->GetBaseSize());
8702 pSeries->SetSeriesOffset(OBJECT_SIZE);
8705 #endif // FEATURE_COLLECTIBLE_TYPES
8706 if (bmtFP->NumGCPointerSeries != 0)
8708 pMT->SetContainsPointers();
8710 // Copy the pointer series map from the parent
8711 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
8712 if (bmtParent->NumParentPointerSeries != 0)
8714 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
8715 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize), (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize), ParentGCSize - sizeof(UINT) );
8719 UINT32 dwInstanceSliceOffset = AlignUp(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0, TARGET_POINTER_SIZE);
8721 // Build the pointer series map for this pointers in this instance
8722 CGCDescSeries *pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
8723 for (UINT i=0; i < bmtGCSeries->numSeries; i++) {
8724 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
8725 BAD_FORMAT_NOTHROW_ASSERT(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
8727 pSeries->SetSeriesSize( (size_t) bmtGCSeries->pSeries[i].len - (size_t) pMT->GetBaseSize() );
8728 pSeries->SetSeriesOffset(bmtGCSeries->pSeries[i].offset + OBJECT_SIZE + dwInstanceSliceOffset);
8733 delete [] bmtGCSeries->pSeries;
8734 bmtGCSeries->pSeries = NULL;
8735 } // MethodTableBuilder::HandleGCForExplicitLayout
8741 MethodTable **pArray,
8742 DWORD nArraySizeMax,
8743 DWORD *pNumAssigned)
8745 LIMITED_METHOD_CONTRACT;
8747 for (DWORD j = 0; j < (*pNumAssigned); j++)
8749 if (pNew == pArray[j])
8752 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found duplicate interface %s (%p) at position %d out of %d\n", pNew->GetDebugClassName(), pNew, j, *pNumAssigned));
8754 return pNew->HasInstantiation(); // bail out - we found a duplicate instantiated interface
8759 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));
8763 if (*pNumAssigned >= nArraySizeMax)
8765 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found interface %s (%p) exceeding size %d of interface array\n", pNew->GetDebugClassName(), pNew, nArraySizeMax));
8768 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Inserting interface %s (%p) at position %d\n", pNew->GetDebugClassName(), pNew, *pNumAssigned));
8769 pArray[(*pNumAssigned)++] = pNew;
8771 } // InsertMethodTable
8774 //*******************************************************************************
8775 // --------------------------------------------------------------------------------------------
8776 // Copy virtual slots inherited from parent:
8778 // In types created at runtime, inherited virtual slots are initialized using approximate parent
8779 // during method table building. This method will update them based on the exact parent.
8780 // In types loaded from NGen image, inherited virtual slots from cross-module parents are not
8781 // initialized. This method will initialize them based on the actually loaded exact parent
8784 void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT, MethodTable *pApproxParentMT)
8789 PRECONDITION(CheckPointer(pMT));
8793 if (pMT->IsZapped())
8796 DWORD nParentVirtuals = pMT->GetNumParentVirtuals();
8797 if (nParentVirtuals == 0)
8800 _ASSERTE(nParentVirtuals == pApproxParentMT->GetNumVirtuals());
8803 // Update all inherited virtual slots to match exact parent
8806 if (!pMT->IsCanonicalMethodTable())
8809 // Copy all slots for non-canonical methodtables to avoid touching methoddescs.
8811 MethodTable * pCanonMT = pMT->GetCanonicalMethodTable();
8813 // Do not write into vtable chunks shared with parent. It would introduce race
8814 // with code:MethodDesc::SetStableEntryPointInterlocked.
8816 // Non-canonical method tables either share everything or nothing so it is sufficient to check
8817 // just the first indirection to detect sharing.
8818 if (pMT->GetVtableIndirections()[0].GetValueMaybeNull() != pCanonMT->GetVtableIndirections()[0].GetValueMaybeNull())
8820 MethodTable::MethodDataWrapper hCanonMTData(MethodTable::GetMethodData(pCanonMT, FALSE));
8821 for (DWORD i = 0; i < nParentVirtuals; i++)
8823 pMT->CopySlotFrom(i, hCanonMTData, pCanonMT);
8829 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
8831 MethodTable * pParentMT = pMT->GetParentMethodTable();
8832 MethodTable::MethodDataWrapper hParentMTData(MethodTable::GetMethodData(pParentMT, FALSE));
8834 for (DWORD i = 0; i < nParentVirtuals; i++)
8836 // fix up wrongly-inherited method descriptors
8837 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
8838 CONSISTENCY_CHECK(CheckPointer(pMD));
8839 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
8841 if (pMD->GetMethodTable() == pMT)
8844 // We need to re-inherit this slot from the exact parent.
8846 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(i);
8847 if (pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() == pApproxParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull())
8849 // The slot lives in a chunk shared from the approximate parent MT
8850 // If so, we need to change to share the chunk from the exact parent MT
8852 #ifdef FEATURE_PREJIT
8853 _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule(), Module::GetPreferredZapModuleForMethodTable(pMT)));
8855 _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule()));
8858 pMT->GetVtableIndirections()[indirectionIndex].SetValueMaybeNull(pParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull());
8860 i = MethodTable::GetEndSlotForVtableIndirection(indirectionIndex, nParentVirtuals) - 1;
8864 // The slot lives in an unshared chunk. We need to update the slot contents
8865 pMT->CopySlotFrom(i, hParentMTData, pParentMT);
8868 } // MethodTableBuilder::CopyExactParentSlots
8870 //*******************************************************************************
8873 MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
8878 PRECONDITION(CheckPointer(pMT));
8882 BOOL hasInstantiatedInterfaces = FALSE;
8883 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
8886 if (it.GetInterface()->HasInstantiation())
8888 hasInstantiatedInterfaces = TRUE;
8893 // If we have some instantiated interfaces, then we have lots more work to do...
8895 // In the worst case we have to use the metadata to
8896 // (a) load the exact interfaces and determine the order in which they
8897 // go. We do those by re-running the interface layout algorithm
8898 // and using metadata-comparisons to place interfaces in the list.
8899 // (b) do a check to see if any ambiguity in the interface dispatch map is introduced
8900 // by the instantiation
8901 // See code:#LoadExactInterfaceMap_Algorithm2
8903 // However, we can do something simpler: we just use
8904 // the loaded interface method tables to determine ordering. This can be done
8905 // if there are no duplicate instantiated interfaces in the interface
8907 // See code:#LoadExactInterfaceMap_Algorithm1.
8909 if (!hasInstantiatedInterfaces)
8915 TypeHandle thisTH(pMT);
8916 SigTypeContext typeContext(thisTH);
8917 MethodTable *pParentMT = pMT->GetParentMethodTable();
8919 //#LoadExactInterfaceMap_Algorithm1
8920 // Exact interface instantiation loading TECHNIQUE 1.
8921 // (a) For interfaces inherited from an instantiated parent class, just copy down from exact parent
8922 // (b) Grab newly declared interfaces by loading and then copying down all their inherited parents
8923 // (c) But check for any exact duplicates along the way
8924 // (d) If no duplicates then we can use the computed interface map we've created
8925 // (e) If duplicates found then use the slow metadata-based technique code:#LoadExactInterfaceMap_Algorithm2
8926 DWORD nInterfacesCount = pMT->GetNumInterfaces();
8927 MethodTable **pExactMTs = (MethodTable**) _alloca(sizeof(MethodTable *) * nInterfacesCount);
8928 DWORD nAssigned = 0;
8929 BOOL duplicates = false;
8930 if (pParentMT != NULL)
8932 MethodTable::InterfaceMapIterator parentIt = pParentMT->IterateInterfaceMap();
8933 while (parentIt.Next())
8935 duplicates |= InsertMethodTable(parentIt.GetInterface(), pExactMTs, nInterfacesCount, &nAssigned);
8938 InterfaceImplEnum ie(pMT->GetModule(), pMT->GetCl(), NULL);
8939 while ((hr = ie.Next()) == S_OK)
8941 MethodTable *pNewIntfMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(),
8944 ClassLoader::ThrowIfNotFound,
8945 ClassLoader::FailIfUninstDefOrRef,
8946 ClassLoader::LoadTypes,
8947 CLASS_LOAD_EXACTPARENTS,
8948 TRUE).GetMethodTable();
8950 duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);
8951 MethodTable::InterfaceMapIterator intIt = pNewIntfMT->IterateInterfaceMap();
8952 while (intIt.Next())
8954 duplicates |= InsertMethodTable(intIt.GetInterface(), pExactMTs, nInterfacesCount, &nAssigned);
8959 pMT->GetAssembly()->ThrowTypeLoadException(pMT->GetMDImport(), pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
8962 duplicates |= EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AlwaysUseMetadataInterfaceMapLayout, FALSE);
8964 //#InjectInterfaceDuplicates_LoadExactInterfaceMap
8965 // If we are injecting duplicates also for non-generic interfaces in check builds, we have to use
8966 // algorithm code:#LoadExactInterfaceMap_Algorithm2.
8967 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
8968 duplicates |= pMT->Debug_HasInjectedInterfaceDuplicates();
8970 CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces()));
8973 //#LoadExactInterfaceMap_Algorithm2
8974 // Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to
8975 // appear in the interface map! This may not be an error: if the duplicates
8976 // were ones that arose because because of inheritance from
8977 // a parent type then we accept that. For example
8978 // class C<T> : I<T>
8979 // class D<T> : C<T>, I<string>
8980 // is acceptable even when loading D<string>. Note that in such a case
8981 // there will be two entries for I<string> in the final interface map for D<string>.
8982 // For dispatch the mappings in D take precedence.
8984 // However we consider it an error if there is real ambiguity within
8985 // the interface definitions within the one class, e.g.
8986 // class E<T> : I<T>, I<string>
8987 // In this situation it is not defined how to dispatch calls to I<string>: would
8988 // we use the bindings for I<T> or I<string>?
8990 // Because we may had duplicates the interface map we created above may not
8991 // be the correct one: for example for D<string> above we would have computed
8992 // a map with only one entry. This is incorrect: an exact instantiation's interface
8993 // map must have entries that match the ordering of the interface map in the generic case
8994 // (this is because code:#InterfaceMap_SupersetOfParent).
8996 // So, in order to determine how to place the interfaces we need go back to
8997 // the metadata. We also do this to check if the presence of duplicates
8998 // has caused any potential ambiguity, i.e. the E<string> case above.
9000 // First we do a GetCheckpoint for the thread-based allocator. ExpandExactInheritedInterfaces allocates substitution chains
9001 // on the thread allocator rather than on the stack.
9002 Thread * pThread = GetThread();
9003 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
9005 // ***********************************************************
9006 // ****** This must be consistent with code:ExpandApproxInterface etc. *******
9008 // The correlation to ExpandApproxInterfaces etc. simply drops out by how we
9009 // traverse interfaces.
9010 // ***********************************************************
9012 bmtExactInterfaceInfo bmtExactInterface;
9013 bmtExactInterface.pInterfaceSubstitution = new (&pThread->m_MarshalAlloc) Substitution[pMT->GetNumInterfaces()];
9014 bmtExactInterface.pExactMTs = pExactMTs;
9015 bmtExactInterface.nAssigned = 0;
9016 bmtExactInterface.typeContext = typeContext;
9018 // Do the interfaces inherited from a parent class
9019 if ((pParentMT != NULL) && (pParentMT->GetNumInterfaces() > 0))
9021 Substitution * pParentSubstForTypeLoad = new (&pThread->m_MarshalAlloc) Substitution(
9022 pMT->GetSubstitutionForParent(NULL));
9023 Substitution * pParentSubstForComparing = new (&pThread->m_MarshalAlloc) Substitution(
9024 pMT->GetSubstitutionForParent(NULL));
9025 ExpandExactInheritedInterfaces(
9028 pParentSubstForTypeLoad,
9029 pParentSubstForComparing);
9032 //#ExactInterfaceMap_SupersetOfParent
9033 // Check that parent's interface map is subset of this interface map
9034 // See code:#InterfaceMap_SupersetOfParent
9036 _ASSERTE(pParentMT->GetNumInterfaces() == bmtExactInterface.nAssigned);
9038 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
9039 UINT32 nInterfaceIndex = 0;
9040 while (parentInterfacesIterator.Next())
9042 if (pMT->IsSharedByGenericInstantiations())
9043 { // The type is a canonical instantiation (contains _Canon)
9044 // The interface instantiations of parent can be different (see
9045 // code:#InterfaceMap_CanonicalSupersetOfParent), therefore we cannot compare
9047 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
9048 bmtExactInterface.pExactMTs[nInterfaceIndex]));
9051 { // It is not canonical instantiation, we can compare MethodTables
9052 _ASSERTE(parentInterfacesIterator.GetInterface() == bmtExactInterface.pExactMTs[nInterfaceIndex]);
9056 _ASSERTE(nInterfaceIndex == bmtExactInterface.nAssigned);
9060 // If there are any __Canon instances in the type argument list, then we defer the
9061 // ambiguity checking until an exact instantiation.
9062 if (!pMT->IsSharedByGenericInstantiations())
9064 // There are no __Canon types in the instantiation, so do ambiguity check.
9065 bmtInterfaceAmbiguityCheckInfo bmtCheckInfo;
9066 bmtCheckInfo.pMT = pMT;
9067 bmtCheckInfo.ppInterfaceSubstitutionChains = new (&pThread->m_MarshalAlloc) Substitution *[pMT->GetNumInterfaces()];
9068 bmtCheckInfo.ppExactDeclaredInterfaces = new (&pThread->m_MarshalAlloc) MethodTable *[pMT->GetNumInterfaces()];
9069 bmtCheckInfo.nAssigned = 0;
9070 bmtCheckInfo.typeContext = typeContext;
9071 MethodTableBuilder::InterfacesAmbiguityCheck(&bmtCheckInfo, pMT->GetModule(), pMT->GetCl(), NULL);
9074 // OK, there is no ambiguity amongst the instantiated interfaces declared on this class.
9075 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9081 COMMA_INDEBUG(pMT));
9082 CONSISTENCY_CHECK(bmtExactInterface.nAssigned == pMT->GetNumInterfaces());
9084 // We cannot process interface duplicates on types with __Canon. The duplicates are processed on
9086 if (!pMT->IsSharedByGenericInstantiations())
9088 // Process all pairs of duplicates in the interface map:
9089 // i.e. If there are 3 duplicates of the same interface at indexes: i1, i2 and i3, then
9090 // process pairs of indexes [i1,i2], [i1,i3] and [i2,i3].
9091 // - Update 'declared on type' flag for those interfaces which duplicate is 'declared on type'
9092 // - Check interface method implementation ambiguity code:#DuplicateInterface_MethodAmbiguity
9093 for (DWORD nOriginalIndex = 0; nOriginalIndex < nInterfacesCount; nOriginalIndex++)
9095 // Search for duplicates further in the interface map
9096 for (DWORD nDuplicateIndex = nOriginalIndex + 1; nDuplicateIndex < nInterfacesCount; nDuplicateIndex++)
9098 if (pExactMTs[nOriginalIndex] != pExactMTs[nDuplicateIndex])
9099 { // It's not a duplicate of original interface, skip it
9102 // We found a duplicate
9104 // Set 'declared on type' flag if either original or duplicate interface is
9105 // 'declared on type'
9106 if (pMT->IsInterfaceDeclaredOnClass(nOriginalIndex) ||
9107 pMT->IsInterfaceDeclaredOnClass(nDuplicateIndex))
9110 // Note that both checks are needed:
9112 // B<T,U> : A<T>, I<U>
9113 // C<T,U> : B<T,U>, I<T> // Reimplements interface from A<T>
9114 // After code:BuildMethodTableThrowing algorithm, this will happen:
9115 // B<int,int> will have interface map similar to B<T,U>:
9116 // I<int> ... not 'declared on type'
9117 // I<int> ... 'declared on type'
9118 // C<int,int> will have interface map similar to C<T,U>:
9119 // I<int> ... 'declared on type'
9120 // I<int> ... not 'declared on type'
9123 pMT->SetInterfaceDeclaredOnClass(nOriginalIndex);
9124 pMT->SetInterfaceDeclaredOnClass(nDuplicateIndex);
9127 //#DuplicateInterface_MethodAmbiguity
9129 // In the ideal world we would now check for interface method implementation
9130 // ambiguity in the instantiation, but that would be a technical breaking change
9131 // (against 2.0 RTM/SP1).
9132 // Therefore we ALLOW when interface method is implemented twice through this
9133 // original and duplicate interface.
9135 // This ambiguity pattern is therefore ALLOWED (can be expressed only in IL, not in C#):
9138 // A<T> : I<T> // abstract class
9139 // B<T,U> : A<T>, I<U>
9140 // void Print(T t) { ... }
9141 // void Print(U u) { ... }
9142 // Now B<int,int> has 2 implementations of I<int>.Print(int), while B<int,char> is
9143 // fine. Therefore an instantiation can introduce ambiguity.
9145 #if 0 // Removing this code for now as it is a technical breaking change (against CLR 2.0 RTM/SP1).
9146 // We might decide later that we want to take this breaking change.
9148 // Note that dispatch map entries are sorted by interface index and then interface
9149 // method slot index.
9151 DispatchMapTypeID originalTypeID = DispatchMapTypeID::InterfaceClassID(nOriginalIndex);
9152 DispatchMap::EncodedMapIterator originalIt(pMT);
9153 // Find first entry for original interface
9154 while (originalIt.IsValid())
9156 DispatchMapEntry *pEntry = originalIt.Entry();
9157 if (pEntry->GetTypeID().ToUINT32() >= originalTypeID.ToUINT32())
9158 { // Found the place where original interface entries should be (dispatch map is
9165 DispatchMapTypeID duplicateTypeID = DispatchMapTypeID::InterfaceClassID(nDuplicateIndex);
9166 DispatchMap::EncodedMapIterator duplicateIt(pMT);
9167 // Find first entry for duplicate interface
9168 while (duplicateIt.IsValid())
9170 DispatchMapEntry *pEntry = duplicateIt.Entry();
9171 if (pEntry->GetTypeID().ToUINT32() >= duplicateTypeID.ToUINT32())
9172 { // Found the place where original interface entries should be (dispatch map is
9179 // Compare original and duplicate interface entries in the dispatch map if they contain
9180 // different implementation for the same interface method
9183 if (!originalIt.IsValid() || !duplicateIt.IsValid())
9184 { // We reached end of one dispatch map iterator
9187 DispatchMapEntry *pOriginalEntry = originalIt.Entry();
9188 if (pOriginalEntry->GetTypeID().ToUINT32() != originalTypeID.ToUINT32())
9189 { // We reached behind original interface entries
9192 DispatchMapEntry *pDuplicateEntry = duplicateIt.Entry();
9193 if (pDuplicateEntry->GetTypeID().ToUINT32() != duplicateTypeID.ToUINT32())
9194 { // We reached behind duplicate interface entries
9198 if (pOriginalEntry->GetSlotNumber() == pDuplicateEntry->GetSlotNumber())
9199 { // Found duplicate implementation of interface method
9200 if (pOriginalEntry->GetTargetSlotNumber() != pDuplicateEntry->GetTargetSlotNumber())
9201 { // Implementation of the slots is different
9202 bmtErrorInfo bmtError;
9204 bmtError.pModule = pMT->GetModule();
9205 bmtError.cl = pMT->GetCl();
9206 bmtError.resIDWhy = IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES;
9207 bmtError.szMethodNameForError = NULL;
9208 bmtError.pThrowable = NULL;
9210 MethodDesc *pMD = pMT->GetMethodDescForSlot(pDuplicateEntry->GetTargetSlotNumber());
9211 bmtError.dMethodDefInError = pMD->GetMemberDef();
9213 BuildMethodTableThrowException(COR_E_TYPELOAD, bmtError);
9215 // The method is implemented by the same slot on both interfaces (original and
9218 // Process next dispatch map entry
9223 // Move iterator representing smaller interface method slot index (the dispatch map
9224 // is sorted by slot indexes)
9225 if (pOriginalEntry->GetSlotNumber() < pDuplicateEntry->GetSlotNumber())
9230 _ASSERTE(pOriginalEntry->GetSlotNumber() > pDuplicateEntry->GetSlotNumber());
9235 // All duplicates of this original interface were processed
9237 // All pairs of duplicates in the interface map are processed
9240 // Duplicates in the interface map are resolved
9242 // OK, if we've got this far then pExactMTs should now hold the array of exact instantiated interfaces.
9243 MethodTable::InterfaceMapIterator thisIt = pMT->IterateInterfaceMap();
9245 while (thisIt.Next())
9248 MethodTable*pOldMT = thisIt.GetInterface();
9249 MethodTable *pNewMT = pExactMTs[i];
9250 CONSISTENCY_CHECK(pOldMT->HasSameTypeDefAs(pNewMT));
9252 thisIt.SetInterface(pExactMTs[i]);
9256 } // MethodTableBuilder::LoadExactInterfaceMap
9258 //*******************************************************************************
9260 MethodTableBuilder::ExpandExactInheritedInterfaces(
9261 bmtExactInterfaceInfo * bmtInfo,
9263 const Substitution * pSubstForTypeLoad,
9264 Substitution * pSubstForComparing)
9266 STANDARD_VM_CONTRACT;
9268 MethodTable *pParentMT = pMT->GetParentMethodTable();
9270 // Backup type's substitution chain for comparing interfaces
9271 Substitution substForComparingBackup = *pSubstForComparing;
9272 // Make type an open type for comparing interfaces
9273 *pSubstForComparing = Substitution();
9277 // Chain parent's substitution for exact type load
9278 Substitution * pParentSubstForTypeLoad = new (&GetThread()->m_MarshalAlloc) Substitution(
9279 pMT->GetSubstitutionForParent(pSubstForTypeLoad));
9281 // Chain parent's substitution for comparing interfaces (note that this type is temporarily
9282 // considered as open type)
9283 Substitution * pParentSubstForComparing = new (&GetThread()->m_MarshalAlloc) Substitution(
9284 pMT->GetSubstitutionForParent(pSubstForComparing));
9286 ExpandExactInheritedInterfaces(
9289 pParentSubstForTypeLoad,
9290 pParentSubstForComparing);
9292 ExpandExactDeclaredInterfaces(
9298 COMMA_INDEBUG(pMT));
9300 // Restore type's subsitution chain for comparing interfaces
9301 *pSubstForComparing = substForComparingBackup;
9302 } // MethodTableBuilder::ExpandExactInheritedInterfaces
9304 //*******************************************************************************
9307 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9308 bmtExactInterfaceInfo * bmtInfo,
9311 const Substitution * pSubstForTypeLoad,
9312 Substitution * pSubstForComparing
9313 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9315 STANDARD_VM_CONTRACT;
9318 InterfaceImplEnum ie(pModule, typeDef, NULL);
9319 while ((hr = ie.Next()) == S_OK)
9321 MethodTable * pInterface = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
9324 &bmtInfo->typeContext,
9325 ClassLoader::ThrowIfNotFound,
9326 ClassLoader::FailIfUninstDefOrRef,
9327 ClassLoader::LoadTypes,
9328 CLASS_LOAD_EXACTPARENTS,
9330 pSubstForTypeLoad).GetMethodTable();
9332 Substitution ifaceSubstForTypeLoad(ie.CurrentToken(), pModule, pSubstForTypeLoad);
9333 Substitution ifaceSubstForComparing(ie.CurrentToken(), pModule, pSubstForComparing);
9334 ExpandExactInterface(
9337 &ifaceSubstForTypeLoad,
9338 &ifaceSubstForComparing
9339 COMMA_INDEBUG(dbg_pClassMT));
9343 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9345 } // MethodTableBuilder::ExpandExactDeclaredInterfaces
9347 //*******************************************************************************
9349 MethodTableBuilder::ExpandExactInterface(
9350 bmtExactInterfaceInfo * bmtInfo,
9351 MethodTable * pIntf,
9352 const Substitution * pSubstForTypeLoad_OnStack, // Allocated on stack!
9353 const Substitution * pSubstForComparing_OnStack // Allocated on stack!
9354 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9356 STANDARD_VM_CONTRACT;
9358 // ****** This must be consistent with code:MethodTableBuilder::ExpandApproxInterface ******
9360 // Is it already present according to the "generic" layout of the interfaces.
9361 // Note we use exactly the same algorithm as when we
9362 // determined the layout of the interface map for the "generic" version of the class.
9363 for (DWORD i = 0; i < bmtInfo->nAssigned; i++)
9365 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
9366 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9367 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtInfo->pExactMTs[i],
9369 &bmtInfo->pInterfaceSubstitution[i],
9370 pSubstForComparing_OnStack,
9374 //#InjectInterfaceDuplicates_ExactInterfaces
9375 // We will inject duplicate interfaces in check builds.
9376 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
9377 if (dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates())
9378 { // Just pretend we didn't find this match
9382 return; // found it, don't add it again
9386 // Add the interface and its sub-interfaces
9387 DWORD n = bmtInfo->nAssigned;
9388 bmtInfo->pExactMTs[n] = pIntf;
9389 bmtInfo->pInterfaceSubstitution[n] = *pSubstForComparing_OnStack;
9390 bmtInfo->nAssigned++;
9392 Substitution * pSubstForTypeLoad = new (&GetThread()->m_MarshalAlloc) Substitution(*pSubstForTypeLoad_OnStack);
9394 ExpandExactDeclaredInterfaces(
9399 &bmtInfo->pInterfaceSubstitution[n]
9400 COMMA_INDEBUG(dbg_pClassMT));
9401 } // MethodTableBuilder::ExpandExactInterface
9403 //*******************************************************************************
9405 void MethodTableBuilder::InterfacesAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9408 const Substitution *pSubstChain)
9410 STANDARD_VM_CONTRACT;
9413 InterfaceImplEnum ie(pModule, typeDef, pSubstChain);
9414 while ((hr = ie.Next()) == S_OK)
9416 MethodTable *pInterface =
9417 ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, ie.CurrentToken(),
9418 &bmtCheckInfo->typeContext,
9419 ClassLoader::ThrowIfNotFound,
9420 ClassLoader::FailIfUninstDefOrRef,
9421 ClassLoader::LoadTypes,
9422 CLASS_LOAD_EXACTPARENTS,
9424 pSubstChain).GetMethodTable();
9425 InterfaceAmbiguityCheck(bmtCheckInfo, ie.CurrentSubst(), pInterface);
9429 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9433 //*******************************************************************************
9434 void MethodTableBuilder::InterfaceAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9435 const Substitution *pItfSubstChain,
9438 STANDARD_VM_CONTRACT;
9440 // Is it already in the generic version of the freshly declared interfaces. We
9441 // do this based on metadata, i.e. via the substitution chains.
9442 // Note we use exactly the same algorithm as when we
9443 // determined the layout of the interface map for the "generic" version of the class.
9444 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9446 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
9447 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9448 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtCheckInfo->ppExactDeclaredInterfaces[i],
9450 bmtCheckInfo->ppInterfaceSubstitutionChains[i],
9453 return; // found it, don't add it again
9456 // OK, so it isn't a duplicate based on the generic IL, now check if the instantiation
9457 // makes it a duplicate.
9458 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9460 if (bmtCheckInfo->ppExactDeclaredInterfaces[i] == pIntf)
9462 bmtCheckInfo->pMT->GetModule()->GetAssembly()->ThrowTypeLoadException(bmtCheckInfo->pMT->GetMDImport(),
9463 bmtCheckInfo->pMT->GetCl(),
9464 IDS_CLASSLOAD_OVERLAPPING_INTERFACES);
9468 DWORD n = bmtCheckInfo->nAssigned;
9469 bmtCheckInfo->ppExactDeclaredInterfaces[n] = pIntf;
9470 bmtCheckInfo->ppInterfaceSubstitutionChains[n] = new (&GetThread()->m_MarshalAlloc) Substitution[pItfSubstChain->GetLength()];
9471 pItfSubstChain->CopyToArray(bmtCheckInfo->ppInterfaceSubstitutionChains[n]);
9473 bmtCheckInfo->nAssigned++;
9474 InterfacesAmbiguityCheck(bmtCheckInfo,pIntf->GetModule(),pIntf->GetCl(),pItfSubstChain);
9478 //*******************************************************************************
9479 void MethodTableBuilder::CheckForSystemTypes()
9481 STANDARD_VM_CONTRACT;
9483 LPCUTF8 name, nameSpace;
9485 MethodTable * pMT = GetHalfBakedMethodTable();
9486 EEClass * pClass = GetHalfBakedClass();
9488 // We can exit early for generic types - there are just a few cases to check for.
9489 if (bmtGenerics->HasInstantiation())
9491 if (pMT->IsIntrinsicType() && pClass->HasLayout())
9493 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9495 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9498 if (strcmp(nameSpace, g_IntrinsicsNS) == 0)
9500 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
9502 // The SIMD Hardware Intrinsic types correspond to fundamental data types in the underlying ABIs:
9503 // * Vector64<T>: __m64
9504 // * Vector128<T>: __m128
9505 // * Vector256<T>: __m256
9507 // These __m128 and __m256 types, among other requirements, are special in that they must always
9508 // be aligned properly.
9510 if (IsCompilationProcess())
9512 // Disable AOT compiling for the SIMD hardware intrinsic types. These types require special
9513 // ABI handling as they represent fundamental data types (__m64, __m128, and __m256) and not
9514 // aggregate or union types. See https://github.com/dotnet/coreclr/issues/15943
9516 // Once they are properly handled according to the ABI requirements, we can remove this check
9517 // and allow them to be used in crossgen/AOT scenarios.
9518 COMPlusThrow(kTypeLoadException, IDS_EE_HWINTRINSIC_NGEN_DISALLOWED);
9521 if (strcmp(name, g_Vector64Name) == 0)
9523 // The System V ABI for i386 defaults to 8-byte alignment for __m64, except for parameter passing,
9524 // where it has an alignment of 4.
9526 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
9527 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
9529 else if (strcmp(name, g_Vector128Name) == 0)
9532 // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128
9534 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8;
9535 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
9537 pLayout->m_LargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
9538 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
9539 #endif // _TARGET_ARM_
9541 else if (strcmp(name, g_Vector256Name) == 0)
9544 // No such type exists for the Procedure Call Standard for ARM. We will default
9545 // to the same alignment as __m128, which is supported by the ABI.
9547 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8;
9548 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
9549 #elif defined(_TARGET_ARM64_)
9550 // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to
9551 // 16-byte alignment for __m256.
9553 pLayout->m_LargestAlignmentRequirementOfAllMembers = 16;
9554 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
9556 pLayout->m_LargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
9557 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
9558 #endif // _TARGET_ARM_ elif _TARGET_ARM64_
9562 // These types should be handled or explicitly skipped below to ensure that we don't
9563 // miss adding required ABI support for future types.
9565 _ASSERTE_MSG(FALSE, "Unhandled Hardware Intrinsic Type.");
9572 if (g_pNullableClass != NULL)
9574 _ASSERTE(g_pByReferenceClass != NULL);
9575 _ASSERTE(g_pByReferenceClass->IsByRefLike());
9578 if (GetCl() == g_pByReferenceClass->GetCl())
9580 // x86 by default treats the type of ByReference<T> as the actual type of its IntPtr field, see calls to
9581 // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be
9582 // treated as a value type so that its field can be considered as a byref pointer.
9583 _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType);
9584 pMT->ClearFlag(MethodTable::enum_flag_Category_Mask);
9585 pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE);
9590 _ASSERTE(g_pNullableClass->IsNullable());
9592 // Pre-compute whether the class is a Nullable<T> so that code:Nullable::IsNullableType is efficient
9593 // This is useful to the performance of boxing/unboxing a Nullable
9594 if (GetCl() == g_pNullableClass->GetCl())
9595 pMT->SetIsNullable();
9601 if (IsNested() || IsEnum())
9604 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9606 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9615 // All special value types are in the system namespace
9616 if (strcmp(nameSpace, g_SystemNS) != 0)
9619 // Check if it is a primitive type
9620 CorElementType type = CorTypeInfo::FindPrimitiveType(name);
9621 if (type != ELEMENT_TYPE_END)
9623 pMT->SetInternalCorElementType(type);
9624 pMT->SetIsTruePrimitive();
9626 #if defined(_TARGET_X86_) && defined(UNIX_X86_ABI)
9629 // The System V ABI for i386 defines different packing for these types.
9631 case ELEMENT_TYPE_I8:
9632 case ELEMENT_TYPE_U8:
9633 case ELEMENT_TYPE_R8:
9635 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
9636 pLayout->m_LargestAlignmentRequirementOfAllMembers = 4;
9637 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 4;
9644 #endif // _TARGET_X86_ && UNIX_X86_ABI
9647 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9649 name = nameSpace = "Invalid TypeDef record";
9651 LOG((LF_CLASSLOADER, LL_INFO10000, "%s::%s marked as primitive type %i\n", nameSpace, name, type));
9654 else if (strcmp(name, g_NullableName) == 0)
9656 pMT->SetIsNullable();
9659 else if (strcmp(name, g_ByReferenceName) == 0)
9661 // x86 by default treats the type of ByReference<T> as the actual type of its IntPtr field, see calls to
9662 // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be
9663 // treated as a value type so that its field can be considered as a byref pointer.
9664 _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType);
9665 pMT->ClearFlag(MethodTable::enum_flag_Category_Mask);
9666 pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE);
9669 #ifndef _TARGET_X86_
9670 else if (strcmp(name, g_RuntimeArgumentHandleName) == 0)
9672 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
9674 else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0)
9676 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
9679 #if defined(ALIGN_ACCESS) || defined(FEATURE_64BIT_ALIGNMENT)
9680 else if (strcmp(name, g_DecimalName) == 0)
9682 // This is required because native layout of System.Decimal causes it to be aligned
9683 // differently to the layout of the native DECIMAL structure, which will cause
9684 // data misalignent exceptions if Decimal is embedded in another type.
9686 EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo();
9687 pLayout->m_LargestAlignmentRequirementOfAllMembers = sizeof(ULONGLONG);
9688 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = sizeof(ULONGLONG);
9690 #ifdef FEATURE_64BIT_ALIGNMENT
9691 // Also need to mark the type so it will be allocated on a 64-bit boundary for
9692 // platforms that won't do this naturally.
9693 SetAlign8Candidate();
9696 #endif // ALIGN_ACCESS || FEATURE_64BIT_ALIGNMENT
9703 if (strcmp(name, g_StringName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9705 // Strings are not "normal" objects, so we need to mess with their method table a bit
9706 // so that the GC can figure out how big each string is...
9707 DWORD baseSize = StringObject::GetBaseSize();
9708 pMT->SetBaseSize(baseSize);
9710 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
9712 pMT->SetComponentSize(2);
9714 #ifdef FEATURE_UTF8STRING
9715 else if (strcmp(name, g_Utf8StringName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9717 // Utf8Strings are not "normal" objects, so we need to mess with their method table a bit
9718 // so that the GC can figure out how big each string is...
9719 DWORD baseSize = Utf8StringObject::GetBaseSize();
9720 pMT->SetBaseSize(baseSize); // NULL character included
9722 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
9724 pMT->SetComponentSize(1);
9726 #endif // FEATURE_UTF8STRING
9727 else if (strcmp(name, g_CriticalFinalizerObjectName) == 0 && strcmp(nameSpace, g_ConstrainedExecutionNS) == 0)
9729 // To introduce a class with a critical finalizer,
9730 // we'll set the bit here.
9731 pMT->SetHasCriticalFinalizer();
9733 #ifdef FEATURE_COMINTEROP
9736 bool bIsComObject = false;
9737 bool bIsRuntimeClass = false;
9739 if (strcmp(name, g_ComObjectName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9740 bIsComObject = true;
9742 if (strcmp(name, g_RuntimeClassName) == 0 && strcmp(nameSpace, g_WinRTNS) == 0)
9743 bIsRuntimeClass = true;
9745 if (bIsComObject || bIsRuntimeClass)
9747 // Make System.__ComObject/System.Runtime.InteropServices.WindowsRuntime.RuntimeClass a ComImport type
9748 // We can't do it using attribute as C# won't allow putting code in ComImport types
9749 pMT->SetComObjectType();
9751 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
9752 // the optional field descriptor.
9753 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
9756 if (bIsRuntimeClass)
9758 // Note that we set it here to avoid type loader considering RuntimeClass as a normal WindowsImportType
9759 // as functions in RuntimeClass doesn't go through COM interop
9760 GetHalfBakedClass()->SetProjectedFromWinRT();
9763 #endif // FEATURE_COMINTEROP
9767 //==========================================================================================
9768 // Helper to create a new method table. This is the only
9769 // way to allocate a new MT. Don't try calling new / ctor.
9770 // Called from SetupMethodTable
9771 // This needs to be kept consistent with MethodTable::GetSavedExtent()
9772 MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule,
9773 DWORD dwVtableSlots,
9776 DWORD dwNumInterfaces,
9778 DWORD cbInstAndDict,
9779 MethodTable *pMTParent,
9780 ClassLoader *pClassLoader,
9781 LoaderAllocator *pAllocator,
9783 BOOL fDynamicStatics,
9784 BOOL fHasGenericsStaticsInfo,
9785 BOOL fNeedsRCWPerTypeData
9786 #ifdef FEATURE_COMINTEROP
9787 , BOOL fHasDynamicInterfaceMap
9789 #ifdef FEATURE_PREJIT
9790 , Module *pComputedPZM
9791 #endif // FEATURE_PREJIT
9792 , AllocMemTracker *pamTracker
9795 CONTRACT (MethodTable*)
9800 POSTCONDITION(CheckPointer(RETVAL));
9804 DWORD dwNonVirtualSlots = dwVtableSlots - dwVirtuals;
9806 // GCSize must be aligned
9807 _ASSERTE(IS_ALIGNED(dwGCSize, sizeof(void*)));
9809 // size without the interface map
9810 S_SIZE_T cbTotalSize = S_SIZE_T(dwGCSize) + S_SIZE_T(sizeof(MethodTable));
9813 cbTotalSize += MethodTable::GetNumVtableIndirections(dwVirtuals) * sizeof(MethodTable::VTableIndir_t);
9816 DWORD dwMultipurposeSlotsMask = 0;
9817 if (dwNumInterfaces != 0)
9818 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasInterfaceMap;
9819 if (dwNumDicts != 0)
9820 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasPerInstInfo;
9821 if (bmtVT->pDispatchMapBuilder->Count() > 0)
9822 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasDispatchMapSlot;
9823 if (dwNonVirtualSlots != 0)
9824 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasNonVirtualSlots;
9825 if (pLoaderModule != GetModule())
9826 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasModuleOverride;
9828 // Add space for optional members here. Same as GetOptionalMembersSize()
9829 cbTotalSize += MethodTable::GetOptionalMembersAllocationSize(dwMultipurposeSlotsMask,
9830 fHasGenericsStaticsInfo,
9831 FALSE, // no GuidInfo needed for canonical instantiations
9832 FALSE, // no CCW template needed for canonical instantiations
9833 fNeedsRCWPerTypeData,
9834 RidFromToken(GetCl()) >= METHODTABLE_TOKEN_OVERFLOW);
9836 // Interface map starts here
9837 S_SIZE_T offsetOfInterfaceMap = cbTotalSize;
9839 cbTotalSize += S_SIZE_T(dwNumInterfaces) * S_SIZE_T(sizeof(InterfaceInfo_t));
9841 #ifdef FEATURE_COMINTEROP
9842 // DynamicInterfaceMap have an extra DWORD added to the end of the normal interface
9843 // map. This will be used to store the count of dynamically added interfaces
9844 // (the ones that are not in the metadata but are QI'ed for at runtime).
9845 cbTotalSize += S_SIZE_T(fHasDynamicInterfaceMap ? sizeof(DWORD_PTR) : 0);
9848 // Dictionary pointers start here
9849 S_SIZE_T offsetOfInstAndDict = cbTotalSize;
9851 if (dwNumDicts != 0)
9853 cbTotalSize += sizeof(GenericsDictInfo);
9854 cbTotalSize += S_SIZE_T(dwNumDicts) * S_SIZE_T(sizeof(MethodTable::PerInstInfoElem_t));
9855 cbTotalSize += cbInstAndDict;
9858 S_SIZE_T offsetOfUnsharedVtableChunks = cbTotalSize;
9860 BOOL canShareVtableChunks = pMTParent && MethodTable::CanShareVtableChunksFrom(pMTParent, pLoaderModule
9861 #ifdef FEATURE_PREJIT
9863 #endif //FEATURE_PREJIT
9866 // If pMTParent has a generic instantiation, we cannot share its vtable chunks
9867 // This is because pMTParent is only approximate at this point, and MethodTableBuilder::CopyExactParentSlots
9868 // may swap in an exact parent that does not satisfy CanShareVtableChunksFrom
9869 if (pMTParent && pMTParent->HasInstantiation())
9871 canShareVtableChunks = FALSE;
9874 // We will share any parent vtable chunk that does not contain a method we overrode (or introduced)
9875 // For the rest, we need to allocate space
9876 for (DWORD i = 0; i < dwVirtuals; i++)
9878 if (!canShareVtableChunks || ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
9880 DWORD chunkStart = MethodTable::GetStartSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
9881 DWORD chunkEnd = MethodTable::GetEndSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
9883 cbTotalSize += S_SIZE_T(chunkEnd - chunkStart) * S_SIZE_T(sizeof(PCODE));
9889 // Add space for the non-virtual slots array (pointed to by an optional member) if required
9890 // If there is only one non-virtual slot, we store it directly in the optional member and need no array
9891 S_SIZE_T offsetOfNonVirtualSlots = cbTotalSize;
9892 if (dwNonVirtualSlots > 1)
9894 cbTotalSize += S_SIZE_T(dwNonVirtualSlots) * S_SIZE_T(sizeof(PCODE));
9897 BYTE *pData = (BYTE *)pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(cbTotalSize));
9899 _ASSERTE(IS_ALIGNED(pData, TARGET_POINTER_SIZE));
9901 // There should be no overflows if we have allocated the memory succesfully
9902 _ASSERTE(!cbTotalSize.IsOverflow());
9904 MethodTable* pMT = (MethodTable*)(pData + dwGCSize);
9906 pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask);
9908 MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *)
9909 pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData))));
9910 // Note: Memory allocated on loader heap is zero filled
9911 pMT->SetWriteableData(pMTWriteableData);
9913 // This also disables IBC logging until the type is sufficiently intitialized so
9914 // it needs to be done early
9915 pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable();
9918 pClassLoader->m_dwGCSize += dwGCSize;
9919 pClassLoader->m_dwInterfaceMapSize += (dwNumInterfaces * sizeof(InterfaceInfo_t));
9920 pClassLoader->m_dwMethodTableSize += (DWORD)cbTotalSize.Value();
9921 pClassLoader->m_dwVtableData += (dwVtableSlots * sizeof(PCODE));
9924 // There should be no overflows if we have allocated the memory succesfully
9925 _ASSERTE(!offsetOfUnsharedVtableChunks.IsOverflow());
9926 _ASSERTE(!offsetOfNonVirtualSlots.IsOverflow());
9927 _ASSERTE(!offsetOfInterfaceMap.IsOverflow());
9928 _ASSERTE(!offsetOfInstAndDict.IsOverflow());
9930 // initialize the total number of slots
9931 pMT->SetNumVirtuals(static_cast<WORD>(dwVirtuals));
9933 pMT->SetParentMethodTable(pMTParent);
9935 // Fill out the vtable indirection slots
9936 SIZE_T dwCurrentUnsharedSlotOffset = offsetOfUnsharedVtableChunks.Value();
9937 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
9940 BOOL shared = canShareVtableChunks;
9942 // Recalculate whether we will share this chunk
9943 if (canShareVtableChunks)
9945 for (DWORD i = it.GetStartSlot(); i < it.GetEndSlot(); i++)
9947 if (ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
9957 // Share the parent chunk
9958 _ASSERTE(it.GetEndSlot() <= pMTParent->GetNumVirtuals());
9959 it.SetIndirectionSlot(pMTParent->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull());
9963 // Use the locally allocated chunk
9964 it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pData+dwCurrentUnsharedSlotOffset));
9965 dwCurrentUnsharedSlotOffset += it.GetSize();
9969 #ifdef FEATURE_COMINTEROP
9970 // Extensible RCW's are prefixed with the count of dynamic interfaces.
9971 if (fHasDynamicInterfaceMap)
9973 _ASSERTE (dwNumInterfaces > 0);
9974 pMT->SetInterfaceMap ((WORD) (dwNumInterfaces), (InterfaceInfo_t*)(pData+offsetOfInterfaceMap.Value()+sizeof(DWORD_PTR)));
9976 *(((DWORD_PTR *)pMT->GetInterfaceMap()) - 1) = 0;
9979 #endif // FEATURE_COMINTEROP
9981 // interface map is at the end of the vtable
9982 pMT->SetInterfaceMap ((WORD) dwNumInterfaces, (InterfaceInfo_t *)(pData+offsetOfInterfaceMap.Value()));
9985 _ASSERTE(((WORD) dwNumInterfaces) == dwNumInterfaces);
9987 if (fDynamicStatics)
9989 pMT->SetDynamicStatics(fHasGenericsStaticsInfo);
9992 if (dwNonVirtualSlots > 0)
9994 if (dwNonVirtualSlots > 1)
9996 pMT->SetNonVirtualSlotsArray((PTR_PCODE)(pData+offsetOfNonVirtualSlots.Value()));
10000 pMT->SetHasSingleNonVirtualSlot();
10004 // the dictionary pointers follow the interface map
10007 MethodTable::PerInstInfoElem_t *pPerInstInfo = (MethodTable::PerInstInfoElem_t *)(pData + offsetOfInstAndDict.Value() + sizeof(GenericsDictInfo));
10009 pMT->SetPerInstInfo ( pPerInstInfo);
10011 // Fill in the dictionary for this type, if it's instantiated
10014 MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *)(pPerInstInfo + (dwNumDicts-1));
10015 pPInstInfo->SetValueMaybeNull((Dictionary*) (pPerInstInfo + dwNumDicts));
10020 pMT->m_pWriteableData.GetValue()->m_dwLastVerifedGCCnt = (DWORD)-1;
10027 //*******************************************************************************
10029 // Used by BuildMethodTable
10031 // Setup the method table
10034 #pragma warning(push)
10035 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
10036 #endif // _PREFAST_
10039 MethodTableBuilder::SetupMethodTable2(
10040 Module * pLoaderModule
10041 #ifdef FEATURE_PREJIT
10042 , Module * pComputedPZM
10043 #endif // FEATURE_PREJIT
10049 PRECONDITION(CheckPointer(this));
10050 PRECONDITION(CheckPointer(bmtVT));
10051 PRECONDITION(CheckPointer(bmtInterface));
10052 PRECONDITION(CheckPointer(bmtInternal));
10053 PRECONDITION(CheckPointer(bmtProp));
10054 PRECONDITION(CheckPointer(bmtMFDescs));
10055 PRECONDITION(CheckPointer(bmtEnumFields));
10056 PRECONDITION(CheckPointer(bmtError));
10057 PRECONDITION(CheckPointer(bmtMetaData));
10058 PRECONDITION(CheckPointer(bmtParent));
10059 PRECONDITION(CheckPointer(bmtGenerics));
10065 #ifdef FEATURE_COMINTEROP
10066 BOOL fHasDynamicInterfaceMap = bmtInterface->dwInterfaceMapSize > 0 &&
10067 bmtProp->fIsComObjectType &&
10068 (GetParentMethodTable() != g_pObjectClass);
10069 BOOL fNeedsRCWPerTypeData = bmtProp->fNeedsRCWPerTypeData;
10070 #else // FEATURE_COMINTEROP
10071 BOOL fNeedsRCWPerTypeData = FALSE;
10072 #endif // FEATURE_COMINTEROP
10074 EEClass *pClass = GetHalfBakedClass();
10076 DWORD cbDict = bmtGenerics->HasInstantiation()
10077 ? DictionaryLayout::GetFirstDictionaryBucketSize(
10078 bmtGenerics->GetNumGenericArgs(), pClass->GetDictionaryLayout())
10081 #ifdef FEATURE_COLLECTIBLE_TYPES
10082 BOOL fCollectible = pLoaderModule->IsCollectible();
10083 #endif // FEATURE_COLLECTIBLE_TYPES
10087 if (bmtFP->NumGCPointerSeries > 0)
10089 dwGCSize = (DWORD)CGCDesc::ComputeSize(bmtFP->NumGCPointerSeries);
10093 #ifdef FEATURE_COLLECTIBLE_TYPES
10095 dwGCSize = (DWORD)CGCDesc::ComputeSize(1);
10097 #endif // FEATURE_COLLECTIBLE_TYPES
10101 pClass->SetNumMethods(bmtVT->cTotalSlots);
10102 pClass->SetNumNonVirtualSlots(bmtVT->cVtableSlots - bmtVT->cVirtualSlots);
10104 // Now setup the method table
10105 // interface map is allocated along with the method table
10106 MethodTable *pMT = AllocateNewMT(pLoaderModule,
10107 bmtVT->cVtableSlots,
10108 bmtVT->cVirtualSlots,
10110 bmtInterface->dwInterfaceMapSize,
10111 bmtGenerics->numDicts,
10113 GetParentMethodTable(),
10117 bmtProp->fDynamicStatics,
10118 bmtProp->fGenericsStatics,
10119 fNeedsRCWPerTypeData,
10120 #ifdef FEATURE_COMINTEROP
10121 fHasDynamicInterfaceMap,
10123 #ifdef FEATURE_PREJIT
10125 #endif //FEATURE_PREJIT
10128 pMT->SetClass(pClass);
10129 pClass->m_pMethodTable.SetValue(pMT);
10130 m_pHalfBakedMT = pMT;
10133 pMT->SetDebugClassName(GetDebugClassName());
10136 #ifdef FEATURE_COMINTEROP
10137 if (fNeedsRCWPerTypeData)
10138 pMT->SetHasRCWPerTypeData();
10139 #endif // FEATURE_COMINTEROP
10143 pMT->SetIsInterface();
10145 if (GetParentMethodTable() != NULL)
10147 if (GetParentMethodTable()->HasModuleDependencies())
10149 pMT->SetHasModuleDependencies();
10153 Module * pModule = GetModule();
10154 Module * pParentModule = GetParentMethodTable()->GetModule();
10155 if (pModule != pParentModule)
10157 pMT->SetHasModuleDependencies();
10161 if (GetParentMethodTable()->HasPreciseInitCctors() || !pClass->IsBeforeFieldInit())
10163 pMT->SetHasPreciseInitCctors();
10167 // Must be done early because various methods test HasInstantiation() and ContainsGenericVariables()
10168 if (bmtGenerics->GetNumGenericArgs() != 0)
10170 pMT->SetHasInstantiation(bmtGenerics->fTypicalInstantiation, bmtGenerics->fSharedByGenericInstantiations);
10172 if (bmtGenerics->fContainsGenericVariables)
10173 pMT->SetContainsGenericVariables();
10176 if (bmtGenerics->numDicts != 0)
10178 if (!FitsIn<WORD>(bmtGenerics->GetNumGenericArgs()))
10180 BuildMethodTableThrowException(IDS_CLASSLOAD_TOOMANYGENERICARGS);
10183 pMT->SetDictInfo(bmtGenerics->numDicts,
10184 static_cast<WORD>(bmtGenerics->GetNumGenericArgs()));
10187 CONSISTENCY_CHECK(pMT->GetNumGenericArgs() == bmtGenerics->GetNumGenericArgs());
10188 CONSISTENCY_CHECK(pMT->GetNumDicts() == bmtGenerics->numDicts);
10189 CONSISTENCY_CHECK(pMT->HasInstantiation() == bmtGenerics->HasInstantiation());
10190 CONSISTENCY_CHECK(pMT->HasInstantiation() == !pMT->GetInstantiation().IsEmpty());
10192 pMT->SetLoaderModule(pLoaderModule);
10193 pMT->SetLoaderAllocator(bmtAllocator);
10195 pMT->SetModule(GetModule());
10197 pMT->SetInternalCorElementType (ELEMENT_TYPE_CLASS);
10199 SetNonGCRegularStaticFieldBytes (bmtProp->dwNonGCRegularStaticFieldBytes);
10200 SetNonGCThreadStaticFieldBytes (bmtProp->dwNonGCThreadStaticFieldBytes);
10202 #ifdef FEATURE_TYPEEQUIVALENCE
10203 if (bmtProp->fHasTypeEquivalence)
10205 pMT->SetHasTypeEquivalence();
10207 #endif //FEATURE_TYPEEQUIVALENCE
10209 #ifdef FEATURE_COMINTEROP
10210 if (bmtProp->fSparse)
10211 pClass->SetSparseForCOMInterop();
10213 if (IsInterface() && IsComImport())
10215 // Determine if we are creating an interface methodtable that may be used to dispatch through VSD
10216 // on an object that has the methodtable of __ComObject.
10218 // This is done to allow COM tearoff interfaces, but as a side-effect of this feature,
10219 // we end up using a domain-shared type (__ComObject) with a domain-specific dispatch token.
10220 // This is a problem because the same domain-specific dispatch token value can appear in
10221 // multiple unshared domains (VSD takes advantage of the fact that in general a shared type
10222 // cannot implement an unshared interface). This means that the same <token, __ComObject> pair
10223 // value can mean different things in different domains (since the token could represent
10224 // IFoo in one domain and IBar in another). This is a problem because the
10225 // VSD polymorphic lookup mechanism relies on a process-wide cache table, and as a result
10226 // these duplicate values would collide if we didn't use fat dispatch token to ensure uniqueness
10227 // and the interface methodtable is not in the shared domain.
10229 pMT->SetRequiresFatDispatchTokens();
10231 #endif // FEATURE_COMINTEROP
10233 if (bmtVT->pCCtor != NULL)
10235 pMT->SetHasClassConstructor();
10236 CONSISTENCY_CHECK(pMT->GetClassConstructorSlot() == bmtVT->pCCtor->GetSlotIndex());
10238 if (bmtVT->pDefaultCtor != NULL)
10240 pMT->SetHasDefaultConstructor();
10241 CONSISTENCY_CHECK(pMT->GetDefaultConstructorSlot() == bmtVT->pDefaultCtor->GetSlotIndex());
10244 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10246 pChunk->SetMethodTable(pMT);
10251 // disable ibc logging because we can assert in ComputerPreferredZapModule for partially constructed
10253 IBCLoggingDisabler disableLogging;
10255 DeclaredMethodIterator it(*this);
10258 MethodDesc *pMD = it->GetMethodDesc();
10261 pMD->m_pDebugMethodTable.SetValue(pMT);
10262 pMD->m_pszDebugMethodSignature = FormatSig(pMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10264 MethodDesc *pUnboxedMD = it->GetUnboxedMethodDesc();
10265 if (pUnboxedMD != NULL)
10267 pUnboxedMD->m_pDebugMethodTable.SetValue(pMT);
10268 pUnboxedMD->m_pszDebugMethodSignature = FormatSig(pUnboxedMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10274 // Note that for value classes, the following calculation is only appropriate
10275 // when the instance is in its "boxed" state.
10276 if (!IsInterface())
10278 DWORD baseSize = Max<DWORD>(bmtFP->NumInstanceFieldBytes + OBJECT_BASESIZE, MIN_OBJECT_SIZE);
10279 baseSize = (baseSize + ALLOC_ALIGN_CONSTANT) & ~ALLOC_ALIGN_CONSTANT; // m_BaseSize must be aligned
10280 pMT->SetBaseSize(baseSize);
10282 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
10284 if (bmtProp->fIsComObjectType)
10285 { // Propagate the com specific info
10286 pMT->SetComObjectType();
10287 #ifdef FEATURE_COMINTEROP
10288 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
10289 // the optional field descriptor.
10290 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10291 #endif // FEATURE_COMINTEROP
10294 #ifdef FEATURE_COMINTEROP
10295 if (pMT->GetAssembly()->IsManagedWinMD())
10297 // We need to mark classes that are implementations of managed WinRT runtime classes with
10298 // the "exported to WinRT" flag. It's not quite possible to tell which ones these are by
10299 // reading metadata so we ask the adapter.
10301 IWinMDImport *pWinMDImport = pMT->GetAssembly()->GetManifestWinMDImport();
10302 _ASSERTE(pWinMDImport != NULL);
10305 IfFailThrow(pWinMDImport->IsRuntimeClassImplementation(GetCl(), &bResult));
10309 pClass->SetExportedToWinRT();
10311 // We need optional fields for activation from WinRT.
10312 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10316 if (pClass->IsProjectedFromWinRT() || pClass->IsExportedToWinRT())
10320 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), g_WindowsFoundationMarshalingBehaviorAttributeClassName, (const void **) &pVal, &cbVal);
10323 CustomAttributeParser cap(pVal, cbVal);
10324 IfFailThrow(cap.SkipProlog());
10326 IfFailThrow(cap.GetU4(&u));
10328 pClass->SetMarshalingType(u);
10331 #endif // FEATURE_COMINTEROP
10335 #ifdef FEATURE_COMINTEROP
10336 // If this is an interface then we need to set the ComInterfaceType to
10337 // -1 to indicate we have not yet determined the interface type.
10338 pClass->SetComInterfaceType((CorIfaceAttr)-1);
10340 // If this is a special COM event interface, then mark the MT as such.
10341 if (bmtProp->fComEventItfType)
10343 pClass->SetComEventItfType();
10345 #endif // FEATURE_COMINTEROP
10347 _ASSERTE((pMT->IsInterface() == 0) == (IsInterface() == 0));
10351 pClass->SetNativeSize(GetLayoutInfo()->GetNativeSize());
10354 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
10355 // Set all field slots to point to the newly created MethodTable
10356 for (i = 0; i < (bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields); i++)
10358 pFieldDescList[i].m_pMTOfEnclosingClass.SetValue(pMT);
10361 // Fill in type parameters before looking up exact parent or fetching the types of any field descriptors!
10362 // This must come before the use of GetFieldType in the value class representation optimization below.
10363 if (bmtGenerics->GetNumGenericArgs() != 0)
10365 // Space has already been allocated for the instantiation but the parameters haven't been filled in
10366 Instantiation destInst = pMT->GetInstantiation();
10367 Instantiation inst = bmtGenerics->GetInstantiation();
10369 // So fill them in...
10370 TypeHandle * pInstDest = (TypeHandle *)destInst.GetRawArgs();
10371 for (DWORD j = 0; j < bmtGenerics->GetNumGenericArgs(); j++)
10373 pInstDest[j] = inst[j];
10377 CorElementType normalizedType = ELEMENT_TYPE_CLASS;
10378 if (IsValueClass())
10382 if (GetNumInstanceFields() != 1 ||
10383 !CorTypeInfo::IsPrimitiveType(pFieldDescList[0].GetFieldType()))
10385 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
10387 CONSISTENCY_CHECK(!pFieldDescList[0].IsStatic());
10388 normalizedType = pFieldDescList->GetFieldType();
10392 #ifdef _TARGET_X86_
10393 // JIT64 is not aware of normalized value types and this
10394 // optimization (return small value types by value in registers)
10395 // is already done in JIT64.
10396 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10397 normalizedType = EEClass::ComputeInternalCorElementTypeForValueType(pMT);
10399 normalizedType = ELEMENT_TYPE_VALUETYPE;
10403 pMT->SetInternalCorElementType(normalizedType);
10405 if (bmtProp->fIsIntrinsicType)
10407 pMT->SetIsIntrinsicType();
10410 if (GetModule()->IsSystem())
10412 // we are in mscorlib
10413 CheckForSystemTypes();
10416 // Now fill in the real interface map with the approximate interfaces
10417 if (bmtInterface->dwInterfaceMapSize > 0)
10419 // First ensure we have enough space to record extra flag information for each interface (we don't
10420 // record this directly into each interface map entry since these flags don't pack well due to
10422 PVOID pExtraInterfaceInfo = NULL;
10423 SIZE_T cbExtraInterfaceInfo = MethodTable::GetExtraInterfaceInfoSize(bmtInterface->dwInterfaceMapSize);
10424 if (cbExtraInterfaceInfo)
10425 pExtraInterfaceInfo = GetMemTracker()->Track(GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbExtraInterfaceInfo)));
10427 // Call this even in the case where pExtraInterfaceInfo == NULL (certain cases are optimized and don't
10428 // require extra buffer space).
10429 pMT->InitializeExtraInterfaceInfo(pExtraInterfaceInfo);
10431 InterfaceInfo_t *pInterfaces = pMT->GetInterfaceMap();
10433 CONSISTENCY_CHECK(CheckPointer(pInterfaces));
10435 // Copy the interface map member by member so there is no junk in the padding.
10436 for (i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
10438 bmtInterfaceEntry * pEntry = &bmtInterface->pInterfaceMap[i];
10440 if (pEntry->IsDeclaredOnType())
10441 pMT->SetInterfaceDeclaredOnClass(i);
10442 _ASSERTE(!!pEntry->IsDeclaredOnType() == !!pMT->IsInterfaceDeclaredOnClass(i));
10444 pInterfaces[i].SetMethodTable(pEntry->GetInterfaceType()->GetMethodTable());
10448 pMT->SetCl(GetCl());
10450 // The type is sufficiently initialized for most general purpose accessor methods to work.
10451 // Mark the type as restored to avoid avoid asserts. Note that this also enables IBC logging.
10452 pMT->GetWriteableDataForWrite_NoLogging()->SetIsRestoredForBuildMethodTable();
10455 // Store status if we tried to inject duplicate interfaces
10456 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
10457 pMT->Debug_SetHasInjectedInterfaceDuplicates();
10460 // Keep bmtInterface data around since we no longer write the flags (IsDeclaredOnType and
10461 // IsImplementedByParent) into the interface map (these flags are only required during type loading).
10464 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10466 // Make sure that temporary entrypoints are create for methods. NGEN uses temporary
10467 // entrypoints as surrogate keys for precodes.
10468 pChunk->EnsureTemporaryEntryPointsCreated(GetLoaderAllocator(), GetMemTracker());
10472 { // copy onto the real vtable (methods only)
10473 //@GENERICS: Because we sometimes load an inexact parent (see ClassLoader::GetParent) the inherited slots might
10474 // come from the wrong place and need fixing up once we know the exact parent
10476 for (bmtVtable::Iterator slotIt = bmtVT->IterateSlots(); !slotIt.AtEnd(); ++slotIt)
10478 SLOT_INDEX iCurSlot = static_cast<SLOT_INDEX>(slotIt.CurrentIndex());
10480 // We want the unboxed MethodDesc if we're out of the virtual method range
10481 // and the method we're dealing with has an unboxing method. If so, then
10482 // the unboxing method was placed in the virtual section of the vtable and
10483 // we now need to place the unboxed version.
10484 MethodDesc * pMD = NULL;
10485 if (iCurSlot < bmtVT->cVirtualSlots || !slotIt->Impl().AsMDMethod()->IsUnboxing())
10487 pMD = slotIt->Impl().GetMethodDesc();
10488 CONSISTENCY_CHECK(slotIt->Decl().GetSlotIndex() == iCurSlot);
10492 pMD = slotIt->Impl().AsMDMethod()->GetUnboxedMethodDesc();
10493 CONSISTENCY_CHECK(pMD->GetSlot() == iCurSlot);
10496 CONSISTENCY_CHECK(CheckPointer(pMD));
10498 if (pMD->GetMethodTable() != pMT)
10503 // Do not write into vtable chunks shared with parent. It would introduce race
10504 // with code:MethodDesc::SetStableEntryPointInterlocked.
10506 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(iCurSlot);
10507 if (GetParentMethodTable()->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() != pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull())
10508 pMT->SetSlot(iCurSlot, pMD->GetInitialEntryPointForCopiedSlot());
10515 _ASSERTE(iCurSlot >= bmtVT->cVirtualSlots || ChangesImplementationOfVirtualSlot(iCurSlot));
10517 PCODE addr = pMD->GetTemporaryEntryPoint();
10518 _ASSERTE(addr != NULL);
10520 if (pMD->HasNonVtableSlot())
10522 *((PCODE *)pMD->GetAddrOfSlot()) = addr;
10526 pMT->SetSlot(iCurSlot, addr);
10529 if (pMD->GetSlot() == iCurSlot && pMD->RequiresStableEntryPoint())
10531 // The rest of the system assumes that certain methods always have stable entrypoints.
10532 // Create them now.
10533 pMD->GetOrCreatePrecode();
10539 // If we have any entries, then finalize them and allocate the object in class loader heap
10540 DispatchMap *pDispatchMap = NULL;
10541 DispatchMapBuilder *pDispatchMapBuilder = bmtVT->pDispatchMapBuilder;
10542 CONSISTENCY_CHECK(CheckPointer(pDispatchMapBuilder));
10544 if (pDispatchMapBuilder->Count() > 0)
10546 // Create a map in stacking memory.
10549 DispatchMap::CreateEncodedMapping(
10551 pDispatchMapBuilder,
10552 pDispatchMapBuilder->GetAllocator(),
10556 // Now finalize the impltable and allocate the block in the low frequency loader heap
10557 size_t objSize = (size_t) DispatchMap::GetObjectSize(cbMap);
10558 void * pv = AllocateFromLowFrequencyHeap(S_SIZE_T(objSize));
10559 _ASSERTE(pv != NULL);
10561 // Use placement new
10562 pDispatchMap = new (pv) DispatchMap(pbMap, cbMap);
10563 pMT->SetDispatchMap(pDispatchMap);
10566 g_sdStats.m_cDispatchMap++;
10567 g_sdStats.m_cbDispatchMap += (UINT32) objSize;
10568 LOG((LF_LOADER, LL_INFO1000, "SD: Dispatch map for %s: %d bytes for map, %d bytes total for object.\n",
10569 pMT->GetDebugClassName(), cbMap, objSize));
10574 // GetMethodData by default will cache its result. However, in the case that we're
10575 // building a MethodTable, we aren't guaranteed that this type is going to successfully
10576 // load and so caching it would result in errors down the road since the memory and
10577 // type occupying the same memory location would very likely be incorrect. The second
10578 // argument specifies that GetMethodData should not cache the returned object.
10579 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
10581 if (!IsInterface())
10583 // Propagate inheritance.
10585 // NOTE: In the world of unfolded interface this was used to propagate overrides into
10586 // the unfolded interface vtables to make sure that overrides of virtual methods
10587 // also overrode the interface methods that they contributed to. This had the
10588 // unfortunate side-effect of also overwriting regular vtable slots that had been
10589 // methodimpl'd and as a result changed the meaning of methodimpl from "substitute
10590 // the body of method A with the body of method B" to "unify the slots of methods
10591 // A and B". But now compilers have come to rely on this side-effect and it can
10592 // not be brought back to its originally intended behaviour.
10594 // For every slot whose body comes from another slot (determined by getting the MethodDesc
10595 // for a slot and seeing if MethodDesc::GetSlot returns a different value than the slot
10596 // from which the MethodDesc was recovered), copy the value of the slot stated by the
10597 // MethodDesc over top of the current slot.
10599 // Because of the way slot unification works, we need to iterate the enture vtable until
10600 // no slots need updated. To understand this, imagine the following:
10601 // C1::M1 is overridden by C2::M2
10602 // C1::M2 is methodImpled by C1::M3
10603 // C1::M3 is overridden by C2::M3
10604 // This should mean that C1::M1 is implemented by C2::M3, but if we didn't run the below
10605 // for loop a second time, this would not be propagated properly - it would only be placed
10606 // into the slot for C1::M2 and never make its way up to C1::M1.
10611 fChangeMade = FALSE;
10612 for (i = 0; i < pMT->GetNumVirtuals(); i++)
10614 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
10616 CONSISTENCY_CHECK(CheckPointer(pMD));
10617 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
10619 // This indicates that the method body in this slot was copied here through a methodImpl.
10620 // Thus, copy the value of the slot from which the body originally came, in case it was
10621 // overridden, to make sure the two slots stay in sync.
10622 DWORD originalIndex = pMD->GetSlot();
10623 if (originalIndex != i)
10625 MethodDesc *pOriginalMD = hMTData->GetImplMethodDesc(originalIndex);
10626 CONSISTENCY_CHECK(CheckPointer(pOriginalMD));
10627 CONSISTENCY_CHECK(pOriginalMD == pMT->GetMethodDescForSlot(originalIndex));
10628 if (pMD != pOriginalMD)
10630 // Copy the slot value in the method's original slot.
10631 pMT->SetSlot(i, pOriginalMD->GetInitialEntryPointForCopiedSlot());
10632 hMTData->InvalidateCachedVirtualSlot(i);
10634 // Update the pMD to the new method desc we just copied over ourselves with. This will
10635 // be used in the check for missing method block below.
10638 // This method is now duplicate
10639 pMD->SetDuplicate();
10640 INDEBUG(g_dupMethods++;)
10641 fChangeMade = TRUE;
10646 while (fChangeMade);
10649 if (!bmtProp->fNoSanityChecks)
10650 VerifyVirtualMethodsImplemented(hMTData);
10654 for (bmtVtable::Iterator i = bmtVT->IterateSlots();
10657 _ASSERTE(i->Impl().GetMethodDesc() != NULL);
10663 #ifdef FEATURE_COMINTEROP
10664 // for ComObject types, i.e. if the class extends from a COM Imported
10666 // make sure any interface implementated by the COM Imported class
10667 // is overridden fully, (OR) not overridden at all..
10668 // We relax this for WinRT where we want to be able to override individual methods.
10669 if (bmtProp->fIsComObjectType && !pMT->IsWinRTObjectType())
10671 MethodTable::InterfaceMapIterator intIt = pMT->IterateInterfaceMap();
10672 while (intIt.Next())
10674 MethodTable* pIntfMT = intIt.GetInterface();
10675 if (pIntfMT->GetNumVirtuals() != 0)
10677 BOOL hasComImportMethod = FALSE;
10678 BOOL hasManagedMethod = FALSE;
10680 // NOTE: Avoid caching the MethodData object for the type being built.
10681 MethodTable::MethodDataWrapper hItfImplData(MethodTable::GetMethodData(pIntfMT, pMT, FALSE));
10682 MethodTable::MethodIterator it(hItfImplData);
10683 for (;it.IsValid(); it.Next())
10685 MethodDesc *pClsMD = NULL;
10686 // If we fail to find an _IMPLEMENTATION_ for the interface MD, then
10687 // we are a ComImportMethod, otherwise we still be a ComImportMethod or
10688 // we can be a ManagedMethod.
10689 DispatchSlot impl(it.GetTarget());
10690 if (!impl.IsNull())
10692 pClsMD = it.GetMethodDesc();
10694 CONSISTENCY_CHECK(!pClsMD->IsInterface());
10695 if (pClsMD->GetClass()->IsComImport())
10697 hasComImportMethod = TRUE;
10701 hasManagedMethod = TRUE;
10706 // Need to set the pClsMD for the error reporting below.
10707 pClsMD = it.GetDeclMethodDesc();
10708 CONSISTENCY_CHECK(CheckPointer(pClsMD));
10709 hasComImportMethod = TRUE;
10712 // One and only one of the two must be set.
10713 if ((hasComImportMethod && hasManagedMethod) ||
10714 (!hasComImportMethod && !hasManagedMethod))
10716 BuildMethodTableThrowException(IDS_EE_BAD_COMEXTENDS_CLASS, pClsMD->GetNameOnNonArrayClass());
10723 // For COM event interfaces, we need to make sure that all the methods are
10724 // methods to add or remove events. This means that they all need to take
10725 // a delegate derived class and have a void return type.
10726 if (bmtProp->fComEventItfType)
10728 // COM event interfaces had better be interfaces.
10729 CONSISTENCY_CHECK(IsInterface());
10731 // Go through all the methods and check the validity of the signature.
10732 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
10733 MethodTable::MethodIterator it(hMTData);
10734 for (;it.IsValid(); it.Next())
10736 MethodDesc* pMD = it.GetMethodDesc();
10742 CONTRACT_VIOLATION(LoadsTypeViolation);
10743 if (Sig.GetReturnType() != ELEMENT_TYPE_VOID ||
10744 Sig.NumFixedArgs() != 1 ||
10745 Sig.NextArg() != ELEMENT_TYPE_CLASS ||
10746 !Sig.GetLastTypeHandleThrowing().CanCastTo(TypeHandle(g_pDelegateClass)))
10748 BuildMethodTableThrowException(IDS_EE_BAD_COMEVENTITF_CLASS, pMD->GetNameOnNonArrayClass());
10753 #endif // FEATURE_COMINTEROP
10755 // If this class uses any VTS (Version Tolerant Serialization) features
10756 // (event callbacks or OptionalField attributes) we've previously cached the
10757 // additional information in the bmtMFDescs structure. Now it's time to add
10758 // this information as an optional extension to the MethodTable.
10761 #pragma warning(pop)
10764 // Returns true if there is at least one default implementation for this interface method
10765 // We don't care about conflicts at this stage in order to avoid impact type load performance
10766 BOOL MethodTableBuilder::HasDefaultInterfaceImplementation(bmtRTType *pDeclType, MethodDesc *pDeclMD)
10768 STANDARD_VM_CONTRACT;
10770 #ifdef FEATURE_DEFAULT_INTERFACES
10771 // If the interface method is already non-abstract, we are done
10772 if (!pDeclMD->IsAbstract())
10775 int targetSlot = pDeclMD->GetSlot();
10777 // Iterate over all the interfaces this type implements
10778 bmtInterfaceEntry * pItfEntry = NULL;
10779 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
10781 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
10783 Module * pCurIntfModule = pCurItf->GetMethodTable()->GetModule();
10785 // Go over the methods on the interface
10786 MethodTable::IntroducedMethodIterator methIt(pCurItf->GetMethodTable());
10787 for (; methIt.IsValid(); methIt.Next())
10789 MethodDesc * pPotentialImpl = methIt.GetMethodDesc();
10791 // If this interface method is not a MethodImpl, it can't possibly implement
10792 // the interface method we are looking for
10793 if (!pPotentialImpl->IsMethodImpl())
10796 // Go over all the decls this MethodImpl is implementing
10797 MethodImpl::Iterator it(pPotentialImpl);
10798 for (; it.IsValid(); it.Next())
10800 MethodDesc *pPotentialDecl = it.GetMethodDesc();
10802 // Check this is a decl with the right slot
10803 if (pPotentialDecl->GetSlot() != targetSlot)
10806 // Find out what interface this default implementation is implementing
10808 IfFailThrow(pCurIntfModule->GetMDImport()->GetParentToken(it.GetToken(), &tkParent));
10810 // We can only load the approximate interface at this point
10811 MethodTable * pPotentialInterfaceMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
10814 &bmtGenerics->typeContext,
10815 ClassLoader::ThrowIfNotFound,
10816 ClassLoader::PermitUninstDefOrRef,
10817 ClassLoader::LoadTypes,
10818 CLASS_LOAD_APPROXPARENTS,
10819 TRUE).GetMethodTable()->GetCanonicalMethodTable();
10821 // Is this a default implementation for the interface we are looking for?
10822 if (pDeclType->GetMethodTable()->HasSameTypeDefAs(pPotentialInterfaceMT))
10824 // If the type is not generic, matching defs are all we need
10825 if (!pDeclType->GetMethodTable()->HasInstantiation())
10828 // If this is generic, we need to compare under substitutions
10829 Substitution curItfSubs(tkParent, pCurIntfModule, &pCurItf->GetSubstitution());
10831 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
10832 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
10833 if (MetaSig::CompareTypeDefsUnderSubstitutions(
10834 pPotentialInterfaceMT, pDeclType->GetMethodTable(),
10835 &curItfSubs, &pDeclType->GetSubstitution(),
10844 #endif // FEATURE_DEFAULT_INTERFACES
10849 void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData * hMTData)
10851 STANDARD_VM_CONTRACT;
10854 // This verification is not applicable or required in many cases
10857 if (IsAbstract() || IsInterface())
10860 #ifdef FEATURE_COMINTEROP
10861 // Note that this is important for WinRT where redirected .NET interfaces appear on the interface
10862 // impl list but their methods are not implemented (the adapter only hides the WinRT methods, it
10863 // does not make up the .NET ones).
10864 if (bmtProp->fIsComObjectType)
10866 #endif // FEATURE_COMINTEROP
10868 // Since interfaces aren't laid out in the vtable for stub dispatch, what we need to do
10869 // is try to find an implementation for every interface contract by iterating through
10870 // the interfaces not declared on a parent.
10871 BOOL fParentIsAbstract = FALSE;
10874 fParentIsAbstract = GetParentMethodTable()->IsAbstract();
10877 // If the parent is abstract, we need to check that each virtual method is implemented
10878 if (fParentIsAbstract)
10880 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
10881 MethodTable::MethodIterator it(hMTData);
10882 for (; it.IsValid() && it.IsVirtual(); it.Next())
10884 MethodDesc *pMD = it.GetMethodDesc();
10885 if (pMD->IsAbstract())
10887 MethodDesc *pDeclMD = it.GetDeclMethodDesc();
10888 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pDeclMD->GetNameOnNonArrayClass());
10893 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs =
10894 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
10896 bmtInterfaceInfo::MapIterator intIt = bmtInterface->IterateInterfaceMap();
10897 for (; !intIt.AtEnd(); intIt.Next())
10899 if (fParentIsAbstract || !intIt->IsImplementedByParent())
10901 // Compute all TypeIDs for this interface (all duplicates in the interface map)
10902 UINT32 cInterfaceDuplicates;
10903 ComputeDispatchMapTypeIDs(
10904 intIt->GetInterfaceType()->GetMethodTable(),
10905 &intIt->GetInterfaceType()->GetSubstitution(),
10906 rgInterfaceDispatchMapTypeIDs,
10907 bmtInterface->dwInterfaceMapSize,
10908 &cInterfaceDuplicates);
10909 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
10910 _ASSERTE(cInterfaceDuplicates > 0);
10912 // NOTE: This override does not cache the resulting MethodData object.
10913 MethodTable::MethodDataWrapper hData(MethodTable::GetMethodData(
10914 rgInterfaceDispatchMapTypeIDs,
10915 cInterfaceDuplicates,
10916 intIt->GetInterfaceType()->GetMethodTable(),
10917 GetHalfBakedMethodTable()));
10918 MethodTable::MethodIterator it(hData);
10919 for (; it.IsValid() && it.IsVirtual(); it.Next())
10921 if (it.GetTarget().IsNull())
10923 MethodDesc *pMD = it.GetDeclMethodDesc();
10925 if (!HasDefaultInterfaceImplementation(intIt->GetInterfaceType(), pMD))
10926 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass());
10933 INT32 __stdcall IsDefined(Module *pModule, mdToken token, TypeHandle attributeClass)
10942 BOOL isDefined = FALSE;
10944 IMDInternalImport *pInternalImport = pModule->GetMDImport();
10945 BOOL isSealed = FALSE;
10947 HENUMInternalHolder hEnum(pInternalImport);
10950 // Get the enum first but don't get any values
10951 hEnum.EnumInit(mdtCustomAttribute, token);
10953 ULONG cMax = pInternalImport->EnumGetCount(&hEnum);
10956 // we have something to look at
10959 if (!attributeClass.IsNull())
10960 isSealed = attributeClass.GetMethodTable()->IsSealed();
10962 // Loop through the Attributes and look for the requested one
10963 mdCustomAttribute cv;
10964 while (pInternalImport->EnumNext(&hEnum, &cv))
10969 IfFailThrow(pInternalImport->GetCustomAttributeProps(cv, &tkCtor));
10971 mdToken tkType = TypeFromToken(tkCtor);
10972 if(tkType != mdtMemberRef && tkType != mdtMethodDef)
10973 continue; // we only deal with the ctor case
10976 // get the info to load the type, so we can check whether the current
10977 // attribute is a subtype of the requested attribute
10978 IfFailThrow(pInternalImport->GetParentToken(tkCtor, &tkType));
10980 _ASSERTE(TypeFromToken(tkType) == mdtTypeRef || TypeFromToken(tkType) == mdtTypeDef);
10984 caTH=ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
10985 ClassLoader::ReturnNullIfNotFound,
10986 ClassLoader::FailIfUninstDefOrRef,
10987 TypeFromToken(tkType) == mdtTypeDef ? tdAllTypes : tdNoTypes);
10991 caTH = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
10992 ClassLoader::ReturnNullIfNotFound,
10993 ClassLoader::FailIfUninstDefOrRef);
10998 // a null class implies all custom attribute
10999 if (!attributeClass.IsNull())
11003 if (attributeClass != caTH)
11008 if (!caTH.CanCastTo(attributeClass))
11014 // if we are here we got one
11023 //*******************************************************************************
11024 VOID MethodTableBuilder::CheckForRemotingProxyAttrib()
11026 STANDARD_VM_CONTRACT;
11031 //*******************************************************************************
11032 // Checks for a bunch of special interface names and if it matches then it sets
11033 // bmtProp->fIsMngStandardItf to TRUE. Additionally, it checks to see if the
11034 // type is an interface and if it has ComEventInterfaceAttribute custom attribute
11035 // set, then it sets bmtProp->fComEventItfType to true.
11037 // NOTE: This only does anything when COM interop is enabled.
11039 VOID MethodTableBuilder::CheckForSpecialTypes()
11041 #ifdef FEATURE_COMINTEROP
11042 STANDARD_VM_CONTRACT;
11045 Module *pModule = GetModule();
11046 IMDInternalImport *pMDImport = pModule->GetMDImport();
11048 // Check to see if this type is a managed standard interface. All the managed
11049 // standard interfaces live in mscorlib.dll so checking for that first
11050 // makes the strcmp that comes afterwards acceptable.
11051 if (pModule->IsSystem())
11055 LPCUTF8 pszClassName;
11056 LPCUTF8 pszClassNamespace;
11057 if (FAILED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11059 pszClassName = pszClassNamespace = NULL;
11061 if ((pszClassName != NULL) && (pszClassNamespace != NULL))
11063 LPUTF8 pszFullyQualifiedName = NULL;
11064 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11066 // This is just to give us a scope to break out of.
11070 #define MNGSTDITF_BEGIN_INTERFACE(FriendlyName, strMngItfName, strUCOMMngItfName, strCustomMarshalerName, strCustomMarshalerCookie, strManagedViewName, NativeItfIID, bCanCastOnNativeItfQI) \
11071 if (strcmp(strMngItfName, pszFullyQualifiedName) == 0) \
11073 bmtProp->fIsMngStandardItf = true; \
11077 #define MNGSTDITF_DEFINE_METH_IMPL(FriendlyName, ECallMethName, MethName, MethSig, FcallDecl)
11079 #define MNGSTDITF_END_INTERFACE(FriendlyName)
11081 #include "mngstditflist.h"
11083 #undef MNGSTDITF_BEGIN_INTERFACE
11084 #undef MNGSTDITF_DEFINE_METH_IMPL
11085 #undef MNGSTDITF_END_INTERFACE
11089 if (strcmp(pszFullyQualifiedName, g_CollectionsGenericCollectionItfName) == 0 ||
11090 strcmp(pszFullyQualifiedName, g_CollectionsGenericReadOnlyCollectionItfName) == 0 ||
11091 strcmp(pszFullyQualifiedName, g_CollectionsCollectionItfName) == 0)
11093 // ICollection`1, ICollection and IReadOnlyCollection`1 are special cases the adapter is unaware of
11094 bmtProp->fIsRedirectedInterface = true;
11098 if (strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IEnumerable)) == 0 ||
11099 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IList)) == 0 ||
11100 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IDictionary)) == 0 ||
11101 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyList)) == 0 ||
11102 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyDictionary)) == 0 ||
11103 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_IEnumerable)) == 0 ||
11104 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_IList)) == 0 ||
11105 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_IDisposable)) == 0)
11107 bmtProp->fIsRedirectedInterface = true;
11111 // We want to allocate the per-type RCW data optional MethodTable field for
11112 // 1. Redirected interfaces
11113 // 2. Mscorlib-declared [WindowsRuntimeImport] interfaces
11114 bmtProp->fNeedsRCWPerTypeData = (bmtProp->fIsRedirectedInterface || GetHalfBakedClass()->IsProjectedFromWinRT());
11116 if (!bmtProp->fNeedsRCWPerTypeData)
11118 // 3. Non-generic IEnumerable
11119 if (strcmp(pszFullyQualifiedName, g_CollectionsEnumerableItfName) == 0)
11121 bmtProp->fNeedsRCWPerTypeData = true;
11126 else if (IsDelegate() && bmtGenerics->HasInstantiation())
11128 // 4. Redirected delegates
11129 if (GetHalfBakedClass()->GetWinRTRedirectedTypeIndex()
11130 != WinMDAdapter::RedirectedTypeIndex_Invalid)
11132 bmtProp->fNeedsRCWPerTypeData = true;
11136 else if (bmtGenerics->HasInstantiation() && pModule->GetAssembly()->IsWinMD())
11138 // 5. WinRT types with variance
11139 if (bmtGenerics->pVarianceInfo != NULL)
11141 bmtProp->fNeedsRCWPerTypeData = true;
11143 else if (IsInterface())
11145 // 6. Windows.Foundation.Collections.IIterator`1
11146 LPCUTF8 pszClassName;
11147 LPCUTF8 pszClassNamespace;
11148 if (SUCCEEDED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11150 LPUTF8 pszFullyQualifiedName = NULL;
11151 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11153 if (strcmp(pszFullyQualifiedName, g_WinRTIIteratorClassName) == 0)
11155 bmtProp->fNeedsRCWPerTypeData = true;
11160 else if ((IsInterface() || IsDelegate()) &&
11161 IsTdPublic(GetHalfBakedClass()->GetAttrClass()) &&
11162 GetHalfBakedClass()->GetWinRTRedirectedTypeIndex() != WinMDAdapter::RedirectedTypeIndex_Invalid)
11164 // 7. System.Collections.Specialized.INotifyCollectionChanged
11165 // 8. System.Collections.Specialized.NotifyCollectionChangedEventHandler
11166 // 9. System.ComponentModel.INotifyPropertyChanged
11167 // 10. System.ComponentModel.PropertyChangedEventHandler
11168 // 11. System.Windows.Input.ICommand
11169 LPCUTF8 pszClassName;
11170 LPCUTF8 pszClassNamespace;
11171 if (SUCCEEDED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11173 LPUTF8 pszFullyQualifiedName = NULL;
11174 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11176 if (strcmp(pszFullyQualifiedName, g_INotifyCollectionChangedName) == 0 ||
11177 strcmp(pszFullyQualifiedName, g_NotifyCollectionChangedEventHandlerName) == 0 ||
11178 strcmp(pszFullyQualifiedName, g_INotifyPropertyChangedName) == 0 ||
11179 strcmp(pszFullyQualifiedName, g_PropertyChangedEventHandlerName) == 0 ||
11180 strcmp(pszFullyQualifiedName, g_ICommandName) == 0)
11182 bmtProp->fNeedsRCWPerTypeData = true;
11187 // Check to see if the type is a COM event interface (classic COM interop only).
11188 if (IsInterface() && !GetHalfBakedClass()->IsProjectedFromWinRT())
11190 HRESULT hr = pMDImport->GetCustomAttributeByName(GetCl(), INTEROP_COMEVENTINTERFACE_TYPE, NULL, NULL);
11193 bmtProp->fComEventItfType = true;
11196 #endif // FEATURE_COMINTEROP
11199 #ifdef FEATURE_READYTORUN
11200 //*******************************************************************************
11201 VOID MethodTableBuilder::CheckLayoutDependsOnOtherModules(MethodTable * pDependencyMT)
11203 STANDARD_VM_CONTRACT;
11205 // These cases are expected to be handled by the caller
11206 _ASSERTE(!(pDependencyMT == g_pObjectClass || pDependencyMT->IsTruePrimitive() || ((g_pEnumClass != NULL) && pDependencyMT->IsEnum())));
11209 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11211 // Track whether field layout of this type depend on information outside its containing module
11213 // It is a stronger condition than MethodTable::IsInheritanceChainLayoutFixedInCurrentVersionBubble().
11214 // It has to remain fixed accross versioning changes in the module dependencies. In particular, it does
11215 // not take into account NonVersionable attribute. Otherwise, adding NonVersionable attribute to existing
11216 // type would be ReadyToRun incompatible change.
11218 if (pDependencyMT->GetModule() == GetModule())
11220 if (!pDependencyMT->GetClass()->HasLayoutDependsOnOtherModules())
11224 GetHalfBakedClass()->SetHasLayoutDependsOnOtherModules();
11227 BOOL MethodTableBuilder::NeedsAlignedBaseOffset()
11229 STANDARD_VM_CONTRACT;
11232 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11234 // This method returns whether the type needs aligned base offset in order to have layout resilient to
11235 // base class layout changes.
11237 if (IsValueClass())
11240 // Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on
11241 // whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching
11242 // ReadyToRun images with NGen.
11243 if (!GetModule()->GetFile()->IsILImageReadyToRun())
11245 // Always use ReadyToRun field layout algorithm to produce ReadyToRun images
11246 if (!IsReadyToRunCompilation())
11250 MethodTable * pParentMT = GetParentMethodTable();
11253 if (pParentMT == NULL || pParentMT == g_pObjectClass)
11256 if (pParentMT->GetModule() == GetModule())
11258 if (!pParentMT->GetClass()->HasLayoutDependsOnOtherModules())
11264 #endif // FEATURE_READYTORUN
11266 //*******************************************************************************
11268 // Used by BuildMethodTable
11270 // Set the HasFinalizer and HasCriticalFinalizer flags
11272 VOID MethodTableBuilder::SetFinalizationSemantics()
11274 STANDARD_VM_CONTRACT;
11276 if (g_pObjectFinalizerMD && !IsInterface() && !IsValueClass())
11278 WORD slot = g_pObjectFinalizerMD->GetSlot();
11280 // Objects not derived from Object will get marked as having a finalizer, if they have
11281 // sufficient virtual methods. This will only be an issue if they can be allocated
11282 // in the GC heap (which will cause all sorts of other problems).
11283 if (slot < bmtVT->cVirtualSlots && (*bmtVT)[slot].Impl().GetMethodDesc() != g_pObjectFinalizerMD)
11285 GetHalfBakedMethodTable()->SetHasFinalizer();
11287 // The need for a critical finalizer can be inherited from a parent.
11288 // Since we set this automatically for CriticalFinalizerObject
11289 // elsewhere, the code below is the means by which any derived class
11290 // picks up the attribute.
11291 if (HasParent() && GetParentMethodTable()->HasCriticalFinalizer())
11293 GetHalfBakedMethodTable()->SetHasCriticalFinalizer();
11299 //*******************************************************************************
11301 // Used by BuildMethodTable
11303 // Perform relevant GC calculations for value classes
11305 VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCache)
11307 STANDARD_VM_CONTRACT;
11311 EEClass *pClass = GetHalfBakedClass();
11312 MethodTable *pMT = GetHalfBakedMethodTable();
11314 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
11316 // Note that for value classes, the following calculation is only appropriate
11317 // when the instance is in its "boxed" state.
11318 #ifdef FEATURE_COLLECTIBLE_TYPES
11319 if (bmtFP->NumGCPointerSeries == 0 && pMT->Collectible())
11321 // For collectible types, insert empty gc series
11322 CGCDescSeries *pSeries;
11324 CGCDesc::Init( (PVOID) pMT, 1);
11325 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11326 pSeries->SetSeriesSize( (size_t) (0) - (size_t) pMT->GetBaseSize());
11327 pSeries->SetSeriesOffset(OBJECT_SIZE);
11330 #endif // FEATURE_COLLECTIBLE_TYPES
11331 if (bmtFP->NumGCPointerSeries != 0)
11333 CGCDescSeries *pSeries;
11334 CGCDescSeries *pHighest;
11336 pMT->SetContainsPointers();
11338 // Copy the pointer series map from the parent
11339 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
11340 if (bmtParent->NumParentPointerSeries != 0)
11342 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
11343 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize),
11344 (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize),
11345 ParentGCSize - sizeof(size_t) // sizeof(size_t) is the NumSeries count
11350 // Build the pointer series map for this pointers in this instance
11351 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11352 if (bmtFP->NumInstanceGCPointerFields)
11354 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
11355 pSeries->SetSeriesSize( (size_t) (bmtFP->NumInstanceGCPointerFields * TARGET_POINTER_SIZE) - (size_t) pMT->GetBaseSize());
11356 pSeries->SetSeriesOffset(bmtFP->GCPointerFieldStart + OBJECT_SIZE);
11360 // Insert GC info for fields which are by-value classes
11361 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
11363 if (pFieldDescList[i].IsByValue())
11365 MethodTable *pByValueMT = pByValueClassCache[i];
11367 if (pByValueMT->ContainsPointers())
11369 // Offset of the by value class in the class we are building, does NOT include Object
11370 DWORD dwCurrentOffset = pFieldDescList[i].GetOffset_NoLogging();
11372 // The by value class may have more than one pointer series
11373 CGCDescSeries * pByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetLowestSeries();
11374 SIZE_T dwNumByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
11376 for (SIZE_T j = 0; j < dwNumByValueSeries; j++)
11378 size_t cbSeriesSize;
11379 size_t cbSeriesOffset;
11381 _ASSERTE(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11383 cbSeriesSize = pByValueSeries->GetSeriesSize();
11385 // Add back the base size of the by value class, since it's being transplanted to this class
11386 cbSeriesSize += pByValueMT->GetBaseSize();
11388 // Subtract the base size of the class we're building
11389 cbSeriesSize -= pMT->GetBaseSize();
11391 // Set current series we're building
11392 pSeries->SetSeriesSize(cbSeriesSize);
11394 // Get offset into the value class of the first pointer field (includes a +Object)
11395 cbSeriesOffset = pByValueSeries->GetSeriesOffset();
11397 // Add it to the offset of the by value class in our class
11398 cbSeriesOffset += dwCurrentOffset;
11400 pSeries->SetSeriesOffset(cbSeriesOffset); // Offset of field
11408 // Adjust the inherited series - since the base size has increased by "# new field instance bytes", we need to
11409 // subtract that from all the series (since the series always has BaseSize subtracted for it - see gcdesc.h)
11410 pHighest = CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries();
11411 while (pSeries <= pHighest)
11413 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
11414 pSeries->SetSeriesSize( pSeries->GetSeriesSize() - ((size_t) pMT->GetBaseSize() - (size_t) GetParentMethodTable()->GetBaseSize()) );
11418 _ASSERTE(pSeries-1 <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11423 //*******************************************************************************
11425 // Used by BuildMethodTable
11427 // Check for the presence of type equivalence. If present, make sure
11428 // it is permitted to be on this type.
11431 void MethodTableBuilder::CheckForTypeEquivalence(
11432 WORD cBuildingInterfaceList,
11433 BuildingInterfaceInfo_t *pBuildingInterfaceList)
11435 STANDARD_VM_CONTRACT;
11437 #ifdef FEATURE_TYPEEQUIVALENCE
11438 bmtProp->fIsTypeEquivalent = !!IsTypeDefEquivalent(GetCl(), GetModule());
11440 if (bmtProp->fIsTypeEquivalent)
11442 BOOL comImportOrEventInterface = IsComImport();
11443 #ifdef FEATURE_COMINTEROP
11444 comImportOrEventInterface = comImportOrEventInterface || bmtProp->fComEventItfType;
11445 #endif // FEATURE_COMINTEROP
11447 BOOL fTypeEquivalentNotPermittedDueToType = !((comImportOrEventInterface && IsInterface()) || IsValueClass() || IsDelegate());
11448 BOOL fTypeEquivalentNotPermittedDueToGenerics = bmtGenerics->HasInstantiation();
11450 if (fTypeEquivalentNotPermittedDueToType || fTypeEquivalentNotPermittedDueToGenerics)
11452 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTBADTYPE);
11455 GetHalfBakedClass()->SetIsEquivalentType();
11458 bmtProp->fHasTypeEquivalence = bmtProp->fIsTypeEquivalent;
11460 if (!bmtProp->fHasTypeEquivalence)
11462 // fHasTypeEquivalence flag is inherited from interfaces so we can quickly detect
11463 // types that implement type equivalent interfaces
11464 for (WORD i = 0; i < cBuildingInterfaceList; i++)
11466 MethodTable *pItfMT = pBuildingInterfaceList[i].m_pMethodTable;
11467 if (pItfMT->HasTypeEquivalence())
11469 bmtProp->fHasTypeEquivalence = true;
11475 if (!bmtProp->fHasTypeEquivalence)
11477 // fHasTypeEquivalence flag is "inherited" from generic arguments so we can quickly detect
11478 // types like List<Str> where Str is a structure with the TypeIdentifierAttribute.
11479 if (bmtGenerics->HasInstantiation() && !bmtGenerics->IsTypicalTypeDefinition())
11481 Instantiation inst = bmtGenerics->GetInstantiation();
11482 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
11484 if (inst[i].HasTypeEquivalence())
11486 bmtProp->fHasTypeEquivalence = true;
11492 #endif //FEATURE_TYPEEQUIVALENCE
11495 //*******************************************************************************
11497 // Used by BuildMethodTable
11499 // Before we make the final leap, make sure we've allocated all memory needed to
11500 // fill out the RID maps.
11502 VOID MethodTableBuilder::EnsureRIDMapsCanBeFilled()
11504 STANDARD_VM_CONTRACT;
11510 // Rather than call Ensure***CanBeStored() hundreds of times, we
11511 // will call it once on the largest token we find. This relies
11512 // on an invariant that RidMaps don't use some kind of sparse
11516 mdMethodDef largest = mdMethodDefNil;
11518 DeclaredMethodIterator it(*this);
11521 if (it.Token() > largest)
11523 largest = it.Token();
11526 if ( largest != mdMethodDefNil )
11528 GetModule()->EnsureMethodDefCanBeStored(largest);
11533 mdFieldDef largest = mdFieldDefNil;
11535 for (i = 0; i < bmtMetaData->cFields; i++)
11537 if (bmtMetaData->pFields[i] > largest)
11539 largest = bmtMetaData->pFields[i];
11542 if ( largest != mdFieldDefNil )
11544 GetModule()->EnsureFieldDefCanBeStored(largest);
11549 #ifdef FEATURE_COMINTEROP
11550 //*******************************************************************************
11551 void MethodTableBuilder::GetCoClassAttribInfo()
11553 STANDARD_VM_CONTRACT;
11555 if (!GetHalfBakedClass()->IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT interfaces
11557 // Retrieve the CoClassAttribute CA.
11558 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COCLASS_TYPE, NULL, NULL);
11561 // COM class interfaces may lazily populate the m_pCoClassForIntf field of EEClass. This field is
11562 // optional so we must ensure the optional field descriptor has been allocated.
11563 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
11564 SetIsComClassInterface();
11568 #endif // FEATURE_COMINTEROP
11570 //*******************************************************************************
11571 void MethodTableBuilder::bmtMethodImplInfo::AddMethodImpl(
11572 bmtMDMethod * pImplMethod, bmtMethodHandle declMethod, mdToken declToken,
11573 StackingAllocator * pStackingAllocator)
11575 STANDARD_VM_CONTRACT;
11577 CONSISTENCY_CHECK(CheckPointer(pImplMethod));
11578 CONSISTENCY_CHECK(!declMethod.IsNull());
11579 if (pIndex >= cMaxIndex)
11581 DWORD newEntriesCount = 0;
11583 if (!ClrSafeInt<DWORD>::multiply(cMaxIndex, 2, newEntriesCount))
11584 ThrowHR(COR_E_OVERFLOW);
11586 if (newEntriesCount == 0)
11587 newEntriesCount = 10;
11589 // If we have to grow this array, we will not free the old array before we clean up the BuildMethodTable operation
11590 // because this is a stacking allocator. However, the old array will get freed when all the stack allocator is freed.
11591 Entry *rgEntriesNew = new (pStackingAllocator) Entry[newEntriesCount];
11592 memcpy(rgEntriesNew, rgEntries, sizeof(Entry) * cMaxIndex);
11594 // Start using newly allocated array.
11595 rgEntries = rgEntriesNew;
11596 cMaxIndex = newEntriesCount;
11598 rgEntries[pIndex++] = Entry(pImplMethod, declMethod, declToken);
11601 //*******************************************************************************
11602 // Returns TRUE if tok acts as a body for any methodImpl entry. FALSE, otherwise.
11603 BOOL MethodTableBuilder::bmtMethodImplInfo::IsBody(mdToken tok)
11605 LIMITED_METHOD_CONTRACT;
11606 CONSISTENCY_CHECK(TypeFromToken(tok) == mdtMethodDef);
11607 for (DWORD i = 0; i < pIndex; i++)
11609 if (GetBodyMethodDesc(i)->GetMemberDef() == tok)
11617 //*******************************************************************************
11619 MethodTableBuilder::AllocateFromHighFrequencyHeap(S_SIZE_T cbMem)
11628 return (BYTE *)GetMemTracker()->Track(
11629 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(cbMem));
11632 //*******************************************************************************
11634 MethodTableBuilder::AllocateFromLowFrequencyHeap(S_SIZE_T cbMem)
11643 return (BYTE *)GetMemTracker()->Track(
11644 GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(cbMem));
11647 //-------------------------------------------------------------------------------
11648 // Make best-case effort to obtain an image name for use in an error message.
11650 // This routine must expect to be called before the this object is fully loaded.
11651 // It can return an empty if the name isn't available or the object isn't initialized
11652 // enough to get a name, but it mustn't crash.
11653 //-------------------------------------------------------------------------------
11654 LPCWSTR MethodTableBuilder::GetPathForErrorMessages()
11656 STANDARD_VM_CONTRACT;
11658 return GetModule()->GetPathForErrorMessages();
11661 BOOL MethodTableBuilder::ChangesImplementationOfVirtualSlot(SLOT_INDEX idx)
11663 STANDARD_VM_CONTRACT;
11665 BOOL fChangesImplementation = TRUE;
11667 _ASSERTE(idx < bmtVT->cVirtualSlots);
11669 if (HasParent() && idx < GetParentMethodTable()->GetNumVirtuals())
11671 _ASSERTE(idx < bmtParent->pSlotTable->GetSlotCount());
11672 bmtMethodHandle VTImpl = (*bmtVT)[idx].Impl();
11673 bmtMethodHandle ParentImpl = (*bmtParent)[idx].Impl();
11675 fChangesImplementation = VTImpl != ParentImpl;
11677 // See code:MethodTableBuilder::SetupMethodTable2 and its logic
11678 // for handling MethodImpl's on parent classes which affect non interface
11680 if (!fChangesImplementation && (ParentImpl.GetSlotIndex() != idx))
11681 fChangesImplementation = TRUE;
11684 return fChangesImplementation;
11687 // Must be called prior to setting the value of any optional field on EEClass (on a debug build an assert will
11688 // fire if this invariant is violated).
11689 void MethodTableBuilder::EnsureOptionalFieldsAreAllocated(EEClass *pClass, AllocMemTracker *pamTracker, LoaderHeap *pHeap)
11691 STANDARD_VM_CONTRACT;
11693 if (pClass->HasOptionalFields())
11696 EEClassOptionalFields *pOptFields = (EEClassOptionalFields*)
11697 pamTracker->Track(pHeap->AllocMem(S_SIZE_T(sizeof(EEClassOptionalFields))));
11699 // Initialize default values for all optional fields.
11700 pOptFields->Init();
11702 // Attach optional fields to the class.
11703 pClass->AttachOptionalFields(pOptFields);
11706 //---------------------------------------------------------------------------------------
11708 // Gather information about a generic type
11709 // - number of parameters
11710 // - variance annotations
11716 MethodTableBuilder::GatherGenericsInfo(
11719 Instantiation inst,
11720 bmtGenericsInfo * bmtGenericsInfo)
11725 PRECONDITION(GetThread() != NULL);
11726 PRECONDITION(CheckPointer(pModule));
11727 PRECONDITION(CheckPointer(bmtGenericsInfo));
11731 IMDInternalImport * pInternalImport = pModule->GetMDImport();
11733 // Enumerate the formal type parameters
11734 HENUMInternal hEnumGenericPars;
11735 HRESULT hr = pInternalImport->EnumInit(mdtGenericParam, cl, &hEnumGenericPars);
11737 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11739 DWORD numGenericArgs = pInternalImport->EnumGetCount(&hEnumGenericPars);
11741 // Work out what kind of EEClass we're creating w.r.t. generics. If there
11742 // are no generics involved this will be a VMFLAG_NONGENERIC.
11743 BOOL fHasVariance = FALSE;
11744 if (numGenericArgs > 0)
11746 // Generic type verification
11750 if (FAILED(pInternalImport->GetTypeDefProps(cl, &dwAttr, &tkParent)))
11752 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11754 // A generic with explicit layout is not allowed.
11755 if (IsTdExplicitLayout(dwAttr))
11757 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_EXPLICIT_GENERIC);
11761 bmtGenericsInfo->numDicts = 1;
11763 mdGenericParam tkTyPar;
11764 bmtGenericsInfo->pVarianceInfo = new (&GetThread()->m_MarshalAlloc) BYTE[numGenericArgs];
11766 // If it has generic arguments but none have been specified, then load the instantiation at the formals
11767 if (inst.IsEmpty())
11769 bmtGenericsInfo->fTypicalInstantiation = TRUE;
11770 S_UINT32 scbAllocSize = S_UINT32(numGenericArgs) * S_UINT32(sizeof(TypeHandle));
11771 TypeHandle * genericArgs = (TypeHandle *) GetThread()->m_MarshalAlloc.Alloc(scbAllocSize);
11773 inst = Instantiation(genericArgs, numGenericArgs);
11775 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
11779 bmtGenericsInfo->fTypicalInstantiation = FALSE;
11781 bmtGenericsInfo->fSharedByGenericInstantiations = TypeHandle::IsCanonicalSubtypeInstantiation(inst);
11782 _ASSERTE(bmtGenericsInfo->fSharedByGenericInstantiations == ClassLoader::IsSharableInstantiation(inst));
11785 // Set typical instantiation MethodTable
11787 MethodTable * pTypicalInstantiationMT = pModule->LookupTypeDef(cl).AsMethodTable();
11788 // Typical instantiation was already loaded by code:ClassLoader::LoadApproxTypeThrowing
11789 _ASSERTE(pTypicalInstantiationMT != NULL);
11790 bmtGenericsInfo->dbg_pTypicalInstantiationMT = pTypicalInstantiationMT;
11795 TypeHandle * pDestInst = (TypeHandle *)inst.GetRawArgs();
11796 for (unsigned int i = 0; i < numGenericArgs; i++)
11798 pInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
11800 if (FAILED(pInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
11802 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11805 if (bmtGenericsInfo->fTypicalInstantiation)
11807 // code:Module.m_GenericParamToDescMap maps generic parameter RIDs to TypeVarTypeDesc
11808 // instances so that we do not leak by allocating them all over again, if the type
11809 // repeatedly fails to load.
11810 TypeVarTypeDesc *pTypeVarTypeDesc = pModule->LookupGenericParam(tkTyPar);
11811 if (pTypeVarTypeDesc == NULL)
11813 // Do NOT use the alloc tracker for this memory as we need it stay allocated even if the load fails.
11814 void *mem = (void *)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TypeVarTypeDesc)));
11815 pTypeVarTypeDesc = new (mem) TypeVarTypeDesc(pModule, cl, i, tkTyPar);
11817 // No race here - the row in GenericParam table is owned exclusively by this type and we
11818 // are holding a lock preventing other threads from concurrently loading it.
11819 pModule->StoreGenericParamThrowing(tkTyPar, pTypeVarTypeDesc);
11821 pDestInst[i] = TypeHandle(pTypeVarTypeDesc);
11824 DWORD varianceAnnotation = flags & gpVarianceMask;
11825 bmtGenericsInfo->pVarianceInfo[i] = static_cast<BYTE>(varianceAnnotation);
11826 if (varianceAnnotation != gpNonVariant)
11828 if (varianceAnnotation != gpContravariant && varianceAnnotation != gpCovariant)
11830 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADVARIANCE);
11834 fHasVariance = TRUE;
11840 bmtGenericsInfo->pVarianceInfo = NULL;
11844 bmtGenericsInfo->fTypicalInstantiation = FALSE;
11845 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
11846 bmtGenericsInfo->numDicts = 0;
11849 bmtGenericsInfo->fContainsGenericVariables = MethodTable::ComputeContainsGenericVariables(inst);
11851 SigTypeContext typeContext(inst, Instantiation());
11852 bmtGenericsInfo->typeContext = typeContext;
11853 } // MethodTableBuilder::GatherGenericsInfo
11855 //=======================================================================
11856 // This is invoked from the class loader while building the internal structures for a type
11857 // This function should check if explicit layout metadata exists.
11860 // TRUE - yes, there's layout metadata
11861 // FALSE - no, there's no layout.
11862 // fail - throws a typeload exception
11865 // *pNLType gets set to nltAnsi or nltUnicode
11866 // *pPackingSize declared packing size
11867 // *pfExplicitoffsets offsets explicit in metadata or computed?
11868 //=======================================================================
11869 BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, mdTypeDef cl, MethodTable* pParentMT, BYTE* pPackingSize, BYTE* pNLTType, BOOL* pfExplicitOffsets)
11876 PRECONDITION(CheckPointer(pInternalImport));
11877 PRECONDITION(CheckPointer(pPackingSize));
11878 PRECONDITION(CheckPointer(pNLTType));
11879 PRECONDITION(CheckPointer(pfExplicitOffsets));
11886 if (FAILED(pInternalImport->GetTypeDefProps(cl, &clFlags, NULL)))
11888 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11891 if (IsTdAutoLayout(clFlags))
11895 else if (IsTdSequentialLayout(clFlags))
11897 *pfExplicitOffsets = FALSE;
11899 else if (IsTdExplicitLayout(clFlags))
11901 *pfExplicitOffsets = TRUE;
11905 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11908 // We now know this class has seq. or explicit layout. Ensure the parent does too.
11909 if (pParentMT && !(pParentMT->IsObjectClass() || pParentMT->IsValueTypeClass()) && !(pParentMT->HasLayout()))
11910 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11912 if (IsTdAnsiClass(clFlags))
11914 *pNLTType = nltAnsi;
11916 else if (IsTdUnicodeClass(clFlags) || IsTdAutoClass(clFlags))
11918 *pNLTType = nltUnicode;
11922 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11926 hr = pInternalImport->GetClassPackSize(cl, &dwPackSize);
11927 if (FAILED(hr) || dwPackSize == 0)
11928 dwPackSize = DEFAULT_PACKING_SIZE;
11930 // This has to be reduced to a BYTE value, so we had better make sure it fits. If
11931 // not, we'll throw an exception instead of trying to munge the value to what we
11932 // think the user might want.
11933 if (!FitsInU1((UINT64)(dwPackSize)))
11935 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11938 *pPackingSize = (BYTE)dwPackSize;
11943 //---------------------------------------------------------------------------------------
11945 // This service is called for normal classes -- and for the pseudo class we invent to
11946 // hold the module's public members.
11950 ClassLoader::CreateTypeHandleForTypeDefThrowing(
11953 Instantiation inst,
11954 AllocMemTracker * pamTracker)
11956 CONTRACT(TypeHandle)
11959 PRECONDITION(GetThread() != NULL);
11960 PRECONDITION(CheckPointer(pModule));
11961 POSTCONDITION(!RETVAL.IsNull());
11962 POSTCONDITION(CheckPointer(RETVAL.GetMethodTable()));
11966 MethodTable * pMT = NULL;
11968 Thread * pThread = GetThread();
11970 MethodTable * pParentMethodTable = NULL;
11971 SigPointer parentInst;
11972 mdTypeDef tdEnclosing = mdTypeDefNil;
11974 BuildingInterfaceInfo_t * pInterfaceBuildInfo = NULL;
11975 IMDInternalImport * pInternalImport = NULL;
11976 LayoutRawFieldInfo * pLayoutRawFieldInfos = NULL;
11977 MethodTableBuilder::bmtGenericsInfo genericsInfo;
11979 Assembly * pAssembly = pModule->GetAssembly();
11980 pInternalImport = pModule->GetMDImport();
11982 if (TypeFromToken(cl) != mdtTypeDef || !pInternalImport->IsValidToken(cl))
11984 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11987 // GetCheckpoint for the thread-based allocator
11988 // This checkpoint provides a scope for all transient allocations of data structures
11989 // used during class loading.
11990 // <NICE> Ideally a debug/checked build should pass around tokens indicating the Checkpoint
11991 // being used and check these dynamically </NICE>
11992 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
11994 // Gather up generics info
11995 MethodTableBuilder::GatherGenericsInfo(pModule, cl, inst, &genericsInfo);
11997 Module * pLoaderModule = pModule;
11998 if (!inst.IsEmpty())
12000 pLoaderModule = ClassLoader::ComputeLoaderModuleWorker(
12005 pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(pModule, inst);
12008 LoaderAllocator * pAllocator = pLoaderModule->GetLoaderAllocator();
12011 // As this is loading a parent type, we are allowed to override the load type limit.
12012 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
12013 pParentMethodTable = LoadApproxParentThrowing(pModule, cl, &parentInst, &genericsInfo.typeContext);
12016 if (pParentMethodTable != NULL)
12018 // Since methods on System.Array assume the layout of arrays, we can not allow
12019 // subclassing of arrays, it is sealed from the users point of view.
12020 // Value types and enums should be sealed - disable inheritting from them (we cannot require sealed
12021 // flag because of AppCompat)
12022 if (pParentMethodTable->IsSealed() ||
12023 (pParentMethodTable == g_pArrayClass) ||
12024 pParentMethodTable->IsValueType())
12026 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_SEALEDPARENT);
12029 DWORD dwTotalDicts = genericsInfo.numDicts + pParentMethodTable->GetNumDicts();
12030 if (!FitsIn<WORD>(dwTotalDicts))
12032 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_TOOMANYGENERICARGS);
12034 genericsInfo.numDicts = static_cast<WORD>(dwTotalDicts);
12037 GetEnclosingClassThrowing(pInternalImport, pModule, cl, &tdEnclosing);
12039 BYTE nstructPackingSize = 0, nstructNLT = 0;
12040 BOOL fExplicitOffsets = FALSE;
12041 // NOTE: HasLayoutMetadata does not load classes
12043 !genericsInfo.fContainsGenericVariables &&
12045 pModule->GetAssembly(),
12048 pParentMethodTable,
12049 &nstructPackingSize,
12051 &fExplicitOffsets);
12053 BOOL fIsEnum = ((g_pEnumClass != NULL) && (pParentMethodTable == g_pEnumClass));
12055 // enums may not have layout because they derive from g_pEnumClass and that has no layout
12056 // this is enforced by HasLayoutMetadata above
12057 _ASSERTE(!(fIsEnum && fHasLayout));
12059 // This is a delegate class if it derives from MulticastDelegate (we do not allow single cast delegates)
12060 BOOL fIsDelegate = pParentMethodTable && pParentMethodTable == g_pMulticastDelegateClass;
12062 // Create a EEClass entry for it, filling out a few fields, such as the parent class token
12063 // (and the generic type should we be creating an instantiation)
12064 EEClass * pClass = MethodTableBuilder::CreateClass(
12074 if ((pParentMethodTable != NULL) && (pParentMethodTable == g_pDelegateClass))
12076 // Note we do not allow single cast delegates
12077 if (pModule->GetAssembly() != SystemDomain::SystemAssembly())
12079 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_CANNOT_INHERIT_FROM_DELEGATE);
12083 // Only MultiCastDelegate should inherit from Delegate
12086 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
12088 className = nameSpace = "Invalid TypeDef record";
12090 BAD_FORMAT_NOTHROW_ASSERT(strcmp(className, "MulticastDelegate") == 0);
12096 if (!pClass->IsSealed())
12098 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_DELEGATE_CLASS_NOTSEALED);
12101 pClass->SetIsDelegate();
12104 if (tdEnclosing != mdTypeDefNil)
12106 pClass->SetIsNested();
12107 THROW_BAD_FORMAT_MAYBE(IsTdNested(pClass->GetProtection()), VLDTR_E_TD_ENCLNOTNESTED, pModule);
12109 else if (IsTdNested(pClass->GetProtection()))
12111 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12114 // We only permit generic interfaces and delegates to have variant type parameters
12115 if (genericsInfo.pVarianceInfo != NULL && !pClass->IsInterface() && !fIsDelegate)
12117 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_CLASS);
12120 // Now load all the interfaces
12121 HENUMInternalHolder hEnumInterfaceImpl(pInternalImport);
12122 hEnumInterfaceImpl.EnumInit(mdtInterfaceImpl, cl);
12124 cInterfaces = pInternalImport->EnumGetCount(&hEnumInterfaceImpl);
12126 if (cInterfaces != 0)
12130 // Allocate the BuildingInterfaceList table
12131 pInterfaceBuildInfo = new (&GetThread()->m_MarshalAlloc) BuildingInterfaceInfo_t[cInterfaces];
12133 mdInterfaceImpl ii;
12134 for (i = 0; pInternalImport->EnumNext(&hEnumInterfaceImpl, &ii); i++)
12136 // Get properties on this interface
12137 mdTypeRef crInterface;
12138 if (FAILED(pInternalImport->GetTypeOfInterfaceImpl(ii, &crInterface)))
12140 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12142 // validate the token
12143 mdToken crIntType =
12144 (RidFromToken(crInterface) && pInternalImport->IsValidToken(crInterface)) ?
12145 TypeFromToken(crInterface) :
12154 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12157 TypeHandle intType;
12160 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
12161 intType = LoadApproxTypeThrowing(pModule, crInterface, NULL, &genericsInfo.typeContext);
12164 pInterfaceBuildInfo[i].m_pMethodTable = intType.AsMethodTable();
12165 if (pInterfaceBuildInfo[i].m_pMethodTable == NULL)
12167 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12170 // Ensure this is an interface
12171 if (!pInterfaceBuildInfo[i].m_pMethodTable->IsInterface())
12173 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_NOTINTERFACE);
12176 // Check interface for use of variant type parameters
12177 if ((genericsInfo.pVarianceInfo != NULL) && (TypeFromToken(crInterface) == mdtTypeSpec))
12180 PCCOR_SIGNATURE pSig;
12181 if (FAILED(pInternalImport->GetTypeSpecFromToken(crInterface, &pSig, &cSig)))
12183 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12185 // Interfaces behave covariantly
12186 if (!EEClass::CheckVarianceInSig(
12187 genericsInfo.GetNumGenericArgs(),
12188 genericsInfo.pVarianceInfo,
12190 SigPointer(pSig, cSig),
12193 pAssembly->ThrowTypeLoadException(
12196 IDS_CLASSLOAD_VARIANCE_IN_INTERFACE);
12200 _ASSERTE(i == cInterfaces);
12204 /* Variant delegates should not have any instance fields of the variant.
12205 type parameter. For now, we just completely disallow all fields even
12206 if they are non-variant or static, as it is not a useful scenario.
12207 @TODO: A more logical place for this check would be in
12208 MethodTableBuilder::EnumerateClassMembers() */
12209 (fIsDelegate && genericsInfo.pVarianceInfo))
12211 // check for fields and variance
12213 HENUMInternalHolder hEnumField(pInternalImport);
12214 hEnumField.EnumInit(mdtFieldDef, cl);
12216 cFields = pInternalImport->EnumGetCount(&hEnumField);
12218 if ((cFields != 0) && fIsDelegate && (genericsInfo.pVarianceInfo != NULL))
12220 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_IN_DELEGATE);
12225 // Though we fail on this condition, we should never run into it.
12226 CONSISTENCY_CHECK(nstructPackingSize != 0);
12227 // MD Val check: PackingSize
12228 if((nstructPackingSize == 0) ||
12229 (nstructPackingSize > 128) ||
12230 (nstructPackingSize & (nstructPackingSize-1)))
12232 THROW_BAD_FORMAT_MAYBE(!"ClassLayout:Invalid PackingSize", BFA_BAD_PACKING_SIZE, pModule);
12233 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12236 pLayoutRawFieldInfos = (LayoutRawFieldInfo *)GetThread()->m_MarshalAlloc.Alloc(
12237 (S_UINT32(1) + S_UINT32(cFields)) * S_UINT32(sizeof(LayoutRawFieldInfo)));
12240 // Warning: this can load classes
12241 CONTRACT_VIOLATION(LoadsTypeViolation);
12243 // Set a flag that allows us to break dead-locks that are result of the LoadsTypeViolation
12244 ThreadStateNCStackHolder tsNC(TRUE, Thread::TSNC_LoadsTypeViolation);
12246 EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
12248 nstructPackingSize,
12250 #ifdef FEATURE_COMINTEROP
12251 pClass->IsProjectedFromWinRT(),
12252 #endif // FEATURE_COMINTEROP
12254 pParentMethodTable,
12258 &genericsInfo.typeContext,
12259 &(((LayoutEEClass *)pClass)->m_LayoutInfo),
12260 pLayoutRawFieldInfos,
12267 // Resolve this class, given that we know now that all of its dependencies are loaded and resolved.
12268 // !!! This must be the last thing in this TRY block: if MethodTableBuilder succeeds, it has published the class
12269 // and there is no going back.
12270 MethodTableBuilder builder(
12273 &GetThread()->m_MarshalAlloc,
12276 pMT = builder.BuildMethodTableThrowing(
12281 pInterfaceBuildInfo,
12282 pLayoutRawFieldInfos,
12283 pParentMethodTable,
12286 (WORD)cInterfaces);
12288 RETURN(TypeHandle(pMT));
12289 } // ClassLoader::CreateTypeHandleForTypeDefThrowing