1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
4 // File: METHODTABLEBUILDER.CPP
11 // ============================================================================
15 #include "methodtablebuilder.h"
17 #include "sigbuilder.h"
18 #include "dllimport.h"
19 #include "fieldmarshaler.h"
22 #include "customattribute.h"
23 #include "typestring.h"
25 //*******************************************************************************
26 // Helper functions to sort GCdescs by offset (decending order)
27 int __cdecl compareCGCDescSeries(const void *arg1, const void *arg2)
29 STATIC_CONTRACT_NOTHROW;
30 STATIC_CONTRACT_GC_NOTRIGGER;
31 STATIC_CONTRACT_FORBID_FAULT;
33 CGCDescSeries* gcInfo1 = (CGCDescSeries*) arg1;
34 CGCDescSeries* gcInfo2 = (CGCDescSeries*) arg2;
36 return (int)(gcInfo2->GetSeriesOffset() - gcInfo1->GetSeriesOffset());
39 //*******************************************************************************
41 const char* FormatSig(MethodDesc* pMD, LoaderHeap *pHeap, AllocMemTracker *pamTracker);
44 unsigned g_dupMethods = 0;
47 //==========================================================================
48 // This function is very specific about how it constructs a EEClass. It first
49 // determines the necessary size of the vtable and the number of statics that
50 // this class requires. The necessary memory is then allocated for a EEClass
51 // and its vtable and statics. The class members are then initialized and
52 // the memory is then returned to the caller
54 // LPEEClass CreateClass()
57 // [in] scope - scope of the current class not the one requested to be opened
58 // [in] cl - class token of the class to be created.
59 // [out] ppEEClass - pointer to pointer to hold the address of the EEClass
60 // allocated in this function.
61 // Return : returns an HRESULT indicating the success of this function.
63 // This parameter has been removed but might need to be reinstated if the
64 // global for the metadata loader is removed.
65 // [in] pIMLoad - MetaDataLoader class/object for the current scope.
68 //==========================================================================
70 MethodTableBuilder::CreateClass( Module *pModule,
75 const MethodTableBuilder::bmtGenericsInfo *bmtGenericsInfo,
76 LoaderAllocator * pAllocator,
77 AllocMemTracker *pamTracker)
82 PRECONDITION(!(fHasLayout && fDelegate));
83 PRECONDITION(!(fHasLayout && fIsEnum));
84 PRECONDITION(CheckPointer(bmtGenericsInfo));
88 EEClass *pEEClass = NULL;
89 IMDInternalImport *pInternalImport;
91 //<TODO>============================================================================
92 // vtabsize and static size need to be converted from pointer sizes to #'s
93 // of bytes this will be very important for 64 bit NT!
94 // We will need to call on IMetaDataLoad to get these sizes and fill out the
97 // From the classref call on metadata to resolve the classref and check scope
98 // to make sure that this class is in the same scope otherwise we need to open
99 // a new scope and possibly file.
101 // if the scopes are different call the code to load a new file and get the new scope
103 // scopes are the same so we can use the existing scope to get the class info
105 // This method needs to be fleshed out.more it currently just returns enough
106 // space for the defined EEClass and the vtable and statics are not set.
107 //=============================================================================</TODO>
111 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) LayoutEEClass();
115 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) DelegateEEClass();
119 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) EEClass(sizeof(EEClass));
122 DWORD dwAttrClass = 0;
123 mdToken tkExtends = mdTokenNil;
125 // Set up variance info
126 if (bmtGenericsInfo->pVarianceInfo)
128 // Variance info is an optional field on EEClass, so ensure the optional field descriptor has been
130 EnsureOptionalFieldsAreAllocated(pEEClass, pamTracker, pAllocator->GetLowFrequencyHeap());
131 pEEClass->SetVarianceInfo((BYTE*) pamTracker->Track(
132 pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(bmtGenericsInfo->GetNumGenericArgs()))));
134 memcpy(pEEClass->GetVarianceInfo(), bmtGenericsInfo->pVarianceInfo, bmtGenericsInfo->GetNumGenericArgs());
137 pInternalImport = pModule->GetMDImport();
139 if (pInternalImport == NULL)
140 COMPlusThrowHR(COR_E_TYPELOAD);
142 IfFailThrow(pInternalImport->GetTypeDefProps(
147 pEEClass->m_dwAttrClass = dwAttrClass;
149 // MDVal check: can't be both tdSequentialLayout and tdExplicitLayout
150 if((dwAttrClass & tdLayoutMask) == tdLayoutMask)
151 COMPlusThrowHR(COR_E_TYPELOAD);
153 if (IsTdInterface(dwAttrClass))
155 // MDVal check: must have nil tkExtends and must be tdAbstract
156 if((tkExtends & 0x00FFFFFF)||(!IsTdAbstract(dwAttrClass)))
157 COMPlusThrowHR(COR_E_TYPELOAD);
161 pEEClass->SetHasLayout();
163 if (IsTdWindowsRuntime(dwAttrClass))
165 COMPlusThrowHR(COR_E_TYPELOAD);
169 pModule->GetClassLoader()->m_dwDebugClasses++;
175 //*******************************************************************************
177 // Create a hash of all methods in this class. The hash is from method name to MethodDesc.
179 MethodTableBuilder::MethodNameHash *
180 MethodTableBuilder::CreateMethodChainHash(
183 STANDARD_VM_CONTRACT;
185 MethodNameHash *pHash = new (GetStackingAllocator()) MethodNameHash();
186 pHash->Init(pMT->GetNumVirtuals(), GetStackingAllocator());
188 unsigned numVirtuals = GetParentMethodTable()->GetNumVirtuals();
189 for (unsigned i = 0; i < numVirtuals; ++i)
191 bmtMethodSlot &slot = (*bmtParent->pSlotTable)[i];
192 bmtRTMethod * pMethod = slot.Decl().AsRTMethod();
193 const MethodSignature &sig = pMethod->GetMethodSignature();
194 pHash->Insert(sig.GetName(), pMethod);
201 //*******************************************************************************
203 // Find a method in this class hierarchy - used ONLY by the loader during layout. Do not use at runtime.
205 // *ppMemberSignature must be NULL on entry - it and *pcMemberSignature may or may not be filled out
207 // ppMethodDesc will be filled out with NULL if no matching method in the hierarchy is found.
209 // Returns FALSE if there was an error of some kind.
211 // pMethodConstraintsMatch receives the result of comparing the method constraints.
212 MethodTableBuilder::bmtRTMethod *
213 MethodTableBuilder::LoaderFindMethodInParentClass(
214 const MethodSignature & methodSig,
215 BOOL * pMethodConstraintsMatch)
220 PRECONDITION(CheckPointer(this));
221 PRECONDITION(CheckPointer(bmtParent));
222 PRECONDITION(CheckPointer(methodSig.GetModule()));
223 PRECONDITION(CheckPointer(methodSig.GetSignature()));
224 PRECONDITION(HasParent());
225 PRECONDITION(methodSig.GetSignatureLength() != 0);
230 MethodNameHash::HashEntry * pEntry;
232 // Have we created a hash of all the methods in the class chain?
233 if (bmtParent->pParentMethodHash == NULL)
235 // There may be such a method, so we will now create a hash table to reduce the pain for
238 // <TODO> Are we really sure that this is worth doing? </TODO>
239 bmtParent->pParentMethodHash = CreateMethodChainHash(GetParentMethodTable());
242 // We have a hash table, so use it
243 pEntry = bmtParent->pParentMethodHash->Lookup(methodSig.GetName());
245 // Traverse the chain of all methods with this name
246 while (pEntry != NULL)
248 bmtRTMethod * pEntryMethod = pEntry->m_data;
249 const MethodSignature & entrySig = pEntryMethod->GetMethodSignature();
251 // Note instantiation info
253 if (methodSig.Equivalent(entrySig))
255 if (pMethodConstraintsMatch != NULL)
257 if ((*methodSig.GetSignature()) & IMAGE_CEE_CS_CALLCONV_GENERIC)
259 // Check the constraints are consistent,
260 // and return the result to the caller.
261 // We do this here to avoid recalculating pSubst.
262 *pMethodConstraintsMatch = MetaSig::CompareMethodConstraints(
263 methodSig.GetSubstitution(), methodSig.GetModule(), methodSig.GetToken(),
264 entrySig.GetSubstitution(), entrySig.GetModule(), entrySig.GetToken());
268 *pMethodConstraintsMatch = TRUE; // If the method isn't generic, just mark that constraints match
276 // Advance to next item in the hash chain which has the same name
277 pEntry = bmtParent->pParentMethodHash->FindNext(pEntry);
281 //@TODO: Move to this code, as the use of a HashTable is broken; overriding semantics
282 //@TODO: require matching against the most-derived slot of a given name and signature,
283 //@TODO: (which deals specifically with newslot methods with identical name and sig), but
284 //@TODO: HashTables are by definition unordered and so we've only been getting by with the
285 //@TODO: implementation being compatible with the order in which methods were added to
286 //@TODO: the HashTable in CreateMethodChainHash.
288 bmtParentInfo::Iterator it(bmtParent->IterateSlots());
289 it.MoveTo(static_cast<size_t>(GetParentMethodTable()->GetNumVirtuals()));
292 bmtMethodHandle decl(it->Decl());
293 const MethodSignature &declSig(decl.GetMethodSignature());
294 if (declSig == methodSig)
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 &declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken());
306 return decl.AsRTMethod();
314 //*******************************************************************************
316 // Given an interface map to fill out, expand pNewInterface (and its sub-interfaces) into it, increasing
317 // pdwInterfaceListSize as appropriate, and avoiding duplicates.
320 MethodTableBuilder::ExpandApproxInterface(
321 bmtInterfaceInfo * bmtInterface, // out parameter, various parts cumulatively written to.
322 const Substitution * pNewInterfaceSubstChain,
323 MethodTable * pNewInterface,
324 InterfaceDeclarationScope declScope
325 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
327 STANDARD_VM_CONTRACT;
329 if (pNewInterface->HasVirtualStaticMethods())
331 bmtProp->fHasVirtualStaticMethods = TRUE;
334 //#ExpandingInterfaces
335 // We expand the tree of inherited interfaces into a set by adding the
336 // current node BEFORE expanding the parents of the current node.
337 // ****** This must be consistent with code:ExpandExactInterface *******
338 // ****** This must be consistent with code:ClassCompat::MethodTableBuilder::BuildInteropVTable_ExpandInterface *******
340 // The interface list contains the fully expanded set of interfaces from the parent then
341 // we start adding all the interfaces we declare. We need to know which interfaces
342 // we declare but do not need duplicates of the ones we declare. This means we can
343 // duplicate our parent entries.
345 // Is it already present in the list?
346 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
348 bmtInterfaceEntry * pItfEntry = &bmtInterface->pInterfaceMap[i];
349 bmtRTType * pItfType = pItfEntry->GetInterfaceType();
351 // Type Equivalence is not respected for this comparison as you can have multiple type equivalent interfaces on a class
352 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
353 if (MetaSig::CompareTypeDefsUnderSubstitutions(pItfType->GetMethodTable(),
355 &pItfType->GetSubstitution(),
356 pNewInterfaceSubstChain,
359 if (declScope.fIsInterfaceDeclaredOnType)
361 pItfEntry->IsDeclaredOnType() = true;
364 //#InjectInterfaceDuplicates_ApproxInterfaces
365 // We can inject duplicate interfaces in check builds.
366 // Has to be in sync with code:#InjectInterfaceDuplicates_Main
367 if (((dbg_pClassMT == NULL) && bmtInterface->dbg_fShouldInjectInterfaceDuplicates) ||
368 ((dbg_pClassMT != NULL) && dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates()))
370 // The injected duplicate interface should have the same status 'ImplementedByParent' as
371 // the original interface (can be false if the interface is implemented indirectly twice)
372 declScope.fIsInterfaceDeclaredOnParent = pItfEntry->IsImplementedByParent();
373 // Just pretend we didn't find this match, but mark all duplicates as 'DeclaredOnType' if
378 return; // found it, don't add it again
382 bmtRTType * pNewItfType =
383 new (GetStackingAllocator()) bmtRTType(*pNewInterfaceSubstChain, pNewInterface);
385 if (bmtInterface->dwInterfaceMapSize >= bmtInterface->dwInterfaceMapAllocated)
388 // Grow the array of interfaces
390 S_UINT32 dwNewAllocated = S_UINT32(2) * S_UINT32(bmtInterface->dwInterfaceMapAllocated) + S_UINT32(5);
392 if (dwNewAllocated.IsOverflow())
394 BuildMethodTableThrowException(COR_E_OVERFLOW);
397 S_SIZE_T safeSize = S_SIZE_T(sizeof(bmtInterfaceEntry)) *
398 S_SIZE_T(dwNewAllocated.Value());
400 if (safeSize.IsOverflow())
402 BuildMethodTableThrowException(COR_E_OVERFLOW);
405 bmtInterfaceEntry * pNewMap = (bmtInterfaceEntry *)new (GetStackingAllocator()) BYTE[safeSize.Value()];
406 if (bmtInterface->dwInterfaceMapAllocated > 0)
407 memcpy(pNewMap, bmtInterface->pInterfaceMap, sizeof(bmtInterfaceEntry) * bmtInterface->dwInterfaceMapAllocated);
409 bmtInterface->pInterfaceMap = pNewMap;
410 bmtInterface->dwInterfaceMapAllocated = dwNewAllocated.Value();
413 // The interface map memory was just allocated as an array of bytes, so we use
414 // in place new to init the new map entry. No need to do anything with the result,
416 CONSISTENCY_CHECK(bmtInterface->dwInterfaceMapSize < bmtInterface->dwInterfaceMapAllocated);
417 new ((void *)&bmtInterface->pInterfaceMap[bmtInterface->dwInterfaceMapSize])
418 bmtInterfaceEntry(pNewItfType, declScope);
420 bmtInterface->dwInterfaceMapSize++;
422 // Checking for further expanded interfaces isn't necessary for the system module, as we can rely on the C# compiler
423 // to have found all of the interfaces that the type implements, and to place them in the interface list itself. Also
424 // we can assume no ambiguous interfaces
425 // Code related to this is marked with #SpecialCorelibInterfaceExpansionAlgorithm
426 if (!(GetModule()->IsSystem() && IsValueClass()))
428 // Make sure to pass in the substitution from the new itf type created above as
429 // these methods assume that substitutions are allocated in the stacking heap,
431 InterfaceDeclarationScope declaredItfScope(declScope.fIsInterfaceDeclaredOnParent, false);
432 ExpandApproxDeclaredInterfaces(
434 bmtTypeHandle(pNewItfType),
436 COMMA_INDEBUG(dbg_pClassMT));
438 } // MethodTableBuilder::ExpandApproxInterface
440 //*******************************************************************************
442 // dbg_pClassMT - Class on which the interfaces are declared (either explicitly or implicitly).
443 // It will never be an interface. It may be NULL (if it is the type being built).
445 MethodTableBuilder::ExpandApproxDeclaredInterfaces(
446 bmtInterfaceInfo * bmtInterface, // out parameter, various parts cumulatively written to.
447 bmtTypeHandle thType,
448 InterfaceDeclarationScope declScope
449 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
451 STANDARD_VM_CONTRACT;
453 _ASSERTE((dbg_pClassMT == NULL) || !dbg_pClassMT->IsInterface());
456 // Iterate the list of interfaces declared by thType and add them to the map.
457 InterfaceImplEnum ie(thType.GetModule(), thType.GetTypeDefToken(), &thType.GetSubstitution());
458 while ((hr = ie.Next()) == S_OK)
460 MethodTable *pGenericIntf = ClassLoader::LoadApproxTypeThrowing(
461 thType.GetModule(), ie.CurrentToken(), NULL, NULL).GetMethodTable();
462 CONSISTENCY_CHECK(pGenericIntf->IsInterface());
464 ExpandApproxInterface(bmtInterface,
468 COMMA_INDEBUG(dbg_pClassMT));
472 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
474 } // MethodTableBuilder::ExpandApproxDeclaredInterfaces
476 //*******************************************************************************
478 MethodTableBuilder::ExpandApproxInheritedInterfaces(
479 bmtInterfaceInfo * bmtInterface,
480 bmtRTType * pParentType)
482 STANDARD_VM_CONTRACT;
484 // Expand interfaces in superclasses first. Interfaces inherited from parents
485 // must have identical indexes as in the parent.
486 bmtRTType * pParentOfParent = pParentType->GetParentType();
488 //#InterfaceMap_SupersetOfParent
489 // We have to load parent's interface map the same way the parent did it (as open type).
490 // Further code depends on this:
491 // code:#InterfaceMap_UseParentInterfaceImplementations
492 // We check that it is truth:
493 // code:#ApproxInterfaceMap_SupersetOfParent
494 // code:#ExactInterfaceMap_SupersetOfParent
496 //#InterfaceMap_CanonicalSupersetOfParent
497 // Note that canonical instantiation of parent can have different interface instantiations in the
498 // interface map than derived type:
499 // class MyClass<T> : MyBase<string, T>, I<T>
500 // class MyBase<U, V> : I<U>
501 // Type MyClass<_Canon> has MyBase<_Canon,_Canon> as parent. The interface maps are:
502 // MyBase<_Canon,_Canon> ... I<_Canon>
503 // MyClass<_Canon> ... I<string> (#1)
505 // The I's instantiation I<string> (#1) in MyClass and I<_Canon> from MyBase are not the same
508 // Backup parent substitution
509 Substitution parentSubstitution = pParentType->GetSubstitution();
510 // Make parent an open type
511 pParentType->SetSubstitution(Substitution());
513 if (pParentOfParent != NULL)
515 ExpandApproxInheritedInterfaces(bmtInterface, pParentOfParent);
518 InterfaceDeclarationScope declScope(true, false);
519 ExpandApproxDeclaredInterfaces(
521 bmtTypeHandle(pParentType),
523 COMMA_INDEBUG(pParentType->GetMethodTable()));
525 // Make sure we loaded the same number of interfaces as the parent type itself
526 CONSISTENCY_CHECK(pParentType->GetMethodTable()->GetNumInterfaces() == bmtInterface->dwInterfaceMapSize);
528 // Restore parent's substitution
529 pParentType->SetSubstitution(parentSubstitution);
530 } // MethodTableBuilder::ExpandApproxInheritedInterfaces
532 //*******************************************************************************
533 // Fill out a fully expanded interface map, such that if we are declared to
534 // implement I3, and I3 extends I1,I2, then I1,I2 are added to our list if
535 // they are not already present.
537 MethodTableBuilder::LoadApproxInterfaceMap()
539 STANDARD_VM_CONTRACT;
541 bmtInterface->dwInterfaceMapSize = 0;
544 //#InjectInterfaceDuplicates_Main
545 // We will inject duplicate interfaces in check builds if env. var.
546 // COMPLUS_INTERNAL_TypeLoader_InjectInterfaceDuplicates is set to TRUE for all types (incl. non-generic
548 // This should allow us better test coverage of duplicates in interface map.
550 // The duplicates are legal for some types:
552 // B<U,V> : A<U>, I<V>
554 // where the interface maps are:
555 // A<T> ... 1 item: I<T>
556 // A<int> ... 1 item: I<int>
557 // B<U,V> ... 2 items: I<U>, I<V>
558 // B<int,int> ... 2 items: I<int>, I<int>
559 // B<_Canon,_Canon> ... 2 items: I<_Canon>, I<_Canon>
560 // B<string,string> ... 2 items: I<string>, I<string>
561 // C ... 2 items: I<int>, I<int>
562 // Note: C had only 1 item (I<int>) in CLR 2.0 RTM/SP1/SP2 and early in CLR 4.0.
564 // We will create duplicate from every re-implemented interface (incl. non-generic):
565 // code:#InjectInterfaceDuplicates_ApproxInterfaces
566 // code:#InjectInterfaceDuplicates_LoadExactInterfaceMap
567 // code:#InjectInterfaceDuplicates_ExactInterfaces
569 // Note that we don't have to do anything for COM, because COM has its own interface map
570 // (code:InteropMethodTableData)which is independent on type's interface map and is created only from
571 // non-generic interfaces (see code:ClassCompat::MethodTableBuilder::BuildInteropVTable_InterfaceList)
573 // We need to keep track which interface duplicates were injected. Right now its either all interfaces
574 // (declared on the type being built, not inheritted) or none. In the future we could inject duplicates
575 // just for some of them.
576 bmtInterface->dbg_fShouldInjectInterfaceDuplicates =
577 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TypeLoader_InjectInterfaceDuplicates) != 0);
578 if (bmtGenerics->Debug_GetTypicalMethodTable() != NULL)
579 { // It's safer to require that all instantiations have the same injected interface duplicates.
580 // In future we could inject different duplicates for various non-shared instantiations.
582 // Use the same injection status as typical instantiation
583 bmtInterface->dbg_fShouldInjectInterfaceDuplicates =
584 bmtGenerics->Debug_GetTypicalMethodTable()->Debug_HasInjectedInterfaceDuplicates();
588 // First inherit all the parent's interfaces. This is important, because our interface map must
589 // list the interfaces in identical order to our parent.
591 // <NICE> we should document the reasons why. One reason is that DispatchMapTypeIDs can be indexes
592 // into the list </NICE>
595 ExpandApproxInheritedInterfaces(bmtInterface, GetParentType());
597 //#ApproxInterfaceMap_SupersetOfParent
598 // Check that parent's interface map is the same as what we just computed
599 // See code:#InterfaceMap_SupersetOfParent
601 MethodTable * pParentMT = GetParentMethodTable();
602 _ASSERTE(pParentMT->GetNumInterfaces() == bmtInterface->dwInterfaceMapSize);
604 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
605 UINT32 nInterfaceIndex = 0;
606 while (parentInterfacesIterator.Next())
608 // Compare TypeDefs of the parent's interface and this interface (full MT comparison is in
609 // code:#ExactInterfaceMap_SupersetOfParent)
610 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
611 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
612 bmtInterface->pInterfaceMap[nInterfaceIndex].GetInterfaceType()->GetMethodTable()));
615 _ASSERTE(nInterfaceIndex == bmtInterface->dwInterfaceMapSize);
620 // Now add in any freshly declared interfaces, possibly augmenting the flags
621 InterfaceDeclarationScope declScope(false, true);
622 ExpandApproxDeclaredInterfaces(
626 COMMA_INDEBUG(NULL));
627 } // MethodTableBuilder::LoadApproxInterfaceMap
629 //*******************************************************************************
630 // Fills array of TypeIDs with all duplicate occurrences of pDeclIntfMT in the interface map.
633 // rg/c DispatchMapTypeIDs - Array of TypeIDs and its count of elements.
634 // pcIfaceDuplicates - Number of duplicate occurrences of the interface in the interface map (ideally <=
635 // count of elements TypeIDs.
637 // Note: If the passed rgDispatchMapTypeIDs array is smaller than the number of duplicates, fills it
638 // with the duplicates that fit and returns number of all existing duplicates (not just those fileld in the
639 // array) in pcIfaceDuplicates.
642 MethodTableBuilder::ComputeDispatchMapTypeIDs(
643 MethodTable * pDeclInftMT,
644 const Substitution * pDeclIntfSubst,
645 DispatchMapTypeID * rgDispatchMapTypeIDs,
646 UINT32 cDispatchMapTypeIDs,
647 UINT32 * pcIfaceDuplicates)
649 STANDARD_VM_CONTRACT;
651 _ASSERTE(pDeclInftMT->IsInterface());
653 // Count of interface duplicates (also used as index into TypeIDs array)
654 *pcIfaceDuplicates = 0;
655 for (DWORD idx = 0; idx < bmtInterface->dwInterfaceMapSize; idx++)
657 bmtInterfaceEntry * pItfEntry = &bmtInterface->pInterfaceMap[idx];
658 bmtRTType * pItfType = pItfEntry->GetInterfaceType();
659 // Type Equivalence is forbidden in interface type ids.
660 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
661 if (MetaSig::CompareTypeDefsUnderSubstitutions(pItfType->GetMethodTable(),
663 &pItfType->GetSubstitution(),
666 { // We found another occurrence of this interface
667 // Can we fit it into the TypeID array?
668 if (*pcIfaceDuplicates < cDispatchMapTypeIDs)
670 rgDispatchMapTypeIDs[*pcIfaceDuplicates] = DispatchMapTypeID::InterfaceClassID(idx);
672 // Increase number of duplicate interfaces
673 (*pcIfaceDuplicates)++;
676 } // MethodTableBuilder::ComputeDispatchMapTypeIDs
678 //*******************************************************************************
680 VOID DECLSPEC_NORETURN
681 MethodTableBuilder::BuildMethodTableThrowException(
683 const bmtErrorInfo & bmtError)
689 INJECT_FAULT(COMPlusThrowOM(););
693 LPCUTF8 pszClassName, pszNameSpace;
694 if (FAILED(bmtError.pModule->GetMDImport()->GetNameOfTypeDef(bmtError.cl, &pszClassName, &pszNameSpace)))
696 pszClassName = pszNameSpace = "Invalid TypeDef record";
699 if (IsNilToken(bmtError.dMethodDefInError) && (bmtError.szMethodNameForError == NULL))
701 if (hr == E_OUTOFMEMORY)
706 bmtError.pModule->GetAssembly()->ThrowTypeLoadException(
707 pszNameSpace, pszClassName, bmtError.resIDWhy);
711 LPCUTF8 szMethodName;
712 if (bmtError.szMethodNameForError == NULL)
714 if (FAILED((bmtError.pModule->GetMDImport())->GetNameOfMethodDef(bmtError.dMethodDefInError, &szMethodName)))
716 szMethodName = "Invalid MethodDef record";
721 szMethodName = bmtError.szMethodNameForError;
724 bmtError.pModule->GetAssembly()->ThrowTypeLoadException(
725 pszNameSpace, pszClassName, szMethodName, bmtError.resIDWhy);
727 } // MethodTableBuilder::BuildMethodTableThrowException
729 //*******************************************************************************
730 void MethodTableBuilder::SetBMTData(
731 LoaderAllocator *bmtAllocator,
732 bmtErrorInfo *bmtError,
733 bmtProperties *bmtProp,
735 bmtParentInfo *bmtParent,
736 bmtInterfaceInfo *bmtInterface,
737 bmtMetaDataInfo *bmtMetaData,
738 bmtMethodInfo *bmtMethod,
739 bmtMethAndFieldDescs *bmtMFDescs,
740 bmtFieldPlacement *bmtFP,
741 bmtInternalInfo *bmtInternal,
742 bmtGCSeriesInfo *bmtGCSeries,
743 bmtMethodImplInfo *bmtMethodImpl,
744 const bmtGenericsInfo *bmtGenerics,
745 bmtEnumFieldInfo *bmtEnumFields)
747 LIMITED_METHOD_CONTRACT;
748 this->bmtAllocator = bmtAllocator;
749 this->bmtError = bmtError;
750 this->bmtProp = bmtProp;
752 this->bmtParent = bmtParent;
753 this->bmtInterface = bmtInterface;
754 this->bmtMetaData = bmtMetaData;
755 this->bmtMethod = bmtMethod;
756 this->bmtMFDescs = bmtMFDescs;
758 this->bmtInternal = bmtInternal;
759 this->bmtGCSeries = bmtGCSeries;
760 this->bmtMethodImpl = bmtMethodImpl;
761 this->bmtGenerics = bmtGenerics;
762 this->bmtEnumFields = bmtEnumFields;
765 //*******************************************************************************
766 // Used by MethodTableBuilder
768 MethodTableBuilder::bmtRTType *
769 MethodTableBuilder::CreateTypeChain(
771 const Substitution & subst)
777 PRECONDITION(CheckPointer(GetStackingAllocator()));
778 PRECONDITION(CheckPointer(pMT));
781 pMT = pMT->GetCanonicalMethodTable();
783 bmtRTType * pType = new (GetStackingAllocator())
784 bmtRTType(subst, pMT);
786 MethodTable * pMTParent = pMT->GetParentMethodTable();
787 if (pMTParent != NULL)
789 pType->SetParentType(
792 pMT->GetSubstitutionForParent(&pType->GetSubstitution())));
798 //*******************************************************************************
800 MethodTableBuilder::bmtRTType *
801 MethodTableBuilder::bmtRTType::FindType(
803 MethodTable * pTargetMT)
807 PRECONDITION(CheckPointer(pType));
808 PRECONDITION(CheckPointer(pTargetMT));
811 pTargetMT = pTargetMT->GetCanonicalMethodTable();
812 while (pType != NULL &&
813 pType->GetMethodTable()->GetCanonicalMethodTable() != pTargetMT)
815 pType = pType->GetParentType();
821 //*******************************************************************************
823 MethodTableBuilder::bmtRTType::GetEnclosingTypeToken() const
825 STANDARD_VM_CONTRACT;
827 mdTypeDef tok = mdTypeDefNil;
830 { // This is guaranteed to succeed because the EEClass would not have been
831 // set as nested unless a valid token was stored in metadata.
832 if (FAILED(GetModule()->m_pEnclosingTypeMap->GetEnclosingTypeNoThrow(GetTypeDefToken(), &tok, GetModule()->GetMDImport())))
841 //*******************************************************************************
843 MethodTableBuilder::MethodSignature::NamesEqual(
844 const MethodSignature & sig1,
845 const MethodSignature & sig2)
847 STANDARD_VM_CONTRACT;
849 if (sig1.GetNameHash() != sig2.GetNameHash())
854 if (strcmp(sig1.GetName(), sig2.GetName()) != 0)
862 //*******************************************************************************
864 MethodTableBuilder::MethodSignature::SignaturesEquivalent(
865 const MethodSignature & sig1,
866 const MethodSignature & sig2,
867 BOOL allowCovariantReturn)
869 STANDARD_VM_CONTRACT;
871 return !!MetaSig::CompareMethodSigs(
872 sig1.GetSignature(), static_cast<DWORD>(sig1.GetSignatureLength()), sig1.GetModule(), sig1.GetSubstitution(),
873 sig2.GetSignature(), static_cast<DWORD>(sig2.GetSignatureLength()), sig2.GetModule(), sig2.GetSubstitution(),
874 allowCovariantReturn);
877 //*******************************************************************************
879 MethodTableBuilder::MethodSignature::SignaturesExactlyEqual(
880 const MethodSignature & sig1,
881 const MethodSignature & sig2)
883 STANDARD_VM_CONTRACT;
885 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
886 return !!MetaSig::CompareMethodSigs(
887 sig1.GetSignature(), static_cast<DWORD>(sig1.GetSignatureLength()), sig1.GetModule(), sig1.GetSubstitution(),
888 sig2.GetSignature(), static_cast<DWORD>(sig2.GetSignatureLength()), sig2.GetModule(), sig2.GetSubstitution(),
892 //*******************************************************************************
894 MethodTableBuilder::MethodSignature::Equivalent(
895 const MethodSignature &rhs) const
897 STANDARD_VM_CONTRACT;
899 return NamesEqual(*this, rhs) && SignaturesEquivalent(*this, rhs, FALSE);
902 //*******************************************************************************
904 MethodTableBuilder::MethodSignature::ExactlyEqual(
905 const MethodSignature &rhs) const
907 STANDARD_VM_CONTRACT;
909 return NamesEqual(*this, rhs) && SignaturesExactlyEqual(*this, rhs);
912 //*******************************************************************************
914 MethodTableBuilder::MethodSignature::GetMethodAttributes() const
916 STANDARD_VM_CONTRACT;
918 IMDInternalImport * pIMD = GetModule()->GetMDImport();
919 if (TypeFromToken(GetToken()) == mdtMethodDef)
922 if (FAILED(pIMD->GetNameAndSigOfMethodDef(GetToken(), &m_pSig, &cSig, &m_szName)))
923 { // We have empty name or signature on error, do nothing
925 m_cSig = static_cast<size_t>(cSig);
929 CONSISTENCY_CHECK(TypeFromToken(m_tok) == mdtMemberRef);
931 if (FAILED(pIMD->GetNameAndSigOfMemberRef(GetToken(), &m_pSig, &cSig, &m_szName)))
932 { // We have empty name or signature on error, do nothing
934 m_cSig = static_cast<size_t>(cSig);
938 //*******************************************************************************
940 MethodTableBuilder::MethodSignature::GetNameHash() const
942 STANDARD_VM_CONTRACT;
944 CheckGetMethodAttributes();
946 if (m_nameHash == INVALID_NAME_HASH)
948 ULONG nameHash = HashStringA(GetName());
949 if (nameHash == INVALID_NAME_HASH)
953 m_nameHash = nameHash;
959 //*******************************************************************************
960 MethodTableBuilder::bmtMDType::bmtMDType(
961 bmtRTType * pParentType,
964 const SigTypeContext & sigContext)
965 : m_pParentType(pParentType),
968 m_enclTok(mdTypeDefNil),
969 m_sigContext(sigContext),
974 STANDARD_VM_CONTRACT;
976 IfFailThrow(m_pModule->GetMDImport()->GetTypeDefProps(m_tok, &m_dwAttrs, NULL));
978 HRESULT hr = m_pModule->m_pEnclosingTypeMap->GetEnclosingTypeNoThrow(m_tok, &m_enclTok, m_pModule->GetMDImport());
982 if (hr != CLDB_E_RECORD_NOTFOUND)
986 // Just in case GetNestedClassProps sets the out param to some other value
987 m_enclTok = mdTypeDefNil;
991 //*******************************************************************************
992 MethodTableBuilder::bmtRTMethod::bmtRTMethod(
993 bmtRTType * pOwningType,
995 : m_pOwningType(pOwningType),
997 m_methodSig(pMD->GetModule(),
999 &pOwningType->GetSubstitution())
1010 //*******************************************************************************
1011 MethodTableBuilder::bmtMDMethod::bmtMDMethod(
1012 bmtMDType * pOwningType,
1017 MethodClassification type,
1018 METHOD_IMPL_TYPE implType)
1019 : m_pOwningType(pOwningType),
1020 m_dwDeclAttrs(dwDeclAttrs),
1021 m_dwImplAttrs(dwImplAttrs),
1024 m_implType(implType),
1025 m_methodSig(pOwningType->GetModule(),
1027 &pOwningType->GetSubstitution()),
1030 m_slotIndex(INVALID_SLOT_INDEX),
1031 m_unboxedSlotIndex(INVALID_SLOT_INDEX)
1041 //*******************************************************************************
1043 MethodTableBuilder::ImportParentMethods()
1045 STANDARD_VM_CONTRACT;
1048 { // If there's no parent, there's no methods to import
1052 SLOT_INDEX numMethods = static_cast<SLOT_INDEX>
1053 (GetParentMethodTable()->GetNumMethods());
1055 bmtParent->pSlotTable = new (GetStackingAllocator())
1056 bmtMethodSlotTable(numMethods, GetStackingAllocator());
1058 MethodTable::MethodIterator it(GetParentMethodTable());
1059 for (;it.IsValid(); it.Next())
1061 MethodDesc * pDeclDesc = NULL;
1062 MethodTable * pDeclMT = NULL;
1063 MethodDesc * pImplDesc = NULL;
1064 MethodTable * pImplMT = NULL;
1068 pDeclDesc = it.GetDeclMethodDesc();
1069 pDeclMT = pDeclDesc->GetMethodTable();
1070 pImplDesc = it.GetMethodDesc();
1071 pImplMT = pImplDesc->GetMethodTable();
1075 pDeclDesc = pImplDesc = it.GetMethodDesc();
1076 pDeclMT = pImplMT = it.GetMethodDesc()->GetMethodTable();
1079 CONSISTENCY_CHECK(CheckPointer(pDeclDesc));
1080 CONSISTENCY_CHECK(CheckPointer(pImplDesc));
1082 // Create and assign to each slot
1083 bmtMethodSlot newSlot;
1084 newSlot.Decl() = new (GetStackingAllocator())
1085 bmtRTMethod(bmtRTType::FindType(GetParentType(), pDeclMT), pDeclDesc);
1086 if (pDeclDesc == pImplDesc)
1088 newSlot.Impl() = newSlot.Decl();
1092 newSlot.Impl() = new (GetStackingAllocator())
1093 bmtRTMethod(bmtRTType::FindType(GetParentType(), pImplMT), pImplDesc);
1096 if (!bmtParent->pSlotTable->AddMethodSlot(newSlot))
1097 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1101 //*******************************************************************************
1103 MethodTableBuilder::CopyParentVtable()
1105 STANDARD_VM_CONTRACT;
1112 for (bmtParentInfo::Iterator it = bmtParent->IterateSlots();
1113 !it.AtEnd() && it.CurrentIndex() < GetParentMethodTable()->GetNumVirtuals();
1116 if (!bmtVT->pSlotTable->AddMethodSlot(*it))
1117 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1118 ++bmtVT->cVirtualSlots;
1119 ++bmtVT->cTotalSlots;
1123 //*******************************************************************************
1124 // Determine if this is the special SIMD type System.Numerics.Vector<T>, whose
1125 // size is determined dynamically based on the hardware and the presence of JIT
1128 // - Update the NumInstanceFieldBytes on the bmtFieldPlacement.
1129 // - Update the m_cbNativeSize and m_cbManagedSize if HasLayout() is true.
1130 // Return a BOOL result to indicate whether the size has been updated.
1132 BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize()
1134 STANDARD_VM_CONTRACT;
1136 #if defined(TARGET_X86) || defined(TARGET_AMD64)
1137 if (!bmtProp->fIsIntrinsicType)
1140 if (bmtFP->NumInstanceFieldBytes != 16)
1146 if (FAILED(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace)))
1149 if (strcmp(className, "Vector`1") != 0 || strcmp(nameSpace, "System.Numerics") != 0)
1152 CORJIT_FLAGS CPUCompileFlags = ExecutionManager::GetEEJitManager()->GetCPUCompileFlags();
1153 uint32_t numInstanceFieldBytes = 16;
1155 if (CPUCompileFlags.IsSet(InstructionSet_VectorT512))
1157 // TODO-XARCH: The JIT needs to be updated to support 64-byte Vector<T>
1158 numInstanceFieldBytes = 32;
1160 else if (CPUCompileFlags.IsSet(InstructionSet_VectorT256))
1162 numInstanceFieldBytes = 32;
1165 if (numInstanceFieldBytes != 16)
1167 bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes;
1171 GetLayoutInfo()->m_cbManagedSize = numInstanceFieldBytes;
1176 #endif // TARGET_X86 || TARGET_AMD64
1181 //*******************************************************************************
1183 MethodTableBuilder::bmtInterfaceEntry::CreateSlotTable(
1184 StackingAllocator * pStackingAllocator)
1186 STANDARD_VM_CONTRACT;
1188 CONSISTENCY_CHECK(m_pImplTable == NULL);
1190 SLOT_INDEX cSlots = (SLOT_INDEX)GetInterfaceType()->GetMethodTable()->GetNumVirtuals();
1191 SLOT_INDEX cSlotsTotal = cSlots;
1193 if (GetInterfaceType()->GetMethodTable()->HasVirtualStaticMethods())
1195 MethodTable::MethodIterator it(GetInterfaceType()->GetMethodTable());
1196 for (; it.IsValid(); it.Next())
1198 MethodDesc *pDeclMD = it.GetDeclMethodDesc();
1199 if (pDeclMD->IsStatic() && pDeclMD->IsVirtual())
1206 bmtInterfaceSlotImpl * pST = new (pStackingAllocator) bmtInterfaceSlotImpl[cSlotsTotal];
1209 MethodTable::MethodIterator it(GetInterfaceType()->GetMethodTable());
1210 for (; it.IsValid(); it.Next())
1212 MethodDesc *pDeclMD = it.GetDeclMethodDesc();
1213 if (!pDeclMD->IsVirtual())
1218 bmtRTMethod * pCurMethod = new (pStackingAllocator)
1219 bmtRTMethod(GetInterfaceType(), it.GetDeclMethodDesc());
1221 if (pDeclMD->IsStatic())
1223 pST[cSlots + m_cImplTableStatics++] = bmtInterfaceSlotImpl(pCurMethod, INVALID_SLOT_INDEX);
1227 CONSISTENCY_CHECK(m_cImplTable == it.GetSlotNumber());
1228 pST[m_cImplTable++] = bmtInterfaceSlotImpl(pCurMethod, INVALID_SLOT_INDEX);
1236 #pragma warning(push)
1237 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1239 //---------------------------------------------------------------------------------------
1241 // Builds the method table, allocates MethodDesc, handles overloaded members, attempts to compress
1242 // interface storage. All dependent classes must already be resolved!
1245 MethodTableBuilder::BuildMethodTableThrowing(
1246 LoaderAllocator * pAllocator,
1247 Module * pLoaderModule,
1250 BuildingInterfaceInfo_t * pBuildingInterfaceList,
1251 const LayoutRawFieldInfo * pLayoutRawFieldInfos,
1252 MethodTable * pParentMethodTable,
1253 const bmtGenericsInfo * bmtGenericsInfo,
1254 SigPointer parentInst,
1255 WORD cBuildingInterfaceList)
1260 PRECONDITION(CheckPointer(GetHalfBakedClass()));
1261 PRECONDITION(CheckPointer(bmtGenericsInfo));
1265 pModule->EnsureLibraryLoaded();
1267 // The following structs, defined as private members of MethodTableBuilder, contain the necessary local
1268 // parameters needed for BuildMethodTable Look at the struct definitions for a detailed list of all
1269 // parameters available to BuildMethodTableThrowing.
1273 new (GetStackingAllocator()) bmtErrorInfo(),
1274 new (GetStackingAllocator()) bmtProperties(),
1275 new (GetStackingAllocator()) bmtVtable(),
1276 new (GetStackingAllocator()) bmtParentInfo(),
1277 new (GetStackingAllocator()) bmtInterfaceInfo(),
1278 new (GetStackingAllocator()) bmtMetaDataInfo(),
1279 new (GetStackingAllocator()) bmtMethodInfo(),
1280 new (GetStackingAllocator()) bmtMethAndFieldDescs(),
1281 new (GetStackingAllocator()) bmtFieldPlacement(),
1282 new (GetStackingAllocator()) bmtInternalInfo(),
1283 new (GetStackingAllocator()) bmtGCSeriesInfo(),
1284 new (GetStackingAllocator()) bmtMethodImplInfo(),
1286 new (GetStackingAllocator()) bmtEnumFieldInfo(pModule->GetMDImport()));
1288 //Initialize structs
1290 bmtError->resIDWhy = IDS_CLASSLOAD_GENERAL; // Set the reason and the offending method def. If the method information
1291 bmtError->pThrowable = NULL;
1292 bmtError->pModule = pModule;
1295 bmtInternal->pInternalImport = pModule->GetMDImport();
1296 bmtInternal->pModule = pModule;
1298 bmtInternal->pParentMT = pParentMethodTable;
1300 // Create the chain of bmtRTType for the parent types. This allows all imported
1301 // parent methods to be associated with their declaring types, and as such it is
1302 // easy to access the appropriate Substitution when comparing signatures.
1303 bmtRTType * pParent = NULL;
1304 if (pParentMethodTable != NULL)
1306 Substitution * pParentSubst =
1307 new (GetStackingAllocator()) Substitution(pModule, parentInst, NULL);
1308 pParent = CreateTypeChain(pParentMethodTable, *pParentSubst);
1311 // Now create the bmtMDType for the type being built.
1312 bmtInternal->pType = new (GetStackingAllocator())
1313 bmtMDType(pParent, pModule, cl, bmtGenericsInfo->typeContext);
1315 // If not NULL, it means there are some by-value fields, and this contains an entry for each inst
1318 // Set debug class name string for easier debugging.
1321 if (FAILED(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace)))
1323 className = nameSpace = "Invalid TypeDef record";
1327 S_SIZE_T safeLen = S_SIZE_T(sizeof(char))*(S_SIZE_T(strlen(className)) + S_SIZE_T(strlen(nameSpace)) + S_SIZE_T(2));
1328 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1330 size_t len = safeLen.Value();
1331 char *name = (char*) AllocateFromHighFrequencyHeap(safeLen);
1332 strcpy_s(name, len, nameSpace);
1333 if (strlen(nameSpace) > 0) {
1334 name[strlen(nameSpace)] = '.';
1335 name[strlen(nameSpace) + 1] = '\0';
1337 strcat_s(name, len, className);
1339 GetHalfBakedClass()->SetDebugClassName(name);
1342 if (g_pConfig->ShouldBreakOnClassBuild(className))
1344 CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassBuild: typename '%s' ", className));
1345 GetHalfBakedClass()->m_fDebuggingClass = TRUE;
1348 LPCUTF8 pszDebugName,pszDebugNamespace;
1349 if (FAILED(pModule->GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &pszDebugName, &pszDebugNamespace)))
1351 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
1354 StackSString debugName(SString::Utf8, pszDebugName);
1356 // If there is an instantiation, update the debug name to include instantiation type names.
1357 if (bmtGenerics->HasInstantiation())
1359 StackSString debugName(SString::Utf8, GetDebugClassName());
1360 TypeString::AppendInst(debugName, bmtGenerics->GetInstantiation(), TypeString::FormatBasic);
1361 const char* pDebugNameUTF8 = debugName.GetUTF8();
1362 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8)) + S_SIZE_T(1);
1363 if(safeLen.IsOverflow())
1364 COMPlusThrowHR(COR_E_OVERFLOW);
1366 size_t len = safeLen.Value();
1367 char *name = (char*) AllocateFromLowFrequencyHeap(safeLen);
1368 strcpy_s(name, len, pDebugNameUTF8);
1369 GetHalfBakedClass()->SetDebugClassName(name);
1370 pszDebugName = (LPCUTF8)name;
1373 LOG((LF_CLASSLOADER, LL_INFO1000, "Loading class \"%s%s%s\" from module \"%s\" in domain 0x%p %s\n",
1374 *pszDebugNamespace ? pszDebugNamespace : "",
1375 *pszDebugNamespace ? NAMESPACE_SEPARATOR_STR : "",
1376 debugName.GetUTF8(),
1377 pModule->GetDebugName(),
1378 pModule->GetDomain(),
1379 (pModule->IsSystem()) ? "System Domain" : ""
1383 // If this is CoreLib, then don't perform some sanity checks on the layout
1384 bmtProp->fNoSanityChecks = pModule->IsSystem() ||
1385 #ifdef FEATURE_READYTORUN
1386 // No sanity checks for ready-to-run compiled images if possible
1387 (pModule->IsReadyToRun() && pModule->GetReadyToRunInfo()->SkipTypeValidation()) ||
1389 // No sanity checks for real generic instantiations
1390 !bmtGenerics->IsTypicalTypeDefinition();
1392 // Interfaces have a parent class of Object, but we don't really want to inherit all of
1393 // Object's virtual methods, so pretend we don't have a parent class - at the bottom of this
1394 // function we reset the parent class
1397 bmtInternal->pType->SetParentType(NULL);
1398 bmtInternal->pParentMT = NULL;
1401 unsigned totalDeclaredFieldSize=0;
1403 // Check to see if the class is a valuetype; but we don't want to mark System.Enum
1404 // as a ValueType. To accomplish this, the check takes advantage of the fact
1405 // that System.ValueType and System.Enum are loaded one immediately after the
1406 // other in that order, and so if the parent MethodTable is System.ValueType and
1407 // the System.Enum MethodTable is unset, then we must be building System.Enum and
1408 // so we don't mark it as a ValueType.
1410 ((g_pEnumClass != NULL && GetParentMethodTable() == g_pValueTypeClass) ||
1411 GetParentMethodTable() == g_pEnumClass))
1413 bmtProp->fIsValueClass = true;
1415 HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
1416 WellKnownAttribute::UnsafeValueType,
1421 SetUnsafeValueClass();
1424 hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
1425 WellKnownAttribute::IsByRefLike,
1430 bmtFP->fIsByRefLikeType = true;
1434 // Check to see if the class is an enumeration. No fancy checks like the one immediately
1435 // above for value types are necessary here.
1436 if(HasParent() && GetParentMethodTable() == g_pEnumClass)
1438 bmtProp->fIsEnum = true;
1440 // Ensure we don't have generic enums, or at least enums that have a
1441 // different number of type parameters from their enclosing class.
1442 // The goal is to ensure that the enum's values can't depend on the
1443 // type parameters in any way. And we don't see any need for an
1444 // enum to have additional type parameters.
1445 if (bmtGenerics->GetNumGenericArgs() != 0)
1447 // Nested enums can have generic type parameters from their enclosing class.
1448 // CLS rules require type parameters to be propagated to nested types.
1449 // Note that class G<T> { enum E { } } will produce "G`1+E<T>".
1450 // We want to disallow class G<T> { enum E<T, U> { } }
1451 // Perhaps the IL equivalent of class G<T> { enum E { } } should be legal.
1454 BuildMethodTableThrowException(IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM);
1457 mdTypeDef tdEnclosing = mdTypeDefNil;
1458 HRESULT hr = GetModule()->m_pEnclosingTypeMap->GetEnclosingTypeNoThrow(GetCl(), &tdEnclosing, GetModule()->GetMDImport());
1460 ThrowHR(hr, BFA_UNABLE_TO_GET_NESTED_PROPS);
1462 uint32_t genericArgCount;
1463 if (FAILED(GetModule()->m_pTypeGenericInfoMap->GetGenericArgumentCountNoThrow(tdEnclosing, &genericArgCount, GetMDImport())))
1465 GetAssembly()->ThrowTypeLoadException(GetMDImport(), tdEnclosing, IDS_CLASSLOAD_BADFORMAT);
1468 if (genericArgCount != bmtGenerics->GetNumGenericArgs())
1470 BuildMethodTableThrowException(IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM);
1475 // If this type is marked by [Intrinsic] attribute, it may be specially treated by the runtime/compiler
1476 // SIMD types have [Intrinsic] attribute, for example
1478 // We check this here fairly early to ensure other downstream checks on these types can be slightly more efficient.
1479 if (GetModule()->IsSystem())
1481 HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
1482 WellKnownAttribute::Intrinsic,
1488 bmtProp->fIsIntrinsicType = true;
1492 #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64)
1493 if (bmtProp->fIsIntrinsicType && !bmtGenerics->HasInstantiation())
1497 HRESULT hr = GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace);
1499 if (bmtInternal->pType->IsNested())
1501 IfFailThrow(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetEnclosingTypeToken(), NULL, &nameSpace));
1504 #if defined(TARGET_ARM64)
1505 // All the funtions in System.Runtime.Intrinsics.Arm are hardware intrinsics.
1506 if (hr == S_OK && strcmp(nameSpace, "System.Runtime.Intrinsics.Arm") == 0)
1508 // All the funtions in System.Runtime.Intrinsics.X86 are hardware intrinsics.
1509 if (hr == S_OK && (strcmp(nameSpace, "System.Runtime.Intrinsics.X86") == 0))
1512 bmtProp->fIsHardwareIntrinsic = true;
1517 // Com Import classes are special. These types must derive from System.Object,
1518 // and we then substitute the parent with System._ComObject.
1519 if (IsComImport() && !IsEnum() && !IsInterface() && !IsValueClass() && !IsDelegate())
1521 #ifdef FEATURE_COMINTEROP
1522 // ComImport classes must extend from Object
1523 MethodTable* pMTParent = GetParentMethodTable();
1524 if ((pMTParent == NULL) || (pMTParent != g_pObjectClass))
1526 BuildMethodTableThrowException(IDS_CLASSLOAD_CANTEXTEND);
1531 // ComImport classes cannot have layout information.
1532 BuildMethodTableThrowException(IDS_CLASSLOAD_COMIMPCANNOTHAVELAYOUT);
1535 if (g_pBaseCOMObject != NULL)
1537 // We could have had COM interop classes derive from System._ComObject,
1538 // but instead we have them derive from System.Object, have them set the
1539 // ComImport bit in the type attributes, and then we swap out the parent
1540 // type under the covers.
1541 bmtInternal->pType->SetParentType(CreateTypeChain(g_pBaseCOMObject, Substitution()));
1542 bmtInternal->pParentMT = g_pBaseCOMObject;
1545 // if the current class is imported
1546 bmtProp->fIsComObjectType = true;
1549 #ifdef FEATURE_COMINTEROP
1550 // Check for special COM interop types.
1551 CheckForSpecialTypes();
1553 CheckForTypeEquivalence(cBuildingInterfaceList, pBuildingInterfaceList);
1556 { // Types that inherit from com object types are themselves com object types.
1557 if (GetParentMethodTable()->IsComObjectType())
1559 // if the parent class is of ComObjectType
1561 bmtProp->fIsComObjectType = true;
1564 #ifdef FEATURE_TYPEEQUIVALENCE
1565 // If your parent is type equivalent then so are you
1566 if (GetParentMethodTable()->HasTypeEquivalence())
1568 bmtProp->fHasTypeEquivalence = true;
1573 #endif // FEATURE_COMINTEROP
1575 if (!HasParent() && !IsInterface())
1577 if(g_pObjectClass != NULL)
1579 if(!IsGlobalClass())
1581 // Non object derived types that are not the global class are prohibited by spec
1582 BuildMethodTableThrowException(IDS_CLASSLOAD_PARENTNULL);
1587 // NOTE: This appears to be the earliest point during class loading that other classes MUST be loaded
1588 // resolve unresolved interfaces, determine an upper bound on the size of the interface map,
1589 // and determine the size of the largest interface (in # slots)
1590 ResolveInterfaces(cBuildingInterfaceList, pBuildingInterfaceList);
1592 // Enumerate this class's methodImpls
1593 EnumerateMethodImpls();
1595 // Enumerate this class's methods and fields
1596 EnumerateClassMethods();
1599 EnumerateClassFields();
1601 // Import the slots of the parent for use in placing this type's methods.
1602 ImportParentMethods();
1604 // This will allocate the working versions of the VTable and NonVTable in bmtVT
1605 AllocateWorkingSlotTables();
1607 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
1608 AllocateFieldDescs();
1610 // Copy the parent's vtable into the current type's vtable
1613 bmtVT->pDispatchMapBuilder = new (GetStackingAllocator()) DispatchMapBuilder(GetStackingAllocator());
1615 // Determine vtable placement for each member in this class
1616 PlaceVirtualMethods();
1617 PlaceNonVirtualMethods();
1619 // Allocate MethodDescs (expects methods placed methods)
1620 AllocAndInitMethodDescs();
1625 // We need to process/place method impls for default interface method overrides.
1626 // We won't build dispatch map for interfaces, though.
1628 ProcessMethodImpls();
1634 // If we are a class, then there may be some unplaced vtable methods (which are by definition
1635 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
1636 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
1637 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
1638 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
1639 // map for all interfaces as they are placed.
1641 // If we are an interface, then all methods are already placed. Fill out the interface map for
1642 // interfaces as they are placed.
1644 ComputeInterfaceMapEquivalenceSet();
1646 PlaceInterfaceMethods();
1648 ProcessMethodImpls();
1649 ProcessInexactMethodImpls();
1652 if (!bmtProp->fNoSanityChecks)
1654 // Now that interface method implementation have been fully resolved,
1655 // we need to make sure that type constraints are also met.
1656 ValidateInterfaceMethodConstraints();
1660 // Verify that we have not overflowed the number of slots.
1661 if (!FitsInU2((UINT64)bmtVT->pSlotTable->GetSlotCount()))
1663 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1666 // ensure we didn't overflow the temporary vtable
1667 _ASSERTE(bmtVT->pSlotTable->GetSlotCount() <= bmtVT->dwMaxVtableSize);
1669 // Allocate and initialize the dictionary for the type. This will be filled out later
1670 // with the final values.
1671 AllocAndInitDictionary();
1673 ////////////////////////////////////////////////////////////////////////////////////////////////
1677 // We decide here if we need a dynamic entry for our statics. We need it here because
1678 // the offsets of our fields will depend on this. For the dynamic case (which requires
1679 // an extra indirection (indirect depending of methodtable) we'll allocate the slot
1680 // in setupmethodtable
1681 if (((pAllocator->IsCollectible() || pModule->IsReflection() || bmtGenerics->HasInstantiation() || !pModule->IsStaticStoragePrepared(cl)) &&
1682 (bmtVT->GetClassCtorSlotIndex() != INVALID_SLOT_INDEX || bmtEnumFields->dwNumStaticFields !=0))
1683 #ifdef EnC_SUPPORTED
1684 // Classes in modules that have been edited (would do on class level if there were a
1685 // way to tell if the class had been edited) also have dynamic statics as the number
1686 // of statics might have changed, so can't use the static module-wide storage
1687 || (pModule->IsEditAndContinueEnabled() &&
1688 ((EditAndContinueModule*)pModule)->GetApplyChangesCount() > CorDB_DEFAULT_ENC_FUNCTION_VERSION)
1689 #endif // EnC_SUPPORTED
1692 // We will need a dynamic id
1693 bmtProp->fDynamicStatics = true;
1695 if (bmtGenerics->HasInstantiation())
1697 bmtProp->fGenericsStatics = true;
1701 // If not NULL, it means there are some by-value fields, and this contains an entry for each instance or static field,
1702 // which is NULL if not a by value field, and points to the EEClass of the field if a by value field. Instance fields
1703 // come first, statics come second.
1704 MethodTable ** pByValueClassCache = NULL;
1706 // Go thru all fields and initialize their FieldDescs.
1707 InitializeFieldDescs(GetApproxFieldDescListRaw(), pLayoutRawFieldInfos, bmtInternal, bmtGenerics,
1708 bmtMetaData, bmtEnumFields, bmtError,
1709 &pByValueClassCache, bmtMFDescs, bmtFP,
1710 &totalDeclaredFieldSize);
1714 const void* pVal; // The custom value.
1715 ULONG cbVal; // Size of the custom value.
1716 HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
1717 WellKnownAttribute::InlineArrayAttribute,
1722 if (bmtEnumFields->dwNumInstanceFields != 1)
1724 BuildMethodTableThrowException(IDS_CLASSLOAD_INLINE_ARRAY_FIELD_COUNT);
1727 if (cbVal >= (sizeof(INT32) + 2))
1729 INT32 repeat = GET_UNALIGNED_VAL32((byte*)pVal + 2);
1732 bmtFP->NumInlineArrayElements = repeat;
1733 GetHalfBakedClass()->SetIsInlineArray();
1737 BuildMethodTableThrowException(IDS_CLASSLOAD_INLINE_ARRAY_LENGTH);
1740 if (HasExplicitFieldOffsetLayout())
1742 BuildMethodTableThrowException(IDS_CLASSLOAD_INLINE_ARRAY_EXPLICIT);
1748 // Place regular static fields
1749 PlaceRegularStaticFields();
1751 // Place thread static fields
1752 PlaceThreadStaticFields();
1754 LOG((LF_CODESHARING,
1756 "Placing %d statics (%d handles) for class %s.\n",
1757 GetNumStaticFields(), GetNumHandleRegularStatics() + GetNumHandleThreadStatics(),
1760 if (IsBlittable() || IsManagedSequential())
1762 bmtFP->NumGCPointerSeries = 0;
1763 bmtFP->NumInstanceGCPointerFields = 0;
1765 _ASSERTE(HasLayout());
1767 if (bmtFP->NumInlineArrayElements != 0)
1769 GetLayoutInfo()->m_cbManagedSize *= bmtFP->NumInlineArrayElements;
1772 bmtFP->NumInstanceFieldBytes = GetLayoutInfo()->m_cbManagedSize;
1774 // For simple Blittable types we still need to check if they have any overlapping
1775 // fields and call the method SetHasOverlaidFields() when they are detected.
1777 if (HasExplicitFieldOffsetLayout())
1779 _ASSERTE(!bmtGenerics->fContainsGenericVariables); // A simple Blittable type can't ever be an open generic type.
1780 HandleExplicitLayout(pByValueClassCache);
1785 _ASSERTE(!IsBlittable());
1786 // HandleExplicitLayout fails for the GenericTypeDefinition when
1787 // it will succeed for some particular instantiations.
1788 // Thus we only do explicit layout for real instantiations, e.g. C<int>, not
1789 // the open types such as the GenericTypeDefinition C<!0> or any
1790 // of the "fake" types involving generic type variables which are
1791 // used for reflection and verification, e.g. C<List<!0>>.
1793 if (!bmtGenerics->fContainsGenericVariables && HasExplicitFieldOffsetLayout())
1795 HandleExplicitLayout(pByValueClassCache);
1799 // Place instance fields
1800 PlaceInstanceFields(pByValueClassCache);
1804 if (CheckIfSIMDAndUpdateSize())
1806 totalDeclaredFieldSize = bmtFP->NumInstanceFieldBytes;
1809 // We enforce that all value classes have non-zero size
1810 if (IsValueClass() && bmtFP->NumInstanceFieldBytes == 0)
1812 BuildMethodTableThrowException(IDS_CLASSLOAD_ZEROSIZE);
1815 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
1816 { // Verify self-referencing statics with RVA (now when the ValueType size is known)
1817 VerifySelfReferencingStaticValueTypeFields_WithRVA(pByValueClassCache);
1821 // Now setup the method table
1823 SetupMethodTable2(pLoaderModule);
1825 MethodTable * pMT = GetHalfBakedMethodTable();
1827 #ifdef FEATURE_64BIT_ALIGNMENT
1828 if (GetHalfBakedClass()->IsAlign8Candidate())
1829 pMT->SetRequiresAlign8();
1832 if (bmtGenerics->pVarianceInfo != NULL)
1834 pMT->SetHasVariance();
1837 if (bmtFP->NumRegularStaticGCBoxedFields != 0)
1839 pMT->SetHasBoxedRegularStatics();
1842 if (bmtFP->fIsByRefLikeType)
1844 pMT->SetIsByRefLike();
1849 if (bmtFP->NumInstanceFieldBytes != totalDeclaredFieldSize || HasOverlaidField())
1850 GetHalfBakedClass()->SetIsNotTightlyPacked();
1853 GetHalfBakedClass()->CheckForHFA(pByValueClassCache);
1855 #ifdef UNIX_AMD64_ABI
1857 #error "Can't have FEATURE_HFA and UNIX_AMD64_ABI defined at the same time."
1858 #endif // FEATURE_HFA
1859 SystemVAmd64CheckForPassStructInRegister(pByValueClassCache);
1860 #endif // UNIX_AMD64_ABI
1864 pMT->SetDebugClassName(GetDebugClassName());
1867 #ifdef FEATURE_COMINTEROP
1870 GetCoClassAttribInfo();
1872 #endif // FEATURE_COMINTEROP
1874 if (HasExplicitFieldOffsetLayout())
1875 // Perform relevant GC calculations for tdexplicit
1876 HandleGCForExplicitLayout();
1878 // Perform relevant GC calculations for value classes
1879 HandleGCForValueClasses(pByValueClassCache);
1881 // GC reqires the series to be sorted.
1882 // TODO: fix it so that we emit them in the correct order in the first place.
1883 if (pMT->ContainsPointers())
1885 CGCDesc* gcDesc = CGCDesc::GetCGCDescFromMT(pMT);
1886 qsort(gcDesc->GetLowestSeries(), (int)gcDesc->GetNumSeries(), sizeof(CGCDescSeries), compareCGCDescSeries);
1889 SetFinalizationSemantics();
1891 // Allocate dynamic slot if necessary
1892 if (bmtProp->fDynamicStatics)
1894 if (bmtProp->fGenericsStatics)
1896 FieldDesc* pStaticFieldDescs = NULL;
1898 if (bmtEnumFields->dwNumStaticFields != 0)
1900 pStaticFieldDescs = pMT->GetApproxFieldDescListRaw() + bmtEnumFields->dwNumInstanceFields;
1903 pMT->SetupGenericsStaticsInfo(pStaticFieldDescs);
1907 // Get an id for the dynamic class. We store it in the class because
1908 // no class that is persisted in ngen should have it (ie, if the class is ngened
1909 // The id is stored in an optional field so we need to ensure an optional field descriptor has
1910 // been allocated for this EEClass instance.
1911 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, pAllocator->GetLowFrequencyHeap());
1912 SetModuleDynamicID(GetModule()->AllocateDynamicEntry(pMT));
1917 // if there are context or thread static set the info in the method table optional members
1920 // structs with GC pointers MUST be pointer sized aligned because the GC assumes it
1921 if (IsValueClass() && pMT->ContainsPointers() && (bmtFP->NumInstanceFieldBytes % TARGET_POINTER_SIZE != 0))
1923 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
1928 // Reset parent class
1929 pMT->SetParentMethodTable (g_pObjectClass);
1933 // Reset the debug method names for BoxedEntryPointStubs
1934 // so they reflect the very best debug information for the methods
1936 DeclaredMethodIterator methIt(*this);
1937 while (methIt.Next())
1939 if (methIt->GetUnboxedMethodDesc() != NULL)
1942 MethodDesc *pMD = methIt->GetUnboxedMethodDesc();
1944 TypeString::AppendMethodDebug(name, pMD);
1945 const char* pDebugNameUTF8 = name.GetUTF8();
1946 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8)) + S_SIZE_T(1);
1947 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1948 size_t len = safeLen.Value();
1949 pMD->m_pszDebugMethodName = (char*) AllocateFromLowFrequencyHeap(safeLen);
1950 _ASSERTE(pMD->m_pszDebugMethodName);
1951 strcpy_s((char *) pMD->m_pszDebugMethodName, len, pDebugNameUTF8);
1955 MethodDesc *pMD = methIt->GetMethodDesc();
1958 TypeString::AppendMethodDebug(name, pMD);
1959 const char* pDebugNameUTF8 = name.GetUTF8();
1960 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8))+S_SIZE_T(1);
1961 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1962 size_t len = safeLen.Value();
1963 pMD->m_pszDebugMethodName = (char*) AllocateFromLowFrequencyHeap(safeLen);
1964 _ASSERTE(pMD->m_pszDebugMethodName);
1965 strcpy_s((char *) pMD->m_pszDebugMethodName, len, pDebugNameUTF8);
1973 //If this is a value type, then propagate the UnsafeValueTypeAttribute from
1974 //its instance members to this type.
1975 if (IsValueClass() && !IsUnsafeValueClass())
1977 ApproxFieldDescIterator fields(GetHalfBakedMethodTable(),
1978 ApproxFieldDescIterator::INSTANCE_FIELDS );
1979 FieldDesc * current;
1980 while (NULL != (current = fields.Next()))
1982 CONSISTENCY_CHECK(!current->IsStatic());
1983 if (current->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1985 _ASSERTE((size_t)fields.GetValueClassCacheIndex() < bmtEnumFields->dwNumInstanceFields);
1986 TypeHandle th = TypeHandle(pByValueClassCache[fields.GetValueClassCacheIndex()]);
1987 CONSISTENCY_CHECK(!th.IsNull());
1988 if (th.AsMethodTable()->GetClass()->IsUnsafeValueClass())
1990 SetUnsafeValueClass();
1997 if (!IsValueClass())
1999 #ifdef FEATURE_ICASTABLE
2000 if (g_pICastableInterface != NULL && pMT->CanCastToInterface(g_pICastableInterface))
2002 pMT->SetICastable();
2004 #endif // FEATURE_ICASTABLE
2006 if (g_pIDynamicInterfaceCastableInterface != NULL && pMT->CanCastToInterface(g_pIDynamicInterfaceCastableInterface))
2008 pMT->SetIDynamicInterfaceCastable();
2012 #ifdef FEATURE_OBJCMARSHAL
2013 // Check if this type has a finalizer and then if it is a referenced tracked type.
2014 if (pMT->HasFinalizer() && !IsValueClass() && !IsInterface() && !IsDelegate())
2016 BOOL isTrackedReference = FALSE;
2019 MethodTable * pParentClass = GetParentMethodTable();
2020 PREFIX_ASSUME(pParentClass != NULL);
2021 isTrackedReference = pParentClass->IsTrackedReferenceWithFinalizer();
2024 if (!isTrackedReference)
2026 HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
2027 WellKnownAttribute::ObjectiveCTrackedTypeAttribute,
2031 isTrackedReference = hr == S_OK ? TRUE : FALSE;
2034 if (isTrackedReference)
2035 pMT->SetIsTrackedReferenceWithFinalizer();
2037 #endif // FEATURE_OBJCMARSHAL
2039 // Grow the typedef ridmap in advance as we can't afford to
2040 // fail once we set the resolve bit
2041 pModule->EnsureTypeDefCanBeStored(bmtInternal->pType->GetTypeDefToken());
2043 // Grow the tables in advance so that RID map filling cannot fail
2044 // once we're past the commit point.
2045 EnsureRIDMapsCanBeFilled();
2048 if (g_pConfig->ShouldDumpOnClassLoad(pszDebugName))
2050 LOG((LF_ALWAYS, LL_ALWAYS, "Method table summary for '%s':\n", pszDebugName));
2051 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static fields: %d\n", bmtEnumFields->dwNumStaticFields));
2052 LOG((LF_ALWAYS, LL_ALWAYS, "Number of instance fields: %d\n", bmtEnumFields->dwNumInstanceFields));
2053 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static obj ref fields: %d\n", bmtEnumFields->dwNumStaticObjRefFields));
2054 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static boxed fields: %d\n", bmtEnumFields->dwNumStaticBoxedFields));
2055 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared fields: %d\n", NumDeclaredFields()));
2056 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared methods: %d\n", NumDeclaredMethods()));
2057 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared non-abstract methods: %d\n", bmtMethod->dwNumDeclaredNonAbstractMethods));
2059 BOOL debugging = IsDebuggerPresent();
2060 pMT->Debug_DumpInterfaceMap("Approximate");
2061 pMT->DebugDumpVtable(pszDebugName, debugging);
2062 pMT->DebugDumpFieldLayout(pszDebugName, debugging);
2063 pMT->DebugDumpGCDesc(pszDebugName, debugging);
2064 pMT->Debug_DumpDispatchMap();
2068 STRESS_LOG3(LF_CLASSLOADER, LL_INFO1000, "MTB:BMTT finished method table for module %p token %x = %p\n",
2071 GetHalfBakedMethodTable());
2073 return GetHalfBakedMethodTable();
2074 } // MethodTableBuilder::BuildMethodTableThrowing
2076 #pragma warning(pop)
2080 //---------------------------------------------------------------------------------------
2082 // Resolve unresolved interfaces, determine an upper bound on the size of the interface map.
2085 MethodTableBuilder::ResolveInterfaces(
2086 WORD cBuildingInterfaceList,
2087 BuildingInterfaceInfo_t * pBuildingInterfaceList)
2092 PRECONDITION(CheckPointer(this));
2093 PRECONDITION(CheckPointer(bmtAllocator));
2094 PRECONDITION(CheckPointer(bmtInterface));
2095 PRECONDITION(CheckPointer(bmtVT));
2096 PRECONDITION(CheckPointer(bmtParent));
2100 // resolve unresolved interfaces and determine the size of the largest interface (in # slots)
2103 LoadApproxInterfaceMap();
2105 // Inherit parental slot counts
2106 //@TODO: This doesn't belong here.
2109 MethodTable * pParentClass = GetParentMethodTable();
2110 PREFIX_ASSUME(pParentClass != NULL);
2112 bmtParent->NumParentPointerSeries = pParentClass->ContainsPointers() ?
2113 (DWORD)CGCDesc::GetCGCDescFromMT(pParentClass)->GetNumSeries() : 0;
2115 if (pParentClass->HasFieldsWhichMustBeInited())
2117 SetHasFieldsWhichMustBeInited();
2119 #ifdef FEATURE_READYTORUN
2120 if (!(IsValueClass() || (pParentClass == g_pObjectClass)))
2122 CheckLayoutDependsOnOtherModules(pParentClass);
2128 bmtParent->NumParentPointerSeries = 0;
2130 } // MethodTableBuilder::ResolveInterfaces
2132 //*******************************************************************************
2134 int __cdecl MethodTableBuilder::bmtMetaDataInfo::MethodImplTokenPair::Compare(
2138 STATIC_CONTRACT_LEAF;
2139 MethodImplTokenPair *e1 = (MethodImplTokenPair *)elem1;
2140 MethodImplTokenPair *e2 = (MethodImplTokenPair *)elem2;
2141 if (e1->methodBody < e2->methodBody) return -1;
2142 else if (e1->methodBody > e2->methodBody) return 1;
2143 else if (e1->methodDecl < e2->methodDecl) return -1;
2144 else if (e1->methodDecl > e2->methodDecl) return 1;
2148 //*******************************************************************************
2150 BOOL MethodTableBuilder::bmtMetaDataInfo::MethodImplTokenPair::Equal(
2151 const MethodImplTokenPair *elem1,
2152 const MethodImplTokenPair *elem2)
2154 STATIC_CONTRACT_LEAF;
2155 return ((elem1->methodBody == elem2->methodBody) &&
2156 (elem1->methodDecl == elem2->methodDecl));
2159 //*******************************************************************************
2160 BOOL MethodTableBuilder::IsEligibleForCovariantReturns(mdToken methodDeclToken)
2162 STANDARD_VM_CONTRACT;
2165 // Note on covariant return types: right now we only support covariant returns for MethodImpls on
2166 // classes, where the MethodDecl is also on a class. Interface methods are not supported.
2167 // We will also allow covariant return types if both the MethodImpl and MethodDecl are not on the same type.
2171 IMDInternalImport* pMDInternalImport = GetMDImport();
2173 // First, check if the type with the MethodImpl is a class.
2174 if (IsValueClass() || IsInterface())
2178 hr = pMDInternalImport->GetParentToken(methodDeclToken, &tkParent);
2180 BuildMethodTableThrowException(hr, *bmtError);
2182 // Second, check that the type with the MethodImpl is not the same as the type with the MethodDecl
2183 if (GetCl() == tkParent)
2186 // Finally, check that the type with the MethodDecl is not an interface. To do so, we need to compute the TypeDef
2187 // token of the type with the MethodDecl, as well as its module, in order to use the metadata to check if the type
2189 mdToken declTypeDefToken = mdTokenNil;
2190 Module* pDeclModule = GetModule();
2191 if (TypeFromToken(tkParent) == mdtTypeRef || TypeFromToken(tkParent) == mdtTypeDef)
2193 if (!ClassLoader::ResolveTokenToTypeDefThrowing(GetModule(), tkParent, &pDeclModule, &declTypeDefToken))
2196 else if (TypeFromToken(tkParent) == mdtTypeSpec)
2199 PCCOR_SIGNATURE pTypeSig;
2200 hr = pMDInternalImport->GetSigFromToken(tkParent, &cbTypeSig, &pTypeSig);
2202 BuildMethodTableThrowException(hr, *bmtError);
2204 SigParser parser(pTypeSig, cbTypeSig);
2206 CorElementType elementType;
2207 IfFailThrow(parser.GetElemType(&elementType));
2209 if (elementType == ELEMENT_TYPE_GENERICINST)
2211 IfFailThrow(parser.GetElemType(&elementType));
2214 if (elementType == ELEMENT_TYPE_CLASS)
2216 mdToken declTypeDefOrRefToken;
2217 IfFailThrow(parser.GetToken(&declTypeDefOrRefToken));
2218 if (!ClassLoader::ResolveTokenToTypeDefThrowing(GetModule(), declTypeDefOrRefToken, &pDeclModule, &declTypeDefToken))
2223 if (declTypeDefToken == mdTokenNil)
2226 // Now that we have computed the TypeDef token and the module, check its attributes to verify it is not an interface.
2229 hr = pDeclModule->GetMDImport()->GetTypeDefProps(declTypeDefToken, &attr, NULL);
2231 BuildMethodTableThrowException(hr, *bmtError);
2233 return !IsTdInterface(attr);
2236 //*******************************************************************************
2238 MethodTableBuilder::EnumerateMethodImpls()
2240 STANDARD_VM_CONTRACT;
2243 IMDInternalImport * pMDInternalImport = GetMDImport();
2244 DWORD rid, maxRidMD, maxRidMR;
2245 HENUMInternalMethodImplHolder hEnumMethodImpl(pMDInternalImport);
2246 hr = hEnumMethodImpl.EnumMethodImplInitNoThrow(GetCl());
2250 BuildMethodTableThrowException(hr, *bmtError);
2253 // This gets the count out of the metadata interface.
2254 bmtMethod->dwNumberMethodImpls = hEnumMethodImpl.EnumMethodImplGetCount();
2255 bmtMethod->dwNumberInexactMethodImplCandidates = 0;
2257 // This is the first pass. In this we will simply enumerate the token pairs and fill in
2258 // the data structures. In addition, we'll sort the list and eliminate duplicates.
2259 if (bmtMethod->dwNumberMethodImpls > 0)
2262 // Allocate the structures to keep track of the token pairs
2264 bmtMetaData->rgMethodImplTokens = new (GetStackingAllocator())
2265 bmtMetaDataInfo::MethodImplTokenPair[bmtMethod->dwNumberMethodImpls];
2267 // Iterate through each MethodImpl declared on this class
2268 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls; i++)
2270 hr = hEnumMethodImpl.EnumMethodImplNext(
2271 &bmtMetaData->rgMethodImplTokens[i].methodBody,
2272 &bmtMetaData->rgMethodImplTokens[i].methodDecl);
2273 bmtMetaData->rgMethodImplTokens[i].fConsiderDuringInexactMethodImplProcessing = false;
2274 bmtMetaData->rgMethodImplTokens[i].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
2275 bmtMetaData->rgMethodImplTokens[i].interfaceEquivalenceSet = 0;
2276 bmtMetaData->rgMethodImplTokens[i].fRequiresCovariantReturnTypeChecking = false;
2280 BuildMethodTableThrowException(hr, *bmtError);
2282 // Grab the next set of body/decl tokens
2285 // In the odd case that the enumerator fails before we've reached the total reported
2286 // entries, let's reset the count and just break out. (Should we throw?)
2287 bmtMethod->dwNumberMethodImpls = i;
2292 // No need to do any sorting or duplicate elimination if there's not two or more methodImpls
2293 if (bmtMethod->dwNumberMethodImpls > 1)
2296 qsort(bmtMetaData->rgMethodImplTokens,
2297 bmtMethod->dwNumberMethodImpls,
2298 sizeof(bmtMetaDataInfo::MethodImplTokenPair),
2299 &bmtMetaDataInfo::MethodImplTokenPair::Compare);
2301 // Now eliminate duplicates
2302 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls - 1; i++)
2304 CONSISTENCY_CHECK((i + 1) < bmtMethod->dwNumberMethodImpls);
2306 bmtMetaDataInfo::MethodImplTokenPair *e1 = &bmtMetaData->rgMethodImplTokens[i];
2307 bmtMetaDataInfo::MethodImplTokenPair *e2 = &bmtMetaData->rgMethodImplTokens[i + 1];
2309 // If the pair are equal, eliminate the first one, and reduce the total count by one.
2310 if (bmtMetaDataInfo::MethodImplTokenPair::Equal(e1, e2))
2312 DWORD dwCopyNum = bmtMethod->dwNumberMethodImpls - (i + 1);
2313 memcpy(e1, e2, dwCopyNum * sizeof(bmtMetaDataInfo::MethodImplTokenPair));
2314 bmtMethod->dwNumberMethodImpls--;
2315 CONSISTENCY_CHECK(bmtMethod->dwNumberMethodImpls > 0);
2321 if (bmtMethod->dwNumberMethodImpls != 0)
2324 // Allocate the structures to keep track of the impl matches
2326 bmtMetaData->pMethodDeclSubsts = new (GetStackingAllocator())
2327 Substitution[bmtMethod->dwNumberMethodImpls];
2329 // These are used for verification
2330 maxRidMD = pMDInternalImport->GetCountWithTokenKind(mdtMethodDef);
2331 maxRidMR = pMDInternalImport->GetCountWithTokenKind(mdtMemberRef);
2333 // Iterate through each MethodImpl declared on this class
2334 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls; i++)
2336 PCCOR_SIGNATURE pSigDecl = NULL;
2337 PCCOR_SIGNATURE pSigBody = NULL;
2342 mdToken theBody, theDecl;
2343 Substitution theDeclSubst(GetModule(), SigPointer(), NULL); // this can get updated later below.
2345 theBody = bmtMetaData->rgMethodImplTokens[i].methodBody;
2346 theDecl = bmtMetaData->rgMethodImplTokens[i].methodDecl;
2348 // IMPLEMENTATION LIMITATION: currently, we require that the body of a methodImpl
2349 // belong to the current type. This is because we need to allocate a different
2350 // type of MethodDesc for bodies that are part of methodImpls.
2351 if (TypeFromToken(theBody) != mdtMethodDef)
2353 hr = FindMethodDeclarationForMethodImpl(
2359 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_MI_ILLEGAL_BODY, mdMethodDefNil);
2362 // Make sure to update the stored token with the resolved token.
2363 bmtMetaData->rgMethodImplTokens[i].methodBody = theBody;
2366 if (TypeFromToken(theBody) != mdtMethodDef)
2368 BuildMethodTableThrowException(BFA_METHODDECL_NOT_A_METHODDEF);
2370 CONSISTENCY_CHECK(theBody == bmtMetaData->rgMethodImplTokens[i].methodBody);
2373 // Now that the tokens of Decl and Body are obtained, do the MD validation
2376 rid = RidFromToken(theDecl);
2378 // Perform initial rudimentary validation of the token. Full token verification
2379 // will be done in TestMethodImpl when placing the methodImpls.
2380 if (TypeFromToken(theDecl) == mdtMethodDef)
2382 // Decl must be valid token
2383 if ((rid == 0) || (rid > maxRidMD))
2385 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL);
2387 // Get signature and length
2388 if (FAILED(pMDInternalImport->GetSigOfMethodDef(theDecl, &cbSigDecl, &pSigDecl)))
2390 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2394 // The token is not a MethodDef (likely a MemberRef)
2397 // Decl must be valid token
2398 if ((TypeFromToken(theDecl) != mdtMemberRef) || (rid == 0) || (rid > maxRidMR))
2400 bmtError->resIDWhy = IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL;
2401 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL);
2404 // Get signature and length
2406 if (FAILED(pMDInternalImport->GetNameAndSigOfMemberRef(theDecl, &pSigDecl, &cbSigDecl, &szDeclName)))
2408 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2412 hr = pMDInternalImport->GetParentToken(theDecl,&tkParent);
2414 BuildMethodTableThrowException(hr, *bmtError);
2416 theDeclSubst = Substitution(tkParent, GetModule(), NULL);
2419 // Perform initial rudimentary validation of the token. Full token verification
2420 // will be done in TestMethodImpl when placing the methodImpls.
2422 // Body must be valid token
2423 rid = RidFromToken(theBody);
2424 if ((rid == 0)||(rid > maxRidMD))
2426 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_BODY);
2428 // Body's parent must be this class
2429 hr = pMDInternalImport->GetParentToken(theBody,&tkParent);
2431 BuildMethodTableThrowException(hr, *bmtError);
2432 if(tkParent != GetCl())
2434 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_BODY);
2437 // Decl's and Body's signatures must match
2438 if(pSigDecl && cbSigDecl)
2440 if (FAILED(pMDInternalImport->GetSigOfMethodDef(theBody, &cbSigBody, &pSigBody)) ||
2441 (pSigBody == NULL) ||
2444 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_BODY);
2447 // Can't use memcmp because there may be two AssemblyRefs
2448 // in this scope, pointing to the same assembly, etc.).
2449 BOOL compatibleSignatures = MetaSig::CompareMethodSigs(pSigDecl, cbSigDecl, GetModule(), &theDeclSubst, pSigBody, cbSigBody, GetModule(), NULL, FALSE);
2451 if (!compatibleSignatures && IsEligibleForCovariantReturns(theDecl))
2453 if (MetaSig::CompareMethodSigs(pSigDecl, cbSigDecl, GetModule(), &theDeclSubst, pSigBody, cbSigBody, GetModule(), NULL, TRUE))
2455 // Signatures matched, except for the return type. Flag that MethodImpl to check the return type at a later
2456 // stage for compatibility, and treat it as compatible for now.
2457 // For compatibility rules, see ECMA I.8.7.1. We will use the MethodTable::CanCastTo() at a later stage to validate
2458 // compatibilities of the return types according to these rules.
2460 compatibleSignatures = TRUE;
2461 bmtMetaData->rgMethodImplTokens[i].fRequiresCovariantReturnTypeChecking = true;
2462 bmtMetaData->fHasCovariantOverride = true;
2466 if (!compatibleSignatures)
2468 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH);
2473 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_DECL);
2476 bmtMetaData->pMethodDeclSubsts[i] = theDeclSubst;
2479 } // MethodTableBuilder::EnumerateMethodImpls
2481 //*******************************************************************************
2483 // Find a method declaration that must reside in the scope passed in. This method cannot be called if
2484 // the reference travels to another scope.
2486 // Protect against finding a declaration that lives within
2487 // us (the type being created)
2489 HRESULT MethodTableBuilder::FindMethodDeclarationForMethodImpl(
2490 mdToken pToken, // Token that is being located (MemberRef or MemberDef)
2491 mdToken* pDeclaration, // [OUT] Method definition for Member
2492 BOOL fSameClass) // Does the declaration need to be in this class
2494 STANDARD_VM_CONTRACT;
2498 IMDInternalImport *pMDInternalImport = GetMDImport();
2500 PCCOR_SIGNATURE pSig; // Signature of Member
2502 LPCUTF8 szMember = NULL;
2504 // The token should be a member ref or def. If it is a ref then we need to travel
2505 // back to us hopefully.
2506 if(TypeFromToken(pToken) == mdtMemberRef)
2510 if (FAILED(pMDInternalImport->GetParentOfMemberRef(pToken, &typeref)))
2512 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid MemberRef record");
2513 IfFailRet(COR_E_TYPELOAD);
2516 if (TypeFromToken(typeref) == mdtMethodDef)
2517 { // If parent is a method def then this is a varags method
2519 IfFailRet(pMDInternalImport->GetParentToken(typeref, &typeDef));
2521 if (TypeFromToken(typeDef) != mdtTypeDef)
2522 { // A mdtMethodDef must be parented by a mdtTypeDef
2523 BAD_FORMAT_NOTHROW_ASSERT(!"MethodDef without TypeDef as Parent");
2524 IfFailRet(COR_E_TYPELOAD);
2527 BAD_FORMAT_NOTHROW_ASSERT(typeDef == GetCl());
2529 // This is the real method we are overriding
2530 *pDeclaration = typeref;
2532 else if (TypeFromToken(typeref) == mdtTypeSpec)
2533 { // Added so that method impls can refer to instantiated interfaces or classes
2534 if (FAILED(pMDInternalImport->GetSigFromToken(typeref, &cSig, &pSig)))
2536 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid TypeSpec record");
2537 IfFailRet(COR_E_TYPELOAD);
2539 CorElementType elemType = (CorElementType) *pSig++;
2541 if (elemType == ELEMENT_TYPE_GENERICINST)
2542 { // If this is a generic inst, we expect that the next elem is ELEMENT_TYPE_CLASS,
2543 // which is handled in the case below.
2544 elemType = (CorElementType) *pSig++;
2545 BAD_FORMAT_NOTHROW_ASSERT(elemType == ELEMENT_TYPE_CLASS);
2548 if (elemType == ELEMENT_TYPE_CLASS)
2549 { // This covers E_T_GENERICINST and E_T_CLASS typespec formats. We don't expect
2550 // any other kinds to come through here.
2551 CorSigUncompressToken(pSig, &typeref);
2554 { // This is an unrecognized signature format.
2555 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2556 IDS_CLASSLOAD_MI_BAD_SIG,
2562 { // Verify that the ref points back to us
2563 mdToken tkDef = mdTokenNil;
2565 if (TypeFromToken(typeref) == mdtTypeRef)
2566 { // We only get here when we know the token does not reference a type in a different scope.
2567 LPCUTF8 pszNameSpace;
2568 LPCUTF8 pszClassName;
2570 if (FAILED(pMDInternalImport->GetNameOfTypeRef(typeref, &pszNameSpace, &pszClassName)))
2572 IfFailRet(COR_E_TYPELOAD);
2575 if (FAILED(pMDInternalImport->GetResolutionScopeOfTypeRef(typeref, &tkRes)))
2577 IfFailRet(COR_E_TYPELOAD);
2579 hr = pMDInternalImport->FindTypeDef(pszNameSpace,
2581 (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil,
2585 IfFailRet(COR_E_TYPELOAD);
2588 else if (TypeFromToken(typeref) == mdtTypeDef)
2589 { // We get a typedef when the parent of the token is a typespec to the type.
2594 CONSISTENCY_CHECK_MSGF(FALSE, ("Invalid methodimpl signature in class %s.", GetDebugClassName()));
2595 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2596 IDS_CLASSLOAD_MI_BAD_SIG,
2600 if (fSameClass && tkDef != GetCl())
2601 { // If we required that the typedef be the same type as the current class,
2602 // and it doesn't match, we need to return a failure result.
2603 IfFailRet(COR_E_TYPELOAD);
2606 IfFailRet(pMDInternalImport->GetNameAndSigOfMemberRef(pToken, &pSig, &cSig, &szMember));
2609 MetaSig::GetCallingConvention(Signature(pSig, cSig)),
2610 IMAGE_CEE_CS_CALLCONV_FIELD))
2612 return VLDTR_E_MR_BADCALLINGCONV;
2615 hr = pMDInternalImport->FindMethodDef(
2616 tkDef, szMember, pSig, cSig, pDeclaration);
2621 else if (TypeFromToken(pToken) == mdtMethodDef)
2625 // Verify that we are the parent
2626 hr = pMDInternalImport->GetParentToken(pToken, &typeDef);
2629 if(typeDef != GetCl())
2631 IfFailRet(COR_E_TYPELOAD);
2634 *pDeclaration = pToken;
2638 IfFailRet(COR_E_TYPELOAD);
2644 #pragma warning(push)
2645 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
2647 //---------------------------------------------------------------------------------------
2649 // Used by BuildMethodTable
2651 // Enumerate this class's members
2654 MethodTableBuilder::EnumerateClassMethods()
2659 PRECONDITION(CheckPointer(bmtInternal));
2660 PRECONDITION(CheckPointer(bmtEnumFields));
2661 PRECONDITION(CheckPointer(bmtMFDescs));
2662 PRECONDITION(CheckPointer(bmtProp));
2663 PRECONDITION(CheckPointer(bmtMetaData));
2664 PRECONDITION(CheckPointer(bmtVT));
2665 PRECONDITION(CheckPointer(bmtError));
2671 IMDInternalImport *pMDInternalImport = GetMDImport();
2673 DWORD dwMemberAttrs;
2674 BOOL fIsClassEnum = IsEnum();
2675 BOOL fIsClassInterface = IsInterface();
2676 BOOL fIsClassValueType = IsValueClass();
2677 BOOL fIsClassComImport = IsComImport();
2678 BOOL fIsClassNotAbstract = (IsTdAbstract(GetAttrClass()) == 0);
2679 PCCOR_SIGNATURE pMemberSignature = NULL;
2680 ULONG cMemberSignature = 0;
2683 // Run through the method list and calculate the following:
2685 // # "other" methods (i.e. static or private)
2686 // # non-other methods
2689 HENUMInternalHolder hEnumMethod(pMDInternalImport);
2690 hr = hEnumMethod.EnumInitNoThrow(mdtMethodDef, GetCl());
2693 BuildMethodTableThrowException(hr, *bmtError);
2696 // Allocate an array to contain the method tokens as well as information about the methods.
2697 DWORD cMethAndGaps = hEnumMethod.EnumGetCount();
2699 if ((DWORD)MAX_SLOT_INDEX <= cMethAndGaps)
2700 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
2702 bmtMethod->m_cMaxDeclaredMethods = (SLOT_INDEX)cMethAndGaps;
2703 bmtMethod->m_cDeclaredMethods = 0;
2704 bmtMethod->m_rgDeclaredMethods = new (GetStackingAllocator())
2705 bmtMDMethod *[bmtMethod->m_cMaxDeclaredMethods];
2707 enum { SeenCtor = 1, SeenInvoke = 2, SeenBeginInvoke = 4, SeenEndInvoke = 8};
2708 unsigned delegateMethodsSeen = 0;
2710 for (i = 0; i < cMethAndGaps; i++)
2714 MethodClassification type;
2715 METHOD_IMPL_TYPE implType;
2716 LPSTR strMethodName;
2718 pMemberSignature = NULL;
2719 cMemberSignature = 0;
2722 // Go to the next method and retrieve its attributes.
2725 hEnumMethod.EnumNext(&tok);
2726 DWORD rid = RidFromToken(tok);
2727 if ((rid == 0)||(rid > pMDInternalImport->GetCountWithTokenKind(mdtMethodDef)))
2729 BuildMethodTableThrowException(BFA_METHOD_TOKEN_OUT_OF_RANGE);
2731 if (!bmtProp->fNoSanityChecks && FAILED(pMDInternalImport->GetSigOfMethodDef(tok, &cMemberSignature, &pMemberSignature)))
2733 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2735 if (FAILED(pMDInternalImport->GetMethodDefProps(tok, &dwMemberAttrs)))
2737 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2740 #ifdef FEATURE_TYPEEQUIVALENCE
2741 // TypeEquivalent structs must not have non-static methods
2742 if (!IsMdStatic(dwMemberAttrs) && bmtProp->fIsTypeEquivalent && fIsClassValueType)
2744 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTMETHODS);
2748 bool isVtblGap = false;
2749 if (IsMdRTSpecialName(dwMemberAttrs) || IsMdVirtual(dwMemberAttrs) || IsDelegate())
2751 if (FAILED(pMDInternalImport->GetNameOfMethodDef(tok, (LPCSTR *)&strMethodName)))
2753 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2755 if(IsStrLongerThan(strMethodName,MAX_CLASS_NAME))
2757 BuildMethodTableThrowException(BFA_METHOD_NAME_TOO_LONG);
2760 isVtblGap = IsMdRTSpecialName(dwMemberAttrs) && IsVtblGapName(strMethodName);
2764 strMethodName = NULL;
2767 // Signature validation
2768 if (!bmtProp->fNoSanityChecks && !isVtblGap)
2770 hr = validateTokenSig(tok,pMemberSignature,cMemberSignature,dwMemberAttrs,pMDInternalImport);
2773 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2777 bool hasGenericMethodArgsComputed;
2778 bool hasGenericMethodArgs = this->GetModule()->m_pMethodIsGenericMap->IsGeneric(tok, &hasGenericMethodArgsComputed);
2779 if (!hasGenericMethodArgsComputed)
2781 if (pMemberSignature == NULL)
2783 if (FAILED(pMDInternalImport->GetSigOfMethodDef(tok, &cMemberSignature, &pMemberSignature)))
2785 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
2788 SigParser genericArgParser(pMemberSignature, cMemberSignature);
2789 uint32_t ulCallConv;
2790 hr = genericArgParser.GetCallingConvInfo(&ulCallConv);
2793 BuildMethodTableThrowException(hr, *bmtError);
2796 // Only read the generic parameter table if the method signature is generic
2797 hasGenericMethodArgs = !!(ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC);
2798 hasGenericMethodArgsComputed = true;
2801 if (hasGenericMethodArgs && !bmtProp->fNoSanityChecks)
2803 HENUMInternalHolder hEnumTyPars(pMDInternalImport);
2804 hr = hEnumTyPars.EnumInitNoThrow(mdtGenericParam, tok);
2807 BuildMethodTableThrowException(hr, *bmtError);
2810 uint32_t numGenericMethodArgs = hEnumTyPars.EnumGetCount();
2811 if (numGenericMethodArgs != 0)
2813 HENUMInternalHolder hEnumGenericPars(pMDInternalImport);
2815 hEnumGenericPars.EnumInit(mdtGenericParam, tok);
2817 for (unsigned methIdx = 0; methIdx < numGenericMethodArgs; methIdx++)
2819 mdGenericParam tkTyPar;
2820 pMDInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
2822 if (FAILED(pMDInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
2824 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2827 if (0 != (flags & ~(gpVarianceMask | gpSpecialConstraintMask)))
2829 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2831 switch (flags & gpVarianceMask)
2836 case gpCovariant: // intentional fallthru
2837 case gpContravariant:
2838 BuildMethodTableThrowException(VLDTR_E_GP_ILLEGAL_VARIANT_MVAR);
2842 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2849 // We need to check if there are any gaps in the vtable. These are
2850 // represented by methods with the mdSpecial flag and a name of the form
2851 // _VTblGap_nnn (to represent nnn empty slots) or _VTblGap (to represent a
2852 // single empty slot).
2858 // This slot doesn't really exist, don't add it to the method
2859 // table. Instead it represents one or more empty slots, encoded
2860 // in the method name. Locate the beginning of the count in the
2861 // name. There are these points to consider:
2862 // There may be no count present at all (in which case the
2863 // count is taken as one).
2864 // There may be an additional count just after Gap but before
2865 // the '_'. We ignore this.
2868 LPCSTR pos = strMethodName + COR_VTABLEGAP_NAME_LENGTH;
2870 // Skip optional number.
2871 while (IS_DIGIT(*pos))
2876 // Check for presence of count.
2885 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2886 IDS_CLASSLOAD_BADSPECIALMETHOD,
2894 bool fReadAtLeastOneDigit = false;
2895 while (IS_DIGIT(*pos))
2899 n += DIGIT_TO_INT(*pos);
2901 fReadAtLeastOneDigit = true;
2904 // Check for end of name.
2905 if (*pos != '\0' || !fReadAtLeastOneDigit)
2907 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2908 IDS_CLASSLOAD_BADSPECIALMETHOD,
2913 #ifdef FEATURE_COMINTEROP
2914 // Record vtable gap in mapping list. The map is an optional field, so ensure we've allocated
2915 // these fields first.
2916 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
2917 if (GetHalfBakedClass()->GetSparseCOMInteropVTableMap() == NULL)
2918 GetHalfBakedClass()->SetSparseCOMInteropVTableMap(new SparseVTableMap());
2920 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->RecordGap((WORD)NumDeclaredMethods(), n);
2922 bmtProp->fSparse = true;
2923 #endif // FEATURE_COMINTEROP
2928 // This is a real method so add it to the enumeration of methods. We now need to retrieve
2929 // information on the method and store it for later use.
2931 if (FAILED(pMDInternalImport->GetMethodImplProps(tok, &dwMethodRVA, &dwImplFlags)))
2933 BuildMethodTableThrowException(
2934 COR_E_BADIMAGEFORMAT,
2935 IDS_CLASSLOAD_BADSPECIALMETHOD,
2939 // Check for the presence of virtual static methods
2940 bool isStaticVirtual = (IsMdVirtual(dwMemberAttrs) && IsMdStatic(dwMemberAttrs));
2941 if (isStaticVirtual)
2943 bmtProp->fHasVirtualStaticMethods = TRUE;
2947 // But first - minimal flags validity checks
2949 // No methods in Enums!
2950 #ifndef _DEBUG // Don't run the minimal validity checks for the system dll/r2r dlls (except in debug builds so we don't build a bad system dll)
2951 if (!bmtProp->fNoSanityChecks)
2956 BuildMethodTableThrowException(BFA_METHOD_IN_A_ENUM);
2959 if (dwMethodRVA != 0)
2961 if(fIsClassComImport)
2963 BuildMethodTableThrowException(BFA_METHOD_WITH_NONZERO_RVA);
2965 if(IsMdAbstract(dwMemberAttrs))
2967 BuildMethodTableThrowException(BFA_ABSTRACT_METHOD_WITH_RVA);
2969 if(IsMiRuntime(dwImplFlags))
2971 BuildMethodTableThrowException(BFA_RUNTIME_METHOD_WITH_RVA);
2973 if(IsMiInternalCall(dwImplFlags))
2975 BuildMethodTableThrowException(BFA_INTERNAL_METHOD_WITH_RVA);
2979 // Abstract / not abstract
2980 if(IsMdAbstract(dwMemberAttrs))
2982 if(fIsClassNotAbstract)
2984 BuildMethodTableThrowException(BFA_AB_METHOD_IN_AB_CLASS);
2986 if(!IsMdVirtual(dwMemberAttrs) && !IsMdStatic(dwMemberAttrs))
2988 BuildMethodTableThrowException(BFA_NONVIRT_AB_METHOD);
2991 else if(fIsClassInterface)
2993 if (IsMdRTSpecialName(dwMemberAttrs))
2995 CONSISTENCY_CHECK(CheckPointer(strMethodName));
2996 if (strcmp(strMethodName, COR_CCTOR_METHOD_NAME))
2998 BuildMethodTableThrowException(BFA_NONAB_NONCCTOR_METHOD_ON_INT);
3003 // Virtual / not virtual
3004 if(IsMdVirtual(dwMemberAttrs))
3006 if(IsMdPinvokeImpl(dwMemberAttrs))
3008 BuildMethodTableThrowException(BFA_VIRTUAL_PINVOKE_METHOD);
3010 if(IsMdStatic(dwMemberAttrs))
3012 if (!fIsClassInterface)
3014 // Static virtual methods are only allowed to exist in interfaces
3015 BuildMethodTableThrowException(BFA_VIRTUAL_STATIC_METHOD);
3018 if(strMethodName && (0==strcmp(strMethodName, COR_CTOR_METHOD_NAME)))
3020 BuildMethodTableThrowException(BFA_VIRTUAL_INSTANCE_CTOR);
3024 // Some interface checks.
3025 // We only need them if default interface method support is disabled or if this is fragile crossgen
3026 #if !defined(FEATURE_DEFAULT_INTERFACES)
3027 if (fIsClassInterface)
3029 if (IsMdVirtual(dwMemberAttrs))
3031 if (!IsMdAbstract(dwMemberAttrs))
3033 BuildMethodTableThrowException(BFA_VIRTUAL_NONAB_INT_METHOD);
3039 if (!IsMdStatic(dwMemberAttrs))
3041 BuildMethodTableThrowException(BFA_NONVIRT_INST_INT_METHOD);
3045 #endif // !defined(FEATURE_DEFAULT_INTERFACES)
3047 // No synchronized methods in ValueTypes
3048 if(fIsClassValueType && IsMiSynchronized(dwImplFlags))
3050 BuildMethodTableThrowException(BFA_SYNC_METHOD_IN_VT);
3056 if(!IsMdStatic(dwMemberAttrs))
3058 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_METHOD);
3060 if (strMethodName) //<TODO>@todo: investigate mc++ generating null name</TODO>
3062 if(0==strcmp(strMethodName, COR_CTOR_METHOD_NAME))
3064 BuildMethodTableThrowException(BFA_GLOBAL_INST_CTOR);
3069 // Generic methods or methods in generic classes
3070 // may not be part of a COM Import class, PInvoke, internal call outside CoreLib.
3071 if ((bmtGenerics->GetNumGenericArgs() != 0 || hasGenericMethodArgs) &&
3073 #ifdef FEATURE_COMINTEROP
3074 fIsClassComImport ||
3075 bmtProp->fComEventItfType ||
3076 #endif // FEATURE_COMINTEROP
3077 IsMdPinvokeImpl(dwMemberAttrs) ||
3078 (IsMiInternalCall(dwImplFlags) && !GetModule()->IsSystem())))
3080 BuildMethodTableThrowException(BFA_BAD_PLACE_FOR_GENERIC_METHOD);
3083 // Generic methods may not be marked "runtime". However note that
3084 // methods in generic delegate classes are, hence we don't apply this to
3085 // methods in generic classes in general.
3086 if (hasGenericMethodArgs && IsMiRuntime(dwImplFlags))
3088 BuildMethodTableThrowException(BFA_GENERIC_METHOD_RUNTIME_IMPL);
3091 // Check the appearance of covariant and contravariant in the method signature
3092 // Note that variance is only supported for interfaces, and these rules are not
3093 // checked for non-virtual static methods as they cannot be called variantly.
3094 if ((bmtGenerics->pVarianceInfo != NULL) && (IsMdVirtual(dwMemberAttrs) || !IsMdStatic(dwMemberAttrs)))
3096 if (pMemberSignature == NULL)
3098 if (FAILED(pMDInternalImport->GetSigOfMethodDef(tok, &cMemberSignature, &pMemberSignature)))
3100 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
3104 SigPointer sp(pMemberSignature, cMemberSignature);
3106 IfFailThrow(sp.GetCallingConvInfo(&callConv));
3108 if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
3109 IfFailThrow(sp.GetData(NULL));
3112 IfFailThrow(sp.GetData(&numArgs));
3114 // Return type behaves covariantly
3115 if (!EEClass::CheckVarianceInSig(
3116 bmtGenerics->GetNumGenericArgs(),
3117 bmtGenerics->pVarianceInfo,
3122 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_RESULT, tok);
3124 IfFailThrow(sp.SkipExactlyOne());
3125 for (uint32_t j = 0; j < numArgs; j++)
3127 // Argument types behave contravariantly
3128 if (!EEClass::CheckVarianceInSig(bmtGenerics->GetNumGenericArgs(),
3129 bmtGenerics->pVarianceInfo,
3134 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_ARG, tok);
3136 IfFailThrow(sp.SkipExactlyOne());
3142 // Determine the method's type
3145 if (IsReallyMdPinvokeImpl(dwMemberAttrs) || IsMiInternalCall(dwImplFlags))
3147 hr = NDirect::HasNAT_LAttribute(pMDInternalImport, tok, dwMemberAttrs);
3149 // There was a problem querying for the attribute
3152 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_BADPINVOKE, tok);
3155 // The attribute is not present
3158 #ifdef FEATURE_COMINTEROP
3159 if (fIsClassComImport || bmtProp->fComEventItfType)
3161 // ComImport classes have methods which are just used
3162 // for implementing all interfaces the class supports
3163 type = mcComInterop;
3165 // constructor is special
3166 if (IsMdRTSpecialName(dwMemberAttrs))
3168 // Note: Method name (.ctor) will be checked in code:ValidateMethods
3173 #endif //FEATURE_COMINTEROP
3174 if (dwMethodRVA == 0)
3183 // The NAT_L attribute is present, marking this method as NDirect
3186 CONSISTENCY_CHECK(hr == S_OK);
3190 else if (IsMiRuntime(dwImplFlags))
3192 // currently the only runtime implemented functions are delegate instance methods
3193 if (!IsDelegate() || IsMdStatic(dwMemberAttrs) || IsMdAbstract(dwMemberAttrs))
3195 BuildMethodTableThrowException(BFA_BAD_RUNTIME_IMPL);
3198 unsigned newDelegateMethodSeen = 0;
3200 if (IsMdRTSpecialName(dwMemberAttrs)) // .ctor
3202 if (strcmp(strMethodName, COR_CTOR_METHOD_NAME) != 0 || IsMdVirtual(dwMemberAttrs))
3204 BuildMethodTableThrowException(BFA_BAD_FLAGS_ON_DELEGATE);
3206 newDelegateMethodSeen = SeenCtor;
3211 if (strcmp(strMethodName, "Invoke") == 0)
3212 newDelegateMethodSeen = SeenInvoke;
3213 else if (strcmp(strMethodName, "BeginInvoke") == 0)
3214 newDelegateMethodSeen = SeenBeginInvoke;
3215 else if (strcmp(strMethodName, "EndInvoke") == 0)
3216 newDelegateMethodSeen = SeenEndInvoke;
3219 BuildMethodTableThrowException(BFA_UNKNOWN_DELEGATE_METHOD);
3224 // If we get here we have either set newDelegateMethodSeen or we have thrown a BMT exception
3225 _ASSERTE(newDelegateMethodSeen != 0);
3227 if ((delegateMethodsSeen & newDelegateMethodSeen) != 0)
3229 BuildMethodTableThrowException(BFA_DUPLICATE_DELEGATE_METHOD);
3232 delegateMethodsSeen |= newDelegateMethodSeen;
3234 else if (hasGenericMethodArgs)
3236 //We use an instantiated method desc to represent a generic method
3237 type = mcInstantiated;
3239 else if (fIsClassInterface)
3241 #ifdef FEATURE_COMINTEROP
3242 if (IsMdStatic(dwMemberAttrs))
3244 // Static methods in interfaces need nothing special.
3247 else if (bmtGenerics->GetNumGenericArgs() != 0 &&
3248 (bmtGenerics->fSharedByGenericInstantiations))
3250 // Methods in instantiated interfaces need nothing special - they are not visible from COM etc.
3253 else if (bmtProp->fIsMngStandardItf)
3255 // If the interface is a standard managed interface then allocate space for an FCall method desc.
3258 else if (IsMdAbstract(dwMemberAttrs))
3260 // If COM interop is supported then all other interface MDs may be
3261 // accessed via COM interop. mcComInterop MDs have an additional
3262 // pointer-sized field pointing to COM interop data which are
3263 // allocated lazily when/if the MD actually gets used for interop.
3264 type = mcComInterop;
3267 #endif // !FEATURE_COMINTEROP
3277 // Generic methods should always be mcInstantiated
3278 if (hasGenericMethodArgs && (type != mcInstantiated))
3280 BuildMethodTableThrowException(BFA_GENERIC_METHODS_INST);
3283 // Check if the method is a MethodImpl body. All method bodies are defined
3284 // on this type so we can just compare the tok with the body token found
3285 // from the overrides.
3286 implType = METHOD_IMPL_NOT;
3287 for (DWORD impls = 0; impls < bmtMethod->dwNumberMethodImpls; impls++)
3289 if (bmtMetaData->rgMethodImplTokens[impls].methodBody == tok)
3291 implType = METHOD_IMPL;
3296 // For delegates we don't allow any non-runtime implemented bodies
3297 // for any of the four special methods
3298 if (IsDelegate() && !IsMiRuntime(dwImplFlags))
3300 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
3301 (strcmp(strMethodName, "Invoke") == 0) ||
3302 (strcmp(strMethodName, "BeginInvoke") == 0) ||
3303 (strcmp(strMethodName, "EndInvoke") == 0) )
3305 BuildMethodTableThrowException(BFA_ILLEGAL_DELEGATE_METHOD);
3310 // Create a new bmtMDMethod representing this method and add it to the
3311 // declared method list.
3314 bmtMDMethod * pNewMethod = new (GetStackingAllocator()) bmtMDMethod(
3323 bmtMethod->AddDeclaredMethod(pNewMethod);
3326 // Update the count of the various types of methods.
3329 bmtVT->dwMaxVtableSize++;
3331 // Increment the number of non-abstract declared methods
3332 if (!IsMdAbstract(dwMemberAttrs))
3334 bmtMethod->dwNumDeclaredNonAbstractMethods++;
3338 if (bmtMethod->dwNumDeclaredNonAbstractMethods == 0)
3340 GetHalfBakedClass()->SetHasOnlyAbstractMethods();
3343 // Check to see that we have all of the required delegate methods (ECMA 13.6 Delegates)
3346 // Do we have all four special delegate methods
3347 // or just the two special delegate methods
3348 if ((delegateMethodsSeen != (SeenCtor | SeenInvoke | SeenBeginInvoke | SeenEndInvoke)) &&
3349 (delegateMethodsSeen != (SeenCtor | SeenInvoke)) )
3351 BuildMethodTableThrowException(BFA_MISSING_DELEGATE_METHOD);
3355 if (i != cMethAndGaps)
3357 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_METHOD_COUNT, mdTokenNil);
3360 #ifdef FEATURE_COMINTEROP
3362 // If the interface is sparse, we need to finalize the mapping list by
3363 // telling it how many real methods we found.
3366 if (bmtProp->fSparse)
3368 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->FinalizeMapping(NumDeclaredMethods());
3370 #endif // FEATURE_COMINTEROP
3371 } // MethodTableBuilder::EnumerateClassMethods
3373 #pragma warning(pop)
3376 //*******************************************************************************
3378 // Run through the field list and calculate the following:
3380 // # static fields that contain object refs.
3381 // # instance fields
3384 MethodTableBuilder::EnumerateClassFields()
3386 STANDARD_VM_CONTRACT;
3390 IMDInternalImport *pMDInternalImport = GetMDImport();
3392 DWORD dwMemberAttrs;
3394 bmtEnumFields->dwNumStaticFields = 0;
3395 bmtEnumFields->dwNumStaticObjRefFields = 0;
3396 bmtEnumFields->dwNumStaticBoxedFields = 0;
3398 bmtEnumFields->dwNumThreadStaticFields = 0;
3399 bmtEnumFields->dwNumThreadStaticObjRefFields = 0;
3400 bmtEnumFields->dwNumThreadStaticBoxedFields = 0;
3402 bmtEnumFields->dwNumInstanceFields = 0;
3404 HENUMInternalHolder hEnumField(pMDInternalImport);
3405 hr = hEnumField.EnumInitNoThrow(mdtFieldDef, GetCl());
3408 BuildMethodTableThrowException(hr, *bmtError);
3411 bmtMetaData->cFields = hEnumField.EnumGetCount();
3413 // Retrieve the fields and store them in a temp array.
3414 bmtMetaData->pFields = new (GetStackingAllocator()) mdToken[bmtMetaData->cFields];
3415 bmtMetaData->pFieldAttrs = new (GetStackingAllocator()) DWORD[bmtMetaData->cFields];
3417 DWORD dwFieldLiteralInitOnly = fdLiteral | fdInitOnly;
3418 DWORD dwMaxFieldDefRid = pMDInternalImport->GetCountWithTokenKind(mdtFieldDef);
3420 for (i = 0; hEnumField.EnumNext(&tok); i++)
3423 // Retrieve the attributes of the field.
3425 DWORD rid = RidFromToken(tok);
3426 if ((rid == 0)||(rid > dwMaxFieldDefRid))
3428 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, mdTokenNil);
3431 if (FAILED(pMDInternalImport->GetFieldDefProps(tok, &dwMemberAttrs)))
3433 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, tok);
3437 // Store the field and its attributes in the bmtMetaData structure for later use.
3440 bmtMetaData->pFields[i] = tok;
3441 bmtMetaData->pFieldAttrs[i] = dwMemberAttrs;
3443 if((dwMemberAttrs & fdFieldAccessMask)==fdFieldAccessMask)
3445 BuildMethodTableThrowException(BFA_INVALID_FIELD_ACC_FLAGS);
3447 if((dwMemberAttrs & dwFieldLiteralInitOnly)==dwFieldLiteralInitOnly)
3449 BuildMethodTableThrowException(BFA_FIELD_LITERAL_AND_INIT);
3452 // can only have static global fields
3455 if(!IsFdStatic(dwMemberAttrs))
3457 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_FIELD);
3462 // Update the count of the various types of fields.
3465 if (IsFdStatic(dwMemberAttrs))
3467 if (!IsFdLiteral(dwMemberAttrs))
3469 #ifdef FEATURE_TYPEEQUIVALENCE
3470 if (bmtProp->fIsTypeEquivalent)
3472 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3476 bmtEnumFields->dwNumStaticFields++;
3478 // If this static field is thread static, then we need
3479 // to increment bmtEnumFields->dwNumThreadStaticFields
3480 hr = GetCustomAttribute(tok,
3481 WellKnownAttribute::ThreadStatic,
3486 // It's a thread static, so increment the count
3487 bmtEnumFields->dwNumThreadStaticFields++;
3493 #ifdef FEATURE_TYPEEQUIVALENCE
3494 if (!IsFdPublic(dwMemberAttrs) && bmtProp->fIsTypeEquivalent)
3496 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3500 if (!IsFdLiteral(dwMemberAttrs))
3502 bmtEnumFields->dwNumInstanceFields++;
3506 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_INT);
3511 if (i != bmtMetaData->cFields)
3513 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD_COUNT, mdTokenNil);
3516 if(IsEnum() && (bmtEnumFields->dwNumInstanceFields==0))
3518 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_ENUM);
3521 bmtEnumFields->dwNumDeclaredFields = bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields;
3524 //*******************************************************************************
3526 // Used by BuildMethodTable
3528 // Determines the maximum size of the vtable and allocates the temporary storage arrays
3529 // Also copies the parent's vtable into the working vtable.
3531 VOID MethodTableBuilder::AllocateWorkingSlotTables()
3536 PRECONDITION(CheckPointer(this));
3537 PRECONDITION(CheckPointer(bmtAllocator));
3538 PRECONDITION(CheckPointer(bmtMFDescs));
3539 PRECONDITION(CheckPointer(bmtMetaData));
3540 PRECONDITION(CheckPointer(bmtVT));
3541 PRECONDITION(CheckPointer(bmtEnumFields));
3542 PRECONDITION(CheckPointer(bmtInterface));
3543 PRECONDITION(CheckPointer(bmtFP));
3544 PRECONDITION(CheckPointer(bmtParent));
3549 // Allocate a FieldDesc* for each field
3550 bmtMFDescs->ppFieldDescList = new (GetStackingAllocator()) FieldDesc*[bmtMetaData->cFields];
3551 ZeroMemory(bmtMFDescs->ppFieldDescList, bmtMetaData->cFields * sizeof(FieldDesc *));
3553 // Create a temporary function table (we don't know how large the vtable will be until the very end,
3554 // since we don't yet know how many declared methods are overrides vs. newslots).
3557 { // ValueClass virtuals are converted into non-virtual methods and the virtual slots
3558 // become unboxing stubs that forward to these new non-virtual methods. This has the
3559 // side effect of doubling the number of slots introduced by newslot virtuals.
3560 bmtVT->dwMaxVtableSize += NumDeclaredMethods();
3563 _ASSERTE(!HasParent() || (bmtInterface->dwInterfaceMapSize - GetParentMethodTable()->GetNumInterfaces()) >= 0);
3566 { // Add parent vtable size. <TODO> This should actually be the parent's virtual method count. </TODO>
3567 bmtVT->dwMaxVtableSize += bmtParent->pSlotTable->GetSlotCount();
3570 S_SLOT_INDEX cMaxSlots = AsClrSafeInt(bmtVT->dwMaxVtableSize) + AsClrSafeInt(NumDeclaredMethods());
3572 if (cMaxSlots.IsOverflow() || MAX_SLOT_INDEX < cMaxSlots.Value())
3573 cMaxSlots = S_SLOT_INDEX(MAX_SLOT_INDEX);
3575 // Allocate the temporary vtable
3576 bmtVT->pSlotTable = new (GetStackingAllocator())
3577 bmtMethodSlotTable(cMaxSlots.Value(), GetStackingAllocator());
3582 // @<TODO>todo: Figure out the right way to override Equals for value
3585 // This is broken because
3586 // (a) g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool); will return
3587 // the EqualsValue method
3588 // (b) When CoreLib has been preloaded (and thus the munge already done
3589 // ahead of time), we cannot easily find both methods
3590 // to compute EqualsAddr & EqualsSlot
3592 // For now, the Equals method has a runtime check to see if it's
3593 // comparing value types.
3596 // If it is a value type, over ride a few of the base class methods.
3599 static WORD EqualsSlot;
3601 // If we haven't been through here yet, get some stuff from the Object class definition.
3602 if (EqualsSlot == NULL)
3604 // Get the slot of the Equals method.
3605 MethodDesc *pEqualsMD = g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool);
3606 THROW_BAD_FORMAT_MAYBE(pEqualsMD != NULL, 0, this);
3607 EqualsSlot = pEqualsMD->GetSlot();
3609 // Get the address of the EqualsValue method.
3610 MethodDesc *pEqualsValueMD = g_pObjectClass->FindMethod("EqualsValue", &gsig_IM_Obj_RetBool);
3611 THROW_BAD_FORMAT_MAYBE(pEqualsValueMD != NULL, 0, this);
3613 // Patch the EqualsValue method desc in a dangerous way to
3614 // look like the Equals method desc.
3615 pEqualsValueMD->SetSlot(EqualsSlot);
3616 pEqualsValueMD->SetMemberDef(pEqualsMD->GetMemberDef());
3619 // Override the valuetype "Equals" with "EqualsValue".
3620 bmtVT->SetMethodDescForSlot(EqualsSlot, EqualsSlot);
3625 S_UINT32 cEntries = S_UINT32(2) * S_UINT32(NumDeclaredMethods());
3626 if (cEntries.IsOverflow())
3628 ThrowHR(COR_E_OVERFLOW);
3632 //*******************************************************************************
3634 // Used by BuildMethodTable
3636 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
3638 VOID MethodTableBuilder::AllocateFieldDescs()
3643 PRECONDITION(CheckPointer(this));
3644 PRECONDITION(CheckPointer(bmtAllocator));
3645 PRECONDITION(CheckPointer(bmtMFDescs));
3646 PRECONDITION(CheckPointer(bmtMetaData));
3647 PRECONDITION(CheckPointer(bmtVT));
3648 PRECONDITION(CheckPointer(bmtEnumFields));
3649 PRECONDITION(CheckPointer(bmtFP));
3650 PRECONDITION(CheckPointer(bmtParent));
3655 // We'll be counting the # fields of each size as we go along
3656 for (DWORD i = 0; i <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++)
3658 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
3659 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
3660 bmtFP->NumInstanceFieldsOfSize[i] = 0;
3664 // Allocate blocks of MethodDescs and FieldDescs for all declared methods and fields
3666 // In order to avoid allocating a field pointing back to the method
3667 // table in every single method desc, we allocate memory in the
3668 // following manner:
3669 // o Field descs get a single contiguous block.
3670 // o Method descs of different sizes (normal vs NDirect) are
3671 // allocated in different MethodDescChunks.
3672 // o Each method desc chunk starts with a header, and has
3673 // at most MAX_ method descs (if there are more
3674 // method descs of a given size, multiple chunks are allocated).
3675 // This way method descs can use an 8-bit offset field to locate the
3676 // pointer to their method table.
3679 /////////////////////////////////////////////////////////////////
3681 if (NumDeclaredFields() > 0)
3683 GetHalfBakedClass()->SetFieldDescList((FieldDesc *)
3684 AllocateFromHighFrequencyHeap(S_SIZE_T(NumDeclaredFields()) * S_SIZE_T(sizeof(FieldDesc))));
3685 INDEBUG(GetClassLoader()->m_dwDebugFieldDescs += NumDeclaredFields();)
3686 INDEBUG(GetClassLoader()->m_dwFieldDescData += (NumDeclaredFields() * sizeof(FieldDesc));)
3690 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
3691 //*******************************************************************************
3693 // Heuristic to determine if we should have instances of this class 8 byte aligned
3695 BOOL MethodTableBuilder::ShouldAlign8(DWORD dwR8Fields, DWORD dwTotalFields)
3697 LIMITED_METHOD_CONTRACT;
3699 return dwR8Fields*2>dwTotalFields && dwR8Fields>=2;
3703 //*******************************************************************************
3704 BOOL MethodTableBuilder::IsSelfReferencingStaticValueTypeField(mdToken dwByValueClassToken,
3705 bmtInternalInfo* bmtInternal,
3706 const bmtGenericsInfo *bmtGenerics,
3707 PCCOR_SIGNATURE pMemberSignature,
3708 DWORD cMemberSignature)
3710 STANDARD_VM_CONTRACT;
3712 if (dwByValueClassToken != this->GetCl())
3717 if (!bmtGenerics->HasInstantiation())
3722 // The value class is generic. Check that the signature of the field
3723 // is _exactly_ equivalent to VC<!0, !1, !2, ...>. Do this by consing up a fake
3725 DWORD nGenericArgs = bmtGenerics->GetNumGenericArgs();
3726 CONSISTENCY_CHECK(nGenericArgs != 0);
3728 SigBuilder sigBuilder;
3730 sigBuilder.AppendElementType(ELEMENT_TYPE_GENERICINST);
3731 sigBuilder.AppendElementType(ELEMENT_TYPE_VALUETYPE);
3732 sigBuilder.AppendToken(dwByValueClassToken);
3733 sigBuilder.AppendData(nGenericArgs);
3734 for (unsigned int typearg = 0; typearg < nGenericArgs; typearg++)
3736 sigBuilder.AppendElementType(ELEMENT_TYPE_VAR);
3737 sigBuilder.AppendData(typearg);
3741 PCCOR_SIGNATURE pFakeSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cFakeSig);
3743 PCCOR_SIGNATURE pFieldSig = pMemberSignature + 1; // skip the CALLCONV_FIELD
3745 return MetaSig::CompareElementType(pFakeSig, pFieldSig,
3746 pFakeSig + cFakeSig, pMemberSignature + cMemberSignature,
3747 GetModule(), GetModule(),
3752 //*******************************************************************************
3754 // Used pByValueClass cache to mark self-references
3756 static BOOL IsSelfRef(MethodTable * pMT)
3758 return pMT == (MethodTable *)-1;
3761 //*******************************************************************************
3763 // Used by BuildMethodTable
3765 // Go thru all fields and initialize their FieldDescs.
3768 #pragma warning(push)
3769 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3772 VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
3773 const LayoutRawFieldInfo* pLayoutRawFieldInfos,
3774 bmtInternalInfo* bmtInternal,
3775 const bmtGenericsInfo* bmtGenerics,
3776 bmtMetaDataInfo* bmtMetaData,
3777 bmtEnumFieldInfo* bmtEnumFields,
3778 bmtErrorInfo* bmtError,
3779 MethodTable *** pByValueClassCache,
3780 bmtMethAndFieldDescs* bmtMFDescs,
3781 bmtFieldPlacement* bmtFP,
3782 unsigned* totalDeclaredSize)
3787 PRECONDITION(CheckPointer(this));
3788 PRECONDITION(CheckPointer(bmtInternal));
3789 PRECONDITION(CheckPointer(bmtGenerics));
3790 PRECONDITION(CheckPointer(bmtMetaData));
3791 PRECONDITION(CheckPointer(bmtEnumFields));
3792 PRECONDITION(CheckPointer(bmtError));
3793 PRECONDITION(CheckPointer(pByValueClassCache));
3794 PRECONDITION(CheckPointer(bmtMFDescs));
3795 PRECONDITION(CheckPointer(bmtFP));
3796 PRECONDITION(CheckPointer(totalDeclaredSize));
3801 IMDInternalImport * pInternalImport = GetMDImport(); // to avoid multiple dereferencings
3803 //========================================================================
3805 // Go thru all fields and initialize their FieldDescs.
3806 //========================================================================
3808 DWORD dwCurrentDeclaredField = 0;
3809 DWORD dwCurrentStaticField = 0;
3810 DWORD dwCurrentThreadStaticField = 0;
3813 DWORD dwR8Fields = 0; // Number of R8's the class has
3815 #ifdef FEATURE_64BIT_ALIGNMENT
3816 // Track whether any field in this type requires 8-byte alignment
3817 BOOL fFieldRequiresAlign8 = HasParent() ? GetParentMethodTable()->RequiresAlign8() : FALSE;
3819 #if defined(EnC_SUPPORTED)
3820 bool isEnCField = pFieldDescList != NULL && pFieldDescList->IsEnCNew();
3822 bool isEnCField = false;
3823 #endif // EnC_SUPPORTED
3825 for (i = 0; i < bmtMetaData->cFields; i++)
3827 PCCOR_SIGNATURE pMemberSignature;
3828 DWORD cMemberSignature;
3829 DWORD dwMemberAttrs;
3831 dwMemberAttrs = bmtMetaData->pFieldAttrs[i];
3833 BOOL fIsStatic = IsFdStatic(dwMemberAttrs);
3835 // We don't store static final primitive fields in the class layout
3836 if (IsFdLiteral(dwMemberAttrs))
3839 if (!IsFdPublic(dwMemberAttrs))
3840 SetHasNonPublicFields();
3842 IfFailThrow(pInternalImport->GetSigOfFieldDef(bmtMetaData->pFields[i], &cMemberSignature, &pMemberSignature));
3843 // Signature validation
3844 IfFailThrow(validateTokenSig(bmtMetaData->pFields[i],pMemberSignature,cMemberSignature,dwMemberAttrs,pInternalImport));
3847 DWORD dwLog2FieldSize = 0;
3848 BOOL bCurrentFieldIsGCPointer = FALSE;
3849 mdToken dwByValueClassToken = 0;
3850 MethodTable * pByValueClass = NULL;
3851 BOOL fIsByValue = FALSE;
3852 BOOL fIsThreadStatic = FALSE;
3853 BOOL fHasRVA = FALSE;
3855 MetaSig fsig(pMemberSignature,
3858 &bmtGenerics->typeContext,
3860 CorElementType ElementType = fsig.NextArg();
3864 if (!isCallConv(fsig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_FIELD))
3866 IfFailThrow(COR_E_TYPELOAD);
3869 // Determine if a static field is special i.e. RVA based, local to
3870 // a thread or a context
3873 if (IsFdHasFieldRVA(dwMemberAttrs))
3880 hr = GetCustomAttribute(bmtMetaData->pFields[i],
3881 WellKnownAttribute::ThreadStatic,
3886 fIsThreadStatic = TRUE;
3890 if (ElementType == ELEMENT_TYPE_VALUETYPE)
3892 hr = GetCustomAttribute(bmtMetaData->pFields[i],
3893 WellKnownAttribute::FixedAddressValueType,
3898 bmtFP->fHasFixedAddressValueTypes = true;
3903 // Do some sanity checks that we are not mixing context and thread
3904 // relative statics.
3905 if (fHasRVA && fIsThreadStatic)
3907 IfFailThrow(COR_E_TYPELOAD);
3910 if (bmtFP->fHasFixedAddressValueTypes && GetAssembly()->IsCollectible())
3912 BuildMethodTableThrowException(IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR);
3918 // Type to store in FieldDesc - we don't want to have extra case statements for
3919 // ELEMENT_TYPE_STRING, SDARRAY etc., so we convert all object types to CLASS.
3920 // Also, BOOLEAN, CHAR are converted to U1, I2.
3921 CorElementType FieldDescElementType = ElementType;
3923 switch (ElementType)
3925 case ELEMENT_TYPE_I1:
3926 case ELEMENT_TYPE_U1:
3928 dwLog2FieldSize = 0;
3932 case ELEMENT_TYPE_I2:
3933 case ELEMENT_TYPE_U2:
3935 dwLog2FieldSize = 1;
3939 case ELEMENT_TYPE_I4:
3940 case ELEMENT_TYPE_U4:
3941 IN_TARGET_32BIT(case ELEMENT_TYPE_I:)
3942 IN_TARGET_32BIT(case ELEMENT_TYPE_U:)
3943 case ELEMENT_TYPE_R4:
3945 dwLog2FieldSize = 2;
3949 case ELEMENT_TYPE_BOOLEAN:
3951 // FieldDescElementType = ELEMENT_TYPE_U1;
3952 dwLog2FieldSize = 0;
3956 case ELEMENT_TYPE_CHAR:
3958 // FieldDescElementType = ELEMENT_TYPE_U2;
3959 dwLog2FieldSize = 1;
3963 case ELEMENT_TYPE_R8:
3967 // Deliberate fall through...
3971 case ELEMENT_TYPE_I8:
3972 case ELEMENT_TYPE_U8:
3973 IN_TARGET_64BIT(case ELEMENT_TYPE_I:)
3974 IN_TARGET_64BIT(case ELEMENT_TYPE_U:)
3976 #ifdef FEATURE_64BIT_ALIGNMENT
3977 // Record that this field requires alignment for Int64/UInt64.
3979 fFieldRequiresAlign8 = true;
3981 dwLog2FieldSize = 3;
3985 case ELEMENT_TYPE_FNPTR:
3986 case ELEMENT_TYPE_PTR: // ptrs are unmanaged scalars, for layout
3988 dwLog2FieldSize = LOG2_PTRSIZE;
3992 case ELEMENT_TYPE_BYREF:
3994 dwLog2FieldSize = LOG2_PTRSIZE;
3997 // Byref-like types cannot be used for static fields
3998 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREF_OR_BYREFLIKE_STATICFIELD);
4000 if (!bmtFP->fIsByRefLikeType)
4002 // Non-byref-like types cannot contain byref-like instance fields
4003 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREF_OR_BYREFLIKE_INSTANCEFIELD);
4008 case ELEMENT_TYPE_TYPEDBYREF:
4013 // Class type variable (method type variables aren't allowed in fields)
4014 // These only occur in open types used for verification/reflection.
4015 case ELEMENT_TYPE_VAR:
4016 case ELEMENT_TYPE_MVAR:
4017 // deliberate drop through - do fake field layout
4018 case ELEMENT_TYPE_STRING:
4019 case ELEMENT_TYPE_SZARRAY: // single dim, zero
4020 case ELEMENT_TYPE_ARRAY: // all other arrays
4021 case ELEMENT_TYPE_CLASS: // objectrefs
4022 case ELEMENT_TYPE_OBJECT:
4024 dwLog2FieldSize = LOG2_PTRSIZE;
4025 bCurrentFieldIsGCPointer = TRUE;
4026 FieldDescElementType = ELEMENT_TYPE_CLASS;
4030 SetHasFieldsWhichMustBeInited();
4033 { // EnumerateFieldDescs already counted the total number of static vs. instance
4034 // fields, now we're further subdividing the static field count by GC and non-GC.
4035 bmtEnumFields->dwNumStaticObjRefFields++;
4036 if (fIsThreadStatic)
4037 bmtEnumFields->dwNumThreadStaticObjRefFields++;
4042 case ELEMENT_TYPE_VALUETYPE: // a byvalue class field
4044 Module * pTokenModule;
4045 dwByValueClassToken = fsig.GetArgProps().PeekValueTypeTokenClosed(GetModule(), &bmtGenerics->typeContext, &pTokenModule);
4048 BAD_FORMAT_NOTHROW_ASSERT(dwByValueClassToken != 0);
4050 if (this->IsValueClass() && (pTokenModule == GetModule()))
4052 if (TypeFromToken(dwByValueClassToken) == mdtTypeRef)
4054 // It's a typeref - check if it's a class that has a static field of itself
4055 LPCUTF8 pszNameSpace;
4056 LPCUTF8 pszClassName;
4057 if (FAILED(pInternalImport->GetNameOfTypeRef(dwByValueClassToken, &pszNameSpace, &pszClassName)))
4059 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4062 if (IsStrLongerThan((char *)pszClassName, MAX_CLASS_NAME)
4063 || IsStrLongerThan((char *)pszNameSpace, MAX_CLASS_NAME)
4064 || (strlen(pszClassName) + strlen(pszNameSpace) + 1 >= MAX_CLASS_NAME))
4066 BuildMethodTableThrowException(BFA_TYPEREG_NAME_TOO_LONG, mdMethodDefNil);
4070 if (FAILED(pInternalImport->GetResolutionScopeOfTypeRef(dwByValueClassToken, &tkRes)))
4072 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, dwByValueClassToken);
4075 if (TypeFromToken(tkRes) == mdtTypeRef)
4077 if (!pInternalImport->IsValidToken(tkRes))
4079 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, mdMethodDefNil);
4087 if (FAILED(pInternalImport->FindTypeDef(pszNameSpace,
4090 &dwByValueClassToken)))
4092 dwByValueClassToken = mdTokenNil;
4094 } // If field is static typeref
4096 BOOL selfref = IsSelfReferencingStaticValueTypeField(dwByValueClassToken,
4103 { // immediately self-referential fields must be static.
4106 BuildMethodTableThrowException(IDS_CLASSLOAD_VALUEINSTANCEFIELD, mdMethodDefNil);
4109 if (!IsValueClass())
4111 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_MUST_BE_BYVAL, mdTokenNil);
4114 pByValueClass = (MethodTable *)-1;
4116 } // If 'this' is a value class
4118 // TypedReference shares the rest of the code here
4123 // It's not self-referential so try to load it
4124 if (pByValueClass == NULL)
4126 // Loading a non-self-ref valuetype field.
4127 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
4128 if (isEnCField || fIsStatic)
4130 // EnCFieldDescs are not created at normal MethodTableBuilder time, and don't need to avoid recursive generic instantiation
4131 pByValueClass = fsig.GetArgProps().GetTypeHandleThrowing(GetModule(),
4132 &bmtGenerics->typeContext,
4133 ClassLoader::LoadTypes,
4134 CLASS_LOAD_APPROXPARENTS,
4140 // We load the approximate type of the field to avoid recursion problems.
4141 // MethodTable::DoFullyLoad() will later load it fully
4142 SigPointer::HandleRecursiveGenericsForFieldLayoutLoad recursiveControl;
4143 recursiveControl.pModuleWithTokenToAvoidIfPossible = GetModule();
4144 recursiveControl.tkTypeDefToAvoidIfPossible = GetCl();
4145 pByValueClass = fsig.GetArgProps().GetTypeHandleThrowing(GetModule(),
4146 &bmtGenerics->typeContext,
4147 ClassLoader::LoadTypes,
4148 CLASS_LOAD_APPROXPARENTS,
4149 TRUE, NULL, NULL, NULL,
4150 &recursiveControl).GetMethodTable();
4154 // #FieldDescTypeMorph IF it is an enum, strip it down to its underlying type
4155 if (IsSelfRef(pByValueClass) ? IsEnum() : pByValueClass->IsEnum())
4157 if (IsSelfRef(pByValueClass))
4158 { // It is self-referencing enum (ValueType) static field - it is forbidden in the ECMA spec, but supported by CLR since v1
4159 // Note: literal static fields are skipped early in this loop
4160 if (bmtMFDescs->ppFieldDescList[0] == NULL)
4161 { // The field is defined before (the only) instance field
4162 // AppCompat with 3.5 SP1 and 4.0 RTM behavior
4163 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4165 // 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
4166 // later in this method)
4167 // Therefore we do not have to run code:VerifySelfReferencingStaticValueTypeFields_WithRVA or code:#SelfReferencingStaticValueTypeField_Checks
4169 BAD_FORMAT_NOTHROW_ASSERT((IsSelfRef(pByValueClass) ?
4170 bmtEnumFields->dwNumInstanceFields : pByValueClass->GetNumInstanceFields())
4171 == 1); // enums must have exactly one field
4172 FieldDesc * enumField = IsSelfRef(pByValueClass) ?
4173 bmtMFDescs->ppFieldDescList[0] : pByValueClass->GetApproxFieldDescListRaw();
4174 BAD_FORMAT_NOTHROW_ASSERT(!enumField->IsStatic()); // no real static fields on enums
4175 ElementType = enumField->GetFieldType();
4176 BAD_FORMAT_NOTHROW_ASSERT(ElementType != ELEMENT_TYPE_VALUETYPE);
4177 fIsByValue = FALSE; // we're going to treat it as the underlying type now
4178 goto GOT_ELEMENT_TYPE;
4181 // Check ByRefLike fields
4182 if (!IsSelfRef(pByValueClass) && pByValueClass->IsByRefLike())
4186 // Byref-like types cannot be used for static fields
4187 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREF_OR_BYREFLIKE_STATICFIELD);
4189 if (!bmtFP->fIsByRefLikeType)
4191 // Non-byref-like types cannot contain byref-like instance fields
4192 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREF_OR_BYREFLIKE_INSTANCEFIELD);
4196 if (!IsSelfRef(pByValueClass) && pByValueClass->GetClass()->HasNonPublicFields())
4197 { // If a class has a field of type ValueType with non-public fields in it,
4198 // the class must "inherit" this characteristic
4199 SetHasNonPublicFields();
4206 // Inherit instance attributes
4207 EEClass * pFieldClass = pByValueClass->GetClass();
4209 #ifdef FEATURE_64BIT_ALIGNMENT
4210 // If a value type requires 8-byte alignment this requirement must be inherited by any
4211 // class/struct that embeds it as a field.
4212 if (pFieldClass->IsAlign8Candidate())
4213 fFieldRequiresAlign8 = true;
4215 if (pFieldClass->HasNonPublicFields())
4216 SetHasNonPublicFields();
4217 if (pFieldClass->HasFieldsWhichMustBeInited())
4218 SetHasFieldsWhichMustBeInited();
4220 #ifdef FEATURE_READYTORUN
4221 if (!(pByValueClass->IsTruePrimitive() || pByValueClass->IsEnum()))
4223 CheckLayoutDependsOnOtherModules(pByValueClass);
4228 { // Increment the number of static fields that contain object references.
4229 bmtEnumFields->dwNumStaticBoxedFields++;
4230 if (fIsThreadStatic)
4231 bmtEnumFields->dwNumThreadStaticBoxedFields++;
4235 if (*pByValueClassCache == NULL)
4237 DWORD dwNumFields = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields;
4239 *pByValueClassCache = new (GetStackingAllocator()) MethodTable * [dwNumFields];
4240 memset (*pByValueClassCache, 0, dwNumFields * sizeof(MethodTable **));
4243 // Thread static fields come after instance fields and regular static fields in this list
4244 if (fIsThreadStatic)
4246 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField] = pByValueClass;
4247 // make sure to record the correct size for static field
4249 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4251 // Regular static fields come after instance fields in this list
4254 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField] = pByValueClass;
4255 // make sure to record the correct size for static field
4257 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4261 (*pByValueClassCache)[dwCurrentDeclaredField] = pByValueClass;
4262 dwLog2FieldSize = 0; // unused
4269 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4275 pFD = &pFieldDescList[dwCurrentDeclaredField]; // lgtm [cpp/upcast-array-pointer-arithmetic] - The call of concern in FixupFieldDescForEnC, initializes this loop invariant to 1, so will never be > 1.
4276 *totalDeclaredSize += (1 << dwLog2FieldSize);
4278 else /* (dwMemberAttrs & mdStatic) */
4280 if (fIsThreadStatic)
4282 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField]; // lgtm [cpp/upcast-array-pointer-arithmetic] - The call of concern in FixupFieldDescForEnC, initializes this loop invariant to 1, so will never be > 1.
4286 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField]; // lgtm [cpp/upcast-array-pointer-arithmetic] - The call of concern in FixupFieldDescForEnC, initializes this loop invariant to 1, so will never be > 1.
4290 bmtMFDescs->ppFieldDescList[i] = pFD;
4292 const LayoutRawFieldInfo *pLayoutFieldInfo = NULL;
4296 const LayoutRawFieldInfo *pwalk = pLayoutRawFieldInfos;
4297 while (pwalk->m_MD != mdFieldDefNil)
4299 if (pwalk->m_MD == bmtMetaData->pFields[i])
4301 pLayoutFieldInfo = pwalk;
4308 LPCSTR pszFieldName = NULL;
4310 if (FAILED(pInternalImport->GetNameOfFieldDef(bmtMetaData->pFields[i], &pszFieldName)))
4312 pszFieldName = "Invalid FieldDef record";
4315 // #InitCall Initialize contents of the field descriptor called from
4317 bmtMetaData->pFields[i],
4318 FieldDescElementType,
4326 // We're using FieldDesc::m_pMTOfEnclosingClass to temporarily store the field's size.
4331 (IsBlittable() || HasExplicitFieldOffsetLayout()))
4333 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4334 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4336 if (pLayoutFieldInfo)
4337 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset));
4339 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4341 else if (!fIsStatic && IsManagedSequential())
4343 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4344 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4346 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset));
4350 // static value class fields hold a handle, which is ptr sized
4351 // (instance field layout ignores this value)
4352 (DWORD_PTR&)(pFD->m_pMTOfEnclosingClass) = LOG2_PTRSIZE;
4353 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4358 (DWORD_PTR &)(pFD->m_pMTOfEnclosingClass) = (size_t)dwLog2FieldSize;
4360 // -1 (FIELD_OFFSET_UNPLACED) means that this is a non-GC field that has not yet been placed
4361 // -2 (FIELD_OFFSET_UNPLACED_GC_PTR) means that this is a GC pointer field that has not yet been placed
4363 // If there is any kind of explicit layout information for this field, use it. If not, then
4364 // mark it as either GC or non-GC and as unplaced; it will get placed later on in an optimized way.
4366 if ((IsBlittable() || HasExplicitFieldOffsetLayout()) && !fIsStatic)
4367 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset));
4368 else if (IsManagedSequential() && !fIsStatic)
4369 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset));
4370 else if (bCurrentFieldIsGCPointer)
4371 pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR);
4373 pFD->SetOffset(FIELD_OFFSET_UNPLACED);
4380 if (++bmtFP->NumInstanceFieldsOfSize[dwLog2FieldSize] == 1)
4381 bmtFP->FirstInstanceFieldOfSize[dwLog2FieldSize] = dwCurrentDeclaredField;
4384 dwCurrentDeclaredField++;
4386 if (bCurrentFieldIsGCPointer)
4388 bmtFP->NumInstanceGCPointerFields++;
4391 else /* static fields */
4393 // Static fields are stored in the vtable after the vtable and interface slots. We don't
4394 // know how large the vtable will be, so we will have to fixup the slot number by
4395 // <vtable + interface size> later.
4397 if (fIsThreadStatic)
4399 dwCurrentThreadStaticField++;
4403 dwCurrentStaticField++;
4408 if (FieldDescElementType == ELEMENT_TYPE_CLASS)
4409 { // RVA fields are not allowed to have GC pointers.
4410 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4411 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4413 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4415 if (IsSelfRef(pByValueClass))
4416 { // We will verify self-referencing statics after the loop through all fields - see code:#SelfReferencingStaticValueTypeField_Checks
4417 bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA = TRUE;
4421 if (pByValueClass->GetClass()->HasFieldsWhichMustBeInited())
4422 { // RVA fields are not allowed to have GC pointers.
4423 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4424 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4429 // Set the field offset
4431 IfFailThrow(pInternalImport->GetFieldRVA(pFD->GetMemberDef(), &rva));
4433 // The PE should be loaded by now.
4434 _ASSERT(GetModule()->GetPEAssembly()->IsLoaded());
4437 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4439 if (IsSelfRef(pByValueClass))
4441 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4443 // We do not known the size yet
4444 _ASSERTE(bmtFP->NumInstanceFieldBytes == 0);
4445 // We will check just the RVA with size 0 now, the full size verification will happen in code:VerifySelfReferencingStaticValueTypeFields_WithRVA
4450 fldSize = pByValueClass->GetNumInstanceFieldBytes();
4455 fldSize = GetSizeForCorElementType(FieldDescElementType);
4458 pFD->SetOffsetRVA(rva);
4460 else if (fIsThreadStatic)
4462 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
4464 if (bCurrentFieldIsGCPointer)
4465 bmtFP->NumThreadStaticGCPointerFields++;
4468 bmtFP->NumThreadStaticGCBoxedFields++;
4472 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
4474 if (bCurrentFieldIsGCPointer)
4475 bmtFP->NumRegularStaticGCPointerFields++;
4478 bmtFP->NumRegularStaticGCBoxedFields++;
4482 // We processed all fields
4484 //#SelfReferencingStaticValueTypeField_Checks
4485 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
4486 { // The type has self-referencing static ValueType field with RVA, do more checks now that depend on all fields being processed
4488 // For enums we already checked its underlying type, we should not get here
4489 _ASSERTE(!IsEnum());
4491 if (HasFieldsWhichMustBeInited())
4492 { // RVA fields are not allowed to have GC pointers.
4493 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA self-referencing static field");
4494 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4498 DWORD dwNumInstanceFields = dwCurrentDeclaredField + (HasParent() ? GetParentMethodTable()->GetNumInstanceFields() : 0);
4499 DWORD dwNumStaticFields = bmtEnumFields->dwNumStaticFields;
4500 DWORD dwNumThreadStaticFields = bmtEnumFields->dwNumThreadStaticFields;
4502 if (!FitsIn<WORD>(dwNumInstanceFields) ||
4503 !FitsIn<WORD>(dwNumStaticFields))
4504 { // An implementation limitation means that it's an error if there are greater that MAX_WORD fields.
4505 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
4510 GetHalfBakedClass()->SetNumInstanceFields((WORD)dwNumInstanceFields);
4511 GetHalfBakedClass()->SetNumStaticFields((WORD)dwNumStaticFields);
4512 GetHalfBakedClass()->SetNumThreadStaticFields((WORD)dwNumThreadStaticFields);
4515 if (bmtFP->fHasFixedAddressValueTypes)
4517 // To make things simpler, if the class has any field with this requirement, we'll set
4518 // all the statics to have this property. This allows us to only need to persist one bit
4519 // for the ngen case.
4520 GetHalfBakedClass()->SetHasFixedAddressVTStatics();
4523 #ifdef FEATURE_64BIT_ALIGNMENT
4524 // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8
4525 // bytes (this mimics what the native compiler does and ensures we match up calling conventions during
4527 // We don't do this for types that are marked as sequential but end up with auto-layout due to containing pointers,
4528 // as auto-layout ignores any Pack directives.
4529 if (HasLayout() && (HasExplicitFieldOffsetLayout() || IsManagedSequential()) && GetLayoutInfo()->GetPackingSize() < 8)
4531 fFieldRequiresAlign8 = false;
4534 if (fFieldRequiresAlign8)
4536 SetAlign8Candidate();
4538 #endif // FEATURE_64BIT_ALIGNMENT
4540 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
4541 if (ShouldAlign8(dwR8Fields, dwNumInstanceFields))
4543 SetAlign8Candidate();
4545 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
4548 //========================================================================
4550 // Go thru all fields and initialize their FieldDescs.
4551 //========================================================================
4554 } // MethodTableBuilder::InitializeFieldDescs
4557 #pragma warning(pop)
4560 //*******************************************************************************
4561 // Verify self-referencing static ValueType fields with RVA (when the size of the ValueType is known).
4563 MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA(
4564 MethodTable ** pByValueClassCache)
4566 STANDARD_VM_CONTRACT;
4568 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4569 // Enum's static self-referencing fields have been verified as the underlying type of the enum, we should not get here for them
4570 _ASSERTE(!IsEnum());
4571 // The size of the ValueType should be known at this point (the caller throws if it is 0)
4572 _ASSERTE(bmtFP->NumInstanceFieldBytes != 0);
4574 FieldDesc * pFieldDescList = GetApproxFieldDescListRaw();
4575 DWORD nFirstThreadStaticFieldIndex = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields;
4576 for (DWORD i = bmtEnumFields->dwNumInstanceFields; i < nFirstThreadStaticFieldIndex; i++)
4578 FieldDesc * pFD = &pFieldDescList[i];
4579 _ASSERTE(pFD->IsStatic());
4581 if (pFD->IsRVA() && pFD->IsByValue())
4583 _ASSERTE(pByValueClassCache[i] != NULL);
4585 if (IsSelfRef(pByValueClassCache[i]))
4588 IfFailThrow(GetMDImport()->GetFieldRVA(pFD->GetMemberDef(), &rva));
4592 } // MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA
4594 //*******************************************************************************
4595 // Returns true if hEnclosingTypeCandidate encloses, at any arbitrary depth,
4596 // hNestedTypeCandidate; returns false otherwise.
4598 bool MethodTableBuilder::IsEnclosingNestedTypePair(
4599 bmtTypeHandle hEnclosingTypeCandidate,
4600 bmtTypeHandle hNestedTypeCandidate)
4602 STANDARD_VM_CONTRACT;
4604 CONSISTENCY_CHECK(!hEnclosingTypeCandidate.IsNull());
4605 CONSISTENCY_CHECK(!hNestedTypeCandidate.IsNull());
4606 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hEnclosingTypeCandidate, hNestedTypeCandidate));
4608 Module * pModule = hEnclosingTypeCandidate.GetModule();
4610 if (pModule != hNestedTypeCandidate.GetModule())
4611 { // If the modules aren't the same, then there's no way
4612 // hBase could be an enclosing type of hChild. We make
4613 // this check early so that the code can deal with only
4614 // one Module and IMDInternalImport instance and can avoid
4619 IMDInternalImport * pMDImport = pModule->GetMDImport();
4621 mdTypeDef tkEncl = hEnclosingTypeCandidate.GetTypeDefToken();
4622 mdTypeDef tkNest = hNestedTypeCandidate.GetTypeDefToken();
4624 while (tkEncl != tkNest)
4625 { // Do this using the metadata APIs because MethodTableBuilder does
4626 // not construct type representations for enclosing type chains.
4627 if (FAILED(pModule->m_pEnclosingTypeMap->GetEnclosingTypeNoThrow(tkNest, &tkNest, pMDImport)))
4628 { // tokNest is not a nested type.
4633 // tkNest's enclosing type is tkEncl, so we've shown that
4634 // hEnclosingTypeCandidate encloses hNestedTypeCandidate
4638 //*******************************************************************************
4639 // Given an arbitrary nesting+subclassing pattern like this:
4642 // private virtual void Foo() { ... }
4645 // class CN : CN-1 {
4646 // private override void Foo() { ... }
4652 // this method will return true, where hChild == N and hBase == C1
4654 // Note that there is no requirement that a type derive from its immediately
4655 // enclosing type, but can skip a level, such as this example:
4659 // private virtual void Foo() { }
4662 // public class C : A
4664 // private override void Foo() { }
4669 // NOTE: IMPORTANT: This code assumes that hBase is indeed a base type of hChild,
4670 // and behaviour is undefined if this is not the case.
4672 bool MethodTableBuilder::IsBaseTypeAlsoEnclosingType(
4673 bmtTypeHandle hBase,
4674 bmtTypeHandle hChild)
4676 STANDARD_VM_CONTRACT;
4678 CONSISTENCY_CHECK(!hBase.IsNull());
4679 CONSISTENCY_CHECK(!hChild.IsNull());
4680 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hBase, hChild));
4682 // The idea of this algorithm is that if we climb the inheritance chain
4683 // starting at hChild then we'll eventually hit hBase. If we check that
4684 // for every (hParent, hChild) pair in the chain that hParent encloses
4685 // hChild, then we've shown that hBase encloses hChild.
4687 while (!bmtTypeHandle::Equal(hBase, hChild))
4689 CONSISTENCY_CHECK(!hChild.GetParentType().IsNull());
4690 bmtTypeHandle hParent(hChild.GetParentType());
4692 if (!IsEnclosingNestedTypePair(hParent, hChild))
4693 { // First, the parent type must enclose the child type.
4694 // If this is not the case we fail immediately.
4698 // Move up one in the inheritance chain, and try again.
4702 // If the loop worked itself from the original hChild all the way
4703 // up to hBase, then we know that for every (hParent, hChild)
4704 // pair in the chain that hParent enclosed hChild, and so we know
4705 // that hBase encloses the original hChild
4709 //*******************************************************************************
4710 BOOL MethodTableBuilder::TestOverrideForAccessibility(
4711 bmtMethodHandle hParentMethod,
4712 bmtTypeHandle hChildType)
4714 STANDARD_VM_CONTRACT;
4716 bmtTypeHandle hParentType(hParentMethod.GetOwningType());
4718 Module * pParentModule = hParentType.GetModule();
4719 Module * pChildModule = hChildType.GetModule();
4721 Assembly * pParentAssembly = pParentModule->GetAssembly();
4722 Assembly * pChildAssembly = pChildModule->GetAssembly();
4724 BOOL isSameAssembly = (pChildAssembly == pParentAssembly);
4726 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4728 // AKA "strict bit". This means that overridability is tightly bound to accessibility.
4729 if (IsMdCheckAccessOnOverride(dwParentAttrs))
4732 if (isSameAssembly || pParentAssembly->GrantsFriendAccessTo(pChildAssembly, hParentMethod.GetMethodDesc())
4733 || pChildAssembly->IgnoresAccessChecksTo(pParentAssembly))
4735 // Can always override any method that has accessibility greater than mdPrivate
4736 if ((dwParentAttrs & mdMemberAccessMask) > mdPrivate)
4739 // Generally, types cannot override inherited mdPrivate methods, except:
4740 // Types can access enclosing type's private members, so it can
4741 // override them if the nested type extends its enclosing type.
4742 else if ((dwParentAttrs & mdMemberAccessMask) == mdPrivate &&
4743 IsBaseTypeAlsoEnclosingType(hParentType, hChildType))
4754 // If the method marks itself as check visibility the method must be
4755 // public, FamORAssem, or family
4756 if((dwParentAttrs & mdMemberAccessMask) <= mdAssem)
4765 //*******************************************************************************
4766 VOID MethodTableBuilder::TestOverRide(bmtMethodHandle hParentMethod,
4767 bmtMethodHandle hChildMethod)
4771 PRECONDITION(IsMdVirtual(hParentMethod.GetDeclAttrs()));
4772 PRECONDITION(IsMdVirtual(hChildMethod.GetDeclAttrs()));
4775 DWORD dwAttrs = hChildMethod.GetDeclAttrs();
4776 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4778 Module *pModule = hChildMethod.GetOwningType().GetModule();
4779 Module *pParentModule = hParentMethod.GetOwningType().GetModule();
4781 Assembly *pAssembly = pModule->GetAssembly();
4782 Assembly *pParentAssembly = pParentModule->GetAssembly();
4784 BOOL isSameModule = (pModule == pParentModule);
4785 BOOL isSameAssembly = (pAssembly == pParentAssembly);
4787 if (!TestOverrideForAccessibility(hParentMethod, hChildMethod.GetOwningType()))
4789 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, hChildMethod.GetMethodSignature().GetToken());
4793 // Refer to Partition II, 9.3.3 for more information on what is permitted.
4796 enum WIDENING_STATUS
4800 e_SA, // YES, but only when same assembly
4801 e_NSA, // YES, but only when NOT same assembly
4802 e_SM, // YES, but only when same module
4805 static_assert_no_msg(mdPrivateScope == 0x00);
4806 static_assert_no_msg(mdPrivate == 0x01);
4807 static_assert_no_msg(mdFamANDAssem == 0x02);
4808 static_assert_no_msg(mdAssem == 0x03);
4809 static_assert_no_msg(mdFamily == 0x04);
4810 static_assert_no_msg(mdFamORAssem == 0x05);
4811 static_assert_no_msg(mdPublic == 0x06);
4813 static const DWORD dwCount = mdPublic - mdPrivateScope + 1;
4814 static const WIDENING_STATUS rgWideningTable[dwCount][dwCount] =
4817 // Subtype | mdPrivateScope mdPrivate mdFamANDAssem mdAssem mdFamily mdFamORAssem mdPublic
4818 // --------------+-------------------------------------------------------------------------------------------------------
4819 /*mdPrivateScope | */ { { e_SM, e_NO, e_NO, e_NO, e_NO, e_NO, e_NO },
4820 /*mdPrivate | */ { e_SM, e_YES, e_NO, e_NO, e_NO, e_NO, e_NO },
4821 /*mdFamANDAssem | */ { e_SM, e_YES, e_SA, e_NO, e_NO, e_NO, e_NO },
4822 /*mdAssem | */ { e_SM, e_YES, e_SA, e_SA, e_NO, e_NO, e_NO },
4823 /*mdFamily | */ { e_SM, e_YES, e_YES, e_NO, e_YES, e_NSA, e_NO },
4824 /*mdFamORAssem | */ { e_SM, e_YES, e_YES, e_SA, e_YES, e_YES, e_NO },
4825 /*mdPublic | */ { e_SM, e_YES, e_YES, e_YES, e_YES, e_YES, e_YES } };
4827 DWORD idxParent = (dwParentAttrs & mdMemberAccessMask) - mdPrivateScope;
4828 DWORD idxMember = (dwAttrs & mdMemberAccessMask) - mdPrivateScope;
4829 CONSISTENCY_CHECK(idxParent < dwCount);
4830 CONSISTENCY_CHECK(idxMember < dwCount);
4832 WIDENING_STATUS entry = rgWideningTable[idxMember][idxParent];
4834 if (entry == e_NO ||
4835 (entry == e_SA && !isSameAssembly && !pParentAssembly->GrantsFriendAccessTo(pAssembly, hParentMethod.GetMethodDesc())
4836 && !pAssembly->IgnoresAccessChecksTo(pParentAssembly)) ||
4837 (entry == e_NSA && isSameAssembly) ||
4838 (entry == e_SM && !isSameModule)
4841 BuildMethodTableThrowException(IDS_CLASSLOAD_REDUCEACCESS, hChildMethod.GetMethodSignature().GetToken());
4847 //*******************************************************************************
4848 VOID MethodTableBuilder::TestMethodImpl(
4849 bmtMethodHandle hDeclMethod,
4850 bmtMethodHandle hImplMethod)
4855 PRECONDITION(!hDeclMethod.IsNull());
4856 PRECONDITION(!hImplMethod.IsNull());
4860 Module * pDeclModule = hDeclMethod.GetOwningType().GetModule();
4861 Module * pImplModule = hImplMethod.GetOwningType().GetModule();
4863 mdTypeDef tokDecl = hDeclMethod.GetMethodSignature().GetToken();
4864 mdTypeDef tokImpl = hImplMethod.GetMethodSignature().GetToken();
4866 BOOL isSameModule = pDeclModule->Equals(pImplModule);
4868 IMDInternalImport *pIMDDecl = pDeclModule->GetMDImport();
4869 IMDInternalImport *pIMDImpl = pImplModule->GetMDImport();
4872 if (FAILED(pIMDDecl->GetMethodDefProps(tokDecl, &dwDeclAttrs)))
4874 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4877 if (FAILED(pIMDImpl->GetMethodDefProps(tokImpl, &dwImplAttrs)))
4879 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4882 HRESULT hr = COR_E_TYPELOAD;
4884 if (!IsMdVirtual(dwDeclAttrs))
4886 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NONVIRTUAL_DECL);
4888 if (!!IsMdVirtual(dwImplAttrs) != !!IsMdAbstract(dwImplAttrs) && IsMdStatic(dwImplAttrs))
4890 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL);
4892 if (!IsMdVirtual(dwImplAttrs) && !IsMdStatic(dwImplAttrs))
4894 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL);
4896 // Virtual methods on classes/valuetypes cannot be static
4897 if (IsMdStatic(dwDeclAttrs) && !hDeclMethod.GetOwningType().IsInterface())
4899 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4901 if ((!!IsMdStatic(dwImplAttrs)) != (!!IsMdStatic(dwDeclAttrs)))
4903 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4905 if (IsMdFinal(dwDeclAttrs))
4907 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL);
4910 // Non-static interface method body that has methodimpl should always be final
4911 if (IsInterface() && !IsMdStatic(dwDeclAttrs) && !IsMdFinal(dwImplAttrs))
4913 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_IMPL);
4916 // Since MethodImpl's do not affect the visibility of the Decl method, there's
4917 // no need to check.
4919 // If Decl's parent is other than this class, Decl must not be private
4920 mdTypeDef tkImplParent = mdTypeDefNil;
4921 mdTypeDef tkDeclParent = mdTypeDefNil;
4923 if (FAILED(hr = pIMDDecl->GetParentToken(tokDecl, &tkDeclParent)))
4925 BuildMethodTableThrowException(hr, *bmtError);
4927 if (FAILED(hr = pIMDImpl->GetParentToken(tokImpl, &tkImplParent)))
4929 BuildMethodTableThrowException(hr, *bmtError);
4932 // Make sure that we test for accessibility restrictions only if the decl is
4933 // not within our own type, as we are allowed to methodImpl a private with the
4934 // strict bit set if it is in our own type.
4935 if (!isSameModule || tkDeclParent != tkImplParent)
4937 if (!TestOverrideForAccessibility(hDeclMethod, hImplMethod.GetOwningType()))
4939 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, tokImpl);
4942 // Decl's parent must not be tdSealed
4943 mdToken tkGrandParentDummyVar;
4944 DWORD dwDeclTypeAttrs;
4945 if (FAILED(hr = pIMDDecl->GetTypeDefProps(tkDeclParent, &dwDeclTypeAttrs, &tkGrandParentDummyVar)))
4947 BuildMethodTableThrowException(hr, *bmtError);
4949 if (IsTdSealed(dwDeclTypeAttrs))
4951 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_SEALED_DECL);
4959 //*******************************************************************************
4961 // Used by BuildMethodTable
4964 MethodTableBuilder::ValidateMethods()
4970 PRECONDITION(CheckPointer(this));
4971 PRECONDITION(CheckPointer(bmtInternal));
4972 PRECONDITION(CheckPointer(bmtMetaData));
4973 PRECONDITION(CheckPointer(bmtError));
4974 PRECONDITION(CheckPointer(bmtProp));
4975 PRECONDITION(CheckPointer(bmtInterface));
4976 PRECONDITION(CheckPointer(bmtParent));
4977 PRECONDITION(CheckPointer(bmtMFDescs));
4978 PRECONDITION(CheckPointer(bmtEnumFields));
4979 PRECONDITION(CheckPointer(bmtMethodImpl));
4980 PRECONDITION(CheckPointer(bmtVT));
4984 // Used to keep track of located default and type constructors.
4985 CONSISTENCY_CHECK(bmtVT->pCCtor == NULL);
4986 CONSISTENCY_CHECK(bmtVT->pDefaultCtor == NULL);
4988 // Fetch the hard-coded signatures for the type constructor and the
4989 // default constructor and create MethodSignature objects for both at
4990 // the method level so this does not happen for every specialname
4995 sig = CoreLibBinder::GetSignature(&gsig_SM_RetVoid);
4997 MethodSignature cctorSig(CoreLibBinder::GetModule(),
4998 COR_CCTOR_METHOD_NAME,
4999 sig.GetRawSig(), sig.GetRawSigLen());
5001 sig = CoreLibBinder::GetSignature(&gsig_IM_RetVoid);
5003 MethodSignature defaultCtorSig(CoreLibBinder::GetModule(),
5004 COR_CTOR_METHOD_NAME,
5005 sig.GetRawSig(), sig.GetRawSigLen());
5007 Module * pModule = GetModule();
5008 DeclaredMethodIterator it(*this);
5011 if (IsMdRTSpecialName(it.Attrs()))
5013 if (IsMdVirtual(it.Attrs()))
5014 { // Virtual specialname methods are illegal
5015 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
5018 // Constructors (.ctor) and class initialisers (.cctor) are special
5019 const MethodSignature &curSig(it->GetMethodSignature());
5021 if (IsMdStatic(it.Attrs()))
5022 { // The only rtSpecialName static method allowed is the .cctor
5023 if (!curSig.ExactlyEqual(cctorSig))
5025 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
5028 // Remember it for later
5029 bmtVT->pCCtor = *it;
5033 if(!MethodSignature::NamesEqual(curSig, defaultCtorSig))
5034 { // The only rtSpecialName instance methods allowed are .ctors
5035 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
5038 // .ctor must return void
5039 MetaSig methodMetaSig(curSig.GetSignature(),
5040 static_cast<DWORD>(curSig.GetSignatureLength()),
5044 if (methodMetaSig.GetReturnType() != ELEMENT_TYPE_VOID)
5045 { // All constructors must have a void return type
5046 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
5049 // See if this is a default constructor. If so, remember it for later.
5050 if (curSig.ExactlyEqual(defaultCtorSig))
5052 bmtVT->pDefaultCtor = *it;
5057 // Make sure that fcalls have a 0 rva. This is assumed by the prejit fixup logic
5058 if (it.MethodType() == mcFCall && it.RVA() != 0)
5060 BuildMethodTableThrowException(BFA_ECALLS_MUST_HAVE_ZERO_RVA, it.Token());
5063 // check for proper use of the Managed and native flags
5064 if (IsMiManaged(it.ImplFlags()))
5066 if (IsMiIL(it.ImplFlags()) || IsMiRuntime(it.ImplFlags())) // IsMiOPTIL(it.ImplFlags()) no longer supported
5068 // No need to set code address, pre stub used automatically.
5072 if (IsMiNative(it.ImplFlags()))
5074 // For now simply disallow managed native code if you turn this on you have to at least
5075 // insure that we have SkipVerificationPermission or equivalent
5076 BuildMethodTableThrowException(BFA_MANAGED_NATIVE_NYI, it.Token());
5080 BuildMethodTableThrowException(BFA_BAD_IMPL_FLAGS, it.Token());
5086 if (IsMiNative(it.ImplFlags()) && IsGlobalClass())
5088 // global function unmanaged entrypoint via IJW thunk was handled
5093 BuildMethodTableThrowException(IDS_CLASSLOAD_BAD_UNMANAGED_RVA, it.Token());
5095 if (it.MethodType() != mcNDirect)
5097 BuildMethodTableThrowException(BFA_BAD_UNMANAGED_ENTRY_POINT);
5101 // Vararg methods are not allowed inside generic classes
5102 // and nor can they be generic methods.
5103 if (bmtGenerics->GetNumGenericArgs() > 0 || (it.MethodType() == mcInstantiated) )
5105 DWORD cMemberSignature;
5106 PCCOR_SIGNATURE pMemberSignature = it.GetSig(&cMemberSignature);
5107 // We've been trying to avoid asking for the signature - now we need it
5108 if (pMemberSignature == NULL)
5110 pMemberSignature = it.GetSig(&cMemberSignature);
5113 if (MetaSig::IsVarArg(Signature(pMemberSignature, cMemberSignature)))
5115 BuildMethodTableThrowException(BFA_GENCODE_NOT_BE_VARARG);
5119 if (IsMdVirtual(it.Attrs()) && IsMdPublic(it.Attrs()) && it.Name() == NULL)
5121 BuildMethodTableThrowException(IDS_CLASSLOAD_NOMETHOD_NAME);
5124 if (it.IsMethodImpl())
5126 if (!IsMdVirtual(it.Attrs()) && !IsMdStatic(it.Attrs()))
5128 // Non-virtual methods may only participate in a methodImpl pair when
5129 // they are static and they implement a virtual static interface method.
5130 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5134 // Virtual static methods are only allowed on interfaces and they must be abstract.
5135 if (IsMdStatic(it.Attrs()) && IsMdVirtual(it.Attrs()))
5139 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL, it.Token());
5145 //*******************************************************************************
5146 // Essentially, this is a helper method that combines calls to InitMethodDesc and
5147 // SetSecurityFlagsOnMethod. It then assigns the newly initialized MethodDesc to
5150 MethodTableBuilder::InitNewMethodDesc(
5151 bmtMDMethod * pMethod,
5152 MethodDesc * pNewMD)
5154 STANDARD_VM_CONTRACT;
5157 // First, set all flags that control layout of optional slots
5159 pNewMD->SetClassification(pMethod->GetMethodType());
5161 if (pMethod->GetMethodImplType() == METHOD_IMPL)
5162 pNewMD->SetHasMethodImplSlot();
5164 if (pMethod->GetSlotIndex() >= bmtVT->cVtableSlots)
5165 pNewMD->SetHasNonVtableSlot();
5167 if (NeedsNativeCodeSlot(pMethod))
5168 pNewMD->SetHasNativeCodeSlot();
5170 // Now we know the classification we can allocate the correct type of
5171 // method desc and perform any classification specific initialization.
5173 LPCSTR pName = pMethod->GetMethodSignature().GetName();
5176 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pName)))
5178 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5183 LPCUTF8 pszDebugMethodName;
5184 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pszDebugMethodName)))
5186 pszDebugMethodName = "Invalid MethodDef record";
5188 S_SIZE_T safeLen = S_SIZE_T(strlen(pszDebugMethodName)) + S_SIZE_T(1);
5189 if(safeLen.IsOverflow())
5190 COMPlusThrowHR(COR_E_OVERFLOW);
5192 size_t len = safeLen.Value();
5193 LPCUTF8 pszDebugMethodNameCopy = (char*) AllocateFromLowFrequencyHeap(safeLen);
5194 strcpy_s((char *) pszDebugMethodNameCopy, len, pszDebugMethodName);
5197 // Do the init specific to each classification of MethodDesc & assign some common fields
5198 InitMethodDesc(pNewMD,
5199 pMethod->GetMethodType(),
5200 pMethod->GetMethodSignature().GetToken(),
5201 pMethod->GetImplAttrs(),
5202 pMethod->GetDeclAttrs(),
5207 COMMA_INDEBUG(pszDebugMethodNameCopy)
5208 COMMA_INDEBUG(GetDebugClassName())
5209 COMMA_INDEBUG("") // FIX this happens on global methods, give better info
5212 pMethod->SetMethodDesc(pNewMD);
5214 bmtRTMethod * pParentMethod = NULL;
5218 SLOT_INDEX idx = pMethod->GetSlotIndex();
5219 CONSISTENCY_CHECK(idx != INVALID_SLOT_INDEX);
5221 if (idx < GetParentMethodTable()->GetNumVirtuals())
5223 pParentMethod = (*bmtParent->pSlotTable)[idx].Decl().AsRTMethod();
5227 // Turn off inlining for any calls
5228 // that are marked in the metadata as not being inlineable.
5229 if(IsMiNoInlining(pMethod->GetImplAttrs()))
5231 pNewMD->SetNotInline(true);
5234 // Check for methods marked as [Intrinsic]
5235 if (GetModule()->IsSystem())
5237 if (bmtProp->fIsHardwareIntrinsic || (S_OK == GetCustomAttribute(pMethod->GetMethodSignature().GetToken(),
5238 WellKnownAttribute::Intrinsic,
5242 pNewMD->SetIsIntrinsic();
5247 pNewMD->SetSlot(pMethod->GetSlotIndex());
5250 //*******************************************************************************
5251 // Determine vtable placement for each non-virtual in the class, while also
5252 // looking for default and type constructors.
5254 MethodTableBuilder::PlaceNonVirtualMethods()
5260 PRECONDITION(CheckPointer(this));
5261 PRECONDITION(CheckPointer(bmtInternal));
5262 PRECONDITION(CheckPointer(bmtMetaData));
5263 PRECONDITION(CheckPointer(bmtError));
5264 PRECONDITION(CheckPointer(bmtProp));
5265 PRECONDITION(CheckPointer(bmtInterface));
5266 PRECONDITION(CheckPointer(bmtParent));
5267 PRECONDITION(CheckPointer(bmtMFDescs));
5268 PRECONDITION(CheckPointer(bmtEnumFields));
5269 PRECONDITION(CheckPointer(bmtMethodImpl));
5270 PRECONDITION(CheckPointer(bmtVT));
5274 INDEBUG(bmtVT->SealVirtualSlotSection();)
5277 // For each non-virtual method, place the method in the next available non-virtual method slot.
5280 // Place the cctor and default ctor first. code::MethodTableGetCCtorSlot and code:MethodTable::GetDefaultCtorSlot
5282 if (bmtVT->pCCtor != NULL)
5284 if (!bmtVT->AddNonVirtualMethod(bmtVT->pCCtor))
5285 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5288 if (bmtVT->pDefaultCtor != NULL)
5290 if (!bmtVT->AddNonVirtualMethod(bmtVT->pDefaultCtor))
5291 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5294 // We use slot during remoting and to map methods between generic instantiations
5295 // (see MethodTable::GetParallelMethodDesc). The current implementation
5296 // of this mechanism requires real slots.
5297 BOOL fCanHaveNonVtableSlots = (bmtGenerics->GetNumGenericArgs() == 0) && !IsInterface();
5299 // Flag to avoid second pass when possible
5300 BOOL fHasNonVtableSlots = FALSE;
5303 // Place all methods that require real vtable slot first. This is necessary so
5304 // that they get consequitive slot numbers right after virtual slots.
5307 DeclaredMethodIterator it(*this);
5310 // Skip methods that are placed already
5311 if (it->GetSlotIndex() != INVALID_SLOT_INDEX)
5315 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5316 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5319 if (!fCanHaveNonVtableSlots ||
5320 it->GetMethodType() == mcInstantiated)
5322 // We use slot during remoting and to map methods between generic instantiations
5323 // (see MethodTable::GetParallelMethodDesc). The current implementation
5324 // of this mechanism requires real slots.
5328 // This method does not need real vtable slot
5329 fHasNonVtableSlots = TRUE;
5333 // This will update slot index in bmtMDMethod
5334 if (!bmtVT->AddNonVirtualMethod(*it))
5335 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5338 // Remeber last real vtable slot
5339 bmtVT->cVtableSlots = bmtVT->cTotalSlots;
5341 // Are there any Non-vtable slots to place?
5342 if (!fHasNonVtableSlots)
5346 // Now, place the remaining methods. They will get non-vtable slot.
5349 DeclaredMethodIterator it2(*this);
5352 // Skip methods that are placed already
5353 if (it2->GetSlotIndex() != INVALID_SLOT_INDEX)
5356 if (!bmtVT->AddNonVirtualMethod(*it2))
5357 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5362 //*******************************************************************************
5363 // Determine vtable placement for each virtual member in this class.
5365 MethodTableBuilder::PlaceVirtualMethods()
5371 PRECONDITION(CheckPointer(this));
5372 PRECONDITION(CheckPointer(bmtInternal));
5373 PRECONDITION(CheckPointer(bmtMetaData));
5374 PRECONDITION(CheckPointer(bmtError));
5375 PRECONDITION(CheckPointer(bmtProp));
5376 PRECONDITION(CheckPointer(bmtInterface));
5377 PRECONDITION(CheckPointer(bmtParent));
5378 PRECONDITION(CheckPointer(bmtMFDescs));
5379 PRECONDITION(CheckPointer(bmtEnumFields));
5380 PRECONDITION(CheckPointer(bmtMethodImpl));
5381 PRECONDITION(CheckPointer(bmtVT));
5386 LPCUTF8 pszDebugName, pszDebugNamespace;
5387 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &pszDebugName, &pszDebugNamespace)))
5389 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
5394 // For each virtual method
5395 // - If the method is not declared as newslot, search all virtual methods in the parent
5396 // type for an override candidate.
5397 // - If such a candidate is found, test to see if the override is valid. If
5398 // the override is not valid, throw TypeLoadException
5399 // - If a candidate is found above, place the method in the inherited slot as both
5400 // the Decl and the Impl.
5401 // - Else, place the method in the next available empty vtable slot.
5404 DeclaredMethodIterator it(*this);
5407 if (!IsMdVirtual(it.Attrs()) || IsMdStatic(it.Attrs()))
5408 { // Only processing declared virtual instance methods
5413 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5414 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5417 // If this member is a method which overrides a parent method, it will be set to non-NULL
5418 bmtRTMethod * pParentMethod = NULL;
5420 // Hash that a method with this name exists in this class
5421 // Note that ctors and static ctors are not added to the table
5422 BOOL fMethodConstraintsMatch = FALSE;
5424 // If the member is marked with a new slot we do not need to find it in the parent
5425 if (HasParent() && !IsMdNewSlot(it.Attrs()))
5427 // Attempt to find the method with this name and signature in the parent class.
5428 // This method may or may not create pParentMethodHash (if it does not already exist).
5429 // It also may or may not fill in pMemberSignature/cMemberSignature.
5430 // An error is only returned when we can not create the hash.
5431 // NOTE: This operation touches metadata
5432 pParentMethod = LoaderFindMethodInParentClass(
5433 it->GetMethodSignature(), bmtProp->fNoSanityChecks ? NULL : &fMethodConstraintsMatch);
5435 if (pParentMethod != NULL)
5436 { // Found an override candidate
5437 DWORD dwParentAttrs = pParentMethod->GetDeclAttrs();
5439 if (!IsMdVirtual(dwParentAttrs))
5440 { // Can't override a non-virtual methods
5441 BuildMethodTableThrowException(BFA_NONVIRT_NO_SEARCH, it.Token());
5444 if(IsMdFinal(dwParentAttrs))
5445 { // Can't override a final methods
5446 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL, it.Token());
5449 if(!bmtProp->fNoSanityChecks)
5451 TestOverRide(bmtMethodHandle(pParentMethod),
5452 bmtMethodHandle(*it));
5454 if (!fMethodConstraintsMatch)
5456 BuildMethodTableThrowException(
5457 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_OVERRIDE,
5467 CONSISTENCY_CHECK(pParentMethod == NULL);
5468 // Also sets new slot number on bmtRTMethod and MethodDesc
5469 if (!bmtVT->AddVirtualMethod(*it))
5470 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5472 else if (pParentMethod != NULL)
5474 bmtVT->SetVirtualMethodOverride(pParentMethod->GetSlotIndex(), *it);
5478 if (!bmtVT->AddVirtualMethod(*it))
5479 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5484 // Given an interface map entry, and a name+signature, compute the method on the interface
5485 // that the name+signature corresponds to. Used by ProcessMethodImpls and ProcessInexactMethodImpls
5486 // Always returns the first match that it finds. Affects the ambiguities in code:#ProcessInexactMethodImpls_Ambiguities
5487 MethodTableBuilder::bmtMethodHandle
5488 MethodTableBuilder::FindDeclMethodOnInterfaceEntry(bmtInterfaceEntry *pItfEntry, MethodSignature &declSig, bool searchForStaticMethods)
5490 STANDARD_VM_CONTRACT;
5492 bmtMethodHandle declMethod;
5494 bmtInterfaceEntry::InterfaceSlotIterator slotIt =
5495 pItfEntry->IterateInterfaceSlots(GetStackingAllocator(), searchForStaticMethods);
5496 // Check for exact match
5497 for (; !slotIt.AtEnd(); slotIt.Next())
5499 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5501 if (declSig.ExactlyEqual(pCurDeclMethod->GetMethodSignature().GetSignatureWithoutSubstitution()))
5503 declMethod = slotIt->Decl();
5507 slotIt.ResetToStart();
5509 // Check for equivalent match if exact match wasn't found
5510 if (declMethod.IsNull())
5512 for (; !slotIt.AtEnd(); slotIt.Next())
5514 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5516 // Type Equivalence is forbidden in MethodImpl MemberRefs
5517 if (declSig.Equivalent(pCurDeclMethod->GetMethodSignature().GetSignatureWithoutSubstitution()))
5519 declMethod = slotIt->Decl();
5528 //*******************************************************************************
5530 // Used by BuildMethodTable
5531 // Process the list of inexact method impls generated during ProcessMethodImpls.
5532 // This list is used to cause a methodImpl to an interface to override
5533 // methods on several equivalent interfaces in the interface map. This logic is necessary
5534 // so that in the presence of an embedded interface the behavior appears to mimic
5535 // the behavior if the interface was not embedded.
5537 // In particular, the logic here is to handle cases such as
5540 // [TypeIdentifier("x","y")]
5542 // { void Method(); }
5543 // interface IOther : I' {}
5546 // [TypeIdentifier("x","y")]
5548 // { void Method(); }
5549 // class Test : I, IOther
5555 // In this case, there is one method, and one methodimpl, but there are 2 interfaces on the class that both
5556 // require an implementation of their method. The correct semantic for type equivalence, is that any
5557 // methodimpl directly targeting a method on an interface must be respected, and if it also applies to a type
5558 // equivalent interface method, then if that method was not methodimpl'd directly, then the methodimpl should apply
5559 // there as well. The ProcessInexactMethodImpls function does this secondary MethodImpl mapping.
5561 //#ProcessInexactMethodImpls_Ambiguities
5562 // In the presence of ambiguities, such as there are 3 equivalent interfaces implemented on a class and 2 methodimpls,
5563 // we will apply the 2 method impls exactly to appropriate interface methods, and arbitrarily pick one to apply to the
5564 // other interface. This is clearly ambiguous, but tricky to detect in the type loader efficiently, and should hopefully
5565 // not cause too many problems.
5568 MethodTableBuilder::ProcessInexactMethodImpls()
5570 STANDARD_VM_CONTRACT;
5572 if (bmtMethod->dwNumberInexactMethodImplCandidates == 0)
5575 DeclaredMethodIterator it(*this);
5578 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5579 // error before reaching this point.
5580 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5582 if (!IsMdVirtual(it.Attrs()))
5583 { // Only virtual methods can participate in methodImpls
5587 if(!it.IsMethodImpl())
5589 // Skip methods which are not the bodies of MethodImpl specifications
5593 // If this method serves as the BODY of a MethodImpl specification, then
5594 // we should iterate all the MethodImpl's for this class and see just how many
5595 // of them this method participates in as the BODY.
5596 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5598 // Inexact matching logic only works on MethodImpls that have been opted into inexactness by ProcessMethodImpls.
5599 if (!bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing)
5604 // If the methodimpl we are working with does not match this method, continue to next methodimpl
5605 if(it.Token() != bmtMetaData->rgMethodImplTokens[m].methodBody)
5610 bool fMatchFound = false;
5612 LPCUTF8 szName = NULL;
5613 PCCOR_SIGNATURE pSig = NULL;
5616 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5618 if (TypeFromToken(mdDecl) == mdtMethodDef)
5619 { // Different methods are aused to access MethodDef and MemberRef
5620 // names and signatures.
5621 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5622 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5624 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5629 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5631 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5635 MethodSignature declSig(GetModule(), szName, pSig, cbSig, NULL);
5636 bmtInterfaceEntry * pItfEntry = NULL;
5638 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5640 if (bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet() != bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet)
5643 bmtMethodHandle declMethod;
5644 pItfEntry = &bmtInterface->pInterfaceMap[i];
5646 // Search for declmethod on this interface
5647 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5649 // If we didn't find a match, continue on to next interface in the equivalence set
5650 if (declMethod.IsNull())
5653 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5654 { // Make sure the decl is virtual
5655 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5660 bool fPreexistingImplFound = false;
5662 // Check to ensure there isn't already a matching declMethod in the method impl list
5663 for (DWORD iMethodImpl = 0; iMethodImpl < bmtMethodImpl->pIndex; iMethodImpl++)
5665 if (bmtMethodImpl->GetDeclarationMethod(iMethodImpl) == declMethod)
5667 fPreexistingImplFound = true;
5672 // Search for other matches
5673 if (fPreexistingImplFound)
5676 if (bmtMetaData->rgMethodImplTokens[m].fRequiresCovariantReturnTypeChecking)
5678 it->GetMethodDesc()->SetRequiresCovariantReturnTypeChecking();
5681 // Otherwise, record the method impl discovery if the match is
5682 bmtMethodImpl->AddMethodImpl(*it, declMethod, bmtMetaData->rgMethodImplTokens[m].methodDecl, GetStackingAllocator());
5685 if (!fMatchFound && bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing)
5687 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5693 //*******************************************************************************
5695 // Used by BuildMethodTable
5698 MethodTableBuilder::ProcessMethodImpls()
5700 STANDARD_VM_CONTRACT;
5702 if (bmtMetaData->fHasCovariantOverride)
5704 GetHalfBakedClass()->SetHasCovariantOverride();
5706 if (GetParentMethodTable() != NULL)
5708 EEClass* parentClass = GetParentMethodTable()->GetClass();
5709 if (parentClass->HasCovariantOverride())
5710 GetHalfBakedClass()->SetHasCovariantOverride();
5711 if (parentClass->HasVTableMethodImpl())
5712 GetHalfBakedClass()->SetHasVTableMethodImpl();
5715 if (bmtMethod->dwNumberMethodImpls == 0)
5720 DeclaredMethodIterator it(*this);
5723 bool isVirtualStaticOverride = it.IsMethodImpl() && IsMdStatic(it.Attrs()) &&
5724 !!IsMdVirtual(it.Attrs()) == !!IsMdAbstract(it.Attrs());
5726 if (isVirtualStaticOverride && bmtProp->fNoSanityChecks)
5728 // Non-virtual methods can only be classified as methodImpl when implementing
5729 // static virtual methods.
5730 CONSISTENCY_CHECK(IsMdStatic(it.Attrs()));
5734 // If this method serves as the BODY of a MethodImpl specification, then
5735 // we should iterate all the MethodImpl's for this class and see just how many
5736 // of them this method participates in as the BODY.
5737 if(it.IsMethodImpl())
5739 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5741 if(it.Token() == bmtMetaData->rgMethodImplTokens[m].methodBody)
5743 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5744 bmtMethodHandle declMethod;
5746 // Get the parent token for the decl method token
5747 mdToken tkParent = mdTypeDefNil;
5748 if (TypeFromToken(mdDecl) == mdtMethodDef || TypeFromToken(mdDecl) == mdtMemberRef)
5750 if (FAILED(hr = GetMDImport()->GetParentToken(mdDecl,&tkParent)))
5752 BuildMethodTableThrowException(hr, *bmtError);
5756 if (GetCl() == tkParent)
5757 { // The DECL has been declared within the class that we're currently building.
5760 if(bmtError->pThrowable != NULL)
5762 *(bmtError->pThrowable) = NULL;
5765 if(TypeFromToken(mdDecl) != mdtMethodDef)
5767 if (FAILED(hr = FindMethodDeclarationForMethodImpl(
5768 mdDecl, &mdDecl, TRUE)))
5770 BuildMethodTableThrowException(hr, *bmtError);
5774 CONSISTENCY_CHECK(TypeFromToken(mdDecl) == mdtMethodDef);
5775 declMethod = bmtMethod->FindDeclaredMethodByToken(mdDecl);
5778 { // We can't call GetDescFromMemberDefOrRef here because this
5779 // method depends on a fully-loaded type, including parent types,
5780 // which is not always guaranteed. In particular, it requires that
5781 // the instantiation dictionary be filled. The solution is the following:
5782 // 1. Load the approximate type that the method belongs to.
5783 // 2. Get or create the correct substitution for the type involved
5784 // 3. Iterate the introduced methods on that type looking for a matching
5787 LPCUTF8 szName = NULL;
5788 PCCOR_SIGNATURE pSig = NULL;
5790 if (TypeFromToken(mdDecl) == mdtMethodDef)
5791 { // Different methods are aused to access MethodDef and MemberRef
5792 // names and signatures.
5793 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5794 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5796 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5801 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5803 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5807 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5809 MethodTable * pDeclMT = NULL;
5810 MethodSignature declSig(GetModule(), szName, pSig, cbSig, NULL);
5812 { // 1. Load the approximate type.
5813 // Block for the LoadsTypeViolation.
5814 CONTRACT_VIOLATION(LoadsTypeViolation);
5815 pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
5818 &bmtGenerics->typeContext,
5819 ClassLoader::ThrowIfNotFound,
5820 ClassLoader::PermitUninstDefOrRef,
5821 ClassLoader::LoadTypes,
5822 CLASS_LOAD_APPROXPARENTS,
5823 TRUE).GetMethodTable()->GetCanonicalMethodTable();
5826 { // 2. Get or create the correct substitution
5827 if (pDeclMT->IsInterface())
5829 // If the declaration method is a part of an interface, search through
5830 // the interface map to find the matching interface so we can provide
5831 // the correct substitution chain.
5832 bmtRTType *pDeclType = NULL;
5834 bmtInterfaceEntry * pItfEntry = NULL;
5835 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5837 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5838 // Type Equivalence is not respected for this comparison as you can have multiple type equivalent interfaces on a class
5839 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5840 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5841 pCurItf->GetMethodTable(), pDeclMT,
5842 &pCurItf->GetSubstitution(), pDeclSubst,
5845 pItfEntry = &bmtInterface->pInterfaceMap[i];
5846 pDeclType = pCurItf;
5853 if (pDeclType == NULL)
5855 // Interface is not implemented by this type.
5856 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5861 if (pDeclType == NULL)
5863 DWORD equivalenceSet = 0;
5865 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5867 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5868 // Type Equivalence is respected for this comparison as we just need to find an
5869 // equivalent interface, the particular interface is unimportant
5870 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5871 pCurItf->GetMethodTable(), pDeclMT,
5872 &pCurItf->GetSubstitution(), pDeclSubst,
5875 equivalenceSet = bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet();
5876 pItfEntry = &bmtInterface->pInterfaceMap[i];
5881 if (equivalenceSet == 0)
5883 // Interface is not implemented by this type.
5884 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5887 // Interface is not implemented by this type exactly. We need to consider this MethodImpl on non exact interface matches,
5888 // as the only match may be one of the non-exact matches
5889 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5890 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = true;
5891 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = equivalenceSet;
5892 bmtMethod->dwNumberInexactMethodImplCandidates++;
5893 continue; // Move on to other MethodImpls
5897 // This method impl may need to match other methods during inexact processing
5898 if (pItfEntry->InEquivalenceSetWithMultipleEntries())
5900 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5901 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
5902 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = pItfEntry->GetInterfaceEquivalenceSet();
5903 bmtMethod->dwNumberInexactMethodImplCandidates++;
5908 // 3. Find the matching method.
5909 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig, isVirtualStaticOverride); // Search for statics when the impl is non-virtual
5913 GetHalfBakedClass()->SetHasVTableMethodImpl();
5914 declMethod = FindDeclMethodOnClassInHierarchy(it, pDeclMT, declSig);
5917 if (declMethod.IsNull())
5918 { // Would prefer to let this fall out to the BuildMethodTableThrowException
5919 // below, but due to v2.0 and earlier behaviour throwing a MissingMethodException,
5920 // primarily because this code used to be a simple call to
5921 // MemberLoader::GetDescFromMemberDefOrRef (see above for reason why),
5922 // we must continue to do the same.
5923 MemberLoader::ThrowMissingMethodException(
5926 declSig.GetModule(),
5927 declSig.GetSignature(),
5928 static_cast<DWORD>(declSig.GetSignatureLength()),
5929 &bmtGenerics->typeContext);
5934 if (declMethod.IsNull())
5935 { // Method not found, throw.
5936 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5939 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5940 { // Make sure the decl is virtual
5941 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5944 if (isVirtualStaticOverride)
5946 // Non-virtual methods can only be classified as methodImpl when implementing
5947 // static virtual methods.
5948 ValidateStaticMethodImpl(declMethod, *it);//bmtMethodHandle(pCurImplMethod));
5952 if (bmtMetaData->rgMethodImplTokens[m].fRequiresCovariantReturnTypeChecking)
5954 it->GetMethodDesc()->SetRequiresCovariantReturnTypeChecking();
5957 bmtMethodImpl->AddMethodImpl(*it, declMethod, mdDecl, GetStackingAllocator());
5961 } /* end ... for each member */
5965 MethodTableBuilder::bmtMethodHandle MethodTableBuilder::FindDeclMethodOnClassInHierarchy(const DeclaredMethodIterator& it, MethodTable * pDeclMT, MethodSignature &declSig)
5967 bmtRTType * pDeclType = NULL;
5968 bmtMethodHandle declMethod;
5969 // Assume the MethodTable is a parent of the current type,
5970 // and create the substitution chain to match it.
5972 for (bmtRTType *pCur = GetParentType();
5974 pCur = pCur->GetParentType())
5976 if (pCur->GetMethodTable() == pDeclMT)
5983 // Instead of using the Substitution chain that reaches back to the type being loaded, instead
5984 // use a substitution chain that points back to the open type associated with the memberref of the declsig.
5985 Substitution emptySubstitution;
5986 Substitution* pDeclTypeSubstitution = &emptySubstitution;
5987 DWORD lengthOfSubstitutionChainHandled = pDeclType->GetSubstitution().GetLength();
5989 if (pDeclType == NULL)
5990 { // Method's type is not a parent.
5991 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5994 // 3. Find the matching method.
5995 bmtRTType *pCurDeclType = pDeclType;
5998 // Update the substitution in use for matching the method. If the substitution length is greater
5999 // than the previously processed data, add onto the end of the chain.
6001 DWORD declTypeSubstitionLength = pCurDeclType->GetSubstitution().GetLength();
6002 if (declTypeSubstitionLength > lengthOfSubstitutionChainHandled)
6004 void *pNewSubstitutionMem = _alloca(sizeof(Substitution));
6005 Substitution substitutionToClone = pCurDeclType->GetSubstitution();
6007 Substitution *pNewSubstitution = new(pNewSubstitutionMem) Substitution(substitutionToClone.GetModule(), substitutionToClone.GetInst(), pDeclTypeSubstitution);
6008 pDeclTypeSubstitution = pNewSubstitution;
6009 lengthOfSubstitutionChainHandled = declTypeSubstitionLength;
6013 // two pass algorithm. search for exact matches followed
6014 // by equivalent matches.
6015 for (int iPass = 0; (iPass < 2) && (declMethod.IsNull()); iPass++)
6017 MethodTable *pCurDeclMT = pCurDeclType->GetMethodTable();
6019 MethodTable::IntroducedMethodIterator methIt(pCurDeclMT);
6020 for(; methIt.IsValid(); methIt.Next())
6022 MethodDesc * pCurMD = methIt.GetMethodDesc();
6024 if (pCurDeclMT != pDeclMT)
6026 // If the method isn't on the declaring type, then it must be virtual.
6027 if (!pCurMD->IsVirtual())
6030 if (strcmp(declSig.GetName(), pCurMD->GetName()) == 0)
6032 PCCOR_SIGNATURE pCurMDSig;
6034 pCurMD->GetSig(&pCurMDSig, &cbCurMDSig);
6036 // First pass searches for declaration methods should not use type equivalence
6037 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
6039 if (MetaSig::CompareMethodSigs(
6040 declSig.GetSignature(),
6041 static_cast<DWORD>(declSig.GetSignatureLength()),
6042 declSig.GetModule(),
6043 NULL, // Do not use the substitution of declSig, as we have adjusted the pDeclTypeSubstitution such that it must not be used.
6046 pCurMD->GetModule(),
6047 pDeclTypeSubstitution,
6049 iPass == 0 ? &newVisited : NULL))
6051 declMethod = (*bmtParent->pSlotTable)[pCurMD->GetSlot()].Decl();
6058 pCurDeclType = pCurDeclType->GetParentType();
6059 } while ((pCurDeclType != NULL) && (declMethod.IsNull()));
6063 //*******************************************************************************
6064 // InitMethodDesc takes a pointer to space that's already allocated for the
6065 // particular type of MethodDesc, and initializes based on the other info.
6066 // This factors logic between PlaceMembers (the regular code path) & AddMethod
6067 // (Edit & Continue (EnC) code path) so we don't have to maintain separate copies.
6069 MethodTableBuilder::InitMethodDesc(
6070 MethodDesc * pNewMD, // This is should actually be of the correct sub-type, based on Classification
6071 DWORD Classification,
6074 DWORD dwMemberAttrs,
6076 DWORD RVA, // Only needed for NDirect case
6077 IMDInternalImport * pIMDII, // Needed for NDirect, EEImpl(Delegate) cases
6078 LPCSTR pMethodName // Only needed for mcEEImpl (Delegate) case
6079 COMMA_INDEBUG(LPCUTF8 pszDebugMethodName)
6080 COMMA_INDEBUG(LPCUTF8 pszDebugClassName)
6081 COMMA_INDEBUG(LPCUTF8 pszDebugMethodSignature)
6087 if (fEnC) { GC_NOTRIGGER; } else { GC_TRIGGERS; }
6092 LOG((LF_CORDB, LL_EVERYTHING, "MTB::IMD: pNewMD:%p (%u) EnC: %s tok:0x%08x (%s::%s)\n",
6093 pNewMD, Classification, (fEnC ? "true" : "false"), tok, pszDebugClassName, pszDebugMethodName));
6095 // Now we know the classification we can perform any classification specific initialization.
6097 // The method desc is zero inited by the caller.
6099 switch (Classification)
6103 // NDirect specific initialization.
6104 NDirectMethodDesc *pNewNMD = (NDirectMethodDesc*)pNewMD;
6106 // Allocate writeable data
6107 pNewNMD->ndirect.m_pWriteableData = (NDirectWriteableData*)
6108 AllocateFromHighFrequencyHeap(S_SIZE_T(sizeof(NDirectWriteableData)));
6110 #ifdef HAS_NDIRECT_IMPORT_PRECODE
6111 pNewNMD->ndirect.m_pImportThunkGlue = Precode::Allocate(PRECODE_NDIRECT_IMPORT, pNewMD,
6112 GetLoaderAllocator(), GetMemTracker())->AsNDirectImportPrecode();
6113 #else // !HAS_NDIRECT_IMPORT_PRECODE
6114 pNewNMD->GetNDirectImportThunkGlue()->Init(pNewNMD);
6115 #endif // !HAS_NDIRECT_IMPORT_PRECODE
6117 #if defined(TARGET_X86)
6118 pNewNMD->ndirect.m_cbStackArgumentSize = 0xFFFF;
6119 #endif // defined(TARGET_X86)
6121 // If the RVA of a native method is set, this is an early-bound IJW call
6122 if (RVA != 0 && IsMiUnmanaged(dwImplFlags) && IsMiNative(dwImplFlags))
6124 // Note that we cannot initialize the stub directly now in the general case,
6125 // as LoadLibrary may not have been performed yet.
6126 pNewNMD->SetIsEarlyBound();
6129 pNewNMD->GetWriteableData()->m_pNDirectTarget = pNewNMD->GetNDirectImportThunkGlue()->GetEntrypoint();
6137 // For the Invoke method we will set a standard invoke method.
6138 BAD_FORMAT_NOTHROW_ASSERT(IsDelegate());
6140 // For the asserts, either the pointer is NULL (since the class hasn't
6141 // been constructed yet), or we're in EnC mode, meaning that the class
6142 // does exist, but we may be re-assigning the field to point to an
6143 // updated MethodDesc
6145 // It is not allowed for EnC to replace one of the runtime builtin methods
6147 if (strcmp(pMethodName, "Invoke") == 0)
6149 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod == NULL);
6150 ((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod = pNewMD;
6152 else if (strcmp(pMethodName, "BeginInvoke") == 0)
6154 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod == NULL);
6155 ((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod = pNewMD;
6157 else if (strcmp(pMethodName, "EndInvoke") == 0)
6159 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod == NULL);
6160 ((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod = pNewMD;
6164 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
6167 // StoredSig specific initialization
6169 StoredSigMethodDesc *pNewSMD = (StoredSigMethodDesc*) pNewMD;;
6171 PCCOR_SIGNATURE pSig;
6172 if (FAILED(pIMDII->GetSigOfMethodDef(tok, &cSig, &pSig)))
6174 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
6176 pNewSMD->SetStoredMethodSig(pSig, cSig);
6180 #ifdef FEATURE_COMINTEROP
6182 #endif // FEATURE_COMINTEROP
6186 case mcInstantiated:
6188 // Initialize the typical instantiation.
6189 InstantiatedMethodDesc* pNewIMD = pNewMD->AsInstantiatedMethodDesc();
6191 //data has the same lifetime as method table, use our allocator
6192 pNewIMD->SetupGenericMethodDefinition(
6194 GetLoaderAllocator(),
6202 BAD_FORMAT_NOTHROW_ASSERT(!"Failed to set a method desc classification");
6205 // Check the method desc's classification.
6206 _ASSERTE(pNewMD->GetClassification() == Classification);
6208 pNewMD->SetMemberDef(tok);
6210 if (IsMdStatic(dwMemberAttrs))
6211 pNewMD->SetStatic();
6213 #ifdef EnC_SUPPORTED
6215 pNewMD->SetIsEnCAddedMethod();
6216 #endif // EnC_SUPPORTED
6219 // Mark as many methods as synchronized as possible.
6221 // Note that this can easily cause programs to deadlock, and that
6222 // should not be treated as a bug in the program.
6224 static ConfigDWORD stressSynchronized;
6225 DWORD stressSynchronizedVal = stressSynchronized.val(CLRConfig::INTERNAL_stressSynchronized);
6227 bool isStressSynchronized = stressSynchronizedVal &&
6228 pNewMD->IsIL() && // Synchronized is not supported on Ecalls, NDirect method, etc
6229 // IsValueClass() and IsEnum() do not work for System.ValueType and System.Enum themselves
6230 ((g_pValueTypeClass != NULL && g_pEnumClass != NULL &&
6231 !IsValueClass()) || // Can not synchronize on byref "this"
6232 IsMdStatic(dwMemberAttrs)) && // IsStatic() blows up in _DEBUG as pNewMD is not fully inited
6233 g_pObjectClass != NULL; // Ignore Object:* since "this" could be a boxed object
6235 // stressSynchronized=1 turns off the stress in the system domain to reduce
6236 // the chances of spurious deadlocks. Deadlocks in user code can still occur.
6237 // stressSynchronized=2 will probably cause more deadlocks, and is not recommended
6238 if (stressSynchronizedVal == 1 && GetAssembly()->IsSystem())
6239 isStressSynchronized = false;
6241 if (IsMiSynchronized(dwImplFlags) || isStressSynchronized)
6243 if (IsMiSynchronized(dwImplFlags))
6245 pNewMD->SetSynchronized();
6248 pNewMD->m_pszDebugMethodName = (LPUTF8)pszDebugMethodName;
6249 pNewMD->m_pszDebugClassName = (LPUTF8)pszDebugClassName;
6250 pNewMD->m_pDebugMethodTable = GetHalfBakedMethodTable();
6252 if (pszDebugMethodSignature == NULL)
6253 pNewMD->m_pszDebugMethodSignature = FormatSig(pNewMD,pNewMD->GetLoaderAllocator()->GetLowFrequencyHeap(),GetMemTracker());
6255 pNewMD->m_pszDebugMethodSignature = pszDebugMethodSignature;
6257 } // MethodTableBuilder::InitMethodDesc
6259 //*******************************************************************************
6261 // Used by BuildMethodTable
6264 MethodTableBuilder::AddMethodImplDispatchMapping(
6265 DispatchMapTypeID typeID,
6266 SLOT_INDEX slotNumber,
6267 bmtMDMethod * pImplMethod)
6269 STANDARD_VM_CONTRACT;
6271 MethodDesc * pMDImpl = pImplMethod->GetMethodDesc();
6273 // Look for an existing entry in the map.
6274 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6275 if (bmtVT->pDispatchMapBuilder->Find(typeID, slotNumber, it))
6277 // Throw if this entry has already previously been MethodImpl'd.
6278 if (it.IsMethodImpl())
6280 // NOTE: This is where we check for duplicate overrides. This is the easiest place to check
6281 // because duplicate overrides could in fact have separate MemberRefs to the same
6282 // member and so just comparing tokens at the very start would not be enough.
6283 if (it.GetTargetMD() != pMDImpl)
6285 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, pMDImpl->GetMemberDef());
6288 // This is the first MethodImpl. That's ok.
6291 it.SetTarget(pMDImpl);
6292 it.SetIsMethodImpl();
6295 // A mapping for this interface method does not exist, so insert it.
6298 bmtVT->pDispatchMapBuilder->InsertMDMapping(
6305 // Save the entry into the vtable as well, if it isn't an interface methodImpl
6306 if (typeID == DispatchMapTypeID::ThisClassID())
6308 bmtVT->SetVirtualMethodImpl(slotNumber, pImplMethod);
6310 } // MethodTableBuilder::AddMethodImplDispatchMapping
6312 //*******************************************************************************
6314 MethodTableBuilder::MethodImplCompareSignatures(
6315 bmtMethodHandle hDecl,
6316 bmtMethodHandle hImpl,
6317 BOOL allowCovariantReturn,
6318 DWORD dwConstraintErrorCode)
6322 PRECONDITION(!hDecl.IsNull());
6323 PRECONDITION(!hImpl.IsNull());
6324 PRECONDITION(TypeFromToken(hDecl.GetMethodSignature().GetToken()) == mdtMethodDef);
6325 PRECONDITION(TypeFromToken(hImpl.GetMethodSignature().GetToken()) == mdtMethodDef);
6328 const MethodSignature &declSig(hDecl.GetMethodSignature());
6329 const MethodSignature &implSig(hImpl.GetMethodSignature());
6331 if (!MethodSignature::SignaturesEquivalent(declSig, implSig, allowCovariantReturn))
6333 LOG((LF_CLASSLOADER, LL_INFO1000, "BADSIG placing MethodImpl: %x\n", declSig.GetToken()));
6334 BuildMethodTableThrowException(COR_E_TYPELOAD, IDS_CLASSLOAD_MI_BADSIGNATURE, declSig.GetToken());
6337 //now compare the method constraints
6338 if ((*declSig.GetSignature()) & IMAGE_CEE_CS_CALLCONV_GENERIC)
6340 if (!MetaSig::CompareMethodConstraints(implSig.GetSubstitution(), implSig.GetModule(), implSig.GetToken(),
6341 declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken()))
6343 BuildMethodTableThrowException(dwConstraintErrorCode, implSig.GetToken());
6348 //*******************************************************************************
6349 // We should have collected all the method impls. Cycle through them creating the method impl
6350 // structure that holds the information about which slots are overridden.
6352 MethodTableBuilder::PlaceMethodImpls()
6354 STANDARD_VM_CONTRACT;
6356 if(bmtMethodImpl->pIndex == 0)
6361 // Allocate some temporary storage. The number of overrides for a single method impl
6362 // cannot be greater then the number of vtable slots for classes. But for interfaces
6363 // it might contain overrides for other interface methods.
6364 DWORD dwMaxSlotSize = IsInterface() ? bmtMethod->dwNumberMethodImpls : bmtVT->cVirtualSlots;
6366 DWORD * slots = new (GetStackingAllocator()) DWORD[dwMaxSlotSize];
6367 mdToken * tokens = new (GetStackingAllocator()) mdToken[dwMaxSlotSize];
6368 MethodDesc ** replaced = new (GetStackingAllocator()) MethodDesc*[dwMaxSlotSize];
6371 bmtMDMethod * pCurImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6373 DWORD slotIndex = 0;
6375 // The impls are sorted according to the method descs for the body of the method impl.
6376 // Loop through the impls until the next body is found. When a single body
6377 // has been done move the slots implemented and method descs replaced into the storage
6378 // found on the body method desc.
6380 { // collect information until we reach the next body
6382 tokens[slotIndex] = bmtMethodImpl->GetDeclarationToken(iEntry);
6384 // Get the declaration part of the method impl. It will either be a token
6385 // (declaration is on this type) or a method desc.
6386 bmtMethodHandle hDeclMethod = bmtMethodImpl->GetDeclarationMethod(iEntry);
6388 // Don't place static virtual method overrides in the vtable
6389 if (!IsMdStatic(hDeclMethod.GetDeclAttrs()))
6391 if(hDeclMethod.IsMDMethod())
6393 // The declaration is on the type being built
6394 bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod();
6396 mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken();
6397 if (bmtMethodImpl->IsBody(mdef))
6398 { // A method declared on this class cannot be both a decl and an impl
6399 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
6405 PlaceInterfaceDeclarationOnInterface(
6408 slots, // Adds override to the slot and replaced arrays.
6411 dwMaxSlotSize); // Increments count
6416 PlaceLocalDeclarationOnClass(
6419 slots, // Adds override to the slot and replaced arrays.
6422 dwMaxSlotSize); // Increments count
6427 bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();
6432 PlaceInterfaceDeclarationOnInterface(
6435 slots, // Adds override to the slot and replaced arrays.
6438 dwMaxSlotSize); // Increments count
6442 // Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
6443 if (pCurDeclMethod->GetOwningType()->IsInterface())
6446 PlaceInterfaceDeclarationOnClass(
6453 PlaceParentDeclarationOnClass(
6459 dwMaxSlotSize); // Increments count
6467 if(iEntry == bmtMethodImpl->pIndex)
6469 // We hit the end of the list so dump the current data and leave
6470 WriteMethodImplData(pCurImplMethod, slotIndex, slots, tokens, replaced);
6475 bmtMDMethod * pNextImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6477 if (pNextImplMethod != pCurImplMethod)
6479 // If we're moving on to a new body, dump the current data and reset the counter
6480 WriteMethodImplData(pCurImplMethod, slotIndex, slots, tokens, replaced);
6484 pCurImplMethod = pNextImplMethod;
6486 } // while(next != NULL)
6487 } // MethodTableBuilder::PlaceMethodImpls
6489 //*******************************************************************************
6491 MethodTableBuilder::WriteMethodImplData(
6492 bmtMDMethod * pImplMethod,
6496 MethodDesc ** rgDeclMD)
6498 STANDARD_VM_CONTRACT;
6500 // Use the number of overrides to
6501 // push information on to the method desc. We store the slots that
6502 // are overridden and the method desc that is replaced. That way
6503 // when derived classes need to determine if the method is to be
6504 // overridden then it can check the name against the replaced
6505 // method desc not the bodies name.
6508 //@TODO:NEWVTWORK: Determine methodImpl status so that we don't need this workaround.
6509 //@TODO:NEWVTWORK: This occurs when only interface decls are involved, since
6510 //@TODO:NEWVTWORK: these are stored in the dispatch map and not on the methoddesc.
6514 MethodImpl * pImpl = pImplMethod->GetMethodDesc()->GetMethodImpl();
6516 // Set the size of the info the MethodImpl needs to keep track of.
6517 pImpl->SetSize(GetLoaderAllocator()->GetHighFrequencyHeap(), GetMemTracker(), cSlots);
6521 // If we are currently builting an interface, the slots here has no meaning and we can skip it
6522 // Sort the two arrays in slot index order
6523 // This is required in MethodImpl::FindSlotIndex and MethodImpl::Iterator as we'll be using
6524 // binary search later
6525 for (DWORD i = 0; i < cSlots; i++)
6527 unsigned int min = i;
6528 for (DWORD j = i + 1; j < cSlots; j++)
6530 if (rgSlots[j] < rgSlots[min])
6538 MethodDesc * mTmp = rgDeclMD[i];
6539 rgDeclMD[i] = rgDeclMD[min];
6540 rgDeclMD[min] = mTmp;
6542 DWORD sTmp = rgSlots[i];
6543 rgSlots[i] = rgSlots[min];
6544 rgSlots[min] = sTmp;
6546 mdToken tTmp = rgTokens[i];
6547 rgTokens[i] = rgTokens[min];
6548 rgTokens[min] = tTmp;
6553 // Go and set the method impl
6554 pImpl->SetData(rgSlots, rgTokens, rgDeclMD);
6556 GetHalfBakedClass()->SetContainsMethodImpls();
6558 } // MethodTableBuilder::WriteMethodImplData
6560 //*******************************************************************************
6562 MethodTableBuilder::PlaceLocalDeclarationOnClass(
6563 bmtMDMethod * pDecl,
6564 bmtMDMethod * pImpl,
6566 MethodDesc ** replaced,
6568 DWORD dwMaxSlotSize)
6573 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6574 PRECONDITION(CheckPointer(pDecl));
6575 PRECONDITION(CheckPointer(pImpl));
6579 if (!bmtProp->fNoSanityChecks)
6581 ///////////////////////////////
6582 // Verify the signatures match
6584 MethodImplCompareSignatures(
6587 FALSE /* allowCovariantReturn */,
6588 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_LOCAL_METHOD_IMPL);
6590 ///////////////////////////////
6591 // Validate the method impl.
6594 bmtMethodHandle(pDecl),
6595 bmtMethodHandle(pImpl));
6598 // Don't allow overrides for any of the four special runtime implemented delegate methods
6601 LPCUTF8 strMethodName = pDecl->GetMethodSignature().GetName();
6602 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
6603 (strcmp(strMethodName, "Invoke") == 0) ||
6604 (strcmp(strMethodName, "BeginInvoke") == 0) ||
6605 (strcmp(strMethodName, "EndInvoke") == 0))
6607 BuildMethodTableThrowException(
6608 IDS_CLASSLOAD_MI_CANNOT_OVERRIDE,
6609 pDecl->GetMethodSignature().GetToken());
6616 // Call helper to add it. Will throw if decl is already MethodImpl'd
6617 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6618 AddMethodImplDispatchMapping(
6619 DispatchMapTypeID::ThisClassID(),
6620 pDecl->GetSlotIndex(),
6623 // We implement this slot, record it
6624 ASSERT(*pSlotIndex < dwMaxSlotSize);
6625 slots[*pSlotIndex] = pDecl->GetSlotIndex();
6626 replaced[*pSlotIndex] = pDecl->GetMethodDesc();
6628 // increment the counter
6630 } // MethodTableBuilder::PlaceLocalDeclarationOnClass
6632 //*******************************************************************************
6633 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnClass(
6634 bmtRTMethod * pDecl,
6635 bmtMDMethod * pImpl)
6639 PRECONDITION(CheckPointer(pDecl));
6640 PRECONDITION(CheckPointer(pImpl));
6641 PRECONDITION(pDecl->GetMethodDesc()->IsInterface());
6642 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6645 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6646 MethodTable * pDeclMT = pDeclMD->GetMethodTable();
6648 // Note that the fact that pDecl is non-NULL means that we found the
6649 // declaration token to be owned by a declared interface for this type.
6651 if (!bmtProp->fNoSanityChecks)
6653 ///////////////////////////////
6654 // Verify the signatures match
6656 MethodImplCompareSignatures(
6659 FALSE /* allowCovariantReturn */,
6660 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6662 ///////////////////////////////
6663 // Validate the method impl.
6666 bmtMethodHandle(pDecl),
6667 bmtMethodHandle(pImpl));
6673 // Note that we need only one DispatchMapTypeID for this interface (though there might be more if there
6674 // are duplicates). The first one is easy to get, but we could (in theory) use the last one or a random
6676 // Q: Why don't we have to place this method for all duplicate interfaces? Because VSD knows about
6677 // duplicates and finds the right (latest) implementation for us - see
6678 // code:MethodTable::MethodDataInterfaceImpl::PopulateNextLevel#ProcessAllDuplicates.
6679 UINT32 cInterfaceDuplicates;
6680 DispatchMapTypeID firstDispatchMapTypeID;
6681 ComputeDispatchMapTypeIDs(
6683 pDecl->GetMethodSignature().GetSubstitution(),
6684 &firstDispatchMapTypeID,
6686 &cInterfaceDuplicates);
6687 CONSISTENCY_CHECK(cInterfaceDuplicates >= 1);
6688 CONSISTENCY_CHECK(firstDispatchMapTypeID.IsImplementedInterface());
6690 // Call helper to add it. Will throw if decl is already MethodImpl'd
6691 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6692 AddMethodImplDispatchMapping(
6693 firstDispatchMapTypeID,
6694 pDecl->GetSlotIndex(),
6698 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
6699 { // We injected interface duplicates
6701 // We have to MethodImpl all interface duplicates as all duplicates are 'declared on type' (see
6702 // code:#InjectInterfaceDuplicates_ApproxInterfaces)
6703 DispatchMapTypeID * rgDispatchMapTypeIDs = (DispatchMapTypeID *)_alloca(sizeof(DispatchMapTypeID) * cInterfaceDuplicates);
6704 ComputeDispatchMapTypeIDs(
6706 pDecl->GetMethodSignature().GetSubstitution(),
6707 rgDispatchMapTypeIDs,
6708 cInterfaceDuplicates,
6709 &cInterfaceDuplicates);
6710 for (UINT32 nInterfaceDuplicate = 1; nInterfaceDuplicate < cInterfaceDuplicates; nInterfaceDuplicate++)
6712 // Add MethodImpl record for each injected interface duplicate
6713 AddMethodImplDispatchMapping(
6714 rgDispatchMapTypeIDs[nInterfaceDuplicate],
6715 pDecl->GetSlotIndex(),
6720 } // MethodTableBuilder::PlaceInterfaceDeclarationOnClass
6722 //*******************************************************************************
6723 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnInterface(
6724 bmtMethodHandle hDecl,
6727 MethodDesc ** replaced,
6729 DWORD dwMaxSlotSize)
6733 PRECONDITION(CheckPointer(pImpl));
6734 PRECONDITION(IsInterface());
6735 PRECONDITION(hDecl.GetMethodDesc()->IsInterface());
6738 MethodDesc * pDeclMD = hDecl.GetMethodDesc();
6740 if (!bmtProp->fNoSanityChecks)
6742 ///////////////////////////////
6743 // Verify the signatures match
6745 MethodImplCompareSignatures(
6747 bmtMethodHandle(pImpl),
6748 FALSE /* allowCovariantReturn */,
6749 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6751 ///////////////////////////////
6752 // Validate the method impl.
6754 TestMethodImpl(hDecl, bmtMethodHandle(pImpl));
6757 // We implement this slot, record it
6758 ASSERT(*pSlotIndex < dwMaxSlotSize);
6759 slots[*pSlotIndex] = hDecl.GetSlotIndex();
6760 replaced[*pSlotIndex] = pDeclMD;
6762 // increment the counter
6764 } // MethodTableBuilder::PlaceInterfaceDeclarationOnInterface
6766 //*******************************************************************************
6768 MethodTableBuilder::PlaceParentDeclarationOnClass(
6769 bmtRTMethod * pDecl,
6770 bmtMDMethod * pImpl,
6772 MethodDesc** replaced,
6774 DWORD dwMaxSlotSize)
6778 PRECONDITION(CheckPointer(pDecl));
6779 PRECONDITION(CheckPointer(pImpl));
6780 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6781 PRECONDITION(CheckPointer(GetParentMethodTable()));
6784 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6786 // Note that the fact that pDecl is non-NULL means that we found the
6787 // declaration token to be owned by a parent type.
6789 if (!bmtProp->fNoSanityChecks)
6791 /////////////////////////////////////////
6792 // Verify that the signatures match
6794 MethodImplCompareSignatures(
6797 TRUE /* allowCovariantReturn */,
6798 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_PARENT_METHOD_IMPL);
6800 ////////////////////////////////
6801 // Verify rules of method impls
6804 bmtMethodHandle(pDecl),
6805 bmtMethodHandle(pImpl));
6811 // Call helper to add it. Will throw if DECL is already MethodImpl'd
6812 AddMethodImplDispatchMapping(
6813 DispatchMapTypeID::ThisClassID(),
6817 // We implement this slot, record it
6818 ASSERT(*pSlotIndex < dwMaxSlotSize);
6819 slots[*pSlotIndex] = pDeclMD->GetSlot();
6820 replaced[*pSlotIndex] = pDeclMD;
6822 // increment the counter
6824 } // MethodTableBuilder::PlaceParentDeclarationOnClass
6826 VOID MethodTableBuilder::ValidateStaticMethodImpl(
6827 bmtMethodHandle hDecl,
6828 bmtMethodHandle hImpl)
6830 // While we don't want to place the static method impl declarations on the class/interface, we do
6831 // need to validate the method constraints and signature are compatible
6832 if (!bmtProp->fNoSanityChecks)
6834 ///////////////////////////////
6835 // Verify the signatures match
6837 MethodImplCompareSignatures(
6840 FALSE /* allowCovariantReturn */,
6841 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6843 ///////////////////////////////
6844 // Validate the method impl.
6846 TestMethodImpl(hDecl, hImpl);
6850 //*******************************************************************************
6851 // This will validate that all interface methods that were matched during
6852 // layout also validate against type constraints.
6854 VOID MethodTableBuilder::ValidateInterfaceMethodConstraints()
6856 STANDARD_VM_CONTRACT;
6858 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6859 for (; it.IsValid(); it.Next())
6861 if (it.GetTypeID() != DispatchMapTypeID::ThisClassID())
6863 bmtRTType * pItf = bmtInterface->pInterfaceMap[it.GetTypeID().GetInterfaceNum()].GetInterfaceType();
6865 // Grab the method token
6866 MethodTable * pMTItf = pItf->GetMethodTable();
6867 CONSISTENCY_CHECK(CheckPointer(pMTItf->GetMethodDescForSlot(it.GetSlotNumber())));
6868 mdMethodDef mdTok = pItf->GetMethodTable()->GetMethodDescForSlot(it.GetSlotNumber())->GetMemberDef();
6870 // Default to the current module. The code immediately below determines if this
6871 // assumption is incorrect.
6872 Module * pTargetModule = GetModule();
6874 // Get the module of the target method. Get it through the chunk to
6875 // avoid triggering the assert that MethodTable is non-NULL. It may
6876 // be null since it may belong to the type we're building right now.
6877 MethodDesc * pTargetMD = it.GetTargetMD();
6879 // If pTargetMT is null, this indicates that the target MethodDesc belongs
6880 // to the current type. Otherwise, the MethodDesc MUST be owned by a parent
6881 // of the type we're building.
6882 BOOL fTargetIsOwnedByParent = pTargetMD->GetMethodTable() != NULL;
6884 // If the method is owned by a parent, we need to use the parent's module,
6885 // and we must construct the substitution chain all the way up to the parent.
6886 const Substitution *pSubstTgt = NULL;
6887 if (fTargetIsOwnedByParent)
6889 CONSISTENCY_CHECK(CheckPointer(GetParentType()));
6890 bmtRTType *pTargetType = bmtRTType::FindType(GetParentType(), pTargetMD->GetMethodTable());
6891 pSubstTgt = &pTargetType->GetSubstitution();
6892 pTargetModule = pTargetType->GetModule();
6895 // Now compare the method constraints.
6896 if ((pTargetMD->GetClassification() == mcInstantiated) && !MetaSig::CompareMethodConstraints(pSubstTgt,
6898 pTargetMD->GetMemberDef(),
6899 &pItf->GetSubstitution(),
6900 pMTItf->GetModule(),
6903 LOG((LF_CLASSLOADER, LL_INFO1000,
6904 "BADCONSTRAINTS on interface method implementation: %x\n", pTargetMD));
6905 // This exception will be due to an implicit implementation, since explicit errors
6906 // will be detected in MethodImplCompareSignatures (for now, anyway).
6907 CONSISTENCY_CHECK(!it.IsMethodImpl());
6908 DWORD idsError = it.IsMethodImpl() ?
6909 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL :
6910 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_IMPLEMENTATION;
6911 if (fTargetIsOwnedByParent)
6913 DefineFullyQualifiedNameForClass();
6914 LPCUTF8 szClassName = GetFullyQualifiedNameForClassNestedAware(pTargetMD->GetMethodTable());
6915 LPCUTF8 szMethodName = pTargetMD->GetName();
6918 // allocate enough room for "<class>.<method>\0"
6919 size_t cchFullName = strlen(szClassName) + 1 + strlen(szMethodName) + 1;
6920 LPUTF8 szFullName = (LPUTF8) qb.AllocThrows(cchFullName);
6921 strcpy_s(szFullName, cchFullName, szClassName);
6922 strcat_s(szFullName, cchFullName, ".");
6923 strcat_s(szFullName, cchFullName, szMethodName);
6925 BuildMethodTableThrowException(idsError, szFullName);
6929 BuildMethodTableThrowException(idsError, pTargetMD->GetMemberDef());
6934 } // MethodTableBuilder::ValidateInterfaceMethodConstraints
6936 //*******************************************************************************
6937 // Used to allocate and initialize MethodDescs (both the boxed and unboxed entrypoints)
6938 VOID MethodTableBuilder::AllocAndInitMethodDescs()
6940 STANDARD_VM_CONTRACT;
6943 // Go over all MethodDescs and create smallest number of MethodDescChunks possible.
6945 // Iterate over all methods and start a new chunk only if:
6946 // - Token range (upper 24 bits of the method token) has changed.
6947 // - The maximum size of the chunk has been reached.
6950 int currentTokenRange = -1; // current token range
6951 SIZE_T sizeOfMethodDescs = 0; // current running size of methodDesc chunk
6952 int startIndex = 0; // start of the current chunk (index into bmtMethod array)
6954 // Limit the maximum MethodDescs per chunk by the number of precodes that can fit to a single memory page,
6955 // since we allocate consecutive temporary entry points for all MethodDescs in the whole chunk.
6956 DWORD maxPrecodesPerPage = Precode::GetMaxTemporaryEntryPointsCount();
6957 DWORD methodDescCount = 0;
6959 DeclaredMethodIterator it(*this);
6962 DWORD currentSlotMethodDescCount = 1;
6963 int tokenRange = GetTokenRange(it.Token());
6965 // This code assumes that iterator returns tokens in ascending order. If this assumption does not hold,
6966 // the code will still work with small performance penalty (method desc chunk layout will be less efficient).
6967 _ASSERTE(tokenRange >= currentTokenRange);
6969 SIZE_T size = MethodDesc::GetBaseSize(it->GetMethodType());
6971 // Add size of optional slots
6973 if (it->GetMethodImplType() == METHOD_IMPL)
6974 size += sizeof(MethodImpl);
6976 if (it->GetSlotIndex() >= bmtVT->cVtableSlots)
6977 size += sizeof(MethodDesc::NonVtableSlot); // slot
6979 if (NeedsNativeCodeSlot(*it))
6980 size += sizeof(MethodDesc::NativeCodeSlot);
6982 // See comment in AllocAndInitMethodDescChunk
6983 if (NeedsTightlyBoundUnboxingStub(*it))
6985 currentSlotMethodDescCount = 2;
6988 if (bmtGenerics->GetNumGenericArgs() == 0) {
6989 size += sizeof(MethodDesc::NonVtableSlot);
6992 bmtVT->cVtableSlots++;
6996 if (tokenRange != currentTokenRange ||
6997 sizeOfMethodDescs + size > MethodDescChunk::MaxSizeOfMethodDescs ||
6998 methodDescCount + currentSlotMethodDescCount > maxPrecodesPerPage)
7000 if (sizeOfMethodDescs != 0)
7002 AllocAndInitMethodDescChunk(startIndex, it.CurrentIndex() - startIndex, sizeOfMethodDescs);
7003 startIndex = it.CurrentIndex();
7006 currentTokenRange = tokenRange;
7007 sizeOfMethodDescs = 0;
7008 methodDescCount = 0;
7011 sizeOfMethodDescs += size;
7012 methodDescCount += currentSlotMethodDescCount;
7015 if (sizeOfMethodDescs != 0)
7017 AllocAndInitMethodDescChunk(startIndex, NumDeclaredMethods() - startIndex, sizeOfMethodDescs);
7021 //*******************************************************************************
7022 // Allocates and initializes one method desc chunk.
7025 // startIndex - index of first method in bmtMethod array.
7026 // count - number of methods in this chunk (contiguous region from startIndex)
7027 // sizeOfMethodDescs - total expected size of MethodDescs in this chunk
7029 // Used by AllocAndInitMethodDescs.
7031 VOID MethodTableBuilder::AllocAndInitMethodDescChunk(COUNT_T startIndex, COUNT_T count, SIZE_T sizeOfMethodDescs)
7035 PRECONDITION(sizeOfMethodDescs <= MethodDescChunk::MaxSizeOfMethodDescs);
7038 void * pMem = GetMemTracker()->Track(
7039 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TADDR) + sizeof(MethodDescChunk) + sizeOfMethodDescs)));
7041 // Skip pointer to temporary entrypoints
7042 MethodDescChunk * pChunk = (MethodDescChunk *)((BYTE*)pMem + sizeof(TADDR));
7044 COUNT_T methodDescCount = 0;
7046 SIZE_T offset = sizeof(MethodDescChunk);
7049 #pragma warning(push)
7050 #pragma warning(disable:22019) // Suppress PREFast warning about integer underflow
7052 for (COUNT_T i = 0; i < count; i++)
7054 #pragma warning(pop)
7058 bmtMDMethod * pMDMethod = (*bmtMethod)[static_cast<SLOT_INDEX>(startIndex + i)];
7060 MethodDesc * pMD = (MethodDesc *)((BYTE *)pChunk + offset);
7062 pMD->SetChunkIndex(pChunk);
7063 pMD->SetMethodDescIndex(methodDescCount);
7065 InitNewMethodDesc(pMDMethod, pMD);
7068 #pragma warning(push)
7069 #pragma warning(disable:22018) // Suppress PREFast warning about integer underflow
7071 offset += pMD->SizeOf();
7073 #pragma warning(pop)
7078 // If we're a value class, we want to create duplicate slots
7079 // and MethodDescs for all methods in the vtable
7080 // section (i.e. not non-virtual instance methods or statics).
7081 // In the name of uniformity it would be much nicer
7082 // if we created _all_ value class BoxedEntryPointStubs at this point.
7083 // However, non-virtual instance methods only require unboxing
7084 // stubs in the rare case that we create a delegate to such a
7085 // method, and thus it would be inefficient to create them on
7086 // loading: after all typical structs will have many non-virtual
7087 // instance methods.
7089 // Unboxing stubs for non-virtual instance methods are created
7090 // in code:MethodDesc::FindOrCreateAssociatedMethodDesc.
7092 if (NeedsTightlyBoundUnboxingStub(pMDMethod))
7094 MethodDesc * pUnboxedMD = (MethodDesc *)((BYTE *)pChunk + offset);
7096 //////////////////////////////////
7097 // Initialize the new MethodDesc
7099 // <NICE> memcpy operations on data structures like MethodDescs are extremely fragile
7100 // and should not be used. We should go to the effort of having proper constructors
7101 // in the MethodDesc class. </NICE>
7103 memcpy(pUnboxedMD, pMD, pMD->SizeOf());
7105 // Reset the chunk index
7106 pUnboxedMD->SetChunkIndex(pChunk);
7107 pUnboxedMD->SetMethodDescIndex(methodDescCount);
7109 if (bmtGenerics->GetNumGenericArgs() == 0) {
7110 pUnboxedMD->SetHasNonVtableSlot();
7113 //////////////////////////////////////////////////////////
7114 // Modify the original MethodDesc to be an unboxing stub
7116 pMD->SetIsUnboxingStub();
7118 ////////////////////////////////////////////////////////////////////
7119 // Add the new MethodDesc to the non-virtual portion of the vtable
7121 if (!bmtVT->AddUnboxedMethod(pMDMethod))
7122 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
7124 pUnboxedMD->SetSlot(pMDMethod->GetUnboxedSlotIndex());
7125 pMDMethod->SetUnboxedMethodDesc(pUnboxedMD);
7127 offset += pUnboxedMD->SizeOf();
7131 _ASSERTE(offset == sizeof(MethodDescChunk) + sizeOfMethodDescs);
7133 pChunk->SetSizeAndCount(sizeOfMethodDescs, methodDescCount);
7135 GetHalfBakedClass()->AddChunk(pChunk);
7138 //*******************************************************************************
7140 MethodTableBuilder::NeedsTightlyBoundUnboxingStub(bmtMDMethod * pMDMethod)
7142 STANDARD_VM_CONTRACT;
7144 return IsValueClass() &&
7145 !IsMdStatic(pMDMethod->GetDeclAttrs()) &&
7146 IsMdVirtual(pMDMethod->GetDeclAttrs()) &&
7147 (pMDMethod->GetMethodType() != mcInstantiated) &&
7148 !IsMdRTSpecialName(pMDMethod->GetDeclAttrs());
7151 //*******************************************************************************
7153 MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
7155 LIMITED_METHOD_CONTRACT;
7158 #ifdef FEATURE_TIERED_COMPILATION
7159 // Keep in-sync with MethodDesc::DetermineAndSetIsEligibleForTieredCompilation()
7160 if ((g_pConfig->TieredCompilation() &&
7162 // Policy - If QuickJit is disabled and the module does not have any pregenerated code, the method would be ineligible
7163 // for tiering currently to avoid some unnecessary overhead
7164 (g_pConfig->TieredCompilation_QuickJit() || GetModule()->IsReadyToRun()) &&
7166 (pMDMethod->GetMethodType() == mcIL || pMDMethod->GetMethodType() == mcInstantiated))
7168 #ifdef FEATURE_REJIT
7171 // Methods that are R2R need precode if ReJIT is enabled. Keep this in sync with MethodDesc::IsEligibleForReJIT()
7172 (ReJitManager::IsReJITEnabled() &&
7174 pMDMethod->GetMethodType() == mcIL &&
7176 !GetModule()->IsCollectible() &&
7178 !GetModule()->IsEditAndContinueEnabled())
7179 #endif // FEATURE_REJIT
7186 #ifdef FEATURE_DEFAULT_INTERFACES
7189 DWORD attrs = pMDMethod->GetDeclAttrs();
7190 if (!IsMdStatic(attrs) && IsMdVirtual(attrs) && !IsMdAbstract(attrs))
7192 // Default interface method. Since interface methods currently need to have a precode, the native code slot will be
7193 // used to retrieve the native code entry point, instead of getting it from the precode, which is not reliable with
7194 // debuggers setting breakpoints.
7200 #if defined(FEATURE_JIT_PITCHING)
7201 if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchEnabled) != 0) &&
7202 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchMemThreshold) != 0))
7206 return GetModule()->IsEditAndContinueEnabled();
7209 //*******************************************************************************
7211 MethodTableBuilder::AllocAndInitDictionary()
7213 STANDARD_VM_CONTRACT;
7215 // Allocate dictionary layout used by all compatible instantiations
7217 if (bmtGenerics->fSharedByGenericInstantiations && !bmtGenerics->fContainsGenericVariables)
7219 // We use the number of methods as a heuristic for the number of slots in the dictionary
7220 // attached to shared class method tables.
7221 // If there are no declared methods then we have no slots, and we will never do any token lookups
7224 // - Classes with a small number of methods (2-3) tend to be more likely to use new slots,
7225 // i.e. further methods tend to reuse slots from previous methods.
7226 // = treat all classes with only 2-3 methods as if they have an extra method.
7227 // - Classes with more generic parameters tend to use more slots.
7228 // = multiply by 1.5 for 2 params or more
7230 DWORD numMethodsAdjusted =
7231 (bmtMethod->dwNumDeclaredNonAbstractMethods == 0)
7233 : (bmtMethod->dwNumDeclaredNonAbstractMethods < 3)
7235 : bmtMethod->dwNumDeclaredNonAbstractMethods;
7237 _ASSERTE(bmtGenerics->GetNumGenericArgs() != 0);
7238 DWORD nTypeFactorBy2 = (bmtGenerics->GetNumGenericArgs() == 1)
7242 DWORD estNumTypeSlots = (numMethodsAdjusted * nTypeFactorBy2 + 2) / 3;
7243 // estNumTypeSlots should fit in a WORD as long as we maintain the current
7244 // limit on the number of methods in a type (approx 2^16).
7245 _ASSERTE(FitsIn<WORD>(estNumTypeSlots));
7246 WORD numTypeSlots = static_cast<WORD>(estNumTypeSlots);
7248 if (numTypeSlots > 0)
7250 // Dictionary layout is an optional field on EEClass, so ensure the optional field descriptor has
7252 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
7253 GetHalfBakedClass()->SetDictionaryLayout(DictionaryLayout::Allocate(numTypeSlots, bmtAllocator, m_pAllocMemTracker));
7259 //*******************************************************************************
7261 // Used by BuildMethodTable
7263 // Compute the set of interfaces which are equivalent. Duplicates in the interface map
7264 // will be placed into different equivalence sets unless they participate in type equivalence.
7265 // This is a bit odd, but it turns out we only need to know about equivalence classes if
7266 // there is type equivalence involved in the interface, and not detecting, or detecting equivalence
7267 // in other cases does not result in differing behavior.
7269 // By restricting the reasons for having equivalence matches, we reduce the algorithm from one which
7270 // is O(n*n) best case to an algorithm which will typically execute something more like O(m*n) best case time
7271 // where m is the number of generic interface (although still n*n in worst case). The assumption is that equivalent
7272 // and generic interfaces are relatively rare.
7274 MethodTableBuilder::ComputeInterfaceMapEquivalenceSet()
7276 STANDARD_VM_CONTRACT;
7278 UINT32 nextEquivalenceSet = 1;
7280 for (DWORD dwCurInterface = 0;
7281 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7284 // Keep track of the current interface we are trying to calculate the equivalence set of
7285 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7286 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7287 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7288 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7290 UINT32 currentEquivalenceSet = 0;
7292 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7293 if (pCurItfMT->HasTypeEquivalence() || pCurItfMT->HasInstantiation())
7295 for (DWORD dwCurInterfaceCompare = 0;
7296 dwCurInterfaceCompare < dwCurInterface;
7297 dwCurInterfaceCompare++)
7299 // Keep track of the current interface we are trying to calculate the equivalence set of
7300 bmtInterfaceEntry * pCompareItfEntry = &bmtInterface->pInterfaceMap[dwCurInterfaceCompare];
7301 bmtRTType * pCompareItf = pCompareItfEntry->GetInterfaceType();
7302 MethodTable * pCompareItfMT = pCompareItf->GetMethodTable();
7303 const Substitution * pCompareItfSubst = &pCompareItf->GetSubstitution();
7305 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7306 if (pCompareItfMT->HasTypeEquivalence() || pCompareItfMT->HasInstantiation())
7308 if (MetaSig::CompareTypeDefsUnderSubstitutions(pCurItfMT,
7314 currentEquivalenceSet = pCompareItfEntry->GetInterfaceEquivalenceSet();
7315 // Use the equivalence set of the interface map entry we just found
7316 pCurItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7317 // Update the interface map entry we just found to indicate that it is part of an equivalence
7318 // set with multiple entries.
7319 pCompareItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7326 // If we did not find an equivalent interface above, use the next available equivalence set indicator
7327 if (currentEquivalenceSet == 0)
7329 pCurItfEntry->SetInterfaceEquivalenceSet(nextEquivalenceSet, false);
7330 nextEquivalenceSet++;
7335 //*******************************************************************************
7337 // Used by PlaceInterfaceMethods
7339 // Given an interface in our interface map, and a particular method on that interface, place
7340 // a method from the parent types implementation of an equivalent interface into that method
7341 // slot. Used by PlaceInterfaceMethods to make equivalent interface implementations have the
7342 // same behavior as if the parent interface was implemented on this type instead of an equivalent interface.
7344 // This logic is used in situations such as below. I and I' are equivalent interfaces
7348 // {void I.Method() { } }
7349 // interface IOther : I' {}
7350 // class Derived : IOther
7351 // { virtual void Method() {}}
7353 // We should Map I'.Method to Base.Method, not Derived.Method
7357 // { virtual void Method() }
7358 // interface IOther : I' {}
7359 // class Derived : IOther
7360 // { virtual void Method() {}}
7362 // We should map I'.Method to Base.Method, not Derived.Method
7365 // {void I.Method() { } }
7366 // class Derived : I'
7369 // We should Map I'.Method to Base.Method, and not throw TypeLoadException
7371 #ifdef FEATURE_COMINTEROP
7373 MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(
7374 bmtInterfaceEntry::InterfaceSlotIterator & itfSlotIt,
7375 bmtInterfaceEntry * pCurItfEntry,
7376 DispatchMapTypeID ** prgInterfaceDispatchMapTypeIDs,
7377 DWORD dwCurInterface)
7379 STANDARD_VM_CONTRACT;
7381 bmtRTMethod * pCurItfMethod = itfSlotIt->Decl().AsRTMethod();
7383 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7388 // For every equivalent interface entry that was actually implemented by parent, then look at equivalent method slot on that entry
7389 // and if it matches and has a slot implementation, then record and continue
7390 for (DWORD dwEquivalentInterface = 0;
7391 (dwEquivalentInterface < bmtInterface->dwInterfaceMapSize) && (itfSlotIt->Impl() == INVALID_SLOT_INDEX);
7392 dwEquivalentInterface++)
7394 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7395 bmtRTType * pEquivItf = pEquivItfEntry->GetInterfaceType();
7396 MethodTable * pEquivItfMT = pEquivItf->GetMethodTable();
7397 const Substitution * pEquivItfSubst = &pEquivItf->GetSubstitution();
7398 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7403 if (!pEquivItfEntry->IsImplementedByParent())
7405 // Not implemented by parent
7409 WORD slot = static_cast<WORD>(itfSlotIt.CurrentIndex());
7410 BOOL fFound = FALSE;
7412 // Determine which slot on the equivalent interface would map to the slot we are attempting to fill
7413 // in with an implementation.
7414 WORD otherMTSlot = GetEquivalentMethodSlot(pCurItfEntry->GetInterfaceType()->GetMethodTable(),
7415 pEquivItfEntry->GetInterfaceType()->GetMethodTable(),
7421 UINT32 cInterfaceDuplicates;
7422 if (*prgInterfaceDispatchMapTypeIDs == NULL)
7424 *prgInterfaceDispatchMapTypeIDs =
7425 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7428 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7429 ComputeDispatchMapTypeIDs(
7432 *prgInterfaceDispatchMapTypeIDs,
7433 bmtInterface->dwInterfaceMapSize,
7434 &cInterfaceDuplicates);
7435 // There cannot be more duplicates than number of interfaces
7436 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7437 _ASSERTE(cInterfaceDuplicates > 0);
7439 // NOTE: This override does not cache the resulting MethodData object
7440 MethodTable::MethodDataWrapper hParentData;
7441 hParentData = MethodTable::GetMethodData(
7442 *prgInterfaceDispatchMapTypeIDs,
7443 cInterfaceDuplicates,
7445 GetParentMethodTable());
7447 SLOT_INDEX slotIndex = static_cast<SLOT_INDEX>
7448 (hParentData->GetImplSlotNumber(static_cast<UINT32>(otherMTSlot)));
7450 // Interface is implemented on parent abstract type and this particular slot was not implemented
7451 if (slotIndex == INVALID_SLOT_INDEX)
7456 bmtMethodSlot & parentSlotImplementation = (*bmtParent->pSlotTable)[slotIndex];
7457 bmtMethodHandle & parentImplementation = parentSlotImplementation.Impl();
7459 // Check to verify that the equivalent slot on the equivalent interface actually matches the method
7460 // on the current interface. If not, then the slot is not a match, and we should search other interfaces
7461 // for an implementation of the method.
7462 if (!MethodSignature::SignaturesEquivalent(pCurItfMethod->GetMethodSignature(), parentImplementation.GetMethodSignature(), FALSE))
7467 itfSlotIt->Impl() = slotIndex;
7469 MethodDesc * pMD = hParentData->GetImplMethodDesc(static_cast<UINT32>(otherMTSlot));
7471 DispatchMapTypeID dispatchMapTypeID =
7472 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7473 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7475 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7480 } // MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot
7481 #endif // FEATURE_COMINTEROP
7483 //*******************************************************************************
7485 // Used by BuildMethodTable
7488 // If we are a class, then there may be some unplaced vtable methods (which are by definition
7489 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
7490 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
7491 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
7492 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
7493 // map for all interfaces as they are placed.
7495 // If we are an interface, then all methods are already placed. Fill out the interface map for
7496 // interfaces as they are placed.
7498 // BEHAVIOUR (based on Partition II: 11.2, not including MethodImpls)
7499 // C is current class, P is a parent class, I is the interface being implemented
7501 // FOREACH interface I implemented by this class C
7502 // FOREACH method I::M
7503 // IF I is EXPLICITLY implemented by C
7504 // IF some method C::M matches I::M
7505 // USE C::M as implementation for I::M
7506 // ELIF we inherit a method P::M that matches I::M
7507 // USE P::M as implementation for I::M
7510 // IF I::M lacks implementation
7511 // IF some method C::M matches I::M
7512 // USE C::M as implementation for I::M
7513 // ELIF we inherit a method P::M that matches I::M
7514 // USE P::M as implementation for I::M
7515 // ELIF I::M was implemented by the parent type with method Parent::M
7516 // USE Parent::M for the implementation of I::M // VSD does this by default if we really
7517 // // implemented I on the parent type, but
7518 // // equivalent interfaces need to make this
7528 MethodTableBuilder::PlaceInterfaceMethods()
7530 STANDARD_VM_CONTRACT;
7532 BOOL fParentInterface;
7533 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs = NULL;
7535 for (DWORD dwCurInterface = 0;
7536 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7539 // Default to being implemented by the current class
7540 fParentInterface = FALSE;
7542 // Keep track of the current interface we are trying to place
7543 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7544 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7545 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7546 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7549 // There are three reasons why an interface could be in the implementation list
7550 // 1. Inherited from parent
7551 // 2. Explicitly declared in the implements list
7552 // 3. Implicitly declared through the implements list of an explicitly declared interface
7554 // The reason these cases need to be distinguished is that an inherited interface that is
7555 // also explicitly redeclared in the implements list must be fully reimplemented using the
7556 // virtual methods of this type (thereby using matching methods in this type that may have
7557 // a different slot than an inherited method, but hidden it by name & sig); however all
7558 // implicitly redeclared interfaces should not be fully reimplemented if they were also
7559 // inherited from the parent.
7562 // interface I1 : I2
7566 // In this example I1 must be fully reimplemented on B, but B can inherit the implementation
7570 if (pCurItfEntry->IsImplementedByParent())
7572 if (!pCurItfEntry->IsDeclaredOnType())
7574 fParentInterface = TRUE;
7578 bool fEquivalentInterfaceImplementedByParent = pCurItfEntry->IsImplementedByParent();
7579 bool fEquivalentInterfaceDeclaredOnType = pCurItfEntry->IsDeclaredOnType();
7581 if (pCurItfEntry->InEquivalenceSetWithMultipleEntries())
7583 for (DWORD dwEquivalentInterface = 0;
7584 dwEquivalentInterface < bmtInterface->dwInterfaceMapSize;
7585 dwEquivalentInterface++)
7587 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7588 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7593 if (pEquivItfEntry->IsImplementedByParent())
7595 fEquivalentInterfaceImplementedByParent = true;
7597 if (pEquivItfEntry->IsDeclaredOnType())
7599 fEquivalentInterfaceDeclaredOnType = true;
7602 if (fEquivalentInterfaceDeclaredOnType && fEquivalentInterfaceImplementedByParent)
7607 bool fParentInterfaceEquivalent = fEquivalentInterfaceImplementedByParent && !fEquivalentInterfaceDeclaredOnType;
7609 CONSISTENCY_CHECK(!fParentInterfaceEquivalent || HasParent());
7611 if (fParentInterfaceEquivalent)
7613 // In the case the fParentInterface is TRUE, virtual overrides are enough and the interface
7614 // does not have to be explicitly (re)implemented. The only exception is if the parent is
7615 // abstract, in which case an inherited interface may not be fully implemented yet.
7616 // This is an optimization that allows us to skip the more expensive slot filling in below.
7617 // Note that the check here is for fParentInterface and not for fParentInterfaceEquivalent.
7618 // This is necessary as if the interface is not actually implemented on the parent type we will
7619 // need to fill in the slot table below.
7620 if (fParentInterface && !GetParentMethodTable()->IsAbstract())
7626 // We will reach here in two cases.
7627 // 1 .The parent is abstract and the interface has been declared on the parent,
7628 // and possibly partially implemented, so we need to populate the
7629 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7631 // 2 .The the interface has not been declared on the parent,
7632 // but an equivalent interface has been. So we need to populate the
7633 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7634 // information from one of the parent equivalent interfaces. We may or may not
7635 // find implementations for all of the methods on the interface on the parent type.
7636 // The parent type may or may not be abstract.
7638 MethodTable::MethodDataWrapper hParentData;
7639 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
7641 if (rgInterfaceDispatchMapTypeIDs == NULL)
7643 rgInterfaceDispatchMapTypeIDs =
7644 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7647 if (pCurItfEntry->IsImplementedByParent())
7649 UINT32 cInterfaceDuplicates;
7650 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7651 ComputeDispatchMapTypeIDs(
7654 rgInterfaceDispatchMapTypeIDs,
7655 bmtInterface->dwInterfaceMapSize,
7656 &cInterfaceDuplicates);
7657 // There cannot be more duplicates than number of interfaces
7658 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7659 _ASSERTE(cInterfaceDuplicates > 0);
7661 //#InterfaceMap_UseParentInterfaceImplementations
7662 // We rely on the fact that interface map of parent type is subset of this type (incl.
7663 // duplicates), see code:#InterfaceMap_SupersetOfParent
7664 // NOTE: This override does not cache the resulting MethodData object
7665 hParentData = MethodTable::GetMethodData(
7666 rgInterfaceDispatchMapTypeIDs,
7667 cInterfaceDuplicates,
7669 GetParentMethodTable());
7671 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7672 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7673 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7675 itfSlotIt->Impl() = static_cast<SLOT_INDEX>
7676 (hParentData->GetImplSlotNumber(static_cast<UINT32>(itfSlotIt.CurrentIndex())));
7679 #ifdef FEATURE_COMINTEROP
7682 // Iterate through the methods on the interface, and if they have a slot which was filled in
7683 // on an equivalent interface inherited from the parent fill in the appropriate slot.
7684 // This code path is only used when there is an implicit implementation of an interface
7685 // that was not implemented on a parent type, but there was an equivalent interface implemented
7686 // on a parent type.
7687 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7688 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7689 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7691 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7694 #endif // FEATURE_COMINTEROP
7698 // For each method declared in this interface
7699 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7700 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7701 for (; !itfSlotIt.AtEnd(); ++itfSlotIt)
7703 if (fParentInterfaceEquivalent)
7705 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7706 { // If this interface is not explicitly declared on this class, and the interface slot has already been
7707 // given an implementation, then the only way to provide a new implementation is through an override
7708 // or through a MethodImpl. This is necessary in addition to the continue statement before this for
7709 // loop because an abstract interface can still have a partial implementation and it is necessary to
7710 // skip those interface slots that have already been satisfied.
7715 BOOL fFoundMatchInBuildingClass = FALSE;
7716 bmtInterfaceSlotImpl & curItfSlot = *itfSlotIt;
7717 bmtRTMethod * pCurItfMethod = curItfSlot.Decl().AsRTMethod();
7718 const MethodSignature & curItfMethodSig = pCurItfMethod->GetMethodSignature();
7721 // First, try to find the method explicitly declared in our class
7724 DeclaredMethodIterator methIt(*this);
7725 while (methIt.Next())
7727 // Note that non-publics can legally be exposed via an interface, but only
7728 // through methodImpls.
7729 if (IsMdVirtual(methIt.Attrs()) && IsMdPublic(methIt.Attrs()))
7732 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(methIt.Name()))
7733 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", methIt.Name()));
7736 if (pCurItfMethod->GetMethodSignature().Equivalent(methIt->GetMethodSignature()))
7738 fFoundMatchInBuildingClass = TRUE;
7739 curItfSlot.Impl() = methIt->GetSlotIndex();
7741 DispatchMapTypeID dispatchMapTypeID =
7742 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7743 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7745 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7746 methIt->GetMethodDesc(),
7752 } // end ... try to find method
7755 // The ECMA CLR spec states that a type will inherit interface implementations
7756 // and that explicit re-declaration of an inherited interface will try to match
7757 // only newslot methods with methods in the re-declared interface (note that
7758 // this also takes care of matching against unsatisfied interface methods in
7759 // the abstract parent type scenario).
7761 // So, if the interface was not declared on a parent and we haven't found a
7762 // newslot method declared on this type as a match, search all remaining
7763 // public virtual methods (including overrides declared on this type) for a
7766 // Please see bug VSW577403 and VSW593884 for details of this breaking change.
7768 if (!fFoundMatchInBuildingClass &&
7769 !fEquivalentInterfaceImplementedByParent)
7773 // Iterate backward through the parent's method table. This is important to
7774 // find the most derived method.
7775 bmtParentInfo::Iterator parentMethodIt = bmtParent->IterateSlots();
7776 parentMethodIt.ResetToEnd();
7777 while (parentMethodIt.Prev())
7779 bmtRTMethod * pCurParentMethod = parentMethodIt->Decl().AsRTMethod();
7780 DWORD dwAttrs = pCurParentMethod->GetDeclAttrs();
7781 if (!IsMdVirtual(dwAttrs) || !IsMdPublic(dwAttrs))
7782 { // Only match mdPublic mdVirtual methods for interface implementation
7786 if (curItfMethodSig.Equivalent(pCurParentMethod->GetMethodSignature()))
7788 fFoundMatchInBuildingClass = TRUE;
7789 curItfSlot.Impl() = pCurParentMethod->GetSlotIndex();
7791 DispatchMapTypeID dispatchMapTypeID =
7792 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7793 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7795 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7796 pCurParentMethod->GetMethodDesc(),
7801 } // end ... try to find parent method
7805 // For type equivalent interfaces that had an equivalent interface implemented by their parent
7806 // and where the previous logic to fill in the method based on the virtual mappings on the type have
7807 // failed, we should attempt to get the mappings from the equivalent interfaces declared on parent types
7808 // of the type we are currently building.
7809 #ifdef FEATURE_COMINTEROP
7810 if (!fFoundMatchInBuildingClass && fEquivalentInterfaceImplementedByParent && !pCurItfEntry->IsImplementedByParent())
7812 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7817 } // MethodTableBuilder::PlaceInterfaceMethods
7820 //*******************************************************************************
7822 // Used by BuildMethodTable
7824 // Place static fields
7826 VOID MethodTableBuilder::PlaceRegularStaticFields()
7828 STANDARD_VM_CONTRACT;
7832 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing statics for %s\n", this->GetDebugClassName()));
7835 // Place gc refs and value types first, as they need to have handles created for them.
7836 // (Placing them together allows us to easily create the handles when Restoring the class,
7837 // and when initializing new DLS for the class.)
7840 DWORD dwCumulativeStaticFieldPos = 0 ;
7841 DWORD dwCumulativeStaticGCFieldPos = 0;
7842 DWORD dwCumulativeStaticBoxFieldPos = 0;
7844 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7845 // guaranteed to be aligned in ModuleStaticsInfo
7846 bmtFP->NumRegularStaticFieldsOfSize[LOG2_PTRSIZE] -=
7847 bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7849 // Place fields, largest first, padding so that each group is aligned to its natural size
7850 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7852 // Fields of this size start at the next available location
7853 bmtFP->RegularStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7854 dwCumulativeStaticFieldPos += (bmtFP->NumRegularStaticFieldsOfSize[i] << i);
7856 // Reset counters for the loop after this one
7857 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
7861 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7862 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7864 DWORD dwNumHandleStatics = bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7865 if (!FitsIn<WORD>(dwNumHandleStatics))
7867 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7869 SetNumHandleRegularStatics(static_cast<WORD>(dwNumHandleStatics));
7871 if (!FitsIn<WORD>(bmtFP->NumRegularStaticGCBoxedFields))
7873 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7875 SetNumBoxedRegularStatics(static_cast<WORD>(bmtFP->NumRegularStaticGCBoxedFields));
7877 // Tell the module to give us the offsets we'll be using and commit space for us
7879 DWORD dwNonGCOffset, dwGCOffset;
7880 GetModule()->GetOffsetsForRegularStaticData(bmtInternal->pType->GetTypeDefToken(),
7881 bmtProp->fDynamicStatics,
7882 GetNumHandleRegularStatics(), dwCumulativeStaticFieldPos,
7883 &dwGCOffset, &dwNonGCOffset);
7885 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7886 dwCumulativeStaticGCFieldPos = bmtFP->NumRegularStaticGCBoxedFields<<LOG2_PTRSIZE;
7888 FieldDesc *pFieldDescList = GetApproxFieldDescListRaw();
7889 // Place static fields
7890 for (i = 0; i < bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields; i++)
7892 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields+i];
7893 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7894 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7898 case FIELD_OFFSET_UNPLACED_GC_PTR:
7899 // Place GC reference static field
7900 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7901 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7902 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset()));
7906 case FIELD_OFFSET_VALUE_CLASS:
7907 // Place boxed GC reference static field
7908 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7909 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7910 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset()));
7914 case FIELD_OFFSET_UNPLACED:
7915 // Place non-GC static field
7916 pCurField->SetOffset(bmtFP->RegularStaticFieldStart[dwLog2FieldSize] +
7917 (bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7919 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
7920 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset()));
7928 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset()));
7931 if (bmtProp->fDynamicStatics)
7933 _ASSERTE(dwNonGCOffset == 0 || // no statics at all
7934 dwNonGCOffset == OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob); // We need space to point to the GC statics
7935 bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos;
7939 bmtProp->dwNonGCRegularStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7941 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCRegularStaticFieldBytes));
7945 VOID MethodTableBuilder::PlaceThreadStaticFields()
7947 STANDARD_VM_CONTRACT;
7951 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing ThreadStatics for %s\n", this->GetDebugClassName()));
7954 // Place gc refs and value types first, as they need to have handles created for them.
7955 // (Placing them together allows us to easily create the handles when Restoring the class,
7956 // and when initializing new DLS for the class.)
7959 DWORD dwCumulativeStaticFieldPos = 0 ;
7960 DWORD dwCumulativeStaticGCFieldPos = 0;
7961 DWORD dwCumulativeStaticBoxFieldPos = 0;
7963 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7964 // guaranteed to be aligned in ModuleStaticsInfo
7965 bmtFP->NumThreadStaticFieldsOfSize[LOG2_PTRSIZE] -=
7966 bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7968 // Place fields, largest first, padding so that each group is aligned to its natural size
7969 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7971 // Fields of this size start at the next available location
7972 bmtFP->ThreadStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7973 dwCumulativeStaticFieldPos += (bmtFP->NumThreadStaticFieldsOfSize[i] << i);
7975 // Reset counters for the loop after this one
7976 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
7980 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7981 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7983 DWORD dwNumHandleStatics = bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7984 if (!FitsIn<WORD>(dwNumHandleStatics))
7986 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7989 SetNumHandleThreadStatics(static_cast<WORD>(dwNumHandleStatics));
7991 if (!FitsIn<WORD>(bmtFP->NumThreadStaticGCBoxedFields))
7993 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7996 SetNumBoxedThreadStatics(static_cast<WORD>(bmtFP->NumThreadStaticGCBoxedFields));
7998 // Tell the module to give us the offsets we'll be using and commit space for us
8000 DWORD dwNonGCOffset, dwGCOffset;
8002 GetModule()->GetOffsetsForThreadStaticData(bmtInternal->pType->GetTypeDefToken(),
8003 bmtProp->fDynamicStatics,
8004 GetNumHandleThreadStatics(), dwCumulativeStaticFieldPos,
8005 &dwGCOffset, &dwNonGCOffset);
8007 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
8008 dwCumulativeStaticGCFieldPos = bmtFP->NumThreadStaticGCBoxedFields<<LOG2_PTRSIZE;
8010 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
8011 // Place static fields
8012 for (i = 0; i < bmtEnumFields->dwNumThreadStaticFields; i++)
8014 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + i];
8015 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
8016 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
8020 case FIELD_OFFSET_UNPLACED_GC_PTR:
8021 // Place GC reference static field
8022 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
8023 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
8024 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset()));
8028 case FIELD_OFFSET_VALUE_CLASS:
8029 // Place boxed GC reference static field
8030 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
8031 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
8032 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset()));
8036 case FIELD_OFFSET_UNPLACED:
8037 // Place non-GC static field
8038 pCurField->SetOffset(bmtFP->ThreadStaticFieldStart[dwLog2FieldSize] +
8039 (bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
8041 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
8042 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset()));
8050 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset()));
8053 if (bmtProp->fDynamicStatics)
8055 _ASSERTE(dwNonGCOffset == 0 || // no thread statics at all
8056 dwNonGCOffset == OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob); // We need space to point to the GC statics
8057 bmtProp->dwNonGCThreadStaticFieldBytes = dwCumulativeStaticFieldPos;
8061 bmtProp->dwNonGCThreadStaticFieldBytes = 0; // Non dynamics shouldnt be using this
8063 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: ThreadStatic field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCThreadStaticFieldBytes));
8066 //*******************************************************************************
8068 // Used by BuildMethodTable
8070 // Place instance fields
8072 VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCache)
8074 STANDARD_VM_CONTRACT;
8079 //===============================================================
8080 // BEGIN: Place instance fields
8081 //===============================================================
8083 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
8084 DWORD dwCumulativeInstanceFieldPos;
8086 bool isAllGCPointers = true;
8088 // Instance fields start right after the parent
8091 MethodTable* pParentMT = GetParentMethodTable();
8092 if (pParentMT->HasLayout() && pParentMT->GetLayoutInfo()->IsZeroSized())
8094 // If the parent type has sequential/explicit layout and is "zero sized"
8095 // then we don't want to use the actual class size here.
8096 // That includes an extra byte that isn't actually used, so we shouldn't
8098 dwCumulativeInstanceFieldPos = 0;
8102 dwCumulativeInstanceFieldPos = pParentMT->GetNumInstanceFieldBytes();
8105 if (pParentMT->GetNumInstanceFields() != 0 && !pParentMT->IsAllGCPointers())
8107 isAllGCPointers = false;
8112 dwCumulativeInstanceFieldPos = 0;
8115 DWORD dwOffsetBias = 0;
8116 #ifdef FEATURE_64BIT_ALIGNMENT
8117 // On platforms where the alignment of 64-bit primitives is a requirement (but we're not guaranteed
8118 // this implicitly by the GC) field offset 0 is actually not 8-byte aligned in reference classes.
8119 // That's because all such platforms are currently 32-bit and the 4-byte MethodTable pointer pushes us
8120 // out of alignment. Ideally we'd solve this by arranging to have the object header allocated at a
8121 // 4-byte offset from an 8-byte boundary, but this is difficult to achieve for objects allocated on
8122 // the large object heap (which actually requires headers to be 8-byte aligned).
8124 // So we adjust dwCumulativeInstanceFieldPos to account for the MethodTable* and our alignment
8125 // calculations will automatically adjust and add padding as necessary. We need to remove this
8126 // adjustment when setting the field offset in the field desc, however, since the rest of the system
8127 // expects that value to not include the MethodTable*.
8129 // This happens only for reference classes: value type field 0 really does lie at offset 0 for unboxed
8130 // value types. We deal with boxed value types by allocating their headers mis-aligned (luckily for us
8131 // value types can never get large enough to allocate on the LOH).
8132 if (!IsValueClass())
8134 dwOffsetBias = TARGET_POINTER_SIZE;
8135 dwCumulativeInstanceFieldPos += dwOffsetBias;
8137 #endif // FEATURE_64BIT_ALIGNMENT
8139 #ifdef FEATURE_READYTORUN
8140 if (NeedsAlignedBaseOffset())
8142 // READYTORUN: FUTURE: Use the minimum possible alignment, reduce padding when inheriting within same bubble
8143 DWORD dwAlignment = DATA_ALIGNMENT;
8144 #ifdef FEATURE_64BIT_ALIGNMENT
8145 if (GetHalfBakedClass()->IsAlign8Candidate())
8148 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
8150 #endif // FEATURE_READYTORUN
8152 // place small fields first if the parent have a number of field bytes that is not aligned
8153 if (!IS_ALIGNED(dwCumulativeInstanceFieldPos, DATA_ALIGNMENT))
8155 for (i = 0; i < MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++) {
8158 if (IS_ALIGNED(dwCumulativeInstanceFieldPos, size_t{ 1 } << (i + 1)))
8161 // check whether there are any bigger fields
8162 for (j = i + 1; j <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; j++) {
8163 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
8166 // nothing to gain if there are no bigger fields
8167 // (the subsequent loop will place fields from large to small fields)
8168 if (j > MAX_LOG2_PRIMITIVE_FIELD_SIZE)
8171 // check whether there are any small enough fields
8172 for (j = i; (signed int) j >= 0; j--) {
8173 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
8175 // TODO: since we will refuse to place GC references we should filter them out here.
8176 // otherwise the "back-filling" process stops completely.
8177 // (PlaceInstanceFields)
8178 // the following code would fix the issue (a replacement for the code above this comment):
8179 // if (bmtFP->NumInstanceFieldsOfSize[j] != 0 &&
8180 // (j != LOG2SLOT || bmtFP->NumInstanceFieldsOfSize[j] > bmtFP->NumInstanceGCPointerFields))
8186 // nothing to play with if there are no smaller fields
8187 if ((signed int) j < 0)
8189 // eventually go back and use the smaller field as filling
8192 CONSISTENCY_CHECK(bmtFP->NumInstanceFieldsOfSize[i] != 0);
8194 j = bmtFP->FirstInstanceFieldOfSize[i];
8196 // Avoid reordering of gcfields
8197 if (i == LOG2SLOT) {
8198 for ( ; j < bmtEnumFields->dwNumInstanceFields; j++) {
8199 if ((pFieldDescList[j].GetOffset() == FIELD_OFFSET_UNPLACED) &&
8200 ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i))
8204 // out of luck - can't reorder gc fields
8205 if (j >= bmtEnumFields->dwNumInstanceFields)
8210 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, size_t{ 1 } << i);
8212 pFieldDescList[j].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
8213 dwCumulativeInstanceFieldPos += (1 << i);
8215 // We've placed this field now, so there is now one less of this size field to place
8216 if (--bmtFP->NumInstanceFieldsOfSize[i] == 0)
8219 // We are done in this round if we haven't picked the first field
8220 if (bmtFP->FirstInstanceFieldOfSize[i] != j)
8223 // Update FirstInstanceFieldOfSize[i] to point to the next such field
8224 for (j = j+1; j < bmtEnumFields->dwNumInstanceFields; j++)
8226 // The log of the field size is stored in the method table
8227 if ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i)
8229 bmtFP->FirstInstanceFieldOfSize[i] = j;
8233 _ASSERTE(j < bmtEnumFields->dwNumInstanceFields);
8237 // Place fields, largest first
8238 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
8240 if (bmtFP->NumInstanceFieldsOfSize[i] == 0)
8243 // Align instance fields if we aren't already
8244 #if defined(TARGET_X86) && defined(UNIX_X86_ABI)
8245 DWORD dwDataAlignment = min(1 << i, DATA_ALIGNMENT);
8247 DWORD dwDataAlignment = 1 << i;
8249 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwDataAlignment);
8251 // Fields of this size start at the next available location
8252 bmtFP->InstanceFieldStart[i] = dwCumulativeInstanceFieldPos;
8253 dwCumulativeInstanceFieldPos += (bmtFP->NumInstanceFieldsOfSize[i] << i);
8255 // Reset counters for the loop after this one
8256 bmtFP->NumInstanceFieldsOfSize[i] = 0;
8260 // Make corrections to reserve space for GC Pointer Fields
8262 // The GC Pointers simply take up the top part of the region associated
8263 // with fields of that size (GC pointers can be 64 bit on certain systems)
8264 if (bmtFP->NumInstanceGCPointerFields)
8266 bmtFP->GCPointerFieldStart = bmtFP->InstanceFieldStart[LOG2SLOT] - dwOffsetBias;
8267 bmtFP->InstanceFieldStart[LOG2SLOT] = bmtFP->InstanceFieldStart[LOG2SLOT] + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT);
8268 bmtFP->NumInstanceGCPointerFields = 0; // reset to zero here, counts up as pointer slots are assigned below
8271 // Place instance fields - be careful not to place any already-placed fields
8272 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8274 DWORD dwFieldSize = (DWORD)(DWORD_PTR&)pFieldDescList[i].m_pMTOfEnclosingClass;
8277 dwOffset = pFieldDescList[i].GetOffset();
8279 // Don't place already-placed fields
8280 if ((dwOffset == FIELD_OFFSET_UNPLACED || dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR || dwOffset == FIELD_OFFSET_VALUE_CLASS))
8282 if (dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR)
8284 pFieldDescList[i].SetOffset(bmtFP->GCPointerFieldStart + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT));
8285 bmtFP->NumInstanceGCPointerFields++;
8287 else if (pFieldDescList[i].IsByValue() == FALSE) // it's a regular field
8289 pFieldDescList[i].SetOffset(bmtFP->InstanceFieldStart[dwFieldSize] + (bmtFP->NumInstanceFieldsOfSize[dwFieldSize] << dwFieldSize) - dwOffsetBias);
8290 bmtFP->NumInstanceFieldsOfSize[dwFieldSize]++;
8295 DWORD dwNumGCPointerSeries;
8296 // Save Number of pointer series
8297 if (bmtFP->NumInstanceGCPointerFields)
8298 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries + 1;
8300 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries;
8302 bool containsGCPointers = bmtFP->NumInstanceGCPointerFields > 0;
8303 // Place by value class fields last
8304 // Update the number of GC pointer series
8305 // Calculate largest alignment requirement
8306 int largestAlignmentRequirement = 1;
8307 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8309 if (pFieldDescList[i].IsByValue())
8311 MethodTable * pByValueMT = pByValueClassCache[i];
8313 #if !defined(TARGET_64BIT) && (DATA_ALIGNMENT > 4)
8314 if (pByValueMT->GetNumInstanceFieldBytes() >= DATA_ALIGNMENT)
8316 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, DATA_ALIGNMENT);
8317 largestAlignmentRequirement = max(largestAlignmentRequirement, DATA_ALIGNMENT);
8320 #elif defined(FEATURE_64BIT_ALIGNMENT)
8321 if (pByValueMT->RequiresAlign8())
8323 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, 8);
8324 largestAlignmentRequirement = max(largestAlignmentRequirement, 8);
8327 #endif // FEATURE_64BIT_ALIGNMENT
8328 if (pByValueMT->ContainsPointers())
8330 // this field type has GC pointers in it, which need to be pointer-size aligned
8331 // so do this if it has not been done already
8332 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, TARGET_POINTER_SIZE);
8333 largestAlignmentRequirement = max(largestAlignmentRequirement, TARGET_POINTER_SIZE);
8334 containsGCPointers = true;
8338 int fieldAlignmentRequirement = pByValueMT->GetFieldAlignmentRequirement();
8339 largestAlignmentRequirement = max(largestAlignmentRequirement, fieldAlignmentRequirement);
8340 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, fieldAlignmentRequirement);
8343 pFieldDescList[i].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
8344 dwCumulativeInstanceFieldPos += pByValueMT->GetNumInstanceFieldBytes();
8346 if (pByValueMT->ContainsPointers())
8348 // Add pointer series for by-value classes
8349 dwNumGCPointerSeries += (DWORD)CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
8352 if (!pByValueMT->ContainsPointers() || !pByValueMT->IsAllGCPointers())
8354 isAllGCPointers = false;
8359 // non-value-type fields always require pointer alignment
8360 // This does not account for types that are marked IsAlign8Candidate due to 8-byte fields
8361 // but that is explicitly handled when we calculate the final alignment for the type.
8362 largestAlignmentRequirement = max(largestAlignmentRequirement, TARGET_POINTER_SIZE);
8364 if (!pFieldDescList[i].IsObjRef())
8366 isAllGCPointers = false;
8372 DWORD dwNumInstanceFieldBytes = dwCumulativeInstanceFieldPos - dwOffsetBias;
8376 // Like C++ we enforce that there can be no 0 length structures.
8377 // Thus for a value class with no fields, we 'pad' the length to be 1
8378 if (dwNumInstanceFieldBytes == 0)
8380 dwNumInstanceFieldBytes = 1;
8381 isAllGCPointers = false;
8384 // The JITs like to copy full machine words,
8385 // so if the size is bigger than a void* round it up to minAlign
8386 // and if the size is smaller than void* round it up to next power of two
8389 #ifdef FEATURE_64BIT_ALIGNMENT
8390 if (GetHalfBakedClass()->IsAlign8Candidate()) {
8394 #endif // FEATURE_64BIT_ALIGNMENT
8395 if (dwNumInstanceFieldBytes > TARGET_POINTER_SIZE) {
8396 minAlign = containsGCPointers ? TARGET_POINTER_SIZE : (unsigned)largestAlignmentRequirement;
8400 while (minAlign < dwNumInstanceFieldBytes)
8404 if (minAlign != min(dwNumInstanceFieldBytes, TARGET_POINTER_SIZE))
8406 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
8407 GetHalfBakedClass()->GetOptionalFields()->m_requiredFieldAlignment = (BYTE)minAlign;
8408 GetHalfBakedClass()->SetHasCustomFieldAlignment();
8411 dwNumInstanceFieldBytes = (dwNumInstanceFieldBytes + minAlign-1) & ~(minAlign-1);
8414 if (dwNumInstanceFieldBytes > FIELD_OFFSET_LAST_REAL_OFFSET) {
8415 BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
8418 if (bmtFP->NumInlineArrayElements > 1)
8420 INT64 extendedSize = (INT64)dwNumInstanceFieldBytes * (INT64)bmtFP->NumInlineArrayElements;
8421 // limit the max size of array instance to 1MiB
8422 const INT64 maxSize = 1024 * 1024;
8423 if (extendedSize > maxSize)
8425 BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
8428 dwNumInstanceFieldBytes = (DWORD)extendedSize;
8430 if (pFieldDescList[0].IsByValue())
8432 dwNumGCPointerSeries *= bmtFP->NumInlineArrayElements;
8436 bmtFP->fIsAllGCPointers = isAllGCPointers && dwNumGCPointerSeries;
8437 if (bmtFP->fIsAllGCPointers)
8439 // we can use optimized form of GCDesc taking one serie
8440 dwNumGCPointerSeries = 1;
8443 bmtFP->NumInstanceFieldBytes = dwNumInstanceFieldBytes;
8445 bmtFP->NumGCPointerSeries = dwNumGCPointerSeries;
8447 //===============================================================
8448 // END: Place instance fields
8449 //===============================================================
8452 //*******************************************************************************
8453 // this accesses the field size which is temporarily stored in m_pMTOfEnclosingClass
8454 // during class loading. Don't use any other time
8455 DWORD MethodTableBuilder::GetFieldSize(FieldDesc *pFD)
8457 STATIC_CONTRACT_NOTHROW;
8458 STATIC_CONTRACT_GC_NOTRIGGER;
8459 STATIC_CONTRACT_FORBID_FAULT;
8461 // We should only be calling this while this class is being built.
8462 _ASSERTE(GetHalfBakedMethodTable() == 0);
8463 BAD_FORMAT_NOTHROW_ASSERT(! pFD->IsByValue() || HasExplicitFieldOffsetLayout());
8465 if (pFD->IsByValue())
8466 return (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass);
8467 return (1 << (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass));
8470 #ifdef UNIX_AMD64_ABI
8471 // checks whether the struct is enregisterable.
8472 void MethodTableBuilder::SystemVAmd64CheckForPassStructInRegister(MethodTable** pByValueClassCache)
8474 STANDARD_VM_CONTRACT;
8476 // This method should be called for valuetypes only
8477 _ASSERTE(IsValueClass());
8479 TypeHandle th(GetHalfBakedMethodTable());
8481 if (th.IsTypeDesc())
8483 // Not an enregisterable managed structure.
8487 DWORD totalStructSize = bmtFP->NumInstanceFieldBytes;
8489 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8490 // pass through stack
8491 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8493 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8494 this->GetDebugClassName(), totalStructSize));
8498 const bool useNativeLayout = false;
8499 // Iterate through the fields and make sure they meet requirements to pass in registers
8500 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8501 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout, pByValueClassCache))
8503 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassStructInRegister: struct %s is enregisterable\n",
8504 this->GetDebugClassName()));
8506 // All the above tests passed. It's registers passed struct!
8507 GetHalfBakedMethodTable()->SetRegPassedStruct();
8509 StoreEightByteClassification(&helper);
8513 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassStructInRegister: struct %s is _not_ enregisterable\n",
8514 this->GetDebugClassName()));
8518 // Store the eightbyte classification into the EEClass
8519 void MethodTableBuilder::StoreEightByteClassification(SystemVStructRegisterPassingHelper* helper)
8521 EEClass* eeClass = GetHalfBakedMethodTable()->GetClass();
8522 LoaderAllocator* pAllocator = MethodTableBuilder::GetLoaderAllocator();
8523 AllocMemTracker* pamTracker = MethodTableBuilder::GetMemTracker();
8524 EnsureOptionalFieldsAreAllocated(eeClass, pamTracker, pAllocator->GetLowFrequencyHeap());
8525 eeClass->SetEightByteClassification(helper->eightByteCount, helper->eightByteClassifications, helper->eightByteSizes);
8528 #endif // UNIX_AMD64_ABI
8530 //---------------------------------------------------------------------------------------
8532 // make sure that no object fields are overlapped incorrectly and define the
8533 // GC pointer series for the class. We are assuming that this class will always be laid out within
8534 // its enclosing class by the compiler in such a way that offset 0 will be the correct alignment
8535 // for object ref fields so we don't need to try to align it
8538 MethodTableBuilder::HandleExplicitLayout(
8539 MethodTable ** pByValueClassCache)
8541 STANDARD_VM_CONTRACT;
8543 // Instance slice size is the total size of an instance, and is calculated as
8544 // the field whose offset and size add to the greatest number.
8545 UINT instanceSliceSize = 0;
8548 for (i = 0; i < bmtMetaData->cFields; i++)
8550 FieldDesc *pFD = bmtMFDescs->ppFieldDescList[i];
8551 if (pFD == NULL || pFD->IsStatic())
8556 UINT fieldExtent = 0;
8557 if (!ClrSafeInt<UINT>::addition(pFD->GetOffset(), GetFieldSize(pFD), fieldExtent))
8559 BuildMethodTableThrowException(COR_E_OVERFLOW);
8562 if (fieldExtent > instanceSliceSize)
8564 instanceSliceSize = fieldExtent;
8569 PREFIX_ASSUME(sizeof(bmtFieldLayoutTag) == 1);
8570 bmtFieldLayoutTag *pFieldLayout = (bmtFieldLayoutTag*)qb.AllocThrows(instanceSliceSize * sizeof(bmtFieldLayoutTag));
8571 for (i=0; i < instanceSliceSize; i++)
8573 pFieldLayout[i] = empty;
8576 // Go through each field and look for invalid layout.
8577 // (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to
8578 // close security holes.)
8580 // This is what we implement:
8582 // 1. Verify that every OREF or BYREF is on a valid alignment.
8583 // 2. Verify that OREFs only overlap with other OREFs.
8584 // 3. Verify that BYREFs only overlap with other BYREFs.
8585 // 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
8586 // 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
8587 // 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
8589 bmtFieldLayoutTag emptyObject[TARGET_POINTER_SIZE];
8590 bmtFieldLayoutTag isObject[TARGET_POINTER_SIZE];
8591 bmtFieldLayoutTag isByRef[TARGET_POINTER_SIZE];
8592 for (i = 0; i < TARGET_POINTER_SIZE; i++)
8594 emptyObject[i] = empty;
8599 ExplicitClassTrust explicitClassTrust;
8601 UINT valueClassCacheIndex = ((UINT)(-1));
8603 FieldDesc * pFD = NULL;
8604 for (i = 0; i < bmtMetaData->cFields; i++)
8606 // Note about this loop body:
8608 // This loop is coded to make it as hard as possible to allow a field to be trusted when it shouldn't.
8610 // Every path in this loop body must lead to an explicit decision as to whether the field nonoverlaps,
8611 // overlaps in a verifiable fashion, overlaps in a nonverifiable fashion or overlaps in a completely illegal fashion.
8613 // It must call fieldTrust.SetTrust() with the appropriate result. If you don't call it, fieldTrust's destructor
8614 // will intentionally default to kNone and mark the entire class illegal.
8616 // If your result is anything but kNone (class is illegal), you must also explicitly "continue" the loop.
8617 // There is a "break" at end of this loop body that will abort the loop if you don't do this. And
8618 // if you don't finish iterating through all the fields, this function will automatically mark the entire
8619 // class illegal. This rule is a vestige of an earlier version of this function.
8621 // This object's dtor will aggregate the trust decision for this field into the trust level for the class as a whole.
8622 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8624 pFD = bmtMFDescs->ppFieldDescList[i];
8625 if (pFD == NULL || pFD->IsStatic())
8627 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverlaid);
8631 // "i" indexes all fields, valueClassCacheIndex indexes non-static fields only. Don't get them confused!
8632 valueClassCacheIndex++;
8634 CorElementType type = pFD->GetFieldType();
8635 if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
8637 // Check that the field is pointer aligned
8638 if ((pFD->GetOffset() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
8640 badOffset = pFD->GetOffset();
8641 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8643 // If we got here, OREF or BYREF field was not pointer aligned. THROW.
8647 // Determine which tag type we are working with.
8648 bmtFieldLayoutTag tag;
8649 SIZE_T tagBlockSize;
8651 if (CorTypeInfo::IsObjRef(type))
8653 tagBlockSize = sizeof(isObject);
8654 tagBlock = (void*)isObject;
8659 _ASSERTE(CorTypeInfo::IsByRef(type));
8660 tagBlockSize = sizeof(isByRef);
8661 tagBlock = (void*)isByRef;
8665 // Check if there is overlap with its own tag type
8666 if (memcmp((void *)&pFieldLayout[pFD->GetOffset()], tagBlock, tagBlockSize) == 0)
8668 // If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
8669 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8672 // check if typed layout is empty at this point
8673 if (memcmp((void *)&pFieldLayout[pFD->GetOffset()], (void *)emptyObject, sizeof(emptyObject)) == 0)
8675 // If we got here, this tag type is overlapping no other fields (yet).
8676 // Record that these bytes now contain the current tag type.
8677 memset((void *)&pFieldLayout[pFD->GetOffset()], tag, tagBlockSize);
8678 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverlaid);
8682 // If we got here, the tag overlaps something else. THROW.
8683 badOffset = pFD->GetOffset();
8684 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8690 if (!pFD->IsByValue())
8692 fieldSize = GetFieldSize(pFD);
8696 MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
8697 if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
8699 if ((pFD->GetOffset() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
8701 // If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
8702 badOffset = pFD->GetOffset();
8703 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8707 ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset()]);
8708 fieldTrust.SetTrust(trust);
8710 if (trust != ExplicitFieldTrust::kNone)
8716 // If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
8717 badOffset = pFD->GetOffset();
8722 // no pointers so fall through to do standard checking
8723 fieldSize = pByValueMT->GetNumInstanceFieldBytes();
8726 // If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
8727 // Look for any orefs or byrefs under this field
8728 bmtFieldLayoutTag* loc = NULL;
8729 bmtFieldLayoutTag* currOffset = pFieldLayout + pFD->GetOffset();
8730 bmtFieldLayoutTag* endOffset = currOffset + fieldSize;
8731 for (; currOffset < endOffset; ++currOffset)
8733 if (*currOffset == oref || *currOffset == byref)
8742 // If we have a nonoref in the range then we are doing an overlay
8743 if(memchr((void*)&pFieldLayout[pFD->GetOffset()], nonoref, fieldSize))
8745 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8749 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverlaid);
8751 memset((void*)&pFieldLayout[pFD->GetOffset()], nonoref, fieldSize);
8755 // If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
8756 // on top of an OREF/BYREF. THROW.
8757 badOffset = (UINT)(loc - pFieldLayout);
8758 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8760 // anything else is an error
8763 // We have to comment out this assert because otherwise, the compiler refuses to build because the _ASSERT is unreachable
8764 // (Thanks for nothing, compiler, that's what the assert is trying to enforce!) But the intent of the assert is correct.
8765 //_ASSERTE(!"You aren't supposed to be here. Some path inside the loop body did not execute an explicit break or continue.");
8768 // If we got here, some code above failed to execute an explicit "break" or "continue." This is a bug! To be safe,
8769 // we will put a catchall "break" here which will cause the typeload to abort (albeit with a probably misleading
8774 // We only break out of the loop above if we detected an error.
8775 if (i < bmtMetaData->cFields || !explicitClassTrust.IsLegal())
8777 ThrowFieldLayoutError(GetCl(),
8780 IDS_CLASSLOAD_EXPLICIT_LAYOUT);
8783 if (!explicitClassTrust.IsNonOverlaid())
8785 SetHasOverlaidFields();
8788 FindPointerSeriesExplicit(instanceSliceSize, pFieldLayout);
8790 // Fixup the offset to include parent as current offsets are relative to instance slice
8791 // Could do this earlier, but it's just easier to assume instance relative for most
8792 // of the earlier calculations
8794 // Instance fields start right after the parent
8795 S_UINT32 dwInstanceSliceOffset = S_UINT32(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0);
8796 if (bmtGCSeries->numSeries != 0)
8798 dwInstanceSliceOffset.AlignUp(TARGET_POINTER_SIZE);
8800 if (dwInstanceSliceOffset.IsOverflow())
8802 // addition overflow or cast truncation
8803 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8806 S_UINT32 numInstanceFieldBytes = dwInstanceSliceOffset + S_UINT32(instanceSliceSize);
8811 if (FAILED(GetMDImport()->GetClassTotalSize(GetCl(), &clstotalsize)))
8816 if (clstotalsize != 0)
8818 // size must be large enough to accommodate layout. If not, we use the layout size instead.
8819 if (!numInstanceFieldBytes.IsOverflow() && clstotalsize >= numInstanceFieldBytes.Value())
8821 numInstanceFieldBytes = S_UINT32(clstotalsize);
8826 // align up to the alignment requirements of the members of this value type.
8827 numInstanceFieldBytes.AlignUp(GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers);
8828 if (numInstanceFieldBytes.IsOverflow())
8830 // addition overflow or cast truncation
8831 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8835 if (!numInstanceFieldBytes.IsOverflow() && numInstanceFieldBytes.Value() == 0)
8837 // If we calculate a 0-byte size here, we should have also calculated a 0-byte size
8838 // in the initial layout algorithm.
8839 _ASSERTE(GetLayoutInfo()->IsZeroSized());
8840 numInstanceFieldBytes = S_UINT32(1);
8844 // The GC requires that all valuetypes containing orefs be sized to a multiple of TARGET_POINTER_SIZE.
8845 if (bmtGCSeries->numSeries != 0)
8847 numInstanceFieldBytes.AlignUp(TARGET_POINTER_SIZE);
8849 if (numInstanceFieldBytes.IsOverflow())
8851 // addition overflow or cast truncation
8852 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8855 // Set the total size
8856 bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes.Value();
8858 for (i = 0; i < bmtMetaData->cFields; i++)
8860 FieldDesc * pTempFD = bmtMFDescs->ppFieldDescList[i];
8861 if ((pTempFD == NULL) || pTempFD->IsStatic())
8865 HRESULT hr = pTempFD->SetOffset(pTempFD->GetOffset() + dwInstanceSliceOffset.Value());
8868 BuildMethodTableThrowException(hr, *bmtError);
8871 } // MethodTableBuilder::HandleExplicitLayout
8873 //*******************************************************************************
8874 // make sure that no object fields are overlapped incorrectly, returns the trust level
8875 /*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, bmtFieldLayoutTag *pFieldLayout)
8877 STANDARD_VM_CONTRACT;
8879 // ByRefLike types need to be checked for ByRef fields.
8880 if (pMT->IsByRefLike())
8881 return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);
8883 // Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
8884 // do know (a) vc is already consistent so don't need to check it's overlaps and
8885 // (b) size and location of all objectrefs. So build it by setting all non-oref
8886 // then fill in the orefs later if present.
8887 UINT fieldSize = pMT->GetNumInstanceFieldBytes();
8890 bmtFieldLayoutTag *vcLayout = (bmtFieldLayoutTag*) qb.AllocThrows(fieldSize * sizeof(bmtFieldLayoutTag));
8891 memset((void*)vcLayout, nonoref, fieldSize);
8893 // If the type contains pointers fill it out from the GC data
8894 if (pMT->ContainsPointers())
8896 // use pointer series to locate the orefs
8897 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
8898 CGCDescSeries *pSeries = map->GetLowestSeries();
8900 for (SIZE_T j = 0; j < map->GetNumSeries(); j++)
8902 CONSISTENCY_CHECK(pSeries <= map->GetHighestSeries());
8904 memset((void*)&vcLayout[pSeries->GetSeriesOffset() - OBJECT_SIZE], oref, pSeries->GetSeriesSize() + pMT->GetBaseSize());
8909 ExplicitClassTrust explicitClassTrust;
8910 for (UINT i=0; i < fieldSize; i++)
8912 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8914 if (vcLayout[i] == oref) {
8915 switch (pFieldLayout[i]) {
8918 pFieldLayout[i] = oref;
8919 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverlaid);
8922 // oref <--> nonoref
8924 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8929 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8933 _ASSERTE(!"Can't get here.");
8935 } else if (vcLayout[i] == nonoref) {
8936 switch (pFieldLayout[i]) {
8937 // nonoref <--> empty
8939 pFieldLayout[i] = nonoref;
8940 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverlaid);
8943 // nonoref <--> nonoref
8945 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8948 // nonoref <--> oref
8950 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8954 _ASSERTE(!"Can't get here.");
8957 _ASSERTE(!"Can't get here.");
8961 return explicitClassTrust.GetTrustLevel();
8965 //*******************************************************************************
8966 // make sure that no byref/object fields are overlapped, returns the trust level
8967 /*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, bmtFieldLayoutTag *pFieldLayout)
8969 STANDARD_VM_CONTRACT;
8970 _ASSERTE(pMT->IsByRefLike());
8972 ExplicitClassTrust explicitClassTrust;
8974 ExplicitFieldTrust::TrustLevel trust;
8975 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
8976 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
8978 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8979 int fieldStartIndex = pFD->GetOffset();
8981 if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
8983 MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
8984 trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
8986 else if (pFD->IsObjRef())
8988 _ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
8989 trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
8991 else if (pFD->IsByRef())
8993 _ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
8994 trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
8998 trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
9001 fieldTrust.SetTrust(trust);
9003 // Some invalid overlap was detected.
9004 if (trust == ExplicitFieldTrust::kNone)
9008 return explicitClassTrust.GetTrustLevel();
9011 //*******************************************************************************
9012 // Set the field's tag type and/or detect invalid overlap
9013 /*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(bmtFieldLayoutTag* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
9015 STANDARD_VM_CONTRACT;
9016 _ASSERTE(field != NULL);
9017 _ASSERTE(fieldSize != 0);
9018 _ASSERTE(tagType != empty);
9020 ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
9021 for (SIZE_T i = 0; i < fieldSize; ++i)
9023 if (field[i] == empty)
9025 // Nothing set for overlap, mark as requested.
9028 else if (field[i] == tagType)
9030 // Only a overlapped nonoref tag is verifiable, all others are simply legal.
9031 ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;
9033 // The ExplicitFieldTrust enum is ranked in descending order of trust.
9034 // We always take the computed minimum trust level.
9035 trust = min(trust, overlapTrust);
9039 // A non-equal overlap was detected. There is no trust for the type.
9040 trust = ExplicitFieldTrust::kNone;
9048 //*******************************************************************************
9049 void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
9050 bmtFieldLayoutTag *pFieldLayout)
9052 STANDARD_VM_CONTRACT;
9055 // Allocate a structure to track the series. We know that the worst case is a
9056 // ref-non-ref-non, and since only ref series are recorded and non-ref series
9057 // are skipped, the max number of series is total instance size / 2 / sizeof(ref).
9058 // But watch out for the case where we have e.g. an instanceSlizeSize of 4.
9059 DWORD sz = (instanceSliceSize + (2 * TARGET_POINTER_SIZE) - 1);
9060 bmtGCSeries->pSeries = new bmtGCSeriesInfo::Series[sz/2/ TARGET_POINTER_SIZE];
9062 bmtFieldLayoutTag *loc = pFieldLayout;
9063 bmtFieldLayoutTag *layoutEnd = pFieldLayout + instanceSliceSize;
9064 while (loc < layoutEnd)
9066 // Find the next OREF entry.
9067 loc = (bmtFieldLayoutTag*)memchr((void*)loc, oref, layoutEnd-loc);
9073 // Find the next non-OREF entry
9074 bmtFieldLayoutTag *cur = loc;
9075 while(cur < layoutEnd && *cur == oref)
9080 // so we have a GC series at loc for cur-loc bytes
9081 bmtGCSeries->pSeries[bmtGCSeries->numSeries].offset = (DWORD)(loc - pFieldLayout);
9082 bmtGCSeries->pSeries[bmtGCSeries->numSeries].len = (DWORD)(cur - loc);
9084 CONSISTENCY_CHECK(IS_ALIGNED(cur - loc, TARGET_POINTER_SIZE));
9086 bmtGCSeries->numSeries++;
9090 // Calculate the total series count including the parent, if a parent exists.
9092 bmtFP->NumGCPointerSeries = bmtParent->NumParentPointerSeries + bmtGCSeries->numSeries;
9094 // since the GC series are computed from a ref map,
9095 // in most cases where optimized GCDesc could be used, that is what we will compute anyways,
9096 // so we will not try optimizing this case.
9097 bmtFP->fIsAllGCPointers = false;
9100 //*******************************************************************************
9102 MethodTableBuilder::HandleGCForExplicitLayout()
9104 STANDARD_VM_CONTRACT;
9106 MethodTable *pMT = GetHalfBakedMethodTable();
9108 if (bmtFP->NumGCPointerSeries != 0)
9110 pMT->SetContainsPointers();
9112 // Copy the pointer series map from the parent
9113 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
9114 if (bmtParent->NumParentPointerSeries != 0)
9116 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
9117 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize),
9118 (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize),
9119 ParentGCSize - sizeof(size_t) // sizeof(size_t) is the NumSeries count
9123 UINT32 dwInstanceSliceOffset = AlignUp(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0, TARGET_POINTER_SIZE);
9125 // Build the pointer series map for this pointers in this instance
9126 CGCDescSeries *pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
9127 for (UINT i=0; i < bmtGCSeries->numSeries; i++) {
9128 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
9129 BAD_FORMAT_NOTHROW_ASSERT(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
9131 pSeries->SetSeriesSize( (size_t) bmtGCSeries->pSeries[i].len - (size_t) pMT->GetBaseSize() );
9132 pSeries->SetSeriesOffset(bmtGCSeries->pSeries[i].offset + OBJECT_SIZE + dwInstanceSliceOffset);
9136 // Adjust the inherited series - since the base size has increased by "# new field instance bytes", we need to
9137 // subtract that from all the series (since the series always has BaseSize subtracted for it - see gcdesc.h)
9138 CGCDescSeries *pHighest = CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries();
9139 while (pSeries <= pHighest)
9141 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
9142 pSeries->SetSeriesSize( pSeries->GetSeriesSize() - ((size_t) pMT->GetBaseSize() - (size_t) GetParentMethodTable()->GetBaseSize()) );
9147 delete [] bmtGCSeries->pSeries;
9148 bmtGCSeries->pSeries = NULL;
9149 } // MethodTableBuilder::HandleGCForExplicitLayout
9155 MethodTable **pArray,
9156 DWORD nArraySizeMax,
9157 DWORD *pNumAssigned)
9159 LIMITED_METHOD_CONTRACT;
9161 for (DWORD j = 0; j < (*pNumAssigned); j++)
9163 if (pNew == pArray[j])
9166 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found duplicate interface %s (%p) at position %d out of %d\n", pNew->GetDebugClassName(), pNew, j, *pNumAssigned));
9168 return pNew->HasInstantiation(); // bail out - we found a duplicate instantiated interface
9173 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));
9177 if (*pNumAssigned >= nArraySizeMax)
9179 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found interface %s (%p) exceeding size %d of interface array\n", pNew->GetDebugClassName(), pNew, nArraySizeMax));
9182 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Inserting interface %s (%p) at position %d\n", pNew->GetDebugClassName(), pNew, *pNumAssigned));
9183 pArray[(*pNumAssigned)++] = pNew;
9185 } // InsertMethodTable
9187 //*******************************************************************************
9188 // --------------------------------------------------------------------------------------------
9189 // Copy virtual slots inherited from parent:
9191 // In types where covariant returns are used, inherited virtual slots may not yet be fully
9192 // resolved during initial MethodTable building. This method will update them based on the
9193 // values computed during exact parent calculation of the parent type.
9195 void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT)
9200 PRECONDITION(CheckPointer(pMT));
9204 DWORD nParentVirtuals = pMT->GetNumParentVirtuals();
9205 if (nParentVirtuals == 0)
9209 // Update all inherited virtual slots to match exact parent
9212 if (!pMT->IsCanonicalMethodTable())
9215 // Copy all slots for non-canonical methodtables to avoid touching methoddescs.
9217 MethodTable * pCanonMT = pMT->GetCanonicalMethodTable();
9219 // Do not write into vtable chunks shared with parent. It would introduce race
9220 // with code:MethodDesc::SetStableEntryPointInterlocked.
9222 // Non-canonical method tables either share everything or nothing so it is sufficient to check
9223 // just the first indirection to detect sharing.
9224 if (pMT->GetVtableIndirections()[0] != pCanonMT->GetVtableIndirections()[0])
9226 MethodTable::MethodDataWrapper hCanonMTData(MethodTable::GetMethodData(pCanonMT, FALSE));
9227 for (DWORD i = 0; i < nParentVirtuals; i++)
9229 pMT->CopySlotFrom(i, hCanonMTData, pCanonMT);
9235 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
9237 MethodTable * pParentMT = pMT->GetParentMethodTable();
9238 MethodTable::MethodDataWrapper hParentMTData(MethodTable::GetMethodData(pParentMT, FALSE));
9240 for (DWORD i = 0; i < nParentVirtuals; i++)
9242 // fix up wrongly-inherited method descriptors
9243 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
9244 CONSISTENCY_CHECK(CheckPointer(pMD));
9245 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
9247 if (pMD->GetMethodTable() == pMT)
9250 // We need to re-inherit this slot from the exact parent.
9252 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(i);
9253 if (pMT->GetVtableIndirections()[indirectionIndex] == pParentMT->GetVtableIndirections()[indirectionIndex])
9255 // The slot lives in a chunk shared from the parent MT
9259 // The slot lives in an unshared chunk. We need to update the slot contents
9260 pMT->CopySlotFrom(i, hParentMTData, pParentMT);
9263 } // MethodTableBuilder::CopyExactParentSlots
9265 bool InstantiationIsAllTypeVariables(const Instantiation &inst)
9267 for (auto i = inst.GetNumArgs(); i > 0;)
9269 TypeHandle th = inst[--i];
9270 if (!th.IsGenericVariable())
9277 //*******************************************************************************
9280 MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
9285 PRECONDITION(CheckPointer(pMT));
9289 BOOL hasInstantiatedInterfaces = FALSE;
9290 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
9293 if (it.GetInterfaceApprox()->HasInstantiation())
9295 hasInstantiatedInterfaces = TRUE;
9300 // If we have some instantiated interfaces, then we have lots more work to do...
9302 // In the worst case we have to use the metadata to
9303 // (a) load the exact interfaces and determine the order in which they
9304 // go. We do those by re-running the interface layout algorithm
9305 // and using metadata-comparisons to place interfaces in the list.
9306 // (b) do a check to see if any ambiguity in the interface dispatch map is introduced
9307 // by the instantiation
9308 // See code:#LoadExactInterfaceMap_Algorithm2
9310 // However, we can do something simpler: we just use
9311 // the loaded interface method tables to determine ordering. This can be done
9312 // if there are no duplicate instantiated interfaces in the interface
9314 // See code:#LoadExactInterfaceMap_Algorithm1.
9316 if (!hasInstantiatedInterfaces)
9322 TypeHandle thisTH(pMT);
9323 SigTypeContext typeContext(thisTH);
9324 MethodTable *pParentMT = pMT->GetParentMethodTable();
9326 //#LoadExactInterfaceMap_Algorithm1
9327 // Exact interface instantiation loading TECHNIQUE 1.
9328 // (a) For interfaces inherited from an instantiated parent class, just copy down from exact parent
9329 // (b) Grab newly declared interfaces by loading and then copying down all their inherited parents
9330 // (c) But check for any exact duplicates along the way
9331 // (d) If no duplicates then we can use the computed interface map we've created
9332 // (e) If duplicates found then use the slow metadata-based technique code:#LoadExactInterfaceMap_Algorithm2
9333 DWORD nInterfacesCount = pMT->GetNumInterfaces();
9334 MethodTable **pExactMTs = (MethodTable**) _alloca(sizeof(MethodTable *) * nInterfacesCount);
9338 // Always use exact loading behavior with classes or shared generics, as they have to deal with inheritance, and the
9339 // inexact matching logic for classes would be more complex to write.
9340 // Also always use the exact loading behavior with any generic that contains generic variables, as the open type is used
9341 // to represent a type instantiated over its own generic variables, and the special marker type is currently the open type
9342 // and we make this case distinguishable by simply disallowing the optimization in those cases.
9343 bool retryWithExactInterfaces = !pMT->IsValueType() || pMT->IsSharedByGenericInstantiations() || pMT->ContainsGenericVariables();
9345 DWORD nAssigned = 0;
9351 if (pParentMT != NULL)
9353 MethodTable::InterfaceMapIterator parentIt = pParentMT->IterateInterfaceMap();
9354 while (parentIt.Next())
9356 duplicates |= InsertMethodTable(parentIt.GetInterface(pParentMT, CLASS_LOAD_EXACTPARENTS), pExactMTs, nInterfacesCount, &nAssigned);
9359 InterfaceImplEnum ie(pMT->GetModule(), pMT->GetCl(), NULL);
9360 while ((hr = ie.Next()) == S_OK)
9362 MethodTable *pNewIntfMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(),
9365 ClassLoader::ThrowIfNotFound,
9366 ClassLoader::FailIfUninstDefOrRef,
9367 ClassLoader::LoadTypes,
9368 CLASS_LOAD_EXACTPARENTS,
9370 (const Substitution*)0,
9371 retryWithExactInterfaces ? NULL : pMT).GetMethodTable();
9373 bool uninstGenericCase = !retryWithExactInterfaces && pNewIntfMT->IsSpecialMarkerTypeForGenericCasting();
9375 duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);
9377 // We have a special algorithm for interface maps in CoreLib, which doesn't expand interfaces, and assumes no ambiguous
9378 // duplicates. Code related to this is marked with #SpecialCorelibInterfaceExpansionAlgorithm
9379 if (!(pMT->GetModule()->IsSystem() && pMT->IsValueType()))
9381 MethodTable::InterfaceMapIterator intIt = pNewIntfMT->IterateInterfaceMap();
9382 while (intIt.Next())
9384 MethodTable *pItfPossiblyApprox = intIt.GetInterfaceApprox();
9385 if (uninstGenericCase && pItfPossiblyApprox->HasInstantiation() && pItfPossiblyApprox->ContainsGenericVariables())
9387 // We allow a limited set of interface generic shapes with type variables. In particular, we require the
9388 // instantiations to be exactly simple type variables, and to have a relatively small number of generic arguments
9389 // so that the fallback instantiating logic works efficiently
9390 if (InstantiationIsAllTypeVariables(pItfPossiblyApprox->GetInstantiation()) && pItfPossiblyApprox->GetInstantiation().GetNumArgs() <= MethodTable::MaxGenericParametersForSpecialMarkerType)
9392 pItfPossiblyApprox = ClassLoader::LoadTypeDefThrowing(pItfPossiblyApprox->GetModule(), pItfPossiblyApprox->GetCl(), ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, CLASS_LOAD_EXACTPARENTS).AsMethodTable();
9400 duplicates |= InsertMethodTable(intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS), pExactMTs, nInterfacesCount, &nAssigned);
9410 retryWithExactInterfaces = true;
9416 pMT->GetAssembly()->ThrowTypeLoadException(pMT->GetMDImport(), pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
9419 if (!pMT->GetModule()->IsSystem())
9422 duplicates |= CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AlwaysUseMetadataInterfaceMapLayout);
9425 //#InjectInterfaceDuplicates_LoadExactInterfaceMap
9426 // If we are injecting duplicates also for non-generic interfaces in check builds, we have to use
9427 // algorithm code:#LoadExactInterfaceMap_Algorithm2.
9428 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
9429 duplicates |= pMT->Debug_HasInjectedInterfaceDuplicates();
9431 // We have a special algorithm for interface maps in CoreLib, which doesn't expand interfaces, and assumes no ambiguous
9432 // duplicates. Code related to this is marked with #SpecialCorelibInterfaceExpansionAlgorithm
9433 _ASSERTE(!duplicates || !(pMT->GetModule()->IsSystem() && pMT->IsValueType()));
9435 CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces()));
9438 //#LoadExactInterfaceMap_Algorithm2
9439 // Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to
9440 // appear in the interface map! This may not be an error: if the duplicates were ones that arose because of
9441 // inheritance from a parent type then we accept that. For example
9442 // class C<T> : I<T>
9443 // class D<T> : C<T>, I<string>
9444 // is acceptable even when loading D<string>. Note that in such a case
9445 // there will be two entries for I<string> in the final interface map for D<string>.
9446 // For dispatch the mappings in D take precedence.
9448 // However we consider it an error if there is real ambiguity within
9449 // the interface definitions within the one class, e.g.
9450 // class E<T> : I<T>, I<string>
9451 // In this situation it is not defined how to dispatch calls to I<string>: would
9452 // we use the bindings for I<T> or I<string>?
9454 // Because we may had duplicates the interface map we created above may not
9455 // be the correct one: for example for D<string> above we would have computed
9456 // a map with only one entry. This is incorrect: an exact instantiation's interface
9457 // map must have entries that match the ordering of the interface map in the generic case
9458 // (this is because code:#InterfaceMap_SupersetOfParent).
9460 // So, in order to determine how to place the interfaces we need go back to
9461 // the metadata. We also do this to check if the presence of duplicates
9462 // has caused any potential ambiguity, i.e. the E<string> case above.
9464 // First we do a GetCheckpoint for the thread-based allocator. ExpandExactInheritedInterfaces allocates substitution chains
9465 // on the thread allocator rather than on the stack.
9466 ACQUIRE_STACKING_ALLOCATOR(pStackingAllocator);
9468 // ***********************************************************
9469 // ****** This must be consistent with code:ExpandApproxInterface etc. *******
9471 // The correlation to ExpandApproxInterfaces etc. simply drops out by how we
9472 // traverse interfaces.
9473 // ***********************************************************
9475 bmtExactInterfaceInfo bmtExactInterface;
9476 bmtExactInterface.pInterfaceSubstitution = new (pStackingAllocator) Substitution[pMT->GetNumInterfaces()];
9477 bmtExactInterface.pExactMTs = pExactMTs;
9478 bmtExactInterface.nAssigned = 0;
9479 bmtExactInterface.typeContext = typeContext;
9481 // Do the interfaces inherited from a parent class
9482 if ((pParentMT != NULL) && (pParentMT->GetNumInterfaces() > 0))
9484 Substitution * pParentSubstForTypeLoad = new (pStackingAllocator) Substitution(
9485 pMT->GetSubstitutionForParent(NULL));
9486 Substitution * pParentSubstForComparing = new (pStackingAllocator) Substitution(
9487 pMT->GetSubstitutionForParent(NULL));
9488 ExpandExactInheritedInterfaces(
9491 pParentSubstForTypeLoad,
9492 pParentSubstForComparing,
9494 retryWithExactInterfaces ? NULL : pMT);
9497 //#ExactInterfaceMap_SupersetOfParent
9498 // Check that parent's interface map is subset of this interface map
9499 // See code:#InterfaceMap_SupersetOfParent
9501 _ASSERTE(pParentMT->GetNumInterfaces() == bmtExactInterface.nAssigned);
9503 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
9504 UINT32 nInterfaceIndex = 0;
9505 while (parentInterfacesIterator.Next())
9507 if (pMT->IsSharedByGenericInstantiations())
9508 { // The type is a canonical instantiation (contains _Canon)
9509 // The interface instantiations of parent can be different (see
9510 // code:#InterfaceMap_CanonicalSupersetOfParent), therefore we cannot compare
9512 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
9513 bmtExactInterface.pExactMTs[nInterfaceIndex]));
9516 { // It is not canonical instantiation, we can compare MethodTables
9517 _ASSERTE(parentInterfacesIterator.GetInterfaceApprox() == bmtExactInterface.pExactMTs[nInterfaceIndex]);
9521 _ASSERTE(nInterfaceIndex == bmtExactInterface.nAssigned);
9525 // If there are any __Canon instances in the type argument list, then we defer the
9526 // ambiguity checking until an exact instantiation.
9527 // As the C# compiler won't allow an ambiguous generic interface to be generated, we don't
9528 // need this logic for CoreLib. We can't use the sanity checks flag here, as these ambiguities
9529 // are specified to the exact instantiation in use, not just whether or not normal the type is
9530 // well formed in metadata.
9531 if (!pMT->IsSharedByGenericInstantiations() && !pMT->GetModule()->IsSystem())
9533 // There are no __Canon types in the instantiation, so do ambiguity check.
9534 bmtInterfaceAmbiguityCheckInfo bmtCheckInfo;
9535 bmtCheckInfo.pMT = pMT;
9536 bmtCheckInfo.ppInterfaceSubstitutionChains = new (pStackingAllocator) Substitution *[pMT->GetNumInterfaces()];
9537 bmtCheckInfo.ppExactDeclaredInterfaces = new (pStackingAllocator) MethodTable *[pMT->GetNumInterfaces()];
9538 bmtCheckInfo.nAssigned = 0;
9539 bmtCheckInfo.typeContext = typeContext;
9540 MethodTableBuilder::InterfacesAmbiguityCheck(&bmtCheckInfo, pMT->GetModule(), pMT->GetCl(), NULL, pStackingAllocator);
9543 // OK, there is no ambiguity amongst the instantiated interfaces declared on this class.
9544 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9551 retryWithExactInterfaces ? NULL : pMT
9552 COMMA_INDEBUG(pMT));
9553 CONSISTENCY_CHECK(bmtExactInterface.nAssigned == pMT->GetNumInterfaces());
9555 // We cannot process interface duplicates on types with __Canon. The duplicates are processed on
9557 if (!pMT->IsSharedByGenericInstantiations())
9559 // Process all pairs of duplicates in the interface map:
9560 // i.e. If there are 3 duplicates of the same interface at indexes: i1, i2 and i3, then
9561 // process pairs of indexes [i1,i2], [i1,i3] and [i2,i3].
9562 // - Update 'declared on type' flag for those interfaces which duplicate is 'declared on type'
9563 // - Check interface method implementation ambiguity code:#DuplicateInterface_MethodAmbiguity
9564 for (DWORD nOriginalIndex = 0; nOriginalIndex < nInterfacesCount; nOriginalIndex++)
9566 // Search for duplicates further in the interface map
9567 for (DWORD nDuplicateIndex = nOriginalIndex + 1; nDuplicateIndex < nInterfacesCount; nDuplicateIndex++)
9569 if (pExactMTs[nOriginalIndex] != pExactMTs[nDuplicateIndex])
9570 { // It's not a duplicate of original interface, skip it
9573 // We found a duplicate
9575 // Set 'declared on type' flag if either original or duplicate interface is
9576 // 'declared on type'
9577 if (pMT->IsInterfaceDeclaredOnClass(nOriginalIndex) ||
9578 pMT->IsInterfaceDeclaredOnClass(nDuplicateIndex))
9581 // Note that both checks are needed:
9583 // B<T,U> : A<T>, I<U>
9584 // C<T,U> : B<T,U>, I<T> // Reimplements interface from A<T>
9585 // After code:BuildMethodTableThrowing algorithm, this will happen:
9586 // B<int,int> will have interface map similar to B<T,U>:
9587 // I<int> ... not 'declared on type'
9588 // I<int> ... 'declared on type'
9589 // C<int,int> will have interface map similar to C<T,U>:
9590 // I<int> ... 'declared on type'
9591 // I<int> ... not 'declared on type'
9594 pMT->SetInterfaceDeclaredOnClass(nOriginalIndex);
9595 pMT->SetInterfaceDeclaredOnClass(nDuplicateIndex);
9598 //#DuplicateInterface_MethodAmbiguity
9600 // In the ideal world we would now check for interface method implementation
9601 // ambiguity in the instantiation, but that would be a technical breaking change
9602 // (against 2.0 RTM/SP1).
9603 // Therefore we ALLOW when interface method is implemented twice through this
9604 // original and duplicate interface.
9606 // This ambiguity pattern is therefore ALLOWED (can be expressed only in IL, not in C#):
9609 // A<T> : I<T> // abstract class
9610 // B<T,U> : A<T>, I<U>
9611 // void Print(T t) { ... }
9612 // void Print(U u) { ... }
9613 // Now B<int,int> has 2 implementations of I<int>.Print(int), while B<int,char> is
9614 // fine. Therefore an instantiation can introduce ambiguity.
9616 #if 0 // Removing this code for now as it is a technical breaking change (against CLR 2.0 RTM/SP1).
9617 // We might decide later that we want to take this breaking change.
9619 // Note that dispatch map entries are sorted by interface index and then interface
9620 // method slot index.
9622 DispatchMapTypeID originalTypeID = DispatchMapTypeID::InterfaceClassID(nOriginalIndex);
9623 DispatchMap::EncodedMapIterator originalIt(pMT);
9624 // Find first entry for original interface
9625 while (originalIt.IsValid())
9627 DispatchMapEntry *pEntry = originalIt.Entry();
9628 if (pEntry->GetTypeID().ToUINT32() >= originalTypeID.ToUINT32())
9629 { // Found the place where original interface entries should be (dispatch map is
9636 DispatchMapTypeID duplicateTypeID = DispatchMapTypeID::InterfaceClassID(nDuplicateIndex);
9637 DispatchMap::EncodedMapIterator duplicateIt(pMT);
9638 // Find first entry for duplicate interface
9639 while (duplicateIt.IsValid())
9641 DispatchMapEntry *pEntry = duplicateIt.Entry();
9642 if (pEntry->GetTypeID().ToUINT32() >= duplicateTypeID.ToUINT32())
9643 { // Found the place where original interface entries should be (dispatch map is
9650 // Compare original and duplicate interface entries in the dispatch map if they contain
9651 // different implementation for the same interface method
9654 if (!originalIt.IsValid() || !duplicateIt.IsValid())
9655 { // We reached end of one dispatch map iterator
9658 DispatchMapEntry *pOriginalEntry = originalIt.Entry();
9659 if (pOriginalEntry->GetTypeID().ToUINT32() != originalTypeID.ToUINT32())
9660 { // We reached behind original interface entries
9663 DispatchMapEntry *pDuplicateEntry = duplicateIt.Entry();
9664 if (pDuplicateEntry->GetTypeID().ToUINT32() != duplicateTypeID.ToUINT32())
9665 { // We reached behind duplicate interface entries
9669 if (pOriginalEntry->GetSlotNumber() == pDuplicateEntry->GetSlotNumber())
9670 { // Found duplicate implementation of interface method
9671 if (pOriginalEntry->GetTargetSlotNumber() != pDuplicateEntry->GetTargetSlotNumber())
9672 { // Implementation of the slots is different
9673 bmtErrorInfo bmtError;
9675 bmtError.pModule = pMT->GetModule();
9676 bmtError.cl = pMT->GetCl();
9677 bmtError.resIDWhy = IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES;
9678 bmtError.szMethodNameForError = NULL;
9679 bmtError.pThrowable = NULL;
9681 MethodDesc *pMD = pMT->GetMethodDescForSlot(pDuplicateEntry->GetTargetSlotNumber());
9682 bmtError.dMethodDefInError = pMD->GetMemberDef();
9684 BuildMethodTableThrowException(COR_E_TYPELOAD, bmtError);
9686 // The method is implemented by the same slot on both interfaces (original and
9689 // Process next dispatch map entry
9694 // Move iterator representing smaller interface method slot index (the dispatch map
9695 // is sorted by slot indexes)
9696 if (pOriginalEntry->GetSlotNumber() < pDuplicateEntry->GetSlotNumber())
9701 _ASSERTE(pOriginalEntry->GetSlotNumber() > pDuplicateEntry->GetSlotNumber());
9706 // All duplicates of this original interface were processed
9708 // All pairs of duplicates in the interface map are processed
9711 // Duplicates in the interface map are resolved
9713 // OK, if we've got this far then pExactMTs should now hold the array of exact instantiated interfaces.
9714 MethodTable::InterfaceMapIterator thisIt = pMT->IterateInterfaceMap();
9716 while (thisIt.Next())
9719 MethodTable *pNewMT = pExactMTs[i];
9720 CONSISTENCY_CHECK(thisIt.HasSameTypeDefAs(pNewMT));
9722 thisIt.SetInterface(pExactMTs[i]);
9726 } // MethodTableBuilder::LoadExactInterfaceMap
9728 //*******************************************************************************
9730 MethodTableBuilder::ExpandExactInheritedInterfaces(
9731 bmtExactInterfaceInfo * bmtInfo,
9733 const Substitution * pSubstForTypeLoad,
9734 Substitution * pSubstForComparing,
9735 StackingAllocator * pStackingAllocator,
9736 MethodTable * pMTInterfaceMapOwner)
9738 STANDARD_VM_CONTRACT;
9740 MethodTable *pParentMT = pMT->GetParentMethodTable();
9742 // Backup type's substitution chain for comparing interfaces
9743 Substitution substForComparingBackup = *pSubstForComparing;
9744 // Make type an open type for comparing interfaces
9745 *pSubstForComparing = Substitution();
9749 // Chain parent's substitution for exact type load
9750 Substitution * pParentSubstForTypeLoad = new (pStackingAllocator) Substitution(
9751 pMT->GetSubstitutionForParent(pSubstForTypeLoad));
9753 // Chain parent's substitution for comparing interfaces (note that this type is temporarily
9754 // considered as open type)
9755 Substitution * pParentSubstForComparing = new (pStackingAllocator) Substitution(
9756 pMT->GetSubstitutionForParent(pSubstForComparing));
9758 ExpandExactInheritedInterfaces(
9761 pParentSubstForTypeLoad,
9762 pParentSubstForComparing,
9764 pMTInterfaceMapOwner);
9766 ExpandExactDeclaredInterfaces(
9773 pMTInterfaceMapOwner
9774 COMMA_INDEBUG(pMT));
9776 // Restore type's substitution chain for comparing interfaces
9777 *pSubstForComparing = substForComparingBackup;
9778 } // MethodTableBuilder::ExpandExactInheritedInterfaces
9780 //*******************************************************************************
9783 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9784 bmtExactInterfaceInfo * bmtInfo,
9787 const Substitution * pSubstForTypeLoad,
9788 Substitution * pSubstForComparing,
9789 StackingAllocator * pStackingAllocator,
9790 MethodTable * pMTInterfaceMapOwner
9791 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9793 STANDARD_VM_CONTRACT;
9796 InterfaceImplEnum ie(pModule, typeDef, NULL);
9797 while ((hr = ie.Next()) == S_OK)
9799 MethodTable * pInterface = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
9802 &bmtInfo->typeContext,
9803 ClassLoader::ThrowIfNotFound,
9804 ClassLoader::FailIfUninstDefOrRef,
9805 ClassLoader::LoadTypes,
9806 CLASS_LOAD_EXACTPARENTS,
9809 pMTInterfaceMapOwner).GetMethodTable();
9811 Substitution ifaceSubstForTypeLoad(ie.CurrentToken(), pModule, pSubstForTypeLoad);
9812 Substitution ifaceSubstForComparing(ie.CurrentToken(), pModule, pSubstForComparing);
9813 ExpandExactInterface(
9816 &ifaceSubstForTypeLoad,
9817 &ifaceSubstForComparing,
9819 pMTInterfaceMapOwner
9820 COMMA_INDEBUG(dbg_pClassMT));
9824 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9826 } // MethodTableBuilder::ExpandExactDeclaredInterfaces
9828 //*******************************************************************************
9830 MethodTableBuilder::ExpandExactInterface(
9831 bmtExactInterfaceInfo * bmtInfo,
9832 MethodTable * pIntf,
9833 const Substitution * pSubstForTypeLoad_OnStack, // Allocated on stack!
9834 const Substitution * pSubstForComparing_OnStack, // Allocated on stack!
9835 StackingAllocator * pStackingAllocator,
9836 MethodTable * pMTInterfaceMapOwner
9837 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9839 STANDARD_VM_CONTRACT;
9841 // ****** This must be consistent with code:MethodTableBuilder::ExpandApproxInterface ******
9843 // Is it already present according to the "generic" layout of the interfaces.
9844 // Note we use exactly the same algorithm as when we
9845 // determined the layout of the interface map for the "generic" version of the class.
9846 for (DWORD i = 0; i < bmtInfo->nAssigned; i++)
9848 // Type Equivalence is not respected for this comparison as you can have multiple type equivalent interfaces on a class
9849 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9850 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtInfo->pExactMTs[i],
9852 &bmtInfo->pInterfaceSubstitution[i],
9853 pSubstForComparing_OnStack,
9857 //#InjectInterfaceDuplicates_ExactInterfaces
9858 // We will inject duplicate interfaces in check builds.
9859 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
9860 if (dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates())
9861 { // Just pretend we didn't find this match
9865 return; // found it, don't add it again
9869 // Add the interface and its sub-interfaces
9870 DWORD n = bmtInfo->nAssigned;
9871 bmtInfo->pExactMTs[n] = pIntf;
9872 bmtInfo->pInterfaceSubstitution[n] = *pSubstForComparing_OnStack;
9873 bmtInfo->nAssigned++;
9875 Substitution * pSubstForTypeLoad = new (pStackingAllocator) Substitution(*pSubstForTypeLoad_OnStack);
9877 ExpandExactDeclaredInterfaces(
9882 &bmtInfo->pInterfaceSubstitution[n],
9884 pMTInterfaceMapOwner
9885 COMMA_INDEBUG(dbg_pClassMT));
9886 } // MethodTableBuilder::ExpandExactInterface
9888 //*******************************************************************************
9890 void MethodTableBuilder::InterfacesAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9893 const Substitution *pSubstChain,
9894 StackingAllocator *pStackingAllocator)
9896 STANDARD_VM_CONTRACT;
9899 InterfaceImplEnum ie(pModule, typeDef, pSubstChain);
9900 while ((hr = ie.Next()) == S_OK)
9902 MethodTable *pInterface =
9903 ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, ie.CurrentToken(),
9904 &bmtCheckInfo->typeContext,
9905 ClassLoader::ThrowIfNotFound,
9906 ClassLoader::FailIfUninstDefOrRef,
9907 ClassLoader::LoadTypes,
9908 CLASS_LOAD_EXACTPARENTS,
9910 pSubstChain).GetMethodTable();
9911 InterfaceAmbiguityCheck(bmtCheckInfo, ie.CurrentSubst(), pInterface, pStackingAllocator);
9915 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9919 //*******************************************************************************
9920 void MethodTableBuilder::InterfaceAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9921 const Substitution *pItfSubstChain,
9923 StackingAllocator *pStackingAllocator)
9925 STANDARD_VM_CONTRACT;
9927 // Is it already in the generic version of the freshly declared interfaces. We
9928 // do this based on metadata, i.e. via the substitution chains.
9929 // Note we use exactly the same algorithm as when we
9930 // determined the layout of the interface map for the "generic" version of the class.
9931 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9933 // Type Equivalence is not respected for this comparison as you can have multiple type equivalent interfaces on a class
9934 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9935 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtCheckInfo->ppExactDeclaredInterfaces[i],
9937 bmtCheckInfo->ppInterfaceSubstitutionChains[i],
9940 return; // found it, don't add it again
9943 // OK, so it isn't a duplicate based on the generic IL, now check if the instantiation
9944 // makes it a duplicate.
9945 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9947 if (bmtCheckInfo->ppExactDeclaredInterfaces[i] == pIntf)
9949 bmtCheckInfo->pMT->GetModule()->GetAssembly()->ThrowTypeLoadException(bmtCheckInfo->pMT->GetMDImport(),
9950 bmtCheckInfo->pMT->GetCl(),
9951 IDS_CLASSLOAD_OVERLAPPING_INTERFACES);
9955 DWORD n = bmtCheckInfo->nAssigned;
9956 bmtCheckInfo->ppExactDeclaredInterfaces[n] = pIntf;
9957 bmtCheckInfo->ppInterfaceSubstitutionChains[n] = new (pStackingAllocator) Substitution[pItfSubstChain->GetLength()];
9958 pItfSubstChain->CopyToArray(bmtCheckInfo->ppInterfaceSubstitutionChains[n]);
9960 bmtCheckInfo->nAssigned++;
9961 InterfacesAmbiguityCheck(bmtCheckInfo,pIntf->GetModule(),pIntf->GetCl(),pItfSubstChain, pStackingAllocator);
9965 //*******************************************************************************
9966 void MethodTableBuilder::CheckForSystemTypes()
9968 STANDARD_VM_CONTRACT;
9970 LPCUTF8 name, nameSpace;
9972 MethodTable * pMT = GetHalfBakedMethodTable();
9973 EEClass * pClass = GetHalfBakedClass();
9975 // We can exit early for generic types - there are just a few cases to check for.
9976 if (bmtGenerics->HasInstantiation())
9978 if (pMT->IsIntrinsicType() && pClass->HasLayout())
9980 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9982 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9985 if (strcmp(nameSpace, g_IntrinsicsNS) == 0)
9987 EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo();
9989 // The SIMD Hardware Intrinsic types correspond to fundamental data types in the underlying ABIs:
9990 // * Vector64<T>: __m64
9991 // * Vector128<T>: __m128
9992 // * Vector256<T>: __m256
9994 // These __m128 and __m256 types, among other requirements, are special in that they must always
9995 // be aligned properly.
9997 if (strcmp(name, g_Vector64Name) == 0)
9999 // The System V ABI for i386 defaults to 8-byte alignment for __m64, except for parameter passing,
10000 // where it has an alignment of 4.
10002 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
10004 else if (strcmp(name, g_Vector128Name) == 0)
10007 // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128
10009 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
10011 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
10012 #endif // TARGET_ARM
10014 else if (strcmp(name, g_Vector256Name) == 0)
10017 // No such type exists for the Procedure Call Standard for ARM. We will default
10018 // to the same alignment as __m128, which is supported by the ABI.
10020 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
10021 #elif defined(TARGET_ARM64)
10022 // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to
10023 // 16-byte alignment for __m256.
10025 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
10026 #elif defined(TARGET_RISCV64)
10027 // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic.
10028 // RISC-V Vector Extenstion Intrinsic Document
10029 // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/vector_type_infos.adoc
10030 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
10032 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
10033 #endif // TARGET_ARM elif TARGET_ARM64
10035 else if (strcmp(name, g_Vector512Name) == 0)
10038 // No such type exists for the Procedure Call Standard for ARM. We will default
10039 // to the same alignment as __m128, which is supported by the ABI.
10041 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
10042 #elif defined(TARGET_ARM64)
10043 // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to
10044 // 16-byte alignment for __m256.
10046 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
10048 #elif defined(TARGET_RISCV64)
10049 // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic.
10050 // RISC-V Vector Extenstion Intrinsic Document
10051 // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/vector_type_infos.adoc
10052 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
10054 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 64; // sizeof(__m512)
10055 #endif // TARGET_ARM elif TARGET_ARM64
10059 // These types should be handled or explicitly skipped below to ensure that we don't
10060 // miss adding required ABI support for future types.
10062 _ASSERTE_MSG(FALSE, "Unhandled Hardware Intrinsic Type.");
10069 if (g_pNullableClass != NULL)
10071 _ASSERTE(g_pNullableClass->IsNullable());
10073 // Pre-compute whether the class is a Nullable<T> so that code:Nullable::IsNullableType is efficient
10074 // This is useful to the performance of boxing/unboxing a Nullable
10075 if (GetCl() == g_pNullableClass->GetCl())
10076 pMT->SetIsNullable();
10082 if (IsNested() || IsEnum())
10085 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
10087 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
10090 if (IsValueClass())
10096 // All special value types are in the system namespace
10097 if (strcmp(nameSpace, g_SystemNS) != 0)
10100 // Check if it is a primitive type
10101 CorElementType type = CorTypeInfo::FindPrimitiveType(name);
10102 if (type != ELEMENT_TYPE_END)
10104 pMT->SetInternalCorElementType(type);
10105 pMT->SetIsTruePrimitive();
10107 #if defined(TARGET_X86) && defined(UNIX_X86_ABI)
10110 // The System V ABI for i386 defines different packing for these types.
10112 case ELEMENT_TYPE_I8:
10113 case ELEMENT_TYPE_U8:
10114 case ELEMENT_TYPE_R8:
10116 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
10117 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 4;
10124 #endif // TARGET_X86 && UNIX_X86_ABI
10127 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
10129 name = nameSpace = "Invalid TypeDef record";
10131 LOG((LF_CLASSLOADER, LL_INFO10000, "%s::%s marked as primitive type %i\n", nameSpace, name, type));
10134 else if (strcmp(name, g_NullableName) == 0)
10136 pMT->SetIsNullable();
10138 else if (strcmp(name, g_RuntimeArgumentHandleName) == 0)
10140 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
10142 else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0)
10144 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
10146 else if (strcmp(name, g_RuntimeFieldHandleInternalName) == 0)
10148 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
10150 else if ((strcmp(name, g_Int128Name) == 0) || (strcmp(name, g_UInt128Name) == 0))
10152 EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo();
10153 pLayout->SetIsInt128OrHasInt128Fields(TRUE);
10155 // No such type exists for the Procedure Call Standard for ARM. We will default
10156 // to the same alignment as __m128, which is supported by the ABI.
10158 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
10159 #elif defined(TARGET_64BIT) || defined(TARGET_X86)
10161 // These types correspond to fundamental data types in the underlying ABIs:
10162 // * Int128: __int128
10163 // * UInt128: unsigned __int128
10165 // This behavior matches the ABI standard on various Unix platforms
10166 // On Windows, no standard for Int128 has been established yet,
10167 // although applying 16 byte alignment is consistent with treatment of 128 bit SSE types
10169 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__int128)
10171 #error Unknown architecture
10172 #endif // TARGET_64BIT
10180 if (strcmp(name, g_StringName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
10182 // Strings are not "normal" objects, so we need to mess with their method table a bit
10183 // so that the GC can figure out how big each string is...
10184 DWORD baseSize = StringObject::GetBaseSize();
10185 pMT->SetBaseSize(baseSize);
10187 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
10189 pMT->SetComponentSize(2);
10191 else if (strcmp(name, g_CriticalFinalizerObjectName) == 0 && strcmp(nameSpace, g_ConstrainedExecutionNS) == 0)
10193 // To introduce a class with a critical finalizer,
10194 // we'll set the bit here.
10195 pMT->SetHasCriticalFinalizer();
10197 #ifdef FEATURE_COMINTEROP
10200 bool bIsComObject = false;
10202 if (strcmp(name, g_ComObjectName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
10203 bIsComObject = true;
10208 // Make System.__ComObject a ComImport type
10209 // We can't do it using attribute as C# won't allow putting code in ComImport types
10210 pMT->SetComObjectType();
10212 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
10213 // the optional field descriptor.
10214 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10217 #endif // FEATURE_COMINTEROP
10221 //==========================================================================================
10222 // Helper to create a new method table. This is the only
10223 // way to allocate a new MT. Don't try calling new / ctor.
10224 // Called from SetupMethodTable
10225 // This needs to be kept consistent with MethodTable::GetSavedExtent()
10226 MethodTable * MethodTableBuilder::AllocateNewMT(
10227 Module *pLoaderModule,
10228 DWORD dwVtableSlots,
10231 DWORD dwNumInterfaces,
10233 DWORD cbInstAndDict,
10234 MethodTable *pMTParent,
10235 ClassLoader *pClassLoader,
10236 LoaderAllocator *pAllocator,
10238 BOOL fDynamicStatics,
10239 BOOL fHasGenericsStaticsInfo,
10240 BOOL fHasVirtualStaticMethods
10241 #ifdef FEATURE_COMINTEROP
10242 , BOOL fHasDynamicInterfaceMap
10244 , AllocMemTracker *pamTracker
10247 CONTRACT (MethodTable*)
10252 POSTCONDITION(CheckPointer(RETVAL));
10256 DWORD dwNonVirtualSlots = dwVtableSlots - dwVirtuals;
10258 // GCSize must be aligned
10259 _ASSERTE(IS_ALIGNED(dwGCSize, sizeof(void*)));
10261 // size without the interface map
10262 S_SIZE_T cbTotalSize = S_SIZE_T(dwGCSize) + S_SIZE_T(sizeof(MethodTable));
10265 cbTotalSize += MethodTable::GetNumVtableIndirections(dwVirtuals) * sizeof(MethodTable::VTableIndir_t);
10267 DWORD dwMultipurposeSlotsMask = 0;
10268 if (dwNumInterfaces != 0)
10269 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasInterfaceMap;
10270 if (dwNumDicts != 0)
10271 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasPerInstInfo;
10272 if (bmtVT->pDispatchMapBuilder->Count() > 0)
10273 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasDispatchMapSlot;
10274 if (dwNonVirtualSlots != 0)
10275 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasNonVirtualSlots;
10276 if (pLoaderModule != GetModule())
10277 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasModuleOverride;
10279 // Add space for optional members here. Same as GetOptionalMembersSize()
10280 cbTotalSize += MethodTable::GetOptionalMembersAllocationSize(dwMultipurposeSlotsMask,
10281 fHasGenericsStaticsInfo,
10282 RidFromToken(GetCl()) >= METHODTABLE_TOKEN_OVERFLOW);
10284 // Interface map starts here
10285 S_SIZE_T offsetOfInterfaceMap = cbTotalSize;
10287 cbTotalSize += S_SIZE_T(dwNumInterfaces) * S_SIZE_T(sizeof(InterfaceInfo_t));
10289 #ifdef FEATURE_COMINTEROP
10290 // DynamicInterfaceMap have an extra DWORD added to the end of the normal interface
10291 // map. This will be used to store the count of dynamically added interfaces
10292 // (the ones that are not in the metadata but are QI'ed for at runtime).
10293 cbTotalSize += S_SIZE_T(fHasDynamicInterfaceMap ? sizeof(DWORD_PTR) : 0);
10296 // Dictionary pointers start here
10297 S_SIZE_T offsetOfInstAndDict = cbTotalSize;
10299 if (dwNumDicts != 0)
10301 cbTotalSize += sizeof(GenericsDictInfo);
10302 cbTotalSize += S_SIZE_T(dwNumDicts) * S_SIZE_T(sizeof(MethodTable::PerInstInfoElem_t));
10303 cbTotalSize += cbInstAndDict;
10306 S_SIZE_T offsetOfUnsharedVtableChunks = cbTotalSize;
10308 // We will share any parent vtable chunk that does not contain a method we overrode (or introduced)
10309 // For the rest, we need to allocate space
10310 for (DWORD i = 0; i < dwVirtuals; i++)
10312 if (ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
10314 DWORD chunkStart = MethodTable::GetStartSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
10315 DWORD chunkEnd = MethodTable::GetEndSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
10317 cbTotalSize += S_SIZE_T(chunkEnd - chunkStart) * S_SIZE_T(sizeof(PCODE));
10323 // Add space for the non-virtual slots array (pointed to by an optional member) if required
10324 // If there is only one non-virtual slot, we store it directly in the optional member and need no array
10325 S_SIZE_T offsetOfNonVirtualSlots = cbTotalSize;
10326 if (dwNonVirtualSlots > 1)
10328 cbTotalSize += S_SIZE_T(dwNonVirtualSlots) * S_SIZE_T(sizeof(PCODE));
10331 BYTE *pData = (BYTE *)pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(cbTotalSize));
10333 _ASSERTE(IS_ALIGNED(pData, TARGET_POINTER_SIZE));
10335 // There should be no overflows if we have allocated the memory successfully
10336 _ASSERTE(!cbTotalSize.IsOverflow());
10338 MethodTable* pMT = (MethodTable*)(pData + dwGCSize);
10340 pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask);
10342 MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *)
10343 pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData))));
10344 // Note: Memory allocated on loader heap is zero filled
10345 pMT->SetWriteableData(pMTWriteableData);
10347 // This also disables IBC logging until the type is sufficiently initialized so
10348 // it needs to be done early
10349 pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable();
10352 pClassLoader->m_dwGCSize += dwGCSize;
10353 pClassLoader->m_dwInterfaceMapSize += (dwNumInterfaces * sizeof(InterfaceInfo_t));
10354 pClassLoader->m_dwMethodTableSize += (DWORD)cbTotalSize.Value();
10355 pClassLoader->m_dwVtableData += (dwVtableSlots * sizeof(PCODE));
10358 // There should be no overflows if we have allocated the memory successfully
10359 _ASSERTE(!offsetOfUnsharedVtableChunks.IsOverflow());
10360 _ASSERTE(!offsetOfNonVirtualSlots.IsOverflow());
10361 _ASSERTE(!offsetOfInterfaceMap.IsOverflow());
10362 _ASSERTE(!offsetOfInstAndDict.IsOverflow());
10364 // initialize the total number of slots
10365 pMT->SetNumVirtuals(static_cast<WORD>(dwVirtuals));
10366 if (fHasVirtualStaticMethods)
10368 pMT->SetHasVirtualStaticMethods();
10371 pMT->SetParentMethodTable(pMTParent);
10373 // Fill out the vtable indirection slots
10374 SIZE_T dwCurrentUnsharedSlotOffset = offsetOfUnsharedVtableChunks.Value();
10375 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
10378 BOOL shared = TRUE;
10380 // Recalculate whether we will share this chunk
10381 for (DWORD i = it.GetStartSlot(); i < it.GetEndSlot(); i++)
10383 if (ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
10392 // Share the parent chunk
10393 _ASSERTE(it.GetEndSlot() <= pMTParent->GetNumVirtuals());
10394 it.SetIndirectionSlot(pMTParent->GetVtableIndirections()[it.GetIndex()]);
10398 // Use the locally allocated chunk
10399 it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pData+dwCurrentUnsharedSlotOffset));
10400 dwCurrentUnsharedSlotOffset += it.GetSize();
10404 #ifdef FEATURE_COMINTEROP
10405 // Extensible RCW's are prefixed with the count of dynamic interfaces.
10406 if (fHasDynamicInterfaceMap)
10408 _ASSERTE (dwNumInterfaces > 0);
10409 pMT->SetInterfaceMap ((WORD) (dwNumInterfaces), (InterfaceInfo_t*)(pData+offsetOfInterfaceMap.Value()+sizeof(DWORD_PTR)));
10411 *(((DWORD_PTR *)pMT->GetInterfaceMap()) - 1) = 0;
10414 #endif // FEATURE_COMINTEROP
10416 // interface map is at the end of the vtable
10417 pMT->SetInterfaceMap ((WORD) dwNumInterfaces, (InterfaceInfo_t *)(pData+offsetOfInterfaceMap.Value()));
10420 _ASSERTE(((WORD) dwNumInterfaces) == dwNumInterfaces);
10422 if (fDynamicStatics)
10424 pMT->SetDynamicStatics(fHasGenericsStaticsInfo);
10427 if (dwNonVirtualSlots > 0)
10429 if (dwNonVirtualSlots > 1)
10431 pMT->SetNonVirtualSlotsArray((PTR_PCODE)(pData+offsetOfNonVirtualSlots.Value()));
10435 pMT->SetHasSingleNonVirtualSlot();
10439 // the dictionary pointers follow the interface map
10442 MethodTable::PerInstInfoElem_t *pPerInstInfo = (MethodTable::PerInstInfoElem_t *)(pData + offsetOfInstAndDict.Value() + sizeof(GenericsDictInfo));
10444 pMT->SetPerInstInfo ( pPerInstInfo);
10446 // Fill in the dictionary for this type, if it's instantiated
10449 MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *)(pPerInstInfo + (dwNumDicts-1));
10450 *pPInstInfo = (Dictionary*) (pPerInstInfo + dwNumDicts);
10455 pMT->m_pWriteableData->m_dwLastVerifedGCCnt = (DWORD)-1;
10462 //*******************************************************************************
10464 // Used by BuildMethodTable
10466 // Setup the method table
10469 #pragma warning(push)
10470 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
10471 #endif // _PREFAST_
10474 MethodTableBuilder::SetupMethodTable2(
10475 Module * pLoaderModule)
10480 PRECONDITION(CheckPointer(this));
10481 PRECONDITION(CheckPointer(bmtVT));
10482 PRECONDITION(CheckPointer(bmtInterface));
10483 PRECONDITION(CheckPointer(bmtInternal));
10484 PRECONDITION(CheckPointer(bmtProp));
10485 PRECONDITION(CheckPointer(bmtMFDescs));
10486 PRECONDITION(CheckPointer(bmtEnumFields));
10487 PRECONDITION(CheckPointer(bmtError));
10488 PRECONDITION(CheckPointer(bmtMetaData));
10489 PRECONDITION(CheckPointer(bmtParent));
10490 PRECONDITION(CheckPointer(bmtGenerics));
10496 #ifdef FEATURE_COMINTEROP
10497 BOOL fHasDynamicInterfaceMap = bmtInterface->dwInterfaceMapSize > 0 &&
10498 bmtProp->fIsComObjectType &&
10499 (GetParentMethodTable() != g_pObjectClass);
10500 #endif // FEATURE_COMINTEROP
10502 EEClass *pClass = GetHalfBakedClass();
10504 DWORD cbDictSlotSize = 0;
10505 DWORD cbDictAllocSize = 0;
10506 if (bmtGenerics->HasInstantiation())
10508 cbDictAllocSize = DictionaryLayout::GetDictionarySizeFromLayout(bmtGenerics->GetNumGenericArgs(), pClass->GetDictionaryLayout(), &cbDictSlotSize);
10513 if (bmtFP->NumGCPointerSeries > 0)
10515 dwGCSize = (DWORD)CGCDesc::ComputeSize(bmtFP->NumGCPointerSeries);
10522 pClass->SetNumMethods(bmtVT->cTotalSlots);
10523 pClass->SetNumNonVirtualSlots(bmtVT->cVtableSlots - bmtVT->cVirtualSlots);
10525 // Now setup the method table
10526 // interface map is allocated along with the method table
10527 MethodTable *pMT = AllocateNewMT(pLoaderModule,
10528 bmtVT->cVtableSlots,
10529 bmtVT->cVirtualSlots,
10531 bmtInterface->dwInterfaceMapSize,
10532 bmtGenerics->numDicts,
10534 GetParentMethodTable(),
10538 bmtProp->fDynamicStatics,
10539 bmtProp->fGenericsStatics,
10540 bmtProp->fHasVirtualStaticMethods,
10541 #ifdef FEATURE_COMINTEROP
10542 fHasDynamicInterfaceMap,
10546 pMT->SetClass(pClass);
10547 pClass->m_pMethodTable = pMT;
10548 m_pHalfBakedMT = pMT;
10551 pMT->SetDebugClassName(GetDebugClassName());
10555 pMT->SetIsInterface();
10557 if (GetParentMethodTable() != NULL)
10559 if (GetParentMethodTable()->HasModuleDependencies())
10561 pMT->SetHasModuleDependencies();
10565 Module * pModule = GetModule();
10566 Module * pParentModule = GetParentMethodTable()->GetModule();
10567 if (pModule != pParentModule)
10569 pMT->SetHasModuleDependencies();
10573 if (GetParentMethodTable()->HasPreciseInitCctors() || !pClass->IsBeforeFieldInit())
10575 pMT->SetHasPreciseInitCctors();
10579 // Must be done early because various methods test HasInstantiation() and ContainsGenericVariables()
10580 if (bmtGenerics->GetNumGenericArgs() != 0)
10582 pMT->SetHasInstantiation(bmtGenerics->fTypicalInstantiation, bmtGenerics->fSharedByGenericInstantiations);
10584 if (bmtGenerics->fContainsGenericVariables)
10585 pMT->SetContainsGenericVariables();
10588 if (bmtGenerics->numDicts != 0)
10590 if (!FitsIn<WORD>(bmtGenerics->GetNumGenericArgs()))
10592 BuildMethodTableThrowException(IDS_CLASSLOAD_TOOMANYGENERICARGS);
10595 pMT->SetDictInfo(bmtGenerics->numDicts,
10596 static_cast<WORD>(bmtGenerics->GetNumGenericArgs()));
10599 CONSISTENCY_CHECK(pMT->GetNumGenericArgs() == bmtGenerics->GetNumGenericArgs());
10600 CONSISTENCY_CHECK(pMT->GetNumDicts() == bmtGenerics->numDicts);
10601 CONSISTENCY_CHECK(pMT->HasInstantiation() == bmtGenerics->HasInstantiation());
10602 CONSISTENCY_CHECK(pMT->HasInstantiation() == !pMT->GetInstantiation().IsEmpty());
10604 pMT->SetLoaderModule(pLoaderModule);
10605 pMT->SetLoaderAllocator(bmtAllocator);
10607 pMT->SetModule(GetModule());
10609 pMT->SetInternalCorElementType (ELEMENT_TYPE_CLASS);
10611 SetNonGCRegularStaticFieldBytes (bmtProp->dwNonGCRegularStaticFieldBytes);
10612 SetNonGCThreadStaticFieldBytes (bmtProp->dwNonGCThreadStaticFieldBytes);
10614 #ifdef FEATURE_TYPEEQUIVALENCE
10615 if (bmtProp->fHasTypeEquivalence)
10617 pMT->SetHasTypeEquivalence();
10619 #endif //FEATURE_TYPEEQUIVALENCE
10621 #ifdef FEATURE_COMINTEROP
10622 if (bmtProp->fSparse)
10623 pClass->SetSparseForCOMInterop();
10624 #endif // FEATURE_COMINTEROP
10626 if (bmtVT->pCCtor != NULL)
10628 pMT->SetHasClassConstructor();
10629 CONSISTENCY_CHECK(pMT->GetClassConstructorSlot() == bmtVT->pCCtor->GetSlotIndex());
10631 if (bmtVT->pDefaultCtor != NULL)
10633 pMT->SetHasDefaultConstructor();
10634 CONSISTENCY_CHECK(pMT->GetDefaultConstructorSlot() == bmtVT->pDefaultCtor->GetSlotIndex());
10637 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10639 pChunk->SetMethodTable(pMT);
10644 DeclaredMethodIterator it(*this);
10647 MethodDesc *pMD = it->GetMethodDesc();
10650 pMD->m_pDebugMethodTable = pMT;
10651 pMD->m_pszDebugMethodSignature = FormatSig(pMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10653 MethodDesc *pUnboxedMD = it->GetUnboxedMethodDesc();
10654 if (pUnboxedMD != NULL)
10656 pUnboxedMD->m_pDebugMethodTable = pMT;
10657 pUnboxedMD->m_pszDebugMethodSignature = FormatSig(pUnboxedMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10663 // Note that for value classes, the following calculation is only appropriate
10664 // when the instance is in its "boxed" state.
10665 if (!IsInterface())
10667 DWORD baseSize = Max<DWORD>(bmtFP->NumInstanceFieldBytes + OBJECT_BASESIZE, MIN_OBJECT_SIZE);
10668 baseSize = (baseSize + ALLOC_ALIGN_CONSTANT) & ~ALLOC_ALIGN_CONSTANT; // m_BaseSize must be aligned
10669 pMT->SetBaseSize(baseSize);
10671 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
10673 if (bmtProp->fIsComObjectType)
10674 { // Propagate the com specific info
10675 pMT->SetComObjectType();
10676 #ifdef FEATURE_COMINTEROP
10677 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
10678 // the optional field descriptor.
10679 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10680 #endif // FEATURE_COMINTEROP
10685 #ifdef FEATURE_COMINTEROP
10686 // If this is an interface then we need to set the ComInterfaceType to
10687 // -1 to indicate we have not yet determined the interface type.
10688 pClass->SetComInterfaceType((CorIfaceAttr)-1);
10690 // If this is a special COM event interface, then mark the MT as such.
10691 if (bmtProp->fComEventItfType)
10693 pClass->SetComEventItfType();
10695 #endif // FEATURE_COMINTEROP
10697 _ASSERTE((pMT->IsInterface() == 0) == (IsInterface() == 0));
10699 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
10700 // Set all field slots to point to the newly created MethodTable
10701 for (i = 0; i < (bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields); i++)
10703 pFieldDescList[i].m_pMTOfEnclosingClass = pMT;
10706 // Fill in type parameters before looking up exact parent or fetching the types of any field descriptors!
10707 // This must come before the use of GetFieldType in the value class representation optimization below.
10708 if (bmtGenerics->GetNumGenericArgs() != 0)
10710 // Space has already been allocated for the instantiation but the parameters haven't been filled in
10711 Instantiation destInst = pMT->GetInstantiation();
10712 Instantiation inst = bmtGenerics->GetInstantiation();
10714 // So fill them in...
10715 TypeHandle * pInstDest = (TypeHandle *)destInst.GetRawArgs();
10716 for (DWORD j = 0; j < bmtGenerics->GetNumGenericArgs(); j++)
10718 pInstDest[j] = inst[j];
10721 PTR_DictionaryLayout pLayout = pClass->GetDictionaryLayout();
10722 if (pLayout != NULL)
10724 _ASSERTE(pLayout->GetMaxSlots() > 0);
10726 PTR_Dictionary pDictionarySlots = pMT->GetPerInstInfo()[bmtGenerics->numDicts - 1];
10727 DWORD* pSizeSlot = (DWORD*)(pDictionarySlots + bmtGenerics->GetNumGenericArgs());
10728 *pSizeSlot = cbDictSlotSize;
10732 CorElementType normalizedType = ELEMENT_TYPE_CLASS;
10733 if (IsValueClass())
10737 if (GetNumInstanceFields() != 1 ||
10738 !CorTypeInfo::IsPrimitiveType(pFieldDescList[0].GetFieldType()))
10740 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
10742 CONSISTENCY_CHECK(!pFieldDescList[0].IsStatic());
10743 normalizedType = pFieldDescList->GetFieldType();
10747 normalizedType = ELEMENT_TYPE_VALUETYPE;
10750 pMT->SetInternalCorElementType(normalizedType);
10752 if (bmtProp->fIsIntrinsicType)
10754 pMT->SetIsIntrinsicType();
10757 if (GetModule()->IsSystem())
10759 CheckForSystemTypes();
10762 // Now fill in the real interface map with the approximate interfaces
10763 if (bmtInterface->dwInterfaceMapSize > 0)
10765 // First ensure we have enough space to record extra flag information for each interface (we don't
10766 // record this directly into each interface map entry since these flags don't pack well due to
10768 PVOID pExtraInterfaceInfo = NULL;
10769 SIZE_T cbExtraInterfaceInfo = MethodTable::GetExtraInterfaceInfoSize(bmtInterface->dwInterfaceMapSize);
10770 if (cbExtraInterfaceInfo)
10771 pExtraInterfaceInfo = GetMemTracker()->Track(GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbExtraInterfaceInfo)));
10773 // Call this even in the case where pExtraInterfaceInfo == NULL (certain cases are optimized and don't
10774 // require extra buffer space).
10775 pMT->InitializeExtraInterfaceInfo(pExtraInterfaceInfo);
10777 InterfaceInfo_t *pInterfaces = pMT->GetInterfaceMap();
10779 CONSISTENCY_CHECK(CheckPointer(pInterfaces));
10781 // Copy the interface map member by member so there is no junk in the padding.
10782 for (i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
10784 bmtInterfaceEntry * pEntry = &bmtInterface->pInterfaceMap[i];
10786 if (pEntry->IsDeclaredOnType())
10787 pMT->SetInterfaceDeclaredOnClass(i);
10788 _ASSERTE(!!pEntry->IsDeclaredOnType() == !!pMT->IsInterfaceDeclaredOnClass(i));
10790 pInterfaces[i].SetMethodTable(pEntry->GetInterfaceType()->GetMethodTable());
10794 pMT->SetCl(GetCl());
10796 // The type is sufficiently initialized for most general purpose accessor methods to work.
10797 // Mark the type as restored to avoid avoid asserts. Note that this also enables IBC logging.
10798 pMT->GetWriteableDataForWrite()->SetIsRestoredForBuildMethodTable();
10801 // Store status if we tried to inject duplicate interfaces
10802 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
10803 pMT->Debug_SetHasInjectedInterfaceDuplicates();
10806 // Keep bmtInterface data around since we no longer write the flags (IsDeclaredOnType and
10807 // IsImplementedByParent) into the interface map (these flags are only required during type loading).
10810 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10812 // Make sure that temporary entrypoints are create for methods. NGEN uses temporary
10813 // entrypoints as surrogate keys for precodes.
10814 pChunk->EnsureTemporaryEntryPointsCreated(GetLoaderAllocator(), GetMemTracker());
10818 { // copy onto the real vtable (methods only)
10819 //@GENERICS: Because we sometimes load an inexact parent (see ClassLoader::GetParent) the inherited slots might
10820 // come from the wrong place and need fixing up once we know the exact parent
10822 for (bmtVtable::Iterator slotIt = bmtVT->IterateSlots(); !slotIt.AtEnd(); ++slotIt)
10824 SLOT_INDEX iCurSlot = static_cast<SLOT_INDEX>(slotIt.CurrentIndex());
10826 // We want the unboxed MethodDesc if we're out of the virtual method range
10827 // and the method we're dealing with has an unboxing method. If so, then
10828 // the unboxing method was placed in the virtual section of the vtable and
10829 // we now need to place the unboxed version.
10830 MethodDesc * pMD = NULL;
10831 if (iCurSlot < bmtVT->cVirtualSlots || !slotIt->Impl().AsMDMethod()->IsUnboxing())
10833 pMD = slotIt->Impl().GetMethodDesc();
10834 CONSISTENCY_CHECK(slotIt->Decl().GetSlotIndex() == iCurSlot);
10838 pMD = slotIt->Impl().AsMDMethod()->GetUnboxedMethodDesc();
10839 CONSISTENCY_CHECK(pMD->GetSlot() == iCurSlot);
10842 CONSISTENCY_CHECK(CheckPointer(pMD));
10844 if (pMD->GetMethodTable() != pMT)
10849 // Do not write into vtable chunks shared with parent. It would introduce race
10850 // with code:MethodDesc::SetStableEntryPointInterlocked.
10852 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(iCurSlot);
10853 if (GetParentMethodTable()->GetVtableIndirections()[indirectionIndex] != pMT->GetVtableIndirections()[indirectionIndex])
10854 pMT->SetSlot(iCurSlot, pMD->GetInitialEntryPointForCopiedSlot());
10861 _ASSERTE(iCurSlot >= bmtVT->cVirtualSlots || ChangesImplementationOfVirtualSlot(iCurSlot));
10863 PCODE addr = pMD->GetTemporaryEntryPoint();
10864 _ASSERTE(addr != NULL);
10866 if (pMD->HasNonVtableSlot())
10868 *((PCODE *)pMD->GetAddrOfSlot()) = addr;
10872 pMT->SetSlot(iCurSlot, addr);
10875 if (pMD->GetSlot() == iCurSlot && pMD->RequiresStableEntryPoint())
10877 // The rest of the system assumes that certain methods always have stable entrypoints.
10878 // Create them now.
10879 pMD->GetOrCreatePrecode();
10885 // If we have any entries, then finalize them and allocate the object in class loader heap
10886 DispatchMap *pDispatchMap = NULL;
10887 DispatchMapBuilder *pDispatchMapBuilder = bmtVT->pDispatchMapBuilder;
10888 CONSISTENCY_CHECK(CheckPointer(pDispatchMapBuilder));
10890 if (pDispatchMapBuilder->Count() > 0)
10892 // Create a map in stacking memory.
10895 DispatchMap::CreateEncodedMapping(
10897 pDispatchMapBuilder,
10898 pDispatchMapBuilder->GetAllocator(),
10902 // Now finalize the impltable and allocate the block in the low frequency loader heap
10903 size_t objSize = (size_t) DispatchMap::GetObjectSize(cbMap);
10904 void * pv = AllocateFromLowFrequencyHeap(S_SIZE_T(objSize));
10905 _ASSERTE(pv != NULL);
10907 // Use placement new
10908 pDispatchMap = new (pv) DispatchMap(pbMap, cbMap);
10909 pMT->SetDispatchMap(pDispatchMap);
10912 g_sdStats.m_cDispatchMap++;
10913 g_sdStats.m_cbDispatchMap += (UINT32) objSize;
10914 LOG((LF_LOADER, LL_INFO1000, "SD: Dispatch map for %s: %d bytes for map, %d bytes total for object.\n",
10915 pMT->GetDebugClassName(), cbMap, objSize));
10920 // GetMethodData by default will cache its result. However, in the case that we're
10921 // building a MethodTable, we aren't guaranteed that this type is going to successfully
10922 // load and so caching it would result in errors down the road since the memory and
10923 // type occupying the same memory location would very likely be incorrect. The second
10924 // argument specifies that GetMethodData should not cache the returned object.
10925 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
10927 if (!IsInterface())
10929 // Propagate inheritance.
10931 // NOTE: In the world of unfolded interface this was used to propagate overrides into
10932 // the unfolded interface vtables to make sure that overrides of virtual methods
10933 // also overrode the interface methods that they contributed to. This had the
10934 // unfortunate side-effect of also overwriting regular vtable slots that had been
10935 // methodimpl'd and as a result changed the meaning of methodimpl from "substitute
10936 // the body of method A with the body of method B" to "unify the slots of methods
10937 // A and B". But now compilers have come to rely on this side-effect and it can
10938 // not be brought back to its originally intended behaviour.
10940 // For every slot whose body comes from another slot (determined by getting the MethodDesc
10941 // for a slot and seeing if MethodDesc::GetSlot returns a different value than the slot
10942 // from which the MethodDesc was recovered), copy the value of the slot stated by the
10943 // MethodDesc over top of the current slot.
10945 // Because of the way slot unification works, we need to iterate the enture vtable until
10946 // no slots need updated. To understand this, imagine the following:
10947 // C1::M1 is overridden by C2::M2
10948 // C1::M2 is methodImpled by C1::M3
10949 // C1::M3 is overridden by C2::M3
10950 // This should mean that C1::M1 is implemented by C2::M3, but if we didn't run the below
10951 // for loop a second time, this would not be propagated properly - it would only be placed
10952 // into the slot for C1::M2 and never make its way up to C1::M1.
10957 fChangeMade = FALSE;
10958 for (i = 0; i < pMT->GetNumVirtuals(); i++)
10960 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
10962 CONSISTENCY_CHECK(CheckPointer(pMD));
10963 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
10965 // This indicates that the method body in this slot was copied here through a methodImpl.
10966 // Thus, copy the value of the slot from which the body originally came, in case it was
10967 // overridden, to make sure the two slots stay in sync.
10968 DWORD originalIndex = pMD->GetSlot();
10969 if (originalIndex != i)
10971 MethodDesc *pOriginalMD = hMTData->GetImplMethodDesc(originalIndex);
10972 CONSISTENCY_CHECK(CheckPointer(pOriginalMD));
10973 CONSISTENCY_CHECK(pOriginalMD == pMT->GetMethodDescForSlot(originalIndex));
10974 if (pMD != pOriginalMD)
10976 // Copy the slot value in the method's original slot.
10977 pMT->SetSlot(i, pOriginalMD->GetInitialEntryPointForCopiedSlot());
10978 hMTData->InvalidateCachedVirtualSlot(i);
10980 // Update the pMD to the new method desc we just copied over ourselves with. This will
10981 // be used in the check for missing method block below.
10984 // This method is now duplicate
10985 pMD->SetDuplicate();
10986 INDEBUG(g_dupMethods++;)
10987 fChangeMade = TRUE;
10992 while (fChangeMade);
10995 if (!bmtProp->fNoSanityChecks)
10996 VerifyVirtualMethodsImplemented(hMTData);
11000 for (bmtVtable::Iterator i = bmtVT->IterateSlots();
11003 _ASSERTE(i->Impl().GetMethodDesc() != NULL);
11009 #ifdef FEATURE_COMINTEROP
11010 // for ComObject types, i.e. if the class extends from a COM Imported
11012 // make sure any interface implemented by the COM Imported class
11013 // is overridden fully, (OR) not overridden at all..
11014 if (bmtProp->fIsComObjectType)
11016 MethodTable::InterfaceMapIterator intIt = pMT->IterateInterfaceMap();
11017 while (intIt.Next())
11019 MethodTable* pIntfMT = intIt.GetInterface(pMT, pMT->GetLoadLevel());
11020 if (pIntfMT->GetNumVirtuals() != 0)
11022 BOOL hasComImportMethod = FALSE;
11023 BOOL hasManagedMethod = FALSE;
11025 // NOTE: Avoid caching the MethodData object for the type being built.
11026 MethodTable::MethodDataWrapper hItfImplData(MethodTable::GetMethodData(pIntfMT, pMT, FALSE));
11027 MethodTable::MethodIterator it(hItfImplData);
11028 for (;it.IsValid(); it.Next())
11030 MethodDesc *pClsMD = NULL;
11031 // If we fail to find an _IMPLEMENTATION_ for the interface MD, then
11032 // we are a ComImportMethod, otherwise we still be a ComImportMethod or
11033 // we can be a ManagedMethod.
11034 DispatchSlot impl(it.GetTarget());
11035 if (!impl.IsNull())
11037 pClsMD = it.GetMethodDesc();
11039 CONSISTENCY_CHECK(!pClsMD->IsInterface());
11040 if (pClsMD->GetClass()->IsComImport())
11042 hasComImportMethod = TRUE;
11046 hasManagedMethod = TRUE;
11051 // Need to set the pClsMD for the error reporting below.
11052 pClsMD = it.GetDeclMethodDesc();
11053 CONSISTENCY_CHECK(CheckPointer(pClsMD));
11054 hasComImportMethod = TRUE;
11057 // One and only one of the two must be set.
11058 if ((hasComImportMethod && hasManagedMethod) ||
11059 (!hasComImportMethod && !hasManagedMethod))
11061 BuildMethodTableThrowException(IDS_EE_BAD_COMEXTENDS_CLASS, pClsMD->GetNameOnNonArrayClass());
11068 // For COM event interfaces, we need to make sure that all the methods are
11069 // methods to add or remove events. This means that they all need to take
11070 // a delegate derived class and have a void return type.
11071 if (bmtProp->fComEventItfType)
11073 // COM event interfaces had better be interfaces.
11074 CONSISTENCY_CHECK(IsInterface());
11076 // Go through all the methods and check the validity of the signature.
11077 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
11078 MethodTable::MethodIterator it(hMTData);
11079 for (;it.IsValid(); it.Next())
11081 MethodDesc* pMD = it.GetMethodDesc();
11087 CONTRACT_VIOLATION(LoadsTypeViolation);
11088 if (Sig.GetReturnType() != ELEMENT_TYPE_VOID ||
11089 Sig.NumFixedArgs() != 1 ||
11090 Sig.NextArg() != ELEMENT_TYPE_CLASS ||
11091 !Sig.GetLastTypeHandleThrowing().CanCastTo(TypeHandle(g_pDelegateClass)))
11093 BuildMethodTableThrowException(IDS_EE_BAD_COMEVENTITF_CLASS, pMD->GetNameOnNonArrayClass());
11098 #endif // FEATURE_COMINTEROP
11100 // If this class uses any VTS (Version Tolerant Serialization) features
11101 // (event callbacks or OptionalField attributes) we've previously cached the
11102 // additional information in the bmtMFDescs structure. Now it's time to add
11103 // this information as an optional extension to the MethodTable.
11106 #pragma warning(pop)
11109 // Returns true if there is at least one default implementation for this interface method
11110 // We don't care about conflicts at this stage in order to avoid impact type load performance
11111 BOOL MethodTableBuilder::HasDefaultInterfaceImplementation(bmtRTType *pDeclType, MethodDesc *pDeclMD)
11113 STANDARD_VM_CONTRACT;
11115 #ifdef FEATURE_DEFAULT_INTERFACES
11116 // If the interface method is already non-abstract, we are done
11117 if (!pDeclMD->IsAbstract())
11120 // If the method is an abstract MethodImpl, this is a reabstraction:
11122 // interface IFoo { void Frob() { } }
11123 // interface IBar : IFoo { abstract void IFoo.Frob() }
11125 // We don't require these to have an implementation because they're final anyway.
11126 if (pDeclMD->IsMethodImpl())
11128 assert(pDeclMD->IsFinal());
11132 int targetSlot = pDeclMD->GetSlot();
11134 // Iterate over all the interfaces this type implements
11135 bmtInterfaceEntry * pItfEntry = NULL;
11136 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
11138 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
11140 Module * pCurIntfModule = pCurItf->GetMethodTable()->GetModule();
11142 // Go over the methods on the interface
11143 MethodTable::IntroducedMethodIterator methIt(pCurItf->GetMethodTable());
11144 for (; methIt.IsValid(); methIt.Next())
11146 MethodDesc * pPotentialImpl = methIt.GetMethodDesc();
11148 // If this interface method is not a MethodImpl, it can't possibly implement
11149 // the interface method we are looking for
11150 if (!pPotentialImpl->IsMethodImpl())
11153 // Go over all the decls this MethodImpl is implementing
11154 MethodImpl::Iterator it(pPotentialImpl);
11155 for (; it.IsValid(); it.Next())
11157 MethodDesc *pPotentialDecl = it.GetMethodDesc();
11159 // Check this is a decl with the right slot
11160 if (pPotentialDecl->GetSlot() != targetSlot)
11163 // Find out what interface this default implementation is implementing
11165 IfFailThrow(pCurIntfModule->GetMDImport()->GetParentToken(it.GetToken(), &tkParent));
11167 // We can only load the approximate interface at this point
11168 MethodTable * pPotentialInterfaceMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
11171 &bmtGenerics->typeContext,
11172 ClassLoader::ThrowIfNotFound,
11173 ClassLoader::PermitUninstDefOrRef,
11174 ClassLoader::LoadTypes,
11175 CLASS_LOAD_APPROXPARENTS,
11176 TRUE).GetMethodTable()->GetCanonicalMethodTable();
11178 // Is this a default implementation for the interface we are looking for?
11179 if (pDeclType->GetMethodTable()->HasSameTypeDefAs(pPotentialInterfaceMT))
11181 // If the type is not generic, matching defs are all we need
11182 if (!pDeclType->GetMethodTable()->HasInstantiation())
11185 // If this is generic, we need to compare under substitutions
11186 Substitution curItfSubs(tkParent, pCurIntfModule, &pCurItf->GetSubstitution());
11188 // Type Equivalence is not respected for this comparison as you can have multiple type equivalent interfaces on a class
11189 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
11190 if (MetaSig::CompareTypeDefsUnderSubstitutions(
11191 pPotentialInterfaceMT, pDeclType->GetMethodTable(),
11192 &curItfSubs, &pDeclType->GetSubstitution(),
11201 #endif // FEATURE_DEFAULT_INTERFACES
11206 void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData * hMTData)
11208 STANDARD_VM_CONTRACT;
11211 // This verification is not applicable or required in many cases
11214 if (IsAbstract() || IsInterface())
11217 #ifdef FEATURE_COMINTEROP
11218 if (bmtProp->fIsComObjectType)
11220 #endif // FEATURE_COMINTEROP
11222 // Since interfaces aren't laid out in the vtable for stub dispatch, what we need to do
11223 // is try to find an implementation for every interface contract by iterating through
11224 // the interfaces not declared on a parent.
11225 BOOL fParentIsAbstract = FALSE;
11228 fParentIsAbstract = GetParentMethodTable()->IsAbstract();
11231 // If the parent is abstract, we need to check that each virtual method is implemented
11232 if (fParentIsAbstract)
11234 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
11235 MethodTable::MethodIterator it(hMTData);
11236 for (; it.IsValid() && it.IsVirtual(); it.Next())
11238 MethodDesc *pMD = it.GetMethodDesc();
11239 if (pMD->IsAbstract())
11241 MethodDesc *pDeclMD = it.GetDeclMethodDesc();
11242 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pDeclMD->GetNameOnNonArrayClass());
11247 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs =
11248 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
11250 bmtInterfaceInfo::MapIterator intIt = bmtInterface->IterateInterfaceMap();
11251 for (; !intIt.AtEnd(); intIt.Next())
11253 if (fParentIsAbstract || !intIt->IsImplementedByParent())
11255 // Compute all TypeIDs for this interface (all duplicates in the interface map)
11256 UINT32 cInterfaceDuplicates;
11257 ComputeDispatchMapTypeIDs(
11258 intIt->GetInterfaceType()->GetMethodTable(),
11259 &intIt->GetInterfaceType()->GetSubstitution(),
11260 rgInterfaceDispatchMapTypeIDs,
11261 bmtInterface->dwInterfaceMapSize,
11262 &cInterfaceDuplicates);
11263 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
11264 _ASSERTE(cInterfaceDuplicates > 0);
11266 // NOTE: This override does not cache the resulting MethodData object.
11267 MethodTable::MethodDataWrapper hData(MethodTable::GetMethodData(
11268 rgInterfaceDispatchMapTypeIDs,
11269 cInterfaceDuplicates,
11270 intIt->GetInterfaceType()->GetMethodTable(),
11271 GetHalfBakedMethodTable()));
11272 MethodTable::MethodIterator it(hData);
11273 for (; it.IsValid() && it.IsVirtual(); it.Next())
11275 if (it.GetTarget().IsNull())
11277 MethodDesc *pMD = it.GetDeclMethodDesc();
11279 if (!HasDefaultInterfaceImplementation(intIt->GetInterfaceType(), pMD))
11280 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass());
11287 INT32 __stdcall IsDefined(Module *pModule, mdToken token, TypeHandle attributeClass)
11296 BOOL isDefined = FALSE;
11298 IMDInternalImport *pInternalImport = pModule->GetMDImport();
11299 BOOL isSealed = FALSE;
11301 HENUMInternalHolder hEnum(pInternalImport);
11304 // Get the enum first but don't get any values
11305 hEnum.EnumInit(mdtCustomAttribute, token);
11307 ULONG cMax = pInternalImport->EnumGetCount(&hEnum);
11310 // we have something to look at
11313 if (!attributeClass.IsNull())
11314 isSealed = attributeClass.GetMethodTable()->IsSealed();
11316 // Loop through the Attributes and look for the requested one
11317 mdCustomAttribute cv;
11318 while (pInternalImport->EnumNext(&hEnum, &cv))
11323 IfFailThrow(pInternalImport->GetCustomAttributeProps(cv, &tkCtor));
11325 mdToken tkType = TypeFromToken(tkCtor);
11326 if(tkType != mdtMemberRef && tkType != mdtMethodDef)
11327 continue; // we only deal with the ctor case
11330 // get the info to load the type, so we can check whether the current
11331 // attribute is a subtype of the requested attribute
11332 IfFailThrow(pInternalImport->GetParentToken(tkCtor, &tkType));
11334 _ASSERTE(TypeFromToken(tkType) == mdtTypeRef || TypeFromToken(tkType) == mdtTypeDef);
11338 caTH=ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
11339 ClassLoader::ReturnNullIfNotFound,
11340 ClassLoader::FailIfUninstDefOrRef,
11341 TypeFromToken(tkType) == mdtTypeDef ? tdAllTypes : tdNoTypes);
11345 caTH = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
11346 ClassLoader::ReturnNullIfNotFound,
11347 ClassLoader::FailIfUninstDefOrRef);
11352 // a null class implies all custom attribute
11353 if (!attributeClass.IsNull())
11357 if (attributeClass != caTH)
11362 if (!caTH.CanCastTo(attributeClass))
11368 // if we are here we got one
11377 //*******************************************************************************
11378 VOID MethodTableBuilder::CheckForRemotingProxyAttrib()
11380 STANDARD_VM_CONTRACT;
11385 //*******************************************************************************
11386 // Checks for a bunch of special interface names and if it matches then it sets
11387 // bmtProp->fIsMngStandardItf to TRUE. Additionally, it checks to see if the
11388 // type is an interface and if it has ComEventInterfaceAttribute custom attribute
11389 // set, then it sets bmtProp->fComEventItfType to true.
11391 // NOTE: This only does anything when COM interop is enabled.
11393 VOID MethodTableBuilder::CheckForSpecialTypes()
11395 #ifdef FEATURE_COMINTEROP
11396 STANDARD_VM_CONTRACT;
11399 Module *pModule = GetModule();
11400 IMDInternalImport *pMDImport = pModule->GetMDImport();
11402 // Check to see if this type is a managed standard interface. All the managed
11403 // standard interfaces live in CoreLib so checking for that first
11404 // makes the strcmp that comes afterwards acceptable.
11405 if (pModule->IsSystem())
11409 LPCUTF8 pszClassName;
11410 LPCUTF8 pszClassNamespace;
11411 if (FAILED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11413 pszClassName = pszClassNamespace = NULL;
11415 if ((pszClassName != NULL) && (pszClassNamespace != NULL))
11417 LPUTF8 pszFullyQualifiedName = NULL;
11418 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11420 // This is just to give us a scope to break out of.
11424 #define MNGSTDITF_BEGIN_INTERFACE(FriendlyName, strMngItfName, strUCOMMngItfName, strCustomMarshalerName, strCustomMarshalerCookie, strManagedViewName, NativeItfIID, bCanCastOnNativeItfQI) \
11425 if (strcmp(strMngItfName, pszFullyQualifiedName) == 0) \
11427 bmtProp->fIsMngStandardItf = true; \
11431 #define MNGSTDITF_DEFINE_METH_IMPL(FriendlyName, ECallMethName, MethName, MethSig, FcallDecl)
11433 #define MNGSTDITF_END_INTERFACE(FriendlyName)
11435 #include "mngstditflist.h"
11437 #undef MNGSTDITF_BEGIN_INTERFACE
11438 #undef MNGSTDITF_DEFINE_METH_IMPL
11439 #undef MNGSTDITF_END_INTERFACE
11446 // Check to see if the type is a COM event interface (classic COM interop only).
11449 HRESULT hr = GetCustomAttribute(GetCl(), WellKnownAttribute::ComEventInterface, NULL, NULL);
11452 bmtProp->fComEventItfType = true;
11455 #endif // FEATURE_COMINTEROP
11458 #ifdef FEATURE_READYTORUN
11460 bool ModulesAreDistributedAsAnIndivisibleUnit(Module* module1, Module* module2)
11462 if (module1 == module2)
11465 bool nativeImagesIdentical = false;
11466 if (module1->GetCompositeNativeImage() != NULL)
11468 return module1->GetCompositeNativeImage() == module2->GetCompositeNativeImage();
11474 //*******************************************************************************
11475 VOID MethodTableBuilder::CheckLayoutDependsOnOtherModules(MethodTable * pDependencyMT)
11477 STANDARD_VM_CONTRACT;
11479 // These cases are expected to be handled by the caller
11480 _ASSERTE(!(pDependencyMT == g_pObjectClass || pDependencyMT->IsTruePrimitive() || ((g_pEnumClass != NULL) && pDependencyMT->IsEnum())));
11483 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11485 // Track whether field layout of this type depend on information outside its containing module and compilation unit
11487 // It is a stronger condition than MethodTable::IsInheritanceChainLayoutFixedInCurrentVersionBubble().
11488 // It has to remain fixed across versioning changes in the module dependencies. In particular, it does
11489 // not take into account NonVersionable attribute. Otherwise, adding NonVersionable attribute to existing
11490 // type would be ReadyToRun incompatible change.
11492 bool modulesDefinedInSameDistributionUnit = ModulesAreDistributedAsAnIndivisibleUnit(pDependencyMT->GetModule(), GetModule());
11493 bool dependsOnOtherModules = !modulesDefinedInSameDistributionUnit || pDependencyMT->GetClass()->HasLayoutDependsOnOtherModules();
11495 if (dependsOnOtherModules)
11496 GetHalfBakedClass()->SetHasLayoutDependsOnOtherModules();
11499 BOOL MethodTableBuilder::NeedsAlignedBaseOffset()
11501 STANDARD_VM_CONTRACT;
11504 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11506 // This method returns whether the type needs aligned base offset in order to have layout resilient to
11507 // base class layout changes.
11509 if (IsValueClass())
11512 MethodTable * pParentMT = GetParentMethodTable();
11515 if (pParentMT == NULL || pParentMT == g_pObjectClass)
11518 // Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on
11519 // whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching
11520 // ReadyToRun images with and without input bubble enabled.
11521 if (!GetModule()->GetPEAssembly()->IsReadyToRun())
11523 // Always use ReadyToRun field layout algorithm to produce ReadyToRun images
11527 if (!ModulesAreDistributedAsAnIndivisibleUnit(GetModule(), pParentMT->GetModule()) ||
11528 pParentMT->GetClass()->HasLayoutDependsOnOtherModules())
11535 #endif // FEATURE_READYTORUN
11537 //*******************************************************************************
11539 // Used by BuildMethodTable
11541 // Set the HasFinalizer and HasCriticalFinalizer flags
11543 VOID MethodTableBuilder::SetFinalizationSemantics()
11545 STANDARD_VM_CONTRACT;
11547 if (g_pObjectFinalizerMD && !IsInterface() && !IsValueClass())
11549 WORD slot = g_pObjectFinalizerMD->GetSlot();
11551 // Objects not derived from Object will get marked as having a finalizer, if they have
11552 // sufficient virtual methods. This will only be an issue if they can be allocated
11553 // in the GC heap (which will cause all sorts of other problems).
11554 if (slot < bmtVT->cVirtualSlots && (*bmtVT)[slot].Impl().GetMethodDesc() != g_pObjectFinalizerMD)
11556 GetHalfBakedMethodTable()->SetHasFinalizer();
11558 // The need for a critical finalizer can be inherited from a parent.
11559 // Since we set this automatically for CriticalFinalizerObject
11560 // elsewhere, the code below is the means by which any derived class
11561 // picks up the attribute.
11562 if (HasParent() && GetParentMethodTable()->HasCriticalFinalizer())
11564 GetHalfBakedMethodTable()->SetHasCriticalFinalizer();
11570 //*******************************************************************************
11572 // Used by BuildMethodTable
11574 // Perform relevant GC calculations for value classes
11576 VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCache)
11578 STANDARD_VM_CONTRACT;
11582 EEClass *pClass = GetHalfBakedClass();
11583 MethodTable *pMT = GetHalfBakedMethodTable();
11585 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
11587 // Note that for value classes, the following calculation is only appropriate
11588 // when the instance is in its "boxed" state.
11589 if (bmtFP->NumGCPointerSeries != 0)
11591 CGCDescSeries *pSeries;
11592 CGCDescSeries *pHighest;
11594 pMT->SetContainsPointers();
11596 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
11598 // special case when all instance fields are objects - we can encode that as one serie.
11599 if (bmtFP->fIsAllGCPointers)
11601 _ASSERTE(bmtFP->NumGCPointerSeries == 1);
11603 CGCDescSeries* pSeries = CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries();
11605 // the data is right after the method table ptr
11606 int offsetToData = TARGET_POINTER_SIZE;
11608 // Set the size as the negative of the BaseSize (the GC always adds the total
11609 // size of the object, so what you end up with is the size of the data portion of the instance)
11610 pSeries->SetSeriesSize(-(SSIZE_T)(offsetToData + TARGET_POINTER_SIZE));
11611 pSeries->SetSeriesOffset(offsetToData);
11616 // Copy the pointer series map from the parent
11617 if (bmtParent->NumParentPointerSeries != 0)
11619 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
11620 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize),
11621 (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize),
11622 ParentGCSize - sizeof(size_t) // sizeof(size_t) is the NumSeries count
11628 if (bmtFP->NumInlineArrayElements > 1)
11630 repeat = bmtFP->NumInlineArrayElements;
11633 // Build the pointer series map for pointers in this instance
11634 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11635 if (bmtFP->NumInstanceGCPointerFields)
11637 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
11638 pSeries->SetSeriesSize((size_t)(bmtFP->NumInstanceGCPointerFields * repeat * TARGET_POINTER_SIZE) - (size_t)pMT->GetBaseSize());
11639 pSeries->SetSeriesOffset(bmtFP->GCPointerFieldStart + OBJECT_SIZE);
11643 // Insert GC info for fields which are by-value classes
11644 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
11646 if (pFieldDescList[i].IsByValue())
11648 MethodTable* pByValueMT = pByValueClassCache[i];
11650 if (pByValueMT->ContainsPointers())
11652 // Offset of the by value class in the class we are building, does NOT include Object
11653 DWORD dwCurrentOffset = pFieldDescList[i].GetOffset();
11654 DWORD dwElementSize = pByValueMT->GetBaseSize() - OBJECT_BASESIZE;
11656 // if we have an inline array, we will have only one formal instance field,
11657 // but will have to replicate the layout "repeat" times.
11658 for (DWORD r = 0; r < repeat; r++)
11660 // The by value class may have more than one pointer series
11661 CGCDescSeries* pByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetLowestSeries();
11662 SIZE_T dwNumByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
11664 for (SIZE_T j = 0; j < dwNumByValueSeries; j++)
11666 size_t cbSeriesSize;
11667 size_t cbSeriesOffset;
11669 _ASSERTE(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11671 cbSeriesSize = pByValueSeries->GetSeriesSize();
11673 // Add back the base size of the by value class, since it's being transplanted to this class
11674 cbSeriesSize += pByValueMT->GetBaseSize();
11676 // Subtract the base size of the class we're building
11677 cbSeriesSize -= pMT->GetBaseSize();
11679 // Set current series we're building
11680 pSeries->SetSeriesSize(cbSeriesSize);
11682 // Get offset into the value class of the first pointer field (includes a +Object)
11683 cbSeriesOffset = pByValueSeries->GetSeriesOffset();
11685 // Add element N offset
11686 cbSeriesOffset += r * dwElementSize;
11688 // Add it to the offset of the by value class in our class
11689 cbSeriesOffset += dwCurrentOffset;
11691 pSeries->SetSeriesOffset(cbSeriesOffset); // Offset of field
11700 // Adjust the inherited series - since the base size has increased by "# new field instance bytes", we need to
11701 // subtract that from all the series (since the series always has BaseSize subtracted for it - see gcdesc.h)
11702 pHighest = CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries();
11703 while (pSeries <= pHighest)
11705 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
11706 pSeries->SetSeriesSize( pSeries->GetSeriesSize() - ((size_t) pMT->GetBaseSize() - (size_t) GetParentMethodTable()->GetBaseSize()) );
11710 _ASSERTE(pSeries-1 <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11715 //*******************************************************************************
11717 // Used by BuildMethodTable
11719 // Check for the presence of type equivalence. If present, make sure
11720 // it is permitted to be on this type.
11723 void MethodTableBuilder::CheckForTypeEquivalence(
11724 WORD cBuildingInterfaceList,
11725 BuildingInterfaceInfo_t *pBuildingInterfaceList)
11727 STANDARD_VM_CONTRACT;
11729 #ifdef FEATURE_TYPEEQUIVALENCE
11730 bmtProp->fIsTypeEquivalent = !!IsTypeDefEquivalent(GetCl(), GetModule());
11732 if (bmtProp->fIsTypeEquivalent)
11734 BOOL comImportOrEventInterface = IsComImport();
11735 #ifdef FEATURE_COMINTEROP
11736 comImportOrEventInterface = comImportOrEventInterface || bmtProp->fComEventItfType;
11737 #endif // FEATURE_COMINTEROP
11739 BOOL fTypeEquivalentNotPermittedDueToType = !((comImportOrEventInterface && IsInterface()) || IsValueClass() || IsDelegate());
11740 BOOL fTypeEquivalentNotPermittedDueToGenerics = bmtGenerics->HasInstantiation();
11742 if (fTypeEquivalentNotPermittedDueToType || fTypeEquivalentNotPermittedDueToGenerics)
11744 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTBADTYPE);
11747 GetHalfBakedClass()->SetIsEquivalentType();
11750 bmtProp->fHasTypeEquivalence = bmtProp->fIsTypeEquivalent;
11752 if (!bmtProp->fHasTypeEquivalence)
11754 // fHasTypeEquivalence flag is inherited from interfaces so we can quickly detect
11755 // types that implement type equivalent interfaces
11756 for (WORD i = 0; i < cBuildingInterfaceList; i++)
11758 MethodTable *pItfMT = pBuildingInterfaceList[i].m_pMethodTable;
11759 if (pItfMT->HasTypeEquivalence())
11761 bmtProp->fHasTypeEquivalence = true;
11767 if (!bmtProp->fHasTypeEquivalence)
11769 // fHasTypeEquivalence flag is "inherited" from generic arguments so we can quickly detect
11770 // types like List<Str> where Str is a structure with the TypeIdentifierAttribute.
11771 if (bmtGenerics->HasInstantiation() && !bmtGenerics->IsTypicalTypeDefinition())
11773 Instantiation inst = bmtGenerics->GetInstantiation();
11774 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
11776 if (inst[i].HasTypeEquivalence())
11778 bmtProp->fHasTypeEquivalence = true;
11784 #endif //FEATURE_TYPEEQUIVALENCE
11787 //*******************************************************************************
11789 // Used by BuildMethodTable
11791 // Before we make the final leap, make sure we've allocated all memory needed to
11792 // fill out the RID maps.
11794 VOID MethodTableBuilder::EnsureRIDMapsCanBeFilled()
11796 STANDARD_VM_CONTRACT;
11802 // Rather than call Ensure***CanBeStored() hundreds of times, we
11803 // will call it once on the largest token we find. This relies
11804 // on an invariant that RidMaps don't use some kind of sparse
11808 mdMethodDef largest = mdMethodDefNil;
11810 DeclaredMethodIterator it(*this);
11813 if (it.Token() > largest)
11815 largest = it.Token();
11818 if ( largest != mdMethodDefNil )
11820 GetModule()->EnsureMethodDefCanBeStored(largest);
11825 mdFieldDef largest = mdFieldDefNil;
11827 for (i = 0; i < bmtMetaData->cFields; i++)
11829 if (bmtMetaData->pFields[i] > largest)
11831 largest = bmtMetaData->pFields[i];
11834 if ( largest != mdFieldDefNil )
11836 GetModule()->EnsureFieldDefCanBeStored(largest);
11841 #ifdef FEATURE_COMINTEROP
11842 //*******************************************************************************
11843 void MethodTableBuilder::GetCoClassAttribInfo()
11845 STANDARD_VM_CONTRACT;
11846 // Retrieve the CoClassAttribute CA.
11847 HRESULT hr = GetCustomAttribute(GetCl(), WellKnownAttribute::CoClass, NULL, NULL);
11850 // COM class interfaces may lazily populate the m_pCoClassForIntf field of EEClass. This field is
11851 // optional so we must ensure the optional field descriptor has been allocated.
11852 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
11853 SetIsComClassInterface();
11856 #endif // FEATURE_COMINTEROP
11858 //*******************************************************************************
11859 void MethodTableBuilder::bmtMethodImplInfo::AddMethodImpl(
11860 bmtMDMethod * pImplMethod, bmtMethodHandle declMethod, mdToken declToken,
11861 StackingAllocator * pStackingAllocator)
11863 STANDARD_VM_CONTRACT;
11865 CONSISTENCY_CHECK(CheckPointer(pImplMethod));
11866 CONSISTENCY_CHECK(!declMethod.IsNull());
11867 if (pIndex >= cMaxIndex)
11869 DWORD newEntriesCount = 0;
11871 if (!ClrSafeInt<DWORD>::multiply(cMaxIndex, 2, newEntriesCount))
11872 ThrowHR(COR_E_OVERFLOW);
11874 if (newEntriesCount == 0)
11875 newEntriesCount = 10;
11877 // If we have to grow this array, we will not free the old array before we clean up the BuildMethodTable operation
11878 // because this is a stacking allocator. However, the old array will get freed when all the stack allocator is freed.
11879 Entry *rgEntriesNew = new (pStackingAllocator) Entry[newEntriesCount];
11881 memcpy((void*)rgEntriesNew, rgEntries, sizeof(Entry) * cMaxIndex);
11883 // Start using newly allocated array.
11884 rgEntries = rgEntriesNew;
11885 cMaxIndex = newEntriesCount;
11887 rgEntries[pIndex++] = Entry(pImplMethod, declMethod, declToken);
11890 //*******************************************************************************
11891 // Returns TRUE if tok acts as a body for any methodImpl entry. FALSE, otherwise.
11892 BOOL MethodTableBuilder::bmtMethodImplInfo::IsBody(mdToken tok)
11894 LIMITED_METHOD_CONTRACT;
11895 CONSISTENCY_CHECK(TypeFromToken(tok) == mdtMethodDef);
11896 for (DWORD i = 0; i < pIndex; i++)
11898 if (GetBodyMethodDesc(i)->GetMemberDef() == tok)
11906 //*******************************************************************************
11908 MethodTableBuilder::AllocateFromHighFrequencyHeap(S_SIZE_T cbMem)
11917 return (BYTE *)GetMemTracker()->Track(
11918 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(cbMem));
11921 //*******************************************************************************
11923 MethodTableBuilder::AllocateFromLowFrequencyHeap(S_SIZE_T cbMem)
11932 return (BYTE *)GetMemTracker()->Track(
11933 GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(cbMem));
11936 //-------------------------------------------------------------------------------
11937 // Make best-case effort to obtain an image name for use in an error message.
11939 // This routine must expect to be called before the this object is fully loaded.
11940 // It can return an empty if the name isn't available or the object isn't initialized
11941 // enough to get a name, but it mustn't crash.
11942 //-------------------------------------------------------------------------------
11943 LPCWSTR MethodTableBuilder::GetPathForErrorMessages()
11945 STANDARD_VM_CONTRACT;
11947 return GetModule()->GetPathForErrorMessages();
11950 BOOL MethodTableBuilder::ChangesImplementationOfVirtualSlot(SLOT_INDEX idx)
11952 STANDARD_VM_CONTRACT;
11954 BOOL fChangesImplementation = TRUE;
11956 _ASSERTE(idx < bmtVT->cVirtualSlots);
11958 if (HasParent() && idx < GetParentMethodTable()->GetNumVirtuals())
11960 _ASSERTE(idx < bmtParent->pSlotTable->GetSlotCount());
11961 bmtMethodHandle VTImpl = (*bmtVT)[idx].Impl();
11962 bmtMethodHandle ParentImpl = (*bmtParent)[idx].Impl();
11964 fChangesImplementation = VTImpl != ParentImpl;
11966 // See code:MethodTableBuilder::SetupMethodTable2 and its logic
11967 // for handling MethodImpl's on parent classes which affect non interface
11969 if (!fChangesImplementation && (ParentImpl.GetSlotIndex() != idx))
11970 fChangesImplementation = TRUE;
11972 // If the current vtable slot is MethodImpl, is it possible that it will be updated by
11973 // the ClassLoader::PropagateCovariantReturnMethodImplSlots.
11974 if (!fChangesImplementation && VTImpl.GetMethodDesc()->IsMethodImpl())
11976 // Note: to know exactly whether the slot will be updated or not, we would need to check the
11977 // PreserveBaseOverridesAttribute presence on the current vtable slot and in the worst case
11978 // on all of its ancestors. This is expensive, so we don't do that check here and accept
11979 // the fact that we get some false positives and end up sharing less vtable chunks.
11981 // Search the previous slots in the parent vtable for the same implementation. If it exists and it was
11982 // overridden, the ClassLoader::PropagateCovariantReturnMethodImplSlots will propagate the change to the current
11983 // slot (idx), so the implementation of it will change.
11984 MethodDesc* pParentMD = ParentImpl.GetMethodDesc();
11985 for (SLOT_INDEX i = 0; i < idx; i++)
11987 if ((*bmtParent)[i].Impl().GetMethodDesc() == pParentMD && (*bmtVT)[i].Impl().GetMethodDesc() != pParentMD)
11989 fChangesImplementation = TRUE;
11996 return fChangesImplementation;
11999 // Must be called prior to setting the value of any optional field on EEClass (on a debug build an assert will
12000 // fire if this invariant is violated).
12001 void MethodTableBuilder::EnsureOptionalFieldsAreAllocated(EEClass *pClass, AllocMemTracker *pamTracker, LoaderHeap *pHeap)
12003 STANDARD_VM_CONTRACT;
12005 if (pClass->HasOptionalFields())
12008 EEClassOptionalFields *pOptFields = (EEClassOptionalFields*)
12009 pamTracker->Track(pHeap->AllocMem(S_SIZE_T(sizeof(EEClassOptionalFields))));
12011 // Initialize default values for all optional fields.
12012 pOptFields->Init();
12014 // Attach optional fields to the class.
12015 pClass->AttachOptionalFields(pOptFields);
12018 //---------------------------------------------------------------------------------------
12020 // Gather information about a generic type
12021 // - number of parameters
12022 // - variance annotations
12028 MethodTableBuilder::GatherGenericsInfo(
12031 Instantiation inst,
12032 bmtGenericsInfo * bmtGenericsInfo,
12033 StackingAllocator*pStackingAllocator)
12038 PRECONDITION(GetThreadNULLOk() != NULL);
12039 PRECONDITION(CheckPointer(pModule));
12040 PRECONDITION(CheckPointer(bmtGenericsInfo));
12044 IMDInternalImport * pInternalImport = pModule->GetMDImport();
12046 // Enumerate the formal type parameters
12047 DWORD numGenericArgs = pModule->m_pTypeGenericInfoMap->GetGenericArgumentCount(cl, pInternalImport);
12049 // Work out what kind of EEClass we're creating w.r.t. generics. If there
12050 // are no generics involved this will be a VMFLAG_NONGENERIC.
12051 BOOL fHasVariance = FALSE;
12052 if (numGenericArgs > 0)
12054 // Generic type verification
12058 if (FAILED(pInternalImport->GetTypeDefProps(cl, &dwAttr, &tkParent)))
12060 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12062 // A generic with explicit layout is not allowed.
12063 if (IsTdExplicitLayout(dwAttr))
12065 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_EXPLICIT_GENERIC);
12069 bmtGenericsInfo->numDicts = 1;
12071 mdGenericParam tkTyPar;
12072 bmtGenericsInfo->pVarianceInfo = new (pStackingAllocator) BYTE[numGenericArgs];
12074 // If it has generic arguments but none have been specified, then load the instantiation at the formals
12075 if (inst.IsEmpty())
12077 bmtGenericsInfo->fTypicalInstantiation = TRUE;
12078 S_UINT32 scbAllocSize = S_UINT32(numGenericArgs) * S_UINT32(sizeof(TypeHandle));
12079 TypeHandle * genericArgs = (TypeHandle *) pStackingAllocator->Alloc(scbAllocSize);
12081 inst = Instantiation(genericArgs, numGenericArgs);
12083 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
12087 bmtGenericsInfo->fTypicalInstantiation = FALSE;
12089 bmtGenericsInfo->fSharedByGenericInstantiations = TypeHandle::IsCanonicalSubtypeInstantiation(inst);
12090 _ASSERTE(bmtGenericsInfo->fSharedByGenericInstantiations == ClassLoader::IsSharableInstantiation(inst));
12093 // Set typical instantiation MethodTable
12095 MethodTable * pTypicalInstantiationMT = pModule->LookupTypeDef(cl).AsMethodTable();
12096 // Typical instantiation was already loaded by code:ClassLoader::LoadApproxTypeThrowing
12097 _ASSERTE(pTypicalInstantiationMT != NULL);
12098 bmtGenericsInfo->dbg_pTypicalInstantiationMT = pTypicalInstantiationMT;
12103 TypeHandle * pDestInst = (TypeHandle *)inst.GetRawArgs();
12105 HENUMInternal hEnumGenericPars;
12106 HRESULT hr = pInternalImport->EnumInit(mdtGenericParam, cl, &hEnumGenericPars);
12108 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12110 // Protect multi-threaded access to Module.m_GenericParamToDescMap. Other threads may be loading the same type
12111 // to break type recursion dead-locks
12112 CrstHolder ch(&pModule->GetClassLoader()->m_AvailableTypesLock);
12114 for (unsigned int i = 0; i < numGenericArgs; i++)
12116 pInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
12118 if (FAILED(pInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
12120 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12123 if (bmtGenericsInfo->fTypicalInstantiation)
12125 // code:Module.m_GenericParamToDescMap maps generic parameter RIDs to TypeVarTypeDesc
12126 // instances so that we do not leak by allocating them all over again, if the type
12127 // repeatedly fails to load.
12128 TypeVarTypeDesc* pTypeVarTypeDesc = pModule->LookupGenericParam(tkTyPar);
12129 if (pTypeVarTypeDesc == NULL)
12131 // Do NOT use the alloc tracker for this memory as we need it stay allocated even if the load fails.
12132 void* mem = (void*)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TypeVarTypeDesc)));
12133 pTypeVarTypeDesc = new (mem) TypeVarTypeDesc(pModule, cl, i, tkTyPar);
12135 pModule->StoreGenericParamThrowing(tkTyPar, pTypeVarTypeDesc);
12137 pDestInst[i] = TypeHandle(pTypeVarTypeDesc);
12140 DWORD varianceAnnotation = flags & gpVarianceMask;
12141 bmtGenericsInfo->pVarianceInfo[i] = static_cast<BYTE>(varianceAnnotation);
12142 if (varianceAnnotation != gpNonVariant)
12144 if (varianceAnnotation != gpContravariant && varianceAnnotation != gpCovariant)
12146 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADVARIANCE);
12150 fHasVariance = TRUE;
12157 bmtGenericsInfo->pVarianceInfo = NULL;
12161 bmtGenericsInfo->fTypicalInstantiation = FALSE;
12162 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
12163 bmtGenericsInfo->numDicts = 0;
12166 bmtGenericsInfo->fContainsGenericVariables = MethodTable::ComputeContainsGenericVariables(inst);
12168 SigTypeContext typeContext(inst, Instantiation());
12169 bmtGenericsInfo->typeContext = typeContext;
12170 } // MethodTableBuilder::GatherGenericsInfo
12172 //=======================================================================
12173 // This is invoked from the class loader while building the internal structures for a type
12174 // This function should check if explicit layout metadata exists.
12177 // TRUE - yes, there's layout metadata
12178 // FALSE - no, there's no layout.
12179 // fail - throws a typeload exception
12182 // *pNLType gets set to nltAnsi or nltUnicode
12183 // *pPackingSize declared packing size
12184 // *pfExplicitoffsets offsets explicit in metadata or computed?
12185 //=======================================================================
12186 BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, mdTypeDef cl, MethodTable* pParentMT, BYTE* pPackingSize, BYTE* pNLTType, BOOL* pfExplicitOffsets)
12193 PRECONDITION(CheckPointer(pInternalImport));
12194 PRECONDITION(CheckPointer(pPackingSize));
12195 PRECONDITION(CheckPointer(pNLTType));
12196 PRECONDITION(CheckPointer(pfExplicitOffsets));
12202 if (FAILED(pInternalImport->GetTypeDefProps(cl, &clFlags, NULL)))
12204 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12207 if (IsTdAutoLayout(clFlags))
12211 else if (IsTdSequentialLayout(clFlags))
12213 *pfExplicitOffsets = FALSE;
12215 else if (IsTdExplicitLayout(clFlags))
12217 *pfExplicitOffsets = TRUE;
12221 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12224 // We now know this class has seq. or explicit layout. Ensure the parent does too.
12225 if (pParentMT && !(pParentMT->IsObjectClass() || pParentMT->IsValueTypeClass()) && !(pParentMT->HasLayout()))
12226 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12228 if (IsTdAnsiClass(clFlags))
12230 *pNLTType = nltAnsi;
12232 else if (IsTdUnicodeClass(clFlags))
12234 *pNLTType = nltUnicode;
12236 else if (IsTdAutoClass(clFlags))
12238 #ifdef TARGET_WINDOWS
12239 *pNLTType = nltUnicode;
12241 *pNLTType = nltAnsi; // We don't have a utf8 charset in metadata yet, but ANSI == UTF-8 off-Windows
12246 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12250 hr = pInternalImport->GetClassPackSize(cl, &dwPackSize);
12251 if (FAILED(hr) || dwPackSize == 0)
12252 dwPackSize = DEFAULT_PACKING_SIZE;
12254 // This has to be reduced to a BYTE value, so we had better make sure it fits. If
12255 // not, we'll throw an exception instead of trying to munge the value to what we
12256 // think the user might want.
12257 if (!FitsInU1((UINT64)(dwPackSize)))
12259 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12262 *pPackingSize = (BYTE)dwPackSize;
12267 //---------------------------------------------------------------------------------------
12269 // This service is called for normal classes -- and for the pseudo class we invent to
12270 // hold the module's public members.
12274 ClassLoader::CreateTypeHandleForTypeDefThrowing(
12277 Instantiation inst,
12278 AllocMemTracker * pamTracker)
12280 CONTRACT(TypeHandle)
12283 PRECONDITION(GetThreadNULLOk() != NULL);
12284 PRECONDITION(CheckPointer(pModule));
12285 POSTCONDITION(!RETVAL.IsNull());
12286 POSTCONDITION(CheckPointer(RETVAL.GetMethodTable()));
12290 MethodTable * pMT = NULL;
12292 MethodTable * pParentMethodTable = NULL;
12293 SigPointer parentInst;
12294 mdTypeDef tdEnclosing = mdTypeDefNil;
12296 BuildingInterfaceInfo_t * pInterfaceBuildInfo = NULL;
12297 IMDInternalImport * pInternalImport = NULL;
12298 LayoutRawFieldInfo * pLayoutRawFieldInfos = NULL;
12299 MethodTableBuilder::bmtGenericsInfo genericsInfo;
12301 Assembly * pAssembly = pModule->GetAssembly();
12302 pInternalImport = pModule->GetMDImport();
12304 if (TypeFromToken(cl) != mdtTypeDef || !pInternalImport->IsValidToken(cl))
12306 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12309 // GetCheckpoint for the thread-based allocator
12310 // This checkpoint provides a scope for all transient allocations of data structures
12311 // used during class loading.
12312 // <NICE> Ideally a debug/checked build should pass around tokens indicating the Checkpoint
12313 // being used and check these dynamically </NICE>
12314 ACQUIRE_STACKING_ALLOCATOR(pStackingAllocator);
12316 // Gather up generics info
12317 MethodTableBuilder::GatherGenericsInfo(pModule, cl, inst, &genericsInfo, pStackingAllocator);
12319 Module * pLoaderModule = pModule;
12320 if (!inst.IsEmpty())
12322 pLoaderModule = ClassLoader::ComputeLoaderModuleWorker(
12327 pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(pModule, inst);
12330 LoaderAllocator * pAllocator = pLoaderModule->GetLoaderAllocator();
12333 // As this is loading a parent type, we are allowed to override the load type limit.
12334 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
12335 pParentMethodTable = LoadApproxParentThrowing(pModule, cl, &parentInst, &genericsInfo.typeContext);
12338 if (pParentMethodTable != NULL)
12340 // Since methods on System.Array assume the layout of arrays, we can not allow
12341 // subclassing of arrays, it is sealed from the users point of view.
12342 // Value types and enums should be sealed - disable inheritting from them (we cannot require sealed
12343 // flag because of AppCompat)
12344 if (pParentMethodTable->IsSealed() ||
12345 (pParentMethodTable == g_pArrayClass) ||
12346 pParentMethodTable->IsValueType())
12348 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_SEALEDPARENT);
12351 DWORD dwTotalDicts = genericsInfo.numDicts + pParentMethodTable->GetNumDicts();
12352 if (!FitsIn<WORD>(dwTotalDicts))
12354 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_TOOMANYGENERICARGS);
12356 genericsInfo.numDicts = static_cast<WORD>(dwTotalDicts);
12359 GetEnclosingClassThrowing(pInternalImport, pModule, cl, &tdEnclosing);
12361 BYTE nstructPackingSize = 0, nstructNLT = 0;
12362 BOOL fExplicitOffsets = FALSE;
12363 // NOTE: HasLayoutMetadata does not load classes
12365 !genericsInfo.fContainsGenericVariables &&
12367 pModule->GetAssembly(),
12370 pParentMethodTable,
12371 &nstructPackingSize,
12373 &fExplicitOffsets);
12375 BOOL fIsEnum = ((g_pEnumClass != NULL) && (pParentMethodTable == g_pEnumClass));
12377 // enums may not have layout because they derive from g_pEnumClass and that has no layout
12378 // this is enforced by HasLayoutMetadata above
12379 _ASSERTE(!(fIsEnum && fHasLayout));
12381 // This is a delegate class if it derives from MulticastDelegate (we do not allow single cast delegates)
12382 BOOL fIsDelegate = pParentMethodTable && pParentMethodTable == g_pMulticastDelegateClass;
12384 // Create a EEClass entry for it, filling out a few fields, such as the parent class token
12385 // (and the generic type should we be creating an instantiation)
12386 EEClass * pClass = MethodTableBuilder::CreateClass(
12396 if ((pParentMethodTable != NULL) && (pParentMethodTable == g_pDelegateClass))
12398 // Note we do not allow single cast delegates
12399 if (pModule->GetAssembly() != SystemDomain::SystemAssembly())
12401 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_CANNOT_INHERIT_FROM_DELEGATE);
12405 // Only MultiCastDelegate should inherit from Delegate
12408 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
12410 className = nameSpace = "Invalid TypeDef record";
12412 BAD_FORMAT_NOTHROW_ASSERT(strcmp(className, "MulticastDelegate") == 0);
12418 if (!pClass->IsSealed())
12420 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_DELEGATE_CLASS_NOTSEALED);
12423 pClass->SetIsDelegate();
12426 if (tdEnclosing != mdTypeDefNil)
12428 pClass->SetIsNested();
12429 THROW_BAD_FORMAT_MAYBE(IsTdNested(pClass->GetProtection()), VLDTR_E_TD_ENCLNOTNESTED, pModule);
12431 else if (IsTdNested(pClass->GetProtection()))
12433 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12436 // We only permit generic interfaces and delegates to have variant type parameters
12437 if (genericsInfo.pVarianceInfo != NULL && !pClass->IsInterface() && !fIsDelegate)
12439 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_CLASS);
12442 // Now load all the interfaces
12443 HENUMInternalHolder hEnumInterfaceImpl(pInternalImport);
12444 hEnumInterfaceImpl.EnumInit(mdtInterfaceImpl, cl);
12446 cInterfaces = pInternalImport->EnumGetCount(&hEnumInterfaceImpl);
12448 if (cInterfaces != 0)
12452 // Allocate the BuildingInterfaceList table
12453 pInterfaceBuildInfo = new (pStackingAllocator) BuildingInterfaceInfo_t[cInterfaces];
12455 mdInterfaceImpl ii;
12456 for (i = 0; pInternalImport->EnumNext(&hEnumInterfaceImpl, &ii); i++)
12458 // Get properties on this interface
12459 mdTypeRef crInterface;
12460 if (FAILED(pInternalImport->GetTypeOfInterfaceImpl(ii, &crInterface)))
12462 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12464 // validate the token
12465 mdToken crIntType =
12466 (RidFromToken(crInterface) && pInternalImport->IsValidToken(crInterface)) ?
12467 TypeFromToken(crInterface) :
12476 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12479 TypeHandle intType;
12482 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
12483 intType = LoadApproxTypeThrowing(pModule, crInterface, NULL, &genericsInfo.typeContext);
12486 pInterfaceBuildInfo[i].m_pMethodTable = intType.AsMethodTable();
12487 if (pInterfaceBuildInfo[i].m_pMethodTable == NULL)
12489 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12492 // Ensure this is an interface
12493 if (!pInterfaceBuildInfo[i].m_pMethodTable->IsInterface())
12495 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_NOTINTERFACE);
12498 // Check interface for use of variant type parameters
12499 if ((genericsInfo.pVarianceInfo != NULL) && (TypeFromToken(crInterface) == mdtTypeSpec))
12502 PCCOR_SIGNATURE pSig;
12503 if (FAILED(pInternalImport->GetTypeSpecFromToken(crInterface, &pSig, &cSig)))
12505 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12507 // Interfaces behave covariantly
12508 if (!EEClass::CheckVarianceInSig(
12509 genericsInfo.GetNumGenericArgs(),
12510 genericsInfo.pVarianceInfo,
12512 SigPointer(pSig, cSig),
12515 pAssembly->ThrowTypeLoadException(
12518 IDS_CLASSLOAD_VARIANCE_IN_INTERFACE);
12522 _ASSERTE(i == cInterfaces);
12526 /* Variant delegates should not have any instance fields of the variant.
12527 type parameter. For now, we just completely disallow all fields even
12528 if they are non-variant or static, as it is not a useful scenario.
12529 @TODO: A more logical place for this check would be in
12530 MethodTableBuilder::EnumerateClassMembers() */
12531 (fIsDelegate && genericsInfo.pVarianceInfo))
12533 // check for fields and variance
12535 HENUMInternalHolder hEnumField(pInternalImport);
12536 hEnumField.EnumInit(mdtFieldDef, cl);
12538 cFields = pInternalImport->EnumGetCount(&hEnumField);
12540 if ((cFields != 0) && fIsDelegate && (genericsInfo.pVarianceInfo != NULL))
12542 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_IN_DELEGATE);
12547 // Though we fail on this condition, we should never run into it.
12548 CONSISTENCY_CHECK(nstructPackingSize != 0);
12549 // MD Val check: PackingSize
12550 if((nstructPackingSize == 0) ||
12551 (nstructPackingSize > 128) ||
12552 (nstructPackingSize & (nstructPackingSize-1)))
12554 THROW_BAD_FORMAT_MAYBE(!"ClassLayout:Invalid PackingSize", BFA_BAD_PACKING_SIZE, pModule);
12555 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12558 pLayoutRawFieldInfos = (LayoutRawFieldInfo *)pStackingAllocator->Alloc(
12559 (S_UINT32(1) + S_UINT32(cFields)) * S_UINT32(sizeof(LayoutRawFieldInfo)));
12562 // Warning: this can load classes
12563 CONTRACT_VIOLATION(LoadsTypeViolation);
12565 // Set a flag that allows us to break dead-locks that are result of the LoadsTypeViolation
12566 ThreadStateNCStackHolder tsNC(TRUE, Thread::TSNC_LoadsTypeViolation);
12568 EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
12570 nstructPackingSize,
12573 pParentMethodTable,
12577 &genericsInfo.typeContext,
12578 &(((LayoutEEClass *)pClass)->m_LayoutInfo),
12579 pLayoutRawFieldInfos,
12586 // Resolve this class, given that we know now that all of its dependencies are loaded and resolved.
12587 // !!! This must be the last thing in this TRY block: if MethodTableBuilder succeeds, it has published the class
12588 // and there is no going back.
12589 MethodTableBuilder builder(
12592 pStackingAllocator,
12595 pMT = builder.BuildMethodTableThrowing(
12600 pInterfaceBuildInfo,
12601 pLayoutRawFieldInfos,
12602 pParentMethodTable,
12605 (WORD)cInterfaces);
12607 RETURN(TypeHandle(pMT));
12608 } // ClassLoader::CreateTypeHandleForTypeDefThrowing