1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // File: METHODTABLEBUILDER.CPP
12 // ============================================================================
16 #include "methodtablebuilder.h"
18 #include "sigbuilder.h"
19 #include "dllimport.h"
20 #include "fieldmarshaler.h"
22 #include "mdaassistants.h"
24 #include "customattribute.h"
25 #include "typestring.h"
27 //*******************************************************************************
28 // Helper functions to sort GCdescs by offset (decending order)
29 int __cdecl compareCGCDescSeries(const void *arg1, const void *arg2)
31 STATIC_CONTRACT_NOTHROW;
32 STATIC_CONTRACT_GC_NOTRIGGER;
33 STATIC_CONTRACT_FORBID_FAULT;
35 CGCDescSeries* gcInfo1 = (CGCDescSeries*) arg1;
36 CGCDescSeries* gcInfo2 = (CGCDescSeries*) arg2;
38 return (int)(gcInfo2->GetSeriesOffset() - gcInfo1->GetSeriesOffset());
41 //*******************************************************************************
43 const char* FormatSig(MethodDesc* pMD, LoaderHeap *pHeap, AllocMemTracker *pamTracker);
46 unsigned g_dupMethods = 0;
49 //==========================================================================
50 // This function is very specific about how it constructs a EEClass. It first
51 // determines the necessary size of the vtable and the number of statics that
52 // this class requires. The necessary memory is then allocated for a EEClass
53 // and its vtable and statics. The class members are then initialized and
54 // the memory is then returned to the caller
56 // LPEEClass CreateClass()
59 // [in] scope - scope of the current class not the one requested to be opened
60 // [in] cl - class token of the class to be created.
61 // [out] ppEEClass - pointer to pointer to hold the address of the EEClass
62 // allocated in this function.
63 // Return : returns an HRESULT indicating the success of this function.
65 // This parameter has been removed but might need to be reinstated if the
66 // global for the metadata loader is removed.
67 // [in] pIMLoad - MetaDataLoader class/object for the current scope.
70 //==========================================================================
72 MethodTableBuilder::CreateClass( Module *pModule,
77 const MethodTableBuilder::bmtGenericsInfo *bmtGenericsInfo,
78 LoaderAllocator * pAllocator,
79 AllocMemTracker *pamTracker)
84 PRECONDITION(!(fHasLayout && fDelegate));
85 PRECONDITION(!(fHasLayout && fIsEnum));
86 PRECONDITION(CheckPointer(bmtGenericsInfo));
90 EEClass *pEEClass = NULL;
91 IMDInternalImport *pInternalImport;
94 //<TODO>============================================================================
95 // vtabsize and static size need to be converted from pointer sizes to #'s
96 // of bytes this will be very important for 64 bit NT!
97 // We will need to call on IMetaDataLoad to get these sizes and fill out the
100 // From the classref call on metadata to resolve the classref and check scope
101 // to make sure that this class is in the same scope otherwise we need to open
102 // a new scope and possibly file.
104 // if the scopes are different call the code to load a new file and get the new scope
106 // scopes are the same so we can use the existing scope to get the class info
108 // This method needs to be fleshed out.more it currently just returns enough
109 // space for the defined EEClass and the vtable and statics are not set.
110 //=============================================================================</TODO>
114 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) LayoutEEClass();
118 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) DelegateEEClass();
122 pEEClass = new (pAllocator->GetLowFrequencyHeap(), pamTracker) EEClass(sizeof(EEClass));
125 DWORD dwAttrClass = 0;
126 mdToken tkExtends = mdTokenNil;
128 // Set up variance info
129 if (bmtGenericsInfo->pVarianceInfo)
131 // Variance info is an optional field on EEClass, so ensure the optional field descriptor has been
133 EnsureOptionalFieldsAreAllocated(pEEClass, pamTracker, pAllocator->GetLowFrequencyHeap());
134 pEEClass->SetVarianceInfo((BYTE*) pamTracker->Track(
135 pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(bmtGenericsInfo->GetNumGenericArgs()))));
137 memcpy(pEEClass->GetVarianceInfo(), bmtGenericsInfo->pVarianceInfo, bmtGenericsInfo->GetNumGenericArgs());
140 pInternalImport = pModule->GetMDImport();
142 if (pInternalImport == NULL)
143 COMPlusThrowHR(COR_E_TYPELOAD);
145 IfFailThrow(pInternalImport->GetTypeDefProps(
150 pEEClass->m_dwAttrClass = dwAttrClass;
152 // MDVal check: can't be both tdSequentialLayout and tdExplicitLayout
153 if((dwAttrClass & tdLayoutMask) == tdLayoutMask)
154 COMPlusThrowHR(COR_E_TYPELOAD);
156 if (IsTdInterface(dwAttrClass))
158 // MDVal check: must have nil tkExtends and must be tdAbstract
159 if((tkExtends & 0x00FFFFFF)||(!IsTdAbstract(dwAttrClass)))
160 COMPlusThrowHR(COR_E_TYPELOAD);
164 pEEClass->SetHasLayout();
166 #ifdef FEATURE_COMINTEROP
167 if (IsTdWindowsRuntime(dwAttrClass))
169 Assembly *pAssembly = pModule->GetAssembly();
171 // On the desktop CLR, we do not allow non-FX assemblies to use/define WindowsRuntimeImport attribute.
173 // On CoreCLR, however, we do allow non-FX assemblies to have this attribute. This enables scenarios where we can
174 // activate 3rd-party WinRT components outside AppContainer - 1st party WinRT components are already allowed
175 // to be activated outside AppContainer (on both Desktop and CoreCLR).
177 pEEClass->SetProjectedFromWinRT();
180 if (pEEClass->IsProjectedFromWinRT())
182 if (IsTdInterface(dwAttrClass))
185 // Check for GuidAttribute
187 BOOL bHasGuid = FALSE;
190 HRESULT hr = pModule->GetMDImport()->GetItemGuid(cl, &guid);
193 if (IsEqualGUID(guid, GUID_NULL))
195 // A WinRT interface should have a GUID
196 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), cl, IDS_EE_WINRT_INTERFACE_WITHOUT_GUID);
201 WinMDAdapter::RedirectedTypeIndex redirectedTypeIndex;
202 redirectedTypeIndex = WinRTTypeNameConverter::GetRedirectedTypeIndexByName(pModule, cl);
203 if (redirectedTypeIndex != WinMDAdapter::RedirectedTypeIndex_Invalid)
205 EnsureOptionalFieldsAreAllocated(pEEClass, pamTracker, pAllocator->GetLowFrequencyHeap());
206 pEEClass->SetWinRTRedirectedTypeIndex(redirectedTypeIndex);
208 #endif // FEAUTRE_COMINTEROP
211 pModule->GetClassLoader()->m_dwDebugClasses++;
217 //*******************************************************************************
219 // Create a hash of all methods in this class. The hash is from method name to MethodDesc.
221 MethodTableBuilder::MethodNameHash *
222 MethodTableBuilder::CreateMethodChainHash(
225 STANDARD_VM_CONTRACT;
227 MethodNameHash *pHash = new (GetStackingAllocator()) MethodNameHash();
228 pHash->Init(pMT->GetNumVirtuals(), GetStackingAllocator());
230 unsigned numVirtuals = GetParentMethodTable()->GetNumVirtuals();
231 for (unsigned i = 0; i < numVirtuals; ++i)
233 bmtMethodSlot &slot = (*bmtParent->pSlotTable)[i];
234 bmtRTMethod * pMethod = slot.Decl().AsRTMethod();
235 const MethodSignature &sig = pMethod->GetMethodSignature();
236 pHash->Insert(sig.GetName(), pMethod);
243 //*******************************************************************************
245 // Find a method in this class hierarchy - used ONLY by the loader during layout. Do not use at runtime.
247 // *ppMemberSignature must be NULL on entry - it and *pcMemberSignature may or may not be filled out
249 // ppMethodDesc will be filled out with NULL if no matching method in the hierarchy is found.
251 // Returns FALSE if there was an error of some kind.
253 // pMethodConstraintsMatch receives the result of comparing the method constraints.
254 MethodTableBuilder::bmtRTMethod *
255 MethodTableBuilder::LoaderFindMethodInParentClass(
256 const MethodSignature & methodSig,
257 BOOL * pMethodConstraintsMatch)
262 PRECONDITION(CheckPointer(this));
263 PRECONDITION(CheckPointer(bmtParent));
264 PRECONDITION(CheckPointer(methodSig.GetModule()));
265 PRECONDITION(CheckPointer(methodSig.GetSignature()));
266 PRECONDITION(HasParent());
267 PRECONDITION(methodSig.GetSignatureLength() != 0);
272 MethodNameHash::HashEntry * pEntry;
274 // Have we created a hash of all the methods in the class chain?
275 if (bmtParent->pParentMethodHash == NULL)
277 // There may be such a method, so we will now create a hash table to reduce the pain for
280 // <TODO> Are we really sure that this is worth doing? </TODO>
281 bmtParent->pParentMethodHash = CreateMethodChainHash(GetParentMethodTable());
284 // We have a hash table, so use it
285 pEntry = bmtParent->pParentMethodHash->Lookup(methodSig.GetName());
287 // Traverse the chain of all methods with this name
288 while (pEntry != NULL)
290 bmtRTMethod * pEntryMethod = pEntry->m_data;
291 const MethodSignature & entrySig = pEntryMethod->GetMethodSignature();
293 // Note instantiation info
295 if (methodSig.Equivalent(entrySig))
297 if (pMethodConstraintsMatch != NULL)
299 // Check the constraints are consistent,
300 // and return the result to the caller.
301 // We do this here to avoid recalculating pSubst.
302 *pMethodConstraintsMatch = MetaSig::CompareMethodConstraints(
303 &methodSig.GetSubstitution(), methodSig.GetModule(), methodSig.GetToken(),
304 &entrySig.GetSubstitution(), entrySig.GetModule(), entrySig.GetToken());
311 // Advance to next item in the hash chain which has the same name
312 pEntry = bmtParent->pParentMethodHash->FindNext(pEntry);
316 //@TODO: Move to this code, as the use of a HashTable is broken; overriding semantics
317 //@TODO: require matching against the most-derived slot of a given name and signature,
318 //@TODO: (which deals specifically with newslot methods with identical name and sig), but
319 //@TODO: HashTables are by definition unordered and so we've only been getting by with the
320 //@TODO: implementation being compatible with the order in which methods were added to
321 //@TODO: the HashTable in CreateMethodChainHash.
323 bmtParentInfo::Iterator it(bmtParent->IterateSlots());
324 it.MoveTo(static_cast<size_t>(GetParentMethodTable()->GetNumVirtuals()));
327 bmtMethodHandle decl(it->Decl());
328 const MethodSignature &declSig(decl.GetMethodSignature());
329 if (declSig == methodSig)
331 if (pMethodConstraintsMatch != NULL)
333 // Check the constraints are consistent,
334 // and return the result to the caller.
335 // We do this here to avoid recalculating pSubst.
336 *pMethodConstraintsMatch = MetaSig::CompareMethodConstraints(
337 &methodSig.GetSubstitution(), methodSig.GetModule(), methodSig.GetToken(),
338 &declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken());
341 return decl.AsRTMethod();
349 //*******************************************************************************
351 // Given an interface map to fill out, expand pNewInterface (and its sub-interfaces) into it, increasing
352 // pdwInterfaceListSize as appropriate, and avoiding duplicates.
355 MethodTableBuilder::ExpandApproxInterface(
356 bmtInterfaceInfo * bmtInterface, // out parameter, various parts cumulatively written to.
357 const Substitution * pNewInterfaceSubstChain,
358 MethodTable * pNewInterface,
359 InterfaceDeclarationScope declScope
360 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
362 STANDARD_VM_CONTRACT;
364 //#ExpandingInterfaces
365 // We expand the tree of inherited interfaces into a set by adding the
366 // current node BEFORE expanding the parents of the current node.
367 // ****** This must be consistent with code:ExpandExactInterface *******
368 // ****** This must be consistent with code:ClassCompat::MethodTableBuilder::BuildInteropVTable_ExpandInterface *******
370 // The interface list contains the fully expanded set of interfaces from the parent then
371 // we start adding all the interfaces we declare. We need to know which interfaces
372 // we declare but do not need duplicates of the ones we declare. This means we can
373 // duplicate our parent entries.
375 // Is it already present in the list?
376 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
378 bmtInterfaceEntry * pItfEntry = &bmtInterface->pInterfaceMap[i];
379 bmtRTType * pItfType = pItfEntry->GetInterfaceType();
381 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
382 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
383 if (MetaSig::CompareTypeDefsUnderSubstitutions(pItfType->GetMethodTable(),
385 &pItfType->GetSubstitution(),
386 pNewInterfaceSubstChain,
389 if (declScope.fIsInterfaceDeclaredOnType)
391 pItfEntry->IsDeclaredOnType() = true;
394 //#InjectInterfaceDuplicates_ApproxInterfaces
395 // We can inject duplicate interfaces in check builds.
396 // Has to be in sync with code:#InjectInterfaceDuplicates_Main
397 if (((dbg_pClassMT == NULL) && bmtInterface->dbg_fShouldInjectInterfaceDuplicates) ||
398 ((dbg_pClassMT != NULL) && dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates()))
400 // The injected duplicate interface should have the same status 'ImplementedByParent' as
401 // the original interface (can be false if the interface is implemented indirectly twice)
402 declScope.fIsInterfaceDeclaredOnParent = pItfEntry->IsImplementedByParent();
403 // Just pretend we didn't find this match, but mark all duplicates as 'DeclaredOnType' if
408 return; // found it, don't add it again
412 bmtRTType * pNewItfType =
413 new (GetStackingAllocator()) bmtRTType(*pNewInterfaceSubstChain, pNewInterface);
415 if (bmtInterface->dwInterfaceMapSize >= bmtInterface->dwInterfaceMapAllocated)
418 // Grow the array of interfaces
420 S_UINT32 dwNewAllocated = S_UINT32(2) * S_UINT32(bmtInterface->dwInterfaceMapAllocated) + S_UINT32(5);
422 if (dwNewAllocated.IsOverflow())
424 BuildMethodTableThrowException(COR_E_OVERFLOW);
427 S_SIZE_T safeSize = S_SIZE_T(sizeof(bmtInterfaceEntry)) *
428 S_SIZE_T(dwNewAllocated.Value());
430 if (safeSize.IsOverflow())
432 BuildMethodTableThrowException(COR_E_OVERFLOW);
435 bmtInterfaceEntry * pNewMap = (bmtInterfaceEntry *)new (GetStackingAllocator()) BYTE[safeSize.Value()];
436 memcpy(pNewMap, bmtInterface->pInterfaceMap, sizeof(bmtInterfaceEntry) * bmtInterface->dwInterfaceMapAllocated);
438 bmtInterface->pInterfaceMap = pNewMap;
439 bmtInterface->dwInterfaceMapAllocated = dwNewAllocated.Value();
442 // The interface map memory was just allocated as an array of bytes, so we use
443 // in place new to init the new map entry. No need to do anything with the result,
445 CONSISTENCY_CHECK(bmtInterface->dwInterfaceMapSize < bmtInterface->dwInterfaceMapAllocated);
446 new ((void *)&bmtInterface->pInterfaceMap[bmtInterface->dwInterfaceMapSize])
447 bmtInterfaceEntry(pNewItfType, declScope);
449 bmtInterface->dwInterfaceMapSize++;
451 // Make sure to pass in the substitution from the new itf type created above as
452 // these methods assume that substitutions are allocated in the stacking heap,
454 InterfaceDeclarationScope declaredItfScope(declScope.fIsInterfaceDeclaredOnParent, false);
455 ExpandApproxDeclaredInterfaces(
457 bmtTypeHandle(pNewItfType),
459 COMMA_INDEBUG(dbg_pClassMT));
460 } // MethodTableBuilder::ExpandApproxInterface
462 //*******************************************************************************
464 // dbg_pClassMT - Class on which the interfaces are declared (either explicitly or implicitly).
465 // It will never be an interface. It may be NULL (if it is the type being built).
467 MethodTableBuilder::ExpandApproxDeclaredInterfaces(
468 bmtInterfaceInfo * bmtInterface, // out parameter, various parts cumulatively written to.
469 bmtTypeHandle thType,
470 InterfaceDeclarationScope declScope
471 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
473 STANDARD_VM_CONTRACT;
475 _ASSERTE((dbg_pClassMT == NULL) || !dbg_pClassMT->IsInterface());
478 // Iterate the list of interfaces declared by thType and add them to the map.
479 InterfaceImplEnum ie(thType.GetModule(), thType.GetTypeDefToken(), &thType.GetSubstitution());
480 while ((hr = ie.Next()) == S_OK)
482 MethodTable *pGenericIntf = ClassLoader::LoadApproxTypeThrowing(
483 thType.GetModule(), ie.CurrentToken(), NULL, NULL).GetMethodTable();
484 CONSISTENCY_CHECK(pGenericIntf->IsInterface());
486 ExpandApproxInterface(bmtInterface,
490 COMMA_INDEBUG(dbg_pClassMT));
494 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
496 } // MethodTableBuilder::ExpandApproxDeclaredInterfaces
498 //*******************************************************************************
500 MethodTableBuilder::ExpandApproxInheritedInterfaces(
501 bmtInterfaceInfo * bmtInterface,
502 bmtRTType * pParentType)
504 STANDARD_VM_CONTRACT;
506 INTERIOR_STACK_PROBE(GetThread());
508 // Expand interfaces in superclasses first. Interfaces inherited from parents
509 // must have identical indexes as in the parent.
510 bmtRTType * pParentOfParent = pParentType->GetParentType();
512 //#InterfaceMap_SupersetOfParent
513 // We have to load parent's interface map the same way the parent did it (as open type).
514 // Further code depends on this:
515 // code:#InterfaceMap_UseParentInterfaceImplementations
516 // We check that it is truth:
517 // code:#ApproxInterfaceMap_SupersetOfParent
518 // code:#ExactInterfaceMap_SupersetOfParent
520 //#InterfaceMap_CanonicalSupersetOfParent
521 // Note that canonical instantiation of parent can have different interface instantiations in the
522 // interface map than derived type:
523 // class MyClass<T> : MyBase<string, T>, I<T>
524 // class MyBase<U, V> : I<U>
525 // Type MyClass<_Canon> has MyBase<_Canon,_Canon> as parent. The interface maps are:
526 // MyBase<_Canon,_Canon> ... I<_Canon>
527 // MyClass<_Canon> ... I<string> (#1)
529 // The I's instantiation I<string> (#1) in MyClass and I<_Canon> from MyBase are not the same
532 // Backup parent substitution
533 Substitution parentSubstitution = pParentType->GetSubstitution();
534 // Make parent an open type
535 pParentType->SetSubstitution(Substitution());
537 if (pParentOfParent != NULL)
539 ExpandApproxInheritedInterfaces(bmtInterface, pParentOfParent);
542 InterfaceDeclarationScope declScope(true, false);
543 ExpandApproxDeclaredInterfaces(
545 bmtTypeHandle(pParentType),
547 COMMA_INDEBUG(pParentType->GetMethodTable()));
549 // Make sure we loaded the same number of interfaces as the parent type itself
550 CONSISTENCY_CHECK(pParentType->GetMethodTable()->GetNumInterfaces() == bmtInterface->dwInterfaceMapSize);
552 // Restore parent's substitution
553 pParentType->SetSubstitution(parentSubstitution);
555 END_INTERIOR_STACK_PROBE;
556 } // MethodTableBuilder::ExpandApproxInheritedInterfaces
558 //*******************************************************************************
559 // Fill out a fully expanded interface map, such that if we are declared to
560 // implement I3, and I3 extends I1,I2, then I1,I2 are added to our list if
561 // they are not already present.
563 MethodTableBuilder::LoadApproxInterfaceMap()
565 STANDARD_VM_CONTRACT;
567 bmtInterface->dwInterfaceMapSize = 0;
570 //#InjectInterfaceDuplicates_Main
571 // We will inject duplicate interfaces in check builds if env. var.
572 // COMPLUS_INTERNAL_TypeLoader_InjectInterfaceDuplicates is set to TRUE for all types (incl. non-generic
574 // This should allow us better test coverage of duplicates in interface map.
576 // The duplicates are legal for some types:
578 // B<U,V> : A<U>, I<V>
580 // where the interface maps are:
581 // A<T> ... 1 item: I<T>
582 // A<int> ... 1 item: I<int>
583 // B<U,V> ... 2 items: I<U>, I<V>
584 // B<int,int> ... 2 items: I<int>, I<int>
585 // B<_Canon,_Canon> ... 2 items: I<_Canon>, I<_Canon>
586 // B<string,string> ... 2 items: I<string>, I<string>
587 // C ... 2 items: I<int>, I<int>
588 // Note: C had only 1 item (I<int>) in CLR 2.0 RTM/SP1/SP2 and early in CLR 4.0.
590 // We will create duplicate from every re-implemented interface (incl. non-generic):
591 // code:#InjectInterfaceDuplicates_ApproxInterfaces
592 // code:#InjectInterfaceDuplicates_LoadExactInterfaceMap
593 // code:#InjectInterfaceDuplicates_ExactInterfaces
595 // Note that we don't have to do anything for COM, because COM has its own interface map
596 // (code:InteropMethodTableData)which is independent on type's interface map and is created only from
597 // non-generic interfaces (see code:ClassCompat::MethodTableBuilder::BuildInteropVTable_InterfaceList)
599 // We need to keep track which interface duplicates were injected. Right now its either all interfaces
600 // (declared on the type being built, not inheritted) or none. In the future we could inject duplicates
601 // just for some of them.
602 bmtInterface->dbg_fShouldInjectInterfaceDuplicates =
603 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TypeLoader_InjectInterfaceDuplicates) != 0);
604 if (bmtGenerics->Debug_GetTypicalMethodTable() != NULL)
605 { // It's safer to require that all instantiations have the same injected interface duplicates.
606 // In future we could inject different duplicates for various non-shared instantiations.
608 // Use the same injection status as typical instantiation
609 bmtInterface->dbg_fShouldInjectInterfaceDuplicates =
610 bmtGenerics->Debug_GetTypicalMethodTable()->Debug_HasInjectedInterfaceDuplicates();
612 if (GetModule() == g_pObjectClass->GetModule())
613 { // mscorlib has some weird hardcoded information about interfaces (e.g.
614 // code:CEEPreloader::ApplyTypeDependencyForSZArrayHelper), so we don't inject duplicates into
616 bmtInterface->dbg_fShouldInjectInterfaceDuplicates = FALSE;
621 // First inherit all the parent's interfaces. This is important, because our interface map must
622 // list the interfaces in identical order to our parent.
624 // <NICE> we should document the reasons why. One reason is that DispatchMapTypeIDs can be indexes
625 // into the list </NICE>
628 ExpandApproxInheritedInterfaces(bmtInterface, GetParentType());
630 //#ApproxInterfaceMap_SupersetOfParent
631 // Check that parent's interface map is the same as what we just computed
632 // See code:#InterfaceMap_SupersetOfParent
634 MethodTable * pParentMT = GetParentMethodTable();
635 _ASSERTE(pParentMT->GetNumInterfaces() == bmtInterface->dwInterfaceMapSize);
637 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
638 UINT32 nInterfaceIndex = 0;
639 while (parentInterfacesIterator.Next())
641 // Compare TypeDefs of the parent's interface and this interface (full MT comparison is in
642 // code:#ExactInterfaceMap_SupersetOfParent)
643 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
644 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
645 bmtInterface->pInterfaceMap[nInterfaceIndex].GetInterfaceType()->GetMethodTable()));
648 _ASSERTE(nInterfaceIndex == bmtInterface->dwInterfaceMapSize);
653 // Now add in any freshly declared interfaces, possibly augmenting the flags
654 InterfaceDeclarationScope declScope(false, true);
655 ExpandApproxDeclaredInterfaces(
659 COMMA_INDEBUG(NULL));
660 } // MethodTableBuilder::LoadApproxInterfaceMap
662 //*******************************************************************************
663 // Fills array of TypeIDs with all duplicate occurences of pDeclIntfMT in the interface map.
666 // rg/c DispatchMapTypeIDs - Array of TypeIDs and its count of elements.
667 // pcIfaceDuplicates - Number of duplicate occurences of the interface in the interface map (ideally <=
668 // count of elements TypeIDs.
670 // Note: If the passed rgDispatchMapTypeIDs array is smaller than the number of duplicates, fills it
671 // with the duplicates that fit and returns number of all existing duplicates (not just those fileld in the
672 // array) in pcIfaceDuplicates.
675 MethodTableBuilder::ComputeDispatchMapTypeIDs(
676 MethodTable * pDeclInftMT,
677 const Substitution * pDeclIntfSubst,
678 DispatchMapTypeID * rgDispatchMapTypeIDs,
679 UINT32 cDispatchMapTypeIDs,
680 UINT32 * pcIfaceDuplicates)
682 STANDARD_VM_CONTRACT;
684 _ASSERTE(pDeclInftMT->IsInterface());
686 // Count of interface duplicates (also used as index into TypeIDs array)
687 *pcIfaceDuplicates = 0;
688 for (DWORD idx = 0; idx < bmtInterface->dwInterfaceMapSize; idx++)
690 bmtInterfaceEntry * pItfEntry = &bmtInterface->pInterfaceMap[idx];
691 bmtRTType * pItfType = pItfEntry->GetInterfaceType();
692 // Type Equivalence is forbidden in interface type ids.
693 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
694 if (MetaSig::CompareTypeDefsUnderSubstitutions(pItfType->GetMethodTable(),
696 &pItfType->GetSubstitution(),
699 { // We found another occurence of this interface
700 // Can we fit it into the TypeID array?
701 if (*pcIfaceDuplicates < cDispatchMapTypeIDs)
703 rgDispatchMapTypeIDs[*pcIfaceDuplicates] = DispatchMapTypeID::InterfaceClassID(idx);
705 // Increase number of duplicate interfaces
706 (*pcIfaceDuplicates)++;
709 } // MethodTableBuilder::ComputeDispatchMapTypeIDs
711 //*******************************************************************************
713 VOID DECLSPEC_NORETURN
714 MethodTableBuilder::BuildMethodTableThrowException(
716 const bmtErrorInfo & bmtError)
722 INJECT_FAULT(COMPlusThrowOM(););
726 LPCUTF8 pszClassName, pszNameSpace;
727 if (FAILED(bmtError.pModule->GetMDImport()->GetNameOfTypeDef(bmtError.cl, &pszClassName, &pszNameSpace)))
729 pszClassName = pszNameSpace = "Invalid TypeDef record";
732 if (IsNilToken(bmtError.dMethodDefInError) && (bmtError.szMethodNameForError == NULL))
734 if (hr == E_OUTOFMEMORY)
739 bmtError.pModule->GetAssembly()->ThrowTypeLoadException(
740 pszNameSpace, pszClassName, bmtError.resIDWhy);
744 LPCUTF8 szMethodName;
745 if (bmtError.szMethodNameForError == NULL)
747 if (FAILED((bmtError.pModule->GetMDImport())->GetNameOfMethodDef(bmtError.dMethodDefInError, &szMethodName)))
749 szMethodName = "Invalid MethodDef record";
754 szMethodName = bmtError.szMethodNameForError;
757 bmtError.pModule->GetAssembly()->ThrowTypeLoadException(
758 pszNameSpace, pszClassName, szMethodName, bmtError.resIDWhy);
760 } // MethodTableBuilder::BuildMethodTableThrowException
762 //*******************************************************************************
763 void MethodTableBuilder::SetBMTData(
764 LoaderAllocator *bmtAllocator,
765 bmtErrorInfo *bmtError,
766 bmtProperties *bmtProp,
768 bmtParentInfo *bmtParent,
769 bmtInterfaceInfo *bmtInterface,
770 bmtMetaDataInfo *bmtMetaData,
771 bmtMethodInfo *bmtMethod,
772 bmtMethAndFieldDescs *bmtMFDescs,
773 bmtFieldPlacement *bmtFP,
774 bmtInternalInfo *bmtInternal,
775 bmtGCSeriesInfo *bmtGCSeries,
776 bmtMethodImplInfo *bmtMethodImpl,
777 const bmtGenericsInfo *bmtGenerics,
778 bmtEnumFieldInfo *bmtEnumFields,
779 bmtContextStaticInfo *bmtCSInfo)
781 LIMITED_METHOD_CONTRACT;
782 this->bmtAllocator = bmtAllocator;
783 this->bmtError = bmtError;
784 this->bmtProp = bmtProp;
786 this->bmtParent = bmtParent;
787 this->bmtInterface = bmtInterface;
788 this->bmtMetaData = bmtMetaData;
789 this->bmtMethod = bmtMethod;
790 this->bmtMFDescs = bmtMFDescs;
792 this->bmtInternal = bmtInternal;
793 this->bmtGCSeries = bmtGCSeries;
794 this->bmtMethodImpl = bmtMethodImpl;
795 this->bmtGenerics = bmtGenerics;
796 this->bmtEnumFields = bmtEnumFields;
797 this->bmtCSInfo = bmtCSInfo;
800 //*******************************************************************************
801 // Used by MethodTableBuilder
803 MethodTableBuilder::bmtRTType *
804 MethodTableBuilder::CreateTypeChain(
806 const Substitution & subst)
812 PRECONDITION(CheckPointer(GetStackingAllocator()));
813 PRECONDITION(CheckPointer(pMT));
816 pMT = pMT->GetCanonicalMethodTable();
818 bmtRTType * pType = new (GetStackingAllocator())
819 bmtRTType(subst, pMT);
821 MethodTable * pMTParent = pMT->GetParentMethodTable();
822 if (pMTParent != NULL)
824 pType->SetParentType(
827 pMT->GetSubstitutionForParent(&pType->GetSubstitution())));
833 //*******************************************************************************
835 MethodTableBuilder::bmtRTType *
836 MethodTableBuilder::bmtRTType::FindType(
838 MethodTable * pTargetMT)
842 PRECONDITION(CheckPointer(pType));
843 PRECONDITION(CheckPointer(pTargetMT));
846 pTargetMT = pTargetMT->GetCanonicalMethodTable();
847 while (pType != NULL &&
848 pType->GetMethodTable()->GetCanonicalMethodTable() != pTargetMT)
850 pType = pType->GetParentType();
856 //*******************************************************************************
858 MethodTableBuilder::bmtRTType::GetEnclosingTypeToken() const
860 STANDARD_VM_CONTRACT;
862 mdTypeDef tok = mdTypeDefNil;
865 { // This is guaranteed to succeed because the EEClass would not have been
866 // set as nested unless a valid token was stored in metadata.
867 if (FAILED(GetModule()->GetMDImport()->GetNestedClassProps(
868 GetTypeDefToken(), &tok)))
877 //*******************************************************************************
879 MethodTableBuilder::MethodSignature::NamesEqual(
880 const MethodSignature & sig1,
881 const MethodSignature & sig2)
883 STANDARD_VM_CONTRACT;
885 if (sig1.GetNameHash() != sig2.GetNameHash())
890 if (strcmp(sig1.GetName(), sig2.GetName()) != 0)
898 //*******************************************************************************
900 MethodTableBuilder::MethodSignature::SignaturesEquivalent(
901 const MethodSignature & sig1,
902 const MethodSignature & sig2)
904 STANDARD_VM_CONTRACT;
906 return !!MetaSig::CompareMethodSigs(
907 sig1.GetSignature(), static_cast<DWORD>(sig1.GetSignatureLength()), sig1.GetModule(), &sig1.GetSubstitution(),
908 sig2.GetSignature(), static_cast<DWORD>(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution());
911 //*******************************************************************************
913 MethodTableBuilder::MethodSignature::SignaturesExactlyEqual(
914 const MethodSignature & sig1,
915 const MethodSignature & sig2)
917 STANDARD_VM_CONTRACT;
919 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
920 return !!MetaSig::CompareMethodSigs(
921 sig1.GetSignature(), static_cast<DWORD>(sig1.GetSignatureLength()), sig1.GetModule(), &sig1.GetSubstitution(),
922 sig2.GetSignature(), static_cast<DWORD>(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution(),
926 //*******************************************************************************
928 MethodTableBuilder::MethodSignature::Equivalent(
929 const MethodSignature &rhs) const
931 STANDARD_VM_CONTRACT;
933 return NamesEqual(*this, rhs) && SignaturesEquivalent(*this, rhs);
936 //*******************************************************************************
938 MethodTableBuilder::MethodSignature::ExactlyEqual(
939 const MethodSignature &rhs) const
941 STANDARD_VM_CONTRACT;
943 return NamesEqual(*this, rhs) && SignaturesExactlyEqual(*this, rhs);
946 //*******************************************************************************
948 MethodTableBuilder::MethodSignature::GetMethodAttributes() const
950 STANDARD_VM_CONTRACT;
952 IMDInternalImport * pIMD = GetModule()->GetMDImport();
953 if (TypeFromToken(GetToken()) == mdtMethodDef)
956 if (FAILED(pIMD->GetNameAndSigOfMethodDef(GetToken(), &m_pSig, &cSig, &m_szName)))
957 { // We have empty name or signature on error, do nothing
959 m_cSig = static_cast<size_t>(cSig);
963 CONSISTENCY_CHECK(TypeFromToken(m_tok) == mdtMemberRef);
965 if (FAILED(pIMD->GetNameAndSigOfMemberRef(GetToken(), &m_pSig, &cSig, &m_szName)))
966 { // We have empty name or signature on error, do nothing
968 m_cSig = static_cast<size_t>(cSig);
972 //*******************************************************************************
974 MethodTableBuilder::MethodSignature::GetNameHash() const
976 STANDARD_VM_CONTRACT;
978 CheckGetMethodAttributes();
980 if (m_nameHash == INVALID_NAME_HASH)
982 ULONG nameHash = HashStringA(GetName());
983 if (nameHash == INVALID_NAME_HASH)
987 m_nameHash = nameHash;
993 //*******************************************************************************
994 MethodTableBuilder::bmtMDType::bmtMDType(
995 bmtRTType * pParentType,
998 const SigTypeContext & sigContext)
999 : m_pParentType(pParentType),
1002 m_enclTok(mdTypeDefNil),
1003 m_sigContext(sigContext),
1008 STANDARD_VM_CONTRACT;
1010 IfFailThrow(m_pModule->GetMDImport()->GetTypeDefProps(m_tok, &m_dwAttrs, NULL));
1012 HRESULT hr = m_pModule->GetMDImport()->GetNestedClassProps(m_tok, &m_enclTok);
1015 if (hr != CLDB_E_RECORD_NOTFOUND)
1019 // Just in case GetNestedClassProps sets the out param to some other value
1020 m_enclTok = mdTypeDefNil;
1024 //*******************************************************************************
1025 MethodTableBuilder::bmtRTMethod::bmtRTMethod(
1026 bmtRTType * pOwningType,
1028 : m_pOwningType(pOwningType),
1030 m_methodSig(pMD->GetModule(),
1031 pMD->GetMemberDef(),
1032 &pOwningType->GetSubstitution())
1043 //*******************************************************************************
1044 MethodTableBuilder::bmtMDMethod::bmtMDMethod(
1045 bmtMDType * pOwningType,
1051 METHOD_IMPL_TYPE implType)
1052 : m_pOwningType(pOwningType),
1053 m_dwDeclAttrs(dwDeclAttrs),
1054 m_dwImplAttrs(dwImplAttrs),
1057 m_implType(implType),
1058 m_methodSig(pOwningType->GetModule(),
1060 &pOwningType->GetSubstitution()),
1063 m_slotIndex(INVALID_SLOT_INDEX),
1064 m_unboxedSlotIndex(INVALID_SLOT_INDEX)
1074 //*******************************************************************************
1076 MethodTableBuilder::ImportParentMethods()
1078 STANDARD_VM_CONTRACT;
1081 { // If there's no parent, there's no methods to import
1085 SLOT_INDEX numMethods = static_cast<SLOT_INDEX>
1086 (GetParentMethodTable()->GetNumMethods());
1088 bmtParent->pSlotTable = new (GetStackingAllocator())
1089 bmtMethodSlotTable(numMethods, GetStackingAllocator());
1091 MethodTable::MethodIterator it(GetParentMethodTable());
1092 for (;it.IsValid(); it.Next())
1094 MethodDesc * pDeclDesc = NULL;
1095 MethodTable * pDeclMT = NULL;
1096 MethodDesc * pImplDesc = NULL;
1097 MethodTable * pImplMT = NULL;
1101 pDeclDesc = it.GetDeclMethodDesc();
1102 pDeclMT = pDeclDesc->GetMethodTable();
1103 pImplDesc = it.GetMethodDesc();
1104 pImplMT = pImplDesc->GetMethodTable();
1108 pDeclDesc = pImplDesc = it.GetMethodDesc();
1109 pDeclMT = pImplMT = it.GetMethodDesc()->GetMethodTable();
1112 CONSISTENCY_CHECK(CheckPointer(pDeclDesc));
1113 CONSISTENCY_CHECK(CheckPointer(pImplDesc));
1115 // Create and assign to each slot
1116 bmtMethodSlot newSlot;
1117 newSlot.Decl() = new (GetStackingAllocator())
1118 bmtRTMethod(bmtRTType::FindType(GetParentType(), pDeclMT), pDeclDesc);
1119 if (pDeclDesc == pImplDesc)
1121 newSlot.Impl() = newSlot.Decl();
1125 newSlot.Impl() = new (GetStackingAllocator())
1126 bmtRTMethod(bmtRTType::FindType(GetParentType(), pImplMT), pImplDesc);
1129 if (!bmtParent->pSlotTable->AddMethodSlot(newSlot))
1130 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1134 //*******************************************************************************
1136 MethodTableBuilder::CopyParentVtable()
1138 STANDARD_VM_CONTRACT;
1145 for (bmtParentInfo::Iterator it = bmtParent->IterateSlots();
1146 !it.AtEnd() && it.CurrentIndex() < GetParentMethodTable()->GetNumVirtuals();
1149 if (!bmtVT->pSlotTable->AddMethodSlot(*it))
1150 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1151 ++bmtVT->cVirtualSlots;
1152 ++bmtVT->cTotalSlots;
1156 //*******************************************************************************
1157 // Determine if this is the special SIMD type System.Numerics.Vector<T>, whose
1158 // size is determined dynamically based on the hardware and the presence of JIT
1161 // - Update the NumInstanceFieldBytes on the bmtFieldPlacement.
1162 // - Update the m_cbNativeSize and m_cbManagedSize if HasLayout() is true.
1163 // Return a BOOL result to indicate whether the size has been updated.
1165 // Will throw IDS_EE_SIMD_NGEN_DISALLOWED if the type is System.Numerics.Vector`1
1166 // and this is an ngen compilation process.
1168 BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize()
1170 STANDARD_VM_CONTRACT;
1172 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
1173 if (!GetAssembly()->IsSIMDVectorAssembly())
1176 if (bmtFP->NumInstanceFieldBytes != 16)
1181 if (FAILED(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace)))
1184 if (strcmp(className, "Vector`1") != 0 || strcmp(nameSpace, "System.Numerics") != 0)
1187 if (IsCompilationProcess())
1189 COMPlusThrow(kTypeLoadException, IDS_EE_SIMD_NGEN_DISALLOWED);
1192 #ifndef CROSSGEN_COMPILE
1193 if (!TargetHasAVXSupport())
1196 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
1197 if (jitMgr->LoadJIT())
1199 CORJIT_FLAGS cpuCompileFlags = jitMgr->GetCPUCompileFlags();
1200 if (cpuCompileFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_FEATURE_SIMD))
1202 unsigned intrinsicSIMDVectorLength = jitMgr->m_jit->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags);
1203 if (intrinsicSIMDVectorLength != 0)
1205 bmtFP->NumInstanceFieldBytes = intrinsicSIMDVectorLength;
1208 GetLayoutInfo()->m_cbNativeSize = intrinsicSIMDVectorLength;
1209 GetLayoutInfo()->m_cbManagedSize = intrinsicSIMDVectorLength;
1215 #endif // !CROSSGEN_COMPILE
1216 #endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
1220 //*******************************************************************************
1222 MethodTableBuilder::bmtInterfaceEntry::CreateSlotTable(
1223 StackingAllocator * pStackingAllocator)
1225 STANDARD_VM_CONTRACT;
1227 CONSISTENCY_CHECK(m_pImplTable == NULL);
1229 SLOT_INDEX cSlots = (SLOT_INDEX)GetInterfaceType()->GetMethodTable()->GetNumVirtuals();
1230 bmtInterfaceSlotImpl * pST = new (pStackingAllocator) bmtInterfaceSlotImpl[cSlots];
1232 MethodTable::MethodIterator it(GetInterfaceType()->GetMethodTable());
1233 for (; it.IsValid(); it.Next())
1235 if (!it.IsVirtual())
1240 bmtRTMethod * pCurMethod = new (pStackingAllocator)
1241 bmtRTMethod(GetInterfaceType(), it.GetDeclMethodDesc());
1243 CONSISTENCY_CHECK(m_cImplTable == it.GetSlotNumber());
1244 pST[m_cImplTable++] = bmtInterfaceSlotImpl(pCurMethod, INVALID_SLOT_INDEX);
1251 #pragma warning(push)
1252 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1254 //---------------------------------------------------------------------------------------
1256 // Builds the method table, allocates MethodDesc, handles overloaded members, attempts to compress
1257 // interface storage. All dependent classes must already be resolved!
1260 MethodTableBuilder::BuildMethodTableThrowing(
1261 LoaderAllocator * pAllocator,
1262 Module * pLoaderModule,
1265 BuildingInterfaceInfo_t * pBuildingInterfaceList,
1266 const LayoutRawFieldInfo * pLayoutRawFieldInfos,
1267 MethodTable * pParentMethodTable,
1268 const bmtGenericsInfo * bmtGenericsInfo,
1269 SigPointer parentInst,
1270 WORD cBuildingInterfaceList)
1275 PRECONDITION(CheckPointer(GetHalfBakedClass()));
1276 PRECONDITION(CheckPointer(bmtGenericsInfo));
1280 pModule->EnsureLibraryLoaded();
1282 // The following structs, defined as private members of MethodTableBuilder, contain the necessary local
1283 // parameters needed for BuildMethodTable Look at the struct definitions for a detailed list of all
1284 // parameters available to BuildMethodTableThrowing.
1288 new (GetStackingAllocator()) bmtErrorInfo(),
1289 new (GetStackingAllocator()) bmtProperties(),
1290 new (GetStackingAllocator()) bmtVtable(),
1291 new (GetStackingAllocator()) bmtParentInfo(),
1292 new (GetStackingAllocator()) bmtInterfaceInfo(),
1293 new (GetStackingAllocator()) bmtMetaDataInfo(),
1294 new (GetStackingAllocator()) bmtMethodInfo(),
1295 new (GetStackingAllocator()) bmtMethAndFieldDescs(),
1296 new (GetStackingAllocator()) bmtFieldPlacement(),
1297 new (GetStackingAllocator()) bmtInternalInfo(),
1298 new (GetStackingAllocator()) bmtGCSeriesInfo(),
1299 new (GetStackingAllocator()) bmtMethodImplInfo(),
1301 new (GetStackingAllocator()) bmtEnumFieldInfo(pModule->GetMDImport()),
1302 new (GetStackingAllocator()) bmtContextStaticInfo());
1304 //Initialize structs
1306 bmtError->resIDWhy = IDS_CLASSLOAD_GENERAL; // Set the reason and the offending method def. If the method information
1307 bmtError->pThrowable = NULL;
1308 bmtError->pModule = pModule;
1311 bmtInternal->pInternalImport = pModule->GetMDImport();
1312 bmtInternal->pModule = pModule;
1314 bmtInternal->pParentMT = pParentMethodTable;
1316 // Create the chain of bmtRTType for the parent types. This allows all imported
1317 // parent methods to be associated with their declaring types, and as such it is
1318 // easy to access the appropriate Substitution when comparing signatures.
1319 bmtRTType * pParent = NULL;
1320 if (pParentMethodTable != NULL)
1322 Substitution * pParentSubst =
1323 new (GetStackingAllocator()) Substitution(pModule, parentInst, NULL);
1324 pParent = CreateTypeChain(pParentMethodTable, *pParentSubst);
1327 // Now create the bmtMDType for the type being built.
1328 bmtInternal->pType = new (GetStackingAllocator())
1329 bmtMDType(pParent, pModule, cl, bmtGenericsInfo->typeContext);
1331 // put the interior stack probe after all the stack-allocted goop above. We check compare our this pointer to the SP on
1332 // the dtor to determine if we are being called on an EH path or not.
1333 INTERIOR_STACK_PROBE_FOR(GetThread(), 8);
1335 // If not NULL, it means there are some by-value fields, and this contains an entry for each inst
1338 // Set debug class name string for easier debugging.
1341 if (FAILED(GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace)))
1343 className = nameSpace = "Invalid TypeDef record";
1347 S_SIZE_T safeLen = S_SIZE_T(sizeof(char))*(S_SIZE_T(strlen(className)) + S_SIZE_T(strlen(nameSpace)) + S_SIZE_T(2));
1348 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1350 size_t len = safeLen.Value();
1351 char *name = (char*) AllocateFromHighFrequencyHeap(safeLen);
1352 strcpy_s(name, len, nameSpace);
1353 if (strlen(nameSpace) > 0) {
1354 name[strlen(nameSpace)] = '.';
1355 name[strlen(nameSpace) + 1] = '\0';
1357 strcat_s(name, len, className);
1359 GetHalfBakedClass()->SetDebugClassName(name);
1362 if (g_pConfig->ShouldBreakOnClassBuild(className))
1364 CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassBuild: typename '%s' ", className));
1365 GetHalfBakedClass()->m_fDebuggingClass = TRUE;
1368 LPCUTF8 pszDebugName,pszDebugNamespace;
1369 if (FAILED(pModule->GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &pszDebugName, &pszDebugNamespace)))
1371 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
1374 StackSString debugName(SString::Utf8, pszDebugName);
1376 // If there is an instantiation, update the debug name to include instantiation type names.
1377 if (bmtGenerics->HasInstantiation())
1379 StackSString debugName(SString::Utf8, GetDebugClassName());
1380 TypeString::AppendInst(debugName, bmtGenerics->GetInstantiation(), TypeString::FormatBasic);
1381 StackScratchBuffer buff;
1382 const char* pDebugNameUTF8 = debugName.GetUTF8(buff);
1383 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8)) + S_SIZE_T(1);
1384 if(safeLen.IsOverflow())
1385 COMPlusThrowHR(COR_E_OVERFLOW);
1387 size_t len = safeLen.Value();
1388 char *name = (char*) AllocateFromLowFrequencyHeap(safeLen);
1389 strcpy_s(name, len, pDebugNameUTF8);
1390 GetHalfBakedClass()->SetDebugClassName(name);
1391 pszDebugName = (LPCUTF8)name;
1394 LOG((LF_CLASSLOADER, LL_INFO1000, "Loading class \"%s%s%S\" from module \"%ws\" in domain 0x%p %s\n",
1395 *pszDebugNamespace ? pszDebugNamespace : "",
1396 *pszDebugNamespace ? NAMESPACE_SEPARATOR_STR : "",
1397 debugName.GetUnicode(),
1398 pModule->GetDebugName(),
1399 pModule->GetDomain(),
1400 (pModule->IsSystem()) ? "System Domain" : ""
1404 // If this is mscorlib, then don't perform some sanity checks on the layout
1405 bmtProp->fNoSanityChecks = ((g_pObjectClass == NULL) || pModule == g_pObjectClass->GetModule()) ||
1406 #ifdef FEATURE_READYTORUN
1407 // No sanity checks for ready-to-run compiled images if possible
1408 (pModule->IsReadyToRun() && pModule->GetReadyToRunInfo()->SkipTypeValidation()) ||
1410 // No sanity checks for real generic instantiations
1411 !bmtGenerics->IsTypicalTypeDefinition();
1413 // Interfaces have a parent class of Object, but we don't really want to inherit all of
1414 // Object's virtual methods, so pretend we don't have a parent class - at the bottom of this
1415 // function we reset the parent class
1418 bmtInternal->pType->SetParentType(NULL);
1419 bmtInternal->pParentMT = NULL;
1422 unsigned totalDeclaredFieldSize=0;
1424 // Check to see if the class is a valuetype; but we don't want to mark System.Enum
1425 // as a ValueType. To accomplish this, the check takes advantage of the fact
1426 // that System.ValueType and System.Enum are loaded one immediately after the
1427 // other in that order, and so if the parent MethodTable is System.ValueType and
1428 // the System.Enum MethodTable is unset, then we must be building System.Enum and
1429 // so we don't mark it as a ValueType.
1431 ((g_pEnumClass != NULL && GetParentMethodTable() == g_pValueTypeClass) ||
1432 GetParentMethodTable() == g_pEnumClass))
1434 bmtProp->fIsValueClass = true;
1436 HRESULT hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
1437 g_CompilerServicesUnsafeValueTypeAttribute,
1442 SetUnsafeValueClass();
1445 hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
1446 g_CompilerServicesIsByRefLikeAttribute,
1451 bmtFP->fIsByRefLikeType = true;
1455 // Check to see if the class is an enumeration. No fancy checks like the one immediately
1456 // above for value types are necessary here.
1457 if(HasParent() && GetParentMethodTable() == g_pEnumClass)
1459 bmtProp->fIsEnum = true;
1461 // Ensure we don't have generic enums, or at least enums that have a
1462 // different number of type parameters from their enclosing class.
1463 // The goal is to ensure that the enum's values can't depend on the
1464 // type parameters in any way. And we don't see any need for an
1465 // enum to have additional type parameters.
1466 if (bmtGenerics->GetNumGenericArgs() != 0)
1468 // Nested enums can have generic type parameters from their enclosing class.
1469 // CLS rules require type parameters to be propogated to nested types.
1470 // Note that class G<T> { enum E { } } will produce "G`1+E<T>".
1471 // We want to disallow class G<T> { enum E<T, U> { } }
1472 // Perhaps the IL equivalent of class G<T> { enum E { } } should be legal.
1475 BuildMethodTableThrowException(IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM);
1478 mdTypeDef tdEnclosing = mdTypeDefNil;
1479 HRESULT hr = GetMDImport()->GetNestedClassProps(GetCl(), &tdEnclosing);
1481 ThrowHR(hr, BFA_UNABLE_TO_GET_NESTED_PROPS);
1483 HENUMInternalHolder hEnumGenericPars(GetMDImport());
1484 if (FAILED(hEnumGenericPars.EnumInitNoThrow(mdtGenericParam, tdEnclosing)))
1486 GetAssembly()->ThrowTypeLoadException(GetMDImport(), tdEnclosing, IDS_CLASSLOAD_BADFORMAT);
1489 if (hEnumGenericPars.EnumGetCount() != bmtGenerics->GetNumGenericArgs())
1491 BuildMethodTableThrowException(IDS_CLASSLOAD_ENUM_EXTRA_GENERIC_TYPE_PARAM);
1496 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1497 if (GetModule()->IsSystem() && !bmtGenerics->HasInstantiation())
1501 HRESULT hr = GetMDImport()->GetNameOfTypeDef(bmtInternal->pType->GetTypeDefToken(), &className, &nameSpace);
1503 if (hr == S_OK && strcmp(nameSpace, "System.Runtime.Intrinsics") == 0)
1505 if (IsCompilationProcess())
1507 // Disable AOT compiling for the SIMD hardware intrinsic types. These types require special
1508 // ABI handling as they represent fundamental data types (__m64, __m128, and __m256) and not
1509 // aggregate or union types. See https://github.com/dotnet/coreclr/issues/15943
1511 // Once they are properly handled according to the ABI requirements, we can remove this check
1512 // and allow them to be used in crossgen/AOT scenarios.
1513 COMPlusThrow(kTypeLoadException, IDS_EE_HWINTRINSIC_NGEN_DISALLOWED);
1517 #if defined(_TARGET_ARM64_)
1518 // All the funtions in System.Runtime.Intrinsics.Arm.Arm64 are hardware intrinsics.
1519 if (hr == S_OK && strcmp(nameSpace, "System.Runtime.Intrinsics.Arm.Arm64") == 0)
1521 // All the funtions in System.Runtime.Intrinsics.X86 are hardware intrinsics.
1522 if (hr == S_OK && strcmp(nameSpace, "System.Runtime.Intrinsics.X86") == 0)
1525 if (IsCompilationProcess())
1527 // Disable AOT compiling for managed implementation of hardware intrinsics in mscorlib.
1528 // We specially treat them here to ensure correct ISA features are set during compilation
1529 COMPlusThrow(kTypeLoadException, IDS_EE_HWINTRINSIC_NGEN_DISALLOWED);
1531 bmtProp->fIsHardwareIntrinsic = true;
1536 #ifdef FEATURE_COMINTEROP
1538 // Com Import classes are special. These types must derive from System.Object,
1539 // and we then substitute the parent with System._ComObject.
1540 if (IsComImport() && !IsEnum() && !IsInterface() && !IsValueClass() && !IsDelegate())
1542 // ComImport classes must either extend from Object or be a WinRT class
1543 // that extends from another WinRT class (and so form a chain of WinRT classes
1544 // that ultimately extend from object).
1545 MethodTable* pMTParent = GetParentMethodTable();
1546 if ((pMTParent == NULL) || !(
1547 // is the parent valid?
1548 (pMTParent == g_pObjectClass) ||
1549 (GetHalfBakedClass()->IsProjectedFromWinRT() && pMTParent->IsProjectedFromWinRT())
1552 BuildMethodTableThrowException(IDS_CLASSLOAD_CANTEXTEND);
1557 // ComImport classes cannot have layout information.
1558 BuildMethodTableThrowException(IDS_CLASSLOAD_COMIMPCANNOTHAVELAYOUT);
1561 if (pMTParent == g_pObjectClass)
1563 // ComImport classes ultimately extend from our __ComObject or RuntimeClass class
1564 MethodTable *pCOMMT = NULL;
1565 if (GetHalfBakedClass()->IsProjectedFromWinRT())
1566 pCOMMT = g_pBaseRuntimeClass;
1568 pCOMMT = g_pBaseCOMObject;
1572 // We could have had COM interop classes derive from System._ComObject,
1573 // but instead we have them derive from System.Object, have them set the
1574 // ComImport bit in the type attributes, and then we swap out the parent
1575 // type under the covers.
1576 bmtInternal->pType->SetParentType(CreateTypeChain(pCOMMT, Substitution()));
1577 bmtInternal->pParentMT = pCOMMT;
1580 // if the current class is imported
1581 bmtProp->fIsComObjectType = true;
1584 if (GetHalfBakedClass()->IsProjectedFromWinRT() && IsValueClass() && !IsEnum())
1586 // WinRT structures must have sequential layout
1587 if (!GetHalfBakedClass()->HasSequentialLayout())
1589 BuildMethodTableThrowException(IDS_EE_STRUCTLAYOUT_WINRT);
1593 // Check for special COM interop types.
1594 CheckForSpecialTypes();
1596 CheckForTypeEquivalence(cBuildingInterfaceList, pBuildingInterfaceList);
1599 { // Types that inherit from com object types are themselves com object types.
1600 if (GetParentMethodTable()->IsComObjectType())
1602 // if the parent class is of ComObjectType
1604 bmtProp->fIsComObjectType = true;
1607 #ifdef FEATURE_TYPEEQUIVALENCE
1608 // If your parent is type equivalent then so are you
1609 if (GetParentMethodTable()->HasTypeEquivalence())
1611 bmtProp->fHasTypeEquivalence = true;
1616 #endif // FEATURE_COMINTEROP
1618 if (!HasParent() && !IsInterface())
1620 if(g_pObjectClass != NULL)
1622 if(!IsGlobalClass())
1624 // Non object derived types that are not the global class are prohibited by spec
1625 BuildMethodTableThrowException(IDS_CLASSLOAD_PARENTNULL);
1630 // NOTE: This appears to be the earliest point during class loading that other classes MUST be loaded
1631 // resolve unresolved interfaces, determine an upper bound on the size of the interface map,
1632 // and determine the size of the largest interface (in # slots)
1633 ResolveInterfaces(cBuildingInterfaceList, pBuildingInterfaceList);
1635 // Enumerate this class's methodImpls
1636 EnumerateMethodImpls();
1638 // Enumerate this class's methods and fields
1639 EnumerateClassMethods();
1642 EnumerateClassFields();
1644 // Import the slots of the parent for use in placing this type's methods.
1645 ImportParentMethods();
1647 // This will allocate the working versions of the VTable and NonVTable in bmtVT
1648 AllocateWorkingSlotTables();
1650 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
1651 AllocateFieldDescs();
1653 // Copy the parent's vtable into the current type's vtable
1656 bmtVT->pDispatchMapBuilder = new (GetStackingAllocator()) DispatchMapBuilder(GetStackingAllocator());
1658 // Determine vtable placement for each member in this class
1659 PlaceVirtualMethods();
1660 PlaceNonVirtualMethods();
1662 // Allocate MethodDescs (expects methods placed methods)
1663 AllocAndInitMethodDescs();
1668 // We need to process/place method impls for default interface method overrides.
1669 // We won't build dispatch map for interfaces, though.
1671 ProcessMethodImpls();
1677 // If we are a class, then there may be some unplaced vtable methods (which are by definition
1678 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
1679 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
1680 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
1681 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
1682 // map for all interfaces as they are placed.
1684 // If we are an interface, then all methods are already placed. Fill out the interface map for
1685 // interfaces as they are placed.
1687 ComputeInterfaceMapEquivalenceSet();
1689 PlaceInterfaceMethods();
1691 ProcessMethodImpls();
1692 ProcessInexactMethodImpls();
1695 if (!bmtProp->fNoSanityChecks)
1697 // Now that interface method implementation have been fully resolved,
1698 // we need to make sure that type constraints are also met.
1699 ValidateInterfaceMethodConstraints();
1703 // Verify that we have not overflowed the number of slots.
1704 if (!FitsInU2((UINT64)bmtVT->pSlotTable->GetSlotCount()))
1706 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
1709 // ensure we didn't overflow the temporary vtable
1710 _ASSERTE(bmtVT->pSlotTable->GetSlotCount() <= bmtVT->dwMaxVtableSize);
1712 // Allocate and initialize the dictionary for the type. This will be filled out later
1713 // with the final values.
1714 AllocAndInitDictionary();
1716 ////////////////////////////////////////////////////////////////////////////////////////////////
1720 // We decide here if we need a dynamic entry for our statics. We need it here because
1721 // the offsets of our fields will depend on this. For the dynamic case (which requires
1722 // an extra indirection (indirect depending of methodtable) we'll allocate the slot
1723 // in setupmethodtable
1724 if (((pModule->IsReflection() || bmtGenerics->HasInstantiation() || !pModule->IsStaticStoragePrepared(cl)) &&
1725 (bmtVT->GetClassCtorSlotIndex() != INVALID_SLOT_INDEX || bmtEnumFields->dwNumStaticFields !=0))
1726 #ifdef EnC_SUPPORTED
1727 // Classes in modules that have been edited (would do on class level if there were a
1728 // way to tell if the class had been edited) also have dynamic statics as the number
1729 // of statics might have changed, so can't use the static module-wide storage
1730 || (pModule->IsEditAndContinueEnabled() &&
1731 ((EditAndContinueModule*)pModule)->GetApplyChangesCount() > CorDB_DEFAULT_ENC_FUNCTION_VERSION)
1732 #endif // EnC_SUPPORTED
1735 // We will need a dynamic id
1736 bmtProp->fDynamicStatics = true;
1738 if (bmtGenerics->HasInstantiation())
1740 bmtProp->fGenericsStatics = true;
1744 // If not NULL, it means there are some by-value fields, and this contains an entry for each instance or static field,
1745 // which is NULL if not a by value field, and points to the EEClass of the field if a by value field. Instance fields
1746 // come first, statics come second.
1747 MethodTable ** pByValueClassCache = NULL;
1749 // Go thru all fields and initialize their FieldDescs.
1750 InitializeFieldDescs(GetApproxFieldDescListRaw(), pLayoutRawFieldInfos, bmtInternal, bmtGenerics,
1751 bmtMetaData, bmtEnumFields, bmtError,
1752 &pByValueClassCache, bmtMFDescs, bmtFP, bmtCSInfo,
1753 &totalDeclaredFieldSize);
1755 // Place regular static fields
1756 PlaceRegularStaticFields();
1758 // Place thread static fields
1759 PlaceThreadStaticFields();
1761 LOG((LF_CODESHARING,
1763 "Placing %d statics (%d handles) for class %s.\n",
1764 GetNumStaticFields(), GetNumHandleRegularStatics() + GetNumHandleThreadStatics(),
1767 if (IsBlittable() || IsManagedSequential())
1769 bmtFP->NumGCPointerSeries = 0;
1770 bmtFP->NumInstanceGCPointerFields = 0;
1772 _ASSERTE(HasLayout());
1774 bmtFP->NumInstanceFieldBytes = IsBlittable() ? GetLayoutInfo()->m_cbNativeSize
1775 : GetLayoutInfo()->m_cbManagedSize;
1777 // For simple Blittable types we still need to check if they have any overlapping
1778 // fields and call the method SetHasOverLayedFields() when they are detected.
1780 if (HasExplicitFieldOffsetLayout())
1782 _ASSERTE(!bmtGenerics->fContainsGenericVariables); // A simple Blittable type can't ever be an open generic type.
1783 HandleExplicitLayout(pByValueClassCache);
1788 _ASSERTE(!IsBlittable());
1789 // HandleExplicitLayout fails for the GenericTypeDefinition when
1790 // it will succeed for some particular instantiations.
1791 // Thus we only do explicit layout for real instantiations, e.g. C<int>, not
1792 // the open types such as the GenericTypeDefinition C<!0> or any
1793 // of the "fake" types involving generic type variables which are
1794 // used for reflection and verification, e.g. C<List<!0>>.
1796 if (!bmtGenerics->fContainsGenericVariables && HasExplicitFieldOffsetLayout())
1798 HandleExplicitLayout(pByValueClassCache);
1802 // Place instance fields
1803 PlaceInstanceFields(pByValueClassCache);
1807 if (CheckIfSIMDAndUpdateSize())
1809 totalDeclaredFieldSize = bmtFP->NumInstanceFieldBytes;
1812 // We enforce that all value classes have non-zero size
1813 if (IsValueClass() && bmtFP->NumInstanceFieldBytes == 0)
1815 BuildMethodTableThrowException(IDS_CLASSLOAD_ZEROSIZE);
1818 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
1819 { // Verify self-referencing statics with RVA (now when the ValueType size is known)
1820 VerifySelfReferencingStaticValueTypeFields_WithRVA(pByValueClassCache);
1824 // Now setup the method table
1826 #ifdef FEATURE_PREJIT
1827 Module *pComputedPZM = pLoaderModule;
1829 if (bmtGenerics->GetNumGenericArgs() > 0)
1831 pComputedPZM = Module::ComputePreferredZapModule(pModule, bmtGenerics->GetInstantiation());
1834 SetupMethodTable2(pLoaderModule, pComputedPZM);
1835 #else // FEATURE_PREJIT
1836 SetupMethodTable2(pLoaderModule);
1837 #endif // FEATURE_PREJIT
1839 MethodTable * pMT = GetHalfBakedMethodTable();
1841 #ifdef FEATURE_64BIT_ALIGNMENT
1842 if (GetHalfBakedClass()->IsAlign8Candidate())
1843 pMT->SetRequiresAlign8();
1846 if (bmtGenerics->pVarianceInfo != NULL)
1848 pMT->SetHasVariance();
1851 if (bmtFP->NumRegularStaticGCBoxedFields != 0)
1853 pMT->SetHasBoxedRegularStatics();
1856 if (bmtFP->fIsByRefLikeType)
1858 pMT->SetIsByRefLike();
1863 if (bmtFP->NumInstanceFieldBytes != totalDeclaredFieldSize || HasOverLayedField())
1864 GetHalfBakedClass()->SetIsNotTightlyPacked();
1867 GetHalfBakedClass()->CheckForHFA(pByValueClassCache);
1869 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1871 #error Can't have FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING defined at the same time.
1872 #endif // FEATURE_HFA
1873 SystemVAmd64CheckForPassStructInRegister();
1874 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1877 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1879 #error Can't have FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING defined at the same time.
1880 #endif // FEATURE_HFA
1883 SystemVAmd64CheckForPassNativeStructInRegister();
1885 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1889 GetHalfBakedClass()->CheckForNativeHFA();
1894 pMT->SetDebugClassName(GetDebugClassName());
1897 #ifdef FEATURE_COMINTEROP
1900 GetCoClassAttribInfo();
1902 #endif // FEATURE_COMINTEROP
1904 if (HasExplicitFieldOffsetLayout())
1905 // Perform relevant GC calculations for tdexplicit
1906 HandleGCForExplicitLayout();
1908 // Perform relevant GC calculations for value classes
1909 HandleGCForValueClasses(pByValueClassCache);
1911 // GC reqires the series to be sorted.
1912 // TODO: fix it so that we emit them in the correct order in the first place.
1913 if (pMT->ContainsPointers())
1915 CGCDesc* gcDesc = CGCDesc::GetCGCDescFromMT(pMT);
1916 qsort(gcDesc->GetLowestSeries(), (int)gcDesc->GetNumSeries(), sizeof(CGCDescSeries), compareCGCDescSeries);
1919 SetFinalizationSemantics();
1922 // Figure out if we're domain agile..
1923 // Note that this checks a bunch of field directly on the class & method table,
1924 // so it needs to come late in the game.
1925 EEClass::SetAppDomainAgileAttribute(pMT);
1928 // Allocate dynamic slot if necessary
1929 if (bmtProp->fDynamicStatics)
1931 if (bmtProp->fGenericsStatics)
1933 FieldDesc* pStaticFieldDescs = NULL;
1935 if (bmtEnumFields->dwNumStaticFields != 0)
1937 pStaticFieldDescs = pMT->GetApproxFieldDescListRaw() + bmtEnumFields->dwNumInstanceFields;
1940 pMT->SetupGenericsStaticsInfo(pStaticFieldDescs);
1944 // Get an id for the dynamic class. We store it in the class because
1945 // no class that is persisted in ngen should have it (ie, if the class is ngened
1946 // The id is stored in an optional field so we need to ensure an optional field descriptor has
1947 // been allocated for this EEClass instance.
1948 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, pAllocator->GetLowFrequencyHeap());
1949 SetModuleDynamicID(GetModule()->AllocateDynamicEntry(pMT));
1954 // if there are context or thread static set the info in the method table optional members
1957 // Check for the RemotingProxy Attribute
1958 // structs with GC pointers MUST be pointer sized aligned because the GC assumes it
1959 if (IsValueClass() && pMT->ContainsPointers() && (bmtFP->NumInstanceFieldBytes % sizeof(void*) != 0))
1961 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
1966 // Reset parent class
1967 pMT->SetParentMethodTable (g_pObjectClass);
1971 // Reset the debug method names for BoxedEntryPointStubs
1972 // so they reflect the very best debug information for the methods
1974 DeclaredMethodIterator methIt(*this);
1975 while (methIt.Next())
1977 if (methIt->GetUnboxedMethodDesc() != NULL)
1980 MethodDesc *pMD = methIt->GetUnboxedMethodDesc();
1981 StackSString name(SString::Utf8);
1982 TypeString::AppendMethodDebug(name, pMD);
1983 StackScratchBuffer buff;
1984 const char* pDebugNameUTF8 = name.GetUTF8(buff);
1985 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8)) + S_SIZE_T(1);
1986 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
1987 size_t len = safeLen.Value();
1988 pMD->m_pszDebugMethodName = (char*) AllocateFromLowFrequencyHeap(safeLen);
1989 _ASSERTE(pMD->m_pszDebugMethodName);
1990 strcpy_s((char *) pMD->m_pszDebugMethodName, len, pDebugNameUTF8);
1994 MethodDesc *pMD = methIt->GetMethodDesc();
1996 StackSString name(SString::Utf8);
1997 TypeString::AppendMethodDebug(name, pMD);
1998 StackScratchBuffer buff;
1999 const char* pDebugNameUTF8 = name.GetUTF8(buff);
2000 S_SIZE_T safeLen = S_SIZE_T(strlen(pDebugNameUTF8))+S_SIZE_T(1);
2001 if(safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
2002 size_t len = safeLen.Value();
2003 pMD->m_pszDebugMethodName = (char*) AllocateFromLowFrequencyHeap(safeLen);
2004 _ASSERTE(pMD->m_pszDebugMethodName);
2005 strcpy_s((char *) pMD->m_pszDebugMethodName, len, pDebugNameUTF8);
2013 //If this is a value type, then propagate the UnsafeValueTypeAttribute from
2014 //its instance members to this type.
2015 if (IsValueClass() && !IsUnsafeValueClass())
2017 ApproxFieldDescIterator fields(GetHalfBakedMethodTable(),
2018 ApproxFieldDescIterator::INSTANCE_FIELDS );
2019 FieldDesc * current;
2020 while (NULL != (current = fields.Next()))
2022 CONSISTENCY_CHECK(!current->IsStatic());
2023 if (current->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
2025 TypeHandle th = current->LookupApproxFieldTypeHandle();
2026 CONSISTENCY_CHECK(!th.IsNull());
2027 if (th.AsMethodTable()->GetClass()->IsUnsafeValueClass())
2029 SetUnsafeValueClass();
2036 #ifdef FEATURE_ICASTABLE
2037 if (!IsValueClass() && g_pICastableInterface != NULL && pMT->CanCastToInterface(g_pICastableInterface))
2039 pMT->SetICastable();
2041 #endif // FEATURE_ICASTABLE
2043 // Grow the typedef ridmap in advance as we can't afford to
2044 // fail once we set the resolve bit
2045 pModule->EnsureTypeDefCanBeStored(bmtInternal->pType->GetTypeDefToken());
2047 // Grow the tables in advance so that RID map filling cannot fail
2048 // once we're past the commit point.
2049 EnsureRIDMapsCanBeFilled();
2052 // NOTE. NOTE!! the EEclass can now be accessed by other threads.
2053 // Do NOT place any initialization after this point.
2054 // You may NOT fail the call after this point.
2056 CANNOTTHROWCOMPLUSEXCEPTION();
2059 GetMemTracker()->SuppressRelease();
2064 if (g_pConfig->ShouldDumpOnClassLoad(pszDebugName))
2066 LOG((LF_ALWAYS, LL_ALWAYS, "Method table summary for '%s':\n", pszDebugName));
2067 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static fields: %d\n", bmtEnumFields->dwNumStaticFields));
2068 LOG((LF_ALWAYS, LL_ALWAYS, "Number of instance fields: %d\n", bmtEnumFields->dwNumInstanceFields));
2069 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static obj ref fields: %d\n", bmtEnumFields->dwNumStaticObjRefFields));
2070 LOG((LF_ALWAYS, LL_ALWAYS, "Number of static boxed fields: %d\n", bmtEnumFields->dwNumStaticBoxedFields));
2071 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared fields: %d\n", NumDeclaredFields()));
2072 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared methods: %d\n", NumDeclaredMethods()));
2073 LOG((LF_ALWAYS, LL_ALWAYS, "Number of declared non-abstract methods: %d\n", bmtMethod->dwNumDeclaredNonAbstractMethods));
2074 pMT->Debug_DumpInterfaceMap("Approximate");
2075 pMT->DebugDumpVtable(pszDebugName, FALSE);
2076 pMT->DebugDumpFieldLayout(pszDebugName, FALSE);
2077 pMT->DebugDumpGCDesc(pszDebugName, FALSE);
2078 pMT->Debug_DumpDispatchMap();
2082 STRESS_LOG3(LF_CLASSLOADER, LL_INFO1000, "MethodTableBuilder: finished method table for module %p token %x = %pT \n",
2085 GetHalfBakedMethodTable());
2087 #ifdef MDA_SUPPORTED
2088 MdaMarshaling* mda = MDA_GET_ASSISTANT(Marshaling);
2089 if (mda && HasLayout())
2091 FieldMarshaler *pFieldMarshaler = (FieldMarshaler*)GetLayoutInfo()->GetFieldMarshalers();
2092 UINT numReferenceFields = GetLayoutInfo()->GetNumCTMFields();
2094 while (numReferenceFields--)
2096 mda->ReportFieldMarshal(pFieldMarshaler);
2098 ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
2101 #endif // MDA_SUPPORTED
2103 #ifdef FEATURE_PREJIT
2104 _ASSERTE(pComputedPZM == Module::GetPreferredZapModuleForMethodTable(pMT));
2105 #endif // FEATURE_PREJIT
2107 END_INTERIOR_STACK_PROBE;
2109 return GetHalfBakedMethodTable();
2110 } // MethodTableBuilder::BuildMethodTableThrowing
2112 #pragma warning(pop)
2116 //---------------------------------------------------------------------------------------
2118 // Resolve unresolved interfaces, determine an upper bound on the size of the interface map.
2121 MethodTableBuilder::ResolveInterfaces(
2122 WORD cBuildingInterfaceList,
2123 BuildingInterfaceInfo_t * pBuildingInterfaceList)
2128 PRECONDITION(CheckPointer(this));
2129 PRECONDITION(CheckPointer(bmtAllocator));
2130 PRECONDITION(CheckPointer(bmtInterface));
2131 PRECONDITION(CheckPointer(bmtVT));
2132 PRECONDITION(CheckPointer(bmtParent));
2136 // resolve unresolved interfaces and determine the size of the largest interface (in # slots)
2139 LoadApproxInterfaceMap();
2141 // Inherit parental slot counts
2142 //@TODO: This doesn't belong here.
2145 MethodTable * pParentClass = GetParentMethodTable();
2146 PREFIX_ASSUME(pParentClass != NULL);
2148 bmtParent->NumParentPointerSeries = pParentClass->ContainsPointers() ?
2149 (DWORD)CGCDesc::GetCGCDescFromMT(pParentClass)->GetNumSeries() : 0;
2151 if (pParentClass->HasFieldsWhichMustBeInited())
2153 SetHasFieldsWhichMustBeInited();
2155 #ifdef FEATURE_READYTORUN
2156 if (!(IsValueClass() || (pParentClass == g_pObjectClass)))
2158 CheckLayoutDependsOnOtherModules(pParentClass);
2164 bmtParent->NumParentPointerSeries = 0;
2166 } // MethodTableBuilder::ResolveInterfaces
2168 //*******************************************************************************
2170 int __cdecl MethodTableBuilder::bmtMetaDataInfo::MethodImplTokenPair::Compare(
2174 STATIC_CONTRACT_LEAF;
2175 MethodImplTokenPair *e1 = (MethodImplTokenPair *)elem1;
2176 MethodImplTokenPair *e2 = (MethodImplTokenPair *)elem2;
2177 if (e1->methodBody < e2->methodBody) return -1;
2178 else if (e1->methodBody > e2->methodBody) return 1;
2179 else if (e1->methodDecl < e2->methodDecl) return -1;
2180 else if (e1->methodDecl > e2->methodDecl) return 1;
2184 //*******************************************************************************
2186 BOOL MethodTableBuilder::bmtMetaDataInfo::MethodImplTokenPair::Equal(
2187 const MethodImplTokenPair *elem1,
2188 const MethodImplTokenPair *elem2)
2190 STATIC_CONTRACT_LEAF;
2191 return ((elem1->methodBody == elem2->methodBody) &&
2192 (elem1->methodDecl == elem2->methodDecl));
2195 //*******************************************************************************
2197 MethodTableBuilder::EnumerateMethodImpls()
2199 STANDARD_VM_CONTRACT;
2202 IMDInternalImport * pMDInternalImport = GetMDImport();
2203 DWORD rid, maxRidMD, maxRidMR;
2204 HENUMInternalMethodImplHolder hEnumMethodImpl(pMDInternalImport);
2205 hr = hEnumMethodImpl.EnumMethodImplInitNoThrow(GetCl());
2209 BuildMethodTableThrowException(hr, *bmtError);
2212 // This gets the count out of the metadata interface.
2213 bmtMethod->dwNumberMethodImpls = hEnumMethodImpl.EnumMethodImplGetCount();
2214 bmtMethod->dwNumberInexactMethodImplCandidates = 0;
2216 // This is the first pass. In this we will simply enumerate the token pairs and fill in
2217 // the data structures. In addition, we'll sort the list and eliminate duplicates.
2218 if (bmtMethod->dwNumberMethodImpls > 0)
2221 // Allocate the structures to keep track of the token pairs
2223 bmtMetaData->rgMethodImplTokens = new (GetStackingAllocator())
2224 bmtMetaDataInfo::MethodImplTokenPair[bmtMethod->dwNumberMethodImpls];
2226 // Iterate through each MethodImpl declared on this class
2227 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls; i++)
2229 hr = hEnumMethodImpl.EnumMethodImplNext(
2230 &bmtMetaData->rgMethodImplTokens[i].methodBody,
2231 &bmtMetaData->rgMethodImplTokens[i].methodDecl);
2232 bmtMetaData->rgMethodImplTokens[i].fConsiderDuringInexactMethodImplProcessing = false;
2233 bmtMetaData->rgMethodImplTokens[i].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
2234 bmtMetaData->rgMethodImplTokens[i].interfaceEquivalenceSet = 0;
2238 BuildMethodTableThrowException(hr, *bmtError);
2240 // Grab the next set of body/decl tokens
2243 // In the odd case that the enumerator fails before we've reached the total reported
2244 // entries, let's reset the count and just break out. (Should we throw?)
2245 bmtMethod->dwNumberMethodImpls = i;
2250 // No need to do any sorting or duplicate elimination if there's not two or more methodImpls
2251 if (bmtMethod->dwNumberMethodImpls > 1)
2254 qsort(bmtMetaData->rgMethodImplTokens,
2255 bmtMethod->dwNumberMethodImpls,
2256 sizeof(bmtMetaDataInfo::MethodImplTokenPair),
2257 &bmtMetaDataInfo::MethodImplTokenPair::Compare);
2259 // Now eliminate duplicates
2260 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls - 1; i++)
2262 CONSISTENCY_CHECK((i + 1) < bmtMethod->dwNumberMethodImpls);
2264 bmtMetaDataInfo::MethodImplTokenPair *e1 = &bmtMetaData->rgMethodImplTokens[i];
2265 bmtMetaDataInfo::MethodImplTokenPair *e2 = &bmtMetaData->rgMethodImplTokens[i + 1];
2267 // If the pair are equal, eliminate the first one, and reduce the total count by one.
2268 if (bmtMetaDataInfo::MethodImplTokenPair::Equal(e1, e2))
2270 DWORD dwCopyNum = bmtMethod->dwNumberMethodImpls - (i + 1);
2271 memcpy(e1, e2, dwCopyNum * sizeof(bmtMetaDataInfo::MethodImplTokenPair));
2272 bmtMethod->dwNumberMethodImpls--;
2273 CONSISTENCY_CHECK(bmtMethod->dwNumberMethodImpls > 0);
2279 if (bmtMethod->dwNumberMethodImpls != 0)
2282 // Allocate the structures to keep track of the impl matches
2284 bmtMetaData->pMethodDeclSubsts = new (GetStackingAllocator())
2285 Substitution[bmtMethod->dwNumberMethodImpls];
2287 // These are used for verification
2288 maxRidMD = pMDInternalImport->GetCountWithTokenKind(mdtMethodDef);
2289 maxRidMR = pMDInternalImport->GetCountWithTokenKind(mdtMemberRef);
2291 // Iterate through each MethodImpl declared on this class
2292 for (DWORD i = 0; i < bmtMethod->dwNumberMethodImpls; i++)
2294 PCCOR_SIGNATURE pSigDecl = NULL;
2295 PCCOR_SIGNATURE pSigBody = NULL;
2300 mdToken theBody, theDecl;
2301 Substitution theDeclSubst(GetModule(), SigPointer(), NULL); // this can get updated later below.
2303 theBody = bmtMetaData->rgMethodImplTokens[i].methodBody;
2304 theDecl = bmtMetaData->rgMethodImplTokens[i].methodDecl;
2306 // IMPLEMENTATION LIMITATION: currently, we require that the body of a methodImpl
2307 // belong to the current type. This is because we need to allocate a different
2308 // type of MethodDesc for bodies that are part of methodImpls.
2309 if (TypeFromToken(theBody) != mdtMethodDef)
2311 hr = FindMethodDeclarationForMethodImpl(
2317 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_MI_ILLEGAL_BODY, mdMethodDefNil);
2320 // Make sure to update the stored token with the resolved token.
2321 bmtMetaData->rgMethodImplTokens[i].methodBody = theBody;
2324 if (TypeFromToken(theBody) != mdtMethodDef)
2326 BuildMethodTableThrowException(BFA_METHODDECL_NOT_A_METHODDEF);
2328 CONSISTENCY_CHECK(theBody == bmtMetaData->rgMethodImplTokens[i].methodBody);
2331 // Now that the tokens of Decl and Body are obtained, do the MD validation
2334 rid = RidFromToken(theDecl);
2336 // Perform initial rudimentary validation of the token. Full token verification
2337 // will be done in TestMethodImpl when placing the methodImpls.
2338 if (TypeFromToken(theDecl) == mdtMethodDef)
2340 // Decl must be valid token
2341 if ((rid == 0) || (rid > maxRidMD))
2343 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL);
2345 // Get signature and length
2346 if (FAILED(pMDInternalImport->GetSigOfMethodDef(theDecl, &cbSigDecl, &pSigDecl)))
2348 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2352 // The token is not a MethodDef (likely a MemberRef)
2355 // Decl must be valid token
2356 if ((TypeFromToken(theDecl) != mdtMemberRef) || (rid == 0) || (rid > maxRidMR))
2358 bmtError->resIDWhy = IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL;
2359 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_DECL);
2362 // Get signature and length
2364 if (FAILED(pMDInternalImport->GetNameAndSigOfMemberRef(theDecl, &pSigDecl, &cbSigDecl, &szDeclName)))
2366 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2370 hr = pMDInternalImport->GetParentToken(theDecl,&tkParent);
2372 BuildMethodTableThrowException(hr, *bmtError);
2374 theDeclSubst = Substitution(tkParent, GetModule(), NULL);
2377 // Perform initial rudimentary validation of the token. Full token verification
2378 // will be done in TestMethodImpl when placing the methodImpls.
2380 // Body must be valid token
2381 rid = RidFromToken(theBody);
2382 if ((rid == 0)||(rid > maxRidMD))
2384 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_TOKEN_BODY);
2386 // Body's parent must be this class
2387 hr = pMDInternalImport->GetParentToken(theBody,&tkParent);
2389 BuildMethodTableThrowException(hr, *bmtError);
2390 if(tkParent != GetCl())
2392 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ILLEGAL_BODY);
2395 // Decl's and Body's signatures must match
2396 if(pSigDecl && cbSigDecl)
2398 if (FAILED(pMDInternalImport->GetSigOfMethodDef(theBody, &cbSigBody, &pSigBody)) ||
2399 (pSigBody == NULL) ||
2402 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_BODY);
2404 // Can't use memcmp because there may be two AssemblyRefs
2405 // in this scope, pointing to the same assembly, etc.).
2406 if (!MetaSig::CompareMethodSigs(
2416 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH);
2421 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_DECL);
2424 bmtMetaData->pMethodDeclSubsts[i] = theDeclSubst;
2427 } // MethodTableBuilder::EnumerateMethodImpls
2429 //*******************************************************************************
2431 // Find a method declaration that must reside in the scope passed in. This method cannot be called if
2432 // the reference travels to another scope.
2434 // Protect against finding a declaration that lives within
2435 // us (the type being created)
2437 HRESULT MethodTableBuilder::FindMethodDeclarationForMethodImpl(
2438 mdToken pToken, // Token that is being located (MemberRef or MemberDef)
2439 mdToken* pDeclaration, // [OUT] Method definition for Member
2440 BOOL fSameClass) // Does the declaration need to be in this class
2442 STANDARD_VM_CONTRACT;
2446 IMDInternalImport *pMDInternalImport = GetMDImport();
2448 PCCOR_SIGNATURE pSig; // Signature of Member
2450 LPCUTF8 szMember = NULL;
2452 // The token should be a member ref or def. If it is a ref then we need to travel
2453 // back to us hopefully.
2454 if(TypeFromToken(pToken) == mdtMemberRef)
2458 if (FAILED(pMDInternalImport->GetParentOfMemberRef(pToken, &typeref)))
2460 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid MemberRef record");
2461 IfFailRet(COR_E_TYPELOAD);
2464 if (TypeFromToken(typeref) == mdtMethodDef)
2465 { // If parent is a method def then this is a varags method
2467 hr = pMDInternalImport->GetParentToken(typeref, &typeDef);
2469 if (TypeFromToken(typeDef) != mdtTypeDef)
2470 { // A mdtMethodDef must be parented by a mdtTypeDef
2471 BAD_FORMAT_NOTHROW_ASSERT(!"MethodDef without TypeDef as Parent");
2472 IfFailRet(COR_E_TYPELOAD);
2475 BAD_FORMAT_NOTHROW_ASSERT(typeDef == GetCl());
2477 // This is the real method we are overriding
2478 *pDeclaration = typeref;
2480 else if (TypeFromToken(typeref) == mdtTypeSpec)
2481 { // Added so that method impls can refer to instantiated interfaces or classes
2482 if (FAILED(pMDInternalImport->GetSigFromToken(typeref, &cSig, &pSig)))
2484 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid TypeSpec record");
2485 IfFailRet(COR_E_TYPELOAD);
2487 CorElementType elemType = (CorElementType) *pSig++;
2489 if (elemType == ELEMENT_TYPE_GENERICINST)
2490 { // If this is a generic inst, we expect that the next elem is ELEMENT_TYPE_CLASS,
2491 // which is handled in the case below.
2492 elemType = (CorElementType) *pSig++;
2493 BAD_FORMAT_NOTHROW_ASSERT(elemType == ELEMENT_TYPE_CLASS);
2496 if (elemType == ELEMENT_TYPE_CLASS)
2497 { // This covers E_T_GENERICINST and E_T_CLASS typespec formats. We don't expect
2498 // any other kinds to come through here.
2499 CorSigUncompressToken(pSig, &typeref);
2502 { // This is an unrecognized signature format.
2503 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2504 IDS_CLASSLOAD_MI_BAD_SIG,
2510 { // Verify that the ref points back to us
2511 mdToken tkDef = mdTokenNil;
2513 if (TypeFromToken(typeref) == mdtTypeRef)
2514 { // We only get here when we know the token does not reference a type in a different scope.
2515 LPCUTF8 pszNameSpace;
2516 LPCUTF8 pszClassName;
2518 if (FAILED(pMDInternalImport->GetNameOfTypeRef(typeref, &pszNameSpace, &pszClassName)))
2520 IfFailRet(COR_E_TYPELOAD);
2523 if (FAILED(pMDInternalImport->GetResolutionScopeOfTypeRef(typeref, &tkRes)))
2525 IfFailRet(COR_E_TYPELOAD);
2527 hr = pMDInternalImport->FindTypeDef(pszNameSpace,
2529 (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil,
2533 IfFailRet(COR_E_TYPELOAD);
2536 else if (TypeFromToken(typeref) == mdtTypeDef)
2537 { // We get a typedef when the parent of the token is a typespec to the type.
2542 CONSISTENCY_CHECK_MSGF(FALSE, ("Invalid methodimpl signature in class %s.", GetDebugClassName()));
2543 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2544 IDS_CLASSLOAD_MI_BAD_SIG,
2548 if (fSameClass && tkDef != GetCl())
2549 { // If we required that the typedef be the same type as the current class,
2550 // and it doesn't match, we need to return a failure result.
2551 IfFailRet(COR_E_TYPELOAD);
2554 IfFailRet(pMDInternalImport->GetNameAndSigOfMemberRef(pToken, &pSig, &cSig, &szMember));
2557 MetaSig::GetCallingConvention(GetModule(), Signature(pSig, cSig)),
2558 IMAGE_CEE_CS_CALLCONV_FIELD))
2560 return VLDTR_E_MR_BADCALLINGCONV;
2563 hr = pMDInternalImport->FindMethodDef(
2564 tkDef, szMember, pSig, cSig, pDeclaration);
2569 else if (TypeFromToken(pToken) == mdtMethodDef)
2573 // Verify that we are the parent
2574 hr = pMDInternalImport->GetParentToken(pToken, &typeDef);
2577 if(typeDef != GetCl())
2579 IfFailRet(COR_E_TYPELOAD);
2582 *pDeclaration = pToken;
2586 IfFailRet(COR_E_TYPELOAD);
2592 #pragma warning(push)
2593 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
2595 //---------------------------------------------------------------------------------------
2597 // Used by BuildMethodTable
2599 // Enumerate this class's members
2602 MethodTableBuilder::EnumerateClassMethods()
2607 PRECONDITION(CheckPointer(bmtInternal));
2608 PRECONDITION(CheckPointer(bmtEnumFields));
2609 PRECONDITION(CheckPointer(bmtMFDescs));
2610 PRECONDITION(CheckPointer(bmtProp));
2611 PRECONDITION(CheckPointer(bmtMetaData));
2612 PRECONDITION(CheckPointer(bmtVT));
2613 PRECONDITION(CheckPointer(bmtError));
2619 IMDInternalImport *pMDInternalImport = GetMDImport();
2621 DWORD dwMemberAttrs;
2622 BOOL fIsClassEnum = IsEnum();
2623 BOOL fIsClassInterface = IsInterface();
2624 BOOL fIsClassValueType = IsValueClass();
2625 BOOL fIsClassComImport = IsComImport();
2626 BOOL fIsClassNotAbstract = (IsTdAbstract(GetAttrClass()) == 0);
2627 PCCOR_SIGNATURE pMemberSignature;
2628 ULONG cMemberSignature;
2631 // Run through the method list and calculate the following:
2633 // # "other" methods (i.e. static or private)
2634 // # non-other methods
2637 HENUMInternalHolder hEnumMethod(pMDInternalImport);
2638 hr = hEnumMethod.EnumInitNoThrow(mdtMethodDef, GetCl());
2641 BuildMethodTableThrowException(hr, *bmtError);
2644 // Allocate an array to contain the method tokens as well as information about the methods.
2645 DWORD cMethAndGaps = hEnumMethod.EnumGetCount();
2647 if ((DWORD)MAX_SLOT_INDEX <= cMethAndGaps)
2648 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
2650 bmtMethod->m_cMaxDeclaredMethods = (SLOT_INDEX)cMethAndGaps;
2651 bmtMethod->m_cDeclaredMethods = 0;
2652 bmtMethod->m_rgDeclaredMethods = new (GetStackingAllocator())
2653 bmtMDMethod *[bmtMethod->m_cMaxDeclaredMethods];
2655 enum { SeenCtor = 1, SeenInvoke = 2, SeenBeginInvoke = 4, SeenEndInvoke = 8};
2656 unsigned delegateMethodsSeen = 0;
2658 for (i = 0; i < cMethAndGaps; i++)
2663 METHOD_IMPL_TYPE implType;
2664 LPSTR strMethodName;
2666 #ifdef FEATURE_TYPEEQUIVALENCE
2667 // TypeEquivalent structs must not have methods
2668 if (bmtProp->fIsTypeEquivalent && fIsClassValueType)
2670 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTMETHODS);
2675 // Go to the next method and retrieve its attributes.
2678 hEnumMethod.EnumNext(&tok);
2679 DWORD rid = RidFromToken(tok);
2680 if ((rid == 0)||(rid > pMDInternalImport->GetCountWithTokenKind(mdtMethodDef)))
2682 BuildMethodTableThrowException(BFA_METHOD_TOKEN_OUT_OF_RANGE);
2685 if (FAILED(pMDInternalImport->GetMethodDefProps(tok, &dwMemberAttrs)))
2687 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2689 if (IsMdRTSpecialName(dwMemberAttrs) || IsMdVirtual(dwMemberAttrs) || IsDelegate())
2691 if (FAILED(pMDInternalImport->GetNameOfMethodDef(tok, (LPCSTR *)&strMethodName)))
2693 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2695 if(IsStrLongerThan(strMethodName,MAX_CLASS_NAME))
2697 BuildMethodTableThrowException(BFA_METHOD_NAME_TOO_LONG);
2702 strMethodName = NULL;
2705 DWORD numGenericMethodArgs = 0;
2708 HENUMInternalHolder hEnumTyPars(pMDInternalImport);
2709 hr = hEnumTyPars.EnumInitNoThrow(mdtGenericParam, tok);
2712 BuildMethodTableThrowException(hr, *bmtError);
2715 numGenericMethodArgs = hEnumTyPars.EnumGetCount();
2717 // We do not want to support context-bound objects with generic methods.
2719 if (numGenericMethodArgs != 0)
2721 HENUMInternalHolder hEnumGenericPars(pMDInternalImport);
2723 hEnumGenericPars.EnumInit(mdtGenericParam, tok);
2725 for (unsigned methIdx = 0; methIdx < numGenericMethodArgs; methIdx++)
2727 mdGenericParam tkTyPar;
2728 pMDInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
2730 if (FAILED(pMDInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
2732 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2735 if (0 != (flags & ~(gpVarianceMask | gpSpecialConstraintMask)))
2737 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2739 switch (flags & gpVarianceMask)
2744 case gpCovariant: // intentional fallthru
2745 case gpContravariant:
2746 BuildMethodTableThrowException(VLDTR_E_GP_ILLEGAL_VARIANT_MVAR);
2750 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
2758 // We need to check if there are any gaps in the vtable. These are
2759 // represented by methods with the mdSpecial flag and a name of the form
2760 // _VTblGap_nnn (to represent nnn empty slots) or _VTblGap (to represent a
2761 // single empty slot).
2764 if (IsMdRTSpecialName(dwMemberAttrs))
2766 PREFIX_ASSUME(strMethodName != NULL); // if we've gotten here we've called GetNameOfMethodDef
2768 // The slot is special, but it might not be a vtable spacer. To
2769 // determine that we must look at the name.
2770 if (strncmp(strMethodName, "_VtblGap", 8) == 0)
2773 // This slot doesn't really exist, don't add it to the method
2774 // table. Instead it represents one or more empty slots, encoded
2775 // in the method name. Locate the beginning of the count in the
2776 // name. There are these points to consider:
2777 // There may be no count present at all (in which case the
2778 // count is taken as one).
2779 // There may be an additional count just after Gap but before
2780 // the '_'. We ignore this.
2783 LPCSTR pos = strMethodName + 8;
2785 // Skip optional number.
2786 while (IS_DIGIT(*pos))
2791 // Check for presence of count.
2798 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2799 IDS_CLASSLOAD_BADSPECIALMETHOD,
2807 bool fReadAtLeastOneDigit = false;
2808 while (IS_DIGIT(*pos))
2812 n += DIGIT_TO_INT(*pos);
2814 fReadAtLeastOneDigit = true;
2817 // Check for end of name.
2818 if (*pos != '\0' || !fReadAtLeastOneDigit)
2820 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
2821 IDS_CLASSLOAD_BADSPECIALMETHOD,
2826 #ifdef FEATURE_COMINTEROP
2827 // Record vtable gap in mapping list. The map is an optional field, so ensure we've allocated
2828 // these fields first.
2829 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
2830 if (GetHalfBakedClass()->GetSparseCOMInteropVTableMap() == NULL)
2831 GetHalfBakedClass()->SetSparseCOMInteropVTableMap(new SparseVTableMap());
2833 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->RecordGap((WORD)NumDeclaredMethods(), n);
2835 bmtProp->fSparse = true;
2836 #endif // FEATURE_COMINTEROP
2844 // This is a real method so add it to the enumeration of methods. We now need to retrieve
2845 // information on the method and store it for later use.
2847 if (FAILED(pMDInternalImport->GetMethodImplProps(tok, &dwMethodRVA, &dwImplFlags)))
2849 BuildMethodTableThrowException(
2850 COR_E_BADIMAGEFORMAT,
2851 IDS_CLASSLOAD_BADSPECIALMETHOD,
2855 // But first - minimal flags validity checks
2857 // No methods in Enums!
2860 BuildMethodTableThrowException(BFA_METHOD_IN_A_ENUM);
2863 if (dwMethodRVA != 0)
2865 #ifdef FEATURE_COMINTEROP
2866 if(fIsClassComImport)
2868 BuildMethodTableThrowException(BFA_METHOD_WITH_NONZERO_RVA);
2870 #endif // FEATURE_COMINTEROP
2871 if(IsMdAbstract(dwMemberAttrs))
2873 BuildMethodTableThrowException(BFA_ABSTRACT_METHOD_WITH_RVA);
2875 if(IsMiRuntime(dwImplFlags))
2877 BuildMethodTableThrowException(BFA_RUNTIME_METHOD_WITH_RVA);
2879 if(IsMiInternalCall(dwImplFlags))
2881 BuildMethodTableThrowException(BFA_INTERNAL_METHOD_WITH_RVA);
2885 // Abstract / not abstract
2886 if(IsMdAbstract(dwMemberAttrs))
2888 if(fIsClassNotAbstract)
2890 BuildMethodTableThrowException(BFA_AB_METHOD_IN_AB_CLASS);
2892 if(!IsMdVirtual(dwMemberAttrs))
2894 BuildMethodTableThrowException(BFA_NONVIRT_AB_METHOD);
2897 else if(fIsClassInterface)
2899 if (IsMdRTSpecialName(dwMemberAttrs))
2901 CONSISTENCY_CHECK(CheckPointer(strMethodName));
2902 if (strcmp(strMethodName, COR_CCTOR_METHOD_NAME))
2904 BuildMethodTableThrowException(BFA_NONAB_NONCCTOR_METHOD_ON_INT);
2909 // Virtual / not virtual
2910 if(IsMdVirtual(dwMemberAttrs))
2912 if(IsMdPinvokeImpl(dwMemberAttrs))
2914 BuildMethodTableThrowException(BFA_VIRTUAL_PINVOKE_METHOD);
2916 if(IsMdStatic(dwMemberAttrs))
2918 BuildMethodTableThrowException(BFA_VIRTUAL_STATIC_METHOD);
2920 if(strMethodName && (0==strcmp(strMethodName, COR_CTOR_METHOD_NAME)))
2922 BuildMethodTableThrowException(BFA_VIRTUAL_INSTANCE_CTOR);
2926 #ifndef FEATURE_DEFAULT_INTERFACES
2927 // Some interface checks.
2928 if (fIsClassInterface)
2930 if (IsMdVirtual(dwMemberAttrs))
2932 if (!IsMdAbstract(dwMemberAttrs))
2934 BuildMethodTableThrowException(BFA_VIRTUAL_NONAB_INT_METHOD);
2939 // Instance field/method
2940 if (!IsMdStatic(dwMemberAttrs))
2942 BuildMethodTableThrowException(BFA_NONVIRT_INST_INT_METHOD);
2948 // No synchronized methods in ValueTypes
2949 if(fIsClassValueType && IsMiSynchronized(dwImplFlags))
2951 BuildMethodTableThrowException(BFA_SYNC_METHOD_IN_VT);
2957 if(!IsMdStatic(dwMemberAttrs))
2959 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_METHOD);
2961 if (strMethodName) //<TODO>@todo: investigate mc++ generating null name</TODO>
2963 if(0==strcmp(strMethodName, COR_CTOR_METHOD_NAME))
2965 BuildMethodTableThrowException(BFA_GLOBAL_INST_CTOR);
2970 // Generic methods or methods in generic classes
2971 // may not be part of a COM Import class (except for WinRT), PInvoke, internal call outside mscorlib.
2972 if ((bmtGenerics->GetNumGenericArgs() != 0 || numGenericMethodArgs != 0) &&
2974 #ifdef FEATURE_COMINTEROP
2975 fIsClassComImport ||
2976 bmtProp->fComEventItfType ||
2977 #endif // FEATURE_COMINTEROP
2978 IsMdPinvokeImpl(dwMemberAttrs) ||
2979 (IsMiInternalCall(dwImplFlags) && !GetModule()->IsSystem())))
2981 #ifdef FEATURE_COMINTEROP
2982 if (!GetHalfBakedClass()->IsProjectedFromWinRT())
2983 #endif // FEATURE_COMINTEROP
2985 BuildMethodTableThrowException(BFA_BAD_PLACE_FOR_GENERIC_METHOD);
2989 // Generic methods may not be marked "runtime". However note that
2990 // methods in generic delegate classes are, hence we don't apply this to
2991 // methods in generic classes in general.
2992 if (numGenericMethodArgs != 0 && IsMiRuntime(dwImplFlags))
2994 BuildMethodTableThrowException(BFA_GENERIC_METHOD_RUNTIME_IMPL);
2998 // Signature validation
2999 if (FAILED(pMDInternalImport->GetSigOfMethodDef(tok, &cMemberSignature, &pMemberSignature)))
3001 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
3003 hr = validateTokenSig(tok,pMemberSignature,cMemberSignature,dwMemberAttrs,pMDInternalImport);
3006 BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
3009 // Check the appearance of covariant and contravariant in the method signature
3010 // Note that variance is only supported for interfaces
3011 if (bmtGenerics->pVarianceInfo != NULL)
3013 SigPointer sp(pMemberSignature, cMemberSignature);
3015 IfFailThrow(sp.GetCallingConvInfo(&callConv));
3017 if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
3018 IfFailThrow(sp.GetData(NULL));
3021 IfFailThrow(sp.GetData(&numArgs));
3023 // Return type behaves covariantly
3024 if (!EEClass::CheckVarianceInSig(
3025 bmtGenerics->GetNumGenericArgs(),
3026 bmtGenerics->pVarianceInfo,
3031 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_RESULT, tok);
3033 IfFailThrow(sp.SkipExactlyOne());
3034 for (DWORD j = 0; j < numArgs; j++)
3036 // Argument types behave contravariantly
3037 if (!EEClass::CheckVarianceInSig(bmtGenerics->GetNumGenericArgs(),
3038 bmtGenerics->pVarianceInfo,
3043 BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_METHOD_ARG, tok);
3045 IfFailThrow(sp.SkipExactlyOne());
3050 // Determine the method's type
3053 if (IsReallyMdPinvokeImpl(dwMemberAttrs) || IsMiInternalCall(dwImplFlags))
3055 hr = NDirect::HasNAT_LAttribute(pMDInternalImport, tok, dwMemberAttrs);
3057 // There was a problem querying for the attribute
3060 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_BADPINVOKE, tok);
3063 // The attribute is not present
3066 if (fIsClassComImport
3067 #ifdef FEATURE_COMINTEROP
3068 || GetHalfBakedClass()->IsProjectedFromWinRT()
3069 || bmtProp->fComEventItfType
3070 #endif //FEATURE_COMINTEROP
3073 #ifdef FEATURE_COMINTEROP
3074 // ComImport classes have methods which are just used
3075 // for implementing all interfaces the class supports
3076 type = METHOD_TYPE_COMINTEROP;
3078 // constructor is special
3079 if (IsMdRTSpecialName(dwMemberAttrs))
3081 // Note: Method name (.ctor) will be checked in code:ValidateMethods
3083 // WinRT ctors are interop calls via stubs
3084 if (!GetHalfBakedClass()->IsProjectedFromWinRT())
3086 // Ctor on a non-WinRT class
3087 type = METHOD_TYPE_FCALL;
3091 //If we don't support com interop, refuse to load interop methods. Otherwise we fail to
3092 //jit calls to them since the constuctor has no intrinsic ID.
3093 BuildMethodTableThrowException(hr, IDS_CLASSLOAD_GENERAL, tok);
3094 #endif // FEATURE_COMINTEROP
3096 else if (dwMethodRVA == 0)
3098 type = METHOD_TYPE_FCALL;
3102 type = METHOD_TYPE_NDIRECT;
3105 // The NAT_L attribute is present, marking this method as NDirect
3108 CONSISTENCY_CHECK(hr == S_OK);
3109 type = METHOD_TYPE_NDIRECT;
3112 else if (IsMiRuntime(dwImplFlags))
3114 // currently the only runtime implemented functions are delegate instance methods
3115 if (!IsDelegate() || IsMdStatic(dwMemberAttrs) || IsMdAbstract(dwMemberAttrs))
3117 BuildMethodTableThrowException(BFA_BAD_RUNTIME_IMPL);
3120 unsigned newDelegateMethodSeen = 0;
3122 if (IsMdRTSpecialName(dwMemberAttrs)) // .ctor
3124 if (strcmp(strMethodName, COR_CTOR_METHOD_NAME) != 0 || IsMdVirtual(dwMemberAttrs))
3126 BuildMethodTableThrowException(BFA_BAD_FLAGS_ON_DELEGATE);
3128 newDelegateMethodSeen = SeenCtor;
3129 type = METHOD_TYPE_FCALL;
3133 if (strcmp(strMethodName, "Invoke") == 0)
3134 newDelegateMethodSeen = SeenInvoke;
3135 else if (strcmp(strMethodName, "BeginInvoke") == 0)
3136 newDelegateMethodSeen = SeenBeginInvoke;
3137 else if (strcmp(strMethodName, "EndInvoke") == 0)
3138 newDelegateMethodSeen = SeenEndInvoke;
3141 BuildMethodTableThrowException(BFA_UNKNOWN_DELEGATE_METHOD);
3143 type = METHOD_TYPE_EEIMPL;
3146 // If we get here we have either set newDelegateMethodSeen or we have thrown a BMT exception
3147 _ASSERTE(newDelegateMethodSeen != 0);
3149 if ((delegateMethodsSeen & newDelegateMethodSeen) != 0)
3151 BuildMethodTableThrowException(BFA_DUPLICATE_DELEGATE_METHOD);
3154 delegateMethodsSeen |= newDelegateMethodSeen;
3156 else if (numGenericMethodArgs != 0)
3158 //We use an instantiated method desc to represent a generic method
3159 type = METHOD_TYPE_INSTANTIATED;
3161 else if (fIsClassInterface)
3163 #ifdef FEATURE_COMINTEROP
3164 if (IsMdStatic(dwMemberAttrs))
3166 // Static methods in interfaces need nothing special.
3167 type = METHOD_TYPE_NORMAL;
3169 else if (bmtGenerics->GetNumGenericArgs() != 0 &&
3170 (bmtGenerics->fSharedByGenericInstantiations || (!bmtProp->fIsRedirectedInterface && !GetHalfBakedClass()->IsProjectedFromWinRT())))
3172 // Methods in instantiated interfaces need nothing special - they are not visible from COM etc.
3173 // mcComInterop is only useful for unshared instantiated WinRT interfaces. If the interface is
3174 // shared by multiple instantiations, the MD would be useless for interop anyway.
3175 type = METHOD_TYPE_NORMAL;
3177 else if (bmtProp->fIsMngStandardItf)
3179 // If the interface is a standard managed interface then allocate space for an FCall method desc.
3180 type = METHOD_TYPE_FCALL;
3182 else if (IsMdAbstract(dwMemberAttrs))
3184 // If COM interop is supported then all other interface MDs may be
3185 // accessed via COM interop. mcComInterop MDs have an additional
3186 // pointer-sized field pointing to COM interop data which are
3187 // allocated lazily when/if the MD actually gets used for interop.
3188 type = METHOD_TYPE_COMINTEROP;
3191 #endif // !FEATURE_COMINTEROP
3193 // This codepath is used by remoting
3194 type = METHOD_TYPE_NORMAL;
3199 type = METHOD_TYPE_NORMAL;
3202 // PInvoke methods are not permitted on collectible types
3203 if ((type == METHOD_TYPE_NDIRECT) && GetAssembly()->IsCollectible())
3205 BuildMethodTableThrowException(IDS_CLASSLOAD_COLLECTIBLEPINVOKE);
3208 // Generic methods should always be METHOD_TYPE_INSTANTIATED
3209 if ((numGenericMethodArgs != 0) && (type != METHOD_TYPE_INSTANTIATED))
3211 BuildMethodTableThrowException(BFA_GENERIC_METHODS_INST);
3214 // count how many overrides this method does All methods bodies are defined
3215 // on this type so we can just compare the tok with the body token found
3216 // from the overrides.
3217 implType = METHOD_IMPL_NOT;
3218 for (DWORD impls = 0; impls < bmtMethod->dwNumberMethodImpls; impls++)
3220 if (bmtMetaData->rgMethodImplTokens[impls].methodBody == tok)
3222 implType = METHOD_IMPL;
3227 // For delegates we don't allow any non-runtime implemented bodies
3228 // for any of the four special methods
3229 if (IsDelegate() && !IsMiRuntime(dwImplFlags))
3231 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
3232 (strcmp(strMethodName, "Invoke") == 0) ||
3233 (strcmp(strMethodName, "BeginInvoke") == 0) ||
3234 (strcmp(strMethodName, "EndInvoke") == 0) )
3236 BuildMethodTableThrowException(BFA_ILLEGAL_DELEGATE_METHOD);
3241 // Create a new bmtMDMethod representing this method and add it to the
3242 // declared method list.
3245 bmtMDMethod * pNewMethod = new (GetStackingAllocator()) bmtMDMethod(
3254 bmtMethod->AddDeclaredMethod(pNewMethod);
3257 // Update the count of the various types of methods.
3260 bmtVT->dwMaxVtableSize++;
3262 // Increment the number of non-abstract declared methods
3263 if (!IsMdAbstract(dwMemberAttrs))
3265 bmtMethod->dwNumDeclaredNonAbstractMethods++;
3269 // Check to see that we have all of the required delegate methods (ECMA 13.6 Delegates)
3272 // Do we have all four special delegate methods
3273 // or just the two special delegate methods
3274 if ((delegateMethodsSeen != (SeenCtor | SeenInvoke | SeenBeginInvoke | SeenEndInvoke)) &&
3275 (delegateMethodsSeen != (SeenCtor | SeenInvoke)) )
3277 BuildMethodTableThrowException(BFA_MISSING_DELEGATE_METHOD);
3281 if (i != cMethAndGaps)
3283 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_METHOD_COUNT, mdTokenNil);
3286 #ifdef FEATURE_COMINTEROP
3288 // If the interface is sparse, we need to finalize the mapping list by
3289 // telling it how many real methods we found.
3292 if (bmtProp->fSparse)
3294 GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->FinalizeMapping(NumDeclaredMethods());
3296 #endif // FEATURE_COMINTEROP
3297 } // MethodTableBuilder::EnumerateClassMethods
3299 #pragma warning(pop)
3302 //*******************************************************************************
3304 // Run through the field list and calculate the following:
3306 // # static fields that contain object refs.
3307 // # instance fields
3310 MethodTableBuilder::EnumerateClassFields()
3312 STANDARD_VM_CONTRACT;
3316 IMDInternalImport *pMDInternalImport = GetMDImport();
3318 DWORD dwMemberAttrs;
3320 bmtEnumFields->dwNumStaticFields = 0;
3321 bmtEnumFields->dwNumStaticObjRefFields = 0;
3322 bmtEnumFields->dwNumStaticBoxedFields = 0;
3324 bmtEnumFields->dwNumThreadStaticFields = 0;
3325 bmtEnumFields->dwNumThreadStaticObjRefFields = 0;
3326 bmtEnumFields->dwNumThreadStaticBoxedFields = 0;
3328 bmtEnumFields->dwNumInstanceFields = 0;
3330 HENUMInternalHolder hEnumField(pMDInternalImport);
3331 hr = hEnumField.EnumInitNoThrow(mdtFieldDef, GetCl());
3334 BuildMethodTableThrowException(hr, *bmtError);
3337 bmtMetaData->cFields = hEnumField.EnumGetCount();
3339 // Retrieve the fields and store them in a temp array.
3340 bmtMetaData->pFields = new (GetStackingAllocator()) mdToken[bmtMetaData->cFields];
3341 bmtMetaData->pFieldAttrs = new (GetStackingAllocator()) DWORD[bmtMetaData->cFields];
3343 DWORD dwFieldLiteralInitOnly = fdLiteral | fdInitOnly;
3344 DWORD dwMaxFieldDefRid = pMDInternalImport->GetCountWithTokenKind(mdtFieldDef);
3346 for (i = 0; hEnumField.EnumNext(&tok); i++)
3349 // Retrieve the attributes of the field.
3351 DWORD rid = RidFromToken(tok);
3352 if ((rid == 0)||(rid > dwMaxFieldDefRid))
3354 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, mdTokenNil);
3357 if (FAILED(pMDInternalImport->GetFieldDefProps(tok, &dwMemberAttrs)))
3359 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN, tok);
3363 // Store the field and its attributes in the bmtMetaData structure for later use.
3366 bmtMetaData->pFields[i] = tok;
3367 bmtMetaData->pFieldAttrs[i] = dwMemberAttrs;
3369 if((dwMemberAttrs & fdFieldAccessMask)==fdFieldAccessMask)
3371 BuildMethodTableThrowException(BFA_INVALID_FIELD_ACC_FLAGS);
3373 if((dwMemberAttrs & dwFieldLiteralInitOnly)==dwFieldLiteralInitOnly)
3375 BuildMethodTableThrowException(BFA_FIELD_LITERAL_AND_INIT);
3378 // can only have static global fields
3381 if(!IsFdStatic(dwMemberAttrs))
3383 BuildMethodTableThrowException(BFA_NONSTATIC_GLOBAL_FIELD);
3388 // Update the count of the various types of fields.
3391 if (IsFdStatic(dwMemberAttrs))
3393 if (!IsFdLiteral(dwMemberAttrs))
3395 #ifdef FEATURE_TYPEEQUIVALENCE
3396 if (bmtProp->fIsTypeEquivalent)
3398 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3402 bmtEnumFields->dwNumStaticFields++;
3404 // If this static field is thread static, then we need
3405 // to increment bmtEnumFields->dwNumThreadStaticFields
3406 hr = pMDInternalImport->GetCustomAttributeByName(tok,
3407 g_ThreadStaticAttributeClassName,
3412 // It's a thread static, so increment the count
3413 bmtEnumFields->dwNumThreadStaticFields++;
3419 #ifdef FEATURE_TYPEEQUIVALENCE
3420 if (!IsFdPublic(dwMemberAttrs) && bmtProp->fIsTypeEquivalent)
3422 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS);
3426 if (!IsFdLiteral(dwMemberAttrs))
3428 bmtEnumFields->dwNumInstanceFields++;
3432 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_INT);
3437 if (i != bmtMetaData->cFields)
3439 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD_COUNT, mdTokenNil);
3442 if(IsEnum() && (bmtEnumFields->dwNumInstanceFields==0))
3444 BuildMethodTableThrowException(BFA_INSTANCE_FIELD_IN_ENUM);
3447 bmtEnumFields->dwNumDeclaredFields = bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields;
3450 //*******************************************************************************
3452 // Used by BuildMethodTable
3454 // Determines the maximum size of the vtable and allocates the temporary storage arrays
3455 // Also copies the parent's vtable into the working vtable.
3457 VOID MethodTableBuilder::AllocateWorkingSlotTables()
3462 PRECONDITION(CheckPointer(this));
3463 PRECONDITION(CheckPointer(bmtAllocator));
3464 PRECONDITION(CheckPointer(bmtMFDescs));
3465 PRECONDITION(CheckPointer(bmtMetaData));
3466 PRECONDITION(CheckPointer(bmtVT));
3467 PRECONDITION(CheckPointer(bmtEnumFields));
3468 PRECONDITION(CheckPointer(bmtInterface));
3469 PRECONDITION(CheckPointer(bmtFP));
3470 PRECONDITION(CheckPointer(bmtParent));
3475 // Allocate a FieldDesc* for each field
3476 bmtMFDescs->ppFieldDescList = new (GetStackingAllocator()) FieldDesc*[bmtMetaData->cFields];
3477 ZeroMemory(bmtMFDescs->ppFieldDescList, bmtMetaData->cFields * sizeof(FieldDesc *));
3479 // Create a temporary function table (we don't know how large the vtable will be until the very end,
3480 // since we don't yet know how many declared methods are overrides vs. newslots).
3483 { // ValueClass virtuals are converted into non-virtual methods and the virtual slots
3484 // become unboxing stubs that forward to these new non-virtual methods. This has the
3485 // side effect of doubling the number of slots introduced by newslot virtuals.
3486 bmtVT->dwMaxVtableSize += NumDeclaredMethods();
3489 _ASSERTE(!HasParent() || (bmtInterface->dwInterfaceMapSize - GetParentMethodTable()->GetNumInterfaces()) >= 0);
3492 { // Add parent vtable size. <TODO> This should actually be the parent's virtual method count. </TODO>
3493 bmtVT->dwMaxVtableSize += bmtParent->pSlotTable->GetSlotCount();
3496 S_SLOT_INDEX cMaxSlots = AsClrSafeInt(bmtVT->dwMaxVtableSize) + AsClrSafeInt(NumDeclaredMethods());
3498 if (cMaxSlots.IsOverflow() || MAX_SLOT_INDEX < cMaxSlots.Value())
3499 cMaxSlots = S_SLOT_INDEX(MAX_SLOT_INDEX);
3501 // Allocate the temporary vtable
3502 bmtVT->pSlotTable = new (GetStackingAllocator())
3503 bmtMethodSlotTable(cMaxSlots.Value(), GetStackingAllocator());
3508 // @<TODO>todo: Figure out the right way to override Equals for value
3511 // This is broken because
3512 // (a) g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool); will return
3513 // the EqualsValue method
3514 // (b) When mscorlib has been preloaded (and thus the munge already done
3515 // ahead of time), we cannot easily find both methods
3516 // to compute EqualsAddr & EqualsSlot
3518 // For now, the Equals method has a runtime check to see if it's
3519 // comparing value types.
3522 // If it is a value type, over ride a few of the base class methods.
3525 static WORD EqualsSlot;
3527 // If we haven't been through here yet, get some stuff from the Object class definition.
3528 if (EqualsSlot == NULL)
3530 // Get the slot of the Equals method.
3531 MethodDesc *pEqualsMD = g_pObjectClass->FindMethod("Equals", &gsig_IM_Obj_RetBool);
3532 THROW_BAD_FORMAT_MAYBE(pEqualsMD != NULL, 0, this);
3533 EqualsSlot = pEqualsMD->GetSlot();
3535 // Get the address of the EqualsValue method.
3536 MethodDesc *pEqualsValueMD = g_pObjectClass->FindMethod("EqualsValue", &gsig_IM_Obj_RetBool);
3537 THROW_BAD_FORMAT_MAYBE(pEqualsValueMD != NULL, 0, this);
3539 // Patch the EqualsValue method desc in a dangerous way to
3540 // look like the Equals method desc.
3541 pEqualsValueMD->SetSlot(EqualsSlot);
3542 pEqualsValueMD->SetMemberDef(pEqualsMD->GetMemberDef());
3545 // Override the valuetype "Equals" with "EqualsValue".
3546 bmtVT->SetMethodDescForSlot(EqualsSlot, EqualsSlot);
3551 S_UINT32 cEntries = S_UINT32(2) * S_UINT32(NumDeclaredMethods());
3552 if (cEntries.IsOverflow())
3554 ThrowHR(COR_E_OVERFLOW);
3558 //*******************************************************************************
3560 // Used by BuildMethodTable
3562 // Allocate a MethodDesc* for each method (needed later when doing interfaces), and a FieldDesc* for each field
3564 VOID MethodTableBuilder::AllocateFieldDescs()
3569 PRECONDITION(CheckPointer(this));
3570 PRECONDITION(CheckPointer(bmtAllocator));
3571 PRECONDITION(CheckPointer(bmtMFDescs));
3572 PRECONDITION(CheckPointer(bmtMetaData));
3573 PRECONDITION(CheckPointer(bmtVT));
3574 PRECONDITION(CheckPointer(bmtEnumFields));
3575 PRECONDITION(CheckPointer(bmtFP));
3576 PRECONDITION(CheckPointer(bmtParent));
3581 // We'll be counting the # fields of each size as we go along
3582 for (DWORD i = 0; i <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++)
3584 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
3585 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
3586 bmtFP->NumInstanceFieldsOfSize[i] = 0;
3590 // Allocate blocks of MethodDescs and FieldDescs for all declared methods and fields
3592 // In order to avoid allocating a field pointing back to the method
3593 // table in every single method desc, we allocate memory in the
3594 // following manner:
3595 // o Field descs get a single contiguous block.
3596 // o Method descs of different sizes (normal vs NDirect) are
3597 // allocated in different MethodDescChunks.
3598 // o Each method desc chunk starts with a header, and has
3599 // at most MAX_ method descs (if there are more
3600 // method descs of a given size, multiple chunks are allocated).
3601 // This way method descs can use an 8-bit offset field to locate the
3602 // pointer to their method table.
3605 /////////////////////////////////////////////////////////////////
3607 if (NumDeclaredFields() > 0)
3609 GetHalfBakedClass()->SetFieldDescList((FieldDesc *)
3610 AllocateFromHighFrequencyHeap(S_SIZE_T(NumDeclaredFields()) * S_SIZE_T(sizeof(FieldDesc))));
3611 INDEBUG(GetClassLoader()->m_dwDebugFieldDescs += NumDeclaredFields();)
3612 INDEBUG(GetClassLoader()->m_dwFieldDescData += (NumDeclaredFields() * sizeof(FieldDesc));)
3616 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
3617 //*******************************************************************************
3619 // Heuristic to determine if we should have instances of this class 8 byte aligned
3621 BOOL MethodTableBuilder::ShouldAlign8(DWORD dwR8Fields, DWORD dwTotalFields)
3623 LIMITED_METHOD_CONTRACT;
3625 return dwR8Fields*2>dwTotalFields && dwR8Fields>=2;
3629 //*******************************************************************************
3630 BOOL MethodTableBuilder::IsSelfReferencingStaticValueTypeField(mdToken dwByValueClassToken,
3631 bmtInternalInfo* bmtInternal,
3632 const bmtGenericsInfo *bmtGenerics,
3633 PCCOR_SIGNATURE pMemberSignature,
3634 DWORD cMemberSignature)
3636 STANDARD_VM_CONTRACT;
3638 if (dwByValueClassToken != this->GetCl())
3643 if (!bmtGenerics->HasInstantiation())
3648 // The value class is generic. Check that the signature of the field
3649 // is _exactly_ equivalent to VC<!0, !1, !2, ...>. Do this by consing up a fake
3651 DWORD nGenericArgs = bmtGenerics->GetNumGenericArgs();
3652 CONSISTENCY_CHECK(nGenericArgs != 0);
3654 SigBuilder sigBuilder;
3656 sigBuilder.AppendElementType(ELEMENT_TYPE_GENERICINST);
3657 sigBuilder.AppendElementType(ELEMENT_TYPE_VALUETYPE);
3658 sigBuilder.AppendToken(dwByValueClassToken);
3659 sigBuilder.AppendData(nGenericArgs);
3660 for (unsigned int typearg = 0; typearg < nGenericArgs; typearg++)
3662 sigBuilder.AppendElementType(ELEMENT_TYPE_VAR);
3663 sigBuilder.AppendData(typearg);
3667 PCCOR_SIGNATURE pFakeSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cFakeSig);
3669 PCCOR_SIGNATURE pFieldSig = pMemberSignature + 1; // skip the CALLCONV_FIELD
3671 return MetaSig::CompareElementType(pFakeSig, pFieldSig,
3672 pFakeSig + cFakeSig, pMemberSignature + cMemberSignature,
3673 GetModule(), GetModule(),
3678 //*******************************************************************************
3680 // Used pByValueClass cache to mark self-references
3682 static BOOL IsSelfRef(MethodTable * pMT)
3684 return pMT == (MethodTable *)-1;
3687 //*******************************************************************************
3689 // Used by BuildMethodTable
3691 // Go thru all fields and initialize their FieldDescs.
3694 #pragma warning(push)
3695 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3698 VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
3699 const LayoutRawFieldInfo* pLayoutRawFieldInfos,
3700 bmtInternalInfo* bmtInternal,
3701 const bmtGenericsInfo* bmtGenerics,
3702 bmtMetaDataInfo* bmtMetaData,
3703 bmtEnumFieldInfo* bmtEnumFields,
3704 bmtErrorInfo* bmtError,
3705 MethodTable *** pByValueClassCache,
3706 bmtMethAndFieldDescs* bmtMFDescs,
3707 bmtFieldPlacement* bmtFP,
3708 bmtContextStaticInfo* pbmtCSInfo,
3709 unsigned* totalDeclaredSize)
3714 PRECONDITION(CheckPointer(this));
3715 PRECONDITION(CheckPointer(bmtInternal));
3716 PRECONDITION(CheckPointer(bmtGenerics));
3717 PRECONDITION(CheckPointer(bmtMetaData));
3718 PRECONDITION(CheckPointer(bmtEnumFields));
3719 PRECONDITION(CheckPointer(bmtError));
3720 PRECONDITION(CheckPointer(pByValueClassCache));
3721 PRECONDITION(CheckPointer(bmtMFDescs));
3722 PRECONDITION(CheckPointer(bmtFP));
3723 PRECONDITION(CheckPointer(totalDeclaredSize));
3728 IMDInternalImport * pInternalImport = GetMDImport(); // to avoid multiple dereferencings
3730 FieldMarshaler * pNextFieldMarshaler = NULL;
3733 pNextFieldMarshaler = (FieldMarshaler*)(GetLayoutInfo()->GetFieldMarshalers());
3737 //========================================================================
3739 // Go thru all fields and initialize their FieldDescs.
3740 //========================================================================
3742 DWORD dwCurrentDeclaredField = 0;
3743 DWORD dwCurrentStaticField = 0;
3744 DWORD dwCurrentThreadStaticField = 0;
3747 DWORD dwR8Fields = 0; // Number of R8's the class has
3749 #ifdef FEATURE_64BIT_ALIGNMENT
3750 // Track whether any field in this type requires 8-byte alignment
3751 BOOL fFieldRequiresAlign8 = HasParent() ? GetParentMethodTable()->RequiresAlign8() : FALSE;
3754 for (i = 0; i < bmtMetaData->cFields; i++)
3756 PCCOR_SIGNATURE pMemberSignature;
3757 DWORD cMemberSignature;
3758 DWORD dwMemberAttrs;
3760 dwMemberAttrs = bmtMetaData->pFieldAttrs[i];
3762 BOOL fIsStatic = IsFdStatic(dwMemberAttrs);
3764 // We don't store static final primitive fields in the class layout
3765 if (IsFdLiteral(dwMemberAttrs))
3768 if (!IsFdPublic(dwMemberAttrs))
3769 SetHasNonPublicFields();
3771 if (IsFdNotSerialized(dwMemberAttrs))
3772 SetCannotBeBlittedByObjectCloner();
3774 IfFailThrow(pInternalImport->GetSigOfFieldDef(bmtMetaData->pFields[i], &cMemberSignature, &pMemberSignature));
3775 // Signature validation
3776 IfFailThrow(validateTokenSig(bmtMetaData->pFields[i],pMemberSignature,cMemberSignature,dwMemberAttrs,pInternalImport));
3779 DWORD dwLog2FieldSize = 0;
3780 BOOL bCurrentFieldIsGCPointer = FALSE;
3781 mdToken dwByValueClassToken = 0;
3782 MethodTable * pByValueClass = NULL;
3783 BOOL fIsByValue = FALSE;
3784 BOOL fIsThreadStatic = FALSE;
3785 static const BOOL fIsContextStatic = FALSE;
3786 BOOL fHasRVA = FALSE;
3788 MetaSig fsig(pMemberSignature,
3791 &bmtGenerics->typeContext,
3793 CorElementType ElementType = fsig.NextArg();
3797 if (!isCallConv(fsig.GetCallingConvention(), IMAGE_CEE_CS_CALLCONV_FIELD))
3799 IfFailThrow(COR_E_TYPELOAD);
3802 // Determine if a static field is special i.e. RVA based, local to
3803 // a thread or a context
3806 if (IsFdHasFieldRVA(dwMemberAttrs))
3813 hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
3814 g_ThreadStaticAttributeClassName,
3819 fIsThreadStatic = TRUE;
3823 if (ElementType == ELEMENT_TYPE_VALUETYPE)
3825 hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
3826 g_CompilerServicesFixedAddressValueTypeAttribute,
3831 bmtFP->fHasFixedAddressValueTypes = true;
3836 // Do some sanity checks that we are not mixing context and thread
3837 // relative statics.
3838 if (fHasRVA && (fIsThreadStatic || fIsContextStatic))
3840 IfFailThrow(COR_E_TYPELOAD);
3843 if ((fIsThreadStatic || fIsContextStatic || bmtFP->fHasFixedAddressValueTypes) && GetAssembly()->IsCollectible())
3845 if (bmtFP->fHasFixedAddressValueTypes)
3847 BuildMethodTableThrowException(IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR);
3849 BuildMethodTableThrowException(IDS_CLASSLOAD_COLLECTIBLESPECIALSTATICS);
3855 // Type to store in FieldDesc - we don't want to have extra case statements for
3856 // ELEMENT_TYPE_STRING, SDARRAY etc., so we convert all object types to CLASS.
3857 // Also, BOOLEAN, CHAR are converted to U1, I2.
3858 CorElementType FieldDescElementType = ElementType;
3860 switch (ElementType)
3862 case ELEMENT_TYPE_I1:
3863 case ELEMENT_TYPE_U1:
3865 dwLog2FieldSize = 0;
3869 case ELEMENT_TYPE_I2:
3870 case ELEMENT_TYPE_U2:
3872 dwLog2FieldSize = 1;
3876 case ELEMENT_TYPE_I4:
3877 case ELEMENT_TYPE_U4:
3878 IN_WIN32(case ELEMENT_TYPE_I:)
3879 IN_WIN32(case ELEMENT_TYPE_U:)
3880 case ELEMENT_TYPE_R4:
3882 dwLog2FieldSize = 2;
3886 case ELEMENT_TYPE_BOOLEAN:
3888 // FieldDescElementType = ELEMENT_TYPE_U1;
3889 dwLog2FieldSize = 0;
3893 case ELEMENT_TYPE_CHAR:
3895 // FieldDescElementType = ELEMENT_TYPE_U2;
3896 dwLog2FieldSize = 1;
3900 case ELEMENT_TYPE_R8:
3904 // Deliberate fall through...
3907 case ELEMENT_TYPE_I8:
3908 case ELEMENT_TYPE_U8:
3909 IN_WIN64(case ELEMENT_TYPE_I:)
3910 IN_WIN64(case ELEMENT_TYPE_U:)
3912 #ifdef FEATURE_64BIT_ALIGNMENT
3913 // Record that this field requires alignment for Int64/UInt64.
3915 fFieldRequiresAlign8 = true;
3917 dwLog2FieldSize = 3;
3921 case ELEMENT_TYPE_FNPTR:
3922 case ELEMENT_TYPE_PTR: // ptrs are unmanaged scalars, for layout
3924 dwLog2FieldSize = LOG2_PTRSIZE;
3928 // Class type variable (method type variables aren't allowed in fields)
3929 // These only occur in open types used for verification/reflection.
3930 case ELEMENT_TYPE_VAR:
3931 case ELEMENT_TYPE_MVAR:
3932 // deliberate drop through - do fake field layout
3933 case ELEMENT_TYPE_STRING:
3934 case ELEMENT_TYPE_SZARRAY: // single dim, zero
3935 case ELEMENT_TYPE_ARRAY: // all other arrays
3936 case ELEMENT_TYPE_CLASS: // objectrefs
3937 case ELEMENT_TYPE_OBJECT:
3939 dwLog2FieldSize = LOG2_PTRSIZE;
3940 bCurrentFieldIsGCPointer = TRUE;
3941 FieldDescElementType = ELEMENT_TYPE_CLASS;
3945 SetHasFieldsWhichMustBeInited();
3946 if (ElementType != ELEMENT_TYPE_STRING)
3947 SetCannotBeBlittedByObjectCloner();
3950 { // EnumerateFieldDescs already counted the total number of static vs. instance
3951 // fields, now we're further subdividing the static field count by GC and non-GC.
3952 bmtEnumFields->dwNumStaticObjRefFields++;
3953 if (fIsThreadStatic)
3954 bmtEnumFields->dwNumThreadStaticObjRefFields++;
3959 case ELEMENT_TYPE_VALUETYPE: // a byvalue class field
3961 Module * pTokenModule;
3962 dwByValueClassToken = fsig.GetArgProps().PeekValueTypeTokenClosed(GetModule(), &bmtGenerics->typeContext, &pTokenModule);
3966 BAD_FORMAT_NOTHROW_ASSERT(dwByValueClassToken != 0);
3968 if (this->IsValueClass() && (pTokenModule == GetModule()))
3970 if (TypeFromToken(dwByValueClassToken) == mdtTypeRef)
3972 // It's a typeref - check if it's a class that has a static field of itself
3973 LPCUTF8 pszNameSpace;
3974 LPCUTF8 pszClassName;
3975 if (FAILED(pInternalImport->GetNameOfTypeRef(dwByValueClassToken, &pszNameSpace, &pszClassName)))
3977 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
3980 if (IsStrLongerThan((char *)pszClassName, MAX_CLASS_NAME)
3981 || IsStrLongerThan((char *)pszNameSpace, MAX_CLASS_NAME)
3982 || (strlen(pszClassName) + strlen(pszNameSpace) + 1 >= MAX_CLASS_NAME))
3984 BuildMethodTableThrowException(BFA_TYPEREG_NAME_TOO_LONG, mdMethodDefNil);
3988 if (FAILED(pInternalImport->GetResolutionScopeOfTypeRef(dwByValueClassToken, &tkRes)))
3990 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, dwByValueClassToken);
3993 if (TypeFromToken(tkRes) == mdtTypeRef)
3995 if (!pInternalImport->IsValidToken(tkRes))
3997 BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, mdMethodDefNil);
4005 if (FAILED(pInternalImport->FindTypeDef(pszNameSpace,
4008 &dwByValueClassToken)))
4010 dwByValueClassToken = mdTokenNil;
4012 } // If field is static typeref
4014 BOOL selfref = IsSelfReferencingStaticValueTypeField(dwByValueClassToken,
4021 { // immediately self-referential fields must be static.
4024 BuildMethodTableThrowException(IDS_CLASSLOAD_VALUEINSTANCEFIELD, mdMethodDefNil);
4027 if (!IsValueClass())
4029 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_MUST_BE_BYVAL, mdTokenNil);
4032 pByValueClass = (MethodTable *)-1;
4034 } // If 'this' is a value class
4036 // It's not self-referential so try to load it
4037 if (pByValueClass == NULL)
4039 // Loading a non-self-ref valuetype field.
4040 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
4041 // We load the approximate type of the field to avoid recursion problems.
4042 // MethodTable::DoFullyLoad() will later load it fully
4043 pByValueClass = fsig.GetArgProps().GetTypeHandleThrowing(GetModule(),
4044 &bmtGenerics->typeContext,
4045 ClassLoader::LoadTypes,
4046 CLASS_LOAD_APPROXPARENTS,
4051 // #FieldDescTypeMorph IF it is an enum, strip it down to its underlying type
4052 if (IsSelfRef(pByValueClass) ? IsEnum() : pByValueClass->IsEnum())
4054 if (IsSelfRef(pByValueClass))
4055 { // It is self-referencing enum (ValueType) static field - it is forbidden in the ECMA spec, but supported by CLR since v1
4056 // Note: literal static fields are skipped early in this loop
4057 if (bmtMFDescs->ppFieldDescList[0] == NULL)
4058 { // The field is defined before (the only) instance field
4059 // AppCompat with 3.5 SP1 and 4.0 RTM behavior
4060 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4062 // 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
4063 // later in this method)
4064 // Therefore we do not have to run code:VerifySelfReferencingStaticValueTypeFields_WithRVA or code:#SelfReferencingStaticValueTypeField_Checks
4066 BAD_FORMAT_NOTHROW_ASSERT((IsSelfRef(pByValueClass) ?
4067 bmtEnumFields->dwNumInstanceFields : pByValueClass->GetNumInstanceFields())
4068 == 1); // enums must have exactly one field
4069 FieldDesc * enumField = IsSelfRef(pByValueClass) ?
4070 bmtMFDescs->ppFieldDescList[0] : pByValueClass->GetApproxFieldDescListRaw();
4071 BAD_FORMAT_NOTHROW_ASSERT(!enumField->IsStatic()); // no real static fields on enums
4072 ElementType = enumField->GetFieldType();
4073 BAD_FORMAT_NOTHROW_ASSERT(ElementType != ELEMENT_TYPE_VALUETYPE);
4074 fIsByValue = FALSE; // we're going to treat it as the underlying type now
4075 goto GOT_ELEMENT_TYPE;
4078 // Check ByRefLike fields
4079 if (!IsSelfRef(pByValueClass) && pByValueClass->IsByRefLike())
4083 // By-ref-like types cannot be used for static fields
4084 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_STATICFIELD);
4086 if (!IsValueClass())
4088 // Non-value-classes cannot contain by-ref-like instance fields
4089 BuildMethodTableThrowException(IDS_CLASSLOAD_BYREFLIKE_NOTVALUECLASSFIELD);
4091 if (!bmtFP->fIsByRefLikeType)
4093 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTBYREFLIKE);
4097 if (!IsSelfRef(pByValueClass) && pByValueClass->GetClass()->HasNonPublicFields())
4098 { // If a class has a field of type ValueType with non-public fields in it,
4099 // the class must "inherit" this characteristic
4100 SetHasNonPublicFields();
4107 // Inherit instance attributes
4108 EEClass * pFieldClass = pByValueClass->GetClass();
4110 #ifdef FEATURE_64BIT_ALIGNMENT
4111 // If a value type requires 8-byte alignment this requirement must be inherited by any
4112 // class/struct that embeds it as a field.
4113 if (pFieldClass->IsAlign8Candidate())
4114 fFieldRequiresAlign8 = true;
4116 if (pFieldClass->HasNonPublicFields())
4117 SetHasNonPublicFields();
4118 if (pFieldClass->HasFieldsWhichMustBeInited())
4119 SetHasFieldsWhichMustBeInited();
4121 #ifdef FEATURE_READYTORUN
4122 if (!(pByValueClass->IsTruePrimitive() || pByValueClass->IsEnum()))
4124 CheckLayoutDependsOnOtherModules(pByValueClass);
4129 { // Increment the number of static fields that contain object references.
4130 bmtEnumFields->dwNumStaticBoxedFields++;
4131 if (fIsThreadStatic)
4132 bmtEnumFields->dwNumThreadStaticBoxedFields++;
4136 if (*pByValueClassCache == NULL)
4138 DWORD dwNumFields = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields;
4140 *pByValueClassCache = new (GetStackingAllocator()) MethodTable * [dwNumFields];
4141 memset (*pByValueClassCache, 0, dwNumFields * sizeof(MethodTable **));
4144 // Thread static fields come after instance fields and regular static fields in this list
4145 if (fIsThreadStatic)
4147 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField] = pByValueClass;
4148 // make sure to record the correct size for static field
4150 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4152 // Regular static fields come after instance fields in this list
4155 (*pByValueClassCache)[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField] = pByValueClass;
4156 // make sure to record the correct size for static field
4158 dwLog2FieldSize = LOG2_PTRSIZE; // handle
4162 (*pByValueClassCache)[dwCurrentDeclaredField] = pByValueClass;
4163 dwLog2FieldSize = 0; // unused
4170 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4176 pFD = &pFieldDescList[dwCurrentDeclaredField];
4177 *totalDeclaredSize += (1 << dwLog2FieldSize);
4179 else /* (dwMemberAttrs & mdStatic) */
4181 if (fIsThreadStatic)
4183 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + dwCurrentThreadStaticField];
4187 pFD = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + dwCurrentStaticField];
4191 bmtMFDescs->ppFieldDescList[i] = pFD;
4193 const LayoutRawFieldInfo *pLayoutFieldInfo = NULL;
4197 const LayoutRawFieldInfo *pwalk = pLayoutRawFieldInfos;
4198 while (pwalk->m_MD != mdFieldDefNil)
4200 if (pwalk->m_MD == bmtMetaData->pFields[i])
4202 pLayoutFieldInfo = pwalk;
4204 const FieldMarshaler *pSrcFieldMarshaler = (const FieldMarshaler *) &pwalk->m_FieldMarshaler;
4206 pSrcFieldMarshaler->CopyTo(pNextFieldMarshaler, MAXFIELDMARSHALERSIZE);
4208 pNextFieldMarshaler->SetFieldDesc(pFD);
4209 pNextFieldMarshaler->SetExternalOffset(pwalk->m_offset);
4211 ((BYTE*&)pNextFieldMarshaler) += MAXFIELDMARSHALERSIZE;
4218 LPCSTR pszFieldName = NULL;
4220 if (FAILED(pInternalImport->GetNameOfFieldDef(bmtMetaData->pFields[i], &pszFieldName)))
4222 pszFieldName = "Invalid FieldDef record";
4225 // #InitCall Initialize contents of the field descriptor called from
4227 bmtMetaData->pFields[i],
4228 FieldDescElementType,
4237 // We're using FieldDesc::m_pMTOfEnclosingClass to temporarily store the field's size.
4242 (IsBlittable() || HasExplicitFieldOffsetLayout()))
4244 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4245 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4247 if (pLayoutFieldInfo)
4248 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
4250 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4252 else if (!fIsStatic && IsManagedSequential())
4254 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
4255 (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
4257 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
4261 // static value class fields hold a handle, which is ptr sized
4262 // (instance field layout ignores this value)
4263 (DWORD_PTR&)(pFD->m_pMTOfEnclosingClass) = LOG2_PTRSIZE;
4264 pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
4269 (DWORD_PTR &)(pFD->m_pMTOfEnclosingClass) = (size_t)dwLog2FieldSize;
4271 // -1 (FIELD_OFFSET_UNPLACED) means that this is a non-GC field that has not yet been placed
4272 // -2 (FIELD_OFFSET_UNPLACED_GC_PTR) means that this is a GC pointer field that has not yet been placed
4274 // If there is any kind of explicit layout information for this field, use it. If not, then
4275 // mark it as either GC or non-GC and as unplaced; it will get placed later on in an optimized way.
4277 if ((IsBlittable() || HasExplicitFieldOffsetLayout()) && !fIsStatic)
4278 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
4279 else if (IsManagedSequential() && !fIsStatic)
4280 IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
4281 else if (bCurrentFieldIsGCPointer)
4282 pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR);
4284 pFD->SetOffset(FIELD_OFFSET_UNPLACED);
4291 if (++bmtFP->NumInstanceFieldsOfSize[dwLog2FieldSize] == 1)
4292 bmtFP->FirstInstanceFieldOfSize[dwLog2FieldSize] = dwCurrentDeclaredField;
4295 dwCurrentDeclaredField++;
4297 if (bCurrentFieldIsGCPointer)
4299 bmtFP->NumInstanceGCPointerFields++;
4302 else /* static fields */
4304 // Static fields are stored in the vtable after the vtable and interface slots. We don't
4305 // know how large the vtable will be, so we will have to fixup the slot number by
4306 // <vtable + interface size> later.
4308 if (fIsThreadStatic)
4310 dwCurrentThreadStaticField++;
4314 dwCurrentStaticField++;
4319 if (FieldDescElementType == ELEMENT_TYPE_CLASS)
4320 { // RVA fields are not allowed to have GC pointers.
4321 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4322 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4324 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4326 if (IsSelfRef(pByValueClass))
4327 { // We will verify self-referencing statics after the loop through all fields - see code:#SelfReferencingStaticValueTypeField_Checks
4328 bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA = TRUE;
4332 if (pByValueClass->GetClass()->HasFieldsWhichMustBeInited())
4333 { // RVA fields are not allowed to have GC pointers.
4334 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA field");
4335 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4340 // Set the field offset
4342 IfFailThrow(pInternalImport->GetFieldRVA(pFD->GetMemberDef(), &rva));
4344 // Ensure that the IL image is loaded. Note that this assembly may
4345 // have an ngen image, but this type may have failed to load during ngen.
4346 GetModule()->GetFile()->LoadLibrary(FALSE);
4349 if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
4351 if (IsSelfRef(pByValueClass))
4353 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4355 // We do not known the size yet
4356 _ASSERTE(bmtFP->NumInstanceFieldBytes == 0);
4357 // We will check just the RVA with size 0 now, the full size verification will happen in code:VerifySelfReferencingStaticValueTypeFields_WithRVA
4362 fldSize = pByValueClass->GetNumInstanceFieldBytes();
4367 fldSize = GetSizeForCorElementType(FieldDescElementType);
4370 pFD->SetOffsetRVA(rva);
4372 else if (fIsThreadStatic)
4374 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
4376 if (bCurrentFieldIsGCPointer)
4377 bmtFP->NumThreadStaticGCPointerFields++;
4380 bmtFP->NumThreadStaticGCBoxedFields++;
4384 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
4386 if (bCurrentFieldIsGCPointer)
4387 bmtFP->NumRegularStaticGCPointerFields++;
4390 bmtFP->NumRegularStaticGCBoxedFields++;
4394 // We processed all fields
4396 //#SelfReferencingStaticValueTypeField_Checks
4397 if (bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA)
4398 { // The type has self-referencing static ValueType field with RVA, do more checks now that depend on all fields being processed
4400 // For enums we already checked its underlying type, we should not get here
4401 _ASSERTE(!IsEnum());
4403 if (HasFieldsWhichMustBeInited())
4404 { // RVA fields are not allowed to have GC pointers.
4405 BAD_FORMAT_NOTHROW_ASSERT(!"ObjectRef in an RVA self-referencing static field");
4406 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
4410 DWORD dwNumInstanceFields = dwCurrentDeclaredField + (HasParent() ? GetParentMethodTable()->GetNumInstanceFields() : 0);
4411 DWORD dwNumStaticFields = bmtEnumFields->dwNumStaticFields;
4412 DWORD dwNumThreadStaticFields = bmtEnumFields->dwNumThreadStaticFields;
4414 if (!FitsIn<WORD>(dwNumInstanceFields) ||
4415 !FitsIn<WORD>(dwNumStaticFields))
4416 { // An implementation limitation means that it's an error if there are greater that MAX_WORD fields.
4417 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
4420 GetHalfBakedClass()->SetNumInstanceFields((WORD)dwNumInstanceFields);
4421 GetHalfBakedClass()->SetNumStaticFields((WORD)dwNumStaticFields);
4422 GetHalfBakedClass()->SetNumThreadStaticFields((WORD)dwNumThreadStaticFields);
4424 if (bmtFP->fHasFixedAddressValueTypes)
4426 // To make things simpler, if the class has any field with this requirement, we'll set
4427 // all the statics to have this property. This allows us to only need to persist one bit
4428 // for the ngen case.
4429 GetHalfBakedClass()->SetHasFixedAddressVTStatics();
4432 #ifdef FEATURE_64BIT_ALIGNMENT
4433 // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8
4434 // bytes (this mimics what the native compiler does and ensures we match up calling conventions during
4436 if (HasLayout() && GetLayoutInfo()->GetPackingSize() < 8)
4438 fFieldRequiresAlign8 = false;
4441 if (fFieldRequiresAlign8)
4443 SetAlign8Candidate();
4445 #endif // FEATURE_64BIT_ALIGNMENT
4447 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
4448 if (ShouldAlign8(dwR8Fields, dwNumInstanceFields))
4450 SetAlign8Candidate();
4452 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
4455 //========================================================================
4457 // Go thru all fields and initialize their FieldDescs.
4458 //========================================================================
4461 } // MethodTableBuilder::InitializeFieldDescs
4464 #pragma warning(pop)
4467 //*******************************************************************************
4468 // Verify self-referencing static ValueType fields with RVA (when the size of the ValueType is known).
4470 MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA(
4471 MethodTable ** pByValueClassCache)
4473 STANDARD_VM_CONTRACT;
4475 _ASSERTE(bmtFP->fHasSelfReferencingStaticValueTypeField_WithRVA);
4476 // Enum's static self-referencing fields have been verified as the underlying type of the enum, we should not get here for them
4477 _ASSERTE(!IsEnum());
4478 // The size of the ValueType should be known at this point (the caller throws if it is 0)
4479 _ASSERTE(bmtFP->NumInstanceFieldBytes != 0);
4481 FieldDesc * pFieldDescList = GetApproxFieldDescListRaw();
4482 DWORD nFirstThreadStaticFieldIndex = bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields;
4483 for (DWORD i = bmtEnumFields->dwNumInstanceFields; i < nFirstThreadStaticFieldIndex; i++)
4485 FieldDesc * pFD = &pFieldDescList[i];
4486 _ASSERTE(pFD->IsStatic());
4488 if (pFD->IsRVA() && pFD->IsByValue())
4490 _ASSERTE(pByValueClassCache[i] != NULL);
4492 if (IsSelfRef(pByValueClassCache[i]))
4495 IfFailThrow(GetMDImport()->GetFieldRVA(pFD->GetMemberDef(), &rva));
4499 } // MethodTableBuilder::VerifySelfReferencingStaticValueTypeFields_WithRVA
4501 //*******************************************************************************
4502 // Returns true if hEnclosingTypeCandidate encloses, at any arbitrary depth,
4503 // hNestedTypeCandidate; returns false otherwise.
4505 bool MethodTableBuilder::IsEnclosingNestedTypePair(
4506 bmtTypeHandle hEnclosingTypeCandidate,
4507 bmtTypeHandle hNestedTypeCandidate)
4509 STANDARD_VM_CONTRACT;
4511 CONSISTENCY_CHECK(!hEnclosingTypeCandidate.IsNull());
4512 CONSISTENCY_CHECK(!hNestedTypeCandidate.IsNull());
4513 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hEnclosingTypeCandidate, hNestedTypeCandidate));
4515 Module * pModule = hEnclosingTypeCandidate.GetModule();
4517 if (pModule != hNestedTypeCandidate.GetModule())
4518 { // If the modules aren't the same, then there's no way
4519 // hBase could be an enclosing type of hChild. We make
4520 // this check early so that the code can deal with only
4521 // one Module and IMDInternalImport instance and can avoid
4526 IMDInternalImport * pMDImport = pModule->GetMDImport();
4528 mdTypeDef tkEncl = hEnclosingTypeCandidate.GetTypeDefToken();
4529 mdTypeDef tkNest = hNestedTypeCandidate.GetTypeDefToken();
4531 while (tkEncl != tkNest)
4532 { // Do this using the metadata APIs because MethodTableBuilder does
4533 // not construct type representations for enclosing type chains.
4534 if (FAILED(pMDImport->GetNestedClassProps(tkNest, &tkNest)))
4535 { // tokNest is not a nested type.
4540 // tkNest's enclosing type is tkEncl, so we've shown that
4541 // hEnclosingTypeCandidate encloses hNestedTypeCandidate
4545 //*******************************************************************************
4546 // Given an arbitrary nesting+subclassing pattern like this:
4549 // private virtual void Foo() { ... }
4552 // class CN : CN-1 {
4553 // private override void Foo() { ... }
4559 // this method will return true, where hChild == N and hBase == C1
4561 // Note that there is no requirement that a type derive from its immediately
4562 // enclosing type, but can skip a level, such as this example:
4566 // private virtual void Foo() { }
4569 // public class C : A
4571 // private override void Foo() { }
4576 // NOTE: IMPORTANT: This code assumes that hBase is indeed a base type of hChild,
4577 // and behaviour is undefined if this is not the case.
4579 bool MethodTableBuilder::IsBaseTypeAlsoEnclosingType(
4580 bmtTypeHandle hBase,
4581 bmtTypeHandle hChild)
4583 STANDARD_VM_CONTRACT;
4585 CONSISTENCY_CHECK(!hBase.IsNull());
4586 CONSISTENCY_CHECK(!hChild.IsNull());
4587 CONSISTENCY_CHECK(!bmtTypeHandle::Equal(hBase, hChild));
4589 // The idea of this algorithm is that if we climb the inheritance chain
4590 // starting at hChild then we'll eventually hit hBase. If we check that
4591 // for every (hParent, hChild) pair in the chain that hParent encloses
4592 // hChild, then we've shown that hBase encloses hChild.
4594 while (!bmtTypeHandle::Equal(hBase, hChild))
4596 CONSISTENCY_CHECK(!hChild.GetParentType().IsNull());
4597 bmtTypeHandle hParent(hChild.GetParentType());
4599 if (!IsEnclosingNestedTypePair(hParent, hChild))
4600 { // First, the parent type must enclose the child type.
4601 // If this is not the case we fail immediately.
4605 // Move up one in the inheritance chain, and try again.
4609 // If the loop worked itself from the original hChild all the way
4610 // up to hBase, then we know that for every (hParent, hChild)
4611 // pair in the chain that hParent enclosed hChild, and so we know
4612 // that hBase encloses the original hChild
4616 //*******************************************************************************
4617 BOOL MethodTableBuilder::TestOverrideForAccessibility(
4618 bmtMethodHandle hParentMethod,
4619 bmtTypeHandle hChildType)
4621 STANDARD_VM_CONTRACT;
4623 bmtTypeHandle hParentType(hParentMethod.GetOwningType());
4625 Module * pParentModule = hParentType.GetModule();
4626 Module * pChildModule = hChildType.GetModule();
4628 Assembly * pParentAssembly = pParentModule->GetAssembly();
4629 Assembly * pChildAssembly = pChildModule->GetAssembly();
4631 BOOL isSameAssembly = (pChildAssembly == pParentAssembly);
4633 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4635 // AKA "strict bit". This means that overridability is tightly bound to accessibility.
4636 if (IsMdCheckAccessOnOverride(dwParentAttrs))
4639 if (isSameAssembly || pParentAssembly->GrantsFriendAccessTo(pChildAssembly, hParentMethod.GetMethodDesc())
4640 || pChildAssembly->IgnoresAccessChecksTo(pParentAssembly))
4642 // Can always override any method that has accessibility greater than mdPrivate
4643 if ((dwParentAttrs & mdMemberAccessMask) > mdPrivate)
4646 // Generally, types cannot override inherited mdPrivate methods, except:
4647 // Types can access enclosing type's private members, so it can
4648 // override them if the nested type extends its enclosing type.
4649 else if ((dwParentAttrs & mdMemberAccessMask) == mdPrivate &&
4650 IsBaseTypeAlsoEnclosingType(hParentType, hChildType))
4661 // If the method marks itself as check visibility the the method must be
4662 // public, FamORAssem, or family
4663 if((dwParentAttrs & mdMemberAccessMask) <= mdAssem)
4672 //*******************************************************************************
4673 VOID MethodTableBuilder::TestOverRide(bmtMethodHandle hParentMethod,
4674 bmtMethodHandle hChildMethod)
4678 PRECONDITION(IsMdVirtual(hParentMethod.GetDeclAttrs()));
4679 PRECONDITION(IsMdVirtual(hChildMethod.GetDeclAttrs()));
4682 DWORD dwAttrs = hChildMethod.GetDeclAttrs();
4683 DWORD dwParentAttrs = hParentMethod.GetDeclAttrs();
4685 Module *pModule = hChildMethod.GetOwningType().GetModule();
4686 Module *pParentModule = hParentMethod.GetOwningType().GetModule();
4688 Assembly *pAssembly = pModule->GetAssembly();
4689 Assembly *pParentAssembly = pParentModule->GetAssembly();
4691 BOOL isSameModule = (pModule == pParentModule);
4692 BOOL isSameAssembly = (pAssembly == pParentAssembly);
4694 if (!TestOverrideForAccessibility(hParentMethod, hChildMethod.GetOwningType()))
4696 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, hChildMethod.GetMethodSignature().GetToken());
4700 // Refer to Partition II, 9.3.3 for more information on what is permitted.
4703 enum WIDENING_STATUS
4707 e_SA, // YES, but only when same assembly
4708 e_NSA, // YES, but only when NOT same assembly
4709 e_SM, // YES, but only when same module
4712 static_assert_no_msg(mdPrivateScope == 0x00);
4713 static_assert_no_msg(mdPrivate == 0x01);
4714 static_assert_no_msg(mdFamANDAssem == 0x02);
4715 static_assert_no_msg(mdAssem == 0x03);
4716 static_assert_no_msg(mdFamily == 0x04);
4717 static_assert_no_msg(mdFamORAssem == 0x05);
4718 static_assert_no_msg(mdPublic == 0x06);
4720 static const DWORD dwCount = mdPublic - mdPrivateScope + 1;
4721 static const WIDENING_STATUS rgWideningTable[dwCount][dwCount] =
4724 // Subtype | mdPrivateScope mdPrivate mdFamANDAssem mdAssem mdFamily mdFamORAssem mdPublic
4725 // --------------+-------------------------------------------------------------------------------------------------------
4726 /*mdPrivateScope | */ { { e_SM, e_NO, e_NO, e_NO, e_NO, e_NO, e_NO },
4727 /*mdPrivate | */ { e_SM, e_YES, e_NO, e_NO, e_NO, e_NO, e_NO },
4728 /*mdFamANDAssem | */ { e_SM, e_YES, e_SA, e_NO, e_NO, e_NO, e_NO },
4729 /*mdAssem | */ { e_SM, e_YES, e_SA, e_SA, e_NO, e_NO, e_NO },
4730 /*mdFamily | */ { e_SM, e_YES, e_YES, e_NO, e_YES, e_NSA, e_NO },
4731 /*mdFamORAssem | */ { e_SM, e_YES, e_YES, e_SA, e_YES, e_YES, e_NO },
4732 /*mdPublic | */ { e_SM, e_YES, e_YES, e_YES, e_YES, e_YES, e_YES } };
4734 DWORD idxParent = (dwParentAttrs & mdMemberAccessMask) - mdPrivateScope;
4735 DWORD idxMember = (dwAttrs & mdMemberAccessMask) - mdPrivateScope;
4736 CONSISTENCY_CHECK(idxParent < dwCount);
4737 CONSISTENCY_CHECK(idxMember < dwCount);
4739 WIDENING_STATUS entry = rgWideningTable[idxMember][idxParent];
4741 if (entry == e_NO ||
4742 (entry == e_SA && !isSameAssembly && !pParentAssembly->GrantsFriendAccessTo(pAssembly, hParentMethod.GetMethodDesc())
4743 && !pAssembly->IgnoresAccessChecksTo(pParentAssembly)) ||
4744 (entry == e_NSA && isSameAssembly) ||
4745 (entry == e_SM && !isSameModule)
4748 BuildMethodTableThrowException(IDS_CLASSLOAD_REDUCEACCESS, hChildMethod.GetMethodSignature().GetToken());
4754 //*******************************************************************************
4755 VOID MethodTableBuilder::TestMethodImpl(
4756 bmtMethodHandle hDeclMethod,
4757 bmtMethodHandle hImplMethod)
4762 PRECONDITION(!hDeclMethod.IsNull());
4763 PRECONDITION(!hImplMethod.IsNull());
4767 Module * pDeclModule = hDeclMethod.GetOwningType().GetModule();
4768 Module * pImplModule = hImplMethod.GetOwningType().GetModule();
4770 mdTypeDef tokDecl = hDeclMethod.GetMethodSignature().GetToken();
4771 mdTypeDef tokImpl = hImplMethod.GetMethodSignature().GetToken();
4773 BOOL isSameModule = pDeclModule->Equals(pImplModule);
4775 IMDInternalImport *pIMDDecl = pDeclModule->GetMDImport();
4776 IMDInternalImport *pIMDImpl = pImplModule->GetMDImport();
4779 if (FAILED(pIMDDecl->GetMethodDefProps(tokDecl, &dwDeclAttrs)))
4781 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4784 if (FAILED(pIMDImpl->GetMethodDefProps(tokImpl, &dwImplAttrs)))
4786 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
4789 HRESULT hr = COR_E_TYPELOAD;
4791 if (!IsMdVirtual(dwDeclAttrs))
4793 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NONVIRTUAL_DECL);
4795 if (!IsMdVirtual(dwImplAttrs))
4797 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL);
4799 // Virtual methods cannot be static
4800 if (IsMdStatic(dwDeclAttrs))
4802 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4804 if (IsMdStatic(dwImplAttrs))
4806 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL);
4808 if (IsMdFinal(dwDeclAttrs))
4810 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL);
4813 // Interface method body that has methodimpl should always be final
4814 if (IsInterface() && !IsMdFinal(dwImplAttrs))
4816 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_IMPL);
4819 // Since MethodImpl's do not affect the visibility of the Decl method, there's
4820 // no need to check.
4822 // If Decl's parent is other than this class, Decl must not be private
4823 mdTypeDef tkImplParent = mdTypeDefNil;
4824 mdTypeDef tkDeclParent = mdTypeDefNil;
4826 if (FAILED(hr = pIMDDecl->GetParentToken(tokDecl, &tkDeclParent)))
4828 BuildMethodTableThrowException(hr, *bmtError);
4830 if (FAILED(hr = pIMDImpl->GetParentToken(tokImpl, &tkImplParent)))
4832 BuildMethodTableThrowException(hr, *bmtError);
4835 // Make sure that we test for accessibility restrictions only if the decl is
4836 // not within our own type, as we are allowed to methodImpl a private with the
4837 // strict bit set if it is in our own type.
4838 if (!isSameModule || tkDeclParent != tkImplParent)
4840 if (!TestOverrideForAccessibility(hDeclMethod, hImplMethod.GetOwningType()))
4842 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_ACCESS_FAILURE, tokImpl);
4845 // Decl's parent must not be tdSealed
4846 mdToken tkGrandParentDummyVar;
4847 DWORD dwDeclTypeAttrs;
4848 if (FAILED(hr = pIMDDecl->GetTypeDefProps(tkDeclParent, &dwDeclTypeAttrs, &tkGrandParentDummyVar)))
4850 BuildMethodTableThrowException(hr, *bmtError);
4852 if (IsTdSealed(dwDeclTypeAttrs))
4854 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_SEALED_DECL);
4862 //*******************************************************************************
4864 // Used by BuildMethodTable
4867 MethodTableBuilder::ValidateMethods()
4873 PRECONDITION(CheckPointer(this));
4874 PRECONDITION(CheckPointer(bmtInternal));
4875 PRECONDITION(CheckPointer(bmtMetaData));
4876 PRECONDITION(CheckPointer(bmtError));
4877 PRECONDITION(CheckPointer(bmtProp));
4878 PRECONDITION(CheckPointer(bmtInterface));
4879 PRECONDITION(CheckPointer(bmtParent));
4880 PRECONDITION(CheckPointer(bmtMFDescs));
4881 PRECONDITION(CheckPointer(bmtEnumFields));
4882 PRECONDITION(CheckPointer(bmtMethodImpl));
4883 PRECONDITION(CheckPointer(bmtVT));
4887 // Used to keep track of located default and type constructors.
4888 CONSISTENCY_CHECK(bmtVT->pCCtor == NULL);
4889 CONSISTENCY_CHECK(bmtVT->pDefaultCtor == NULL);
4891 // Fetch the hard-coded signatures for the type constructor and the
4892 // default constructor and create MethodSignature objects for both at
4893 // the method level so this does not happen for every specialname
4898 sig = MscorlibBinder::GetSignature(&gsig_SM_RetVoid);
4900 MethodSignature cctorSig(MscorlibBinder::GetModule(),
4901 COR_CCTOR_METHOD_NAME,
4902 sig.GetRawSig(), sig.GetRawSigLen());
4904 sig = MscorlibBinder::GetSignature(&gsig_IM_RetVoid);
4906 MethodSignature defaultCtorSig(MscorlibBinder::GetModule(),
4907 COR_CTOR_METHOD_NAME,
4908 sig.GetRawSig(), sig.GetRawSigLen());
4910 Module * pModule = GetModule();
4911 DeclaredMethodIterator it(*this);
4914 // The RVA is only valid/testable if it has not been overwritten
4915 // for something like edit-and-continue
4916 // Complete validation of non-zero RVAs is done later inside MethodDesc::GetILHeader.
4917 if ((it.RVA() == 0) && (pModule->GetDynamicIL(it.Token(), FALSE) == NULL))
4919 // for IL code that is implemented here must have a valid code RVA
4920 // this came up due to a linker bug where the ImplFlags/DescrOffset were
4921 // being set to null and we weren't coping with it
4922 if((IsMiIL(it.ImplFlags()) || IsMiOPTIL(it.ImplFlags())) &&
4923 !IsMdAbstract(it.Attrs()) &&
4924 !IsReallyMdPinvokeImpl(it.Attrs()) &&
4925 !IsMiInternalCall(it.ImplFlags()))
4927 BuildMethodTableThrowException(IDS_CLASSLOAD_MISSINGMETHODRVA, it.Token());
4931 if (IsMdRTSpecialName(it.Attrs()))
4933 if (IsMdVirtual(it.Attrs()))
4934 { // Virtual specialname methods are illegal
4935 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4938 // Constructors (.ctor) and class initialisers (.cctor) are special
4939 const MethodSignature &curSig(it->GetMethodSignature());
4941 if (IsMdStatic(it.Attrs()))
4942 { // The only rtSpecialName static method allowed is the .cctor
4943 if (!curSig.ExactlyEqual(cctorSig))
4945 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4948 // Remember it for later
4949 bmtVT->pCCtor = *it;
4953 if(!MethodSignature::NamesEqual(curSig, defaultCtorSig))
4954 { // The only rtSpecialName instance methods allowed are .ctors
4955 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4958 // .ctor must return void
4959 MetaSig methodMetaSig(curSig.GetSignature(),
4960 static_cast<DWORD>(curSig.GetSignatureLength()),
4964 if (methodMetaSig.GetReturnType() != ELEMENT_TYPE_VOID)
4965 { // All constructors must have a void return type
4966 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
4969 // See if this is a default constructor. If so, remember it for later.
4970 if (curSig.ExactlyEqual(defaultCtorSig))
4972 bmtVT->pDefaultCtor = *it;
4977 // Make sure that fcalls have a 0 rva. This is assumed by the prejit fixup logic
4978 if (it.MethodType() == METHOD_TYPE_FCALL && it.RVA() != 0)
4980 BuildMethodTableThrowException(BFA_ECALLS_MUST_HAVE_ZERO_RVA, it.Token());
4983 // check for proper use of the Managed and native flags
4984 if (IsMiManaged(it.ImplFlags()))
4986 if (IsMiIL(it.ImplFlags()) || IsMiRuntime(it.ImplFlags())) // IsMiOPTIL(it.ImplFlags()) no longer supported
4988 // No need to set code address, pre stub used automatically.
4992 if (IsMiNative(it.ImplFlags()))
4994 // For now simply disallow managed native code if you turn this on you have to at least
4995 // insure that we have SkipVerificationPermission or equivalent
4996 BuildMethodTableThrowException(BFA_MANAGED_NATIVE_NYI, it.Token());
5000 BuildMethodTableThrowException(BFA_BAD_IMPL_FLAGS, it.Token());
5006 if (IsMiNative(it.ImplFlags()) && IsGlobalClass())
5008 // global function unmanaged entrypoint via IJW thunk was handled
5013 BuildMethodTableThrowException(IDS_CLASSLOAD_BAD_UNMANAGED_RVA, it.Token());
5015 if (it.MethodType() != METHOD_TYPE_NDIRECT)
5017 BuildMethodTableThrowException(BFA_BAD_UNMANAGED_ENTRY_POINT);
5021 // Vararg methods are not allowed inside generic classes
5022 // and nor can they be generic methods.
5023 if (bmtGenerics->GetNumGenericArgs() > 0 || (it.MethodType() == METHOD_TYPE_INSTANTIATED) )
5025 DWORD cMemberSignature;
5026 PCCOR_SIGNATURE pMemberSignature = it.GetSig(&cMemberSignature);
5027 // We've been trying to avoid asking for the signature - now we need it
5028 if (pMemberSignature == NULL)
5030 pMemberSignature = it.GetSig(&cMemberSignature);
5033 if (MetaSig::IsVarArg(pModule, Signature(pMemberSignature, cMemberSignature)))
5035 BuildMethodTableThrowException(BFA_GENCODE_NOT_BE_VARARG);
5039 if (IsMdVirtual(it.Attrs()) && IsMdPublic(it.Attrs()) && it.Name() == NULL)
5041 BuildMethodTableThrowException(IDS_CLASSLOAD_NOMETHOD_NAME);
5044 if (it.IsMethodImpl())
5046 if (!IsMdVirtual(it.Attrs()))
5047 { // Non-virtual methods cannot participate in a methodImpl pair.
5048 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5052 // Virtual static methods are not allowed.
5053 if (IsMdStatic(it.Attrs()) && IsMdVirtual(it.Attrs()))
5055 BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL, it.Token());
5060 //*******************************************************************************
5061 // Essentially, this is a helper method that combines calls to InitMethodDesc and
5062 // SetSecurityFlagsOnMethod. It then assigns the newly initialized MethodDesc to
5065 MethodTableBuilder::InitNewMethodDesc(
5066 bmtMDMethod * pMethod,
5067 MethodDesc * pNewMD)
5069 STANDARD_VM_CONTRACT;
5072 // First, set all flags that control layout of optional slots
5074 pNewMD->SetClassification(GetMethodClassification(pMethod->GetMethodType()));
5076 if (pMethod->GetMethodImplType() == METHOD_IMPL)
5077 pNewMD->SetHasMethodImplSlot();
5079 if (pMethod->GetSlotIndex() >= bmtVT->cVtableSlots)
5080 pNewMD->SetHasNonVtableSlot();
5082 if (NeedsNativeCodeSlot(pMethod))
5083 pNewMD->SetHasNativeCodeSlot();
5085 // Now we know the classification we can allocate the correct type of
5086 // method desc and perform any classification specific initialization.
5088 LPCSTR pName = pMethod->GetMethodSignature().GetName();
5091 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pName)))
5093 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5098 LPCUTF8 pszDebugMethodName;
5099 if (FAILED(GetMDImport()->GetNameOfMethodDef(pMethod->GetMethodSignature().GetToken(), &pszDebugMethodName)))
5101 pszDebugMethodName = "Invalid MethodDef record";
5103 S_SIZE_T safeLen = S_SIZE_T(strlen(pszDebugMethodName)) + S_SIZE_T(1);
5104 if(safeLen.IsOverflow())
5105 COMPlusThrowHR(COR_E_OVERFLOW);
5107 size_t len = safeLen.Value();
5108 LPCUTF8 pszDebugMethodNameCopy = (char*) AllocateFromLowFrequencyHeap(safeLen);
5109 strcpy_s((char *) pszDebugMethodNameCopy, len, pszDebugMethodName);
5112 // Do the init specific to each classification of MethodDesc & assign some common fields
5113 InitMethodDesc(pNewMD,
5114 GetMethodClassification(pMethod->GetMethodType()),
5115 pMethod->GetMethodSignature().GetToken(),
5116 pMethod->GetImplAttrs(),
5117 pMethod->GetDeclAttrs(),
5122 COMMA_INDEBUG(pszDebugMethodNameCopy)
5123 COMMA_INDEBUG(GetDebugClassName())
5124 COMMA_INDEBUG("") // FIX this happens on global methods, give better info
5127 pMethod->SetMethodDesc(pNewMD);
5129 bmtRTMethod * pParentMethod = NULL;
5133 SLOT_INDEX idx = pMethod->GetSlotIndex();
5134 CONSISTENCY_CHECK(idx != INVALID_SLOT_INDEX);
5136 if (idx < GetParentMethodTable()->GetNumVirtuals())
5138 pParentMethod = (*bmtParent->pSlotTable)[idx].Decl().AsRTMethod();
5142 // Turn off inlining for any calls
5143 // that are marked in the metadata as not being inlineable.
5144 if(IsMiNoInlining(pMethod->GetImplAttrs()))
5146 pNewMD->SetNotInline(true);
5149 // Check for methods marked as [Intrinsic]
5150 if (GetModule()->IsSystem())
5152 HRESULT hr = GetMDImport()->GetCustomAttributeByName(pMethod->GetMethodSignature().GetToken(),
5153 g_CompilerServicesIntrinsicAttribute,
5157 if (hr == S_OK || bmtProp->fIsHardwareIntrinsic)
5159 pNewMD->SetIsJitIntrinsic();
5164 pNewMD->SetSlot(pMethod->GetSlotIndex());
5167 //*******************************************************************************
5168 // Determine vtable placement for each non-virtual in the class, while also
5169 // looking for default and type constructors.
5171 MethodTableBuilder::PlaceNonVirtualMethods()
5177 PRECONDITION(CheckPointer(this));
5178 PRECONDITION(CheckPointer(bmtInternal));
5179 PRECONDITION(CheckPointer(bmtMetaData));
5180 PRECONDITION(CheckPointer(bmtError));
5181 PRECONDITION(CheckPointer(bmtProp));
5182 PRECONDITION(CheckPointer(bmtInterface));
5183 PRECONDITION(CheckPointer(bmtParent));
5184 PRECONDITION(CheckPointer(bmtMFDescs));
5185 PRECONDITION(CheckPointer(bmtEnumFields));
5186 PRECONDITION(CheckPointer(bmtMethodImpl));
5187 PRECONDITION(CheckPointer(bmtVT));
5191 INDEBUG(bmtVT->SealVirtualSlotSection();)
5194 // For each non-virtual method, place the method in the next available non-virtual method slot.
5197 // Place the cctor and default ctor first. code::MethodTableGetCCtorSlot and code:MethodTable::GetDefaultCtorSlot
5199 if (bmtVT->pCCtor != NULL)
5201 if (!bmtVT->AddNonVirtualMethod(bmtVT->pCCtor))
5202 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5205 if (bmtVT->pDefaultCtor != NULL)
5207 if (!bmtVT->AddNonVirtualMethod(bmtVT->pDefaultCtor))
5208 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5211 // We use slot during remoting and to map methods between generic instantiations
5212 // (see MethodTable::GetParallelMethodDesc). The current implementation
5213 // of this mechanism requires real slots.
5214 BOOL fCanHaveNonVtableSlots = (bmtGenerics->GetNumGenericArgs() == 0) && !IsInterface();
5216 // Flag to avoid second pass when possible
5217 BOOL fHasNonVtableSlots = FALSE;
5220 // Place all methods that require real vtable slot first. This is necessary so
5221 // that they get consequitive slot numbers right after virtual slots.
5224 DeclaredMethodIterator it(*this);
5227 // Skip methods that are placed already
5228 if (it->GetSlotIndex() != INVALID_SLOT_INDEX)
5232 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5233 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5236 if (!fCanHaveNonVtableSlots ||
5237 it->GetMethodType() == METHOD_TYPE_INSTANTIATED ||
5238 MayBeRemotingIntercepted(*it))
5240 // We use slot during remoting and to map methods between generic instantiations
5241 // (see MethodTable::GetParallelMethodDesc). The current implementation
5242 // of this mechanism requires real slots.
5246 // This method does not need real vtable slot
5247 fHasNonVtableSlots = TRUE;
5251 // This will update slot index in bmtMDMethod
5252 if (!bmtVT->AddNonVirtualMethod(*it))
5253 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5256 // Remeber last real vtable slot
5257 bmtVT->cVtableSlots = bmtVT->cTotalSlots;
5259 // Are there any Non-vtable slots to place?
5260 if (!fHasNonVtableSlots)
5264 // Now, place the remaining methods. They will get non-vtable slot.
5267 DeclaredMethodIterator it2(*this);
5270 // Skip methods that are placed already
5271 if (it2->GetSlotIndex() != INVALID_SLOT_INDEX)
5274 if (!bmtVT->AddNonVirtualMethod(*it2))
5275 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5280 //*******************************************************************************
5281 // Determine vtable placement for each virtual member in this class.
5283 MethodTableBuilder::PlaceVirtualMethods()
5289 PRECONDITION(CheckPointer(this));
5290 PRECONDITION(CheckPointer(bmtInternal));
5291 PRECONDITION(CheckPointer(bmtMetaData));
5292 PRECONDITION(CheckPointer(bmtError));
5293 PRECONDITION(CheckPointer(bmtProp));
5294 PRECONDITION(CheckPointer(bmtInterface));
5295 PRECONDITION(CheckPointer(bmtParent));
5296 PRECONDITION(CheckPointer(bmtMFDescs));
5297 PRECONDITION(CheckPointer(bmtEnumFields));
5298 PRECONDITION(CheckPointer(bmtMethodImpl));
5299 PRECONDITION(CheckPointer(bmtVT));
5304 LPCUTF8 pszDebugName, pszDebugNamespace;
5305 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &pszDebugName, &pszDebugNamespace)))
5307 pszDebugName = pszDebugNamespace = "Invalid TypeDef record";
5312 // For each virtual method
5313 // - If the method is not declared as newslot, search all virtual methods in the parent
5314 // type for an override candidate.
5315 // - If such a candidate is found, test to see if the override is valid. If
5316 // the override is not valid, throw TypeLoadException
5317 // - If a candidate is found above, place the method in the inherited slot as both
5318 // the Decl and the Impl.
5319 // - Else, place the method in the next available empty vtable slot.
5322 DeclaredMethodIterator it(*this);
5325 if (!IsMdVirtual(it.Attrs()))
5326 { // Only processing declared virtual methods
5331 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(it.Name()))
5332 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", it.Name()));
5335 // If this member is a method which overrides a parent method, it will be set to non-NULL
5336 bmtRTMethod * pParentMethod = NULL;
5338 // Hash that a method with this name exists in this class
5339 // Note that ctors and static ctors are not added to the table
5340 BOOL fMethodConstraintsMatch = FALSE;
5342 // If the member is marked with a new slot we do not need to find it in the parent
5343 if (HasParent() && !IsMdNewSlot(it.Attrs()))
5345 // Attempt to find the method with this name and signature in the parent class.
5346 // This method may or may not create pParentMethodHash (if it does not already exist).
5347 // It also may or may not fill in pMemberSignature/cMemberSignature.
5348 // An error is only returned when we can not create the hash.
5349 // NOTE: This operation touches metadata
5350 pParentMethod = LoaderFindMethodInParentClass(
5351 it->GetMethodSignature(), bmtProp->fNoSanityChecks ? NULL : &fMethodConstraintsMatch);
5353 if (pParentMethod != NULL)
5354 { // Found an override candidate
5355 DWORD dwParentAttrs = pParentMethod->GetDeclAttrs();
5357 if (!IsMdVirtual(dwParentAttrs))
5358 { // Can't override a non-virtual methods
5359 BuildMethodTableThrowException(BFA_NONVIRT_NO_SEARCH, it.Token());
5362 if(IsMdFinal(dwParentAttrs))
5363 { // Can't override a final methods
5364 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL, it.Token());
5367 if(!bmtProp->fNoSanityChecks)
5369 TestOverRide(bmtMethodHandle(pParentMethod),
5370 bmtMethodHandle(*it));
5372 if (!fMethodConstraintsMatch)
5374 BuildMethodTableThrowException(
5375 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_OVERRIDE,
5385 CONSISTENCY_CHECK(pParentMethod == NULL);
5386 // Also sets new slot number on bmtRTMethod and MethodDesc
5387 if (!bmtVT->AddVirtualMethod(*it))
5388 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5390 else if (pParentMethod != NULL)
5392 bmtVT->SetVirtualMethodOverride(pParentMethod->GetSlotIndex(), *it);
5396 if (!bmtVT->AddVirtualMethod(*it))
5397 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
5402 // Given an interface map entry, and a name+signature, compute the method on the interface
5403 // that the name+signature corresponds to. Used by ProcessMethodImpls and ProcessInexactMethodImpls
5404 // Always returns the first match that it finds. Affects the ambiguities in code:#ProcessInexactMethodImpls_Ambiguities
5405 MethodTableBuilder::bmtMethodHandle
5406 MethodTableBuilder::FindDeclMethodOnInterfaceEntry(bmtInterfaceEntry *pItfEntry, MethodSignature &declSig)
5408 STANDARD_VM_CONTRACT;
5410 bmtMethodHandle declMethod;
5412 bmtInterfaceEntry::InterfaceSlotIterator slotIt =
5413 pItfEntry->IterateInterfaceSlots(GetStackingAllocator());
5414 // Check for exact match
5415 for (; !slotIt.AtEnd(); slotIt.Next())
5417 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5419 if (declSig.ExactlyEqual(pCurDeclMethod->GetMethodSignature()))
5421 declMethod = slotIt->Decl();
5425 slotIt.ResetToStart();
5427 // Check for equivalent match if exact match wasn't found
5428 if (declMethod.IsNull())
5430 for (; !slotIt.AtEnd(); slotIt.Next())
5432 bmtRTMethod * pCurDeclMethod = slotIt->Decl().AsRTMethod();
5434 // Type Equivalence is forbidden in MethodImpl MemberRefs
5435 if (declSig.Equivalent(pCurDeclMethod->GetMethodSignature()))
5437 declMethod = slotIt->Decl();
5446 //*******************************************************************************
5448 // Used by BuildMethodTable
5449 // Process the list of inexact method impls generated during ProcessMethodImpls.
5450 // This list is used to cause a methodImpl to an interface to override
5451 // methods on several equivalent interfaces in the interface map. This logic is necessary
5452 // so that in the presence of an embedded interface the behavior appears to mimic
5453 // the behavior if the interface was not embedded.
5455 // In particular, the logic here is to handle cases such as
5458 // [TypeIdentifier("x","y")]
5460 // { void Method(); }
5461 // interface IOther : I' {}
5464 // [TypeIdentifier("x","y")]
5466 // { void Method(); }
5467 // class Test : I, IOther
5473 // In this case, there is one method, and one methodimpl, but there are 2 interfaces on the class that both
5474 // require an implementation of their method. The correct semantic for type equivalence, is that any
5475 // methodimpl directly targeting a method on an interface must be respected, and if it also applies to a type
5476 // equivalent interface method, then if that method was not methodimpl'd directly, then the methodimpl should apply
5477 // there as well. The ProcessInexactMethodImpls function does this secondary MethodImpl mapping.
5479 //#ProcessInexactMethodImpls_Ambiguities
5480 // In the presence of ambiguities, such as there are 3 equivalent interfaces implemented on a class and 2 methodimpls,
5481 // we will apply the 2 method impls exactly to appropriate interface methods, and arbitrarily pick one to apply to the
5482 // other interface. This is clearly ambiguous, but tricky to detect in the type loader efficiently, and should hopefully
5483 // not cause too many problems.
5486 MethodTableBuilder::ProcessInexactMethodImpls()
5488 STANDARD_VM_CONTRACT;
5490 if (bmtMethod->dwNumberInexactMethodImplCandidates == 0)
5493 DeclaredMethodIterator it(*this);
5496 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5497 // error before reaching this point.
5498 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5500 if (!IsMdVirtual(it.Attrs()))
5501 { // Only virtual methods can participate in methodImpls
5505 if(!it.IsMethodImpl())
5507 // Skip methods which are not the bodies of MethodImpl specifications
5511 // If this method serves as the BODY of a MethodImpl specification, then
5512 // we should iterate all the MethodImpl's for this class and see just how many
5513 // of them this method participates in as the BODY.
5514 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5516 // Inexact matching logic only works on MethodImpls that have been opted into inexactness by ProcessMethodImpls.
5517 if (!bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing)
5522 // If the methodimpl we are working with does not match this method, continue to next methodimpl
5523 if(it.Token() != bmtMetaData->rgMethodImplTokens[m].methodBody)
5528 bool fMatchFound = false;
5530 LPCUTF8 szName = NULL;
5531 PCCOR_SIGNATURE pSig = NULL;
5534 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5536 if (TypeFromToken(mdDecl) == mdtMethodDef)
5537 { // Different methods are aused to access MethodDef and MemberRef
5538 // names and signatures.
5539 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5540 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5542 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5547 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5549 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5553 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5554 MethodSignature declSig(GetModule(), szName, pSig, cbSig, pDeclSubst);
5555 bmtInterfaceEntry * pItfEntry = NULL;
5557 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5559 if (bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet() != bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet)
5562 bmtMethodHandle declMethod;
5563 pItfEntry = &bmtInterface->pInterfaceMap[i];
5565 // Search for declmethod on this interface
5566 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5568 // If we didn't find a match, continue on to next interface in the equivalence set
5569 if (declMethod.IsNull())
5572 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5573 { // Make sure the decl is virtual
5574 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5579 bool fPreexistingImplFound = false;
5581 // Check to ensure there isn't already a matching declMethod in the method impl list
5582 for (DWORD iMethodImpl = 0; iMethodImpl < bmtMethodImpl->pIndex; iMethodImpl++)
5584 if (bmtMethodImpl->GetDeclarationMethod(iMethodImpl) == declMethod)
5586 fPreexistingImplFound = true;
5591 // Search for other matches
5592 if (fPreexistingImplFound)
5595 // Otherwise, record the method impl discovery if the match is
5596 bmtMethodImpl->AddMethodImpl(*it, declMethod, GetStackingAllocator());
5599 if (!fMatchFound && bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing)
5601 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5607 //*******************************************************************************
5609 // Used by BuildMethodTable
5612 MethodTableBuilder::ProcessMethodImpls()
5614 STANDARD_VM_CONTRACT;
5616 if (bmtMethod->dwNumberMethodImpls == 0)
5621 DeclaredMethodIterator it(*this);
5624 // Non-virtual methods cannot be classified as methodImpl - we should have thrown an
5625 // error before reaching this point.
5626 CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));
5628 if (!IsMdVirtual(it.Attrs()))
5629 { // Only virtual methods can participate in methodImpls
5633 // If this method serves as the BODY of a MethodImpl specification, then
5634 // we should iterate all the MethodImpl's for this class and see just how many
5635 // of them this method participates in as the BODY.
5636 if(it.IsMethodImpl())
5638 for(DWORD m = 0; m < bmtMethod->dwNumberMethodImpls; m++)
5640 if(it.Token() == bmtMetaData->rgMethodImplTokens[m].methodBody)
5642 mdToken mdDecl = bmtMetaData->rgMethodImplTokens[m].methodDecl;
5643 bmtMethodHandle declMethod;
5645 // Get the parent token for the decl method token
5646 mdToken tkParent = mdTypeDefNil;
5647 if (TypeFromToken(mdDecl) == mdtMethodDef || TypeFromToken(mdDecl) == mdtMemberRef)
5649 if (FAILED(hr = GetMDImport()->GetParentToken(mdDecl,&tkParent)))
5651 BuildMethodTableThrowException(hr, *bmtError);
5655 if (GetCl() == tkParent)
5656 { // The DECL has been declared within the class that we're currently building.
5659 if(bmtError->pThrowable != NULL)
5661 *(bmtError->pThrowable) = NULL;
5664 if(TypeFromToken(mdDecl) != mdtMethodDef)
5666 if (FAILED(hr = FindMethodDeclarationForMethodImpl(
5667 mdDecl, &mdDecl, TRUE)))
5669 BuildMethodTableThrowException(hr, *bmtError);
5673 CONSISTENCY_CHECK(TypeFromToken(mdDecl) == mdtMethodDef);
5674 declMethod = bmtMethod->FindDeclaredMethodByToken(mdDecl);
5677 { // We can't call GetDescFromMemberDefOrRef here because this
5678 // method depends on a fully-loaded type, including parent types,
5679 // which is not always guaranteed. In particular, it requires that
5680 // the instantiation dictionary be filled. The solution is the following:
5681 // 1. Load the approximate type that the method belongs to.
5682 // 2. Get or create the correct substitution for the type involved
5683 // 3. Iterate the introduced methods on that type looking for a matching
5686 LPCUTF8 szName = NULL;
5687 PCCOR_SIGNATURE pSig = NULL;
5689 if (TypeFromToken(mdDecl) == mdtMethodDef)
5690 { // Different methods are aused to access MethodDef and MemberRef
5691 // names and signatures.
5692 if (FAILED(GetMDImport()->GetNameOfMethodDef(mdDecl, &szName)) ||
5693 FAILED(GetMDImport()->GetSigOfMethodDef(mdDecl, &cbSig, &pSig)))
5695 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5700 if (FAILED(GetMDImport()->GetNameAndSigOfMemberRef(mdDecl, &pSig, &cbSig, &szName)))
5702 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
5706 Substitution *pDeclSubst = &bmtMetaData->pMethodDeclSubsts[m];
5707 MethodTable * pDeclMT = NULL;
5708 MethodSignature declSig(GetModule(), szName, pSig, cbSig, pDeclSubst);
5710 { // 1. Load the approximate type.
5711 // Block for the LoadsTypeViolation.
5712 CONTRACT_VIOLATION(LoadsTypeViolation);
5713 pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
5716 &bmtGenerics->typeContext,
5717 ClassLoader::ThrowIfNotFound,
5718 ClassLoader::PermitUninstDefOrRef,
5719 ClassLoader::LoadTypes,
5720 CLASS_LOAD_APPROXPARENTS,
5721 TRUE).GetMethodTable()->GetCanonicalMethodTable();
5724 { // 2. Get or create the correct substitution
5725 bmtRTType * pDeclType = NULL;
5727 if (pDeclMT->IsInterface())
5728 { // If the declaration method is a part of an interface, search through
5729 // the interface map to find the matching interface so we can provide
5730 // the correct substitution chain.
5733 bmtInterfaceEntry * pItfEntry = NULL;
5734 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5736 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5737 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
5738 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5739 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5740 pCurItf->GetMethodTable(), pDeclMT,
5741 &pCurItf->GetSubstitution(), pDeclSubst,
5744 pItfEntry = &bmtInterface->pInterfaceMap[i];
5745 pDeclType = pCurItf;
5752 if (pDeclType == NULL)
5754 // Interface is not implemented by this type.
5755 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5760 if (pDeclType == NULL)
5762 DWORD equivalenceSet = 0;
5764 for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
5766 bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
5767 // Type Equivalence is respected for this comparision as we just need to find an
5768 // equivalent interface, the particular interface is unimportant
5769 if (MetaSig::CompareTypeDefsUnderSubstitutions(
5770 pCurItf->GetMethodTable(), pDeclMT,
5771 &pCurItf->GetSubstitution(), pDeclSubst,
5774 equivalenceSet = bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet();
5775 pItfEntry = &bmtInterface->pInterfaceMap[i];
5780 if (equivalenceSet == 0)
5782 // Interface is not implemented by this type.
5783 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
5786 // Interface is not implemented by this type exactly. We need to consider this MethodImpl on non exact interface matches,
5787 // as the only match may be one of the non-exact matches
5788 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5789 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = true;
5790 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = equivalenceSet;
5791 bmtMethod->dwNumberInexactMethodImplCandidates++;
5792 continue; // Move on to other MethodImpls
5796 // This method impl may need to match other methods during inexact processing
5797 if (pItfEntry->InEquivalenceSetWithMultipleEntries())
5799 bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
5800 bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
5801 bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = pItfEntry->GetInterfaceEquivalenceSet();
5802 bmtMethod->dwNumberInexactMethodImplCandidates++;
5807 // 3. Find the matching method.
5808 declMethod = FindDeclMethodOnInterfaceEntry(pItfEntry, declSig);
5811 { // Assume the MethodTable is a parent of the current type,
5812 // and create the substitution chain to match it.
5816 for (bmtRTType *pCur = GetParentType();
5818 pCur = pCur->GetParentType())
5820 if (pCur->GetMethodTable() == pDeclMT)
5827 if (pDeclType == NULL)
5828 { // Method's type is not a parent.
5829 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5832 // 3. Find the matching method.
5833 bmtRTType *pCurDeclType = pDeclType;
5836 // two pass algorithm. search for exact matches followed
5837 // by equivalent matches.
5838 for (int iPass = 0; (iPass < 2) && (declMethod.IsNull()); iPass++)
5840 MethodTable *pCurDeclMT = pCurDeclType->GetMethodTable();
5842 MethodTable::IntroducedMethodIterator methIt(pCurDeclMT);
5843 for(; methIt.IsValid(); methIt.Next())
5845 MethodDesc * pCurMD = methIt.GetMethodDesc();
5847 if (pCurDeclMT != pDeclMT)
5849 // If the method isn't on the declaring type, then it must be virtual.
5850 if (!pCurMD->IsVirtual())
5853 if (strcmp(szName, pCurMD->GetName()) == 0)
5855 PCCOR_SIGNATURE pCurMDSig;
5857 pCurMD->GetSig(&pCurMDSig, &cbCurMDSig);
5859 // First pass searches for declaration methods should not use type equivalence
5860 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
5862 if (MetaSig::CompareMethodSigs(
5863 declSig.GetSignature(),
5864 static_cast<DWORD>(declSig.GetSignatureLength()),
5865 declSig.GetModule(),
5866 &declSig.GetSubstitution(),
5869 pCurMD->GetModule(),
5870 &pCurDeclType->GetSubstitution(),
5871 iPass == 0 ? &newVisited : NULL))
5873 declMethod = (*bmtParent->pSlotTable)[pCurMD->GetSlot()].Decl();
5880 pCurDeclType = pCurDeclType->GetParentType();
5881 } while ((pCurDeclType != NULL) && (declMethod.IsNull()));
5884 if (declMethod.IsNull())
5885 { // Would prefer to let this fall out to the BuildMethodTableThrowException
5886 // below, but due to v2.0 and earlier behaviour throwing a MissingMethodException,
5887 // primarily because this code used to be a simple call to
5888 // MemberLoader::GetDescFromMemberDefOrRef (see above for reason why),
5889 // we must continue to do the same.
5890 MemberLoader::ThrowMissingMethodException(
5893 declSig.GetModule(),
5894 declSig.GetSignature(),
5895 static_cast<DWORD>(declSig.GetSignatureLength()),
5896 &bmtGenerics->typeContext);
5901 if (declMethod.IsNull())
5902 { // Method not found, throw.
5903 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
5906 if (!IsMdVirtual(declMethod.GetDeclAttrs()))
5907 { // Make sure the decl is virtual
5908 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
5911 bmtMethodImpl->AddMethodImpl(*it, declMethod, GetStackingAllocator());
5915 } /* end ... for each member */
5918 //*******************************************************************************
5919 // InitMethodDesc takes a pointer to space that's already allocated for the
5920 // particular type of MethodDesc, and initializes based on the other info.
5921 // This factors logic between PlaceMembers (the regular code path) & AddMethod
5922 // (Edit & Continue (EnC) code path) so we don't have to maintain separate copies.
5924 MethodTableBuilder::InitMethodDesc(
5925 MethodDesc * pNewMD, // This is should actually be of the correct sub-type, based on Classification
5926 DWORD Classification,
5929 DWORD dwMemberAttrs,
5931 DWORD RVA, // Only needed for NDirect case
5932 IMDInternalImport * pIMDII, // Needed for NDirect, EEImpl(Delegate) cases
5933 LPCSTR pMethodName // Only needed for mcEEImpl (Delegate) case
5934 COMMA_INDEBUG(LPCUTF8 pszDebugMethodName)
5935 COMMA_INDEBUG(LPCUTF8 pszDebugClassName)
5936 COMMA_INDEBUG(LPCUTF8 pszDebugMethodSignature)
5942 if (fEnC) { GC_NOTRIGGER; } else { GC_TRIGGERS; }
5947 LOG((LF_CORDB, LL_EVERYTHING, "EEC::IMD: pNewMD:0x%x for tok:0x%x (%s::%s)\n",
5948 pNewMD, tok, pszDebugClassName, pszDebugMethodName));
5950 // Now we know the classification we can perform any classification specific initialization.
5952 // The method desc is zero inited by the caller.
5954 switch (Classification)
5958 // NDirect specific initialization.
5959 NDirectMethodDesc *pNewNMD = (NDirectMethodDesc*)pNewMD;
5961 // Allocate writeable data
5962 pNewNMD->ndirect.m_pWriteableData.SetValue((NDirectWriteableData*)
5963 AllocateFromHighFrequencyHeap(S_SIZE_T(sizeof(NDirectWriteableData))));
5965 #ifdef HAS_NDIRECT_IMPORT_PRECODE
5966 pNewNMD->ndirect.m_pImportThunkGlue.SetValue(Precode::Allocate(PRECODE_NDIRECT_IMPORT, pNewMD,
5967 GetLoaderAllocator(), GetMemTracker())->AsNDirectImportPrecode());
5968 #else // !HAS_NDIRECT_IMPORT_PRECODE
5969 pNewNMD->GetNDirectImportThunkGlue()->Init(pNewNMD);
5970 #endif // !HAS_NDIRECT_IMPORT_PRECODE
5972 #if defined(_TARGET_X86_)
5973 pNewNMD->ndirect.m_cbStackArgumentSize = 0xFFFF;
5974 #endif // defined(_TARGET_X86_)
5977 pNewNMD->GetWriteableData()->m_pNDirectTarget = pNewNMD->GetNDirectImportThunkGlue()->GetEntrypoint();
5985 // For the Invoke method we will set a standard invoke method.
5986 BAD_FORMAT_NOTHROW_ASSERT(IsDelegate());
5988 // For the asserts, either the pointer is NULL (since the class hasn't
5989 // been constructed yet), or we're in EnC mode, meaning that the class
5990 // does exist, but we may be re-assigning the field to point to an
5991 // updated MethodDesc
5993 // It is not allowed for EnC to replace one of the runtime builtin methods
5995 if (strcmp(pMethodName, "Invoke") == 0)
5997 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod.IsNull());
5998 ((DelegateEEClass*)GetHalfBakedClass())->m_pInvokeMethod.SetValue(pNewMD);
6000 else if (strcmp(pMethodName, "BeginInvoke") == 0)
6002 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod.IsNull());
6003 ((DelegateEEClass*)GetHalfBakedClass())->m_pBeginInvokeMethod.SetValue(pNewMD);
6005 else if (strcmp(pMethodName, "EndInvoke") == 0)
6007 BAD_FORMAT_NOTHROW_ASSERT(((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod.IsNull());
6008 ((DelegateEEClass*)GetHalfBakedClass())->m_pEndInvokeMethod.SetValue(pNewMD);
6012 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
6015 // StoredSig specific intialization
6017 StoredSigMethodDesc *pNewSMD = (StoredSigMethodDesc*) pNewMD;;
6019 PCCOR_SIGNATURE pSig;
6020 if (FAILED(pIMDII->GetSigOfMethodDef(tok, &cSig, &pSig)))
6022 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
6024 pNewSMD->SetStoredMethodSig(pSig, cSig);
6028 #ifdef FEATURE_COMINTEROP
6030 #endif // FEATURE_COMINTEROP
6034 case mcInstantiated:
6035 #ifdef EnC_SUPPORTED
6038 // We reuse the instantiated methoddescs to get the slot
6039 InstantiatedMethodDesc* pNewIMD = (InstantiatedMethodDesc*) pNewMD;
6040 pNewIMD->SetupEnCAddedMethod();
6043 #endif // EnC_SUPPORTED
6045 // Initialize the typical instantiation.
6046 InstantiatedMethodDesc* pNewIMD = (InstantiatedMethodDesc*) pNewMD;
6047 //data has the same lifetime as method table, use our allocator
6048 pNewIMD->SetupGenericMethodDefinition(pIMDII, GetLoaderAllocator(), GetMemTracker(), GetModule(),
6054 BAD_FORMAT_NOTHROW_ASSERT(!"Failed to set a method desc classification");
6057 // Check the method desc's classification.
6058 _ASSERTE(pNewMD->GetClassification() == Classification);
6060 pNewMD->SetMemberDef(tok);
6062 if (IsMdStatic(dwMemberAttrs))
6063 pNewMD->SetStatic();
6065 // Set suppress unmanaged code access permission attribute
6067 if (pNewMD->IsNDirect())
6068 pNewMD->ComputeSuppressUnmanagedCodeAccessAttr(pIMDII);
6071 // Mark as many methods as synchronized as possible.
6073 // Note that this can easily cause programs to deadlock, and that
6074 // should not be treated as a bug in the program.
6076 static ConfigDWORD stressSynchronized;
6077 DWORD stressSynchronizedVal = stressSynchronized.val(CLRConfig::INTERNAL_stressSynchronized);
6079 bool isStressSynchronized = stressSynchronizedVal &&
6080 pNewMD->IsIL() && // Synchronized is not supported on Ecalls, NDirect method, etc
6081 // IsValueClass() and IsEnum() do not work for System.ValueType and System.Enum themselves
6082 ((g_pValueTypeClass != NULL && g_pEnumClass != NULL &&
6083 !IsValueClass()) || // Can not synchronize on byref "this"
6084 IsMdStatic(dwMemberAttrs)) && // IsStatic() blows up in _DEBUG as pNewMD is not fully inited
6085 g_pObjectClass != NULL; // Ignore Object:* since "this" could be a boxed object
6087 // stressSynchronized=1 turns off the stress in the system domain to reduce
6088 // the chances of spurious deadlocks. Deadlocks in user code can still occur.
6089 // stressSynchronized=2 will probably cause more deadlocks, and is not recommended
6090 if (stressSynchronizedVal == 1 && GetAssembly()->IsSystem())
6091 isStressSynchronized = false;
6093 if (IsMiSynchronized(dwImplFlags) || isStressSynchronized)
6095 if (IsMiSynchronized(dwImplFlags))
6097 pNewMD->SetSynchronized();
6100 pNewMD->m_pszDebugMethodName = (LPUTF8)pszDebugMethodName;
6101 pNewMD->m_pszDebugClassName = (LPUTF8)pszDebugClassName;
6102 pNewMD->m_pDebugMethodTable.SetValue(GetHalfBakedMethodTable());
6104 if (pszDebugMethodSignature == NULL)
6105 pNewMD->m_pszDebugMethodSignature = FormatSig(pNewMD,pNewMD->GetLoaderAllocator()->GetLowFrequencyHeap(),GetMemTracker());
6107 pNewMD->m_pszDebugMethodSignature = pszDebugMethodSignature;
6109 } // MethodTableBuilder::InitMethodDesc
6111 //*******************************************************************************
6113 // Used by BuildMethodTable
6116 MethodTableBuilder::AddMethodImplDispatchMapping(
6117 DispatchMapTypeID typeID,
6118 SLOT_INDEX slotNumber,
6119 bmtMDMethod * pImplMethod)
6121 STANDARD_VM_CONTRACT;
6123 MethodDesc * pMDImpl = pImplMethod->GetMethodDesc();
6125 // Look for an existing entry in the map.
6126 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6127 if (bmtVT->pDispatchMapBuilder->Find(typeID, slotNumber, it))
6129 // Throw if this entry has already previously been MethodImpl'd.
6130 if (it.IsMethodImpl())
6132 // NOTE: This is where we check for duplicate overrides. This is the easiest place to check
6133 // because duplicate overrides could in fact have separate MemberRefs to the same
6134 // member and so just comparing tokens at the very start would not be enough.
6135 if (it.GetTargetMD() != pMDImpl)
6137 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, pMDImpl->GetMemberDef());
6140 // This is the first MethodImpl. That's ok.
6143 it.SetTarget(pMDImpl);
6144 it.SetIsMethodImpl();
6147 // A mapping for this interface method does not exist, so insert it.
6150 bmtVT->pDispatchMapBuilder->InsertMDMapping(
6157 // Save the entry into the vtable as well, if it isn't an interface methodImpl
6158 if (typeID == DispatchMapTypeID::ThisClassID())
6160 bmtVT->SetVirtualMethodImpl(slotNumber, pImplMethod);
6162 } // MethodTableBuilder::AddMethodImplDispatchMapping
6164 //*******************************************************************************
6166 MethodTableBuilder::MethodImplCompareSignatures(
6167 bmtMethodHandle hDecl,
6168 bmtMethodHandle hImpl,
6169 DWORD dwConstraintErrorCode)
6173 PRECONDITION(!hDecl.IsNull());
6174 PRECONDITION(!hImpl.IsNull());
6175 PRECONDITION(TypeFromToken(hDecl.GetMethodSignature().GetToken()) == mdtMethodDef);
6176 PRECONDITION(TypeFromToken(hImpl.GetMethodSignature().GetToken()) == mdtMethodDef);
6179 const MethodSignature &declSig(hDecl.GetMethodSignature());
6180 const MethodSignature &implSig(hImpl.GetMethodSignature());
6182 if (!MethodSignature::SignaturesEquivalent(declSig, implSig))
6184 LOG((LF_CLASSLOADER, LL_INFO1000, "BADSIG placing MethodImpl: %x\n", declSig.GetToken()));
6185 BuildMethodTableThrowException(COR_E_TYPELOAD, IDS_CLASSLOAD_MI_BADSIGNATURE, declSig.GetToken());
6188 //now compare the method constraints
6189 if (!MetaSig::CompareMethodConstraints(&implSig.GetSubstitution(), implSig.GetModule(), implSig.GetToken(),
6190 &declSig.GetSubstitution(), declSig.GetModule(), declSig.GetToken()))
6192 BuildMethodTableThrowException(dwConstraintErrorCode, implSig.GetToken());
6196 //*******************************************************************************
6197 // We should have collected all the method impls. Cycle through them creating the method impl
6198 // structure that holds the information about which slots are overridden.
6200 MethodTableBuilder::PlaceMethodImpls()
6202 STANDARD_VM_CONTRACT;
6204 if(bmtMethodImpl->pIndex == 0)
6209 // Allocate some temporary storage. The number of overrides for a single method impl
6210 // cannot be greater then the number of vtable slots for classes. But for interfaces
6211 // it might contain overrides for other interface methods.
6212 DWORD dwMaxSlotSize = IsInterface() ? bmtMethod->dwNumberMethodImpls : bmtVT->cVirtualSlots;
6214 DWORD * slots = new (&GetThread()->m_MarshalAlloc) DWORD[dwMaxSlotSize];
6215 RelativePointer<MethodDesc *> * replaced = new (&GetThread()->m_MarshalAlloc) RelativePointer<MethodDesc*>[dwMaxSlotSize];
6218 bmtMDMethod * pCurImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6220 DWORD slotIndex = 0;
6222 // The impls are sorted according to the method descs for the body of the method impl.
6223 // Loop through the impls until the next body is found. When a single body
6224 // has been done move the slots implemented and method descs replaced into the storage
6225 // found on the body method desc.
6227 { // collect information until we reach the next body
6229 // Get the declaration part of the method impl. It will either be a token
6230 // (declaration is on this type) or a method desc.
6231 bmtMethodHandle hDeclMethod = bmtMethodImpl->GetDeclarationMethod(iEntry);
6232 if(hDeclMethod.IsMDMethod())
6234 // The declaration is on the type being built
6235 bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod();
6237 mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken();
6238 if (bmtMethodImpl->IsBody(mdef))
6239 { // A method declared on this class cannot be both a decl and an impl
6240 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
6246 PlaceInterfaceDeclarationOnInterface(
6249 slots, // Adds override to the slot and replaced arrays.
6252 dwMaxSlotSize); // Increments count
6257 PlaceLocalDeclarationOnClass(
6260 slots, // Adds override to the slot and replaced arrays.
6263 dwMaxSlotSize); // Increments count
6268 bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();
6273 PlaceInterfaceDeclarationOnInterface(
6276 slots, // Adds override to the slot and replaced arrays.
6279 dwMaxSlotSize); // Increments count
6283 // Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
6284 if (pCurDeclMethod->GetOwningType()->IsInterface())
6287 PlaceInterfaceDeclarationOnClass(
6294 PlaceParentDeclarationOnClass(
6300 dwMaxSlotSize); // Increments count
6307 if(iEntry == bmtMethodImpl->pIndex)
6309 // We hit the end of the list so dump the current data and leave
6310 WriteMethodImplData(pCurImplMethod, slotIndex, slots, replaced);
6315 bmtMDMethod * pNextImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry);
6317 if (pNextImplMethod != pCurImplMethod)
6319 // If we're moving on to a new body, dump the current data and reset the counter
6320 WriteMethodImplData(pCurImplMethod, slotIndex, slots, replaced);
6324 pCurImplMethod = pNextImplMethod;
6326 } // while(next != NULL)
6327 } // MethodTableBuilder::PlaceMethodImpls
6329 //*******************************************************************************
6331 MethodTableBuilder::WriteMethodImplData(
6332 bmtMDMethod * pImplMethod,
6335 RelativePointer<MethodDesc *> * rgDeclMD)
6337 STANDARD_VM_CONTRACT;
6339 // Use the number of overrides to
6340 // push information on to the method desc. We store the slots that
6341 // are overridden and the method desc that is replaced. That way
6342 // when derived classes need to determine if the method is to be
6343 // overridden then it can check the name against the replaced
6344 // method desc not the bodies name.
6347 //@TODO:NEWVTWORK: Determine methodImpl status so that we don't need this workaround.
6348 //@TODO:NEWVTWORK: This occurs when only interface decls are involved, since
6349 //@TODO:NEWVTWORK: these are stored in the dispatch map and not on the methoddesc.
6353 MethodImpl * pImpl = pImplMethod->GetMethodDesc()->GetMethodImpl();
6355 // Set the size of the info the MethodImpl needs to keep track of.
6356 pImpl->SetSize(GetLoaderAllocator()->GetHighFrequencyHeap(), GetMemTracker(), cSlots);
6360 // If we are currently builting an interface, the slots here has no meaning and we can skip it
6361 // Sort the two arrays in slot index order
6362 // This is required in MethodImpl::FindSlotIndex and MethodImpl::Iterator as we'll be using
6363 // binary search later
6364 for (DWORD i = 0; i < cSlots; i++)
6367 for (DWORD j = i + 1; j < cSlots; j++)
6369 if (rgSlots[j] < rgSlots[min])
6377 MethodDesc * mTmp = rgDeclMD[i].GetValue();
6378 rgDeclMD[i].SetValue(rgDeclMD[min].GetValue());
6379 rgDeclMD[min].SetValue(mTmp);
6381 DWORD sTmp = rgSlots[i];
6382 rgSlots[i] = rgSlots[min];
6383 rgSlots[min] = sTmp;
6388 // Go and set the method impl
6389 pImpl->SetData(rgSlots, rgDeclMD);
6391 GetHalfBakedClass()->SetContainsMethodImpls();
6393 } // MethodTableBuilder::WriteMethodImplData
6395 //*******************************************************************************
6397 MethodTableBuilder::PlaceLocalDeclarationOnClass(
6398 bmtMDMethod * pDecl,
6399 bmtMDMethod * pImpl,
6401 RelativePointer<MethodDesc *> * replaced,
6403 DWORD dwMaxSlotSize)
6408 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6409 PRECONDITION(CheckPointer(pDecl));
6410 PRECONDITION(CheckPointer(pImpl));
6414 if (!bmtProp->fNoSanityChecks)
6416 ///////////////////////////////
6417 // Verify the signatures match
6419 MethodImplCompareSignatures(
6422 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_LOCAL_METHOD_IMPL);
6424 ///////////////////////////////
6425 // Validate the method impl.
6428 bmtMethodHandle(pDecl),
6429 bmtMethodHandle(pImpl));
6432 // Don't allow overrides for any of the four special runtime implemented delegate methods
6435 LPCUTF8 strMethodName = pDecl->GetMethodSignature().GetName();
6436 if ((strcmp(strMethodName, COR_CTOR_METHOD_NAME) == 0) ||
6437 (strcmp(strMethodName, "Invoke") == 0) ||
6438 (strcmp(strMethodName, "BeginInvoke") == 0) ||
6439 (strcmp(strMethodName, "EndInvoke") == 0))
6441 BuildMethodTableThrowException(
6442 IDS_CLASSLOAD_MI_CANNOT_OVERRIDE,
6443 pDecl->GetMethodSignature().GetToken());
6450 // Call helper to add it. Will throw if decl is already MethodImpl'd
6451 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6452 AddMethodImplDispatchMapping(
6453 DispatchMapTypeID::ThisClassID(),
6454 pDecl->GetSlotIndex(),
6457 // We implement this slot, record it
6458 ASSERT(*pSlotIndex < dwMaxSlotSize);
6459 slots[*pSlotIndex] = pDecl->GetSlotIndex();
6460 replaced[*pSlotIndex].SetValue(pDecl->GetMethodDesc());
6462 // increment the counter
6464 } // MethodTableBuilder::PlaceLocalDeclarationOnClass
6466 //*******************************************************************************
6467 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnClass(
6468 bmtRTMethod * pDecl,
6469 bmtMDMethod * pImpl)
6473 PRECONDITION(CheckPointer(pDecl));
6474 PRECONDITION(CheckPointer(pImpl));
6475 PRECONDITION(pDecl->GetMethodDesc()->IsInterface());
6476 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6479 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6480 MethodTable * pDeclMT = pDeclMD->GetMethodTable();
6482 // Note that the fact that pDecl is non-NULL means that we found the
6483 // declaration token to be owned by a declared interface for this type.
6485 if (!bmtProp->fNoSanityChecks)
6487 ///////////////////////////////
6488 // Verify the signatures match
6490 MethodImplCompareSignatures(
6493 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6495 ///////////////////////////////
6496 // Validate the method impl.
6499 bmtMethodHandle(pDecl),
6500 bmtMethodHandle(pImpl));
6506 // Note that we need only one DispatchMapTypeID for this interface (though there might be more if there
6507 // are duplicates). The first one is easy to get, but we could (in theory) use the last one or a random
6509 // Q: Why don't we have to place this method for all duplicate interfaces? Because VSD knows about
6510 // duplicates and finds the right (latest) implementation for us - see
6511 // code:MethodTable::MethodDataInterfaceImpl::PopulateNextLevel#ProcessAllDuplicates.
6512 UINT32 cInterfaceDuplicates;
6513 DispatchMapTypeID firstDispatchMapTypeID;
6514 ComputeDispatchMapTypeIDs(
6516 &pDecl->GetMethodSignature().GetSubstitution(),
6517 &firstDispatchMapTypeID,
6519 &cInterfaceDuplicates);
6520 CONSISTENCY_CHECK(cInterfaceDuplicates >= 1);
6521 CONSISTENCY_CHECK(firstDispatchMapTypeID.IsImplementedInterface());
6523 // Call helper to add it. Will throw if decl is already MethodImpl'd
6524 CONSISTENCY_CHECK(pDecl->GetSlotIndex() == static_cast<SLOT_INDEX>(pDecl->GetMethodDesc()->GetSlot()));
6525 AddMethodImplDispatchMapping(
6526 firstDispatchMapTypeID,
6527 pDecl->GetSlotIndex(),
6530 if (IsCompilationProcess())
6533 // Mark this interface as overridable. It is used to skip generation of
6534 // CCWs stubs during NGen (see code:MethodNeedsReverseComStub)
6536 if (!IsMdFinal(pImpl->GetDeclAttrs()))
6538 pDeclMT->GetWriteableDataForWrite()->SetIsOverridingInterface();
6543 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
6544 { // We injected interface duplicates
6546 // We have to MethodImpl all interface duplicates as all duplicates are 'declared on type' (see
6547 // code:#InjectInterfaceDuplicates_ApproxInterfaces)
6548 DispatchMapTypeID * rgDispatchMapTypeIDs = (DispatchMapTypeID *)_alloca(sizeof(DispatchMapTypeID) * cInterfaceDuplicates);
6549 ComputeDispatchMapTypeIDs(
6551 &pDecl->GetMethodSignature().GetSubstitution(),
6552 rgDispatchMapTypeIDs,
6553 cInterfaceDuplicates,
6554 &cInterfaceDuplicates);
6555 for (UINT32 nInterfaceDuplicate = 1; nInterfaceDuplicate < cInterfaceDuplicates; nInterfaceDuplicate++)
6557 // Add MethodImpl record for each injected interface duplicate
6558 AddMethodImplDispatchMapping(
6559 rgDispatchMapTypeIDs[nInterfaceDuplicate],
6560 pDecl->GetSlotIndex(),
6565 } // MethodTableBuilder::PlaceInterfaceDeclarationOnClass
6567 //*******************************************************************************
6568 VOID MethodTableBuilder::PlaceInterfaceDeclarationOnInterface(
6569 bmtMethodHandle hDecl,
6572 RelativePointer<MethodDesc *> * replaced,
6574 DWORD dwMaxSlotSize)
6578 PRECONDITION(CheckPointer(pImpl));
6579 PRECONDITION(IsInterface());
6580 PRECONDITION(hDecl.GetMethodDesc()->IsInterface());
6583 MethodDesc * pDeclMD = hDecl.GetMethodDesc();
6585 if (!bmtProp->fNoSanityChecks)
6587 ///////////////////////////////
6588 // Verify the signatures match
6590 MethodImplCompareSignatures(
6592 bmtMethodHandle(pImpl),
6593 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL);
6595 ///////////////////////////////
6596 // Validate the method impl.
6598 TestMethodImpl(hDecl, bmtMethodHandle(pImpl));
6601 // We implement this slot, record it
6602 ASSERT(*pSlotIndex < dwMaxSlotSize);
6603 slots[*pSlotIndex] = hDecl.GetSlotIndex();
6604 replaced[*pSlotIndex].SetValue(pDeclMD);
6606 // increment the counter
6608 } // MethodTableBuilder::PlaceInterfaceDeclarationOnInterface
6610 //*******************************************************************************
6612 MethodTableBuilder::PlaceParentDeclarationOnClass(
6613 bmtRTMethod * pDecl,
6614 bmtMDMethod * pImpl,
6616 RelativePointer<MethodDesc *> * replaced,
6618 DWORD dwMaxSlotSize)
6622 PRECONDITION(CheckPointer(pDecl));
6623 PRECONDITION(CheckPointer(pImpl));
6624 PRECONDITION(CheckPointer(bmtVT->pDispatchMapBuilder));
6625 PRECONDITION(CheckPointer(GetParentMethodTable()));
6628 MethodDesc * pDeclMD = pDecl->GetMethodDesc();
6630 // Note that the fact that pDecl is non-NULL means that we found the
6631 // declaration token to be owned by a parent type.
6633 if (!bmtProp->fNoSanityChecks)
6635 /////////////////////////////////////////
6636 // Verify that the signatures match
6638 MethodImplCompareSignatures(
6641 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_PARENT_METHOD_IMPL);
6643 ////////////////////////////////
6644 // Verify rules of method impls
6647 bmtMethodHandle(pDecl),
6648 bmtMethodHandle(pImpl));
6654 // Call helper to add it. Will throw if DECL is already MethodImpl'd
6655 AddMethodImplDispatchMapping(
6656 DispatchMapTypeID::ThisClassID(),
6660 // We implement this slot, record it
6661 ASSERT(*pSlotIndex < dwMaxSlotSize);
6662 slots[*pSlotIndex] = pDeclMD->GetSlot();
6663 replaced[*pSlotIndex].SetValue(pDeclMD);
6665 // increment the counter
6667 } // MethodTableBuilder::PlaceParentDeclarationOnClass
6669 //*******************************************************************************
6670 // This will validate that all interface methods that were matched during
6671 // layout also validate against type constraints.
6673 VOID MethodTableBuilder::ValidateInterfaceMethodConstraints()
6675 STANDARD_VM_CONTRACT;
6677 DispatchMapBuilder::Iterator it(bmtVT->pDispatchMapBuilder);
6678 for (; it.IsValid(); it.Next())
6680 if (it.GetTypeID() != DispatchMapTypeID::ThisClassID())
6682 bmtRTType * pItf = bmtInterface->pInterfaceMap[it.GetTypeID().GetInterfaceNum()].GetInterfaceType();
6684 // Grab the method token
6685 MethodTable * pMTItf = pItf->GetMethodTable();
6686 CONSISTENCY_CHECK(CheckPointer(pMTItf->GetMethodDescForSlot(it.GetSlotNumber())));
6687 mdMethodDef mdTok = pItf->GetMethodTable()->GetMethodDescForSlot(it.GetSlotNumber())->GetMemberDef();
6689 // Default to the current module. The code immediately below determines if this
6690 // assumption is incorrect.
6691 Module * pTargetModule = GetModule();
6693 // Get the module of the target method. Get it through the chunk to
6694 // avoid triggering the assert that MethodTable is non-NULL. It may
6695 // be null since it may belong to the type we're building right now.
6696 MethodDesc * pTargetMD = it.GetTargetMD();
6698 // If pTargetMT is null, this indicates that the target MethodDesc belongs
6699 // to the current type. Otherwise, the MethodDesc MUST be owned by a parent
6700 // of the type we're building.
6701 BOOL fTargetIsOwnedByParent = !pTargetMD->GetMethodTablePtr()->IsNull();
6703 // If the method is owned by a parent, we need to use the parent's module,
6704 // and we must construct the substitution chain all the way up to the parent.
6705 const Substitution *pSubstTgt = NULL;
6706 if (fTargetIsOwnedByParent)
6708 CONSISTENCY_CHECK(CheckPointer(GetParentType()));
6709 bmtRTType *pTargetType = bmtRTType::FindType(GetParentType(), pTargetMD->GetMethodTable());
6710 pSubstTgt = &pTargetType->GetSubstitution();
6711 pTargetModule = pTargetType->GetModule();
6714 // Now compare the method constraints.
6715 if (!MetaSig::CompareMethodConstraints(pSubstTgt,
6717 pTargetMD->GetMemberDef(),
6718 &pItf->GetSubstitution(),
6719 pMTItf->GetModule(),
6722 LOG((LF_CLASSLOADER, LL_INFO1000,
6723 "BADCONSTRAINTS on interface method implementation: %x\n", pTargetMD));
6724 // This exception will be due to an implicit implementation, since explicit errors
6725 // will be detected in MethodImplCompareSignatures (for now, anyway).
6726 CONSISTENCY_CHECK(!it.IsMethodImpl());
6727 DWORD idsError = it.IsMethodImpl() ?
6728 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL :
6729 IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_IMPLEMENTATION;
6730 if (fTargetIsOwnedByParent)
6732 DefineFullyQualifiedNameForClass();
6733 LPCUTF8 szClassName = GetFullyQualifiedNameForClassNestedAware(pTargetMD->GetMethodTable());
6734 LPCUTF8 szMethodName = pTargetMD->GetName();
6737 // allocate enough room for "<class>.<method>\0"
6738 size_t cchFullName = strlen(szClassName) + 1 + strlen(szMethodName) + 1;
6739 LPUTF8 szFullName = (LPUTF8) qb.AllocThrows(cchFullName);
6740 strcpy_s(szFullName, cchFullName, szClassName);
6741 strcat_s(szFullName, cchFullName, ".");
6742 strcat_s(szFullName, cchFullName, szMethodName);
6744 BuildMethodTableThrowException(idsError, szFullName);
6748 BuildMethodTableThrowException(idsError, pTargetMD->GetMemberDef());
6753 } // MethodTableBuilder::ValidateInterfaceMethodConstraints
6755 //*******************************************************************************
6756 // Used to allocate and initialize MethodDescs (both the boxed and unboxed entrypoints)
6757 VOID MethodTableBuilder::AllocAndInitMethodDescs()
6759 STANDARD_VM_CONTRACT;
6762 // Go over all MethodDescs and create smallest number of MethodDescChunks possible.
6764 // Iterate over all methods and start a new chunk only if:
6765 // - Token range (upper 24 bits of the method token) has changed.
6766 // - The maximum size of the chunk has been reached.
6769 int currentTokenRange = -1; // current token range
6770 SIZE_T sizeOfMethodDescs = 0; // current running size of methodDesc chunk
6771 int startIndex = 0; // start of the current chunk (index into bmtMethod array)
6773 DeclaredMethodIterator it(*this);
6776 int tokenRange = GetTokenRange(it.Token());
6778 // This code assumes that iterator returns tokens in ascending order. If this assumption does not hold,
6779 // the code will still work with small performance penalty (method desc chunk layout will be less efficient).
6780 _ASSERTE(tokenRange >= currentTokenRange);
6782 SIZE_T size = MethodDesc::GetBaseSize(GetMethodClassification(it->GetMethodType()));
6784 // Add size of optional slots
6786 if (it->GetMethodImplType() == METHOD_IMPL)
6787 size += sizeof(MethodImpl);
6789 if (it->GetSlotIndex() >= bmtVT->cVtableSlots)
6790 size += sizeof(MethodDesc::NonVtableSlot); // slot
6792 if (NeedsNativeCodeSlot(*it))
6793 size += sizeof(MethodDesc::NativeCodeSlot);
6795 // See comment in AllocAndInitMethodDescChunk
6796 if (NeedsTightlyBoundUnboxingStub(*it))
6800 if (bmtGenerics->GetNumGenericArgs() == 0) {
6801 size += sizeof(MethodDesc::NonVtableSlot);
6804 bmtVT->cVtableSlots++;
6808 if (tokenRange != currentTokenRange ||
6809 sizeOfMethodDescs + size > MethodDescChunk::MaxSizeOfMethodDescs)
6811 if (sizeOfMethodDescs != 0)
6813 AllocAndInitMethodDescChunk(startIndex, it.CurrentIndex() - startIndex, sizeOfMethodDescs);
6814 startIndex = it.CurrentIndex();
6817 currentTokenRange = tokenRange;
6818 sizeOfMethodDescs = 0;
6821 sizeOfMethodDescs += size;
6824 if (sizeOfMethodDescs != 0)
6826 AllocAndInitMethodDescChunk(startIndex, NumDeclaredMethods() - startIndex, sizeOfMethodDescs);
6830 //*******************************************************************************
6831 // Allocates and initializes one method desc chunk.
6834 // startIndex - index of first method in bmtMethod array.
6835 // count - number of methods in this chunk (contiguous region from startIndex)
6836 // sizeOfMethodDescs - total expected size of MethodDescs in this chunk
6838 // Used by AllocAndInitMethodDescs.
6840 VOID MethodTableBuilder::AllocAndInitMethodDescChunk(COUNT_T startIndex, COUNT_T count, SIZE_T sizeOfMethodDescs)
6844 PRECONDITION(sizeOfMethodDescs <= MethodDescChunk::MaxSizeOfMethodDescs);
6847 void * pMem = GetMemTracker()->Track(
6848 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TADDR) + sizeof(MethodDescChunk) + sizeOfMethodDescs)));
6850 // Skip pointer to temporary entrypoints
6851 MethodDescChunk * pChunk = (MethodDescChunk *)((BYTE*)pMem + sizeof(TADDR));
6853 COUNT_T methodDescCount = 0;
6855 SIZE_T offset = sizeof(MethodDescChunk);
6858 #pragma warning(push)
6859 #pragma warning(disable:22019) // Suppress PREFast warning about integer underflow
6861 for (COUNT_T i = 0; i < count; i++)
6863 #pragma warning(pop)
6867 bmtMDMethod * pMDMethod = (*bmtMethod)[static_cast<SLOT_INDEX>(startIndex + i)];
6869 MethodDesc * pMD = (MethodDesc *)((BYTE *)pChunk + offset);
6871 pMD->SetChunkIndex(pChunk);
6873 InitNewMethodDesc(pMDMethod, pMD);
6876 #pragma warning(push)
6877 #pragma warning(disable:22018) // Suppress PREFast warning about integer underflow
6879 offset += pMD->SizeOf();
6881 #pragma warning(pop)
6886 // If we're a value class, we want to create duplicate slots
6887 // and MethodDescs for all methods in the vtable
6888 // section (i.e. not non-virtual instance methods or statics).
6889 // In the name of uniformity it would be much nicer
6890 // if we created _all_ value class BoxedEntryPointStubs at this point.
6891 // However, non-virtual instance methods only require unboxing
6892 // stubs in the rare case that we create a delegate to such a
6893 // method, and thus it would be inefficient to create them on
6894 // loading: after all typical structs will have many non-virtual
6895 // instance methods.
6897 // Unboxing stubs for non-virtual instance methods are created
6898 // in code:MethodDesc::FindOrCreateAssociatedMethodDesc.
6900 if (NeedsTightlyBoundUnboxingStub(pMDMethod))
6902 MethodDesc * pUnboxedMD = (MethodDesc *)((BYTE *)pChunk + offset);
6904 //////////////////////////////////
6905 // Initialize the new MethodDesc
6907 // <NICE> memcpy operations on data structures like MethodDescs are extremely fragile
6908 // and should not be used. We should go to the effort of having proper constructors
6909 // in the MethodDesc class. </NICE>
6911 memcpy(pUnboxedMD, pMD, pMD->SizeOf());
6913 // Reset the chunk index
6914 pUnboxedMD->SetChunkIndex(pChunk);
6916 if (bmtGenerics->GetNumGenericArgs() == 0) {
6917 pUnboxedMD->SetHasNonVtableSlot();
6920 //////////////////////////////////////////////////////////
6921 // Modify the original MethodDesc to be an unboxing stub
6923 pMD->SetIsUnboxingStub();
6925 ////////////////////////////////////////////////////////////////////
6926 // Add the new MethodDesc to the non-virtual portion of the vtable
6928 if (!bmtVT->AddUnboxedMethod(pMDMethod))
6929 BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS);
6931 pUnboxedMD->SetSlot(pMDMethod->GetUnboxedSlotIndex());
6932 pMDMethod->SetUnboxedMethodDesc(pUnboxedMD);
6934 offset += pUnboxedMD->SizeOf();
6938 _ASSERTE(offset == sizeof(MethodDescChunk) + sizeOfMethodDescs);
6940 pChunk->SetSizeAndCount((ULONG)sizeOfMethodDescs, methodDescCount);
6942 GetHalfBakedClass()->AddChunk(pChunk);
6945 //*******************************************************************************
6947 MethodTableBuilder::NeedsTightlyBoundUnboxingStub(bmtMDMethod * pMDMethod)
6949 STANDARD_VM_CONTRACT;
6951 return IsValueClass() &&
6952 !IsMdStatic(pMDMethod->GetDeclAttrs()) &&
6953 IsMdVirtual(pMDMethod->GetDeclAttrs()) &&
6954 (pMDMethod->GetMethodType() != METHOD_TYPE_INSTANTIATED) &&
6955 !IsMdRTSpecialName(pMDMethod->GetDeclAttrs());
6958 //*******************************************************************************
6960 MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
6962 LIMITED_METHOD_CONTRACT;
6965 #ifdef FEATURE_TIERED_COMPILATION
6966 // Keep in-sync with MethodDesc::IsEligibleForTieredCompilation()
6967 if (g_pConfig->TieredCompilation() &&
6968 (pMDMethod->GetMethodType() == METHOD_TYPE_NORMAL || pMDMethod->GetMethodType() == METHOD_TYPE_INSTANTIATED))
6974 #if defined(FEATURE_JIT_PITCHING)
6975 if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchEnabled) != 0) &&
6976 (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchMemThreshold) != 0))
6980 return GetModule()->IsEditAndContinueEnabled();
6983 //*******************************************************************************
6985 MethodTableBuilder::MayBeRemotingIntercepted(bmtMDMethod * pMDMethod)
6987 LIMITED_METHOD_CONTRACT;
6992 //*******************************************************************************
6994 MethodTableBuilder::AllocAndInitDictionary()
6996 STANDARD_VM_CONTRACT;
6998 // Allocate dictionary layout used by all compatible instantiations
7000 if (bmtGenerics->fSharedByGenericInstantiations && !bmtGenerics->fContainsGenericVariables)
7002 // We use the number of methods as a heuristic for the number of slots in the dictionary
7003 // attached to shared class method tables.
7004 // If there are no declared methods then we have no slots, and we will never do any token lookups
7007 // - Classes with a small number of methods (2-3) tend to be more likely to use new slots,
7008 // i.e. further methods tend to reuse slots from previous methods.
7009 // = treat all classes with only 2-3 methods as if they have an extra method.
7010 // - Classes with more generic parameters tend to use more slots.
7011 // = multiply by 1.5 for 2 params or more
7013 DWORD numMethodsAdjusted =
7014 (bmtMethod->dwNumDeclaredNonAbstractMethods == 0)
7016 : (bmtMethod->dwNumDeclaredNonAbstractMethods < 3)
7018 : bmtMethod->dwNumDeclaredNonAbstractMethods;
7020 _ASSERTE(bmtGenerics->GetNumGenericArgs() != 0);
7021 DWORD nTypeFactorBy2 = (bmtGenerics->GetNumGenericArgs() == 1)
7025 DWORD estNumTypeSlots = (numMethodsAdjusted * nTypeFactorBy2 + 2) / 3;
7026 // estNumTypeSlots should fit in a WORD as long as we maintain the current
7027 // limit on the number of methods in a type (approx 2^16).
7028 _ASSERTE(FitsIn<WORD>(estNumTypeSlots));
7029 WORD numTypeSlots = static_cast<WORD>(estNumTypeSlots);
7031 if (numTypeSlots > 0)
7033 // Dictionary layout is an optional field on EEClass, so ensure the optional field descriptor has
7035 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
7036 GetHalfBakedClass()->SetDictionaryLayout(DictionaryLayout::Allocate(numTypeSlots, bmtAllocator, m_pAllocMemTracker));
7042 //*******************************************************************************
7044 // Used by BuildMethodTable
7046 // Compute the set of interfaces which are equivalent. Duplicates in the interface map
7047 // will be placed into different equivalence sets unless they participate in type equivalence.
7048 // This is a bit odd, but it turns out we only need to know about equivalence classes if
7049 // there is type equivalence involved in the interface, and not detecting, or detecting equivalence
7050 // in other cases does not result in differing behavior.
7052 // By restricting the reasons for having equivalence matches, we reduce the algorithm from one which
7053 // is O(n*n) best case to an algorithm which will typically execute something more like O(m*n) best case time
7054 // where m is the number of generic interface (although still n*n in worst case). The assumption is that equivalent
7055 // and generic interfaces are relatively rare.
7057 MethodTableBuilder::ComputeInterfaceMapEquivalenceSet()
7059 STANDARD_VM_CONTRACT;
7061 UINT32 nextEquivalenceSet = 1;
7063 for (DWORD dwCurInterface = 0;
7064 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7067 // Keep track of the current interface we are trying to calculate the equivalence set of
7068 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7069 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7070 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7071 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7073 UINT32 currentEquivalenceSet = 0;
7075 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7076 if (pCurItfMT->HasTypeEquivalence() || pCurItfMT->HasInstantiation())
7078 for (DWORD dwCurInterfaceCompare = 0;
7079 dwCurInterfaceCompare < dwCurInterface;
7080 dwCurInterfaceCompare++)
7082 // Keep track of the current interface we are trying to calculate the equivalence set of
7083 bmtInterfaceEntry * pCompareItfEntry = &bmtInterface->pInterfaceMap[dwCurInterfaceCompare];
7084 bmtRTType * pCompareItf = pCompareItfEntry->GetInterfaceType();
7085 MethodTable * pCompareItfMT = pCompareItf->GetMethodTable();
7086 const Substitution * pCompareItfSubst = &pCompareItf->GetSubstitution();
7088 // Only interfaces with type equivalence, or that are generic need to be compared for equivalence
7089 if (pCompareItfMT->HasTypeEquivalence() || pCompareItfMT->HasInstantiation())
7091 if (MetaSig::CompareTypeDefsUnderSubstitutions(pCurItfMT,
7097 currentEquivalenceSet = pCompareItfEntry->GetInterfaceEquivalenceSet();
7098 // Use the equivalence set of the interface map entry we just found
7099 pCurItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7100 // Update the interface map entry we just found to indicate that it is part of an equivalence
7101 // set with multiple entries.
7102 pCompareItfEntry->SetInterfaceEquivalenceSet(currentEquivalenceSet, true);
7109 // If we did not find an equivalent interface above, use the next available equivalence set indicator
7110 if (currentEquivalenceSet == 0)
7112 pCurItfEntry->SetInterfaceEquivalenceSet(nextEquivalenceSet, false);
7113 nextEquivalenceSet++;
7118 //*******************************************************************************
7120 // Used by PlaceInterfaceMethods
7122 // Given an interface in our interface map, and a particular method on that interface, place
7123 // a method from the parent types implementation of an equivalent interface into that method
7124 // slot. Used by PlaceInterfaceMethods to make equivalent interface implementations have the
7125 // same behavior as if the parent interface was implemented on this type instead of an equivalent interface.
7127 // This logic is used in situations such as below. I and I' are equivalent interfaces
7131 // {void I.Method() { } }
7132 // interface IOther : I' {}
7133 // class Derived : IOther
7134 // { virtual void Method() {}}
7136 // We should Map I'.Method to Base.Method, not Derived.Method
7140 // { virtual void Method() }
7141 // interface IOther : I' {}
7142 // class Derived : IOther
7143 // { virtual void Method() {}}
7145 // We should map I'.Method to Base.Method, not Derived.Method
7148 // {void I.Method() { } }
7149 // class Derived : I'
7152 // We should Map I'.Method to Base.Method, and not throw TypeLoadException
7154 #ifdef FEATURE_COMINTEROP
7156 MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(
7157 bmtInterfaceEntry::InterfaceSlotIterator & itfSlotIt,
7158 bmtInterfaceEntry * pCurItfEntry,
7159 DispatchMapTypeID ** prgInterfaceDispatchMapTypeIDs,
7160 DWORD dwCurInterface)
7162 STANDARD_VM_CONTRACT;
7164 bmtRTMethod * pCurItfMethod = itfSlotIt->Decl().AsRTMethod();
7166 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7171 // For every equivalent interface entry that was actually implemented by parent, then look at equivalent method slot on that entry
7172 // and if it matches and has a slot implementation, then record and continue
7173 for (DWORD dwEquivalentInterface = 0;
7174 (dwEquivalentInterface < bmtInterface->dwInterfaceMapSize) && (itfSlotIt->Impl() == INVALID_SLOT_INDEX);
7175 dwEquivalentInterface++)
7177 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7178 bmtRTType * pEquivItf = pEquivItfEntry->GetInterfaceType();
7179 MethodTable * pEquivItfMT = pEquivItf->GetMethodTable();
7180 const Substitution * pEquivItfSubst = &pEquivItf->GetSubstitution();
7181 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7186 if (!pEquivItfEntry->IsImplementedByParent())
7188 // Not implemented by parent
7192 WORD slot = static_cast<WORD>(itfSlotIt.CurrentIndex());
7193 BOOL fFound = FALSE;
7195 // Determine which slot on the equivalent interface would map to the slot we are attempting to fill
7196 // in with an implementation.
7197 WORD otherMTSlot = GetEquivalentMethodSlot(pCurItfEntry->GetInterfaceType()->GetMethodTable(),
7198 pEquivItfEntry->GetInterfaceType()->GetMethodTable(),
7204 UINT32 cInterfaceDuplicates;
7205 if (*prgInterfaceDispatchMapTypeIDs == NULL)
7207 *prgInterfaceDispatchMapTypeIDs =
7208 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7211 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7212 ComputeDispatchMapTypeIDs(
7215 *prgInterfaceDispatchMapTypeIDs,
7216 bmtInterface->dwInterfaceMapSize,
7217 &cInterfaceDuplicates);
7218 // There cannot be more duplicates than number of interfaces
7219 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7220 _ASSERTE(cInterfaceDuplicates > 0);
7222 // NOTE: This override does not cache the resulting MethodData object
7223 MethodTable::MethodDataWrapper hParentData;
7224 hParentData = MethodTable::GetMethodData(
7225 *prgInterfaceDispatchMapTypeIDs,
7226 cInterfaceDuplicates,
7228 GetParentMethodTable());
7230 SLOT_INDEX slotIndex = static_cast<SLOT_INDEX>
7231 (hParentData->GetImplSlotNumber(static_cast<UINT32>(otherMTSlot)));
7233 // Interface is implemented on parent abstract type and this particular slot was not implemented
7234 if (slotIndex == INVALID_SLOT_INDEX)
7239 bmtMethodSlot & parentSlotImplementation = (*bmtParent->pSlotTable)[slotIndex];
7240 bmtMethodHandle & parentImplementation = parentSlotImplementation.Impl();
7242 // Check to verify that the equivalent slot on the equivalent interface actually matches the method
7243 // on the current interface. If not, then the slot is not a match, and we should search other interfaces
7244 // for an implementation of the method.
7245 if (!MethodSignature::SignaturesEquivalent(pCurItfMethod->GetMethodSignature(), parentImplementation.GetMethodSignature()))
7250 itfSlotIt->Impl() = slotIndex;
7252 MethodDesc * pMD = hParentData->GetImplMethodDesc(static_cast<UINT32>(otherMTSlot));
7254 DispatchMapTypeID dispatchMapTypeID =
7255 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7256 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7258 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7263 } // MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot
7264 #endif // FEATURE_COMINTEROP
7266 //*******************************************************************************
7268 // Used by BuildMethodTable
7271 // If we are a class, then there may be some unplaced vtable methods (which are by definition
7272 // interface methods, otherwise they'd already have been placed). Place as many unplaced methods
7273 // as possible, in the order preferred by interfaces. However, do not allow any duplicates - once
7274 // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
7275 // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot. Fill out the interface
7276 // map for all interfaces as they are placed.
7278 // If we are an interface, then all methods are already placed. Fill out the interface map for
7279 // interfaces as they are placed.
7281 // BEHAVIOUR (based on Partition II: 11.2, not including MethodImpls)
7282 // C is current class, P is a parent class, I is the interface being implemented
7284 // FOREACH interface I implemented by this class C
7285 // FOREACH method I::M
7286 // IF I is EXPLICITLY implemented by C
7287 // IF some method C::M matches I::M
7288 // USE C::M as implementation for I::M
7289 // ELIF we inherit a method P::M that matches I::M
7290 // USE P::M as implementation for I::M
7293 // IF I::M lacks implementation
7294 // IF some method C::M matches I::M
7295 // USE C::M as implementation for I::M
7296 // ELIF we inherit a method P::M that matches I::M
7297 // USE P::M as implementation for I::M
7298 // ELIF I::M was implemented by the parent type with method Parent::M
7299 // USE Parent::M for the implementation of I::M // VSD does this by default if we really
7300 // // implemented I on the parent type, but
7301 // // equivalent interfaces need to make this
7311 MethodTableBuilder::PlaceInterfaceMethods()
7313 STANDARD_VM_CONTRACT;
7315 BOOL fParentInterface;
7316 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs = NULL;
7318 for (DWORD dwCurInterface = 0;
7319 dwCurInterface < bmtInterface->dwInterfaceMapSize;
7322 // Default to being implemented by the current class
7323 fParentInterface = FALSE;
7325 // Keep track of the current interface we are trying to place
7326 bmtInterfaceEntry * pCurItfEntry = &bmtInterface->pInterfaceMap[dwCurInterface];
7327 bmtRTType * pCurItf = pCurItfEntry->GetInterfaceType();
7328 MethodTable * pCurItfMT = pCurItf->GetMethodTable();
7329 const Substitution * pCurItfSubst = &pCurItf->GetSubstitution();
7332 // There are three reasons why an interface could be in the implementation list
7333 // 1. Inherited from parent
7334 // 2. Explicitly declared in the implements list
7335 // 3. Implicitly declared through the implements list of an explicitly declared interface
7337 // The reason these cases need to be distinguished is that an inherited interface that is
7338 // also explicitly redeclared in the implements list must be fully reimplemented using the
7339 // virtual methods of this type (thereby using matching methods in this type that may have
7340 // a different slot than an inherited method, but hidden it by name & sig); however all
7341 // implicitly redeclared interfaces should not be fully reimplemented if they were also
7342 // inherited from the parent.
7345 // interface I1 : I2
7349 // In this example I1 must be fully reimplemented on B, but B can inherit the implementation
7353 if (pCurItfEntry->IsImplementedByParent())
7355 if (!pCurItfEntry->IsDeclaredOnType())
7357 fParentInterface = TRUE;
7361 bool fEquivalentInterfaceImplementedByParent = pCurItfEntry->IsImplementedByParent();
7362 bool fEquivalentInterfaceDeclaredOnType = pCurItfEntry->IsDeclaredOnType();
7364 if (pCurItfEntry->InEquivalenceSetWithMultipleEntries())
7366 for (DWORD dwEquivalentInterface = 0;
7367 dwEquivalentInterface < bmtInterface->dwInterfaceMapSize;
7368 dwEquivalentInterface++)
7370 bmtInterfaceEntry * pEquivItfEntry = &bmtInterface->pInterfaceMap[dwEquivalentInterface];
7371 if (pEquivItfEntry->GetInterfaceEquivalenceSet() != pCurItfEntry->GetInterfaceEquivalenceSet())
7376 if (pEquivItfEntry->IsImplementedByParent())
7378 fEquivalentInterfaceImplementedByParent = true;
7380 if (pEquivItfEntry->IsDeclaredOnType())
7382 fEquivalentInterfaceDeclaredOnType = true;
7385 if (fEquivalentInterfaceDeclaredOnType && fEquivalentInterfaceImplementedByParent)
7390 bool fParentInterfaceEquivalent = fEquivalentInterfaceImplementedByParent && !fEquivalentInterfaceDeclaredOnType;
7392 CONSISTENCY_CHECK(!fParentInterfaceEquivalent || HasParent());
7394 if (fParentInterfaceEquivalent)
7396 // In the case the fParentInterface is TRUE, virtual overrides are enough and the interface
7397 // does not have to be explicitly (re)implemented. The only exception is if the parent is
7398 // abstract, in which case an inherited interface may not be fully implemented yet.
7399 // This is an optimization that allows us to skip the more expensive slot filling in below.
7400 // Note that the check here is for fParentInterface and not for fParentInterfaceEquivalent.
7401 // This is necessary as if the interface is not actually implemented on the parent type we will
7402 // need to fill in the slot table below.
7403 if (fParentInterface && !GetParentMethodTable()->IsAbstract())
7409 // We will reach here in two cases.
7410 // 1 .The parent is abstract and the interface has been declared on the parent,
7411 // and possibly partially implemented, so we need to populate the
7412 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7414 // 2 .The the interface has not been declared on the parent,
7415 // but an equivalent interface has been. So we need to populate the
7416 // bmtInterfaceSlotImpl table for this interface with the implementation slot
7417 // information from one of the parent equivalent interfaces. We may or may not
7418 // find implementations for all of the methods on the interface on the parent type.
7419 // The parent type may or may not be abstract.
7421 MethodTable::MethodDataWrapper hParentData;
7422 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
7424 if (rgInterfaceDispatchMapTypeIDs == NULL)
7426 rgInterfaceDispatchMapTypeIDs =
7427 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
7430 if (pCurItfEntry->IsImplementedByParent())
7432 UINT32 cInterfaceDuplicates;
7433 // Compute all TypeIDs for this interface (all duplicates in the interface map)
7434 ComputeDispatchMapTypeIDs(
7437 rgInterfaceDispatchMapTypeIDs,
7438 bmtInterface->dwInterfaceMapSize,
7439 &cInterfaceDuplicates);
7440 // There cannot be more duplicates than number of interfaces
7441 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
7442 _ASSERTE(cInterfaceDuplicates > 0);
7444 //#InterfaceMap_UseParentInterfaceImplementations
7445 // We rely on the fact that interface map of parent type is subset of this type (incl.
7446 // duplicates), see code:#InterfaceMap_SupersetOfParent
7447 // NOTE: This override does not cache the resulting MethodData object
7448 hParentData = MethodTable::GetMethodData(
7449 rgInterfaceDispatchMapTypeIDs,
7450 cInterfaceDuplicates,
7452 GetParentMethodTable());
7454 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7455 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7456 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7458 itfSlotIt->Impl() = static_cast<SLOT_INDEX>
7459 (hParentData->GetImplSlotNumber(static_cast<UINT32>(itfSlotIt.CurrentIndex())));
7462 #ifdef FEATURE_COMINTEROP
7465 // Iterate through the methods on the interface, and if they have a slot which was filled in
7466 // on an equivalent interface inherited from the parent fill in the approrpriate slot.
7467 // This code path is only used when there is an implicit implementation of an interface
7468 // that was not implemented on a parent type, but there was an equivalent interface implemented
7469 // on a parent type.
7470 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7471 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7472 for (; !itfSlotIt.AtEnd(); itfSlotIt.Next())
7474 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7477 #endif // FEATURE_COMINTEROP
7481 #ifdef FEATURE_COMINTEROP
7482 // WinRT types always use methodimpls to line up methods with interface implementations, so we do not want to allow implicit
7483 // interface implementations to kick in. This can especially cause problems with redirected interfaces, where the underlying
7484 // runtimeclass doesn't actually implement the interfaces we claim it does. For example, a WinRT class which implements both
7485 // IVector<int> and ICalculator will be projected as implementing IList<int> and ICalculator. In this case, we do not want the
7486 // ICalculator Add(int) method to get lined up with the ICollection<int> Add method, since that will cause us to dispatch to the
7487 // wrong underlying COM interface.
7489 // There are a special WinRT types in mscorlib (notably DisposableRuntimeClass) which do implement interfaces in the normal way
7490 // so we skip this check for them. (Note that we can't use a methodimpl directly in mscorlib, since ComImport classes are
7491 // forbidden from having implementation code by the C# compiler).
7492 if (GetHalfBakedClass()->IsProjectedFromWinRT() && !GetModule()->IsSystem())
7496 #endif // FEATURE_COMINTEROP
7498 // For each method declared in this interface
7499 bmtInterfaceEntry::InterfaceSlotIterator itfSlotIt =
7500 pCurItfEntry->IterateInterfaceSlots(GetStackingAllocator());
7501 for (; !itfSlotIt.AtEnd(); ++itfSlotIt)
7503 if (fParentInterfaceEquivalent)
7505 if (itfSlotIt->Impl() != INVALID_SLOT_INDEX)
7506 { // If this interface is not explicitly declared on this class, and the interface slot has already been
7507 // given an implementation, then the only way to provide a new implementation is through an override
7508 // or through a MethodImpl. This is necessary in addition to the continue statement before this for
7509 // loop because an abstract interface can still have a partial implementation and it is necessary to
7510 // skip those interface slots that have already been satisfied.
7515 BOOL fFoundMatchInBuildingClass = FALSE;
7516 bmtInterfaceSlotImpl & curItfSlot = *itfSlotIt;
7517 bmtRTMethod * pCurItfMethod = curItfSlot.Decl().AsRTMethod();
7518 const MethodSignature & curItfMethodSig = pCurItfMethod->GetMethodSignature();
7521 // First, try to find the method explicitly declared in our class
7524 DeclaredMethodIterator methIt(*this);
7525 while (methIt.Next())
7527 // Note that non-publics can legally be exposed via an interface, but only
7528 // through methodImpls.
7529 if (IsMdVirtual(methIt.Attrs()) && IsMdPublic(methIt.Attrs()))
7532 if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(methIt.Name()))
7533 CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", methIt.Name()));
7536 if (pCurItfMethod->GetMethodSignature().Equivalent(methIt->GetMethodSignature()))
7538 fFoundMatchInBuildingClass = TRUE;
7539 curItfSlot.Impl() = methIt->GetSlotIndex();
7541 DispatchMapTypeID dispatchMapTypeID =
7542 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7543 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7545 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7546 methIt->GetMethodDesc(),
7552 } // end ... try to find method
7555 // The ECMA CLR spec states that a type will inherit interface implementations
7556 // and that explicit re-declaration of an inherited interface will try to match
7557 // only newslot methods with methods in the re-declared interface (note that
7558 // this also takes care of matching against unsatisfied interface methods in
7559 // the abstract parent type scenario).
7561 // So, if the interface was not declared on a parent and we haven't found a
7562 // newslot method declared on this type as a match, search all remaining
7563 // public virtual methods (including overrides declared on this type) for a
7566 // Please see bug VSW577403 and VSW593884 for details of this breaking change.
7568 if (!fFoundMatchInBuildingClass &&
7569 !fEquivalentInterfaceImplementedByParent)
7573 // Iterate backward through the parent's method table. This is important to
7574 // find the most derived method.
7575 bmtParentInfo::Iterator parentMethodIt = bmtParent->IterateSlots();
7576 parentMethodIt.ResetToEnd();
7577 while (parentMethodIt.Prev())
7579 bmtRTMethod * pCurParentMethod = parentMethodIt->Decl().AsRTMethod();
7580 DWORD dwAttrs = pCurParentMethod->GetDeclAttrs();
7581 if (!IsMdVirtual(dwAttrs) || !IsMdPublic(dwAttrs))
7582 { // Only match mdPublic mdVirtual methods for interface implementation
7586 if (curItfMethodSig.Equivalent(pCurParentMethod->GetMethodSignature()))
7588 fFoundMatchInBuildingClass = TRUE;
7589 curItfSlot.Impl() = pCurParentMethod->GetSlotIndex();
7591 DispatchMapTypeID dispatchMapTypeID =
7592 DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7593 bmtVT->pDispatchMapBuilder->InsertMDMapping(
7595 static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7596 pCurParentMethod->GetMethodDesc(),
7601 } // end ... try to find parent method
7605 // For type equivalent interfaces that had an equivalent interface implemented by their parent
7606 // and where the previous logic to fill in the method based on the virtual mappings on the type have
7607 // failed, we should attempt to get the mappings from the equivalent interfaces declared on parent types
7608 // of the type we are currently building.
7609 #ifdef FEATURE_COMINTEROP
7610 if (!fFoundMatchInBuildingClass && fEquivalentInterfaceImplementedByParent && !pCurItfEntry->IsImplementedByParent())
7612 PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot(itfSlotIt, pCurItfEntry, &rgInterfaceDispatchMapTypeIDs, dwCurInterface);
7617 } // MethodTableBuilder::PlaceInterfaceMethods
7620 //*******************************************************************************
7622 // Used by BuildMethodTable
7624 // Place static fields
7626 VOID MethodTableBuilder::PlaceRegularStaticFields()
7628 STANDARD_VM_CONTRACT;
7632 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing statics for %s\n", this->GetDebugClassName()));
7635 // Place gc refs and value types first, as they need to have handles created for them.
7636 // (Placing them together allows us to easily create the handles when Restoring the class,
7637 // and when initializing new DLS for the class.)
7640 DWORD dwCumulativeStaticFieldPos = 0 ;
7641 DWORD dwCumulativeStaticGCFieldPos = 0;
7642 DWORD dwCumulativeStaticBoxFieldPos = 0;
7644 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7645 // guaranteed to be aligned in ModuleStaticsInfo
7646 bmtFP->NumRegularStaticFieldsOfSize[LOG2_PTRSIZE] -=
7647 bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7649 // Place fields, largest first, padding so that each group is aligned to its natural size
7650 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7652 // Fields of this size start at the next available location
7653 bmtFP->RegularStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7654 dwCumulativeStaticFieldPos += (bmtFP->NumRegularStaticFieldsOfSize[i] << i);
7656 // Reset counters for the loop after this one
7657 bmtFP->NumRegularStaticFieldsOfSize[i] = 0;
7661 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7662 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7664 DWORD dwNumHandleStatics = bmtFP->NumRegularStaticGCBoxedFields + bmtFP->NumRegularStaticGCPointerFields;
7665 if (!FitsIn<WORD>(dwNumHandleStatics))
7667 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7669 SetNumHandleRegularStatics(static_cast<WORD>(dwNumHandleStatics));
7671 if (!FitsIn<WORD>(bmtFP->NumRegularStaticGCBoxedFields))
7673 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7675 SetNumBoxedRegularStatics(static_cast<WORD>(bmtFP->NumRegularStaticGCBoxedFields));
7677 // Tell the module to give us the offsets we'll be using and commit space for us
7679 DWORD dwNonGCOffset, dwGCOffset;
7680 GetModule()->GetOffsetsForRegularStaticData(bmtInternal->pType->GetTypeDefToken(),
7681 bmtProp->fDynamicStatics,
7682 GetNumHandleRegularStatics(), dwCumulativeStaticFieldPos,
7683 &dwGCOffset, &dwNonGCOffset);
7685 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7686 dwCumulativeStaticGCFieldPos = bmtFP->NumRegularStaticGCBoxedFields<<LOG2_PTRSIZE;
7688 FieldDesc *pFieldDescList = GetApproxFieldDescListRaw();
7689 // Place static fields
7690 for (i = 0; i < bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields; i++)
7692 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields+i];
7693 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7694 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7698 case FIELD_OFFSET_UNPLACED_GC_PTR:
7699 // Place GC reference static field
7700 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7701 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7702 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7706 case FIELD_OFFSET_VALUE_CLASS:
7707 // Place boxed GC reference static field
7708 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7709 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7710 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7714 case FIELD_OFFSET_UNPLACED:
7715 // Place non-GC static field
7716 pCurField->SetOffset(bmtFP->RegularStaticFieldStart[dwLog2FieldSize] +
7717 (bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7719 bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
7720 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7728 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset_NoLogging()));
7731 if (bmtProp->fDynamicStatics)
7733 _ASSERTE(dwNonGCOffset == 0 || // no statics at all
7734 dwNonGCOffset == DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob()); // We need space to point to the GC statics
7735 bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos;
7739 bmtProp->dwNonGCRegularStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7741 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCRegularStaticFieldBytes));
7745 VOID MethodTableBuilder::PlaceThreadStaticFields()
7747 STANDARD_VM_CONTRACT;
7751 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Placing ThreadStatics for %s\n", this->GetDebugClassName()));
7754 // Place gc refs and value types first, as they need to have handles created for them.
7755 // (Placing them together allows us to easily create the handles when Restoring the class,
7756 // and when initializing new DLS for the class.)
7759 DWORD dwCumulativeStaticFieldPos = 0 ;
7760 DWORD dwCumulativeStaticGCFieldPos = 0;
7761 DWORD dwCumulativeStaticBoxFieldPos = 0;
7763 // We don't need to do any calculations for the gc refs or valuetypes, as they're
7764 // guaranteed to be aligned in ModuleStaticsInfo
7765 bmtFP->NumThreadStaticFieldsOfSize[LOG2_PTRSIZE] -=
7766 bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7768 // Place fields, largest first, padding so that each group is aligned to its natural size
7769 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
7771 // Fields of this size start at the next available location
7772 bmtFP->ThreadStaticFieldStart[i] = dwCumulativeStaticFieldPos;
7773 dwCumulativeStaticFieldPos += (bmtFP->NumThreadStaticFieldsOfSize[i] << i);
7775 // Reset counters for the loop after this one
7776 bmtFP->NumThreadStaticFieldsOfSize[i] = 0;
7780 if (dwCumulativeStaticFieldPos > FIELD_OFFSET_LAST_REAL_OFFSET)
7781 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
7783 DWORD dwNumHandleStatics = bmtFP->NumThreadStaticGCBoxedFields + bmtFP->NumThreadStaticGCPointerFields;
7784 if (!FitsIn<WORD>(dwNumHandleStatics))
7786 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7789 SetNumHandleThreadStatics(static_cast<WORD>(dwNumHandleStatics));
7791 if (!FitsIn<WORD>(bmtFP->NumThreadStaticGCBoxedFields))
7793 BuildMethodTableThrowException(IDS_EE_TOOMANYFIELDS);
7796 SetNumBoxedThreadStatics(static_cast<WORD>(bmtFP->NumThreadStaticGCBoxedFields));
7798 // Tell the module to give us the offsets we'll be using and commit space for us
7800 DWORD dwNonGCOffset, dwGCOffset;
7802 GetModule()->GetOffsetsForThreadStaticData(bmtInternal->pType->GetTypeDefToken(),
7803 bmtProp->fDynamicStatics,
7804 GetNumHandleThreadStatics(), dwCumulativeStaticFieldPos,
7805 &dwGCOffset, &dwNonGCOffset);
7807 // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
7808 dwCumulativeStaticGCFieldPos = bmtFP->NumThreadStaticGCBoxedFields<<LOG2_PTRSIZE;
7810 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
7811 // Place static fields
7812 for (i = 0; i < bmtEnumFields->dwNumThreadStaticFields; i++)
7814 FieldDesc * pCurField = &pFieldDescList[bmtEnumFields->dwNumInstanceFields + bmtEnumFields->dwNumStaticFields - bmtEnumFields->dwNumThreadStaticFields + i];
7815 DWORD dwLog2FieldSize = (DWORD)(DWORD_PTR&)pCurField->m_pMTOfEnclosingClass; // log2(field size)
7816 DWORD dwOffset = (DWORD) pCurField->m_dwOffset; // offset or type of field
7820 case FIELD_OFFSET_UNPLACED_GC_PTR:
7821 // Place GC reference static field
7822 pCurField->SetOffset(dwCumulativeStaticGCFieldPos + dwGCOffset);
7823 dwCumulativeStaticGCFieldPos += 1<<LOG2_PTRSIZE;
7824 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7828 case FIELD_OFFSET_VALUE_CLASS:
7829 // Place boxed GC reference static field
7830 pCurField->SetOffset(dwCumulativeStaticBoxFieldPos + dwGCOffset);
7831 dwCumulativeStaticBoxFieldPos += 1<<LOG2_PTRSIZE;
7832 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7836 case FIELD_OFFSET_UNPLACED:
7837 // Place non-GC static field
7838 pCurField->SetOffset(bmtFP->ThreadStaticFieldStart[dwLog2FieldSize] +
7839 (bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize] << dwLog2FieldSize) +
7841 bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
7842 LOG((LF_CLASSLOADER, LL_INFO10000, "THREAD STATICS: Field placed at non GC offset 0x%x\n", pCurField->GetOffset_NoLogging()));
7850 LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset_NoLogging()));
7853 if (bmtProp->fDynamicStatics)
7855 _ASSERTE(dwNonGCOffset == 0 || // no thread statics at all
7856 dwNonGCOffset == ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob()); // We need space to point to the GC statics
7857 bmtProp->dwNonGCThreadStaticFieldBytes = dwCumulativeStaticFieldPos;
7861 bmtProp->dwNonGCThreadStaticFieldBytes = 0; // Non dynamics shouldnt be using this
7863 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: ThreadStatic field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCThreadStaticFieldBytes));
7866 //*******************************************************************************
7868 // Used by BuildMethodTable
7870 // Place instance fields
7872 VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCache)
7874 STANDARD_VM_CONTRACT;
7879 //===============================================================
7880 // BEGIN: Place instance fields
7881 //===============================================================
7883 FieldDesc *pFieldDescList = GetHalfBakedClass()->GetFieldDescList();
7884 DWORD dwCumulativeInstanceFieldPos;
7886 // Instance fields start right after the parent
7887 dwCumulativeInstanceFieldPos = HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0;
7889 DWORD dwOffsetBias = 0;
7890 #ifdef FEATURE_64BIT_ALIGNMENT
7891 // On platforms where the alignment of 64-bit primitives is a requirement (but we're not guaranteed
7892 // this implicitly by the GC) field offset 0 is actually not 8-byte aligned in reference classes.
7893 // That's because all such platforms are currently 32-bit and the 4-byte MethodTable pointer pushes us
7894 // out of alignment. Ideally we'd solve this by arranging to have the object header allocated at a
7895 // 4-byte offset from an 8-byte boundary, but this is difficult to achieve for objects allocated on
7896 // the large object heap (which actually requires headers to be 8-byte aligned).
7898 // So we adjust dwCumulativeInstanceFieldPos to account for the MethodTable* and our alignment
7899 // calculations will automatically adjust and add padding as necessary. We need to remove this
7900 // adjustment when setting the field offset in the field desc, however, since the rest of the system
7901 // expects that value to not include the MethodTable*.
7903 // This happens only for reference classes: value type field 0 really does lie at offset 0 for unboxed
7904 // value types. We deal with boxed value types by allocating their headers mis-aligned (luckily for us
7905 // value types can never get large enough to allocate on the LOH).
7906 if (!IsValueClass())
7908 dwOffsetBias = sizeof(MethodTable*);
7909 dwCumulativeInstanceFieldPos += dwOffsetBias;
7911 #endif // FEATURE_64BIT_ALIGNMENT
7913 #ifdef FEATURE_READYTORUN
7914 if (NeedsAlignedBaseOffset())
7916 // READYTORUN: FUTURE: Use the minimum possible alignment, reduce padding when inheriting within same bubble
7917 DWORD dwAlignment = DATA_ALIGNMENT;
7918 #ifdef FEATURE_64BIT_ALIGNMENT
7919 if (GetHalfBakedClass()->IsAlign8Candidate())
7922 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
7924 #endif // FEATURE_READYTORUN
7926 // place small fields first if the parent have a number of field bytes that is not aligned
7927 if (!IS_ALIGNED(dwCumulativeInstanceFieldPos, DATA_ALIGNMENT))
7929 for (i = 0; i < MAX_LOG2_PRIMITIVE_FIELD_SIZE; i++) {
7932 if (IS_ALIGNED(dwCumulativeInstanceFieldPos, 1<<(i+1)))
7935 // check whether there are any bigger fields
7936 for (j = i + 1; j <= MAX_LOG2_PRIMITIVE_FIELD_SIZE; j++) {
7937 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
7940 // nothing to gain if there are no bigger fields
7941 // (the subsequent loop will place fields from large to small fields)
7942 if (j > MAX_LOG2_PRIMITIVE_FIELD_SIZE)
7945 // check whether there are any small enough fields
7946 for (j = i; (signed int) j >= 0; j--) {
7947 if (bmtFP->NumInstanceFieldsOfSize[j] != 0)
7949 // TODO: since we will refuse to place GC references we should filter them out here.
7950 // otherwise the "back-filling" process stops completely.
7951 // (PlaceInstanceFields)
7952 // the following code would fix the issue (a replacement for the code above this comment):
7953 // if (bmtFP->NumInstanceFieldsOfSize[j] != 0 &&
7954 // (j != LOG2SLOT || bmtFP->NumInstanceFieldsOfSize[j] > bmtFP->NumInstanceGCPointerFields))
7960 // nothing to play with if there are no smaller fields
7961 if ((signed int) j < 0)
7963 // eventually go back and use the smaller field as filling
7966 CONSISTENCY_CHECK(bmtFP->NumInstanceFieldsOfSize[i] != 0);
7968 j = bmtFP->FirstInstanceFieldOfSize[i];
7970 // Avoid reordering of gcfields
7971 if (i == LOG2SLOT) {
7972 for ( ; j < bmtEnumFields->dwNumInstanceFields; j++) {
7973 if ((pFieldDescList[j].GetOffset_NoLogging() == FIELD_OFFSET_UNPLACED) &&
7974 ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i))
7978 // out of luck - can't reorder gc fields
7979 if (j >= bmtEnumFields->dwNumInstanceFields)
7984 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, 1 << i);
7986 pFieldDescList[j].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
7987 dwCumulativeInstanceFieldPos += (1 << i);
7989 // We've placed this field now, so there is now one less of this size field to place
7990 if (--bmtFP->NumInstanceFieldsOfSize[i] == 0)
7993 // We are done in this round if we haven't picked the first field
7994 if (bmtFP->FirstInstanceFieldOfSize[i] != j)
7997 // Update FirstInstanceFieldOfSize[i] to point to the next such field
7998 for (j = j+1; j < bmtEnumFields->dwNumInstanceFields; j++)
8000 // The log of the field size is stored in the method table
8001 if ((DWORD_PTR&)pFieldDescList[j].m_pMTOfEnclosingClass == (size_t)i)
8003 bmtFP->FirstInstanceFieldOfSize[i] = j;
8007 _ASSERTE(j < bmtEnumFields->dwNumInstanceFields);
8011 // Place fields, largest first
8012 for (i = MAX_LOG2_PRIMITIVE_FIELD_SIZE; (signed int) i >= 0; i--)
8014 if (bmtFP->NumInstanceFieldsOfSize[i] == 0)
8017 // Align instance fields if we aren't already
8018 #ifdef FEATURE_64BIT_ALIGNMENT
8019 DWORD dwDataAlignment = 1 << i;
8021 DWORD dwDataAlignment = min(1 << i, DATA_ALIGNMENT);
8023 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwDataAlignment);
8025 // Fields of this size start at the next available location
8026 bmtFP->InstanceFieldStart[i] = dwCumulativeInstanceFieldPos;
8027 dwCumulativeInstanceFieldPos += (bmtFP->NumInstanceFieldsOfSize[i] << i);
8029 // Reset counters for the loop after this one
8030 bmtFP->NumInstanceFieldsOfSize[i] = 0;
8034 // Make corrections to reserve space for GC Pointer Fields
8036 // The GC Pointers simply take up the top part of the region associated
8037 // with fields of that size (GC pointers can be 64 bit on certain systems)
8038 if (bmtFP->NumInstanceGCPointerFields)
8040 bmtFP->GCPointerFieldStart = bmtFP->InstanceFieldStart[LOG2SLOT] - dwOffsetBias;
8041 bmtFP->InstanceFieldStart[LOG2SLOT] = bmtFP->InstanceFieldStart[LOG2SLOT] + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT);
8042 bmtFP->NumInstanceGCPointerFields = 0; // reset to zero here, counts up as pointer slots are assigned below
8045 // Place instance fields - be careful not to place any already-placed fields
8046 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8048 DWORD dwFieldSize = (DWORD)(DWORD_PTR&)pFieldDescList[i].m_pMTOfEnclosingClass;
8051 dwOffset = pFieldDescList[i].GetOffset_NoLogging();
8053 // Don't place already-placed fields
8054 if ((dwOffset == FIELD_OFFSET_UNPLACED || dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR || dwOffset == FIELD_OFFSET_VALUE_CLASS))
8056 if (dwOffset == FIELD_OFFSET_UNPLACED_GC_PTR)
8058 pFieldDescList[i].SetOffset(bmtFP->GCPointerFieldStart + (bmtFP->NumInstanceGCPointerFields << LOG2SLOT));
8059 bmtFP->NumInstanceGCPointerFields++;
8061 else if (pFieldDescList[i].IsByValue() == FALSE) // it's a regular field
8063 pFieldDescList[i].SetOffset(bmtFP->InstanceFieldStart[dwFieldSize] + (bmtFP->NumInstanceFieldsOfSize[dwFieldSize] << dwFieldSize) - dwOffsetBias);
8064 bmtFP->NumInstanceFieldsOfSize[dwFieldSize]++;
8069 DWORD dwNumGCPointerSeries;
8070 // Save Number of pointer series
8071 if (bmtFP->NumInstanceGCPointerFields)
8072 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries + 1;
8074 dwNumGCPointerSeries = bmtParent->NumParentPointerSeries;
8076 // Place by value class fields last
8077 // Update the number of GC pointer series
8078 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
8080 if (pFieldDescList[i].IsByValue())
8082 MethodTable * pByValueMT = pByValueClassCache[i];
8084 // value classes could have GC pointers in them, which need to be pointer-size aligned
8085 // so do this if it has not been done already
8087 #if !defined(_WIN64) && (DATA_ALIGNMENT > 4)
8088 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos,
8089 (pByValueMT->GetNumInstanceFieldBytes() >= DATA_ALIGNMENT) ? DATA_ALIGNMENT : sizeof(void*));
8090 #else // !(!defined(_WIN64) && (DATA_ALIGNMENT > 4))
8091 #ifdef FEATURE_64BIT_ALIGNMENT
8092 if (pByValueMT->RequiresAlign8())
8093 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, 8);
8095 #endif // FEATURE_64BIT_ALIGNMENT
8096 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, sizeof(void*));
8097 #endif // !(!defined(_WIN64) && (DATA_ALIGNMENT > 4))
8099 pFieldDescList[i].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias);
8100 dwCumulativeInstanceFieldPos += pByValueMT->GetAlignedNumInstanceFieldBytes();
8102 // Add pointer series for by-value classes
8103 dwNumGCPointerSeries += pByValueMT->ContainsPointers() ?
8104 (DWORD)CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries() : 0;
8109 DWORD dwNumInstanceFieldBytes = dwCumulativeInstanceFieldPos - dwOffsetBias;
8113 // Like C++ we enforce that there can be no 0 length structures.
8114 // Thus for a value class with no fields, we 'pad' the length to be 1
8115 if (dwNumInstanceFieldBytes == 0)
8116 dwNumInstanceFieldBytes = 1;
8118 // The JITs like to copy full machine words,
8119 // so if the size is bigger than a void* round it up to minAlign
8120 // and if the size is smaller than void* round it up to next power of two
8123 #ifdef FEATURE_64BIT_ALIGNMENT
8124 if (GetHalfBakedClass()->IsAlign8Candidate()) {
8128 #endif // FEATURE_64BIT_ALIGNMENT
8129 if (dwNumInstanceFieldBytes > sizeof(void*)) {
8130 minAlign = sizeof(void*);
8134 while (minAlign < dwNumInstanceFieldBytes)
8138 dwNumInstanceFieldBytes = (dwNumInstanceFieldBytes + minAlign-1) & ~(minAlign-1);
8141 if (dwNumInstanceFieldBytes > FIELD_OFFSET_LAST_REAL_OFFSET) {
8142 BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
8145 bmtFP->NumInstanceFieldBytes = dwNumInstanceFieldBytes;
8147 bmtFP->NumGCPointerSeries = dwNumGCPointerSeries;
8149 //===============================================================
8150 // END: Place instance fields
8151 //===============================================================
8154 //*******************************************************************************
8155 // this accesses the field size which is temporarily stored in m_pMTOfEnclosingClass
8156 // during class loading. Don't use any other time
8157 DWORD MethodTableBuilder::GetFieldSize(FieldDesc *pFD)
8159 STATIC_CONTRACT_NOTHROW;
8160 STATIC_CONTRACT_GC_NOTRIGGER;
8161 STATIC_CONTRACT_FORBID_FAULT;
8163 // We should only be calling this while this class is being built.
8164 _ASSERTE(GetHalfBakedMethodTable() == 0);
8165 BAD_FORMAT_NOTHROW_ASSERT(! pFD->IsByValue() || HasExplicitFieldOffsetLayout());
8167 if (pFD->IsByValue())
8168 return (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass);
8169 return (1 << (DWORD)(DWORD_PTR&)(pFD->m_pMTOfEnclosingClass));
8172 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
8173 // checks whether the struct is enregisterable.
8174 void MethodTableBuilder::SystemVAmd64CheckForPassStructInRegister()
8176 STANDARD_VM_CONTRACT;
8178 // This method should be called for valuetypes only
8179 _ASSERTE(IsValueClass());
8181 TypeHandle th(GetHalfBakedMethodTable());
8183 if (th.IsTypeDesc())
8185 // Not an enregisterable managed structure.
8189 DWORD totalStructSize = bmtFP->NumInstanceFieldBytes;
8191 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8192 // pass through stack
8193 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8195 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8196 this->GetDebugClassName(), totalStructSize));
8200 const bool useNativeLayout = false;
8201 // Iterate through the fields and make sure they meet requirements to pass in registers
8202 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8203 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout))
8205 // All the above tests passed. It's registers passed struct!
8206 GetHalfBakedMethodTable()->SetRegPassedStruct();
8208 StoreEightByteClassification(&helper);
8212 // checks whether the struct is enregisterable.
8213 void MethodTableBuilder::SystemVAmd64CheckForPassNativeStructInRegister()
8215 STANDARD_VM_CONTRACT;
8216 DWORD totalStructSize = 0;
8218 // If not a native value type, return.
8219 if (!IsValueClass())
8224 totalStructSize = GetLayoutInfo()->GetNativeSize();
8226 // If num of bytes for the fields is bigger than CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS
8227 // pass through stack
8228 if (totalStructSize > CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
8230 LOG((LF_JIT, LL_EVERYTHING, "**** SystemVAmd64CheckForPassNativeStructInRegister: struct %s is too big to pass in registers (%d bytes)\n",
8231 this->GetDebugClassName(), totalStructSize));
8235 _ASSERTE(HasLayout());
8237 // Classify the native layout for this struct.
8238 const bool useNativeLayout = true;
8239 // Iterate through the fields and make sure they meet requirements to pass in registers
8240 SystemVStructRegisterPassingHelper helper((unsigned int)totalStructSize);
8241 if (GetHalfBakedMethodTable()->ClassifyEightBytes(&helper, 0, 0, useNativeLayout))
8243 GetLayoutInfo()->SetNativeStructPassedInRegisters();
8247 // Store the eightbyte classification into the EEClass
8248 void MethodTableBuilder::StoreEightByteClassification(SystemVStructRegisterPassingHelper* helper)
8250 EEClass* eeClass = GetHalfBakedMethodTable()->GetClass();
8251 LoaderAllocator* pAllocator = MethodTableBuilder::GetLoaderAllocator();
8252 AllocMemTracker* pamTracker = MethodTableBuilder::GetMemTracker();
8253 EnsureOptionalFieldsAreAllocated(eeClass, pamTracker, pAllocator->GetLowFrequencyHeap());
8254 eeClass->SetEightByteClassification(helper->eightByteCount, helper->eightByteClassifications, helper->eightByteSizes);
8257 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
8259 //---------------------------------------------------------------------------------------
8261 // make sure that no object fields are overlapped incorrectly and define the
8262 // GC pointer series for the class. We are assuming that this class will always be laid out within
8263 // its enclosing class by the compiler in such a way that offset 0 will be the correct alignment
8264 // for object ref fields so we don't need to try to align it
8267 MethodTableBuilder::HandleExplicitLayout(
8268 MethodTable ** pByValueClassCache)
8270 STANDARD_VM_CONTRACT;
8273 // Instance slice size is the total size of an instance, and is calculated as
8274 // the field whose offset and size add to the greatest number.
8275 UINT instanceSliceSize = 0;
8276 DWORD firstObjectOverlapOffset = ((DWORD)(-1));
8280 for (i = 0; i < bmtMetaData->cFields; i++)
8282 FieldDesc *pFD = bmtMFDescs->ppFieldDescList[i];
8283 if (pFD == NULL || pFD->IsStatic())
8288 UINT fieldExtent = 0;
8289 if (!ClrSafeInt<UINT>::addition(pFD->GetOffset_NoLogging(), GetFieldSize(pFD), fieldExtent))
8291 BuildMethodTableThrowException(COR_E_OVERFLOW);
8294 if (fieldExtent > instanceSliceSize)
8296 instanceSliceSize = fieldExtent;
8301 PREFIX_ASSUME(sizeof(BYTE) == 1);
8302 BYTE *pFieldLayout = (BYTE*) qb.AllocThrows(instanceSliceSize * sizeof(BYTE));
8303 for (i=0; i < instanceSliceSize; i++)
8305 pFieldLayout[i] = empty;
8308 // go through each field and look for invalid layout
8309 // (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to
8310 // close security holes.)
8312 // This is what we implment:
8314 // 1. Verify that every OREF is on a valid alignment
8315 // 2. Verify that OREFs only overlap with other OREFs.
8316 // 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
8317 // 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
8319 char emptyObject[sizeof(void*)];
8320 char isObject[sizeof(void*)];
8321 for (i = 0; i < sizeof(void*); i++)
8323 emptyObject[i] = empty;
8328 ExplicitClassTrust explicitClassTrust;
8330 UINT valueClassCacheIndex = ((UINT)(-1));
8332 FieldDesc * pFD = NULL;
8333 for (i = 0; i < bmtMetaData->cFields; i++)
8335 // Note about this loop body:
8337 // This loop is coded to make it as hard as possible to allow a field to be trusted when it shouldn't.
8339 // Every path in this loop body must lead to an explicit decision as to whether the field nonoverlaps,
8340 // overlaps in a verifiable fashion, overlaps in a nonverifiable fashion or overlaps in a completely illegal fashion.
8342 // It must call fieldTrust.SetTrust() with the appropriate result. If you don't call it, fieldTrust's destructor
8343 // will intentionally default to kNone and mark the entire class illegal.
8345 // If your result is anything but kNone (class is illegal), you must also explicitly "continue" the loop.
8346 // There is a "break" at end of this loop body that will abort the loop if you don't do this. And
8347 // if you don't finish iterating through all the fields, this function will automatically mark the entire
8348 // class illegal. This rule is a vestige of an earlier version of this function.
8350 // This object's dtor will aggregate the trust decision for this field into the trust level for the class as a whole.
8351 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8353 pFD = bmtMFDescs->ppFieldDescList[i];
8354 if (pFD == NULL || pFD->IsStatic())
8356 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8360 // "i" indexes all fields, valueClassCacheIndex indexes non-static fields only. Don't get them confused!
8361 valueClassCacheIndex++;
8363 if (CorTypeInfo::IsObjRef(pFD->GetFieldType()))
8365 // Check that the ref offset is pointer aligned
8366 if ((pFD->GetOffset_NoLogging() & ((ULONG)sizeof(OBJECTREF) - 1)) != 0)
8368 badOffset = pFD->GetOffset_NoLogging();
8369 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8371 // If we got here, OREF field was not pointer aligned. THROW.
8374 // check if overlaps another object
8375 if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
8377 // If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
8378 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8380 if (firstObjectOverlapOffset == ((DWORD)(-1)))
8382 firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
8387 // check if is empty at this point
8388 if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
8390 // If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
8391 memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
8392 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8396 // If we got here, the OREF overlaps a non-OREF. THROW.
8397 badOffset = pFD->GetOffset_NoLogging();
8398 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8404 if (pFD->IsByValue())
8406 MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
8407 if (pByValueMT->ContainsPointers())
8409 if ((pFD->GetOffset_NoLogging() & ((ULONG)sizeof(void*) - 1)) == 0)
8411 ExplicitFieldTrust::TrustLevel trust;
8412 DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
8413 trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
8414 fieldTrust.SetTrust(trust);
8415 if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
8417 if (firstObjectOverlapOffset == ((DWORD)(-1)))
8419 firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
8423 if (trust != ExplicitFieldTrust::kNone)
8429 // If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
8430 badOffset = pFD->GetOffset_NoLogging();
8434 // If we got here, then a valuetype containing an OREF was misaligned.
8435 badOffset = pFD->GetOffset_NoLogging();
8436 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8439 // no pointers so fall through to do standard checking
8440 fieldSize = pByValueMT->GetNumInstanceFieldBytes();
8444 // field size temporarily stored in pInterface field
8445 fieldSize = GetFieldSize(pFD);
8448 // If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
8449 // Look for any orefs under this field
8451 if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
8453 // If we have a nonoref in the range then we are doing an overlay
8454 if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
8456 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8460 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8462 memset((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize);
8466 // If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
8467 // on top of an OREF. THROW.
8468 badOffset = (UINT)(loc - pFieldLayout);
8469 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8471 // anything else is an error
8474 // We have to comment out this assert because otherwise, the compiler refuses to build because the _ASSERT is unreachable
8475 // (Thanks for nothing, compiler, that's what the assert is trying to enforce!) But the intent of the assert is correct.
8476 //_ASSERTE(!"You aren't supposed to be here. Some path inside the loop body did not execute an explicit break or continue.");
8479 // If we got here, some code above failed to execute an explicit "break" or "continue." This is a bug! To be safe,
8480 // we will put a catchall "break" here which will cause the typeload to abort (albeit with a probably misleading
8485 // We only break out of the loop above if we detected an error.
8486 if (i < bmtMetaData->cFields || !explicitClassTrust.IsLegal())
8488 ThrowFieldLayoutError(GetCl(),
8491 IDS_CLASSLOAD_EXPLICIT_LAYOUT);
8494 if (!explicitClassTrust.IsNonOverLayed())
8496 SetHasOverLayedFields();
8499 if (IsBlittable() || IsManagedSequential())
8501 // Bug 849333: We shouldn't update "bmtFP->NumInstanceFieldBytes"
8502 // for Blittable/ManagedSequential types. As this will break backward compatiblity
8503 // for the size of types that return true for HasExplicitFieldOffsetLayout()
8508 FindPointerSeriesExplicit(instanceSliceSize, pFieldLayout);
8510 // Fixup the offset to include parent as current offsets are relative to instance slice
8511 // Could do this earlier, but it's just easier to assume instance relative for most
8512 // of the earlier calculations
8514 // Instance fields start right after the parent
8515 S_UINT32 dwInstanceSliceOffset = S_UINT32(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0);
8516 if (bmtGCSeries->numSeries != 0)
8518 dwInstanceSliceOffset.AlignUp(sizeof(void*));
8520 if (dwInstanceSliceOffset.IsOverflow())
8522 // addition overflow or cast truncation
8523 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8526 S_UINT32 numInstanceFieldBytes = dwInstanceSliceOffset + S_UINT32(instanceSliceSize);
8531 if (FAILED(GetMDImport()->GetClassTotalSize(GetCl(), &clstotalsize)))
8536 if (clstotalsize != 0)
8538 // size must be large enough to accomodate layout. If not, we use the layout size instead.
8539 if (!numInstanceFieldBytes.IsOverflow() && clstotalsize >= numInstanceFieldBytes.Value())
8541 numInstanceFieldBytes = S_UINT32(clstotalsize);
8546 // The GC requires that all valuetypes containing orefs be sized to a multiple of sizeof(void*).
8547 if (bmtGCSeries->numSeries != 0)
8549 numInstanceFieldBytes.AlignUp(sizeof(void*));
8551 if (numInstanceFieldBytes.IsOverflow())
8553 // addition overflow or cast truncation
8554 BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
8557 // Set the total size
8558 bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes.Value();
8560 for (i = 0; i < bmtMetaData->cFields; i++)
8562 FieldDesc * pTempFD = bmtMFDescs->ppFieldDescList[i];
8563 if ((pTempFD == NULL) || pTempFD->IsStatic())
8567 HRESULT hr = pTempFD->SetOffset(pTempFD->GetOffset_NoLogging() + dwInstanceSliceOffset.Value());
8570 BuildMethodTableThrowException(hr, *bmtError);
8573 } // MethodTableBuilder::HandleExplicitLayout
8575 //*******************************************************************************
8576 // make sure that no object fields are overlapped incorrectly, returns S_FALSE if
8577 // there overlap but nothing illegal, S_OK if there is no overlap
8578 /*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
8580 STANDARD_VM_CONTRACT;
8583 *pFirstObjectOverlapOffset = (DWORD)(-1);
8585 // Build a layout of the value class. Don't know the sizes of all the fields easily, but
8586 // do know a) vc is already consistent so don't need to check it's overlaps and
8587 // b) size and location of all objectrefs. So build it by setting all non-oref
8588 // then fill in the orefs later
8589 UINT fieldSize = pMT->GetNumInstanceFieldBytes();
8591 BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));
8593 memset((void*)vcLayout, nonoref, fieldSize);
8595 // use pointer series to locate the orefs
8597 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
8598 CGCDescSeries *pSeries = map->GetLowestSeries();
8600 for (SIZE_T j = 0; j < map->GetNumSeries(); j++)
8602 CONSISTENCY_CHECK(pSeries <= map->GetHighestSeries());
8604 memset((void*)&vcLayout[pSeries->GetSeriesOffset()-sizeof(Object)], oref, pSeries->GetSeriesSize() + pMT->GetBaseSize());
8609 ExplicitClassTrust explicitClassTrust;
8611 for (UINT i=0; i < fieldSize; i++) {
8613 ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
8615 if (vcLayout[i] == oref) {
8616 switch (pFieldLayout[i]) {
8619 pFieldLayout[i] = oref;
8620 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8623 // oref <--> nonoref
8625 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8630 fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
8631 if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
8633 *pFirstObjectOverlapOffset = (DWORD)i;
8638 _ASSERTE(!"Can't get here.");
8640 } else if (vcLayout[i] == nonoref) {
8641 switch (pFieldLayout[i]) {
8642 // nonoref <--> empty
8644 pFieldLayout[i] = nonoref;
8645 fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
8648 // nonoref <--> nonoref
8650 fieldTrust.SetTrust(ExplicitFieldTrust::kVerifiable);
8653 // nonoref <--> oref
8655 fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
8659 _ASSERTE(!"Can't get here.");
8662 _ASSERTE(!"Can't get here.");
8666 return explicitClassTrust.GetTrustLevel();
8675 //*******************************************************************************
8676 void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
8679 STANDARD_VM_CONTRACT;
8682 // Allocate a structure to track the series. We know that the worst case is a
8683 // ref-non-ref-non, and since only ref series are recorded and non-ref series
8684 // are skipped, the max number of series is total instance size / 2 / sizeof(ref).
8685 // But watch out for the case where we have e.g. an instanceSlizeSize of 4.
8686 DWORD sz = (instanceSliceSize + (2 * sizeof(OBJECTREF)) - 1);
8687 bmtGCSeries->pSeries = new bmtGCSeriesInfo::Series[sz/2/sizeof(OBJECTREF)];
8689 BYTE *loc = pFieldLayout;
8690 BYTE *layoutEnd = pFieldLayout + instanceSliceSize;
8691 while (loc < layoutEnd)
8693 // Find the next OREF entry.
8694 loc = (BYTE*)memchr((void*)loc, oref, layoutEnd-loc);
8700 // Find the next non-OREF entry
8702 while(cur < layoutEnd && *cur == oref)
8707 // so we have a GC series at loc for cur-loc bytes
8708 bmtGCSeries->pSeries[bmtGCSeries->numSeries].offset = (DWORD)(loc - pFieldLayout);
8709 bmtGCSeries->pSeries[bmtGCSeries->numSeries].len = (DWORD)(cur - loc);
8711 CONSISTENCY_CHECK(IS_ALIGNED(cur - loc, sizeof(size_t)));
8713 bmtGCSeries->numSeries++;
8717 // Calculate the total series count including the parent, if a parent exists.
8719 bmtFP->NumGCPointerSeries = bmtParent->NumParentPointerSeries + bmtGCSeries->numSeries;
8723 //*******************************************************************************
8725 MethodTableBuilder::HandleGCForExplicitLayout()
8727 STANDARD_VM_CONTRACT;
8729 MethodTable *pMT = GetHalfBakedMethodTable();
8731 #ifdef FEATURE_COLLECTIBLE_TYPES
8732 if (bmtFP->NumGCPointerSeries == 0 && pMT->Collectible())
8734 // For collectible types, insert empty gc series
8735 CGCDescSeries *pSeries;
8737 CGCDesc::Init( (PVOID) pMT, 1);
8738 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
8739 pSeries->SetSeriesSize( (size_t) (0) - (size_t) pMT->GetBaseSize());
8740 pSeries->SetSeriesOffset(sizeof(Object));
8743 #endif // FEATURE_COLLECTIBLE_TYPES
8744 if (bmtFP->NumGCPointerSeries != 0)
8746 pMT->SetContainsPointers();
8748 // Copy the pointer series map from the parent
8749 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
8750 if (bmtParent->NumParentPointerSeries != 0)
8752 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
8753 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize), (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize), ParentGCSize - sizeof(UINT) );
8757 UINT32 dwInstanceSliceOffset = AlignUp(HasParent() ? GetParentMethodTable()->GetNumInstanceFieldBytes() : 0, sizeof(void*));
8759 // Build the pointer series map for this pointers in this instance
8760 CGCDescSeries *pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
8761 for (UINT i=0; i < bmtGCSeries->numSeries; i++) {
8762 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
8763 BAD_FORMAT_NOTHROW_ASSERT(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
8765 pSeries->SetSeriesSize( (size_t) bmtGCSeries->pSeries[i].len - (size_t) pMT->GetBaseSize() );
8766 pSeries->SetSeriesOffset(bmtGCSeries->pSeries[i].offset + sizeof(Object) + dwInstanceSliceOffset);
8771 delete [] bmtGCSeries->pSeries;
8772 bmtGCSeries->pSeries = NULL;
8773 } // MethodTableBuilder::HandleGCForExplicitLayout
8779 MethodTable **pArray,
8780 DWORD nArraySizeMax,
8781 DWORD *pNumAssigned)
8783 LIMITED_METHOD_CONTRACT;
8785 for (DWORD j = 0; j < (*pNumAssigned); j++)
8787 if (pNew == pArray[j])
8790 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found duplicate interface %s (%p) at position %d out of %d\n", pNew->GetDebugClassName(), pNew, j, *pNumAssigned));
8792 return pNew->HasInstantiation(); // bail out - we found a duplicate instantiated interface
8797 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));
8801 if (*pNumAssigned >= nArraySizeMax)
8803 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Found interface %s (%p) exceeding size %d of interface array\n", pNew->GetDebugClassName(), pNew, nArraySizeMax));
8806 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Inserting interface %s (%p) at position %d\n", pNew->GetDebugClassName(), pNew, *pNumAssigned));
8807 pArray[(*pNumAssigned)++] = pNew;
8809 } // InsertMethodTable
8812 //*******************************************************************************
8813 // --------------------------------------------------------------------------------------------
8814 // Copy virtual slots inherited from parent:
8816 // In types created at runtime, inherited virtual slots are initialized using approximate parent
8817 // during method table building. This method will update them based on the exact parent.
8818 // In types loaded from NGen image, inherited virtual slots from cross-module parents are not
8819 // initialized. This method will initialize them based on the actually loaded exact parent
8822 void MethodTableBuilder::CopyExactParentSlots(MethodTable *pMT, MethodTable *pApproxParentMT)
8827 PRECONDITION(CheckPointer(pMT));
8831 if (pMT->IsZapped())
8834 DWORD nParentVirtuals = pMT->GetNumParentVirtuals();
8835 if (nParentVirtuals == 0)
8838 _ASSERTE(nParentVirtuals == pApproxParentMT->GetNumVirtuals());
8841 // Update all inherited virtual slots to match exact parent
8844 if (!pMT->IsCanonicalMethodTable())
8847 // Copy all slots for non-canonical methodtables to avoid touching methoddescs.
8849 MethodTable * pCanonMT = pMT->GetCanonicalMethodTable();
8851 // Do not write into vtable chunks shared with parent. It would introduce race
8852 // with code:MethodDesc::SetStableEntryPointInterlocked.
8854 // Non-canonical method tables either share everything or nothing so it is sufficient to check
8855 // just the first indirection to detect sharing.
8856 if (pMT->GetVtableIndirections()[0].GetValueMaybeNull() != pCanonMT->GetVtableIndirections()[0].GetValueMaybeNull())
8858 for (DWORD i = 0; i < nParentVirtuals; i++)
8860 PCODE target = pCanonMT->GetRestoredSlot(i);
8861 pMT->SetSlot(i, target);
8867 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
8869 MethodTable * pParentMT = pMT->GetParentMethodTable();
8871 for (DWORD i = 0; i < nParentVirtuals; i++)
8873 // fix up wrongly-inherited method descriptors
8874 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
8875 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
8877 if (pMD->GetMethodTable() == pMT)
8880 // We need to re-inherit this slot from the exact parent.
8882 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(i);
8883 if (pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() == pApproxParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull())
8885 // The slot lives in a chunk shared from the approximate parent MT
8886 // If so, we need to change to share the chunk from the exact parent MT
8888 #ifdef FEATURE_PREJIT
8889 _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule(), Module::GetPreferredZapModuleForMethodTable(pMT)));
8891 _ASSERTE(MethodTable::CanShareVtableChunksFrom(pParentMT, pMT->GetLoaderModule()));
8894 pMT->GetVtableIndirections()[indirectionIndex].SetValueMaybeNull(pParentMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull());
8896 i = MethodTable::GetEndSlotForVtableIndirection(indirectionIndex, nParentVirtuals) - 1;
8900 // The slot lives in an unshared chunk. We need to update the slot contents
8901 PCODE target = pParentMT->GetRestoredSlot(i);
8902 pMT->SetSlot(i, target);
8905 } // MethodTableBuilder::CopyExactParentSlots
8907 //*******************************************************************************
8910 MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
8915 PRECONDITION(CheckPointer(pMT));
8919 BOOL hasInstantiatedInterfaces = FALSE;
8920 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
8923 if (it.GetInterface()->HasInstantiation())
8925 hasInstantiatedInterfaces = TRUE;
8930 // If we have some instantiated interfaces, then we have lots more work to do...
8932 // In the worst case we have to use the metadata to
8933 // (a) load the exact interfaces and determine the order in which they
8934 // go. We do those by re-running the interface layout algorithm
8935 // and using metadata-comparisons to place interfaces in the list.
8936 // (b) do a check to see if any ambiguity in the interface dispatch map is introduced
8937 // by the instantiation
8938 // See code:#LoadExactInterfaceMap_Algorithm2
8940 // However, we can do something simpler: we just use
8941 // the loaded interface method tables to determine ordering. This can be done
8942 // if there are no duplicate instantiated interfaces in the interface
8944 // See code:#LoadExactInterfaceMap_Algorithm1.
8946 if (!hasInstantiatedInterfaces)
8952 TypeHandle thisTH(pMT);
8953 SigTypeContext typeContext(thisTH);
8954 MethodTable *pParentMT = pMT->GetParentMethodTable();
8956 //#LoadExactInterfaceMap_Algorithm1
8957 // Exact interface instantiation loading TECHNIQUE 1.
8958 // (a) For interfaces inherited from an instantiated parent class, just copy down from exact parent
8959 // (b) Grab newly declared interfaces by loading and then copying down all their inherited parents
8960 // (c) But check for any exact duplicates along the way
8961 // (d) If no duplicates then we can use the computed interface map we've created
8962 // (e) If duplicates found then use the slow metadata-based technique code:#LoadExactInterfaceMap_Algorithm2
8963 DWORD nInterfacesCount = pMT->GetNumInterfaces();
8964 MethodTable **pExactMTs = (MethodTable**) _alloca(sizeof(MethodTable *) * nInterfacesCount);
8965 DWORD nAssigned = 0;
8966 BOOL duplicates = false;
8967 if (pParentMT != NULL)
8969 MethodTable::InterfaceMapIterator parentIt = pParentMT->IterateInterfaceMap();
8970 while (parentIt.Next())
8972 duplicates |= InsertMethodTable(parentIt.GetInterface(), pExactMTs, nInterfacesCount, &nAssigned);
8975 InterfaceImplEnum ie(pMT->GetModule(), pMT->GetCl(), NULL);
8976 while ((hr = ie.Next()) == S_OK)
8978 MethodTable *pNewIntfMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(),
8981 ClassLoader::ThrowIfNotFound,
8982 ClassLoader::FailIfUninstDefOrRef,
8983 ClassLoader::LoadTypes,
8984 CLASS_LOAD_EXACTPARENTS,
8985 TRUE).GetMethodTable();
8987 duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);
8988 MethodTable::InterfaceMapIterator intIt = pNewIntfMT->IterateInterfaceMap();
8989 while (intIt.Next())
8991 duplicates |= InsertMethodTable(intIt.GetInterface(), pExactMTs, nInterfacesCount, &nAssigned);
8996 pMT->GetAssembly()->ThrowTypeLoadException(pMT->GetMDImport(), pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
8999 duplicates |= EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AlwaysUseMetadataInterfaceMapLayout, FALSE);
9001 //#InjectInterfaceDuplicates_LoadExactInterfaceMap
9002 // If we are injecting duplicates also for non-generic interfaces in check builds, we have to use
9003 // algorithm code:#LoadExactInterfaceMap_Algorithm2.
9004 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
9005 duplicates |= pMT->Debug_HasInjectedInterfaceDuplicates();
9007 CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces()));
9010 //#LoadExactInterfaceMap_Algorithm2
9011 // Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to
9012 // appear in the interface map! This may not be an error: if the duplicates
9013 // were ones that arose because because of inheritance from
9014 // a parent type then we accept that. For example
9015 // class C<T> : I<T>
9016 // class D<T> : C<T>, I<string>
9017 // is acceptable even when loading D<string>. Note that in such a case
9018 // there will be two entries for I<string> in the final interface map for D<string>.
9019 // For dispatch the mappings in D take precedence.
9021 // However we consider it an error if there is real ambiguity within
9022 // the interface definitions within the one class, e.g.
9023 // class E<T> : I<T>, I<string>
9024 // In this situation it is not defined how to dispatch calls to I<string>: would
9025 // we use the bindings for I<T> or I<string>?
9027 // Because we may had duplicates the interface map we created above may not
9028 // be the correct one: for example for D<string> above we would have computed
9029 // a map with only one entry. This is incorrect: an exact instantiation's interface
9030 // map must have entries that match the ordering of the interface map in the generic case
9031 // (this is because code:#InterfaceMap_SupersetOfParent).
9033 // So, in order to determine how to place the interfaces we need go back to
9034 // the metadata. We also do this to check if the presence of duplicates
9035 // has caused any potential ambiguity, i.e. the E<string> case above.
9037 // First we do a GetCheckpoint for the thread-based allocator. ExpandExactInheritedInterfaces allocates substitution chains
9038 // on the thread allocator rather than on the stack.
9039 Thread * pThread = GetThread();
9040 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
9042 // ***********************************************************
9043 // ****** This must be consistent with code:ExpandApproxInterface etc. *******
9045 // The correlation to ExpandApproxInterfaces etc. simply drops out by how we
9046 // traverse interfaces.
9047 // ***********************************************************
9049 bmtExactInterfaceInfo bmtExactInterface;
9050 bmtExactInterface.pInterfaceSubstitution = new (&pThread->m_MarshalAlloc) Substitution[pMT->GetNumInterfaces()];
9051 bmtExactInterface.pExactMTs = pExactMTs;
9052 bmtExactInterface.nAssigned = 0;
9053 bmtExactInterface.typeContext = typeContext;
9055 // Do the interfaces inherited from a parent class
9056 if ((pParentMT != NULL) && (pParentMT->GetNumInterfaces() > 0))
9058 Substitution * pParentSubstForTypeLoad = new (&pThread->m_MarshalAlloc) Substitution(
9059 pMT->GetSubstitutionForParent(NULL));
9060 Substitution * pParentSubstForComparing = new (&pThread->m_MarshalAlloc) Substitution(
9061 pMT->GetSubstitutionForParent(NULL));
9062 ExpandExactInheritedInterfaces(
9065 pParentSubstForTypeLoad,
9066 pParentSubstForComparing);
9069 //#ExactInterfaceMap_SupersetOfParent
9070 // Check that parent's interface map is subset of this interface map
9071 // See code:#InterfaceMap_SupersetOfParent
9073 _ASSERTE(pParentMT->GetNumInterfaces() == bmtExactInterface.nAssigned);
9075 MethodTable::InterfaceMapIterator parentInterfacesIterator = pParentMT->IterateInterfaceMap();
9076 UINT32 nInterfaceIndex = 0;
9077 while (parentInterfacesIterator.Next())
9079 if (pMT->IsSharedByGenericInstantiations())
9080 { // The type is a canonical instantiation (contains _Canon)
9081 // The interface instantiations of parent can be different (see
9082 // code:#InterfaceMap_CanonicalSupersetOfParent), therefore we cannot compare
9084 _ASSERTE(parentInterfacesIterator.GetInterfaceInfo()->GetApproxMethodTable(pParentMT->GetLoaderModule())->HasSameTypeDefAs(
9085 bmtExactInterface.pExactMTs[nInterfaceIndex]));
9088 { // It is not canonical instantiation, we can compare MethodTables
9089 _ASSERTE(parentInterfacesIterator.GetInterface() == bmtExactInterface.pExactMTs[nInterfaceIndex]);
9093 _ASSERTE(nInterfaceIndex == bmtExactInterface.nAssigned);
9097 // If there are any __Canon instances in the type argument list, then we defer the
9098 // ambiguity checking until an exact instantiation.
9099 if (!pMT->IsSharedByGenericInstantiations())
9101 // There are no __Canon types in the instantiation, so do ambiguity check.
9102 bmtInterfaceAmbiguityCheckInfo bmtCheckInfo;
9103 bmtCheckInfo.pMT = pMT;
9104 bmtCheckInfo.ppInterfaceSubstitutionChains = new (&pThread->m_MarshalAlloc) Substitution *[pMT->GetNumInterfaces()];
9105 bmtCheckInfo.ppExactDeclaredInterfaces = new (&pThread->m_MarshalAlloc) MethodTable *[pMT->GetNumInterfaces()];
9106 bmtCheckInfo.nAssigned = 0;
9107 bmtCheckInfo.typeContext = typeContext;
9108 MethodTableBuilder::InterfacesAmbiguityCheck(&bmtCheckInfo, pMT->GetModule(), pMT->GetCl(), NULL);
9111 // OK, there is no ambiguity amongst the instantiated interfaces declared on this class.
9112 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9118 COMMA_INDEBUG(pMT));
9119 CONSISTENCY_CHECK(bmtExactInterface.nAssigned == pMT->GetNumInterfaces());
9121 // We cannot process interface duplicates on types with __Canon. The duplicates are processed on
9123 if (!pMT->IsSharedByGenericInstantiations())
9125 // Process all pairs of duplicates in the interface map:
9126 // i.e. If there are 3 duplicates of the same interface at indexes: i1, i2 and i3, then
9127 // process pairs of indexes [i1,i2], [i1,i3] and [i2,i3].
9128 // - Update 'declared on type' flag for those interfaces which duplicate is 'declared on type'
9129 // - Check interface method implementation ambiguity code:#DuplicateInterface_MethodAmbiguity
9130 for (DWORD nOriginalIndex = 0; nOriginalIndex < nInterfacesCount; nOriginalIndex++)
9132 // Search for duplicates further in the interface map
9133 for (DWORD nDuplicateIndex = nOriginalIndex + 1; nDuplicateIndex < nInterfacesCount; nDuplicateIndex++)
9135 if (pExactMTs[nOriginalIndex] != pExactMTs[nDuplicateIndex])
9136 { // It's not a duplicate of original interface, skip it
9139 // We found a duplicate
9141 // Set 'declared on type' flag if either original or duplicate interface is
9142 // 'declared on type'
9143 if (pMT->IsInterfaceDeclaredOnClass(nOriginalIndex) ||
9144 pMT->IsInterfaceDeclaredOnClass(nDuplicateIndex))
9147 // Note that both checks are needed:
9149 // B<T,U> : A<T>, I<U>
9150 // C<T,U> : B<T,U>, I<T> // Reimplements interface from A<T>
9151 // After code:BuildMethodTableThrowing algorithm, this will happen:
9152 // B<int,int> will have interface map similar to B<T,U>:
9153 // I<int> ... not 'declared on type'
9154 // I<int> ... 'declared on type'
9155 // C<int,int> will have interface map similar to C<T,U>:
9156 // I<int> ... 'declared on type'
9157 // I<int> ... not 'declared on type'
9160 pMT->SetInterfaceDeclaredOnClass(nOriginalIndex);
9161 pMT->SetInterfaceDeclaredOnClass(nDuplicateIndex);
9164 //#DuplicateInterface_MethodAmbiguity
9166 // In the ideal world we would now check for interface method implementation
9167 // ambiguity in the instantiation, but that would be a technical breaking change
9168 // (against 2.0 RTM/SP1).
9169 // Therefore we ALLOW when interface method is implemented twice through this
9170 // original and duplicate interface.
9172 // This ambiguity pattern is therefore ALLOWED (can be expressed only in IL, not in C#):
9175 // A<T> : I<T> // abstract class
9176 // B<T,U> : A<T>, I<U>
9177 // void Print(T t) { ... }
9178 // void Print(U u) { ... }
9179 // Now B<int,int> has 2 implementations of I<int>.Print(int), while B<int,char> is
9180 // fine. Therefore an instantiation can introduce ambiguity.
9182 #if 0 // Removing this code for now as it is a technical breaking change (against CLR 2.0 RTM/SP1).
9183 // We might decide later that we want to take this breaking change.
9185 // Note that dispatch map entries are sorted by interface index and then interface
9186 // method slot index.
9188 DispatchMapTypeID originalTypeID = DispatchMapTypeID::InterfaceClassID(nOriginalIndex);
9189 DispatchMap::EncodedMapIterator originalIt(pMT);
9190 // Find first entry for original interface
9191 while (originalIt.IsValid())
9193 DispatchMapEntry *pEntry = originalIt.Entry();
9194 if (pEntry->GetTypeID().ToUINT32() >= originalTypeID.ToUINT32())
9195 { // Found the place where original interface entries should be (dispatch map is
9202 DispatchMapTypeID duplicateTypeID = DispatchMapTypeID::InterfaceClassID(nDuplicateIndex);
9203 DispatchMap::EncodedMapIterator duplicateIt(pMT);
9204 // Find first entry for duplicate interface
9205 while (duplicateIt.IsValid())
9207 DispatchMapEntry *pEntry = duplicateIt.Entry();
9208 if (pEntry->GetTypeID().ToUINT32() >= duplicateTypeID.ToUINT32())
9209 { // Found the place where original interface entries should be (dispatch map is
9216 // Compare original and duplicate interface entries in the dispatch map if they contain
9217 // different implementation for the same interface method
9220 if (!originalIt.IsValid() || !duplicateIt.IsValid())
9221 { // We reached end of one dispatch map iterator
9224 DispatchMapEntry *pOriginalEntry = originalIt.Entry();
9225 if (pOriginalEntry->GetTypeID().ToUINT32() != originalTypeID.ToUINT32())
9226 { // We reached behind original interface entries
9229 DispatchMapEntry *pDuplicateEntry = duplicateIt.Entry();
9230 if (pDuplicateEntry->GetTypeID().ToUINT32() != duplicateTypeID.ToUINT32())
9231 { // We reached behind duplicate interface entries
9235 if (pOriginalEntry->GetSlotNumber() == pDuplicateEntry->GetSlotNumber())
9236 { // Found duplicate implementation of interface method
9237 if (pOriginalEntry->GetTargetSlotNumber() != pDuplicateEntry->GetTargetSlotNumber())
9238 { // Implementation of the slots is different
9239 bmtErrorInfo bmtError;
9241 bmtError.pModule = pMT->GetModule();
9242 bmtError.cl = pMT->GetCl();
9243 bmtError.resIDWhy = IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES;
9244 bmtError.szMethodNameForError = NULL;
9245 bmtError.pThrowable = NULL;
9247 MethodDesc *pMD = pMT->GetMethodDescForSlot(pDuplicateEntry->GetTargetSlotNumber());
9248 bmtError.dMethodDefInError = pMD->GetMemberDef();
9250 BuildMethodTableThrowException(COR_E_TYPELOAD, bmtError);
9252 // The method is implemented by the same slot on both interfaces (original and
9255 // Process next dispatch map entry
9260 // Move iterator representing smaller interface method slot index (the dispatch map
9261 // is sorted by slot indexes)
9262 if (pOriginalEntry->GetSlotNumber() < pDuplicateEntry->GetSlotNumber())
9267 _ASSERTE(pOriginalEntry->GetSlotNumber() > pDuplicateEntry->GetSlotNumber());
9272 // All duplicates of this original interface were processed
9274 // All pairs of duplicates in the interface map are processed
9277 // Duplicates in the interface map are resolved
9279 // OK, if we've got this far then pExactMTs should now hold the array of exact instantiated interfaces.
9280 MethodTable::InterfaceMapIterator thisIt = pMT->IterateInterfaceMap();
9282 while (thisIt.Next())
9285 MethodTable*pOldMT = thisIt.GetInterface();
9286 MethodTable *pNewMT = pExactMTs[i];
9287 CONSISTENCY_CHECK(pOldMT->HasSameTypeDefAs(pNewMT));
9289 thisIt.SetInterface(pExactMTs[i]);
9293 } // MethodTableBuilder::LoadExactInterfaceMap
9295 //*******************************************************************************
9297 MethodTableBuilder::ExpandExactInheritedInterfaces(
9298 bmtExactInterfaceInfo * bmtInfo,
9300 const Substitution * pSubstForTypeLoad,
9301 Substitution * pSubstForComparing)
9303 STANDARD_VM_CONTRACT;
9305 MethodTable *pParentMT = pMT->GetParentMethodTable();
9307 // Backup type's substitution chain for comparing interfaces
9308 Substitution substForComparingBackup = *pSubstForComparing;
9309 // Make type an open type for comparing interfaces
9310 *pSubstForComparing = Substitution();
9314 // Chain parent's substitution for exact type load
9315 Substitution * pParentSubstForTypeLoad = new (&GetThread()->m_MarshalAlloc) Substitution(
9316 pMT->GetSubstitutionForParent(pSubstForTypeLoad));
9318 // Chain parent's substitution for comparing interfaces (note that this type is temporarily
9319 // considered as open type)
9320 Substitution * pParentSubstForComparing = new (&GetThread()->m_MarshalAlloc) Substitution(
9321 pMT->GetSubstitutionForParent(pSubstForComparing));
9323 ExpandExactInheritedInterfaces(
9326 pParentSubstForTypeLoad,
9327 pParentSubstForComparing);
9329 ExpandExactDeclaredInterfaces(
9335 COMMA_INDEBUG(pMT));
9337 // Restore type's subsitution chain for comparing interfaces
9338 *pSubstForComparing = substForComparingBackup;
9339 } // MethodTableBuilder::ExpandExactInheritedInterfaces
9341 //*******************************************************************************
9344 MethodTableBuilder::ExpandExactDeclaredInterfaces(
9345 bmtExactInterfaceInfo * bmtInfo,
9348 const Substitution * pSubstForTypeLoad,
9349 Substitution * pSubstForComparing
9350 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9352 STANDARD_VM_CONTRACT;
9355 InterfaceImplEnum ie(pModule, typeDef, NULL);
9356 while ((hr = ie.Next()) == S_OK)
9358 MethodTable * pInterface = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
9361 &bmtInfo->typeContext,
9362 ClassLoader::ThrowIfNotFound,
9363 ClassLoader::FailIfUninstDefOrRef,
9364 ClassLoader::LoadTypes,
9365 CLASS_LOAD_EXACTPARENTS,
9367 pSubstForTypeLoad).GetMethodTable();
9369 Substitution ifaceSubstForTypeLoad(ie.CurrentToken(), pModule, pSubstForTypeLoad);
9370 Substitution ifaceSubstForComparing(ie.CurrentToken(), pModule, pSubstForComparing);
9371 ExpandExactInterface(
9374 &ifaceSubstForTypeLoad,
9375 &ifaceSubstForComparing
9376 COMMA_INDEBUG(dbg_pClassMT));
9380 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9382 } // MethodTableBuilder::ExpandExactDeclaredInterfaces
9384 //*******************************************************************************
9386 MethodTableBuilder::ExpandExactInterface(
9387 bmtExactInterfaceInfo * bmtInfo,
9388 MethodTable * pIntf,
9389 const Substitution * pSubstForTypeLoad_OnStack, // Allocated on stack!
9390 const Substitution * pSubstForComparing_OnStack // Allocated on stack!
9391 COMMA_INDEBUG(MethodTable * dbg_pClassMT))
9393 STANDARD_VM_CONTRACT;
9395 // ****** This must be consistent with code:MethodTableBuilder::ExpandApproxInterface ******
9397 // Is it already present according to the "generic" layout of the interfaces.
9398 // Note we use exactly the same algorithm as when we
9399 // determined the layout of the interface map for the "generic" version of the class.
9400 for (DWORD i = 0; i < bmtInfo->nAssigned; i++)
9402 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
9403 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9404 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtInfo->pExactMTs[i],
9406 &bmtInfo->pInterfaceSubstitution[i],
9407 pSubstForComparing_OnStack,
9411 //#InjectInterfaceDuplicates_ExactInterfaces
9412 // We will inject duplicate interfaces in check builds.
9413 // Has to be in sync with code:#InjectInterfaceDuplicates_Main.
9414 if (dbg_pClassMT->Debug_HasInjectedInterfaceDuplicates())
9415 { // Just pretend we didn't find this match
9419 return; // found it, don't add it again
9423 // Add the interface and its sub-interfaces
9424 DWORD n = bmtInfo->nAssigned;
9425 bmtInfo->pExactMTs[n] = pIntf;
9426 bmtInfo->pInterfaceSubstitution[n] = *pSubstForComparing_OnStack;
9427 bmtInfo->nAssigned++;
9429 Substitution * pSubstForTypeLoad = new (&GetThread()->m_MarshalAlloc) Substitution(*pSubstForTypeLoad_OnStack);
9431 ExpandExactDeclaredInterfaces(
9436 &bmtInfo->pInterfaceSubstitution[n]
9437 COMMA_INDEBUG(dbg_pClassMT));
9438 } // MethodTableBuilder::ExpandExactInterface
9440 //*******************************************************************************
9442 void MethodTableBuilder::InterfacesAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9445 const Substitution *pSubstChain)
9447 STANDARD_VM_CONTRACT;
9450 InterfaceImplEnum ie(pModule, typeDef, pSubstChain);
9451 while ((hr = ie.Next()) == S_OK)
9453 MethodTable *pInterface =
9454 ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, ie.CurrentToken(),
9455 &bmtCheckInfo->typeContext,
9456 ClassLoader::ThrowIfNotFound,
9457 ClassLoader::FailIfUninstDefOrRef,
9458 ClassLoader::LoadTypes,
9459 CLASS_LOAD_EXACTPARENTS,
9461 pSubstChain).GetMethodTable();
9462 InterfaceAmbiguityCheck(bmtCheckInfo, ie.CurrentSubst(), pInterface);
9466 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
9470 //*******************************************************************************
9471 void MethodTableBuilder::InterfaceAmbiguityCheck(bmtInterfaceAmbiguityCheckInfo *bmtCheckInfo,
9472 const Substitution *pItfSubstChain,
9475 STANDARD_VM_CONTRACT;
9477 // Is it already in the generic version of the freshly declared interfaces. We
9478 // do this based on metadata, i.e. via the substitution chains.
9479 // Note we use exactly the same algorithm as when we
9480 // determined the layout of the interface map for the "generic" version of the class.
9481 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9483 // Type Equivalence is not respected for this comparision as you can have multiple type equivalent interfaces on a class
9484 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(NULL);
9485 if (MetaSig::CompareTypeDefsUnderSubstitutions(bmtCheckInfo->ppExactDeclaredInterfaces[i],
9487 bmtCheckInfo->ppInterfaceSubstitutionChains[i],
9490 return; // found it, don't add it again
9493 // OK, so it isn't a duplicate based on the generic IL, now check if the instantiation
9494 // makes it a duplicate.
9495 for (DWORD i = 0; i < bmtCheckInfo->nAssigned; i++)
9497 if (bmtCheckInfo->ppExactDeclaredInterfaces[i] == pIntf)
9499 bmtCheckInfo->pMT->GetModule()->GetAssembly()->ThrowTypeLoadException(bmtCheckInfo->pMT->GetMDImport(),
9500 bmtCheckInfo->pMT->GetCl(),
9501 IDS_CLASSLOAD_OVERLAPPING_INTERFACES);
9505 DWORD n = bmtCheckInfo->nAssigned;
9506 bmtCheckInfo->ppExactDeclaredInterfaces[n] = pIntf;
9507 bmtCheckInfo->ppInterfaceSubstitutionChains[n] = new (&GetThread()->m_MarshalAlloc) Substitution[pItfSubstChain->GetLength()];
9508 pItfSubstChain->CopyToArray(bmtCheckInfo->ppInterfaceSubstitutionChains[n]);
9510 bmtCheckInfo->nAssigned++;
9511 InterfacesAmbiguityCheck(bmtCheckInfo,pIntf->GetModule(),pIntf->GetCl(),pItfSubstChain);
9515 //*******************************************************************************
9516 void MethodTableBuilder::CheckForSystemTypes()
9518 STANDARD_VM_CONTRACT;
9520 LPCUTF8 name, nameSpace;
9522 MethodTable * pMT = GetHalfBakedMethodTable();
9523 EEClass * pClass = GetHalfBakedClass();
9525 // We can exit early for generic types - there are just a few cases to check for.
9526 if (bmtGenerics->HasInstantiation())
9528 if (pMT->IsIntrinsicType() && pClass->HasLayout())
9530 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9532 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9535 if (strcmp(nameSpace, g_IntrinsicsNS) == 0)
9537 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
9539 // The SIMD Hardware Intrinsic types correspond to fundamental data types in the underlying ABIs:
9540 // * Vector64<T>: __m64
9541 // * Vector128<T>: __m128
9542 // * Vector256<T>: __m256
9544 // These __m128 and __m256 types, among other requirements, are special in that they must always
9545 // be aligned properly.
9547 if (strcmp(name, g_Vector64Name) == 0)
9549 // The System V ABI for i386 defaults to 8-byte alignment for __m64, except for parameter passing,
9550 // where it has an alignment of 4.
9552 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
9553 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64)
9555 else if (strcmp(name, g_Vector128Name) == 0)
9558 // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128
9560 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8;
9561 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
9563 pLayout->m_LargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
9564 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128)
9565 #endif // _TARGET_ARM_
9567 else if (strcmp(name, g_Vector256Name) == 0)
9570 // No such type exists for the Procedure Call Standard for ARM. We will default
9571 // to the same alignment as __m128, which is supported by the ABI.
9573 pLayout->m_LargestAlignmentRequirementOfAllMembers = 8;
9574 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8;
9575 #elif defined(_TARGET_ARM64_)
9576 // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to
9577 // 16-byte alignment for __m256.
9579 pLayout->m_LargestAlignmentRequirementOfAllMembers = 16;
9580 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16;
9582 pLayout->m_LargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
9583 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256)
9584 #endif // _TARGET_ARM_ elif _TARGET_ARM64_
9588 // These types should be handled or explicitly skipped below to ensure that we don't
9589 // miss adding required ABI support for future types.
9591 _ASSERTE_MSG(FALSE, "Unhandled Hardware Intrinsic Type.");
9598 if (g_pNullableClass != NULL)
9600 _ASSERTE(g_pByReferenceClass != NULL);
9601 _ASSERTE(g_pByReferenceClass->IsByRefLike());
9604 if (GetCl() == g_pByReferenceClass->GetCl())
9606 // x86 by default treats the type of ByReference<T> as the actual type of its IntPtr field, see calls to
9607 // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be
9608 // treated as a value type so that its field can be considered as a by-ref pointer.
9609 _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType);
9610 pMT->ClearFlag(MethodTable::enum_flag_Category_Mask);
9611 pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE);
9616 _ASSERTE(g_pNullableClass->IsNullable());
9618 // Pre-compute whether the class is a Nullable<T> so that code:Nullable::IsNullableType is efficient
9619 // This is useful to the performance of boxing/unboxing a Nullable
9620 if (GetCl() == g_pNullableClass->GetCl())
9621 pMT->SetIsNullable();
9627 if (IsNested() || IsEnum())
9630 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9632 BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
9641 // All special value types are in the system namespace
9642 if (strcmp(nameSpace, g_SystemNS) != 0)
9645 // Check if it is a primitive type
9646 CorElementType type = CorTypeInfo::FindPrimitiveType(name);
9647 if (type != ELEMENT_TYPE_END)
9649 pMT->SetInternalCorElementType(type);
9650 pMT->SetIsTruePrimitive();
9652 #if defined(_TARGET_X86_) && defined(UNIX_X86_ABI)
9655 // The System V ABI for i386 defines different packing for these types.
9657 case ELEMENT_TYPE_I8:
9658 case ELEMENT_TYPE_U8:
9659 case ELEMENT_TYPE_R8:
9661 EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo();
9662 pLayout->m_LargestAlignmentRequirementOfAllMembers = 4;
9663 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 4;
9670 #endif // _TARGET_X86_ && UNIX_X86_ABI
9673 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &name, &nameSpace)))
9675 name = nameSpace = "Invalid TypeDef record";
9677 LOG((LF_CLASSLOADER, LL_INFO10000, "%s::%s marked as primitive type %i\n", nameSpace, name, type));
9680 else if (strcmp(name, g_NullableName) == 0)
9682 pMT->SetIsNullable();
9685 else if (strcmp(name, g_ByReferenceName) == 0)
9687 // x86 by default treats the type of ByReference<T> as the actual type of its IntPtr field, see calls to
9688 // ComputeInternalCorElementTypeForValueType in this file. This is a special case where the struct needs to be
9689 // treated as a value type so that its field can be considered as a by-ref pointer.
9690 _ASSERTE(pMT->GetFlag(MethodTable::enum_flag_Category_Mask) == MethodTable::enum_flag_Category_PrimitiveValueType);
9691 pMT->ClearFlag(MethodTable::enum_flag_Category_Mask);
9692 pMT->SetInternalCorElementType(ELEMENT_TYPE_VALUETYPE);
9695 #ifndef _TARGET_X86_
9696 else if (strcmp(name, g_RuntimeArgumentHandleName) == 0)
9698 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
9700 else if (strcmp(name, g_RuntimeMethodHandleInternalName) == 0)
9702 pMT->SetInternalCorElementType (ELEMENT_TYPE_I);
9705 #if defined(ALIGN_ACCESS) || defined(FEATURE_64BIT_ALIGNMENT)
9706 else if (strcmp(name, g_DecimalName) == 0)
9708 // This is required because native layout of System.Decimal causes it to be aligned
9709 // differently to the layout of the native DECIMAL structure, which will cause
9710 // data misalignent exceptions if Decimal is embedded in another type.
9712 EEClassLayoutInfo* pLayout = pClass->GetLayoutInfo();
9713 pLayout->m_LargestAlignmentRequirementOfAllMembers = sizeof(ULONGLONG);
9714 pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = sizeof(ULONGLONG);
9716 #ifdef FEATURE_64BIT_ALIGNMENT
9717 // Also need to mark the type so it will be allocated on a 64-bit boundary for
9718 // platforms that won't do this naturally.
9719 SetAlign8Candidate();
9722 #endif // ALIGN_ACCESS || FEATURE_64BIT_ALIGNMENT
9729 if (strcmp(name, g_StringName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9731 // Strings are not "normal" objects, so we need to mess with their method table a bit
9732 // so that the GC can figure out how big each string is...
9733 DWORD baseSize = ObjSizeOf(StringObject) + sizeof(WCHAR);
9734 pMT->SetBaseSize(baseSize); // NULL character included
9736 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
9738 pMT->SetComponentSize(2);
9740 else if (strcmp(name, g_CriticalFinalizerObjectName) == 0 && strcmp(nameSpace, g_ConstrainedExecutionNS) == 0)
9742 // To introduce a class with a critical finalizer,
9743 // we'll set the bit here.
9744 pMT->SetHasCriticalFinalizer();
9746 #ifdef FEATURE_COMINTEROP
9749 bool bIsComObject = false;
9750 bool bIsRuntimeClass = false;
9752 if (strcmp(name, g_ComObjectName) == 0 && strcmp(nameSpace, g_SystemNS) == 0)
9753 bIsComObject = true;
9755 if (strcmp(name, g_RuntimeClassName) == 0 && strcmp(nameSpace, g_WinRTNS) == 0)
9756 bIsRuntimeClass = true;
9758 if (bIsComObject || bIsRuntimeClass)
9760 // Make System.__ComObject/System.Runtime.InteropServices.WindowsRuntime.RuntimeClass a ComImport type
9761 // We can't do it using attribute as C# won't allow putting code in ComImport types
9762 pMT->SetComObjectType();
9764 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
9765 // the optional field descriptor.
9766 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
9769 if (bIsRuntimeClass)
9771 // Note that we set it here to avoid type loader considering RuntimeClass as a normal WindowsImportType
9772 // as functions in RuntimeClass doesn't go through COM interop
9773 GetHalfBakedClass()->SetProjectedFromWinRT();
9776 #endif // FEATURE_COMINTEROP
9780 //==========================================================================================
9781 // Helper to create a new method table. This is the only
9782 // way to allocate a new MT. Don't try calling new / ctor.
9783 // Called from SetupMethodTable
9784 // This needs to be kept consistent with MethodTable::GetSavedExtent()
9785 MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule,
9786 DWORD dwVtableSlots,
9789 DWORD dwNumInterfaces,
9791 DWORD cbInstAndDict,
9792 MethodTable *pMTParent,
9793 ClassLoader *pClassLoader,
9794 LoaderAllocator *pAllocator,
9796 BOOL fDynamicStatics,
9797 BOOL fHasGenericsStaticsInfo,
9798 BOOL fNeedsRCWPerTypeData,
9799 BOOL fNeedsRemotableMethodInfo,
9800 BOOL fNeedsRemotingVtsInfo,
9801 BOOL fHasContextStatics
9802 #ifdef FEATURE_COMINTEROP
9803 , BOOL fHasDynamicInterfaceMap
9805 #ifdef FEATURE_PREJIT
9806 , Module *pComputedPZM
9807 #endif // FEATURE_PREJIT
9808 , AllocMemTracker *pamTracker
9811 CONTRACT (MethodTable*)
9816 POSTCONDITION(CheckPointer(RETVAL));
9820 DWORD dwNonVirtualSlots = dwVtableSlots - dwVirtuals;
9822 // GCSize must be aligned
9823 _ASSERTE(IS_ALIGNED(dwGCSize, sizeof(void*)));
9825 // size without the interface map
9826 S_SIZE_T cbTotalSize = S_SIZE_T(dwGCSize) + S_SIZE_T(sizeof(MethodTable));
9829 cbTotalSize += MethodTable::GetNumVtableIndirections(dwVirtuals) * sizeof(MethodTable::VTableIndir_t);
9832 DWORD dwMultipurposeSlotsMask = 0;
9833 if (dwNumInterfaces != 0)
9834 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasInterfaceMap;
9835 if (dwNumDicts != 0)
9836 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasPerInstInfo;
9837 if (bmtVT->pDispatchMapBuilder->Count() > 0)
9838 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasDispatchMapSlot;
9839 if (dwNonVirtualSlots != 0)
9840 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasNonVirtualSlots;
9841 if (pLoaderModule != GetModule())
9842 dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasModuleOverride;
9844 // Add space for optional members here. Same as GetOptionalMembersSize()
9845 cbTotalSize += MethodTable::GetOptionalMembersAllocationSize(dwMultipurposeSlotsMask,
9846 fNeedsRemotableMethodInfo,
9847 fHasGenericsStaticsInfo,
9848 FALSE, // no GuidInfo needed for canonical instantiations
9849 FALSE, // no CCW template needed for canonical instantiations
9850 fNeedsRCWPerTypeData,
9851 fNeedsRemotingVtsInfo,
9853 RidFromToken(GetCl()) >= METHODTABLE_TOKEN_OVERFLOW);
9855 // Interface map starts here
9856 S_SIZE_T offsetOfInterfaceMap = cbTotalSize;
9858 cbTotalSize += S_SIZE_T(dwNumInterfaces) * S_SIZE_T(sizeof(InterfaceInfo_t));
9860 #ifdef FEATURE_COMINTEROP
9861 // DynamicInterfaceMap have an extra DWORD added to the end of the normal interface
9862 // map. This will be used to store the count of dynamically added interfaces
9863 // (the ones that are not in the metadata but are QI'ed for at runtime).
9864 cbTotalSize += S_SIZE_T(fHasDynamicInterfaceMap ? sizeof(DWORD_PTR) : 0);
9867 // Dictionary pointers start here
9868 S_SIZE_T offsetOfInstAndDict = cbTotalSize;
9870 if (dwNumDicts != 0)
9872 cbTotalSize += sizeof(GenericsDictInfo);
9873 cbTotalSize += S_SIZE_T(dwNumDicts) * S_SIZE_T(sizeof(MethodTable::PerInstInfoElem_t));
9874 cbTotalSize += cbInstAndDict;
9877 S_SIZE_T offsetOfUnsharedVtableChunks = cbTotalSize;
9879 BOOL canShareVtableChunks = pMTParent && MethodTable::CanShareVtableChunksFrom(pMTParent, pLoaderModule
9880 #ifdef FEATURE_PREJIT
9882 #endif //FEATURE_PREJIT
9885 // If pMTParent has a generic instantiation, we cannot share its vtable chunks
9886 // This is because pMTParent is only approximate at this point, and MethodTableBuilder::CopyExactParentSlots
9887 // may swap in an exact parent that does not satisfy CanShareVtableChunksFrom
9888 if (pMTParent && pMTParent->HasInstantiation())
9890 canShareVtableChunks = FALSE;
9893 // We will share any parent vtable chunk that does not contain a method we overrode (or introduced)
9894 // For the rest, we need to allocate space
9895 for (DWORD i = 0; i < dwVirtuals; i++)
9897 if (!canShareVtableChunks || ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
9899 DWORD chunkStart = MethodTable::GetStartSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
9900 DWORD chunkEnd = MethodTable::GetEndSlotForVtableIndirection(MethodTable::GetIndexOfVtableIndirection(i), dwVirtuals);
9902 cbTotalSize += S_SIZE_T(chunkEnd - chunkStart) * S_SIZE_T(sizeof(PCODE));
9908 // Add space for the non-virtual slots array (pointed to by an optional member) if required
9909 // If there is only one non-virtual slot, we store it directly in the optional member and need no array
9910 S_SIZE_T offsetOfNonVirtualSlots = cbTotalSize;
9911 if (dwNonVirtualSlots > 1)
9913 cbTotalSize += S_SIZE_T(dwNonVirtualSlots) * S_SIZE_T(sizeof(PCODE));
9916 BYTE *pData = (BYTE *)pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(cbTotalSize));
9918 _ASSERTE(IS_ALIGNED(pData, sizeof(size_t)));
9920 // There should be no overflows if we have allocated the memory succesfully
9921 _ASSERTE(!cbTotalSize.IsOverflow());
9923 MethodTable* pMT = (MethodTable*)(pData + dwGCSize);
9925 pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask);
9927 MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *)
9928 pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData))));
9929 // Note: Memory allocated on loader heap is zero filled
9930 pMT->SetWriteableData(pMTWriteableData);
9932 // This also disables IBC logging until the type is sufficiently intitialized so
9933 // it needs to be done early
9934 pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable();
9937 pClassLoader->m_dwGCSize += dwGCSize;
9938 pClassLoader->m_dwInterfaceMapSize += (dwNumInterfaces * sizeof(InterfaceInfo_t));
9939 pClassLoader->m_dwMethodTableSize += (DWORD)cbTotalSize.Value();
9940 pClassLoader->m_dwVtableData += (dwVtableSlots * sizeof(PCODE));
9943 // There should be no overflows if we have allocated the memory succesfully
9944 _ASSERTE(!offsetOfUnsharedVtableChunks.IsOverflow());
9945 _ASSERTE(!offsetOfNonVirtualSlots.IsOverflow());
9946 _ASSERTE(!offsetOfInterfaceMap.IsOverflow());
9947 _ASSERTE(!offsetOfInstAndDict.IsOverflow());
9949 // initialize the total number of slots
9950 pMT->SetNumVirtuals(static_cast<WORD>(dwVirtuals));
9952 pMT->SetParentMethodTable(pMTParent);
9954 // Fill out the vtable indirection slots
9955 SIZE_T dwCurrentUnsharedSlotOffset = offsetOfUnsharedVtableChunks.Value();
9956 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
9959 BOOL shared = canShareVtableChunks;
9961 // Recalculate whether we will share this chunk
9962 if (canShareVtableChunks)
9964 for (DWORD i = it.GetStartSlot(); i < it.GetEndSlot(); i++)
9966 if (ChangesImplementationOfVirtualSlot(static_cast<SLOT_INDEX>(i)))
9976 // Share the parent chunk
9977 _ASSERTE(it.GetEndSlot() <= pMTParent->GetNumVirtuals());
9978 it.SetIndirectionSlot(pMTParent->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull());
9982 // Use the locally allocated chunk
9983 it.SetIndirectionSlot((PTR_PCODE)(pData+dwCurrentUnsharedSlotOffset));
9984 dwCurrentUnsharedSlotOffset += it.GetSize();
9988 #ifdef FEATURE_COMINTEROP
9989 // Extensible RCW's are prefixed with the count of dynamic interfaces.
9990 if (fHasDynamicInterfaceMap)
9992 _ASSERTE (dwNumInterfaces > 0);
9993 pMT->SetInterfaceMap ((WORD) (dwNumInterfaces), (InterfaceInfo_t*)(pData+offsetOfInterfaceMap.Value()+sizeof(DWORD_PTR)));
9995 *(((DWORD_PTR *)pMT->GetInterfaceMap()) - 1) = 0;
9998 #endif // FEATURE_COMINTEROP
10000 // interface map is at the end of the vtable
10001 pMT->SetInterfaceMap ((WORD) dwNumInterfaces, (InterfaceInfo_t *)(pData+offsetOfInterfaceMap.Value()));
10004 _ASSERTE(((WORD) dwNumInterfaces) == dwNumInterfaces);
10006 if (fDynamicStatics)
10008 pMT->SetDynamicStatics(fHasGenericsStaticsInfo);
10011 if (dwNonVirtualSlots > 0)
10013 if (dwNonVirtualSlots > 1)
10015 pMT->SetNonVirtualSlotsArray((PTR_PCODE)(pData+offsetOfNonVirtualSlots.Value()));
10019 pMT->SetHasSingleNonVirtualSlot();
10023 // the dictionary pointers follow the interface map
10026 MethodTable::PerInstInfoElem_t *pPerInstInfo = (MethodTable::PerInstInfoElem_t *)(pData + offsetOfInstAndDict.Value() + sizeof(GenericsDictInfo));
10028 pMT->SetPerInstInfo ( pPerInstInfo);
10030 // Fill in the dictionary for this type, if it's instantiated
10033 MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *)(pPerInstInfo + (dwNumDicts-1));
10034 pPInstInfo->SetValueMaybeNull((Dictionary*) (pPerInstInfo + dwNumDicts));
10039 pMT->m_pWriteableData.GetValue()->m_dwLastVerifedGCCnt = (DWORD)-1;
10046 //*******************************************************************************
10048 // Used by BuildMethodTable
10050 // Setup the method table
10053 #pragma warning(push)
10054 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
10055 #endif // _PREFAST_
10058 MethodTableBuilder::SetupMethodTable2(
10059 Module * pLoaderModule
10060 #ifdef FEATURE_PREJIT
10061 , Module * pComputedPZM
10062 #endif // FEATURE_PREJIT
10068 PRECONDITION(CheckPointer(this));
10069 PRECONDITION(CheckPointer(bmtVT));
10070 PRECONDITION(CheckPointer(bmtInterface));
10071 PRECONDITION(CheckPointer(bmtInternal));
10072 PRECONDITION(CheckPointer(bmtProp));
10073 PRECONDITION(CheckPointer(bmtMFDescs));
10074 PRECONDITION(CheckPointer(bmtEnumFields));
10075 PRECONDITION(CheckPointer(bmtError));
10076 PRECONDITION(CheckPointer(bmtMetaData));
10077 PRECONDITION(CheckPointer(bmtParent));
10078 PRECONDITION(CheckPointer(bmtGenerics));
10084 #ifdef FEATURE_COMINTEROP
10085 BOOL fHasDynamicInterfaceMap = bmtInterface->dwInterfaceMapSize > 0 &&
10086 bmtProp->fIsComObjectType &&
10087 (GetParentMethodTable() != g_pObjectClass);
10088 BOOL fNeedsRCWPerTypeData = bmtProp->fNeedsRCWPerTypeData;
10089 #else // FEATURE_COMINTEROP
10090 BOOL fNeedsRCWPerTypeData = FALSE;
10091 #endif // FEATURE_COMINTEROP
10093 EEClass *pClass = GetHalfBakedClass();
10095 DWORD cbDict = bmtGenerics->HasInstantiation()
10096 ? DictionaryLayout::GetFirstDictionaryBucketSize(
10097 bmtGenerics->GetNumGenericArgs(), pClass->GetDictionaryLayout())
10101 BOOL fHasContextStatics = FALSE;
10102 BOOL fNeedsRemotableMethodInfo=FALSE;
10103 BOOL fNeedsRemotingVtsInfo = FALSE;
10105 #ifdef FEATURE_COLLECTIBLE_TYPES
10106 BOOL fCollectible = pLoaderModule->IsCollectible();
10107 #endif // FEATURE_COLLECTIBLE_TYPES
10111 if (bmtFP->NumGCPointerSeries > 0)
10113 dwGCSize = (DWORD)CGCDesc::ComputeSize(bmtFP->NumGCPointerSeries);
10117 #ifdef FEATURE_COLLECTIBLE_TYPES
10119 dwGCSize = (DWORD)CGCDesc::ComputeSize(1);
10121 #endif // FEATURE_COLLECTIBLE_TYPES
10125 pClass->SetNumMethods(bmtVT->cTotalSlots);
10126 pClass->SetNumNonVirtualSlots(bmtVT->cVtableSlots - bmtVT->cVirtualSlots);
10128 // Now setup the method table
10129 // interface map is allocated along with the method table
10130 MethodTable *pMT = AllocateNewMT(pLoaderModule,
10131 bmtVT->cVtableSlots,
10132 bmtVT->cVirtualSlots,
10134 bmtInterface->dwInterfaceMapSize,
10135 bmtGenerics->numDicts,
10137 GetParentMethodTable(),
10141 bmtProp->fDynamicStatics,
10142 bmtProp->fGenericsStatics,
10143 fNeedsRCWPerTypeData,
10144 fNeedsRemotableMethodInfo,
10145 fNeedsRemotingVtsInfo,
10146 fHasContextStatics,
10147 #ifdef FEATURE_COMINTEROP
10148 fHasDynamicInterfaceMap,
10150 #ifdef FEATURE_PREJIT
10152 #endif //FEATURE_PREJIT
10155 pMT->SetClass(pClass);
10156 pClass->m_pMethodTable.SetValue(pMT);
10157 m_pHalfBakedMT = pMT;
10160 pMT->SetDebugClassName(GetDebugClassName());
10163 #ifdef FEATURE_COMINTEROP
10164 if (fNeedsRCWPerTypeData)
10165 pMT->SetHasRCWPerTypeData();
10166 #endif // FEATURE_COMINTEROP
10170 pMT->SetIsInterface();
10172 if (GetParentMethodTable() != NULL)
10174 if (GetParentMethodTable()->HasModuleDependencies())
10176 pMT->SetHasModuleDependencies();
10180 Module * pModule = GetModule();
10181 Module * pParentModule = GetParentMethodTable()->GetModule();
10182 if (pModule != pParentModule && !pModule->HasUnconditionalActiveDependency(pParentModule))
10184 pMT->SetHasModuleDependencies();
10188 if (GetParentMethodTable()->HasPreciseInitCctors() || !pClass->IsBeforeFieldInit())
10190 pMT->SetHasPreciseInitCctors();
10194 // Must be done early because various methods test HasInstantiation() and ContainsGenericVariables()
10195 if (bmtGenerics->GetNumGenericArgs() != 0)
10197 pMT->SetHasInstantiation(bmtGenerics->fTypicalInstantiation, bmtGenerics->fSharedByGenericInstantiations);
10199 if (bmtGenerics->fContainsGenericVariables)
10200 pMT->SetContainsGenericVariables();
10203 if (bmtGenerics->numDicts != 0)
10205 if (!FitsIn<WORD>(bmtGenerics->GetNumGenericArgs()))
10207 BuildMethodTableThrowException(IDS_CLASSLOAD_TOOMANYGENERICARGS);
10210 pMT->SetDictInfo(bmtGenerics->numDicts,
10211 static_cast<WORD>(bmtGenerics->GetNumGenericArgs()));
10214 CONSISTENCY_CHECK(pMT->GetNumGenericArgs() == bmtGenerics->GetNumGenericArgs());
10215 CONSISTENCY_CHECK(pMT->GetNumDicts() == bmtGenerics->numDicts);
10216 CONSISTENCY_CHECK(pMT->HasInstantiation() == bmtGenerics->HasInstantiation());
10217 CONSISTENCY_CHECK(pMT->HasInstantiation() == !pMT->GetInstantiation().IsEmpty());
10219 pMT->SetLoaderModule(pLoaderModule);
10220 pMT->SetLoaderAllocator(bmtAllocator);
10222 pMT->SetModule(GetModule());
10224 pMT->SetInternalCorElementType (ELEMENT_TYPE_CLASS);
10226 SetNonGCRegularStaticFieldBytes (bmtProp->dwNonGCRegularStaticFieldBytes);
10227 SetNonGCThreadStaticFieldBytes (bmtProp->dwNonGCThreadStaticFieldBytes);
10229 #ifdef FEATURE_TYPEEQUIVALENCE
10230 if (bmtProp->fHasTypeEquivalence)
10232 pMT->SetHasTypeEquivalence();
10234 #endif //FEATURE_TYPEEQUIVALENCE
10236 #ifdef FEATURE_COMINTEROP
10237 if (bmtProp->fSparse)
10238 pClass->SetSparseForCOMInterop();
10240 if (IsInterface() && IsComImport())
10242 // Determine if we are creating an interface methodtable that may be used to dispatch through VSD
10243 // on an object that has the methodtable of __ComObject.
10245 // This is done to allow COM tearoff interfaces, but as a side-effect of this feature,
10246 // we end up using a domain-shared type (__ComObject) with a domain-specific dispatch token.
10247 // This is a problem because the same domain-specific dispatch token value can appear in
10248 // multiple unshared domains (VSD takes advantage of the fact that in general a shared type
10249 // cannot implement an unshared interface). This means that the same <token, __ComObject> pair
10250 // value can mean different things in different domains (since the token could represent
10251 // IFoo in one domain and IBar in another). This is a problem because the
10252 // VSD polymorphic lookup mechanism relies on a process-wide cache table, and as a result
10253 // these duplicate values would collide if we didn't use fat dispatch token to ensure uniqueness
10254 // and the interface methodtable is not in the shared domain.
10256 pMT->SetRequiresFatDispatchTokens();
10258 #endif // FEATURE_COMINTEROP
10260 if (bmtVT->pCCtor != NULL)
10262 pMT->SetHasClassConstructor();
10263 CONSISTENCY_CHECK(pMT->GetClassConstructorSlot() == bmtVT->pCCtor->GetSlotIndex());
10265 if (bmtVT->pDefaultCtor != NULL)
10267 pMT->SetHasDefaultConstructor();
10268 CONSISTENCY_CHECK(pMT->GetDefaultConstructorSlot() == bmtVT->pDefaultCtor->GetSlotIndex());
10271 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10273 pChunk->SetMethodTable(pMT);
10278 // disable ibc logging because we can assert in ComputerPreferredZapModule for partially constructed
10280 IBCLoggingDisabler disableLogging;
10282 DeclaredMethodIterator it(*this);
10285 MethodDesc *pMD = it->GetMethodDesc();
10288 pMD->m_pDebugMethodTable.SetValue(pMT);
10289 pMD->m_pszDebugMethodSignature = FormatSig(pMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10291 MethodDesc *pUnboxedMD = it->GetUnboxedMethodDesc();
10292 if (pUnboxedMD != NULL)
10294 pUnboxedMD->m_pDebugMethodTable.SetValue(pMT);
10295 pUnboxedMD->m_pszDebugMethodSignature = FormatSig(pUnboxedMD, GetLoaderAllocator()->GetLowFrequencyHeap(), GetMemTracker());
10301 // Note that for value classes, the following calculation is only appropriate
10302 // when the instance is in its "boxed" state.
10303 if (!IsInterface())
10305 DWORD baseSize = Max<DWORD>(bmtFP->NumInstanceFieldBytes + ObjSizeOf(Object), MIN_OBJECT_SIZE);
10306 baseSize = (baseSize + ALLOC_ALIGN_CONSTANT) & ~ALLOC_ALIGN_CONSTANT; // m_BaseSize must be aligned
10307 pMT->SetBaseSize(baseSize);
10309 GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes);
10311 #ifdef FEATURE_COMINTEROP
10312 if (bmtProp->fIsComObjectType)
10313 { // Propagate the com specific info
10314 pMT->SetComObjectType();
10316 // COM objects need an optional field on the EEClass, so ensure this class instance has allocated
10317 // the optional field descriptor.
10318 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10321 if (pMT->GetAssembly()->IsManagedWinMD())
10323 // We need to mark classes that are implementations of managed WinRT runtime classes with
10324 // the "exported to WinRT" flag. It's not quite possible to tell which ones these are by
10325 // reading metadata so we ask the adapter.
10327 IWinMDImport *pWinMDImport = pMT->GetAssembly()->GetManifestWinMDImport();
10328 _ASSERTE(pWinMDImport != NULL);
10331 IfFailThrow(pWinMDImport->IsRuntimeClassImplementation(GetCl(), &bResult));
10335 pClass->SetExportedToWinRT();
10337 // We need optional fields for activation from WinRT.
10338 EnsureOptionalFieldsAreAllocated(pClass, m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
10342 if (pClass->IsProjectedFromWinRT() || pClass->IsExportedToWinRT())
10346 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), g_WindowsFoundationMarshalingBehaviorAttributeClassName, (const void **) &pVal, &cbVal);
10349 CustomAttributeParser cap(pVal, cbVal);
10350 IfFailThrow(cap.SkipProlog());
10352 IfFailThrow(cap.GetU4(&u));
10354 pClass->SetMarshalingType(u);
10357 #endif // FEATURE_COMINTEROP
10361 #ifdef FEATURE_COMINTEROP
10362 // If this is an interface then we need to set the ComInterfaceType to
10363 // -1 to indicate we have not yet determined the interface type.
10364 pClass->SetComInterfaceType((CorIfaceAttr)-1);
10366 // If this is a special COM event interface, then mark the MT as such.
10367 if (bmtProp->fComEventItfType)
10369 pClass->SetComEventItfType();
10371 #endif // FEATURE_COMINTEROP
10373 _ASSERTE((pMT->IsInterface() == 0) == (IsInterface() == 0));
10377 pClass->SetNativeSize(GetLayoutInfo()->GetNativeSize());
10380 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
10381 // Set all field slots to point to the newly created MethodTable
10382 for (i = 0; i < (bmtEnumFields->dwNumStaticFields + bmtEnumFields->dwNumInstanceFields); i++)
10384 pFieldDescList[i].m_pMTOfEnclosingClass.SetValue(pMT);
10387 // Fill in type parameters before looking up exact parent or fetching the types of any field descriptors!
10388 // This must come before the use of GetFieldType in the value class representation optimization below.
10389 if (bmtGenerics->GetNumGenericArgs() != 0)
10391 // Space has already been allocated for the instantiation but the parameters haven't been filled in
10392 Instantiation destInst = pMT->GetInstantiation();
10393 Instantiation inst = bmtGenerics->GetInstantiation();
10395 // So fill them in...
10396 TypeHandle * pInstDest = (TypeHandle *)destInst.GetRawArgs();
10397 for (DWORD j = 0; j < bmtGenerics->GetNumGenericArgs(); j++)
10399 pInstDest[j] = inst[j];
10403 CorElementType normalizedType = ELEMENT_TYPE_CLASS;
10404 if (IsValueClass())
10408 if (GetNumInstanceFields() != 1 ||
10409 !CorTypeInfo::IsPrimitiveType(pFieldDescList[0].GetFieldType()))
10411 BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
10413 CONSISTENCY_CHECK(!pFieldDescList[0].IsStatic());
10414 normalizedType = pFieldDescList->GetFieldType();
10418 #ifdef _TARGET_X86_
10419 // JIT64 is not aware of normalized value types and this
10420 // optimization (return small value types by value in registers)
10421 // is already done in JIT64.
10422 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10423 normalizedType = EEClass::ComputeInternalCorElementTypeForValueType(pMT);
10425 normalizedType = ELEMENT_TYPE_VALUETYPE;
10429 pMT->SetInternalCorElementType(normalizedType);
10431 // If this type is marked by [Intrinsic] attribute, it may be specially treated by the runtime/compiler
10432 // Currently, only SIMD types have [Intrinsic] attribute
10434 // We check this here fairly early to ensure other downstream checks on these types can be slightly more efficient.
10435 if ((GetModule()->IsSystem() || GetAssembly()->IsSIMDVectorAssembly()) && IsValueClass() && bmtGenerics->HasInstantiation())
10437 HRESULT hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
10438 g_CompilerServicesIntrinsicAttribute,
10444 pMT->SetIsIntrinsicType();
10448 if (GetModule()->IsSystem())
10450 // we are in mscorlib
10451 CheckForSystemTypes();
10454 // Now fill in the real interface map with the approximate interfaces
10455 if (bmtInterface->dwInterfaceMapSize > 0)
10457 // First ensure we have enough space to record extra flag information for each interface (we don't
10458 // record this directly into each interface map entry since these flags don't pack well due to
10460 PVOID pExtraInterfaceInfo = NULL;
10461 SIZE_T cbExtraInterfaceInfo = MethodTable::GetExtraInterfaceInfoSize(bmtInterface->dwInterfaceMapSize);
10462 if (cbExtraInterfaceInfo)
10463 pExtraInterfaceInfo = GetMemTracker()->Track(GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbExtraInterfaceInfo)));
10465 // Call this even in the case where pExtraInterfaceInfo == NULL (certain cases are optimized and don't
10466 // require extra buffer space).
10467 pMT->InitializeExtraInterfaceInfo(pExtraInterfaceInfo);
10469 InterfaceInfo_t *pInterfaces = pMT->GetInterfaceMap();
10471 CONSISTENCY_CHECK(CheckPointer(pInterfaces));
10473 // Copy the interface map member by member so there is no junk in the padding.
10474 for (i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
10476 bmtInterfaceEntry * pEntry = &bmtInterface->pInterfaceMap[i];
10478 if (pEntry->IsDeclaredOnType())
10479 pMT->SetInterfaceDeclaredOnClass(i);
10480 _ASSERTE(!!pEntry->IsDeclaredOnType() == !!pMT->IsInterfaceDeclaredOnClass(i));
10482 pInterfaces[i].SetMethodTable(pEntry->GetInterfaceType()->GetMethodTable());
10486 pMT->SetCl(GetCl());
10488 // The type is sufficiently initialized for most general purpose accessor methods to work.
10489 // Mark the type as restored to avoid avoid asserts. Note that this also enables IBC logging.
10490 pMT->GetWriteableDataForWrite_NoLogging()->SetIsRestoredForBuildMethodTable();
10493 // Store status if we tried to inject duplicate interfaces
10494 if (bmtInterface->dbg_fShouldInjectInterfaceDuplicates)
10495 pMT->Debug_SetHasInjectedInterfaceDuplicates();
10498 // Keep bmtInterface data around since we no longer write the flags (IsDeclaredOnType and
10499 // IsImplementedByParent) into the interface map (these flags are only required during type loading).
10502 for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
10504 // Make sure that temporary entrypoints are create for methods. NGEN uses temporary
10505 // entrypoints as surrogate keys for precodes.
10506 pChunk->EnsureTemporaryEntryPointsCreated(GetLoaderAllocator(), GetMemTracker());
10510 { // copy onto the real vtable (methods only)
10511 //@GENERICS: Because we sometimes load an inexact parent (see ClassLoader::GetParent) the inherited slots might
10512 // come from the wrong place and need fixing up once we know the exact parent
10514 for (bmtVtable::Iterator slotIt = bmtVT->IterateSlots(); !slotIt.AtEnd(); ++slotIt)
10516 SLOT_INDEX iCurSlot = static_cast<SLOT_INDEX>(slotIt.CurrentIndex());
10518 // We want the unboxed MethodDesc if we're out of the virtual method range
10519 // and the method we're dealing with has an unboxing method. If so, then
10520 // the unboxing method was placed in the virtual section of the vtable and
10521 // we now need to place the unboxed version.
10522 MethodDesc * pMD = NULL;
10523 if (iCurSlot < bmtVT->cVirtualSlots || !slotIt->Impl().AsMDMethod()->IsUnboxing())
10525 pMD = slotIt->Impl().GetMethodDesc();
10526 CONSISTENCY_CHECK(slotIt->Decl().GetSlotIndex() == iCurSlot);
10530 pMD = slotIt->Impl().AsMDMethod()->GetUnboxedMethodDesc();
10531 CONSISTENCY_CHECK(pMD->GetSlot() == iCurSlot);
10534 CONSISTENCY_CHECK(CheckPointer(pMD));
10536 if (pMD->GetMethodTable() != pMT)
10541 // Do not write into vtable chunks shared with parent. It would introduce race
10542 // with code:MethodDesc::SetStableEntryPointInterlocked.
10544 DWORD indirectionIndex = MethodTable::GetIndexOfVtableIndirection(iCurSlot);
10545 if (GetParentMethodTable()->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull() != pMT->GetVtableIndirections()[indirectionIndex].GetValueMaybeNull())
10546 pMT->SetSlot(iCurSlot, pMD->GetMethodEntryPoint());
10553 _ASSERTE(iCurSlot >= bmtVT->cVirtualSlots || ChangesImplementationOfVirtualSlot(iCurSlot));
10555 PCODE addr = pMD->GetTemporaryEntryPoint();
10556 _ASSERTE(addr != NULL);
10558 if (pMD->HasNonVtableSlot())
10560 *pMD->GetAddrOfSlot() = addr;
10564 pMT->SetSlot(iCurSlot, addr);
10567 if (pMD->GetSlot() == iCurSlot && pMD->RequiresStableEntryPoint())
10569 // The rest of the system assumes that certain methods always have stable entrypoints.
10570 // Create them now.
10571 pMD->GetOrCreatePrecode();
10577 // If we have any entries, then finalize them and allocate the object in class loader heap
10578 DispatchMap *pDispatchMap = NULL;
10579 DispatchMapBuilder *pDispatchMapBuilder = bmtVT->pDispatchMapBuilder;
10580 CONSISTENCY_CHECK(CheckPointer(pDispatchMapBuilder));
10582 if (pDispatchMapBuilder->Count() > 0)
10584 // Create a map in stacking memory.
10587 DispatchMap::CreateEncodedMapping(
10589 pDispatchMapBuilder,
10590 pDispatchMapBuilder->GetAllocator(),
10594 // Now finalize the impltable and allocate the block in the low frequency loader heap
10595 size_t objSize = (size_t) DispatchMap::GetObjectSize(cbMap);
10596 void * pv = AllocateFromLowFrequencyHeap(S_SIZE_T(objSize));
10597 _ASSERTE(pv != NULL);
10599 // Use placement new
10600 pDispatchMap = new (pv) DispatchMap(pbMap, cbMap);
10601 pMT->SetDispatchMap(pDispatchMap);
10604 g_sdStats.m_cDispatchMap++;
10605 g_sdStats.m_cbDispatchMap += (UINT32) objSize;
10606 LOG((LF_LOADER, LL_INFO1000, "SD: Dispatch map for %s: %d bytes for map, %d bytes total for object.\n",
10607 pMT->GetDebugClassName(), cbMap, objSize));
10612 // GetMethodData by default will cache its result. However, in the case that we're
10613 // building a MethodTable, we aren't guaranteed that this type is going to successfully
10614 // load and so caching it would result in errors down the road since the memory and
10615 // type occupying the same memory location would very likely be incorrect. The second
10616 // argument specifies that GetMethodData should not cache the returned object.
10617 MethodTable::MethodDataWrapper hMTData(MethodTable::GetMethodData(pMT, FALSE));
10619 if (!IsInterface())
10621 // Propagate inheritance.
10623 // NOTE: In the world of unfolded interface this was used to propagate overrides into
10624 // the unfolded interface vtables to make sure that overrides of virtual methods
10625 // also overrode the interface methods that they contributed to. This had the
10626 // unfortunate side-effect of also overwriting regular vtable slots that had been
10627 // methodimpl'd and as a result changed the meaning of methodimpl from "substitute
10628 // the body of method A with the body of method B" to "unify the slots of methods
10629 // A and B". But now compilers have come to rely on this side-effect and it can
10630 // not be brought back to its originally intended behaviour.
10632 // For every slot whose body comes from another slot (determined by getting the MethodDesc
10633 // for a slot and seeing if MethodDesc::GetSlot returns a different value than the slot
10634 // from which the MethodDesc was recovered), copy the value of the slot stated by the
10635 // MethodDesc over top of the current slot.
10637 // Because of the way slot unification works, we need to iterate the enture vtable until
10638 // no slots need updated. To understand this, imagine the following:
10639 // C1::M1 is overridden by C2::M2
10640 // C1::M2 is methodImpled by C1::M3
10641 // C1::M3 is overridden by C2::M3
10642 // This should mean that C1::M1 is implemented by C2::M3, but if we didn't run the below
10643 // for loop a second time, this would not be propagated properly - it would only be placed
10644 // into the slot for C1::M2 and never make its way up to C1::M1.
10649 fChangeMade = FALSE;
10650 for (i = 0; i < pMT->GetNumVirtuals(); i++)
10652 MethodDesc* pMD = hMTData->GetImplMethodDesc(i);
10654 CONSISTENCY_CHECK(CheckPointer(pMD));
10655 CONSISTENCY_CHECK(pMD == pMT->GetMethodDescForSlot(i));
10657 // This indicates that the method body in this slot was copied here through a methodImpl.
10658 // Thus, copy the value of the slot from which the body originally came, in case it was
10659 // overridden, to make sure the two slots stay in sync.
10660 INDEBUG(MethodDesc * pMDOld; pMDOld = pMD;)
10661 if(pMD->GetSlot() != i &&
10662 pMT->GetSlot(i) != pMT->GetSlot(pMD->GetSlot()))
10664 // Copy the slot value in the method's original slot.
10665 pMT->SetSlot(i,pMT->GetSlot(pMD->GetSlot()));
10666 hMTData->InvalidateCachedVirtualSlot(i);
10668 // Update the pMD to the new method desc we just copied over ourselves with. This will
10669 // be used in the check for missing method block below.
10670 pMD = pMT->GetMethodDescForSlot(pMD->GetSlot());
10672 // This method is now duplicate
10673 pMD->SetDuplicate();
10674 INDEBUG(g_dupMethods++;)
10675 fChangeMade = TRUE;
10679 while (fChangeMade);
10682 if (!bmtProp->fNoSanityChecks)
10683 VerifyVirtualMethodsImplemented(hMTData);
10687 for (bmtVtable::Iterator i = bmtVT->IterateSlots();
10690 _ASSERTE(i->Impl().GetMethodDesc() != NULL);
10696 #ifdef FEATURE_COMINTEROP
10697 // for ComObject types, i.e. if the class extends from a COM Imported
10699 // make sure any interface implementated by the COM Imported class
10700 // is overridden fully, (OR) not overridden at all..
10701 // We relax this for WinRT where we want to be able to override individual methods.
10702 if (bmtProp->fIsComObjectType && !pMT->IsWinRTObjectType())
10704 MethodTable::InterfaceMapIterator intIt = pMT->IterateInterfaceMap();
10705 while (intIt.Next())
10707 MethodTable* pIntfMT = intIt.GetInterface();
10708 if (pIntfMT->GetNumVirtuals() != 0)
10710 BOOL hasComImportMethod = FALSE;
10711 BOOL hasManagedMethod = FALSE;
10713 // NOTE: Avoid caching the MethodData object for the type being built.
10714 MethodTable::MethodDataWrapper hItfImplData(MethodTable::GetMethodData(pIntfMT, pMT, FALSE));
10715 MethodTable::MethodIterator it(hItfImplData);
10716 for (;it.IsValid(); it.Next())
10718 MethodDesc *pClsMD = NULL;
10719 // If we fail to find an _IMPLEMENTATION_ for the interface MD, then
10720 // we are a ComImportMethod, otherwise we still be a ComImportMethod or
10721 // we can be a ManagedMethod.
10722 DispatchSlot impl(it.GetTarget());
10723 if (!impl.IsNull())
10725 pClsMD = it.GetMethodDesc();
10727 CONSISTENCY_CHECK(!pClsMD->IsInterface());
10728 if (pClsMD->GetClass()->IsComImport())
10730 hasComImportMethod = TRUE;
10734 hasManagedMethod = TRUE;
10739 // Need to set the pClsMD for the error reporting below.
10740 pClsMD = it.GetDeclMethodDesc();
10741 CONSISTENCY_CHECK(CheckPointer(pClsMD));
10742 hasComImportMethod = TRUE;
10745 // One and only one of the two must be set.
10746 if ((hasComImportMethod && hasManagedMethod) ||
10747 (!hasComImportMethod && !hasManagedMethod))
10749 BuildMethodTableThrowException(IDS_EE_BAD_COMEXTENDS_CLASS, pClsMD->GetNameOnNonArrayClass());
10756 // For COM event interfaces, we need to make sure that all the methods are
10757 // methods to add or remove events. This means that they all need to take
10758 // a delegate derived class and have a void return type.
10759 if (bmtProp->fComEventItfType)
10761 // COM event interfaces had better be interfaces.
10762 CONSISTENCY_CHECK(IsInterface());
10764 // Go through all the methods and check the validity of the signature.
10765 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
10766 MethodTable::MethodIterator it(hMTData);
10767 for (;it.IsValid(); it.Next())
10769 MethodDesc* pMD = it.GetMethodDesc();
10775 CONTRACT_VIOLATION(LoadsTypeViolation);
10776 if (Sig.GetReturnType() != ELEMENT_TYPE_VOID ||
10777 Sig.NumFixedArgs() != 1 ||
10778 Sig.NextArg() != ELEMENT_TYPE_CLASS ||
10779 !Sig.GetLastTypeHandleThrowing().CanCastTo(TypeHandle(g_pDelegateClass)))
10781 BuildMethodTableThrowException(IDS_EE_BAD_COMEVENTITF_CLASS, pMD->GetNameOnNonArrayClass());
10786 #endif // FEATURE_COMINTEROP
10788 // If this class uses any VTS (Version Tolerant Serialization) features
10789 // (event callbacks or OptionalField attributes) we've previously cached the
10790 // additional information in the bmtMFDescs structure. Now it's time to add
10791 // this information as an optional extension to the MethodTable.
10794 #pragma warning(pop)
10797 // Returns true if there is at least one default implementation for this interface method
10798 // We don't care about conflicts at this stage in order to avoid impact type load performance
10799 BOOL MethodTableBuilder::HasDefaultInterfaceImplementation(MethodDesc *pDeclMD)
10801 STANDARD_VM_CONTRACT;
10803 #ifdef FEATURE_DEFAULT_INTERFACES
10804 // If the interface method is already non-abstract, we are done
10805 if (pDeclMD->IsDefaultInterfaceMethod())
10808 MethodTable *pDeclMT = pDeclMD->GetMethodTable();
10810 // Otherwise, traverse the list of interfaces and see if there is at least one override
10811 bmtInterfaceInfo::MapIterator intIt = bmtInterface->IterateInterfaceMap();
10812 for (; !intIt.AtEnd(); intIt.Next())
10814 MethodTable *pIntfMT = intIt->GetInterfaceType()->GetMethodTable();
10815 if (pIntfMT->GetClass()->ContainsMethodImpls() && pIntfMT->CanCastToInterface(pDeclMT))
10817 MethodTable::MethodIterator methodIt(pIntfMT);
10818 for (; methodIt.IsValid(); methodIt.Next())
10820 MethodDesc *pMD = methodIt.GetMethodDesc();
10821 if (pMD->IsMethodImpl())
10823 MethodImpl::Iterator it(pMD);
10824 while (it.IsValid())
10826 if (it.GetMethodDesc() == pDeclMD)
10833 #endif // FEATURE_DEFAULT_INTERFACES
10838 void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData * hMTData)
10840 STANDARD_VM_CONTRACT;
10843 // This verification is not applicable or required in many cases
10846 if (IsAbstract() || IsInterface())
10849 #ifdef FEATURE_COMINTEROP
10850 // Note that this is important for WinRT where redirected .NET interfaces appear on the interface
10851 // impl list but their methods are not implemented (the adapter only hides the WinRT methods, it
10852 // does not make up the .NET ones).
10853 if (bmtProp->fIsComObjectType)
10855 #endif // FEATURE_COMINTEROP
10857 // Since interfaces aren't laid out in the vtable for stub dispatch, what we need to do
10858 // is try to find an implementation for every interface contract by iterating through
10859 // the interfaces not declared on a parent.
10860 BOOL fParentIsAbstract = FALSE;
10863 fParentIsAbstract = GetParentMethodTable()->IsAbstract();
10866 // If the parent is abstract, we need to check that each virtual method is implemented
10867 if (fParentIsAbstract)
10869 // NOTE: Uses hMTData to avoid caching a MethodData object for the type being built.
10870 MethodTable::MethodIterator it(hMTData);
10871 for (; it.IsValid() && it.IsVirtual(); it.Next())
10873 MethodDesc *pMD = it.GetMethodDesc();
10874 if (pMD->IsAbstract())
10876 MethodDesc *pDeclMD = it.GetDeclMethodDesc();
10877 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pDeclMD->GetNameOnNonArrayClass());
10882 DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs =
10883 new (GetStackingAllocator()) DispatchMapTypeID[bmtInterface->dwInterfaceMapSize];
10885 bmtInterfaceInfo::MapIterator intIt = bmtInterface->IterateInterfaceMap();
10886 for (; !intIt.AtEnd(); intIt.Next())
10888 if (fParentIsAbstract || !intIt->IsImplementedByParent())
10890 // Compute all TypeIDs for this interface (all duplicates in the interface map)
10891 UINT32 cInterfaceDuplicates;
10892 ComputeDispatchMapTypeIDs(
10893 intIt->GetInterfaceType()->GetMethodTable(),
10894 &intIt->GetInterfaceType()->GetSubstitution(),
10895 rgInterfaceDispatchMapTypeIDs,
10896 bmtInterface->dwInterfaceMapSize,
10897 &cInterfaceDuplicates);
10898 _ASSERTE(cInterfaceDuplicates <= bmtInterface->dwInterfaceMapSize);
10899 _ASSERTE(cInterfaceDuplicates > 0);
10901 // NOTE: This override does not cache the resulting MethodData object.
10902 MethodTable::MethodDataWrapper hData(MethodTable::GetMethodData(
10903 rgInterfaceDispatchMapTypeIDs,
10904 cInterfaceDuplicates,
10905 intIt->GetInterfaceType()->GetMethodTable(),
10906 GetHalfBakedMethodTable()));
10907 MethodTable::MethodIterator it(hData);
10908 for (; it.IsValid() && it.IsVirtual(); it.Next())
10910 if (it.GetTarget().IsNull())
10912 MethodDesc *pMD = it.GetDeclMethodDesc();
10914 if (!HasDefaultInterfaceImplementation(pMD))
10915 BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass());
10922 INT32 __stdcall IsDefined(Module *pModule, mdToken token, TypeHandle attributeClass)
10931 BOOL isDefined = FALSE;
10933 IMDInternalImport *pInternalImport = pModule->GetMDImport();
10934 BOOL isSealed = FALSE;
10936 HENUMInternalHolder hEnum(pInternalImport);
10939 // Get the enum first but don't get any values
10940 hEnum.EnumInit(mdtCustomAttribute, token);
10942 ULONG cMax = pInternalImport->EnumGetCount(&hEnum);
10945 // we have something to look at
10948 if (!attributeClass.IsNull())
10949 isSealed = attributeClass.GetMethodTable()->IsSealed();
10951 // Loop through the Attributes and look for the requested one
10952 mdCustomAttribute cv;
10953 while (pInternalImport->EnumNext(&hEnum, &cv))
10958 IfFailThrow(pInternalImport->GetCustomAttributeProps(cv, &tkCtor));
10960 mdToken tkType = TypeFromToken(tkCtor);
10961 if(tkType != mdtMemberRef && tkType != mdtMethodDef)
10962 continue; // we only deal with the ctor case
10965 // get the info to load the type, so we can check whether the current
10966 // attribute is a subtype of the requested attribute
10967 IfFailThrow(pInternalImport->GetParentToken(tkCtor, &tkType));
10969 _ASSERTE(TypeFromToken(tkType) == mdtTypeRef || TypeFromToken(tkType) == mdtTypeDef);
10973 caTH=ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
10974 ClassLoader::ReturnNullIfNotFound,
10975 ClassLoader::FailIfUninstDefOrRef,
10976 TypeFromToken(tkType) == mdtTypeDef ? tdAllTypes : tdNoTypes);
10980 caTH = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tkType,
10981 ClassLoader::ReturnNullIfNotFound,
10982 ClassLoader::FailIfUninstDefOrRef);
10987 // a null class implies all custom attribute
10988 if (!attributeClass.IsNull())
10992 if (attributeClass != caTH)
10997 if (!caTH.CanCastTo(attributeClass))
11003 // if we are here we got one
11012 //*******************************************************************************
11013 VOID MethodTableBuilder::CheckForRemotingProxyAttrib()
11015 STANDARD_VM_CONTRACT;
11020 //*******************************************************************************
11021 // Checks for a bunch of special interface names and if it matches then it sets
11022 // bmtProp->fIsMngStandardItf to TRUE. Additionally, it checks to see if the
11023 // type is an interface and if it has ComEventInterfaceAttribute custom attribute
11024 // set, then it sets bmtProp->fComEventItfType to true.
11026 // NOTE: This only does anything when COM interop is enabled.
11028 VOID MethodTableBuilder::CheckForSpecialTypes()
11030 #ifdef FEATURE_COMINTEROP
11031 STANDARD_VM_CONTRACT;
11034 Module *pModule = GetModule();
11035 IMDInternalImport *pMDImport = pModule->GetMDImport();
11037 // Check to see if this type is a managed standard interface. All the managed
11038 // standard interfaces live in mscorlib.dll so checking for that first
11039 // makes the strcmp that comes afterwards acceptable.
11040 if (pModule->IsSystem())
11044 LPCUTF8 pszClassName;
11045 LPCUTF8 pszClassNamespace;
11046 if (FAILED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11048 pszClassName = pszClassNamespace = NULL;
11050 if ((pszClassName != NULL) && (pszClassNamespace != NULL))
11052 LPUTF8 pszFullyQualifiedName = NULL;
11053 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11055 // This is just to give us a scope to break out of.
11059 #define MNGSTDITF_BEGIN_INTERFACE(FriendlyName, strMngItfName, strUCOMMngItfName, strCustomMarshalerName, strCustomMarshalerCookie, strManagedViewName, NativeItfIID, bCanCastOnNativeItfQI) \
11060 if (strcmp(strMngItfName, pszFullyQualifiedName) == 0) \
11062 bmtProp->fIsMngStandardItf = true; \
11066 #define MNGSTDITF_DEFINE_METH_IMPL(FriendlyName, ECallMethName, MethName, MethSig, FcallDecl)
11068 #define MNGSTDITF_END_INTERFACE(FriendlyName)
11070 #include "mngstditflist.h"
11072 #undef MNGSTDITF_BEGIN_INTERFACE
11073 #undef MNGSTDITF_DEFINE_METH_IMPL
11074 #undef MNGSTDITF_END_INTERFACE
11078 if (strcmp(pszFullyQualifiedName, g_CollectionsGenericCollectionItfName) == 0 ||
11079 strcmp(pszFullyQualifiedName, g_CollectionsGenericReadOnlyCollectionItfName) == 0 ||
11080 strcmp(pszFullyQualifiedName, g_CollectionsCollectionItfName) == 0)
11082 // ICollection`1, ICollection and IReadOnlyCollection`1 are special cases the adapter is unaware of
11083 bmtProp->fIsRedirectedInterface = true;
11087 if (strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IEnumerable)) == 0 ||
11088 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IList)) == 0 ||
11089 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IDictionary)) == 0 ||
11090 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyList)) == 0 ||
11091 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyDictionary)) == 0 ||
11092 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_IEnumerable)) == 0 ||
11093 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_Collections_IList)) == 0 ||
11094 strcmp(pszFullyQualifiedName, WinMDAdapter::GetRedirectedTypeFullCLRName(WinMDAdapter::RedirectedTypeIndex_System_IDisposable)) == 0)
11096 bmtProp->fIsRedirectedInterface = true;
11100 // We want to allocate the per-type RCW data optional MethodTable field for
11101 // 1. Redirected interfaces
11102 // 2. Mscorlib-declared [WindowsRuntimeImport] interfaces
11103 bmtProp->fNeedsRCWPerTypeData = (bmtProp->fIsRedirectedInterface || GetHalfBakedClass()->IsProjectedFromWinRT());
11105 if (!bmtProp->fNeedsRCWPerTypeData)
11107 // 3. Non-generic IEnumerable
11108 if (strcmp(pszFullyQualifiedName, g_CollectionsEnumerableItfName) == 0)
11110 bmtProp->fNeedsRCWPerTypeData = true;
11115 else if (IsDelegate() && bmtGenerics->HasInstantiation())
11117 // 4. Redirected delegates
11118 if (GetHalfBakedClass()->GetWinRTRedirectedTypeIndex()
11119 != WinMDAdapter::RedirectedTypeIndex_Invalid)
11121 bmtProp->fNeedsRCWPerTypeData = true;
11125 else if (bmtGenerics->HasInstantiation() && pModule->GetAssembly()->IsWinMD())
11127 // 5. WinRT types with variance
11128 if (bmtGenerics->pVarianceInfo != NULL)
11130 bmtProp->fNeedsRCWPerTypeData = true;
11132 else if (IsInterface())
11134 // 6. Windows.Foundation.Collections.IIterator`1
11135 LPCUTF8 pszClassName;
11136 LPCUTF8 pszClassNamespace;
11137 if (SUCCEEDED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11139 LPUTF8 pszFullyQualifiedName = NULL;
11140 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11142 if (strcmp(pszFullyQualifiedName, g_WinRTIIteratorClassName) == 0)
11144 bmtProp->fNeedsRCWPerTypeData = true;
11149 else if ((IsInterface() || IsDelegate()) &&
11150 IsTdPublic(GetHalfBakedClass()->GetAttrClass()) &&
11151 GetHalfBakedClass()->GetWinRTRedirectedTypeIndex() != WinMDAdapter::RedirectedTypeIndex_Invalid)
11153 // 7. System.Collections.Specialized.INotifyCollectionChanged
11154 // 8. System.Collections.Specialized.NotifyCollectionChangedEventHandler
11155 // 9. System.ComponentModel.INotifyPropertyChanged
11156 // 10. System.ComponentModel.PropertyChangedEventHandler
11157 // 11. System.Windows.Input.ICommand
11158 LPCUTF8 pszClassName;
11159 LPCUTF8 pszClassNamespace;
11160 if (SUCCEEDED(pMDImport->GetNameOfTypeDef(GetCl(), &pszClassName, &pszClassNamespace)))
11162 LPUTF8 pszFullyQualifiedName = NULL;
11163 MAKE_FULLY_QUALIFIED_NAME(pszFullyQualifiedName, pszClassNamespace, pszClassName);
11165 if (strcmp(pszFullyQualifiedName, g_INotifyCollectionChangedName) == 0 ||
11166 strcmp(pszFullyQualifiedName, g_NotifyCollectionChangedEventHandlerName) == 0 ||
11167 strcmp(pszFullyQualifiedName, g_INotifyPropertyChangedName) == 0 ||
11168 strcmp(pszFullyQualifiedName, g_PropertyChangedEventHandlerName) == 0 ||
11169 strcmp(pszFullyQualifiedName, g_ICommandName) == 0)
11171 bmtProp->fNeedsRCWPerTypeData = true;
11176 // Check to see if the type is a COM event interface (classic COM interop only).
11177 if (IsInterface() && !GetHalfBakedClass()->IsProjectedFromWinRT())
11179 HRESULT hr = pMDImport->GetCustomAttributeByName(GetCl(), INTEROP_COMEVENTINTERFACE_TYPE, NULL, NULL);
11182 bmtProp->fComEventItfType = true;
11185 #endif // FEATURE_COMINTEROP
11188 #ifdef FEATURE_READYTORUN
11189 //*******************************************************************************
11190 VOID MethodTableBuilder::CheckLayoutDependsOnOtherModules(MethodTable * pDependencyMT)
11192 STANDARD_VM_CONTRACT;
11194 // These cases are expected to be handled by the caller
11195 _ASSERTE(!(pDependencyMT == g_pObjectClass || pDependencyMT->IsTruePrimitive() || ((g_pEnumClass != NULL) && pDependencyMT->IsEnum())));
11198 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11200 // Track whether field layout of this type depend on information outside its containing module
11202 // It is a stronger condition than MethodTable::IsInheritanceChainLayoutFixedInCurrentVersionBubble().
11203 // It has to remain fixed accross versioning changes in the module dependencies. In particular, it does
11204 // not take into account NonVersionable attribute. Otherwise, adding NonVersionable attribute to existing
11205 // type would be ReadyToRun incompatible change.
11207 if (pDependencyMT->GetModule() == GetModule())
11209 if (!pDependencyMT->GetClass()->HasLayoutDependsOnOtherModules())
11213 GetHalfBakedClass()->SetHasLayoutDependsOnOtherModules();
11216 BOOL MethodTableBuilder::NeedsAlignedBaseOffset()
11218 STANDARD_VM_CONTRACT;
11221 // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!!
11223 // This method returns whether the type needs aligned base offset in order to have layout resilient to
11224 // base class layout changes.
11226 if (IsValueClass())
11229 // Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on
11230 // whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching
11231 // ReadyToRun images with NGen.
11232 if (!GetModule()->GetFile()->IsILImageReadyToRun())
11234 // Always use ReadyToRun field layout algorithm to produce ReadyToRun images
11235 if (!IsReadyToRunCompilation())
11239 MethodTable * pParentMT = GetParentMethodTable();
11242 if (pParentMT == NULL || pParentMT == g_pObjectClass)
11245 if (pParentMT->GetModule() == GetModule())
11247 if (!pParentMT->GetClass()->HasLayoutDependsOnOtherModules())
11253 #endif // FEATURE_READYTORUN
11255 //*******************************************************************************
11257 // Used by BuildMethodTable
11259 // Set the HasFinalizer and HasCriticalFinalizer flags
11261 VOID MethodTableBuilder::SetFinalizationSemantics()
11263 STANDARD_VM_CONTRACT;
11265 if (g_pObjectFinalizerMD && !IsInterface() && !IsValueClass())
11267 WORD slot = g_pObjectFinalizerMD->GetSlot();
11269 // Objects not derived from Object will get marked as having a finalizer, if they have
11270 // sufficient virtual methods. This will only be an issue if they can be allocated
11271 // in the GC heap (which will cause all sorts of other problems).
11272 if (slot < bmtVT->cVirtualSlots && (*bmtVT)[slot].Impl().GetMethodDesc() != g_pObjectFinalizerMD)
11274 GetHalfBakedMethodTable()->SetHasFinalizer();
11276 // The need for a critical finalizer can be inherited from a parent.
11277 // Since we set this automatically for CriticalFinalizerObject
11278 // elsewhere, the code below is the means by which any derived class
11279 // picks up the attribute.
11280 if (HasParent() && GetParentMethodTable()->HasCriticalFinalizer())
11282 GetHalfBakedMethodTable()->SetHasCriticalFinalizer();
11288 //*******************************************************************************
11290 // Used by BuildMethodTable
11292 // Perform relevant GC calculations for value classes
11294 VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCache)
11296 STANDARD_VM_CONTRACT;
11300 EEClass *pClass = GetHalfBakedClass();
11301 MethodTable *pMT = GetHalfBakedMethodTable();
11303 FieldDesc *pFieldDescList = pClass->GetFieldDescList();
11305 // Note that for value classes, the following calculation is only appropriate
11306 // when the instance is in its "boxed" state.
11307 #ifdef FEATURE_COLLECTIBLE_TYPES
11308 if (bmtFP->NumGCPointerSeries == 0 && pMT->Collectible())
11310 // For collectible types, insert empty gc series
11311 CGCDescSeries *pSeries;
11313 CGCDesc::Init( (PVOID) pMT, 1);
11314 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11315 pSeries->SetSeriesSize( (size_t) (0) - (size_t) pMT->GetBaseSize());
11316 pSeries->SetSeriesOffset(sizeof(Object));
11319 #endif // FEATURE_COLLECTIBLE_TYPES
11320 if (bmtFP->NumGCPointerSeries != 0)
11322 CGCDescSeries *pSeries;
11323 CGCDescSeries *pHighest;
11325 pMT->SetContainsPointers();
11327 // Copy the pointer series map from the parent
11328 CGCDesc::Init( (PVOID) pMT, bmtFP->NumGCPointerSeries );
11329 if (bmtParent->NumParentPointerSeries != 0)
11331 size_t ParentGCSize = CGCDesc::ComputeSize(bmtParent->NumParentPointerSeries);
11332 memcpy( (PVOID) (((BYTE*) pMT) - ParentGCSize),
11333 (PVOID) (((BYTE*) GetParentMethodTable()) - ParentGCSize),
11334 ParentGCSize - sizeof(size_t) // sizeof(size_t) is the NumSeries count
11339 // Build the pointer series map for this pointers in this instance
11340 pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
11341 if (bmtFP->NumInstanceGCPointerFields)
11343 // See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
11344 pSeries->SetSeriesSize( (size_t) (bmtFP->NumInstanceGCPointerFields * sizeof(OBJECTREF)) - (size_t) pMT->GetBaseSize());
11345 pSeries->SetSeriesOffset(bmtFP->GCPointerFieldStart+sizeof(Object));
11349 // Insert GC info for fields which are by-value classes
11350 for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++)
11352 if (pFieldDescList[i].IsByValue())
11354 MethodTable *pByValueMT = pByValueClassCache[i];
11356 if (pByValueMT->ContainsPointers())
11358 // Offset of the by value class in the class we are building, does NOT include Object
11359 DWORD dwCurrentOffset = pFieldDescList[i].GetOffset_NoLogging();
11361 // The by value class may have more than one pointer series
11362 CGCDescSeries * pByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetLowestSeries();
11363 SIZE_T dwNumByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
11365 for (SIZE_T j = 0; j < dwNumByValueSeries; j++)
11367 size_t cbSeriesSize;
11368 size_t cbSeriesOffset;
11370 _ASSERTE(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11372 cbSeriesSize = pByValueSeries->GetSeriesSize();
11374 // Add back the base size of the by value class, since it's being transplanted to this class
11375 cbSeriesSize += pByValueMT->GetBaseSize();
11377 // Subtract the base size of the class we're building
11378 cbSeriesSize -= pMT->GetBaseSize();
11380 // Set current series we're building
11381 pSeries->SetSeriesSize(cbSeriesSize);
11383 // Get offset into the value class of the first pointer field (includes a +Object)
11384 cbSeriesOffset = pByValueSeries->GetSeriesOffset();
11386 // Add it to the offset of the by value class in our class
11387 cbSeriesOffset += dwCurrentOffset;
11389 pSeries->SetSeriesOffset(cbSeriesOffset); // Offset of field
11397 // Adjust the inherited series - since the base size has increased by "# new field instance bytes", we need to
11398 // subtract that from all the series (since the series always has BaseSize subtracted for it - see gcdesc.h)
11399 pHighest = CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries();
11400 while (pSeries <= pHighest)
11402 CONSISTENCY_CHECK(CheckPointer(GetParentMethodTable()));
11403 pSeries->SetSeriesSize( pSeries->GetSeriesSize() - ((size_t) pMT->GetBaseSize() - (size_t) GetParentMethodTable()->GetBaseSize()) );
11407 _ASSERTE(pSeries-1 <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
11412 //*******************************************************************************
11414 // Used by BuildMethodTable
11416 // Check for the presence of type equivalence. If present, make sure
11417 // it is permitted to be on this type.
11420 void MethodTableBuilder::CheckForTypeEquivalence(
11421 WORD cBuildingInterfaceList,
11422 BuildingInterfaceInfo_t *pBuildingInterfaceList)
11424 STANDARD_VM_CONTRACT;
11426 #ifdef FEATURE_TYPEEQUIVALENCE
11427 bmtProp->fIsTypeEquivalent = !!IsTypeDefEquivalent(GetCl(), GetModule());
11429 if (bmtProp->fIsTypeEquivalent)
11431 BOOL fTypeEquivalentNotPermittedDueToType = !(((IsComImport() || bmtProp->fComEventItfType) && IsInterface()) || IsValueClass() || IsDelegate());
11432 BOOL fTypeEquivalentNotPermittedDueToGenerics = bmtGenerics->HasInstantiation();
11434 if (fTypeEquivalentNotPermittedDueToType || fTypeEquivalentNotPermittedDueToGenerics)
11436 BuildMethodTableThrowException(IDS_CLASSLOAD_EQUIVALENTBADTYPE);
11439 GetHalfBakedClass()->SetIsEquivalentType();
11442 bmtProp->fHasTypeEquivalence = bmtProp->fIsTypeEquivalent;
11444 if (!bmtProp->fHasTypeEquivalence)
11446 // fHasTypeEquivalence flag is inherited from interfaces so we can quickly detect
11447 // types that implement type equivalent interfaces
11448 for (WORD i = 0; i < cBuildingInterfaceList; i++)
11450 MethodTable *pItfMT = pBuildingInterfaceList[i].m_pMethodTable;
11451 if (pItfMT->HasTypeEquivalence())
11453 bmtProp->fHasTypeEquivalence = true;
11459 if (!bmtProp->fHasTypeEquivalence)
11461 // fHasTypeEquivalence flag is "inherited" from generic arguments so we can quickly detect
11462 // types like List<Str> where Str is a structure with the TypeIdentifierAttribute.
11463 if (bmtGenerics->HasInstantiation() && !bmtGenerics->IsTypicalTypeDefinition())
11465 Instantiation inst = bmtGenerics->GetInstantiation();
11466 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
11468 if (inst[i].HasTypeEquivalence())
11470 bmtProp->fHasTypeEquivalence = true;
11476 #endif //FEATURE_TYPEEQUIVALENCE
11479 //*******************************************************************************
11481 // Used by BuildMethodTable
11483 // Before we make the final leap, make sure we've allocated all memory needed to
11484 // fill out the RID maps.
11486 VOID MethodTableBuilder::EnsureRIDMapsCanBeFilled()
11488 STANDARD_VM_CONTRACT;
11494 // Rather than call Ensure***CanBeStored() hundreds of times, we
11495 // will call it once on the largest token we find. This relies
11496 // on an invariant that RidMaps don't use some kind of sparse
11500 mdMethodDef largest = mdMethodDefNil;
11502 DeclaredMethodIterator it(*this);
11505 if (it.Token() > largest)
11507 largest = it.Token();
11510 if ( largest != mdMethodDefNil )
11512 GetModule()->EnsureMethodDefCanBeStored(largest);
11517 mdFieldDef largest = mdFieldDefNil;
11519 for (i = 0; i < bmtMetaData->cFields; i++)
11521 if (bmtMetaData->pFields[i] > largest)
11523 largest = bmtMetaData->pFields[i];
11526 if ( largest != mdFieldDefNil )
11528 GetModule()->EnsureFieldDefCanBeStored(largest);
11533 #ifdef FEATURE_COMINTEROP
11534 //*******************************************************************************
11535 void MethodTableBuilder::GetCoClassAttribInfo()
11537 STANDARD_VM_CONTRACT;
11539 if (!GetHalfBakedClass()->IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT interfaces
11541 // Retrieve the CoClassAttribute CA.
11542 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COCLASS_TYPE, NULL, NULL);
11545 // COM class interfaces may lazily populate the m_pCoClassForIntf field of EEClass. This field is
11546 // optional so we must ensure the optional field descriptor has been allocated.
11547 EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
11548 SetIsComClassInterface();
11552 #endif // FEATURE_COMINTEROP
11554 //*******************************************************************************
11555 void MethodTableBuilder::bmtMethodImplInfo::AddMethodImpl(
11556 bmtMDMethod * pImplMethod, bmtMethodHandle declMethod,
11557 StackingAllocator * pStackingAllocator)
11559 STANDARD_VM_CONTRACT;
11561 CONSISTENCY_CHECK(CheckPointer(pImplMethod));
11562 CONSISTENCY_CHECK(!declMethod.IsNull());
11563 if (pIndex >= cMaxIndex)
11565 DWORD newEntriesCount = 0;
11567 if (!ClrSafeInt<DWORD>::multiply(cMaxIndex, 2, newEntriesCount))
11568 ThrowHR(COR_E_OVERFLOW);
11570 if (newEntriesCount == 0)
11571 newEntriesCount = 10;
11573 // If we have to grow this array, we will not free the old array before we clean up the BuildMethodTable operation
11574 // because this is a stacking allocator. However, the old array will get freed when all the stack allocator is freed.
11575 Entry *rgEntriesNew = new (pStackingAllocator) Entry[newEntriesCount];
11576 memcpy(rgEntriesNew, rgEntries, sizeof(Entry) * cMaxIndex);
11578 // Start using newly allocated array.
11579 rgEntries = rgEntriesNew;
11580 cMaxIndex = newEntriesCount;
11582 rgEntries[pIndex++] = Entry(pImplMethod, declMethod);
11585 //*******************************************************************************
11586 // Returns TRUE if tok acts as a body for any methodImpl entry. FALSE, otherwise.
11587 BOOL MethodTableBuilder::bmtMethodImplInfo::IsBody(mdToken tok)
11589 LIMITED_METHOD_CONTRACT;
11590 CONSISTENCY_CHECK(TypeFromToken(tok) == mdtMethodDef);
11591 for (DWORD i = 0; i < pIndex; i++)
11593 if (GetBodyMethodDesc(i)->GetMemberDef() == tok)
11601 //*******************************************************************************
11603 MethodTableBuilder::AllocateFromHighFrequencyHeap(S_SIZE_T cbMem)
11612 return (BYTE *)GetMemTracker()->Track(
11613 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(cbMem));
11616 //*******************************************************************************
11618 MethodTableBuilder::AllocateFromLowFrequencyHeap(S_SIZE_T cbMem)
11627 return (BYTE *)GetMemTracker()->Track(
11628 GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(cbMem));
11631 //-------------------------------------------------------------------------------
11632 // Make best-case effort to obtain an image name for use in an error message.
11634 // This routine must expect to be called before the this object is fully loaded.
11635 // It can return an empty if the name isn't available or the object isn't initialized
11636 // enough to get a name, but it mustn't crash.
11637 //-------------------------------------------------------------------------------
11638 LPCWSTR MethodTableBuilder::GetPathForErrorMessages()
11640 STANDARD_VM_CONTRACT;
11642 return GetModule()->GetPathForErrorMessages();
11645 BOOL MethodTableBuilder::ChangesImplementationOfVirtualSlot(SLOT_INDEX idx)
11647 STANDARD_VM_CONTRACT;
11649 BOOL fChangesImplementation = TRUE;
11651 _ASSERTE(idx < bmtVT->cVirtualSlots);
11653 if (HasParent() && idx < GetParentMethodTable()->GetNumVirtuals())
11655 _ASSERTE(idx < bmtParent->pSlotTable->GetSlotCount());
11656 bmtMethodHandle VTImpl = (*bmtVT)[idx].Impl();
11657 bmtMethodHandle ParentImpl = (*bmtParent)[idx].Impl();
11659 fChangesImplementation = VTImpl != ParentImpl;
11661 // See code:MethodTableBuilder::SetupMethodTable2 and its logic
11662 // for handling MethodImpl's on parent classes which affect non interface
11664 if (!fChangesImplementation && (ParentImpl.GetSlotIndex() != idx))
11665 fChangesImplementation = TRUE;
11668 return fChangesImplementation;
11671 // Must be called prior to setting the value of any optional field on EEClass (on a debug build an assert will
11672 // fire if this invariant is violated).
11673 void MethodTableBuilder::EnsureOptionalFieldsAreAllocated(EEClass *pClass, AllocMemTracker *pamTracker, LoaderHeap *pHeap)
11675 STANDARD_VM_CONTRACT;
11677 if (pClass->HasOptionalFields())
11680 EEClassOptionalFields *pOptFields = (EEClassOptionalFields*)
11681 pamTracker->Track(pHeap->AllocMem(S_SIZE_T(sizeof(EEClassOptionalFields))));
11683 // Initialize default values for all optional fields.
11684 pOptFields->Init();
11686 // Attach optional fields to the class.
11687 pClass->AttachOptionalFields(pOptFields);
11690 //---------------------------------------------------------------------------------------
11692 // Gather information about a generic type
11693 // - number of parameters
11694 // - variance annotations
11700 MethodTableBuilder::GatherGenericsInfo(
11703 Instantiation inst,
11704 bmtGenericsInfo * bmtGenericsInfo)
11709 PRECONDITION(GetThread() != NULL);
11710 PRECONDITION(CheckPointer(pModule));
11711 PRECONDITION(CheckPointer(bmtGenericsInfo));
11715 IMDInternalImport * pInternalImport = pModule->GetMDImport();
11717 // Enumerate the formal type parameters
11718 HENUMInternal hEnumGenericPars;
11719 HRESULT hr = pInternalImport->EnumInit(mdtGenericParam, cl, &hEnumGenericPars);
11721 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11723 DWORD numGenericArgs = pInternalImport->EnumGetCount(&hEnumGenericPars);
11725 // Work out what kind of EEClass we're creating w.r.t. generics. If there
11726 // are no generics involved this will be a VMFLAG_NONGENERIC.
11727 BOOL fHasVariance = FALSE;
11728 if (numGenericArgs > 0)
11730 // Generic type verification
11734 if (FAILED(pInternalImport->GetTypeDefProps(cl, &dwAttr, &tkParent)))
11736 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11738 // A generic with explicit layout is not allowed.
11739 if (IsTdExplicitLayout(dwAttr))
11741 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_EXPLICIT_GENERIC);
11745 bmtGenericsInfo->numDicts = 1;
11747 mdGenericParam tkTyPar;
11748 bmtGenericsInfo->pVarianceInfo = new (&GetThread()->m_MarshalAlloc) BYTE[numGenericArgs];
11750 // If it has generic arguments but none have been specified, then load the instantiation at the formals
11751 if (inst.IsEmpty())
11753 bmtGenericsInfo->fTypicalInstantiation = TRUE;
11754 S_UINT32 scbAllocSize = S_UINT32(numGenericArgs) * S_UINT32(sizeof(TypeHandle));
11755 TypeHandle * genericArgs = (TypeHandle *) GetThread()->m_MarshalAlloc.Alloc(scbAllocSize);
11757 inst = Instantiation(genericArgs, numGenericArgs);
11759 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
11763 bmtGenericsInfo->fTypicalInstantiation = FALSE;
11765 bmtGenericsInfo->fSharedByGenericInstantiations = TypeHandle::IsCanonicalSubtypeInstantiation(inst);
11766 _ASSERTE(bmtGenericsInfo->fSharedByGenericInstantiations == ClassLoader::IsSharableInstantiation(inst));
11769 // Set typical instantiation MethodTable
11771 MethodTable * pTypicalInstantiationMT = pModule->LookupTypeDef(cl).AsMethodTable();
11772 // Typical instantiation was already loaded by code:ClassLoader::LoadApproxTypeThrowing
11773 _ASSERTE(pTypicalInstantiationMT != NULL);
11774 bmtGenericsInfo->dbg_pTypicalInstantiationMT = pTypicalInstantiationMT;
11779 TypeHandle * pDestInst = (TypeHandle *)inst.GetRawArgs();
11780 for (unsigned int i = 0; i < numGenericArgs; i++)
11782 pInternalImport->EnumNext(&hEnumGenericPars, &tkTyPar);
11784 if (FAILED(pInternalImport->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
11786 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11789 if (bmtGenericsInfo->fTypicalInstantiation)
11791 // code:Module.m_GenericParamToDescMap maps generic parameter RIDs to TypeVarTypeDesc
11792 // instances so that we do not leak by allocating them all over again, if the type
11793 // repeatedly fails to load.
11794 TypeVarTypeDesc *pTypeVarTypeDesc = pModule->LookupGenericParam(tkTyPar);
11795 if (pTypeVarTypeDesc == NULL)
11797 // Do NOT use the alloc tracker for this memory as we need it stay allocated even if the load fails.
11798 void *mem = (void *)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TypeVarTypeDesc)));
11799 pTypeVarTypeDesc = new (mem) TypeVarTypeDesc(pModule, cl, i, tkTyPar);
11801 // No race here - the row in GenericParam table is owned exclusively by this type and we
11802 // are holding a lock preventing other threads from concurrently loading it.
11803 pModule->StoreGenericParamThrowing(tkTyPar, pTypeVarTypeDesc);
11805 pDestInst[i] = TypeHandle(pTypeVarTypeDesc);
11808 DWORD varianceAnnotation = flags & gpVarianceMask;
11809 bmtGenericsInfo->pVarianceInfo[i] = static_cast<BYTE>(varianceAnnotation);
11810 if (varianceAnnotation != gpNonVariant)
11812 if (varianceAnnotation != gpContravariant && varianceAnnotation != gpCovariant)
11814 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADVARIANCE);
11818 fHasVariance = TRUE;
11824 bmtGenericsInfo->pVarianceInfo = NULL;
11828 bmtGenericsInfo->fTypicalInstantiation = FALSE;
11829 bmtGenericsInfo->fSharedByGenericInstantiations = FALSE;
11830 bmtGenericsInfo->numDicts = 0;
11833 bmtGenericsInfo->fContainsGenericVariables = MethodTable::ComputeContainsGenericVariables(inst);
11835 SigTypeContext typeContext(inst, Instantiation());
11836 bmtGenericsInfo->typeContext = typeContext;
11837 } // MethodTableBuilder::GatherGenericsInfo
11839 //---------------------------------------------------------------------------------------
11841 // This service is called for normal classes -- and for the pseudo class we invent to
11842 // hold the module's public members.
11846 ClassLoader::CreateTypeHandleForTypeDefThrowing(
11849 Instantiation inst,
11850 AllocMemTracker * pamTracker)
11852 CONTRACT(TypeHandle)
11855 PRECONDITION(GetThread() != NULL);
11856 PRECONDITION(CheckPointer(pModule));
11857 POSTCONDITION(!RETVAL.IsNull());
11858 POSTCONDITION(CheckPointer(RETVAL.GetMethodTable()));
11862 MethodTable * pMT = NULL;
11864 Thread * pThread = GetThread();
11865 BEGIN_SO_INTOLERANT_CODE_FOR(pThread, DefaultEntryProbeAmount() * 2)
11867 MethodTable * pParentMethodTable = NULL;
11868 SigPointer parentInst;
11869 mdTypeDef tdEnclosing = mdTypeDefNil;
11871 BuildingInterfaceInfo_t * pInterfaceBuildInfo = NULL;
11872 IMDInternalImport * pInternalImport = NULL;
11873 LayoutRawFieldInfo * pLayoutRawFieldInfos = NULL;
11874 MethodTableBuilder::bmtGenericsInfo genericsInfo;
11876 Assembly * pAssembly = pModule->GetAssembly();
11877 pInternalImport = pModule->GetMDImport();
11879 if (TypeFromToken(cl) != mdtTypeDef || !pInternalImport->IsValidToken(cl))
11881 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
11884 // GetCheckpoint for the thread-based allocator
11885 // This checkpoint provides a scope for all transient allocations of data structures
11886 // used during class loading.
11887 // <NICE> Ideally a debug/checked build should pass around tokens indicating the Checkpoint
11888 // being used and check these dynamically </NICE>
11889 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
11891 // Gather up generics info
11892 MethodTableBuilder::GatherGenericsInfo(pModule, cl, inst, &genericsInfo);
11894 Module * pLoaderModule = pModule;
11895 if (!inst.IsEmpty())
11897 pLoaderModule = ClassLoader::ComputeLoaderModuleWorker(
11902 pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(pModule, inst);
11905 LoaderAllocator * pAllocator = pLoaderModule->GetLoaderAllocator();
11908 // As this is loading a parent type, we are allowed to override the load type limit.
11909 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
11910 pParentMethodTable = LoadApproxParentThrowing(pModule, cl, &parentInst, &genericsInfo.typeContext);
11913 if (pParentMethodTable != NULL)
11915 // Since methods on System.Array assume the layout of arrays, we can not allow
11916 // subclassing of arrays, it is sealed from the users point of view.
11917 // Value types and enums should be sealed - disable inheritting from them (we cannot require sealed
11918 // flag because of AppCompat)
11919 if (pParentMethodTable->IsSealed() ||
11920 (pParentMethodTable == g_pArrayClass) ||
11921 pParentMethodTable->IsValueType())
11923 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_SEALEDPARENT);
11926 DWORD dwTotalDicts = genericsInfo.numDicts + pParentMethodTable->GetNumDicts();
11927 if (!FitsIn<WORD>(dwTotalDicts))
11929 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_TOOMANYGENERICARGS);
11931 genericsInfo.numDicts = static_cast<WORD>(dwTotalDicts);
11934 GetEnclosingClassThrowing(pInternalImport, pModule, cl, &tdEnclosing);
11936 BYTE nstructPackingSize = 0, nstructNLT = 0;
11937 BOOL fExplicitOffsets = FALSE;
11938 // NOTE: HasLayoutMetadata does not load classes
11940 !genericsInfo.fContainsGenericVariables &&
11942 pModule->GetAssembly(),
11945 pParentMethodTable,
11946 &nstructPackingSize,
11948 &fExplicitOffsets);
11950 BOOL fIsEnum = ((g_pEnumClass != NULL) && (pParentMethodTable == g_pEnumClass));
11952 // enums may not have layout because they derive from g_pEnumClass and that has no layout
11953 // this is enforced by HasLayoutMetadata above
11954 _ASSERTE(!(fIsEnum && fHasLayout));
11956 // This is a delegate class if it derives from MulticastDelegate (we do not allow single cast delegates)
11957 BOOL fIsDelegate = pParentMethodTable && pParentMethodTable == g_pMulticastDelegateClass;
11959 // Create a EEClass entry for it, filling out a few fields, such as the parent class token
11960 // (and the generic type should we be creating an instantiation)
11961 EEClass * pClass = MethodTableBuilder::CreateClass(
11971 if ((pParentMethodTable != NULL) && (pParentMethodTable == g_pDelegateClass))
11973 // Note we do not allow single cast delegates
11974 if (pModule->GetAssembly() != SystemDomain::SystemAssembly())
11976 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_CANNOT_INHERIT_FROM_DELEGATE);
11980 // Only MultiCastDelegate should inherit from Delegate
11983 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
11985 className = nameSpace = "Invalid TypeDef record";
11987 BAD_FORMAT_NOTHROW_ASSERT(strcmp(className, "MulticastDelegate") == 0);
11993 if (!pClass->IsSealed())
11995 pAssembly->ThrowTypeLoadException(pInternalImport, cl, BFA_DELEGATE_CLASS_NOTSEALED);
11998 pClass->SetIsDelegate();
12001 if (tdEnclosing != mdTypeDefNil)
12003 pClass->SetIsNested();
12004 THROW_BAD_FORMAT_MAYBE(IsTdNested(pClass->GetProtection()), VLDTR_E_TD_ENCLNOTNESTED, pModule);
12006 else if (IsTdNested(pClass->GetProtection()))
12008 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12011 // We only permit generic interfaces and delegates to have variant type parameters
12012 if (genericsInfo.pVarianceInfo != NULL && !pClass->IsInterface() && !fIsDelegate)
12014 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_CLASS);
12017 // Now load all the interfaces
12018 HENUMInternalHolder hEnumInterfaceImpl(pInternalImport);
12019 hEnumInterfaceImpl.EnumInit(mdtInterfaceImpl, cl);
12021 cInterfaces = pInternalImport->EnumGetCount(&hEnumInterfaceImpl);
12023 if (cInterfaces != 0)
12027 // Allocate the BuildingInterfaceList table
12028 pInterfaceBuildInfo = new (&GetThread()->m_MarshalAlloc) BuildingInterfaceInfo_t[cInterfaces];
12030 mdInterfaceImpl ii;
12031 for (i = 0; pInternalImport->EnumNext(&hEnumInterfaceImpl, &ii); i++)
12033 // Get properties on this interface
12034 mdTypeRef crInterface;
12035 if (FAILED(pInternalImport->GetTypeOfInterfaceImpl(ii, &crInterface)))
12037 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12039 // validate the token
12040 mdToken crIntType =
12041 (RidFromToken(crInterface) && pInternalImport->IsValidToken(crInterface)) ?
12042 TypeFromToken(crInterface) :
12051 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12054 TypeHandle intType;
12057 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
12058 intType = LoadApproxTypeThrowing(pModule, crInterface, NULL, &genericsInfo.typeContext);
12061 pInterfaceBuildInfo[i].m_pMethodTable = intType.AsMethodTable();
12062 if (pInterfaceBuildInfo[i].m_pMethodTable == NULL)
12064 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACENULL);
12067 // Ensure this is an interface
12068 if (!pInterfaceBuildInfo[i].m_pMethodTable->IsInterface())
12070 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_NOTINTERFACE);
12073 // Check interface for use of variant type parameters
12074 if ((genericsInfo.pVarianceInfo != NULL) && (TypeFromToken(crInterface) == mdtTypeSpec))
12077 PCCOR_SIGNATURE pSig;
12078 if (FAILED(pInternalImport->GetTypeSpecFromToken(crInterface, &pSig, &cSig)))
12080 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12082 // Interfaces behave covariantly
12083 if (!EEClass::CheckVarianceInSig(
12084 genericsInfo.GetNumGenericArgs(),
12085 genericsInfo.pVarianceInfo,
12087 SigPointer(pSig, cSig),
12090 pAssembly->ThrowTypeLoadException(
12093 IDS_CLASSLOAD_VARIANCE_IN_INTERFACE);
12097 _ASSERTE(i == cInterfaces);
12101 /* Variant delegates should not have any instance fields of the variant.
12102 type parameter. For now, we just completely disallow all fields even
12103 if they are non-variant or static, as it is not a useful scenario.
12104 @TODO: A more logical place for this check would be in
12105 MethodTableBuilder::EnumerateClassMembers() */
12106 (fIsDelegate && genericsInfo.pVarianceInfo))
12108 // check for fields and variance
12110 HENUMInternalHolder hEnumField(pInternalImport);
12111 hEnumField.EnumInit(mdtFieldDef, cl);
12113 cFields = pInternalImport->EnumGetCount(&hEnumField);
12115 if ((cFields != 0) && fIsDelegate && (genericsInfo.pVarianceInfo != NULL))
12117 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_IN_DELEGATE);
12122 // Though we fail on this condition, we should never run into it.
12123 CONSISTENCY_CHECK(nstructPackingSize != 0);
12124 // MD Val check: PackingSize
12125 if((nstructPackingSize == 0) ||
12126 (nstructPackingSize > 128) ||
12127 (nstructPackingSize & (nstructPackingSize-1)))
12129 THROW_BAD_FORMAT_MAYBE(!"ClassLayout:Invalid PackingSize", BFA_BAD_PACKING_SIZE, pModule);
12130 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
12133 pLayoutRawFieldInfos = (LayoutRawFieldInfo *)GetThread()->m_MarshalAlloc.Alloc(
12134 (S_UINT32(1) + S_UINT32(cFields)) * S_UINT32(sizeof(LayoutRawFieldInfo)));
12137 // Warning: this can load classes
12138 CONTRACT_VIOLATION(LoadsTypeViolation);
12140 // Set a flag that allows us to break dead-locks that are result of the LoadsTypeViolation
12141 ThreadStateNCStackHolder tsNC(TRUE, Thread::TSNC_LoadsTypeViolation);
12143 EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
12145 nstructPackingSize,
12147 #ifdef FEATURE_COMINTEROP
12148 pClass->IsProjectedFromWinRT(),
12149 #endif // FEATURE_COMINTEROP
12151 pParentMethodTable,
12155 &genericsInfo.typeContext,
12156 &(((LayoutEEClass *)pClass)->m_LayoutInfo),
12157 pLayoutRawFieldInfos,
12164 // Resolve this class, given that we know now that all of its dependencies are loaded and resolved.
12165 // !!! This must be the last thing in this TRY block: if MethodTableBuilder succeeds, it has published the class
12166 // and there is no going back.
12167 MethodTableBuilder builder(
12170 &GetThread()->m_MarshalAlloc,
12173 pMT = builder.BuildMethodTableThrowing(
12178 pInterfaceBuildInfo,
12179 pLayoutRawFieldInfos,
12180 pParentMethodTable,
12183 (WORD)cInterfaces);
12185 END_SO_INTOLERANT_CODE;
12186 RETURN(TypeHandle(pMT));
12187 } // ClassLoader::CreateTypeHandleForTypeDefThrowing