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.
10 #include "dllimport.h"
11 #include "dllimportcallback.h"
12 #include "fieldmarshaler.h"
13 #include "customattribute.h"
15 #include "typestring.h"
16 #include "dbginterface.h"
18 #ifdef FEATURE_COMINTEROP
19 #include "comcallablewrapper.h"
20 #include "clrtocomcall.h"
21 #include "runtimecallablewrapper.h"
22 #endif // FEATURE_COMINTEROP
24 //#define DEBUG_LAYOUT
27 #ifndef DACCESS_COMPILE
28 #include "methodtablebuilder.h"
30 #include "nsenumhandleallcases.h"
32 #ifndef DACCESS_COMPILE
35 //*******************************************************************************
36 EEClass::EEClass(DWORD cbFixedEEClassFields)
38 LIMITED_METHOD_CONTRACT;
40 // Cache size of fixed fields (this instance also contains a set of packed fields whose final size isn't
41 // determined until the end of class loading). We store the size into a spare byte made available by
42 // compiler field alignment, so we need to ensure we never allocate a flavor of EEClass more than 255
44 _ASSERTE(cbFixedEEClassFields <= 0xff);
45 m_cbFixedEEClassFields = (BYTE)cbFixedEEClassFields;
47 // All other members are initialized to zero
50 //*******************************************************************************
51 void *EEClass::operator new(
54 AllocMemTracker *pamTracker)
60 INJECT_FAULT(COMPlusThrowOM());
64 // EEClass (or sub-type) is always followed immediately by an EEClassPackedFields structure. This is
65 // maximally sized at runtime but in the ngen scenario will be optimized into a smaller structure (which
66 // is why it must go after all the fixed sized fields).
67 S_SIZE_T safeSize = S_SIZE_T(size) + S_SIZE_T(sizeof(EEClassPackedFields));
69 void *p = pamTracker->Track(pHeap->AllocMem(safeSize));
71 // No need to memset since this memory came from VirtualAlloc'ed memory
72 // memset (p, 0, size);
77 //*******************************************************************************
78 void EEClass::Destruct(MethodTable * pOwningMT)
85 PRECONDITION(pOwningMT != NULL);
89 #ifndef CROSSGEN_COMPILE
91 // Not expected to be called for array EEClass
92 _ASSERTE(!pOwningMT->IsArray());
95 _ASSERTE(!IsDestroyed());
99 #ifdef PROFILING_SUPPORTED
100 // If profiling, then notify the class is getting unloaded.
102 BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
104 // Calls to the profiler callback may throw, or otherwise fail, if
105 // the profiler AVs/throws an unhandled exception/etc. We don't want
106 // those failures to affect the runtime, so we'll ignore them.
108 // Note that the profiler callback may turn around and make calls into
109 // the profiling runtime that may throw. This try/catch block doesn't
110 // protect the profiler against such failures. To protect the profiler
111 // against that, we will need try/catch blocks around all calls into the
123 g_profControlBlock.pProfInterface->ClassUnloadStarted((ClassID) pOwningMT);
127 // The exception here came from the profiler itself. We'll just
128 // swallow the exception, since we don't want the profiler to bring
131 EX_END_CATCH(RethrowTerminalExceptions);
135 #endif // PROFILING_SUPPORTED
137 #ifdef FEATURE_COMINTEROP
138 // clean up any COM Data
141 m_pccwTemplate->Release();
142 m_pccwTemplate = NULL;
146 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
147 if (GetComClassFactory())
149 GetComClassFactory()->Cleanup();
151 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
152 #endif // FEATURE_COMINTEROP
157 DelegateEEClass* pDelegateEEClass = (DelegateEEClass*)this;
159 if (pDelegateEEClass->m_pStaticCallStub)
161 BOOL fStubDeleted = pDelegateEEClass->m_pStaticCallStub->DecRef();
164 DelegateInvokeStubManager::g_pManager->RemoveStub(pDelegateEEClass->m_pStaticCallStub);
167 if (pDelegateEEClass->m_pInstRetBuffCallStub)
169 pDelegateEEClass->m_pInstRetBuffCallStub->DecRef();
171 // While m_pMultiCastInvokeStub is also a member,
172 // it is owned by the m_pMulticastStubCache, not by the class
173 // - it is shared across classes. So we don't decrement
174 // its ref count here
175 delete pDelegateEEClass->m_pUMThunkMarshInfo;
178 #ifdef FEATURE_COMINTEROP
179 if (GetSparseCOMInteropVTableMap() != NULL && !pOwningMT->IsZapped())
180 delete GetSparseCOMInteropVTableMap();
181 #endif // FEATURE_COMINTEROP
183 #ifdef PROFILING_SUPPORTED
184 // If profiling, then notify the class is getting unloaded.
186 BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
188 // See comments in the call to ClassUnloadStarted for details on this
189 // FAULT_NOT_FATAL marker and exception swallowing.
194 g_profControlBlock.pProfInterface->ClassUnloadFinished((ClassID) pOwningMT, S_OK);
199 EX_END_CATCH(RethrowTerminalExceptions);
203 #endif // PROFILING_SUPPORTED
205 #endif // CROSSGEN_COMPILE
208 //*******************************************************************************
210 EEClass::CreateMinimalClass(LoaderHeap *pHeap, AllocMemTracker *pamTracker)
219 return new (pHeap, pamTracker) EEClass(sizeof(EEClass));
223 //*******************************************************************************
225 //-----------------------------------------------------------------------------------
226 // Note: this only loads the type to CLASS_DEPENDENCIES_LOADED as this can be called
227 // indirectly from DoFullyLoad() as part of accessibility checking.
228 //-----------------------------------------------------------------------------------
229 MethodTable *MethodTable::LoadEnclosingMethodTable(ClassLoadLevel targetLevel)
235 INJECT_FAULT(COMPlusThrowOM(););
240 mdTypeDef tdEnclosing = GetEnclosingCl();
242 if (tdEnclosing == mdTypeDefNil)
247 return ClassLoader::LoadTypeDefThrowing(GetModule(),
249 ClassLoader::ThrowIfNotFound,
250 ClassLoader::PermitUninstDefOrRef,
259 //*******************************************************************************
260 VOID EEClass::FixupFieldDescForEnC(MethodTable * pMT, EnCFieldDesc *pFD, mdFieldDef fieldDef)
266 WRAPPER(GC_TRIGGERS);
267 INJECT_FAULT(COMPlusThrowOM(););
271 Module * pModule = pMT->GetModule();
272 IMDInternalImport *pImport = pModule->GetMDImport();
275 if (LoggingEnabled())
278 if (FAILED(pImport->GetNameOfFieldDef(fieldDef, &szFieldName)))
280 szFieldName = "Invalid FieldDef record";
282 LOG((LF_ENC, LL_INFO100, "EEClass::InitializeFieldDescForEnC %s\n", szFieldName));
288 BOOL shouldBreak = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EncFixupFieldBreak);
289 if (shouldBreak > 0) {
290 _ASSERTE(!"EncFixupFieldBreak");
294 // MethodTableBuilder uses the stacking allocator for most of it's
295 // working memory requirements, so this makes sure to free the memory
296 // once this function is out of scope.
297 ACQUIRE_STACKING_ALLOCATOR(pStackingAllocator);
299 MethodTableBuilder::bmtMetaDataInfo bmtMetaData;
300 bmtMetaData.cFields = 1;
301 bmtMetaData.pFields = (mdToken*)_alloca(sizeof(mdToken));
302 bmtMetaData.pFields[0] = fieldDef;
303 bmtMetaData.pFieldAttrs = (DWORD*)_alloca(sizeof(DWORD));
304 IfFailThrow(pImport->GetFieldDefProps(fieldDef, &bmtMetaData.pFieldAttrs[0]));
306 MethodTableBuilder::bmtMethAndFieldDescs bmtMFDescs;
307 // We need to alloc the memory, but don't have to fill it in. InitializeFieldDescs
308 // will copy pFD (1st arg) into here.
309 bmtMFDescs.ppFieldDescList = (FieldDesc**)_alloca(sizeof(FieldDesc*));
311 MethodTableBuilder::bmtFieldPlacement bmtFP;
313 // This simulates the environment that BuildMethodTableThrowing creates
314 // just enough to run InitializeFieldDescs
315 MethodTableBuilder::bmtErrorInfo bmtError;
316 bmtError.pModule = pModule;
317 bmtError.cl = pMT->GetCl();
318 bmtError.dMethodDefInError = mdTokenNil;
319 bmtError.szMethodNameForError = NULL;
321 MethodTableBuilder::bmtInternalInfo bmtInternal;
322 bmtInternal.pModule = pModule;
323 bmtInternal.pInternalImport = pImport;
324 bmtInternal.pParentMT = pMT->GetParentMethodTable();
326 MethodTableBuilder::bmtProperties bmtProp;
327 bmtProp.fIsValueClass = !!pMT->IsValueType();
329 MethodTableBuilder::bmtEnumFieldInfo bmtEnumFields(bmtInternal.pInternalImport);
333 bmtEnumFields.dwNumStaticFields = 1;
337 bmtEnumFields.dwNumInstanceFields = 1;
340 // We shouldn't have to fill this in b/c we're not allowed to EnC value classes, or
341 // anything else with layout info associated with it.
342 LayoutRawFieldInfo *pLayoutRawFieldInfos = (LayoutRawFieldInfo*)_alloca((2) * sizeof(LayoutRawFieldInfo));
344 // If not NULL, it means there are some by-value fields, and this contains an entry for each instance or static field,
345 // which is NULL if not a by value field, and points to the EEClass of the field if a by value field. Instance fields
346 // come first, statics come second.
347 MethodTable **pByValueClassCache = NULL;
349 EEClass * pClass = pMT->GetClass();
351 // InitializeFieldDescs are going to change these numbers to something wrong,
352 // even though we already have the right numbers. Save & restore after.
353 WORD wNumInstanceFields = pMT->GetNumInstanceFields();
354 WORD wNumStaticFields = pMT->GetNumStaticFields();
355 unsigned totalDeclaredFieldSize = 0;
357 AllocMemTracker dummyAmTracker;
359 BaseDomain * pDomain = pMT->GetDomain();
360 MethodTableBuilder builder(pMT, pClass,
364 MethodTableBuilder::bmtGenericsInfo genericsInfo;
366 OBJECTREF pThrowable = NULL;
367 GCPROTECT_BEGIN(pThrowable);
369 builder.SetBMTData(pMT->GetLoaderAllocator(),
388 builder.InitializeFieldDescs(pFD,
389 pLayoutRawFieldInfos,
398 &totalDeclaredFieldSize);
400 EX_CATCH_THROWABLE(&pThrowable);
402 dummyAmTracker.SuppressRelease();
405 pClass->SetNumInstanceFields(wNumInstanceFields);
406 pClass->SetNumStaticFields(wNumStaticFields);
408 // PERF: For now, we turn off the fast equality check for valuetypes when a
409 // a field is modified by EnC. Consider doing a check and setting the bit only when
411 if (pMT->IsValueType())
413 pClass->SetIsNotTightlyPacked();
416 if (pThrowable != NULL)
418 COMPlusThrow(pThrowable);
423 pFD->SetMethodTable(pMT);
425 // We set this when we first created the FieldDesc, but initializing the FieldDesc
426 // may have overwritten it so we need to set it again.
432 //---------------------------------------------------------------------------------------
434 // AddField - called when a new field is added by EnC
436 // Since instances of this class may already exist on the heap, we can't change the
437 // runtime layout of the object to accomodate the new field. Instead we hang the field
438 // off the syncblock (for instance fields) or in the FieldDesc for static fields.
440 // Here we just create the FieldDesc and link it to the class. The actual storage will
441 // be created lazily on demand.
443 HRESULT EEClass::AddField(MethodTable * pMT, mdFieldDef fieldDef, EnCFieldDesc **ppNewFD)
453 Module * pModule = pMT->GetModule();
454 IMDInternalImport *pImport = pModule->GetMDImport();
457 if (LoggingEnabled())
460 if (FAILED(pImport->GetNameOfFieldDef(fieldDef, &szFieldName)))
462 szFieldName = "Invalid FieldDef record";
464 LOG((LF_ENC, LL_INFO100, "EEClass::AddField %s\n", szFieldName));
468 // We can only add fields to normal classes
469 if (pMT->HasLayout() || pMT->IsValueType())
471 return CORDBG_E_ENC_CANT_ADD_FIELD_TO_VALUE_OR_LAYOUT_CLASS;
474 // We only add private fields.
475 // This may not be strictly necessary, but helps avoid any semantic confusion with
476 // existing code etc.
478 IfFailThrow(pImport->GetFieldDefProps(fieldDef, &dwFieldAttrs));
480 LoaderAllocator* pAllocator = pMT->GetLoaderAllocator();
482 // Here we allocate a FieldDesc and set just enough info to be able to fix it up later
483 // when we're running in managed code.
484 EnCAddedFieldElement *pAddedField = (EnCAddedFieldElement *)
485 (void*)pAllocator->GetHighFrequencyHeap()->AllocMem_NoThrow(S_SIZE_T(sizeof(EnCAddedFieldElement)));
488 return E_OUTOFMEMORY;
490 pAddedField->Init( fieldDef, IsFdStatic(dwFieldAttrs) );
492 EnCFieldDesc *pNewFD = &pAddedField->m_fieldDesc;
494 // Get the EnCEEClassData for this class
495 // Don't adjust EEClass stats b/c EnC fields shouldn't touch EE data structures.
496 // We'll just update our private EnC structures instead.
497 EnCEEClassData *pEnCClass = ((EditAndContinueModule*)pModule)->GetEnCEEClassData(pMT);
501 // Add the field element to the list of added fields for this class
502 pEnCClass->AddField(pAddedField);
504 // Store the FieldDesc into the module's field list
506 CONTRACT_VIOLATION(ThrowsViolation); // B#25680 (Fix Enc violations): Must handle OOM's from Ensure
507 pModule->EnsureFieldDefCanBeStored(fieldDef);
509 pModule->EnsuredStoreFieldDef(fieldDef, pNewFD);
510 pNewFD->SetMethodTable(pMT);
512 // Success, return the new FieldDesc
520 //---------------------------------------------------------------------------------------
522 // AddMethod - called when a new method is added by EnC
524 // The method has already been added to the metadata with token methodDef.
525 // Create a new MethodDesc for the method.
527 HRESULT EEClass::AddMethod(MethodTable * pMT, mdMethodDef methodDef, RVA newRVA, MethodDesc **ppMethod)
537 Module * pModule = pMT->GetModule();
538 IMDInternalImport *pImport = pModule->GetMDImport();
541 if (LoggingEnabled())
544 if (FAILED(pImport->GetNameOfMethodDef(methodDef, &szMethodName)))
546 szMethodName = "Invalid MethodDef record";
548 LOG((LF_ENC, LL_INFO100, "EEClass::AddMethod %s\n", szMethodName));
556 if (FAILED(pImport->GetMethodImplProps(methodDef, &dwDescrOffset, &dwImplFlags)))
558 return COR_E_BADIMAGEFORMAT;
562 IfFailThrow(pImport->GetMethodDefProps(methodDef, &dwMemberAttrs));
564 // Refuse to add other special cases
565 if (IsReallyMdPinvokeImpl(dwMemberAttrs) ||
566 (pMT->IsInterface() && !IsMdStatic(dwMemberAttrs)) ||
567 IsMiRuntime(dwImplFlags))
569 _ASSERTE(! "**Error** EEClass::AddMethod only IL private non-virtual methods are supported");
570 LOG((LF_ENC, LL_INFO100, "**Error** EEClass::AddMethod only IL private non-virtual methods are supported\n"));
571 return CORDBG_E_ENC_EDIT_NOT_SUPPORTED;
575 // Validate that this methodDef correctly has a parent typeDef
576 mdTypeDef parentTypeDef;
577 if (FAILED(hr = pImport->GetParentToken(methodDef, &parentTypeDef)))
579 _ASSERTE(! "**Error** EEClass::AddMethod parent token not found");
580 LOG((LF_ENC, LL_INFO100, "**Error** EEClass::AddMethod parent token not found\n"));
585 EEClass * pClass = pMT->GetClass();
587 // @todo: OOM: InitMethodDesc will allocate loaderheap memory but leak it
588 // on failure. This AllocMemTracker should be replaced with a real one.
589 AllocMemTracker dummyAmTracker;
591 LoaderAllocator* pAllocator = pMT->GetLoaderAllocator();
593 // Create a new MethodDescChunk to hold the new MethodDesc
594 // Create the chunk somewhere we'll know is within range of the VTable
595 MethodDescChunk *pChunk = MethodDescChunk::CreateChunk(pAllocator->GetHighFrequencyHeap(),
596 1, // methodDescCount
598 TRUE /* fNonVtableSlot */,
599 TRUE /* fNativeCodeSlot */,
600 FALSE /* fComPlusCallInfo */,
604 // Get the new MethodDesc (Note: The method desc memory is zero initialized)
605 MethodDesc *pNewMD = pChunk->GetFirstMethodDesc();
608 // Initialize the new MethodDesc
610 // This method runs on a debugger thread. Debugger threads do not have Thread object that caches StackingAllocator.
611 // Use a local StackingAllocator instead.
612 StackingAllocator stackingAllocator;
614 MethodTableBuilder builder(pMT,
620 INDEBUG(LPCSTR debug_szFieldName);
621 INDEBUG(if (FAILED(pImport->GetNameOfMethodDef(methodDef, &debug_szFieldName))) { debug_szFieldName = "Invalid MethodDef record"; });
622 builder.InitMethodDesc(pNewMD,
623 mcInstantiated, // Use instantiated methoddesc for EnC added methods to get space for slot
631 COMMA_INDEBUG(debug_szFieldName)
632 COMMA_INDEBUG(pMT->GetDebugClassName())
636 pNewMD->SetTemporaryEntryPoint(pAllocator, &dummyAmTracker);
638 EX_CATCH_HRESULT(hr);
642 dummyAmTracker.SuppressRelease();
644 _ASSERTE(pNewMD->IsEnCAddedMethod());
646 pNewMD->SetSlot(MethodTable::NO_SLOT); // we can't ever use the slot for EnC methods
648 pClass->AddChunk(pChunk);
650 // Store the new MethodDesc into the collection for this class
651 pModule->EnsureMethodDefCanBeStored(methodDef);
652 pModule->EnsuredStoreMethodDef(methodDef, pNewMD);
654 LOG((LF_ENC, LL_INFO100, "EEClass::AddMethod new methoddesc %p for token %p\n", pNewMD, methodDef));
656 // Success - return the new MethodDesc
657 _ASSERTE( SUCCEEDED(hr) );
665 #endif // EnC_SUPPORTED
667 //---------------------------------------------------------------------------------------
669 // Check that the class type parameters are used consistently in this signature blob
670 // in accordance with their variance annotations
671 // The signature is assumed to be well-formed but indices and arities might not be correct
674 EEClass::CheckVarianceInSig(
675 DWORD numGenericArgs,
676 BYTE * pVarianceInfo,
679 CorGenericParamAttr position)
689 if (pVarianceInfo == NULL)
693 IfFailThrow(psig.GetElemType(&typ));
697 case ELEMENT_TYPE_STRING:
700 case ELEMENT_TYPE_I1:
701 case ELEMENT_TYPE_U1:
702 case ELEMENT_TYPE_BOOLEAN:
703 case ELEMENT_TYPE_I2:
704 case ELEMENT_TYPE_U2:
705 case ELEMENT_TYPE_CHAR:
706 case ELEMENT_TYPE_I4:
707 case ELEMENT_TYPE_U4:
708 case ELEMENT_TYPE_I8:
709 case ELEMENT_TYPE_U8:
710 case ELEMENT_TYPE_R4:
711 case ELEMENT_TYPE_R8:
712 case ELEMENT_TYPE_VOID:
713 case ELEMENT_TYPE_OBJECT:
714 case ELEMENT_TYPE_TYPEDBYREF:
715 case ELEMENT_TYPE_MVAR:
716 case ELEMENT_TYPE_CLASS:
717 case ELEMENT_TYPE_VALUETYPE:
720 case ELEMENT_TYPE_VAR:
723 IfFailThrow(psig.GetData(&index));
725 // This will be checked later anyway; so give up and don't indicate a variance failure
726 if (index < 0 || index >= numGenericArgs)
729 // Non-variant parameters are allowed to appear anywhere
730 if (pVarianceInfo[index] == gpNonVariant)
733 // Covariant and contravariant parameters can *only* appear in resp. covariant and contravariant positions
734 return ((CorGenericParamAttr) (pVarianceInfo[index]) == position);
737 case ELEMENT_TYPE_GENERICINST:
739 IfFailThrow(psig.GetElemType(&typ));
741 IfFailThrow(psig.GetToken(&typeref));
743 // The number of type parameters follows
745 IfFailThrow(psig.GetData(&ntypars));
747 // If this is a value type, or position == gpNonVariant, then
748 // we're disallowing covariant and contravariant completely
749 if (typ == ELEMENT_TYPE_VALUETYPE || position == gpNonVariant)
751 for (unsigned i = 0; i < ntypars; i++)
753 if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant))
756 IfFailThrow(psig.SkipExactlyOne());
759 // Otherwise we need to take notice of the variance annotation on each type parameter to the generic type
764 // This will also be resolved later; so, give up and don't indicate a variance failure
765 if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule, typeref, &pDefModule, &typeDef))
768 HENUMInternal hEnumGenericPars;
769 if (FAILED(pDefModule->GetMDImport()->EnumInit(mdtGenericParam, typeDef, &hEnumGenericPars)))
771 pDefModule->GetAssembly()->ThrowTypeLoadException(pDefModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
774 for (unsigned i = 0; i < ntypars; i++)
776 mdGenericParam tkTyPar;
777 pDefModule->GetMDImport()->EnumNext(&hEnumGenericPars, &tkTyPar);
779 if (FAILED(pDefModule->GetMDImport()->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
781 pDefModule->GetAssembly()->ThrowTypeLoadException(pDefModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
783 CorGenericParamAttr genPosition = (CorGenericParamAttr) (flags & gpVarianceMask);
784 // If the surrounding context is contravariant then we need to flip the variance of this parameter
785 if (position == gpContravariant)
787 genPosition = genPosition == gpCovariant ? gpContravariant
788 : genPosition == gpContravariant ? gpCovariant
791 if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, genPosition))
794 IfFailThrow(psig.SkipExactlyOne());
796 pDefModule->GetMDImport()->EnumClose(&hEnumGenericPars);
802 // Arrays behave covariantly
803 case ELEMENT_TYPE_ARRAY:
804 case ELEMENT_TYPE_SZARRAY:
805 return CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, position);
807 // Pointers behave non-variantly
808 case ELEMENT_TYPE_BYREF:
809 case ELEMENT_TYPE_PTR:
810 return CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant);
812 case ELEMENT_TYPE_FNPTR:
814 // Calling convention
815 IfFailThrow(psig.GetData(NULL));
819 IfFailThrow(psig.GetData(&cArgs));
821 // Conservatively, assume non-variance of function pointer types
822 if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant))
825 IfFailThrow(psig.SkipExactlyOne());
827 for (unsigned i = 0; i < cArgs; i++)
829 if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant))
832 IfFailThrow(psig.SkipExactlyOne());
839 THROW_BAD_FORMAT(IDS_CLASSLOAD_BAD_VARIANCE_SIG, pModule);
843 } // EEClass::CheckVarianceInSig
846 ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)
851 PRECONDITION(CheckPointer(pMT));
856 TypeHandle thisTH(pMT);
857 SigTypeContext typeContext(thisTH);
858 IMDInternalImport* pInternalImport = pMT->GetMDImport();
859 MethodTable *pParentMT = pMT->GetParentMethodTable();
861 if (pParentMT != NULL && pParentMT->HasInstantiation())
863 // Fill in exact parent if it's instantiated
865 IfFailThrow(pInternalImport->GetTypeDefProps(
870 _ASSERTE(!IsNilToken(crExtends));
871 _ASSERTE(TypeFromToken(crExtends) == mdtTypeSpec);
873 TypeHandle newParent = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(), crExtends, &typeContext,
874 ClassLoader::ThrowIfNotFound,
875 ClassLoader::FailIfUninstDefOrRef,
876 ClassLoader::LoadTypes,
877 CLASS_LOAD_EXACTPARENTS,
880 MethodTable* pNewParentMT = newParent.AsMethodTable();
881 if (pNewParentMT != pParentMT)
883 LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Replaced approximate parent %s with exact parent %s from token %x\n", pParentMT->GetDebugClassName(), pNewParentMT->GetDebugClassName(), crExtends));
885 // SetParentMethodTable is not used here since we want to update the indirection cell in the NGen case
886 if (pMT->IsParentMethodTableIndirectPointerMaybeNull())
888 *EnsureWritablePages(pMT->GetParentMethodTableValuePtr()) = pNewParentMT;
892 EnsureWritablePages(pMT->GetParentMethodTablePointerPtr());
893 pMT->GetParentMethodTablePointerPtr()->SetValueMaybeNull(pNewParentMT);
896 pParentMT = pNewParentMT;
900 if (pParentMT != NULL)
902 EnsureLoaded(pParentMT, CLASS_LOAD_EXACTPARENTS);
906 if (pParentMT != NULL && pParentMT->HasPerInstInfo())
908 // Copy down all inherited dictionary pointers which we
910 DWORD nDicts = pParentMT->GetNumDicts();
911 for (DWORD iDict = 0; iDict < nDicts; iDict++)
913 if (pMT->GetPerInstInfo()[iDict].GetValueMaybeNull() != pParentMT->GetPerInstInfo()[iDict].GetValueMaybeNull())
915 EnsureWritablePages(&pMT->GetPerInstInfo()[iDict]);
916 pMT->GetPerInstInfo()[iDict].SetValueMaybeNull(pParentMT->GetPerInstInfo()[iDict].GetValueMaybeNull());
921 #ifdef FEATURE_PREJIT
922 // Restore action, not in MethodTable::Restore because we may have had approx parents at that point
925 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
928 Module::RestoreMethodTablePointer(&it.GetInterfaceInfo()->m_pMethodTable, pMT->GetLoaderModule(), CLASS_LOAD_EXACTPARENTS);
934 MethodTableBuilder::LoadExactInterfaceMap(pMT);
938 if (g_pConfig->ShouldDumpOnClassLoad(pMT->GetDebugClassName()))
940 pMT->Debug_DumpInterfaceMap("Exact");
943 } // ClassLoader::LoadExactParentAndInterfacesTransitively
945 // CLASS_LOAD_EXACTPARENTS phase of loading:
946 // * Load the base class at exact instantiation
947 // * Recurse LoadExactParents up parent hierarchy
948 // * Load explicitly declared interfaces on this class at exact instantiation
952 void ClassLoader::LoadExactParents(MethodTable *pMT)
957 PRECONDITION(CheckPointer(pMT));
958 POSTCONDITION(pMT->CheckLoadLevel(CLASS_LOAD_EXACTPARENTS));
962 MethodTable *pApproxParentMT = pMT->GetParentMethodTable();
964 if (!pMT->IsCanonicalMethodTable())
966 EnsureLoaded(TypeHandle(pMT->GetCanonicalMethodTable()), CLASS_LOAD_EXACTPARENTS);
969 LoadExactParentAndInterfacesTransitively(pMT);
971 MethodTableBuilder::CopyExactParentSlots(pMT, pApproxParentMT);
973 // We can now mark this type as having exact parents
974 pMT->SetHasExactParent();
979 //*******************************************************************************
980 // This is the routine that computes the internal type of a given type. It normalizes
981 // structs that have only one field (of int/ptr sized values), to be that underlying type.
983 // * see code:MethodTable#KindsOfElementTypes for more
984 // * It get used by code:TypeHandle::GetInternalCorElementType
985 CorElementType EEClass::ComputeInternalCorElementTypeForValueType(MethodTable * pMT)
992 if (pMT->GetNumInstanceFields() == 1 && (!pMT->HasLayout()
993 || pMT->GetNumInstanceFieldBytes() == 4
994 #ifdef _TARGET_64BIT_
995 || pMT->GetNumInstanceFieldBytes() == 8
996 #endif // _TARGET_64BIT_
997 )) // Don't do the optimization if we're getting specified anything but the trivial layout.
999 FieldDesc * pFD = pMT->GetApproxFieldDescListRaw();
1000 CorElementType type = pFD->GetFieldType();
1002 if (type == ELEMENT_TYPE_VALUETYPE)
1004 //@todo: Is it more apropos to call LookupApproxFieldTypeHandle() here?
1005 TypeHandle fldHnd = pFD->GetApproxFieldTypeHandleThrowing();
1006 CONSISTENCY_CHECK(!fldHnd.IsNull());
1008 type = fldHnd.GetInternalCorElementType();
1013 // "DDB 20951: vc8 unmanaged pointer bug."
1014 // If ELEMENT_TYPE_PTR were returned, Compiler::verMakeTypeInfo would have problem
1015 // creating a TI_STRUCT out of CORINFO_TYPE_PTR.
1016 // As a result, the importer would not be able to realize that the thing on the stack
1017 // is an instance of a valuetype (that contains one single "void*" field), rather than
1018 // a pointer to a valuetype.
1019 // Returning ELEMENT_TYPE_U allows verMakeTypeInfo to go down the normal code path
1020 // for creating a TI_STRUCT.
1021 case ELEMENT_TYPE_PTR:
1022 type = ELEMENT_TYPE_U;
1024 case ELEMENT_TYPE_I:
1025 case ELEMENT_TYPE_U:
1026 case ELEMENT_TYPE_I4:
1027 case ELEMENT_TYPE_U4:
1028 #ifdef _TARGET_64BIT_
1029 case ELEMENT_TYPE_I8:
1030 case ELEMENT_TYPE_U8:
1031 #endif // _TARGET_64BIT_
1042 return ELEMENT_TYPE_VALUETYPE;
1045 //*******************************************************************************
1047 // Debugger notification
1049 BOOL TypeHandle::NotifyDebuggerLoad(AppDomain *pDomain, BOOL attaching) const
1051 LIMITED_METHOD_CONTRACT;
1053 if (!CORDebuggerAttached())
1058 if (!GetModule()->IsVisibleToDebugger())
1063 return g_pDebugInterface->LoadClass(
1064 *this, GetCl(), GetModule(), pDomain);
1067 //*******************************************************************************
1068 void TypeHandle::NotifyDebuggerUnload(AppDomain *pDomain) const
1070 LIMITED_METHOD_CONTRACT;
1072 if (!GetModule()->IsVisibleToDebugger())
1075 if (!pDomain->IsDebuggerAttached())
1078 g_pDebugInterface->UnloadClass(GetCl(), GetModule(), pDomain);
1081 //*******************************************************************************
1082 // Given the (generics-shared or generics-exact) value class method, find the
1083 // (generics-shared) unboxing Stub for the given method . We search the vtable.
1085 // This is needed when creating a delegate to an instance method in a value type
1086 MethodDesc* MethodTable::GetBoxedEntryPointMD(MethodDesc *pMD)
1088 CONTRACT (MethodDesc *) {
1091 INJECT_FAULT(COMPlusThrowOM(););
1092 PRECONDITION(IsValueType());
1093 PRECONDITION(!pMD->ContainsGenericVariables());
1094 PRECONDITION(!pMD->IsUnboxingStub());
1095 POSTCONDITION(RETVAL->IsUnboxingStub());
1098 RETURN MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
1099 pMD->GetMethodTable(),
1100 TRUE /* get unboxing entry point */,
1101 pMD->GetMethodInstantiation(),
1102 FALSE /* no allowInstParam */ );
1106 //*******************************************************************************
1107 // Given the unboxing value class method, find the non-unboxing method
1108 // This is used when generating the code for an BoxedEntryPointStub.
1109 MethodDesc* MethodTable::GetUnboxedEntryPointMD(MethodDesc *pMD)
1111 CONTRACT (MethodDesc *) {
1114 INJECT_FAULT(COMPlusThrowOM(););
1115 PRECONDITION(IsValueType());
1116 // reflection needs to call this for methods in non instantiated classes,
1117 // so move the assert to the caller when needed
1118 //PRECONDITION(!pMD->ContainsGenericVariables());
1119 PRECONDITION(pMD->IsUnboxingStub());
1120 POSTCONDITION(!RETVAL->IsUnboxingStub());
1123 BOOL allowInstParam = (pMD->GetNumGenericMethodArgs() == 0);
1124 RETURN MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
1126 FALSE /* don't get unboxing entry point */,
1127 pMD->GetMethodInstantiation(),
1132 //*******************************************************************************
1133 // Given the unboxing value class method, find the non-unboxing method
1134 // This is used when generating the code for an BoxedEntryPointStub.
1135 MethodDesc* MethodTable::GetExistingUnboxedEntryPointMD(MethodDesc *pMD)
1137 CONTRACT (MethodDesc *) {
1140 INJECT_FAULT(COMPlusThrowOM(););
1141 PRECONDITION(IsValueType());
1142 // reflection needs to call this for methods in non instantiated classes,
1143 // so move the assert to the caller when needed
1144 //PRECONDITION(!pMD->ContainsGenericVariables());
1145 PRECONDITION(pMD->IsUnboxingStub());
1146 POSTCONDITION(!RETVAL->IsUnboxingStub());
1149 BOOL allowInstParam = (pMD->GetNumGenericMethodArgs() == 0);
1150 RETURN MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
1152 FALSE /* don't get unboxing entry point */,
1153 pMD->GetMethodInstantiation(),
1155 FALSE, /* forceRemotableMethod */
1156 FALSE /* allowCreate */
1160 #endif // !DACCESS_COMPILE
1162 //*******************************************************************************
1163 #if !defined(FEATURE_HFA)
1164 bool MethodTable::IsHFA()
1166 LIMITED_METHOD_CONTRACT;
1167 #ifdef DACCESS_COMPILE
1170 if (GetClass()->GetMethodTable()->IsValueType())
1172 return GetClass()->CheckForHFA();
1180 #endif // !FEATURE_HFA
1182 //*******************************************************************************
1183 int MethodTable::GetVectorSize()
1185 // This is supported for finding HVA types for Arm64. In order to support the altjit,
1186 // we support this on 64-bit platforms (i.e. Arm64 and X64).
1187 #ifdef _TARGET_64BIT_
1188 if (IsIntrinsicType())
1190 LPCUTF8 namespaceName;
1191 LPCUTF8 className = GetFullyQualifiedNameInfo(&namespaceName);
1194 if (strcmp(className, "Vector`1") == 0)
1196 vectorSize = GetNumInstanceFieldBytes();
1197 _ASSERTE(strcmp(namespaceName, "System.Numerics") == 0);
1200 if (strcmp(className, "Vector128`1") == 0)
1204 else if (strcmp(className, "Vector256`1") == 0)
1208 else if (strcmp(className, "Vector64`1") == 0)
1212 if (vectorSize != 0)
1214 // We need to verify that T (the element or "base" type) is a primitive type.
1215 TypeHandle typeArg = GetInstantiation()[0];
1216 CorElementType corType = typeArg.GetSignatureCorElementType();
1217 bool isSupportedElementType = (corType >= ELEMENT_TYPE_I1 && corType <= ELEMENT_TYPE_R8);
1218 // These element types are not supported for Vector64<T>.
1219 if ((vectorSize == 8) && (corType == ELEMENT_TYPE_I8 || corType == ELEMENT_TYPE_U8 || corType == ELEMENT_TYPE_R8))
1221 isSupportedElementType = false;
1223 if (isSupportedElementType)
1225 _ASSERTE(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0);
1230 #endif // _TARGET_64BIT_
1234 //*******************************************************************************
1235 CorElementType MethodTable::GetHFAType()
1239 WRAPPER(THROWS); // we end up in the class loader which has the conditional contracts
1240 WRAPPER(GC_TRIGGERS);
1245 return ELEMENT_TYPE_END;
1247 MethodTable * pMT = this;
1250 _ASSERTE(pMT->IsValueType());
1251 _ASSERTE(pMT->GetNumInstanceFields() > 0);
1253 int vectorSize = pMT->GetVectorSize();
1254 if (vectorSize != 0)
1256 return (vectorSize == 8) ? ELEMENT_TYPE_R8 : ELEMENT_TYPE_VALUETYPE;
1259 PTR_FieldDesc pFirstField = pMT->GetApproxFieldDescListRaw();
1261 CorElementType fieldType = pFirstField->GetFieldType();
1263 // All HFA fields have to be of the same type, so we can just return the type of the first field
1266 case ELEMENT_TYPE_VALUETYPE:
1267 pMT = pFirstField->LookupApproxFieldTypeHandle().GetMethodTable();
1268 vectorSize = pMT->GetVectorSize();
1269 if (vectorSize != 0)
1271 return (vectorSize == 8) ? ELEMENT_TYPE_R8 : ELEMENT_TYPE_VALUETYPE;
1275 case ELEMENT_TYPE_R4:
1276 case ELEMENT_TYPE_R8:
1280 // This should never happen. MethodTable::IsHFA() should be set only on types
1281 // that have a valid HFA type when the flag is used to track HFA status.
1283 return ELEMENT_TYPE_END;
1288 bool MethodTable::IsNativeHFA()
1290 LIMITED_METHOD_CONTRACT;
1291 return HasLayout() ? GetLayoutInfo()->IsNativeHFA() : IsHFA();
1294 CorElementType MethodTable::GetNativeHFAType()
1296 LIMITED_METHOD_CONTRACT;
1297 return HasLayout() ? GetLayoutInfo()->GetNativeHFAType() : GetHFAType();
1300 //---------------------------------------------------------------------------------------
1302 // When FEATURE_HFA is defined, we cache the value; otherwise we recompute it with each
1303 // call. The latter is only for the armaltjit and the arm64altjit.
1306 #if defined(FEATURE_HFA)
1307 EEClass::CheckForHFA(MethodTable ** pByValueClassCache)
1309 EEClass::CheckForHFA()
1312 STANDARD_VM_CONTRACT;
1314 // This method should be called for valuetypes only
1315 _ASSERTE(GetMethodTable()->IsValueType());
1318 // The opaque Vector types appear to have multiple fields, but need to be treated
1319 // as an opaque type of a single vector.
1320 if (GetMethodTable()->GetVectorSize() != 0)
1322 #if defined(FEATURE_HFA)
1323 GetMethodTable()->SetIsHFA();
1329 CorElementType hfaType = ELEMENT_TYPE_END;
1331 FieldDesc *pFieldDescList = GetFieldDescList();
1333 bool hasZeroOffsetField = false;
1335 for (UINT i = 0; i < GetNumInstanceFields(); i++)
1337 FieldDesc *pFD = &pFieldDescList[i];
1338 hasZeroOffsetField |= (pFD->GetOffset() == 0);
1340 CorElementType fieldType = pFD->GetFieldType();
1344 case ELEMENT_TYPE_VALUETYPE:
1346 #ifdef _TARGET_ARM64_
1347 // hfa/hva types are unique by size, except for Vector64 which we can conveniently
1348 // treat as if it were a double for ABI purposes. However, it only qualifies as
1349 // an HVA if all fields are the same type. This will ensure that we only
1350 // consider it an HVA if all the fields are ELEMENT_TYPE_VALUETYPE (which have been
1351 // determined above to be vectors) of the same size.
1353 #if defined(FEATURE_HFA)
1354 pMT = pByValueClassCache[i];
1356 pMT = pFD->LookupApproxFieldTypeHandle().AsMethodTable();
1358 int thisElemSize = pMT->GetVectorSize();
1359 if (thisElemSize != 0)
1363 elemSize = thisElemSize;
1365 else if ((thisElemSize != elemSize) || (hfaType != ELEMENT_TYPE_VALUETYPE))
1371 #endif // _TARGET_ARM64_
1373 #if defined(FEATURE_HFA)
1374 fieldType = pByValueClassCache[i]->GetHFAType();
1376 fieldType = pFD->LookupApproxFieldTypeHandle().AsMethodTable()->GetHFAType();
1382 case ELEMENT_TYPE_R4:
1384 static const int REQUIRED_FLOAT_ALIGNMENT = 4;
1385 if (pFD->GetOffset() % REQUIRED_FLOAT_ALIGNMENT != 0) // HFAs don't have unaligned fields.
1391 case ELEMENT_TYPE_R8:
1393 static const int REQUIRED_DOUBLE_ALIGNMENT = 8;
1394 if (pFD->GetOffset() % REQUIRED_DOUBLE_ALIGNMENT != 0) // HFAs don't have unaligned fields.
1405 // Field type should be a valid HFA type.
1406 if (fieldType == ELEMENT_TYPE_END)
1411 // Initialize with a valid HFA type.
1412 if (hfaType == ELEMENT_TYPE_END)
1414 hfaType = fieldType;
1416 // All field types should be equal.
1417 else if (fieldType != hfaType)
1425 case ELEMENT_TYPE_R4:
1428 case ELEMENT_TYPE_R8:
1431 #ifdef _TARGET_ARM64_
1432 case ELEMENT_TYPE_VALUETYPE:
1433 // Should already have set elemSize, but be conservative
1445 if (!hasZeroOffsetField) // If the struct doesn't have a zero-offset field, it's not an HFA.
1448 // Note that we check the total size, but do not perform any checks on number of fields:
1449 // - Type of fields can be HFA valuetype itself
1450 // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that
1451 // the valuetype is HFA and explicitly specified size
1453 DWORD totalSize = GetMethodTable()->GetNumInstanceFieldBytes();
1455 if (totalSize % elemSize != 0)
1458 // On ARM, HFAs can have a maximum of four fields regardless of whether those are float or double.
1459 if (totalSize / elemSize > 4)
1462 // All the above tests passed. It's HFA(/HVA)!
1463 #if defined(FEATURE_HFA)
1464 GetMethodTable()->SetIsHFA();
1469 CorElementType EEClassLayoutInfo::GetNativeHFATypeRaw()
1471 UINT numReferenceFields = GetNumCTMFields();
1473 CorElementType hfaType = ELEMENT_TYPE_END;
1475 #ifndef DACCESS_COMPILE
1476 const FieldMarshaler *pFieldMarshaler = GetFieldMarshalers();
1477 while (numReferenceFields--)
1479 CorElementType fieldType = ELEMENT_TYPE_END;
1481 switch (pFieldMarshaler->GetNStructFieldType())
1485 fieldType = pFieldMarshaler->GetFieldDesc()->GetFieldType();
1486 // An HFA can only have aligned float and double fields
1487 if ((fieldType != ELEMENT_TYPE_R4 && fieldType != ELEMENT_TYPE_R8) || (pFieldMarshaler->GetExternalOffset() % pFieldMarshaler->AlignmentRequirement() != 0))
1488 return ELEMENT_TYPE_END;
1491 case NFT_NESTEDLAYOUTCLASS:
1492 fieldType = ((FieldMarshaler_NestedLayoutClass *)pFieldMarshaler)->GetMethodTable()->GetNativeHFAType();
1495 case NFT_NESTEDVALUECLASS:
1496 fieldType = ((FieldMarshaler_NestedValueClass *)pFieldMarshaler)->GetMethodTable()->GetNativeHFAType();
1499 case NFT_FIXEDARRAY:
1500 fieldType = ((FieldMarshaler_FixedArray *)pFieldMarshaler)->GetElementTypeHandle().GetMethodTable()->GetNativeHFAType();
1504 fieldType = ELEMENT_TYPE_R8;
1509 return ELEMENT_TYPE_END;
1512 // Field type should be a valid HFA type.
1513 if (fieldType == ELEMENT_TYPE_END)
1515 return ELEMENT_TYPE_END;
1518 // Initialize with a valid HFA type.
1519 if (hfaType == ELEMENT_TYPE_END)
1521 hfaType = fieldType;
1523 // All field types should be equal.
1524 else if (fieldType != hfaType)
1526 return ELEMENT_TYPE_END;
1529 ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
1532 if (hfaType == ELEMENT_TYPE_END)
1533 return ELEMENT_TYPE_END;
1538 case ELEMENT_TYPE_R4: elemSize = sizeof(float); break;
1539 case ELEMENT_TYPE_R8: elemSize = sizeof(double); break;
1540 #ifdef _TARGET_ARM64_
1541 case ELEMENT_TYPE_VALUETYPE: elemSize = 16; break;
1543 default: _ASSERTE(!"Invalid HFA Type");
1546 // Note that we check the total size, but do not perform any checks on number of fields:
1547 // - Type of fields can be HFA valuetype itself
1548 // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that
1549 // the valuetype is HFA and explicitly specified size
1551 DWORD totalSize = GetNativeSize();
1553 if (totalSize % elemSize != 0)
1554 return ELEMENT_TYPE_END;
1556 // On ARM, HFAs can have a maximum of four fields regardless of whether those are float or double.
1557 if (totalSize / elemSize > 4)
1558 return ELEMENT_TYPE_END;
1560 #endif // !DACCESS_COMPILE
1567 // The managed and unmanaged views of the types can differ for non-blitable types. This method
1568 // mirrors the HFA type computation for the unmanaged view.
1570 VOID EEClass::CheckForNativeHFA()
1572 STANDARD_VM_CONTRACT;
1574 // No HFAs with inheritance
1575 if (!(GetMethodTable()->IsValueType() || (GetMethodTable()->GetParentMethodTable() == g_pObjectClass)))
1578 // No HFAs with explicit layout. There may be cases where explicit layout may be still
1579 // eligible for HFA, but it is hard to tell the real intent. Make it simple and just
1580 // unconditionally disable HFAs for explicit layout.
1581 if (HasExplicitFieldOffsetLayout())
1584 CorElementType hfaType = GetLayoutInfo()->GetNativeHFATypeRaw();
1585 if (hfaType == ELEMENT_TYPE_END)
1590 // All the above tests passed. It's HFA!
1591 GetLayoutInfo()->SetNativeHFAType(hfaType);
1593 #endif // FEATURE_HFA
1595 #ifdef FEATURE_64BIT_ALIGNMENT
1596 // Returns true iff the native view of this type requires 64-bit aligment.
1597 bool MethodTable::NativeRequiresAlign8()
1599 LIMITED_METHOD_CONTRACT;
1603 return (GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers() >= 8);
1605 return RequiresAlign8();
1607 #endif // FEATURE_64BIT_ALIGNMENT
1609 #ifndef DACCESS_COMPILE
1611 #ifdef FEATURE_COMINTEROP
1612 //==========================================================================================
1613 TypeHandle MethodTable::GetCoClassForInterface()
1619 INJECT_FAULT(COMPlusThrowOM(););
1623 EEClass * pClass = GetClass();
1625 if (!pClass->IsComClassInterface())
1626 return TypeHandle();
1628 _ASSERTE(IsInterface());
1630 TypeHandle th = pClass->GetCoClassForInterface();
1634 return SetupCoClassForInterface();
1637 //*******************************************************************************
1638 TypeHandle MethodTable::SetupCoClassForInterface()
1644 INJECT_FAULT(COMPlusThrowOM(););
1645 PRECONDITION(IsComClassInterface());
1650 TypeHandle CoClassType;
1651 const BYTE *pVal = NULL;
1654 if (!IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT types
1656 HRESULT hr = GetCustomAttribute(WellKnownAttribute::CoClass, (const void **)&pVal, &cbVal);
1659 CustomAttributeParser cap(pVal, cbVal);
1661 IfFailThrow(cap.SkipProlog());
1663 // Retrieve the COM source interface class name.
1666 IfFailThrow(cap.GetNonNullString(&szName, &cbName));
1668 // Copy the name to a temporary buffer and NULL terminate it.
1669 StackSString ss(SString::Utf8, szName, cbName);
1671 // Try to load the class using its name as a fully qualified name. If that fails,
1672 // then we try to load it in the assembly of the current class.
1673 CoClassType = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), GetAssembly());
1675 // Cache the coclass type
1676 g_IBCLogger.LogEEClassCOWTableAccess(this);
1677 GetClass_NoLogging()->SetCoClassForInterface(CoClassType);
1683 //*******************************************************************************
1684 void MethodTable::GetEventInterfaceInfo(MethodTable **ppSrcItfClass, MethodTable **ppEvProvClass)
1690 INJECT_FAULT(COMPlusThrowOM(););
1695 TypeHandle EventProvType;
1696 TypeHandle SrcItfType;
1697 const BYTE *pVal = NULL;
1700 // Retrieve the ComEventProviderAttribute CA.
1701 HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COMEVENTINTERFACE_TYPE, (const void**)&pVal, &cbVal);
1707 CustomAttributeParser cap(pVal, cbVal);
1709 // Skip the CA type prefix.
1710 IfFailThrow(cap.SkipProlog());
1712 // Retrieve the COM source interface class name.
1715 IfFailThrow(cap.GetNonNullString(&szName, &cbName));
1717 // Copy the name to a temporary buffer and NULL terminate it.
1718 StackSString ss(SString::Utf8, szName, cbName);
1720 // Try to load the class using its name as a fully qualified name. If that fails,
1721 // then we try to load it in the assembly of the current class.
1722 SrcItfType = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), GetAssembly());
1724 // Retrieve the COM event provider class name.
1725 IfFailThrow(cap.GetNonNullString(&szName, &cbName));
1727 // Copy the name to a temporary buffer and NULL terminate it.
1728 ss.SetUTF8(szName, cbName);
1730 // Try to load the class using its name as a fully qualified name. If that fails,
1731 // then we try to load it in the assembly of the current class.
1732 EventProvType = TypeName::GetTypeUsingCASearchRules(ss.GetUnicode(), GetAssembly());
1734 // Set the source interface and event provider classes.
1735 *ppSrcItfClass = SrcItfType.GetMethodTable();
1736 *ppEvProvClass = EventProvType.GetMethodTable();
1739 //*******************************************************************************
1740 TypeHandle MethodTable::GetDefItfForComClassItf()
1746 INJECT_FAULT(COMPlusThrowOM(););
1750 BAD_FORMAT_NOTHROW_ASSERT(GetClass()->IsComClassInterface());
1752 // The COM class interface uses the normal scheme which is to have no
1753 // methods and to implement default interface and optionnally the
1754 // default source interface. In this scheme, the first implemented
1755 // interface is the default interface which we return.
1756 InterfaceMapIterator it = IterateInterfaceMap();
1759 return TypeHandle(it.GetInterface());
1763 // The COM class interface has the methods directly on the itself.
1764 // Because of this we need to consider it to be the default interface.
1765 return TypeHandle(this);
1769 #endif // FEATURE_COMINTEROP
1772 #endif // !DACCESS_COMPILE
1774 //---------------------------------------------------------------------------------------
1776 // Get the metadata token of the outer type for a nested type
1779 // The token of the outer class if this EEClass is nested, or mdTypeDefNil if the
1780 // EEClass is not a nested type
1783 mdTypeDef MethodTable::GetEnclosingCl()
1793 mdTypeDef tdEnclosing = mdTypeDefNil;
1795 if (GetClass()->IsNested())
1797 HRESULT hr = GetMDImport()->GetNestedClassProps(GetCl(), &tdEnclosing);
1800 ThrowHR(hr, BFA_UNABLE_TO_GET_NESTED_PROPS);
1807 //*******************************************************************************
1809 // Helper routines for the macros defined at the top of this class.
1810 // You probably should not use these functions directly.
1812 template<typename RedirectFunctor>
1813 SString &MethodTable::_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf)
1818 INJECT_FAULT(COMPlusThrowOM(););
1823 LPCUTF8 pszNamespace;
1825 pszName = GetFullyQualifiedNameInfo(&pszNamespace);
1826 if (pszName == NULL)
1831 StackSString ssName(SString::Utf8, pszName);
1833 mdTypeDef mdEncl = GetCl();
1834 IMDInternalImport *pImport = GetMDImport();
1836 // Check if the type is nested
1838 IfFailThrow(pImport->GetTypeDefProps(GetCl(), &dwAttr, NULL));
1840 RedirectFunctor redirectFunctor;
1841 if (IsTdNested(dwAttr))
1843 StackSString ssFullyQualifiedName;
1844 StackSString ssPath;
1846 // Build the nesting chain.
1847 while (SUCCEEDED(pImport->GetNestedClassProps(mdEncl, &mdEncl)))
1850 LPCUTF8 szEnclNameSpace;
1851 IfFailThrow(pImport->GetNameOfTypeDef(
1856 ns::MakePath(ssPath,
1857 StackSString(SString::Utf8, redirectFunctor(szEnclNameSpace)),
1858 StackSString(SString::Utf8, szEnclName));
1859 ns::MakeNestedTypeName(ssFullyQualifiedName, ssPath, ssName);
1861 ssName = ssFullyQualifiedName;
1867 StackSString(SString::Utf8, redirectFunctor(pszNamespace)), ssName);
1875 LPCUTF8 operator() (LPCUTF8 szEnclNamespace)
1877 LIMITED_METHOD_CONTRACT;
1879 return szEnclNamespace;
1883 SString &MethodTable::_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf)
1885 LIMITED_METHOD_CONTRACT;
1887 return _GetFullyQualifiedNameForClassNestedAwareInternal<PassThrough>(ssBuf);
1890 //*******************************************************************************
1891 SString &MethodTable::_GetFullyQualifiedNameForClass(SString &ssBuf)
1897 INJECT_FAULT(COMPlusThrowOM(););
1905 TypeDesc::ConstructName(GetInternalCorElementType(),
1906 GetApproxArrayElementTypeHandle(),
1910 else if (!IsNilToken(GetCl()))
1912 LPCUTF8 szNamespace;
1914 IfFailThrow(GetMDImport()->GetNameOfTypeDef(GetCl(), &szName, &szNamespace));
1917 StackSString(SString::Utf8, szNamespace),
1918 StackSString(SString::Utf8, szName));
1924 //*******************************************************************************
1926 // Gets the namespace and class name for the class. The namespace
1927 // can legitimately come back NULL, however a return value of NULL indicates
1930 // NOTE: this used to return array class names, which were sometimes squirreled away by the
1931 // class loader hash table. It's been removed because it wasted space and was basically broken
1932 // in general (sometimes wasn't set, sometimes set wrong). If you need array class names,
1933 // use GetFullyQualifiedNameForClass instead.
1935 LPCUTF8 MethodTable::GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace)
1947 *ppszNamespace = NULL;
1953 if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &szName, ppszNamespace)))
1955 *ppszNamespace = NULL;
1962 #ifndef DACCESS_COMPILE
1964 #ifdef FEATURE_COMINTEROP
1966 //*******************************************************************************
1967 CorIfaceAttr MethodTable::GetComInterfaceType()
1977 // This should only be called on interfaces.
1978 BAD_FORMAT_NOTHROW_ASSERT(IsInterface());
1980 // Check to see if we have already determined the COM interface type
1981 // of this interface.
1982 CorIfaceAttr ItfType = GetClass()->GetComInterfaceType();
1984 if (ItfType != (CorIfaceAttr)-1)
1987 if (IsProjectedFromWinRT())
1989 // WinRT interfaces are always IInspectable-based
1990 ItfType = ifInspectable;
1994 // Retrieve the interface type from the metadata.
1995 HRESULT hr = GetMDImport()->GetIfaceTypeOfTypeDef(GetCl(), (ULONG*)&ItfType);
2000 // if not found in metadata, use the default
2005 // Cache the interface type
2006 g_IBCLogger.LogEEClassCOWTableAccess(this);
2007 GetClass_NoLogging()->SetComInterfaceType(ItfType);
2012 #endif // FEATURE_COMINTEROP
2014 //*******************************************************************************
2015 void EEClass::GetBestFitMapping(MethodTable * pMT, BOOL *pfBestFitMapping, BOOL *pfThrowOnUnmappableChar)
2025 EEClass * pClass = pMT->GetClass();
2028 if (!(pClass->m_VMFlags & VMFLAG_BESTFITMAPPING_INITED))
2030 *pfBestFitMapping = FALSE;
2031 *pfThrowOnUnmappableChar = FALSE;
2033 ReadBestFitCustomAttribute(pMT->GetModule(), pMT->GetCl(), pfBestFitMapping, pfThrowOnUnmappableChar);
2035 DWORD flags = VMFLAG_BESTFITMAPPING_INITED;
2036 if (*pfBestFitMapping) flags |= VMFLAG_BESTFITMAPPING;
2037 if (*pfThrowOnUnmappableChar) flags |= VMFLAG_THROWONUNMAPPABLECHAR;
2039 FastInterlockOr(EnsureWritablePages(&pClass->m_VMFlags), flags);
2043 *pfBestFitMapping = (pClass->m_VMFlags & VMFLAG_BESTFITMAPPING);
2044 *pfThrowOnUnmappableChar = (pClass->m_VMFlags & VMFLAG_THROWONUNMAPPABLECHAR);
2050 //*******************************************************************************
2051 void MethodTable::DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug)
2053 WRAPPER_NO_CONTRACT; // It's a dev helper, who cares about contracts
2057 StackSString ssBuff;
2059 DWORD cParentInstanceFields;
2062 CONSISTENCY_CHECK(CheckLoadLevel(CLASS_LOAD_APPROXPARENTS));
2064 MethodTable *pParentMT = GetParentMethodTable();
2065 if (pParentMT != NULL)
2067 cParentInstanceFields = pParentMT->GetClass()->GetNumInstanceFields();
2068 DefineFullyQualifiedNameForClass();
2069 LPCUTF8 name = GetFullyQualifiedNameForClass(pParentMT);
2070 pParentMT->DebugRecursivelyDumpInstanceFields(name, debug);
2074 cParentInstanceFields = 0;
2077 // Are there any new instance fields declared by this class?
2078 if (GetNumInstanceFields() > cParentInstanceFields)
2082 ssBuff.Printf(W("%S:\n"), pszClassName);
2083 WszOutputDebugString(ssBuff.GetUnicode());
2086 LOG((LF_CLASSLOADER, LL_ALWAYS, "%s:\n", pszClassName));
2089 for (i = 0; i < (GetNumInstanceFields()-cParentInstanceFields); i++)
2091 FieldDesc *pFD = &GetClass()->GetFieldDescList()[i];
2093 printf("offset %s%3d %s\n", pFD->IsByValue() ? "byvalue " : "", pFD->GetOffset_NoLogging(), pFD->GetName());
2096 ssBuff.Printf(W("offset %3d %S\n"), pFD->GetOffset_NoLogging(), pFD->GetName());
2097 WszOutputDebugString(ssBuff.GetUnicode());
2100 LOG((LF_CLASSLOADER, LL_ALWAYS, "offset %3d %s\n", pFD->GetOffset_NoLogging(), pFD->GetName()));
2109 WszOutputDebugString(W("<Exception Thrown>\n"));
2113 LOG((LF_CLASSLOADER, LL_ALWAYS, "<Exception Thrown>\n"));
2116 EX_END_CATCH(SwallowAllExceptions);
2119 //*******************************************************************************
2120 void MethodTable::DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug)
2122 WRAPPER_NO_CONTRACT; // It's a dev helper, who cares about contracts
2124 if (GetNumStaticFields() == 0 && GetNumInstanceFields() == 0)
2129 StackSString ssBuff;
2132 DWORD cParentInstanceFields;
2134 CONSISTENCY_CHECK(CheckLoadLevel(CLASS_LOAD_APPROXPARENTS));
2136 if (GetParentMethodTable() != NULL)
2137 cParentInstanceFields = GetParentMethodTable()->GetNumInstanceFields();
2140 cParentInstanceFields = 0;
2145 ssBuff.Printf(W("Field layout for '%S':\n\n"), pszClassName);
2146 WszOutputDebugString(ssBuff.GetUnicode());
2150 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2151 LOG((LF_ALWAYS, LL_ALWAYS, "Field layout for '%s':\n\n", pszClassName));
2154 if (GetNumStaticFields() > 0)
2158 WszOutputDebugString(W("Static fields (stored at vtable offsets)\n"));
2159 WszOutputDebugString(W("----------------------------------------\n"));
2163 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2164 LOG((LF_ALWAYS, LL_ALWAYS, "Static fields (stored at vtable offsets)\n"));
2165 LOG((LF_ALWAYS, LL_ALWAYS, "----------------------------------------\n"));
2168 for (i = 0; i < GetNumStaticFields(); i++)
2170 FieldDesc *pFD = GetClass()->GetFieldDescList() + ((GetNumInstanceFields()-cParentInstanceFields) + i);
2172 ssBuff.Printf(W("offset %3d %S\n"), pFD->GetOffset_NoLogging(), pFD->GetName());
2173 WszOutputDebugString(ssBuff.GetUnicode());
2177 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2178 LOG((LF_ALWAYS, LL_ALWAYS, "offset %3d %s\n", pFD->GetOffset_NoLogging(), pFD->GetName()));
2183 if (GetNumInstanceFields() > 0)
2185 if (GetNumStaticFields()) {
2187 WszOutputDebugString(W("\n"));
2191 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2192 LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
2198 WszOutputDebugString(W("Instance fields\n"));
2199 WszOutputDebugString(W("---------------\n"));
2203 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2204 LOG((LF_ALWAYS, LL_ALWAYS, "Instance fields\n"));
2205 LOG((LF_ALWAYS, LL_ALWAYS, "---------------\n"));
2208 DebugRecursivelyDumpInstanceFields(pszClassName, debug);
2213 WszOutputDebugString(W("\n"));
2217 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2218 LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
2225 WszOutputDebugString(W("<Exception Thrown>\n"));
2229 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2230 LOG((LF_ALWAYS, LL_ALWAYS, "<Exception Thrown>\n"));
2233 EX_END_CATCH(SwallowAllExceptions);
2234 } // MethodTable::DebugDumpFieldLayout
2236 //*******************************************************************************
2238 MethodTable::DebugDumpGCDesc(
2239 LPCUTF8 pszClassName,
2242 WRAPPER_NO_CONTRACT; // It's a dev helper, who cares about contracts
2246 StackSString ssBuff;
2250 ssBuff.Printf(W("GC description for '%S':\n\n"), pszClassName);
2251 WszOutputDebugString(ssBuff.GetUnicode());
2255 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2256 LOG((LF_ALWAYS, LL_ALWAYS, "GC description for '%s':\n\n", pszClassName));
2259 if (ContainsPointersOrCollectible())
2261 CGCDescSeries *pSeries;
2262 CGCDescSeries *pHighest;
2266 WszOutputDebugString(W("GCDesc:\n"));
2269 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2270 LOG((LF_ALWAYS, LL_ALWAYS, "GCDesc:\n"));
2273 pSeries = CGCDesc::GetCGCDescFromMT(this)->GetLowestSeries();
2274 pHighest = CGCDesc::GetCGCDescFromMT(this)->GetHighestSeries();
2276 while (pSeries <= pHighest)
2280 ssBuff.Printf(W(" offset %5d (%d w/o Object), size %5d (%5d w/o BaseSize subtr)\n"),
2281 pSeries->GetSeriesOffset(),
2282 pSeries->GetSeriesOffset() - OBJECT_SIZE,
2283 pSeries->GetSeriesSize(),
2284 pSeries->GetSeriesSize() + GetBaseSize() );
2285 WszOutputDebugString(ssBuff.GetUnicode());
2289 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2290 LOG((LF_ALWAYS, LL_ALWAYS, " offset %5d (%d w/o Object), size %5d (%5d w/o BaseSize subtr)\n",
2291 pSeries->GetSeriesOffset(),
2292 pSeries->GetSeriesOffset() - OBJECT_SIZE,
2293 pSeries->GetSeriesSize(),
2294 pSeries->GetSeriesSize() + GetBaseSize()
2302 WszOutputDebugString(W("\n"));
2305 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2306 LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
2314 WszOutputDebugString(W("<Exception Thrown>\n"));
2318 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2319 LOG((LF_ALWAYS, LL_ALWAYS, "<Exception Thrown>\n"));
2322 EX_END_CATCH(SwallowAllExceptions);
2323 } // MethodTable::DebugDumpGCDesc
2327 #ifdef FEATURE_COMINTEROP
2328 //*******************************************************************************
2329 CorClassIfaceAttr MethodTable::GetComClassInterfaceType()
2336 PRECONDITION(!IsInterface());
2340 // If the type is an open generic type, then it is considered ClassInterfaceType.None.
2341 if (ContainsGenericVariables())
2344 // Classes that either have generic instantiations (G<int>) or derive from classes
2345 // with generic instantiations (D : B<int>) are always considered ClassInterfaceType.None.
2346 if (HasGenericClassInstantiationInHierarchy())
2349 // If the class does not support IClassX because it derives from or implements WinRT types,
2350 // then it is considered ClassInterfaceType.None unless explicitly overriden by the CA
2351 if (!ClassSupportsIClassX(this))
2354 return ReadClassInterfaceTypeCustomAttribute(TypeHandle(this));
2356 #endif // FEATURE_COMINTEROP
2358 //---------------------------------------------------------------------------------------
2361 MethodTable::GetSubstitutionForParent(
2362 const Substitution * pSubst)
2377 return Substitution(GetModule(), SigPointer(), pSubst);
2380 IfFailThrow(GetMDImport()->GetTypeDefProps(
2385 return Substitution(crExtends, GetModule(), pSubst);
2386 } // MethodTable::GetSubstitutionForParent
2388 #endif //!DACCESS_COMPILE
2391 //*******************************************************************************
2392 #ifdef FEATURE_PREJIT
2393 DWORD EEClass::GetSize()
2403 // Total instance size consists of the fixed ("normal") fields, cached at construction time and dependent
2404 // on whether we're a vanilla EEClass or DelegateEEClass etc., and a portion for the packed fields tacked on
2405 // the end. The size of the packed fields can be retrieved from the fields themselves or, if we were
2406 // unsuccessful in our attempts to compress the data, the full size of the EEClassPackedFields structure
2407 // (which is essentially just a DWORD array of all the field values).
2408 return m_cbFixedEEClassFields +
2409 (m_fFieldsArePacked ? GetPackedFields()->GetPackedSize() : sizeof(EEClassPackedFields));
2411 #endif // FEATURE_PREJIT
2413 #ifndef DACCESS_COMPILE
2414 #ifdef FEATURE_COMINTEROP
2417 // Implementations of SparseVTableMap methods.
2420 //*******************************************************************************
2421 SparseVTableMap::SparseVTableMap()
2423 LIMITED_METHOD_CONTRACT;
2425 // Note that this will also zero out all gaps. It is important for NGen determinism.
2426 ZeroMemory(this, sizeof(*this));
2429 //*******************************************************************************
2430 SparseVTableMap::~SparseVTableMap()
2432 LIMITED_METHOD_CONTRACT;
2434 if (m_MapList != NULL)
2436 delete [] m_MapList;
2441 //*******************************************************************************
2442 // Allocate or expand the mapping list for a new entry.
2443 void SparseVTableMap::AllocOrExpand()
2445 STANDARD_VM_CONTRACT;
2447 if (m_MapEntries == m_Allocated) {
2449 Entry *maplist = new Entry[m_Allocated + MapGrow];
2451 if (m_MapList != NULL)
2452 memcpy(maplist, m_MapList, m_MapEntries * sizeof(Entry));
2454 m_Allocated += MapGrow;
2455 delete [] m_MapList;
2456 m_MapList = maplist;
2460 //*******************************************************************************
2461 // While building mapping list, record a gap in VTable slot numbers.
2462 void SparseVTableMap::RecordGap(WORD StartMTSlot, WORD NumSkipSlots)
2464 STANDARD_VM_CONTRACT;
2466 _ASSERTE((StartMTSlot == 0) || (StartMTSlot > m_MTSlot));
2467 _ASSERTE(NumSkipSlots > 0);
2469 // We use the information about the current gap to complete a map entry for
2470 // the last non-gap. There is a special case where the vtable begins with a
2471 // gap, so we don't have a non-gap to record.
2472 if (StartMTSlot == 0) {
2473 _ASSERTE((m_MTSlot == 0) && (m_VTSlot == 0));
2474 m_VTSlot = NumSkipSlots;
2478 // We need an entry, allocate or expand the list as necessary.
2481 // Update the list with an entry describing the last non-gap in vtable
2483 m_MapList[m_MapEntries].m_Start = m_MTSlot;
2484 m_MapList[m_MapEntries].m_Span = StartMTSlot - m_MTSlot;
2485 m_MapList[m_MapEntries].m_MapTo = m_VTSlot;
2487 m_VTSlot += (StartMTSlot - m_MTSlot) + NumSkipSlots;
2488 m_MTSlot = StartMTSlot;
2493 //*******************************************************************************
2494 // Finish creation of mapping list.
2495 void SparseVTableMap::FinalizeMapping(WORD TotalMTSlots)
2497 STANDARD_VM_CONTRACT;
2499 _ASSERTE(TotalMTSlots >= m_MTSlot);
2501 // If mapping ended with a gap, we have nothing else to record.
2502 if (TotalMTSlots == m_MTSlot)
2505 // Allocate or expand the list as necessary.
2508 // Update the list with an entry describing the last non-gap in vtable
2510 m_MapList[m_MapEntries].m_Start = m_MTSlot;
2511 m_MapList[m_MapEntries].m_Span = TotalMTSlots - m_MTSlot;
2512 m_MapList[m_MapEntries].m_MapTo = m_VTSlot;
2514 // Update VT slot cursor, because we use it to determine total number of
2515 // vtable slots for GetNumVirtuals
2516 m_VTSlot += TotalMTSlots - m_MTSlot;
2521 //*******************************************************************************
2522 // Lookup a VTable slot number from a method table slot number.
2523 WORD SparseVTableMap::LookupVTSlot(WORD MTSlot)
2533 // As an optimization, check the last entry which yielded a correct result.
2534 if ((MTSlot >= m_MapList[m_LastUsed].m_Start) &&
2535 (MTSlot < (m_MapList[m_LastUsed].m_Start + m_MapList[m_LastUsed].m_Span)))
2536 return (MTSlot - m_MapList[m_LastUsed].m_Start) + m_MapList[m_LastUsed].m_MapTo;
2538 // Check all MT slots spans to see which one our input slot lies in.
2539 for (WORD i = 0; i < m_MapEntries; i++) {
2540 if ((MTSlot >= m_MapList[i].m_Start) &&
2541 (MTSlot < (m_MapList[i].m_Start + m_MapList[i].m_Span))) {
2543 return (MTSlot - m_MapList[i].m_Start) + m_MapList[i].m_MapTo;
2547 _ASSERTE(!"Invalid MethodTable slot");
2551 //*******************************************************************************
2552 // Retrieve the number of slots in the vtable (both empty and full).
2553 WORD SparseVTableMap::GetNumVTableSlots()
2555 LIMITED_METHOD_CONTRACT;
2560 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
2561 //*******************************************************************************
2562 void SparseVTableMap::Save(DataImage *image)
2564 STANDARD_VM_CONTRACT;
2566 image->StoreStructure(this, sizeof(SparseVTableMap),
2567 DataImage::ITEM_SPARSE_VTABLE_MAP_TABLE);
2569 // Trim unused portion of the table
2570 m_Allocated = m_MapEntries;
2572 image->StoreInternedStructure(m_MapList, m_Allocated * sizeof(Entry),
2573 DataImage::ITEM_SPARSE_VTABLE_MAP_ENTRIES);
2576 //*******************************************************************************
2577 void SparseVTableMap::Fixup(DataImage *image)
2579 STANDARD_VM_CONTRACT;
2581 image->FixupPointerField(this, offsetof(SparseVTableMap, m_MapList));
2583 #endif //FEATURE_NATIVE_IMAGE_GENERATION
2584 #endif //FEATURE_COMINTEROP
2586 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
2588 //*******************************************************************************
2589 void EEClass::Save(DataImage *image, MethodTable *pMT)
2594 PRECONDITION(this == pMT->GetClass());
2595 PRECONDITION(pMT->IsCanonicalMethodTable());
2596 PRECONDITION(pMT->IsFullyLoaded());
2597 PRECONDITION(!image->IsStored(this));
2598 PRECONDITION(image->GetModule()->GetAssembly() ==
2599 GetAppDomain()->ToCompilationDomain()->GetTargetAssembly());
2603 LOG((LF_ZAP, LL_INFO10000, "EEClass::Save %s (%p)\n", m_szDebugClassName, this));
2605 m_fFieldsArePacked = GetPackedFields()->PackFields();
2607 DWORD cbSize = GetSize();
2609 // ***************************************************************
2610 // Only put new actions in this function if they really relate to EEClass
2611 // rather than MethodTable. For example, if you need to allocate
2612 // a per-type entry in some table in the NGEN image, then you will probably
2613 // need to allocate one such entry per MethodTable, e.g. per generic
2614 // instantiation. You probably don't want to allocate one that is common
2615 // to a group of shared instantiations.
2616 // ***************************************************************
2618 DataImage::ItemKind item =
2619 (!pMT->IsGenericTypeDefinition() && pMT->ContainsGenericVariables())
2620 ? DataImage::ITEM_EECLASS_COLD
2621 // Until we get all the access paths for generics tidied up, many paths touch the EEClass, e.g. GetInstantiation()
2622 : pMT->HasInstantiation()
2623 ? DataImage::ITEM_EECLASS_WARM
2624 : DataImage::ITEM_EECLASS;
2626 // Save optional fields if we have any.
2627 if (HasOptionalFields())
2628 image->StoreStructure(GetOptionalFields(),
2629 sizeof(EEClassOptionalFields),
2633 if (!image->IsStored(m_szDebugClassName))
2634 image->StoreStructure(m_szDebugClassName, (ULONG)(strlen(m_szDebugClassName)+1),
2635 DataImage::ITEM_DEBUG,
2639 #ifdef FEATURE_COMINTEROP
2640 if (GetSparseCOMInteropVTableMap() != NULL)
2641 GetSparseCOMInteropVTableMap()->Save(image);
2642 #endif // FEATURE_COMINTEROP
2648 MethodDescChunk *chunk = GetChunks();
2651 MethodDesc::SaveChunk methodDescSaveChunk(image);
2653 MethodTable::IntroducedMethodIterator it(pMT, TRUE);
2654 for (; it.IsValid(); it.Next())
2656 MethodDesc * pMD = it.GetMethodDesc();
2658 // Do not save IL stubs that we have failed to generate code for
2659 if (pMD->IsILStub() && image->GetCodeAddress(pMD) == NULL)
2662 methodDescSaveChunk.Append(pMD);
2665 ZapStoredStructure * pChunksNode = methodDescSaveChunk.Save();
2666 if (pChunksNode != NULL)
2667 image->BindPointer(chunk, pChunksNode, 0);
2675 SIZE_T fieldCount = FieldDescListSize(pMT);
2677 if (fieldCount != 0)
2679 FieldDesc *pFDStart = GetFieldDescList();
2680 FieldDesc *pFDEnd = pFDStart + fieldCount;
2682 FieldDesc *pFD = pFDStart;
2683 while (pFD < pFDEnd)
2685 pFD->PrecomputeNameHash();
2689 ZapStoredStructure * pFDNode = image->StoreStructure(pFDStart, (ULONG)(fieldCount * sizeof(FieldDesc)),
2690 DataImage::ITEM_FIELD_DESC_LIST);
2693 while (pFD < pFDEnd)
2695 pFD->SaveContents(image);
2696 if (pFD != pFDStart)
2697 image->BindPointer(pFD, pFDNode, (BYTE *)pFD - (BYTE *)pFDStart);
2708 EEClassLayoutInfo *pInfo = &((LayoutEEClass*)this)->m_LayoutInfo;
2710 if (pInfo->m_numCTMFields > 0)
2712 ZapStoredStructure * pNode = image->StoreStructure(pInfo->GetFieldMarshalers(),
2713 pInfo->m_numCTMFields * MAXFIELDMARSHALERSIZE,
2714 DataImage::ITEM_FIELD_MARSHALERS);
2716 for (UINT iField = 0; iField < pInfo->m_numCTMFields; iField++)
2718 FieldMarshaler *pFM = (FieldMarshaler*)((BYTE *)pInfo->GetFieldMarshalers() + iField * MAXFIELDMARSHALERSIZE);
2722 image->BindPointer(pFM, pNode, iField * MAXFIELDMARSHALERSIZE);
2727 // Save dictionary layout information
2728 DictionaryLayout *pDictLayout = GetDictionaryLayout();
2729 if (pMT->IsSharedByGenericInstantiations() && pDictLayout != NULL)
2731 pDictLayout->Save(image);
2732 LOG((LF_ZAP, LL_INFO10000, "ZAP: dictionary for %s has %d slots used out of possible %d\n", m_szDebugClassName,
2733 pDictLayout->GetNumUsedSlots(), pDictLayout->GetMaxSlots()));
2736 if (GetVarianceInfo() != NULL)
2737 image->StoreInternedStructure(GetVarianceInfo(),
2738 pMT->GetNumGenericArgs(),
2739 DataImage::ITEM_CLASS_VARIANCE_INFO);
2741 image->StoreStructure(this, cbSize, item);
2743 if (pMT->IsInterface())
2745 // Make sure our guid is computed
2747 #ifdef FEATURE_COMINTEROP
2748 // Generic WinRT types can have their GUID computed only if the instantiation is WinRT-legal
2749 if (!pMT->IsProjectedFromWinRT() ||
2750 !pMT->SupportsGenericInterop(TypeHandle::Interop_NativeToManaged) ||
2751 pMT->IsLegalNonArrayWinRTType())
2752 #endif // FEATURE_COMINTEROP
2755 if (SUCCEEDED(pMT->GetGuidNoThrow(&dummy, TRUE, FALSE)))
2757 GuidInfo* pGuidInfo = pMT->GetGuidInfo();
2758 _ASSERTE(pGuidInfo != NULL);
2760 image->StoreStructure(pGuidInfo, sizeof(GuidInfo),
2761 DataImage::ITEM_GUID_INFO);
2763 #ifdef FEATURE_COMINTEROP
2764 if (pMT->IsLegalNonArrayWinRTType())
2766 Module *pModule = pMT->GetModule();
2767 if (pModule->CanCacheWinRTTypeByGuid(pMT))
2769 pModule->CacheWinRTTypeByGuid(pMT, pGuidInfo);
2772 #endif // FEATURE_COMINTEROP
2776 // make sure we don't store a GUID_NULL guid in the NGEN image
2777 // instead we'll compute the GUID at runtime, and throw, if appropriate
2778 m_pGuidInfo.SetValueMaybeNull(NULL);
2783 #ifdef FEATURE_COMINTEROP
2786 DelegateEEClass *pDelegateClass = (DelegateEEClass *)this;
2787 ComPlusCallInfo *pComInfo = pDelegateClass->m_pComPlusCallInfo;
2789 if (pComInfo != NULL && pComInfo->ShouldSave(image))
2791 image->StoreStructure(pDelegateClass->m_pComPlusCallInfo,
2792 sizeof(ComPlusCallInfo),
2796 #endif // FEATURE_COMINTEROP
2798 LOG((LF_ZAP, LL_INFO10000, "EEClass::Save %s (%p) complete.\n", m_szDebugClassName, this));
2801 //*******************************************************************************
2802 DWORD EEClass::FieldDescListSize(MethodTable * pMT)
2804 LIMITED_METHOD_CONTRACT;
2806 EEClass * pClass = pMT->GetClass();
2807 DWORD fieldCount = pClass->GetNumInstanceFields() + pClass->GetNumStaticFields();
2809 MethodTable * pParentMT = pMT->GetParentMethodTable();
2810 if (pParentMT != NULL)
2811 fieldCount -= pParentMT->GetNumInstanceFields();
2815 //*******************************************************************************
2816 void EEClass::Fixup(DataImage *image, MethodTable *pMT)
2821 PRECONDITION(this == pMT->GetClass());
2822 PRECONDITION(pMT->IsCanonicalMethodTable());
2823 PRECONDITION(pMT->IsFullyLoaded());
2824 PRECONDITION(image->IsStored(this));
2828 LOG((LF_ZAP, LL_INFO10000, "EEClass::Fixup %s (%p)\n", GetDebugClassName(), this));
2830 // Fixup pointer to optional fields if this class has any. This pointer is a relative pointer (to avoid
2831 // the need for base relocation fixups) and thus needs to use the IMAGE_REL_BASED_RELPTR fixup type.
2832 if (HasOptionalFields())
2833 image->FixupRelativePointerField(this, offsetof(EEClass, m_rpOptionalFields));
2836 image->FixupPointerField(this, offsetof(EEClass, m_szDebugClassName));
2839 #ifdef FEATURE_COMINTEROP
2840 if (GetSparseCOMInteropVTableMap() != NULL)
2842 image->FixupPointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pSparseVTableMap));
2843 GetSparseCOMInteropVTableMap()->Fixup(image);
2845 #endif // FEATURE_COMINTEROP
2847 DictionaryLayout *pDictLayout = GetDictionaryLayout();
2848 if (pDictLayout != NULL)
2850 pDictLayout->Fixup(image, FALSE);
2851 image->FixupPointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pDictLayout));
2854 if (HasOptionalFields())
2855 image->FixupRelativePointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pVarianceInfo));
2858 // We pass in the method table, because some classes (e.g. remoting proxy)
2859 // have fake method tables set up in them & we want to restore the regular
2862 image->FixupField(this, offsetof(EEClass, m_pMethodTable), pMT, 0, IMAGE_REL_BASED_RelativePointer);
2865 // Fixup MethodDescChunk and MethodDescs
2867 MethodDescChunk* pChunks = GetChunks();
2869 if (pChunks!= NULL && image->IsStored(pChunks))
2871 image->FixupRelativePointerField(this, offsetof(EEClass, m_pChunks));
2873 MethodTable::IntroducedMethodIterator it(pMT, TRUE);
2874 for (; it.IsValid(); it.Next())
2876 MethodDesc * pMD = it.GetMethodDesc();
2878 // Skip IL stubs that were not saved into the image
2879 if (pMD->IsILStub() && !image->IsStored(pMD))
2882 it.GetMethodDesc()->Fixup(image);
2888 image->ZeroPointerField(this, offsetof(EEClass, m_pChunks));
2895 SIZE_T fieldCount = FieldDescListSize(pMT);
2897 if (fieldCount != 0)
2899 image->FixupRelativePointerField(this, offsetof(EEClass, m_pFieldDescList));
2901 FieldDesc *pField = GetFieldDescList();
2902 FieldDesc *pFieldEnd = pField + fieldCount;
2903 while (pField < pFieldEnd)
2905 pField->Fixup(image);
2910 #ifdef FEATURE_COMINTEROP
2911 // These fields will be lazy inited if we zero them
2912 if (HasOptionalFields())
2913 image->ZeroPointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pCoClassForIntf));
2914 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2915 if (HasOptionalFields())
2916 image->ZeroPointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pClassFactory));
2918 image->ZeroPointerField(this, offsetof(EEClass, m_pccwTemplate));
2919 #endif // FEATURE_COMINTEROP
2923 image->FixupRelativePointerField(this, offsetof(LayoutEEClass, m_LayoutInfo.m_pFieldMarshalers));
2925 EEClassLayoutInfo *pInfo = &((LayoutEEClass*)this)->m_LayoutInfo;
2927 FieldMarshaler *pFM = pInfo->GetFieldMarshalers();
2928 FieldMarshaler *pFMEnd = (FieldMarshaler*) ((BYTE *)pFM + pInfo->m_numCTMFields*MAXFIELDMARSHALERSIZE);
2929 while (pFM < pFMEnd)
2932 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2935 else if (IsDelegate())
2937 image->FixupRelativePointerField(this, offsetof(DelegateEEClass, m_pInvokeMethod));
2938 image->FixupRelativePointerField(this, offsetof(DelegateEEClass, m_pBeginInvokeMethod));
2939 image->FixupRelativePointerField(this, offsetof(DelegateEEClass, m_pEndInvokeMethod));
2941 image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pUMThunkMarshInfo));
2942 image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pStaticCallStub));
2943 image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pMultiCastInvokeStub));
2944 image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pWrapperDelegateInvokeStub));
2945 image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pMarshalStub));
2947 #ifdef FEATURE_COMINTEROP
2948 DelegateEEClass *pDelegateClass = (DelegateEEClass *)this;
2949 ComPlusCallInfo *pComInfo = pDelegateClass->m_pComPlusCallInfo;
2951 if (image->IsStored(pComInfo))
2953 image->FixupPointerField(this, offsetof(DelegateEEClass, m_pComPlusCallInfo));
2954 pComInfo->Fixup(image);
2958 image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pComPlusCallInfo));
2960 #endif // FEATURE_COMINTEROP
2962 image->FixupPointerField(this, offsetof(DelegateEEClass, m_pForwardStubMD));
2963 image->FixupPointerField(this, offsetof(DelegateEEClass, m_pReverseStubMD));
2967 // This field must be initialized at
2971 if (IsInterface() && GetGuidInfo() != NULL)
2972 image->FixupRelativePointerField(this, offsetof(EEClass, m_pGuidInfo));
2974 image->ZeroPointerField(this, offsetof(EEClass, m_pGuidInfo));
2976 LOG((LF_ZAP, LL_INFO10000, "EEClass::Fixup %s (%p) complete.\n", GetDebugClassName(), this));
2978 #endif // FEATURE_NATIVE_IMAGE_GENERATION
2981 //*******************************************************************************
2982 void EEClass::AddChunk (MethodDescChunk* pNewChunk)
2984 STATIC_CONTRACT_NOTHROW;
2985 STATIC_CONTRACT_GC_NOTRIGGER;
2986 STATIC_CONTRACT_FORBID_FAULT;
2988 _ASSERTE(pNewChunk->GetNextChunk() == NULL);
2989 pNewChunk->SetNextChunk(GetChunks());
2990 SetChunks(pNewChunk);
2993 //*******************************************************************************
2994 void EEClass::AddChunkIfItHasNotBeenAdded (MethodDescChunk* pNewChunk)
2996 STATIC_CONTRACT_NOTHROW;
2997 STATIC_CONTRACT_GC_NOTRIGGER;
2998 STATIC_CONTRACT_FORBID_FAULT;
3000 // return if the chunk has been added
3001 if (pNewChunk->GetNextChunk() != NULL)
3004 // even if pNewChunk->GetNextChunk() is NULL, this may still be the first chunk we added
3005 // (last in the list) so find the end of the list and verify that
3006 MethodDescChunk *chunk = GetChunks();
3009 while (chunk->GetNextChunk() != NULL)
3010 chunk = chunk->GetNextChunk();
3012 if (chunk == pNewChunk)
3016 pNewChunk->SetNextChunk(GetChunks());
3017 SetChunks(pNewChunk);
3020 #endif // !DACCESS_COMPILE
3022 //*******************************************************************************
3023 // ApproxFieldDescIterator is used to iterate over fields in a given class.
3024 // It does not includes EnC fields, and not inherited fields.
3025 // <NICE> ApproxFieldDescIterator is only used to iterate over static fields in one place,
3026 // and this will probably change anyway. After
3027 // we clean this up we should make ApproxFieldDescIterator work
3028 // over instance fields only </NICE>
3029 ApproxFieldDescIterator::ApproxFieldDescIterator()
3040 m_pFieldDescList = NULL;
3045 //*******************************************************************************
3046 void ApproxFieldDescIterator::Init(MethodTable *pMT, int iteratorType)
3057 m_iteratorType = iteratorType;
3058 m_pFieldDescList = pMT->GetApproxFieldDescListRaw();
3061 // This gets non-EnC fields.
3062 m_totalFields = pMT->GetNumIntroducedInstanceFields();
3064 if (!(iteratorType & (int)INSTANCE_FIELDS))
3066 // if not handling instances then skip them by setting curr to last one
3067 m_currField = m_totalFields - 1;
3070 if (iteratorType & (int)STATIC_FIELDS)
3072 m_totalFields += pMT->GetNumStaticFields();
3076 //*******************************************************************************
3077 PTR_FieldDesc ApproxFieldDescIterator::Next()
3088 // This will iterate through all non-inherited and non-EnC fields.
3090 if (m_currField >= m_totalFields)
3095 return m_pFieldDescList + m_currField;
3098 //*******************************************************************************
3100 DeepFieldDescIterator::NextClass()
3102 WRAPPER_NO_CONTRACT;
3104 if (m_curClass <= 0)
3109 if (m_numClasses <= 0) {
3110 _ASSERTE(m_numClasses > 0);
3117 // If we're in the cache just grab the cache entry.
3119 // If we're deeper in the hierarchy than the
3120 // portion we cached we need to take the
3121 // deepest cache entry and search down manually.
3124 if (--m_curClass < m_numClasses)
3126 pMT = m_classes[m_curClass];
3130 pMT = m_classes[m_numClasses - 1];
3131 int depthDiff = m_curClass - m_numClasses + 1;
3134 pMT = pMT->GetParentMethodTable();
3138 m_fieldIter.Init(pMT, m_fieldIter.GetIteratorType());
3142 //*******************************************************************************
3144 DeepFieldDescIterator::Init(MethodTable* pMT, int iteratorType,
3145 bool includeParents)
3147 WRAPPER_NO_CONTRACT;
3149 MethodTable * lastClass = NULL;
3153 // Walk up the parent chain, collecting
3154 // parent pointers and counting fields.
3159 m_deepTotalFields = 0;
3160 m_lastNextFromParentClass = false;
3164 if (m_numClasses < (int)NumItems(m_classes))
3166 m_classes[m_numClasses++] = pMT;
3169 if ((iteratorType & ApproxFieldDescIterator::INSTANCE_FIELDS) != 0)
3171 m_deepTotalFields += pMT->GetNumIntroducedInstanceFields();
3173 if ((iteratorType & ApproxFieldDescIterator::STATIC_FIELDS) != 0)
3175 m_deepTotalFields += pMT->GetNumStaticFields();
3183 pMT = pMT->GetParentMethodTable();
3191 // Start the per-class field iterator on the base-most parent.
3194 m_curClass = numClasses - 1;
3195 m_fieldIter.Init(lastClass, iteratorType);
3203 //*******************************************************************************
3205 DeepFieldDescIterator::Next()
3207 WRAPPER_NO_CONTRACT;
3213 m_lastNextFromParentClass = m_curClass > 0;
3215 field = m_fieldIter.Next();
3217 if (!field && !NextClass())
3227 //*******************************************************************************
3229 DeepFieldDescIterator::Skip(int numSkip)
3231 WRAPPER_NO_CONTRACT;
3233 while (numSkip >= m_fieldIter.CountRemaining())
3235 numSkip -= m_fieldIter.CountRemaining();
3251 #ifdef DACCESS_COMPILE
3253 //*******************************************************************************
3255 EEClass::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, MethodTable * pMT)
3259 EMEM_OUT(("MEM: %p EEClass\n", dac_cast<TADDR>(this)));
3261 // The DAC_ENUM_DTHIS above won't have reported the packed fields tacked on the end of this instance (they
3262 // aren't part of the static class definition because the fields are variably sized and thus have to come
3263 // right at the end of the structure, even for sub-types such as LayoutEEClass or DelegateEEClass).
3264 DacEnumMemoryRegion(dac_cast<TADDR>(GetPackedFields()), sizeof(EEClassPackedFields));
3266 if (HasOptionalFields())
3267 DacEnumMemoryRegion(dac_cast<TADDR>(GetOptionalFields()), sizeof(EEClassOptionalFields));
3269 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
3271 PTR_Module pModule = pMT->GetModule();
3272 if (pModule.IsValid())
3274 pModule->EnumMemoryRegions(flags, true);
3276 PTR_MethodDescChunk chunk = GetChunks();
3277 while (chunk.IsValid())
3279 chunk->EnumMemoryRegions(flags);
3280 chunk = chunk->GetNextChunk();
3284 PTR_FieldDesc pFieldDescList = GetFieldDescList();
3285 if (pFieldDescList.IsValid())
3287 // add one to make sos's code happy.
3288 DacEnumMemoryRegion(dac_cast<TADDR>(pFieldDescList),
3289 (pMT->GetNumIntroducedInstanceFields() +
3290 GetNumStaticFields() + 1) *
3296 #endif // DACCESS_COMPILE
3298 // Get pointer to the packed fields structure attached to this instance.
3299 PTR_EEClassPackedFields EEClass::GetPackedFields()
3301 LIMITED_METHOD_DAC_CONTRACT;
3303 return dac_cast<PTR_EEClassPackedFields>(PTR_HOST_TO_TADDR(this) + m_cbFixedEEClassFields);
3306 // Get the value of the given field. Works regardless of whether the field is currently in its packed or
3308 DWORD EEClass::GetPackableField(EEClassFieldId eField)
3319 return m_fFieldsArePacked ?
3320 GetPackedFields()->GetPackedField(eField) :
3321 GetPackedFields()->GetUnpackedField(eField);
3324 // Set the value of the given field. The field *must* be in the unpacked state for this to be legal (in
3325 // practice all packable fields must be initialized during class construction and from then on remain
3327 void EEClass::SetPackableField(EEClassFieldId eField, DWORD dwValue)
3337 _ASSERTE(!m_fFieldsArePacked);
3338 GetPackedFields()->SetUnpackedField(eField, dwValue);
3341 #ifndef DACCESS_COMPILE
3343 void EEClassLayoutInfo::SetOffsetsAndSortFields(
3344 IMDInternalImport* pInternalImport,
3346 LayoutRawFieldInfo* pFieldInfoArray,
3347 const ULONG cInstanceFields,
3348 const BOOL fExplicitOffsets,
3349 const UINT32 cbAdjustedParentLayoutNativeSize,
3351 LayoutRawFieldInfo** pSortArrayOut
3355 MD_CLASS_LAYOUT classlayout;
3356 hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
3359 COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
3362 LayoutRawFieldInfo* pfwalk = pFieldInfoArray;
3365 while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
3369 fd != mdFieldDefNil)
3371 // watch for the last entry: must be mdFieldDefNil
3372 while ((mdFieldDefNil != pfwalk->m_MD) && (pfwalk->m_MD < fd))
3375 // if we haven't found a matching token, it must be a static field with layout -- ignore it
3376 if (pfwalk->m_MD != fd) continue;
3378 if (!fExplicitOffsets)
3380 // ulOffset is the sequence
3381 pfwalk->m_sequence = ulOffset;
3385 // ulOffset is the explicit offset
3386 pfwalk->m_nativePlacement.m_offset = ulOffset;
3387 pfwalk->m_sequence = (ULONG)-1;
3389 // Treat base class as an initial member.
3390 if (!SafeAddUINT32(&(pfwalk->m_nativePlacement.m_offset), cbAdjustedParentLayoutNativeSize))
3396 LayoutRawFieldInfo** pSortArrayEnd = pSortArrayOut;
3397 // now sort the array
3398 if (!fExplicitOffsets)
3400 // sort sequential by ascending sequence
3401 for (ULONG i = 0; i < cInstanceFields; i++)
3403 LayoutRawFieldInfo** pSortWalk = pSortArrayEnd;
3404 while (pSortWalk != pSortArrayOut)
3406 if (pFieldInfoArray[i].m_sequence >= (*(pSortWalk - 1))->m_sequence)
3412 // pSortWalk now points to the target location for new LayoutRawFieldInfo*.
3413 MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
3414 *pSortWalk = &pFieldInfoArray[i];
3418 else // no sorting for explicit layout
3420 for (ULONG i = 0; i < cInstanceFields; i++)
3422 if (pFieldInfoArray[i].m_MD != mdFieldDefNil)
3424 if (pFieldInfoArray[i].m_nativePlacement.m_offset == (UINT32)-1)
3426 LPCUTF8 szFieldName;
3427 if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName)))
3429 szFieldName = "Invalid FieldDef record";
3431 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
3434 IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
3436 else if ((INT)pFieldInfoArray[i].m_nativePlacement.m_offset < 0)
3438 LPCUTF8 szFieldName;
3439 if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName)))
3441 szFieldName = "Invalid FieldDef record";
3443 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
3446 IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
3450 *pSortArrayEnd = &pFieldInfoArray[i];
3456 void EEClassLayoutInfo::CalculateSizeAndFieldOffsets(
3457 const UINT32 parentSize,
3458 ULONG numInstanceFields,
3459 BOOL fExplicitOffsets,
3460 LayoutRawFieldInfo* const* pSortedFieldInfoArray,
3461 ULONG classSizeInMetadata,
3463 BYTE parentAlignmentRequirement,
3464 BOOL calculatingNativeLayout,
3465 EEClassLayoutInfo* pEEClassLayoutInfoOut
3468 UINT32 cbCurOffset = parentSize;
3469 BYTE LargestAlignmentRequirement = max(1, min(packingSize, parentAlignmentRequirement));
3471 // Start with the size inherited from the parent (if any).
3472 uint32_t calcTotalSize = parentSize;
3474 LayoutRawFieldInfo* const* pSortWalk;
3476 for (pSortWalk = pSortedFieldInfoArray, i = numInstanceFields; i; i--, pSortWalk++)
3478 LayoutRawFieldInfo* pfwalk = *pSortWalk;
3479 RawFieldPlacementInfo* placementInfo;
3481 if (calculatingNativeLayout)
3483 placementInfo = &pfwalk->m_nativePlacement;
3487 placementInfo = &pfwalk->m_managedPlacement;
3490 BYTE alignmentRequirement = placementInfo->m_alignment;
3492 alignmentRequirement = min(alignmentRequirement, packingSize);
3494 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
3496 switch (alignmentRequirement)
3506 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
3509 if (!fExplicitOffsets)
3511 // Insert enough padding to align the current data member.
3512 while (cbCurOffset % alignmentRequirement)
3514 if (!SafeAddUINT32(&cbCurOffset, 1))
3518 // if we overflow we will catch it below
3519 placementInfo->m_offset = cbCurOffset;
3520 cbCurOffset += placementInfo->m_size;
3523 uint32_t fieldEnd = placementInfo->m_offset + placementInfo->m_size;
3524 if (fieldEnd < placementInfo->m_offset)
3527 // size of the structure is the size of the last field.
3528 if (fieldEnd > calcTotalSize)
3529 calcTotalSize = fieldEnd;
3532 if (classSizeInMetadata != 0)
3534 ULONG classSize = classSizeInMetadata;
3535 if (!SafeAddULONG(&classSize, (ULONG)parentSize))
3538 // size must be large enough to accomodate layout. If not, we use the layout size instead.
3539 calcTotalSize = max(classSize, calcTotalSize);
3543 // There was no class size given in metadata, so let's round up to a multiple of the alignment requirement
3544 // to make array allocations of this structure simple to keep aligned.
3545 calcTotalSize += (LargestAlignmentRequirement - calcTotalSize % LargestAlignmentRequirement) % LargestAlignmentRequirement;
3547 if (calcTotalSize % LargestAlignmentRequirement != 0)
3549 if (!SafeAddUINT32(&calcTotalSize, LargestAlignmentRequirement - (calcTotalSize % LargestAlignmentRequirement)))
3554 // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
3555 // that we don't expose some overflow bug later on.
3556 if (calcTotalSize >= MAX_SIZE_FOR_INTEROP && calculatingNativeLayout)
3559 // This is a zero-sized struct - need to record the fact and bump it up to 1.
3560 if (calcTotalSize == 0)
3562 pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
3566 // The packingSize acts as a ceiling on all individual alignment
3567 // requirements so it follows that the largest alignment requirement
3569 _ASSERTE(LargestAlignmentRequirement <= packingSize);
3571 if (calculatingNativeLayout)
3573 pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
3574 pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
3578 pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
3579 pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
3583 //=======================================================================
3584 // Called from the clsloader to load up and summarize the field metadata
3585 // for layout classes.
3587 // Warning: This function can load other classes (esp. for nested structs.)
3588 //=======================================================================
3590 #pragma warning(push)
3591 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3593 VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
3594 mdTypeDef cl, // cl of the NStruct being loaded
3595 BYTE packingSize, // packing size (from @dll.struct)
3596 BYTE nlType, // nltype (from @dll.struct)
3597 #ifdef FEATURE_COMINTEROP
3598 BOOL isWinRT, // Is the type a WinRT type
3599 #endif // FEATURE_COMINTEROP
3600 BOOL fExplicitOffsets, // explicit offsets?
3601 MethodTable *pParentMT, // the loaded superclass
3602 ULONG cTotalFields, // total number of fields (instance and static)
3603 HENUMInternal *phEnumField, // enumerator for field
3604 Module *pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
3605 const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded
3606 EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
3607 LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements
3608 LoaderAllocator *pAllocator,
3609 AllocMemTracker *pamTracker
3617 INJECT_FAULT(COMPlusThrowOM());
3618 PRECONDITION(CheckPointer(pModule));
3622 // Internal interface for the NStruct being loaded.
3623 IMDInternalImport *pInternalImport = pModule->GetMDImport();
3627 LPCUTF8 szNamespace;
3628 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
3630 szName = szNamespace = "Invalid TypeDef record";
3633 if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
3634 CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
3637 // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
3639 BOOL fDisqualifyFromManagedSequential;
3641 // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be
3642 // ManagedSequential. Other issues checked below might also disqualify the type.
3643 if ( (!fExplicitOffsets) && // Is it marked sequential?
3644 (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype?
3647 fDisqualifyFromManagedSequential = FALSE;
3651 fDisqualifyFromManagedSequential = TRUE;
3655 BOOL fHasNonTrivialParent = pParentMT &&
3656 !pParentMT->IsObjectClass() &&
3657 !pParentMT->IsValueTypeClass();
3660 // Set some defaults based on the parent type of this type (if one exists).
3661 _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
3663 pEEClassLayoutInfoOut->m_numCTMFields = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0;
3664 pEEClassLayoutInfoOut->SetFieldMarshalers(NULL);
3665 pEEClassLayoutInfoOut->SetIsBlittable(TRUE);
3666 if (fHasNonTrivialParent)
3667 pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable());
3668 pEEClassLayoutInfoOut->SetIsZeroSized(FALSE);
3669 pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE);
3670 pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;
3672 BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
3673 UINT32 cbAdjustedParentLayoutNativeSize = 0;
3674 EEClassLayoutInfo *pParentLayoutInfo = NULL;
3675 if (fParentHasLayout)
3677 pParentLayoutInfo = pParentMT->GetLayoutInfo();
3678 // Treat base class as an initial member.
3679 cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize();
3680 // If the parent was originally a zero-sized explicit type but
3681 // got bumped up to a size of 1 for compatibility reasons, then
3682 // we need to remove the padding, but ONLY for inheritance situations.
3683 if (pParentLayoutInfo->IsZeroSized()) {
3684 CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1);
3685 cbAdjustedParentLayoutNativeSize = 0;
3689 ULONG cInstanceFields = 0;
3691 ParseNativeTypeFlags nativeTypeFlags = ParseNativeTypeFlags::None;
3692 #ifdef FEATURE_COMINTEROP
3694 nativeTypeFlags = ParseNativeTypeFlags::IsWinRT;
3695 else // WinRT types have nlType == nltAnsi but should be treated as Unicode
3696 #endif // FEATURE_COMINTEROP
3697 if (nlType == nltAnsi)
3698 nativeTypeFlags = ParseNativeTypeFlags::IsAnsi;
3700 ParseFieldNativeTypes(
3708 &fDisqualifyFromManagedSequential,
3710 pEEClassLayoutInfoOut,
3712 DEBUGARG(szNamespace)
3716 // Now compute the native size of each field
3717 for (LayoutRawFieldInfo* pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
3719 pfwalk->m_nativePlacement.m_size = ((FieldMarshaler*) & (pfwalk->m_FieldMarshaler))->NativeSize();
3720 pfwalk->m_nativePlacement.m_alignment = ((FieldMarshaler*) & (pfwalk->m_FieldMarshaler))->AlignmentRequirement();
3723 // @perf: If the type is blittable, the managed and native layouts have to be identical
3724 // so they really shouldn't be calculated twice. Until this code has been well tested and
3725 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
3726 // case. The managed size is only calculated in the managed-sequential case.
3727 if (!fDisqualifyFromManagedSequential && pEEClassLayoutInfoOut->IsBlittable())
3729 _ASSERTE(pfwalk->m_managedPlacement.m_size == pfwalk->m_nativePlacement.m_size);
3734 S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo*));
3735 if (cbSortArraySize.IsOverflow())
3737 ThrowHR(COR_E_TYPELOAD);
3739 LayoutRawFieldInfo** pSortArray = (LayoutRawFieldInfo * *)_alloca(cbSortArraySize.Value());
3740 SetOffsetsAndSortFields(pInternalImport, cl, pInfoArrayOut, cInstanceFields, fExplicitOffsets, cbAdjustedParentLayoutNativeSize, pModule, pSortArray);
3743 if (pEEClassLayoutInfoOut->m_numCTMFields)
3745 pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
3747 // Bring in the parent's fieldmarshalers
3748 if (fHasNonTrivialParent)
3750 CONSISTENCY_CHECK(fParentHasLayout);
3751 PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above
3753 UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
3755 BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
3756 BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
3758 for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
3760 FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
3761 FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
3763 pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
3769 ULONG classSizeInMetadata = 0;
3770 if (FAILED(pInternalImport->GetClassTotalSize(cl, &classSizeInMetadata)))
3772 classSizeInMetadata = 0;
3776 // If we can get the class size from metadata, that means that the user
3777 // explicitly provided a value to the StructLayoutAttribute.Size field
3778 // or explicitly provided the size in IL.
3779 pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE);
3782 BYTE parentAlignmentRequirement = 0;
3783 if (fParentHasLayout)
3785 parentAlignmentRequirement = pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers();
3788 CalculateSizeAndFieldOffsets(
3789 cbAdjustedParentLayoutNativeSize,
3793 classSizeInMetadata,
3795 parentAlignmentRequirement,
3796 /*calculatingNativeLayout*/ TRUE, pEEClassLayoutInfoOut);
3798 // Calculate the managedsequential layout if the type is eligible.
3799 if (!fDisqualifyFromManagedSequential)
3801 BYTE parentManagedAlignmentRequirement = 0;
3802 UINT32 parentSize = 0;
3803 if (pParentMT && pParentMT->IsManagedSequential())
3805 parentManagedAlignmentRequirement = pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
3806 parentSize = pParentMT->GetNumInstanceFieldBytes();
3809 CalculateSizeAndFieldOffsets(
3812 /* fExplicitOffsets */ FALSE,
3814 classSizeInMetadata,
3816 parentManagedAlignmentRequirement,
3817 /*calculatingNativeLayout*/ FALSE,
3818 pEEClassLayoutInfoOut);
3821 // @perf: If the type is blittable, the managed and native layouts have to be identical
3822 // so they really shouldn't be calculated twice. Until this code has been well tested and
3823 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
3825 if (pEEClassLayoutInfoOut->IsBlittable())
3827 _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
3828 _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
3833 pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
3837 BOOL illegalMarshaler = FALSE;
3839 LOG((LF_INTEROP, LL_INFO100000, "\n\n"));
3840 LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName));
3841 LOG((LF_INTEROP, LL_INFO100000, "Packsize = %lu\n", (ULONG)packingSize));
3842 LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers)));
3843 LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n"));
3844 for (LayoutRawFieldInfo* pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
3847 if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
3851 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu ", (ULONG)(pfwalk->m_nativePlacement.m_offset)));
3852 LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname));
3853 LOG((LF_INTEROP, LL_INFO100000, "\n"));
3855 if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
3856 illegalMarshaler = TRUE;
3859 // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
3860 if (fHasNonTrivialParent)
3862 FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
3863 for (UINT i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
3865 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
3866 illegalMarshaler = TRUE;
3867 ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
3871 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize)));
3872 LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable"), szNamespace, szName));
3878 #pragma warning(pop)
3881 //=====================================================================
3882 // ParseNativeFieldTypes:
3883 // Figure out the native field type of each field based on both the CLR
3884 // signature of the field and the FieldMarshaler metadata.
3885 //=====================================================================
3886 void EEClassLayoutInfo::ParseFieldNativeTypes(
3887 IMDInternalImport* pInternalImport,
3889 HENUMInternal* phEnumField,
3890 const ULONG cTotalFields,
3892 ParseNativeTypeFlags nativeTypeFlags,
3893 const SigTypeContext* pTypeContext,
3894 BOOL* fDisqualifyFromManagedSequential,
3895 LayoutRawFieldInfo* pFieldInfoArrayOut,
3896 EEClassLayoutInfo* pEEClassLayoutInfoOut,
3897 ULONG* cInstanceFields
3900 LPCUTF8 szNamespace,
3907 ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
3910 for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
3913 ULONG rid = RidFromToken(fd);
3915 if ((rid == 0) || (rid > maxRid))
3917 COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
3920 IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
3922 PCCOR_SIGNATURE pNativeType = NULL;
3924 // We ignore marshaling data attached to statics and literals,
3925 // since these do not contribute to instance data.
3926 if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
3928 PCCOR_SIGNATURE pCOMSignature;
3929 ULONG cbCOMSignature;
3931 if (IsFdHasFieldMarshal(dwFieldAttrs))
3933 hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
3944 IfFailThrow(pInternalImport->GetSigOfFieldDef(fd, &cbCOMSignature, &pCOMSignature));
3946 IfFailThrow(::validateTokenSig(fd, pCOMSignature, cbCOMSignature, dwFieldAttrs, pInternalImport));
3948 // fill the appropriate entry in pInfoArrayOut
3949 pFieldInfoArrayOut->m_MD = fd;
3950 pFieldInfoArrayOut->m_nativePlacement.m_offset = (UINT32)-1;
3951 pFieldInfoArrayOut->m_sequence = 0;
3954 LPCUTF8 szFieldName;
3955 if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
3957 szFieldName = "Invalid FieldDef record";
3961 ParseNativeType(pModule,
3970 fDisqualifyFromManagedSequential
3979 if (!IsFieldBlittable((FieldMarshaler*)(&pFieldInfoArrayOut->m_FieldMarshaler)))
3980 pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
3982 (*cInstanceFields)++;
3983 pFieldInfoArrayOut++;
3987 _ASSERTE(i == cTotalFields);
3989 // Set the number of fields here.
3990 pEEClassLayoutInfoOut->m_numCTMFields += *cInstanceFields;
3991 // NULL out the last entry
3992 pFieldInfoArrayOut->m_MD = mdFieldDefNil;
3995 #endif // DACCESS_COMPILE