Implement instantiating and unboxing through portable stublinker codeā€¦ (#106)
[platform/upstream/coreclr.git] / src / vm / class.cpp
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.
4 //
5 // File: CLASS.CPP
6 //
7
8 #include "common.h"
9
10 #include "dllimport.h"
11 #include "dllimportcallback.h"
12 #include "fieldmarshaler.h"
13 #include "customattribute.h"
14 #include "encee.h"
15 #include "typestring.h"
16 #include "dbginterface.h"
17
18 #ifdef FEATURE_COMINTEROP 
19 #include "comcallablewrapper.h"
20 #include "clrtocomcall.h"
21 #include "runtimecallablewrapper.h"
22 #endif // FEATURE_COMINTEROP
23
24 //#define DEBUG_LAYOUT
25 #define SORT_BY_RID
26
27 #ifndef DACCESS_COMPILE 
28 #include "methodtablebuilder.h"
29 #endif
30 #include "nsenumhandleallcases.h"
31
32 #ifndef DACCESS_COMPILE 
33
34
35 //*******************************************************************************
36 EEClass::EEClass(DWORD cbFixedEEClassFields)
37 {
38     LIMITED_METHOD_CONTRACT;
39
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
43     // bytes long.
44     _ASSERTE(cbFixedEEClassFields <= 0xff);
45     m_cbFixedEEClassFields = (BYTE)cbFixedEEClassFields;
46
47     // All other members are initialized to zero
48 }
49
50 //*******************************************************************************
51 void *EEClass::operator new(
52     size_t size,
53     LoaderHeap *pHeap,
54     AllocMemTracker *pamTracker)
55 {
56     CONTRACTL
57     {
58         THROWS;
59         GC_NOTRIGGER;
60         INJECT_FAULT(COMPlusThrowOM());
61     }
62     CONTRACTL_END;
63
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));
68
69     void *p = pamTracker->Track(pHeap->AllocMem(safeSize));
70
71     // No need to memset since this memory came from VirtualAlloc'ed memory
72     // memset (p, 0, size);
73
74     return p;
75 }
76
77 //*******************************************************************************
78 void EEClass::Destruct(MethodTable * pOwningMT)
79 {
80     CONTRACTL
81     {
82         NOTHROW;
83         GC_TRIGGERS;
84         FORBID_FAULT;
85         PRECONDITION(pOwningMT != NULL);
86     }
87     CONTRACTL_END
88
89 #ifndef CROSSGEN_COMPILE
90
91     // Not expected to be called for array EEClass
92     _ASSERTE(!pOwningMT->IsArray());
93
94 #ifdef _DEBUG
95     _ASSERTE(!IsDestroyed());
96     SetDestroyed();
97 #endif
98
99 #ifdef PROFILING_SUPPORTED
100     // If profiling, then notify the class is getting unloaded.
101     {
102         BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
103         {
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.
107             //
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
112             // profiling API.
113             //
114             // (Bug #26467)
115             //
116
117             FAULT_NOT_FATAL();
118
119             EX_TRY
120             {
121                 GCX_PREEMP();
122
123                 g_profControlBlock.pProfInterface->ClassUnloadStarted((ClassID) pOwningMT);
124             }
125             EX_CATCH
126             {
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
129                 // down the runtime.
130             }
131             EX_END_CATCH(RethrowTerminalExceptions);
132         }
133         END_PIN_PROFILER();
134     }
135 #endif // PROFILING_SUPPORTED
136
137 #ifdef FEATURE_COMINTEROP 
138     // clean up any COM Data
139     if (m_pccwTemplate)
140     {
141         m_pccwTemplate->Release();
142         m_pccwTemplate = NULL;
143     }
144
145
146 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION 
147     if (GetComClassFactory())
148     {
149         GetComClassFactory()->Cleanup();
150     }
151 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
152 #endif // FEATURE_COMINTEROP
153
154
155     if (IsDelegate())
156     {
157         DelegateEEClass* pDelegateEEClass = (DelegateEEClass*)this;
158
159         if (pDelegateEEClass->m_pStaticCallStub)
160         {
161             BOOL fStubDeleted = pDelegateEEClass->m_pStaticCallStub->DecRef();
162             if (fStubDeleted)
163             {
164                 DelegateInvokeStubManager::g_pManager->RemoveStub(pDelegateEEClass->m_pStaticCallStub);
165             }
166         }
167         if (pDelegateEEClass->m_pInstRetBuffCallStub)
168         {
169             pDelegateEEClass->m_pInstRetBuffCallStub->DecRef();
170         }
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;
176     }
177
178 #ifdef FEATURE_COMINTEROP 
179     if (GetSparseCOMInteropVTableMap() != NULL && !pOwningMT->IsZapped())
180         delete GetSparseCOMInteropVTableMap();
181 #endif // FEATURE_COMINTEROP
182
183 #ifdef PROFILING_SUPPORTED
184     // If profiling, then notify the class is getting unloaded.
185     {
186         BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
187         {
188             // See comments in the call to ClassUnloadStarted for details on this
189             // FAULT_NOT_FATAL marker and exception swallowing.
190             FAULT_NOT_FATAL();
191             EX_TRY
192             {
193                 GCX_PREEMP();
194                 g_profControlBlock.pProfInterface->ClassUnloadFinished((ClassID) pOwningMT, S_OK);
195             }
196             EX_CATCH
197             {
198             }
199             EX_END_CATCH(RethrowTerminalExceptions);
200         }
201         END_PIN_PROFILER();
202     }
203 #endif // PROFILING_SUPPORTED
204
205 #endif // CROSSGEN_COMPILE
206 }
207
208 //*******************************************************************************
209 /*static*/ EEClass * 
210 EEClass::CreateMinimalClass(LoaderHeap *pHeap, AllocMemTracker *pamTracker)
211 {
212     CONTRACTL
213     {
214         THROWS;
215         GC_NOTRIGGER;
216     }
217     CONTRACTL_END;
218
219     return new (pHeap, pamTracker) EEClass(sizeof(EEClass));
220 }
221
222
223 //*******************************************************************************
224
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)
230 {
231     CONTRACTL
232     {
233         THROWS;
234         GC_TRIGGERS;
235         INJECT_FAULT(COMPlusThrowOM(););
236         MODE_ANY;
237     }
238     CONTRACTL_END
239
240     mdTypeDef tdEnclosing = GetEnclosingCl();
241     
242     if (tdEnclosing == mdTypeDefNil)
243     {
244         return NULL;
245     }
246
247     return ClassLoader::LoadTypeDefThrowing(GetModule(),
248                                             tdEnclosing,
249                                             ClassLoader::ThrowIfNotFound,
250                                             ClassLoader::PermitUninstDefOrRef,
251                                             tdNoTypes,
252                                             targetLevel
253                                             ).GetMethodTable();
254
255 }
256
257 #ifdef EnC_SUPPORTED 
258
259 //*******************************************************************************
260 VOID EEClass::FixupFieldDescForEnC(MethodTable * pMT, EnCFieldDesc *pFD, mdFieldDef fieldDef)
261 {
262     CONTRACTL
263     {
264         THROWS;
265         MODE_COOPERATIVE;
266         WRAPPER(GC_TRIGGERS);
267         INJECT_FAULT(COMPlusThrowOM(););
268     }
269     CONTRACTL_END
270
271     Module * pModule = pMT->GetModule();
272     IMDInternalImport *pImport = pModule->GetMDImport();
273
274 #ifdef LOGGING
275     if (LoggingEnabled())
276     {
277         LPCSTR szFieldName;
278         if (FAILED(pImport->GetNameOfFieldDef(fieldDef, &szFieldName)))
279         {
280             szFieldName = "Invalid FieldDef record";
281         }
282         LOG((LF_ENC, LL_INFO100, "EEClass::InitializeFieldDescForEnC %s\n", szFieldName));
283     }
284 #endif //LOGGING
285     
286     
287 #ifdef _DEBUG 
288     BOOL shouldBreak = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EncFixupFieldBreak);
289     if (shouldBreak > 0) {
290         _ASSERTE(!"EncFixupFieldBreak");
291     }
292 #endif // _DEBUG
293
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);
298
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]));
305     
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*));
310
311     MethodTableBuilder::bmtFieldPlacement bmtFP;
312
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;
320
321     MethodTableBuilder::bmtInternalInfo bmtInternal;
322     bmtInternal.pModule = pModule;
323     bmtInternal.pInternalImport = pImport;
324     bmtInternal.pParentMT = pMT->GetParentMethodTable();
325
326     MethodTableBuilder::bmtProperties bmtProp;
327     bmtProp.fIsValueClass = !!pMT->IsValueType();
328
329     MethodTableBuilder::bmtEnumFieldInfo bmtEnumFields(bmtInternal.pInternalImport);
330
331     if (pFD->IsStatic())
332     {
333         bmtEnumFields.dwNumStaticFields = 1;
334     }
335     else
336     {
337         bmtEnumFields.dwNumInstanceFields = 1;
338     }
339     
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));
343
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;
348
349     EEClass * pClass = pMT->GetClass();
350
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;
356
357     AllocMemTracker dummyAmTracker;
358
359     BaseDomain * pDomain = pMT->GetDomain();
360     MethodTableBuilder builder(pMT, pClass,
361                                pStackingAllocator,
362                                &dummyAmTracker);
363
364     MethodTableBuilder::bmtGenericsInfo genericsInfo;
365
366     OBJECTREF pThrowable = NULL;
367     GCPROTECT_BEGIN(pThrowable);
368
369     builder.SetBMTData(pMT->GetLoaderAllocator(),
370                        &bmtError,
371                        &bmtProp,
372                        NULL,
373                        NULL,
374                        NULL,
375                        &bmtMetaData,
376                        NULL,
377                        &bmtMFDescs,
378                        &bmtFP,
379                        &bmtInternal,
380                        NULL,
381                        NULL,
382                        &genericsInfo,
383                        &bmtEnumFields);
384
385     EX_TRY
386     {
387         GCX_PREEMP();
388         builder.InitializeFieldDescs(pFD,
389                                  pLayoutRawFieldInfos,
390                                  &bmtInternal,
391                                  &genericsInfo,
392                                  &bmtMetaData,
393                                  &bmtEnumFields,
394                                  &bmtError,
395                                  &pByValueClassCache,
396                                  &bmtMFDescs,
397                                  &bmtFP,
398                                  &totalDeclaredFieldSize);
399     }
400     EX_CATCH_THROWABLE(&pThrowable);
401
402     dummyAmTracker.SuppressRelease();
403
404     // Restore now
405     pClass->SetNumInstanceFields(wNumInstanceFields);
406     pClass->SetNumStaticFields(wNumStaticFields);
407
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
410     // necessary.
411     if (pMT->IsValueType())
412     {
413         pClass->SetIsNotTightlyPacked();
414     }
415
416     if (pThrowable != NULL)
417     {
418         COMPlusThrow(pThrowable);
419     }
420
421     GCPROTECT_END();
422
423     pFD->SetMethodTable(pMT);
424
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.
427     pFD->SetEnCNew();
428
429     return;
430 }
431
432 //---------------------------------------------------------------------------------------
433 //
434 // AddField - called when a new field is added by EnC
435 //
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.
439 //
440 // Here we just create the FieldDesc and link it to the class.  The actual storage will
441 // be created lazily on demand.
442 //
443 HRESULT EEClass::AddField(MethodTable * pMT, mdFieldDef fieldDef, EnCFieldDesc **ppNewFD)
444 {
445     CONTRACTL
446     {
447         THROWS;
448         GC_NOTRIGGER;
449         MODE_COOPERATIVE;
450     }
451     CONTRACTL_END;
452
453     Module * pModule = pMT->GetModule();
454     IMDInternalImport *pImport = pModule->GetMDImport();
455
456 #ifdef LOGGING
457     if (LoggingEnabled())
458     {
459         LPCSTR szFieldName;
460         if (FAILED(pImport->GetNameOfFieldDef(fieldDef, &szFieldName)))
461         {
462             szFieldName = "Invalid FieldDef record";
463         }
464         LOG((LF_ENC, LL_INFO100, "EEClass::AddField %s\n", szFieldName));
465     }
466 #endif //LOGGING
467
468     // We can only add fields to normal classes
469     if (pMT->HasLayout() || pMT->IsValueType())
470     {
471         return CORDBG_E_ENC_CANT_ADD_FIELD_TO_VALUE_OR_LAYOUT_CLASS;
472     }
473
474     // We only add private fields.
475     // This may not be strictly necessary, but helps avoid any semantic confusion with
476     // existing code etc.
477     DWORD dwFieldAttrs;
478     IfFailThrow(pImport->GetFieldDefProps(fieldDef, &dwFieldAttrs));
479
480     LoaderAllocator* pAllocator = pMT->GetLoaderAllocator();
481         
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)));
486     if (!pAddedField)
487     {
488         return E_OUTOFMEMORY;
489     }
490     pAddedField->Init( fieldDef, IsFdStatic(dwFieldAttrs) );
491
492     EnCFieldDesc *pNewFD = &pAddedField->m_fieldDesc;
493
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);
498     if (! pEnCClass)
499         return E_FAIL;
500
501     // Add the field element to the list of added fields for this class
502     pEnCClass->AddField(pAddedField);
503
504     // Store the FieldDesc into the module's field list
505     {
506         CONTRACT_VIOLATION(ThrowsViolation); // B#25680 (Fix Enc violations): Must handle OOM's from Ensure
507         pModule->EnsureFieldDefCanBeStored(fieldDef);
508     }
509     pModule->EnsuredStoreFieldDef(fieldDef, pNewFD);
510     pNewFD->SetMethodTable(pMT);
511
512     // Success, return the new FieldDesc
513     if (ppNewFD)
514     {
515         *ppNewFD = pNewFD;
516     }
517     return S_OK;
518 }
519
520 //---------------------------------------------------------------------------------------
521 //
522 // AddMethod - called when a new method is added by EnC
523 //
524 // The method has already been added to the metadata with token methodDef.
525 // Create a new MethodDesc for the method.
526 //
527 HRESULT EEClass::AddMethod(MethodTable * pMT, mdMethodDef methodDef, RVA newRVA, MethodDesc **ppMethod)
528 {
529     CONTRACTL
530     {
531         THROWS;
532         GC_NOTRIGGER;
533         MODE_COOPERATIVE;
534     }
535     CONTRACTL_END;
536
537     Module * pModule = pMT->GetModule();
538     IMDInternalImport *pImport = pModule->GetMDImport();
539
540 #ifdef LOGGING
541     if (LoggingEnabled())
542     {
543         LPCSTR szMethodName;
544         if (FAILED(pImport->GetNameOfMethodDef(methodDef, &szMethodName)))
545         {
546             szMethodName = "Invalid MethodDef record";
547         }
548         LOG((LF_ENC, LL_INFO100, "EEClass::AddMethod %s\n", szMethodName));
549     }
550 #endif //LOGGING
551     
552     DWORD dwDescrOffset;
553     DWORD dwImplFlags;
554     HRESULT hr = S_OK;
555
556     if (FAILED(pImport->GetMethodImplProps(methodDef, &dwDescrOffset, &dwImplFlags)))
557     {
558         return COR_E_BADIMAGEFORMAT;
559     }
560     
561     DWORD dwMemberAttrs;
562     IfFailThrow(pImport->GetMethodDefProps(methodDef, &dwMemberAttrs));
563
564     // Refuse to add other special cases
565     if (IsReallyMdPinvokeImpl(dwMemberAttrs)  ||
566          (pMT->IsInterface() && !IsMdStatic(dwMemberAttrs)) ||
567          IsMiRuntime(dwImplFlags))
568     {
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;
572     }
573
574 #ifdef _DEBUG 
575     // Validate that this methodDef correctly has a parent typeDef
576     mdTypeDef   parentTypeDef;
577     if (FAILED(hr = pImport->GetParentToken(methodDef, &parentTypeDef)))
578     {
579         _ASSERTE(! "**Error** EEClass::AddMethod parent token not found");
580         LOG((LF_ENC, LL_INFO100, "**Error** EEClass::AddMethod parent token not found\n"));
581         return E_FAIL;
582     }
583 #endif // _DEBUG
584
585     EEClass * pClass = pMT->GetClass();
586
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;
590
591     LoaderAllocator* pAllocator = pMT->GetLoaderAllocator();
592
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
597                                                            mcInstantiated,
598                                                            TRUE /* fNonVtableSlot */,
599                                                            TRUE /* fNativeCodeSlot */,
600                                                            FALSE /* fComPlusCallInfo */,
601                                                            pMT,
602                                                            &dummyAmTracker);
603
604     // Get the new MethodDesc (Note: The method desc memory is zero initialized)
605     MethodDesc *pNewMD = pChunk->GetFirstMethodDesc();
606
607
608     // Initialize the new MethodDesc
609     
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;
613
614     MethodTableBuilder builder(pMT,
615                                pClass,
616                                &stackingAllocator,
617                                &dummyAmTracker);
618     EX_TRY
619     {
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
624                                methodDef,
625                                dwImplFlags,
626                                dwMemberAttrs,
627                                TRUE,            // fEnC
628                                newRVA,
629                                pImport,
630                                NULL
631                                COMMA_INDEBUG(debug_szFieldName)
632                                COMMA_INDEBUG(pMT->GetDebugClassName())
633                                COMMA_INDEBUG(NULL)
634                               );
635         
636         pNewMD->SetTemporaryEntryPoint(pAllocator, &dummyAmTracker);
637     }
638     EX_CATCH_HRESULT(hr);
639     if (S_OK != hr)
640         return hr;
641
642     dummyAmTracker.SuppressRelease();
643
644     _ASSERTE(pNewMD->IsEnCAddedMethod());
645
646     pNewMD->SetSlot(MethodTable::NO_SLOT);    // we can't ever use the slot for EnC methods
647
648     pClass->AddChunk(pChunk);
649
650     // Store the new MethodDesc into the collection for this class
651     pModule->EnsureMethodDefCanBeStored(methodDef);
652     pModule->EnsuredStoreMethodDef(methodDef, pNewMD);
653
654     LOG((LF_ENC, LL_INFO100, "EEClass::AddMethod new methoddesc %p for token %p\n", pNewMD, methodDef));
655
656     // Success - return the new MethodDesc
657     _ASSERTE( SUCCEEDED(hr) );
658     if (ppMethod)
659     {
660         *ppMethod = pNewMD;
661     }
662     return S_OK;
663 }
664
665 #endif // EnC_SUPPORTED
666
667 //---------------------------------------------------------------------------------------
668 //
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
672 // 
673 BOOL 
674 EEClass::CheckVarianceInSig(
675     DWORD               numGenericArgs, 
676     BYTE *              pVarianceInfo, 
677     Module *            pModule, 
678     SigPointer          psig, 
679     CorGenericParamAttr position)
680 {
681     CONTRACTL
682     {
683         THROWS;
684         GC_TRIGGERS;
685         MODE_ANY;
686     }
687     CONTRACTL_END;
688
689     if (pVarianceInfo == NULL)
690         return TRUE;
691
692     CorElementType typ;
693     IfFailThrow(psig.GetElemType(&typ));
694
695     switch (typ)
696     {
697         case ELEMENT_TYPE_STRING:
698         case ELEMENT_TYPE_U:
699         case ELEMENT_TYPE_I:
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:
718             return TRUE;
719
720         case ELEMENT_TYPE_VAR:
721         {
722             DWORD index;
723             IfFailThrow(psig.GetData(&index));
724
725             // This will be checked later anyway; so give up and don't indicate a variance failure
726             if (index < 0 || index >= numGenericArgs)
727                 return TRUE;
728
729             // Non-variant parameters are allowed to appear anywhere
730             if (pVarianceInfo[index] == gpNonVariant)
731                 return TRUE;
732
733             // Covariant and contravariant parameters can *only* appear in resp. covariant and contravariant positions
734             return ((CorGenericParamAttr) (pVarianceInfo[index]) == position);
735         }
736
737         case ELEMENT_TYPE_GENERICINST:
738         {
739             IfFailThrow(psig.GetElemType(&typ));
740             mdTypeRef typeref;
741             IfFailThrow(psig.GetToken(&typeref));
742
743             // The number of type parameters follows
744             DWORD ntypars;
745             IfFailThrow(psig.GetData(&ntypars));
746
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)
750             {
751                 for (unsigned i = 0; i < ntypars; i++)
752                 {
753                     if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant))
754                         return FALSE;
755
756                     IfFailThrow(psig.SkipExactlyOne());
757                 }
758             }
759             // Otherwise we need to take notice of the variance annotation on each type parameter to the generic type
760             else
761             {
762                 mdTypeDef typeDef;
763                 Module *  pDefModule;
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))
766                     return TRUE;
767
768                 HENUMInternal   hEnumGenericPars;
769                 if (FAILED(pDefModule->GetMDImport()->EnumInit(mdtGenericParam, typeDef, &hEnumGenericPars)))
770                 {
771                     pDefModule->GetAssembly()->ThrowTypeLoadException(pDefModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
772                 }
773                 
774                 for (unsigned i = 0; i < ntypars; i++)
775                 {
776                     mdGenericParam tkTyPar;
777                     pDefModule->GetMDImport()->EnumNext(&hEnumGenericPars, &tkTyPar);
778                     DWORD flags;
779                     if (FAILED(pDefModule->GetMDImport()->GetGenericParamProps(tkTyPar, NULL, &flags, NULL, NULL, NULL)))
780                     {
781                         pDefModule->GetAssembly()->ThrowTypeLoadException(pDefModule->GetMDImport(), typeDef, IDS_CLASSLOAD_BADFORMAT);
782                     }
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)
786                     {
787                         genPosition = genPosition == gpCovariant ? gpContravariant
788                                     : genPosition == gpContravariant ? gpCovariant
789                                     : gpNonVariant;
790                     }
791                     if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, genPosition))
792                         return FALSE;
793
794                     IfFailThrow(psig.SkipExactlyOne());
795                 }
796                 pDefModule->GetMDImport()->EnumClose(&hEnumGenericPars);
797             }
798
799             return TRUE;
800         }
801
802         // Arrays behave covariantly
803         case ELEMENT_TYPE_ARRAY:
804         case ELEMENT_TYPE_SZARRAY:
805             return CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, position);
806
807         // Pointers behave non-variantly
808         case ELEMENT_TYPE_BYREF:
809         case ELEMENT_TYPE_PTR:
810             return CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant);
811
812         case ELEMENT_TYPE_FNPTR:
813             {
814                 // Calling convention
815                 IfFailThrow(psig.GetData(NULL));
816
817                 // Get arg count;
818                 ULONG cArgs;
819                 IfFailThrow(psig.GetData(&cArgs));
820
821                 // Conservatively, assume non-variance of function pointer types
822                 if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant))
823                     return FALSE;
824
825                 IfFailThrow(psig.SkipExactlyOne());
826
827                 for (unsigned i = 0; i < cArgs; i++)
828                 {
829                     if (!CheckVarianceInSig(numGenericArgs, pVarianceInfo, pModule, psig, gpNonVariant))
830                         return FALSE;
831
832                     IfFailThrow(psig.SkipExactlyOne());
833                 }
834
835                 return TRUE;
836             }
837
838         default:
839             THROW_BAD_FORMAT(IDS_CLASSLOAD_BAD_VARIANCE_SIG, pModule);
840     }
841
842     return FALSE;
843 } // EEClass::CheckVarianceInSig
844
845 void 
846 ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)
847 {
848     CONTRACTL
849     {
850         STANDARD_VM_CHECK;
851         PRECONDITION(CheckPointer(pMT));
852     }
853     CONTRACTL_END;
854
855
856     TypeHandle thisTH(pMT);
857     SigTypeContext typeContext(thisTH);
858     IMDInternalImport* pInternalImport = pMT->GetMDImport();
859     MethodTable *pParentMT = pMT->GetParentMethodTable();
860
861     if (pParentMT != NULL && pParentMT->HasInstantiation())
862     {
863         // Fill in exact parent if it's instantiated
864         mdToken crExtends;
865         IfFailThrow(pInternalImport->GetTypeDefProps(
866             pMT->GetCl(), 
867             NULL, 
868             &crExtends));
869         
870         _ASSERTE(!IsNilToken(crExtends));
871         _ASSERTE(TypeFromToken(crExtends) == mdtTypeSpec);
872
873         TypeHandle newParent = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pMT->GetModule(), crExtends, &typeContext,
874                                                                            ClassLoader::ThrowIfNotFound,
875                                                                            ClassLoader::FailIfUninstDefOrRef,
876                                                                            ClassLoader::LoadTypes,
877                                                                            CLASS_LOAD_EXACTPARENTS,
878                                                                            TRUE);
879
880         MethodTable* pNewParentMT = newParent.AsMethodTable();
881         if (pNewParentMT != pParentMT)
882         {
883             LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Replaced approximate parent %s with exact parent %s from token %x\n", pParentMT->GetDebugClassName(), pNewParentMT->GetDebugClassName(), crExtends));
884
885             // SetParentMethodTable is not used here since we want to update the indirection cell in the NGen case
886             if (pMT->IsParentMethodTableIndirectPointerMaybeNull())
887             {
888                 *EnsureWritablePages(pMT->GetParentMethodTableValuePtr()) = pNewParentMT;
889             }
890             else
891             {
892                 EnsureWritablePages(pMT->GetParentMethodTablePointerPtr());
893                 pMT->GetParentMethodTablePointerPtr()->SetValueMaybeNull(pNewParentMT);
894             }
895
896             pParentMT = pNewParentMT;
897         }
898     }
899
900     if (pParentMT != NULL)
901     {
902         EnsureLoaded(pParentMT, CLASS_LOAD_EXACTPARENTS);
903     }
904
905
906     if (pParentMT != NULL && pParentMT->HasPerInstInfo())
907     {
908         // Copy down all inherited dictionary pointers which we
909         // could not embed.
910         DWORD nDicts = pParentMT->GetNumDicts();
911         for (DWORD iDict = 0; iDict < nDicts; iDict++)
912         {
913             if (pMT->GetPerInstInfo()[iDict].GetValueMaybeNull() != pParentMT->GetPerInstInfo()[iDict].GetValueMaybeNull())
914             {
915                 EnsureWritablePages(&pMT->GetPerInstInfo()[iDict]);
916                 pMT->GetPerInstInfo()[iDict].SetValueMaybeNull(pParentMT->GetPerInstInfo()[iDict].GetValueMaybeNull());
917             }
918         }
919     }
920
921 #ifdef FEATURE_PREJIT
922     // Restore action, not in MethodTable::Restore because we may have had approx parents at that point
923     if (pMT->IsZapped())
924     {
925         MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
926         while (it.Next())
927         {
928             Module::RestoreMethodTablePointer(&it.GetInterfaceInfo()->m_pMethodTable, pMT->GetLoaderModule(), CLASS_LOAD_EXACTPARENTS);
929         }
930     }
931     else
932 #endif
933     {
934         MethodTableBuilder::LoadExactInterfaceMap(pMT);
935     }
936     
937 #ifdef _DEBUG
938     if (g_pConfig->ShouldDumpOnClassLoad(pMT->GetDebugClassName()))
939     {
940         pMT->Debug_DumpInterfaceMap("Exact");
941     }
942 #endif //_DEBUG
943 } // ClassLoader::LoadExactParentAndInterfacesTransitively
944
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
949 // * Fixup vtable
950 //
951 /*static*/
952 void ClassLoader::LoadExactParents(MethodTable *pMT)
953 {
954     CONTRACT_VOID
955     {
956         STANDARD_VM_CHECK;
957         PRECONDITION(CheckPointer(pMT));
958         POSTCONDITION(pMT->CheckLoadLevel(CLASS_LOAD_EXACTPARENTS));
959     }
960     CONTRACT_END;
961
962     MethodTable *pApproxParentMT = pMT->GetParentMethodTable();
963
964     if (!pMT->IsCanonicalMethodTable())
965     {
966         EnsureLoaded(TypeHandle(pMT->GetCanonicalMethodTable()), CLASS_LOAD_EXACTPARENTS);
967     }
968
969     LoadExactParentAndInterfacesTransitively(pMT);
970
971     MethodTableBuilder::CopyExactParentSlots(pMT, pApproxParentMT);
972
973     // We can now mark this type as having exact parents
974     pMT->SetHasExactParent();
975
976     RETURN;
977 }
978
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.
982 // 
983 // * see code:MethodTable#KindsOfElementTypes for more
984 // * It get used by code:TypeHandle::GetInternalCorElementType
985 CorElementType EEClass::ComputeInternalCorElementTypeForValueType(MethodTable * pMT)
986 {
987     CONTRACTL {
988         THROWS;
989         GC_TRIGGERS;
990     } CONTRACTL_END;
991
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.
998     {
999         FieldDesc * pFD = pMT->GetApproxFieldDescListRaw();
1000         CorElementType type = pFD->GetFieldType();
1001
1002         if (type == ELEMENT_TYPE_VALUETYPE)
1003         {
1004             //@todo: Is it more apropos to call LookupApproxFieldTypeHandle() here?
1005             TypeHandle fldHnd = pFD->GetApproxFieldTypeHandleThrowing();
1006             CONSISTENCY_CHECK(!fldHnd.IsNull());
1007
1008             type = fldHnd.GetInternalCorElementType();
1009         }
1010
1011         switch (type)
1012         {
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;
1023                 
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_
1032             
1033             {
1034                 return type;
1035             }
1036
1037             default:
1038                 break;
1039         }
1040     }
1041
1042     return ELEMENT_TYPE_VALUETYPE;
1043 }
1044
1045 //*******************************************************************************
1046 //
1047 // Debugger notification
1048 //
1049 BOOL TypeHandle::NotifyDebuggerLoad(AppDomain *pDomain, BOOL attaching) const
1050 {
1051     LIMITED_METHOD_CONTRACT;
1052
1053     if (!CORDebuggerAttached())
1054     {
1055         return FALSE;
1056     }
1057
1058     if (!GetModule()->IsVisibleToDebugger())
1059     {
1060         return FALSE;
1061     }
1062
1063     return g_pDebugInterface->LoadClass(
1064         *this, GetCl(), GetModule(), pDomain);
1065 }
1066
1067 //*******************************************************************************
1068 void TypeHandle::NotifyDebuggerUnload(AppDomain *pDomain) const
1069 {
1070     LIMITED_METHOD_CONTRACT;
1071
1072     if (!GetModule()->IsVisibleToDebugger())
1073         return;
1074
1075     if (!pDomain->IsDebuggerAttached())
1076         return;
1077
1078     g_pDebugInterface->UnloadClass(GetCl(), GetModule(), pDomain);
1079 }
1080
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.
1084 //
1085 // This is needed when creating a delegate to an instance method in a value type
1086 MethodDesc* MethodTable::GetBoxedEntryPointMD(MethodDesc *pMD)
1087 {
1088     CONTRACT (MethodDesc *) {
1089         THROWS;
1090         GC_TRIGGERS;
1091         INJECT_FAULT(COMPlusThrowOM(););
1092         PRECONDITION(IsValueType());
1093         PRECONDITION(!pMD->ContainsGenericVariables());
1094         PRECONDITION(!pMD->IsUnboxingStub());
1095         POSTCONDITION(RETVAL->IsUnboxingStub());
1096     } CONTRACT_END;
1097
1098     RETURN MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
1099                                                         pMD->GetMethodTable(),
1100                                                         TRUE /* get unboxing entry point */,
1101                                                         pMD->GetMethodInstantiation(),
1102                                                         FALSE /* no allowInstParam */ );
1103
1104 }
1105
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)
1110 {
1111     CONTRACT (MethodDesc *) {
1112         THROWS;
1113         GC_TRIGGERS;
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());
1121     } CONTRACT_END;
1122
1123     BOOL allowInstParam = (pMD->GetNumGenericMethodArgs() == 0);
1124     RETURN MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
1125                                                         this,
1126                                                         FALSE /* don't get unboxing entry point */,
1127                                                         pMD->GetMethodInstantiation(),
1128                                                         allowInstParam);
1129 }
1130
1131
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)
1136 {
1137     CONTRACT (MethodDesc *) {
1138         THROWS;
1139         GC_NOTRIGGER;
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());
1147     } CONTRACT_END;
1148
1149     BOOL allowInstParam = (pMD->GetNumGenericMethodArgs() == 0);
1150     RETURN MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
1151                                                         this,
1152                                                         FALSE /* don't get unboxing entry point */,
1153                                                         pMD->GetMethodInstantiation(),
1154                                                         allowInstParam,
1155                                                         FALSE, /* forceRemotableMethod */
1156                                                         FALSE  /* allowCreate */
1157                                                        );
1158 }
1159
1160 #endif // !DACCESS_COMPILE 
1161
1162 //*******************************************************************************
1163 #if !defined(FEATURE_HFA)
1164 bool MethodTable::IsHFA()
1165 {
1166     LIMITED_METHOD_CONTRACT;
1167 #ifdef DACCESS_COMPILE
1168     return false;
1169 #else
1170     if (GetClass()->GetMethodTable()->IsValueType())
1171     {
1172         return GetClass()->CheckForHFA();
1173     }
1174     else
1175     {
1176         return false;
1177     }
1178 #endif
1179 }
1180 #endif // !FEATURE_HFA
1181
1182 //*******************************************************************************
1183 int MethodTable::GetVectorSize()
1184 {
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())
1189     {
1190         LPCUTF8 namespaceName;
1191         LPCUTF8 className = GetFullyQualifiedNameInfo(&namespaceName);
1192         int vectorSize = 0;
1193
1194         if (strcmp(className, "Vector`1") == 0)
1195         {
1196             vectorSize = GetNumInstanceFieldBytes();
1197             _ASSERTE(strcmp(namespaceName, "System.Numerics") == 0);
1198             return vectorSize;
1199         }
1200         if (strcmp(className, "Vector128`1") == 0)
1201         {
1202             vectorSize = 16;
1203         }
1204         else if (strcmp(className, "Vector256`1") == 0)
1205         {
1206             vectorSize = 32;
1207         }
1208         else if (strcmp(className, "Vector64`1") == 0)
1209         {
1210             vectorSize = 8;
1211         }
1212         if (vectorSize != 0)
1213         {
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))
1220             {
1221                 isSupportedElementType = false;
1222             }
1223             if (isSupportedElementType)
1224             {
1225                 _ASSERTE(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0);
1226                 return vectorSize;
1227             }
1228         }
1229     }
1230 #endif // _TARGET_64BIT_
1231     return 0;
1232 }
1233
1234 //*******************************************************************************
1235 CorElementType MethodTable::GetHFAType()
1236 {
1237     CONTRACTL
1238     {
1239         WRAPPER(THROWS);        // we end up in the class loader which has the conditional contracts
1240         WRAPPER(GC_TRIGGERS);
1241     }
1242     CONTRACTL_END;
1243
1244     if (!IsHFA())
1245         return ELEMENT_TYPE_END;
1246
1247     MethodTable * pMT = this;
1248     for (;;)
1249     {
1250         _ASSERTE(pMT->IsValueType());
1251         _ASSERTE(pMT->GetNumInstanceFields() > 0);
1252
1253         int vectorSize = pMT->GetVectorSize();
1254         if (vectorSize != 0)
1255         {
1256             return (vectorSize == 8) ? ELEMENT_TYPE_R8 : ELEMENT_TYPE_VALUETYPE;
1257         }
1258
1259         PTR_FieldDesc pFirstField = pMT->GetApproxFieldDescListRaw();
1260
1261         CorElementType fieldType = pFirstField->GetFieldType();
1262
1263         // All HFA fields have to be of the same type, so we can just return the type of the first field
1264         switch (fieldType)
1265         {
1266         case ELEMENT_TYPE_VALUETYPE:
1267             pMT = pFirstField->LookupApproxFieldTypeHandle().GetMethodTable();
1268             vectorSize = pMT->GetVectorSize();
1269             if (vectorSize != 0)
1270             {
1271                 return (vectorSize == 8) ? ELEMENT_TYPE_R8 : ELEMENT_TYPE_VALUETYPE;
1272             }
1273             break;
1274
1275         case ELEMENT_TYPE_R4:
1276         case ELEMENT_TYPE_R8:
1277             return fieldType;
1278
1279         default:
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.
1282             _ASSERTE(false);
1283             return ELEMENT_TYPE_END;
1284         }
1285     }
1286 }
1287
1288 bool MethodTable::IsNativeHFA()
1289 {
1290     LIMITED_METHOD_CONTRACT;
1291     return HasLayout() ? GetLayoutInfo()->IsNativeHFA() : IsHFA();
1292 }
1293
1294 CorElementType MethodTable::GetNativeHFAType()
1295 {
1296     LIMITED_METHOD_CONTRACT;
1297     return HasLayout() ? GetLayoutInfo()->GetNativeHFAType() : GetHFAType();
1298 }
1299
1300 //---------------------------------------------------------------------------------------
1301 //
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.
1304 //
1305 bool
1306 #if defined(FEATURE_HFA)
1307 EEClass::CheckForHFA(MethodTable ** pByValueClassCache)
1308 #else
1309 EEClass::CheckForHFA()
1310 #endif
1311 {
1312     STANDARD_VM_CONTRACT;
1313
1314     // This method should be called for valuetypes only
1315     _ASSERTE(GetMethodTable()->IsValueType());
1316
1317
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)
1321     {
1322 #if defined(FEATURE_HFA)
1323         GetMethodTable()->SetIsHFA();
1324 #endif
1325         return true;
1326     }
1327
1328     int elemSize = 0;
1329     CorElementType hfaType = ELEMENT_TYPE_END;
1330
1331     FieldDesc *pFieldDescList = GetFieldDescList();
1332
1333     bool hasZeroOffsetField = false;
1334
1335     for (UINT i = 0; i < GetNumInstanceFields(); i++)
1336     {
1337         FieldDesc *pFD = &pFieldDescList[i];
1338         hasZeroOffsetField |= (pFD->GetOffset() == 0);
1339
1340         CorElementType fieldType = pFD->GetFieldType();
1341
1342         switch (fieldType)
1343         {
1344         case ELEMENT_TYPE_VALUETYPE:
1345             {
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.
1352                 MethodTable* pMT;
1353 #if defined(FEATURE_HFA)
1354                 pMT = pByValueClassCache[i];
1355 #else
1356                 pMT = pFD->LookupApproxFieldTypeHandle().AsMethodTable();
1357 #endif
1358                 int thisElemSize = pMT->GetVectorSize();
1359                 if (thisElemSize != 0)
1360                 {
1361                     if (elemSize == 0)
1362                     {
1363                         elemSize = thisElemSize;
1364                     }
1365                     else if ((thisElemSize != elemSize) || (hfaType != ELEMENT_TYPE_VALUETYPE))
1366                     {
1367                         return false;
1368                     }
1369                 }
1370                 else
1371 #endif // _TARGET_ARM64_
1372                 {
1373 #if defined(FEATURE_HFA)
1374                     fieldType = pByValueClassCache[i]->GetHFAType();
1375 #else
1376                     fieldType = pFD->LookupApproxFieldTypeHandle().AsMethodTable()->GetHFAType();
1377 #endif
1378                 }
1379             }
1380             break;
1381
1382         case ELEMENT_TYPE_R4:
1383             {
1384                 static const int REQUIRED_FLOAT_ALIGNMENT = 4;
1385                 if (pFD->GetOffset() % REQUIRED_FLOAT_ALIGNMENT != 0) // HFAs don't have unaligned fields.
1386                 {
1387                     return false;
1388                 }
1389             }
1390             break;
1391         case ELEMENT_TYPE_R8:
1392             {
1393                 static const int REQUIRED_DOUBLE_ALIGNMENT = 8;
1394                 if (pFD->GetOffset() % REQUIRED_DOUBLE_ALIGNMENT != 0) // HFAs don't have unaligned fields.
1395                 {
1396                     return false;
1397                 }
1398             }
1399             break;
1400         default:
1401             // Not HFA
1402             return false;
1403         }
1404
1405         // Field type should be a valid HFA type.
1406         if (fieldType == ELEMENT_TYPE_END)
1407         {
1408             return false;
1409         }
1410
1411         // Initialize with a valid HFA type.
1412         if (hfaType == ELEMENT_TYPE_END)
1413         {
1414             hfaType = fieldType;
1415         }
1416         // All field types should be equal.
1417         else if (fieldType != hfaType)
1418         {
1419             return false;
1420         }
1421     }
1422
1423     switch (hfaType)
1424     {
1425     case ELEMENT_TYPE_R4:
1426         elemSize = 4;
1427         break;
1428     case ELEMENT_TYPE_R8:
1429         elemSize = 8;
1430         break;
1431 #ifdef _TARGET_ARM64_
1432     case ELEMENT_TYPE_VALUETYPE:
1433         // Should already have set elemSize, but be conservative
1434         if (elemSize == 0)
1435         {
1436             return false;
1437         }
1438         break;
1439 #endif
1440     default:
1441         // ELEMENT_TYPE_END
1442         return false;
1443     }
1444         
1445     if (!hasZeroOffsetField) // If the struct doesn't have a zero-offset field, it's not an HFA.
1446         return false;
1447
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
1452
1453     DWORD totalSize = GetMethodTable()->GetNumInstanceFieldBytes();
1454
1455     if (totalSize % elemSize != 0)
1456         return false;
1457
1458     // On ARM, HFAs can have a maximum of four fields regardless of whether those are float or double.
1459     if (totalSize / elemSize > 4)
1460         return false;
1461
1462     // All the above tests passed. It's HFA(/HVA)!
1463 #if defined(FEATURE_HFA)
1464     GetMethodTable()->SetIsHFA();
1465 #endif
1466     return true;
1467 }
1468
1469 CorElementType EEClassLayoutInfo::GetNativeHFATypeRaw()
1470 {
1471     UINT  numReferenceFields = GetNumCTMFields();
1472
1473     CorElementType hfaType = ELEMENT_TYPE_END;
1474
1475 #ifndef DACCESS_COMPILE
1476     const FieldMarshaler *pFieldMarshaler = GetFieldMarshalers();
1477     while (numReferenceFields--)
1478     {
1479         CorElementType fieldType = ELEMENT_TYPE_END;
1480
1481         switch (pFieldMarshaler->GetNStructFieldType())
1482         {
1483         case NFT_COPY4:
1484         case NFT_COPY8:
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;
1489             break;
1490
1491         case NFT_NESTEDLAYOUTCLASS:
1492             fieldType = ((FieldMarshaler_NestedLayoutClass *)pFieldMarshaler)->GetMethodTable()->GetNativeHFAType();
1493             break;
1494
1495         case NFT_NESTEDVALUECLASS:
1496             fieldType = ((FieldMarshaler_NestedValueClass *)pFieldMarshaler)->GetMethodTable()->GetNativeHFAType();
1497             break;
1498
1499         case NFT_FIXEDARRAY:
1500             fieldType = ((FieldMarshaler_FixedArray *)pFieldMarshaler)->GetElementTypeHandle().GetMethodTable()->GetNativeHFAType();
1501             break;
1502
1503         case NFT_DATE:
1504             fieldType = ELEMENT_TYPE_R8;
1505             break;
1506
1507         default:
1508             // Not HFA
1509             return ELEMENT_TYPE_END;
1510         }
1511
1512         // Field type should be a valid HFA type.
1513         if (fieldType == ELEMENT_TYPE_END)
1514         {
1515             return ELEMENT_TYPE_END;
1516         }
1517
1518         // Initialize with a valid HFA type.
1519         if (hfaType == ELEMENT_TYPE_END)
1520         {
1521             hfaType = fieldType;
1522         }
1523         // All field types should be equal.
1524         else if (fieldType != hfaType)
1525         {
1526             return ELEMENT_TYPE_END;
1527         }
1528
1529         ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
1530     }
1531
1532     if (hfaType == ELEMENT_TYPE_END)
1533         return ELEMENT_TYPE_END;
1534
1535     int elemSize = 1;
1536     switch (hfaType)
1537     {
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;
1542 #endif
1543     default: _ASSERTE(!"Invalid HFA Type");
1544     }
1545
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
1550
1551     DWORD totalSize = GetNativeSize();
1552
1553     if (totalSize % elemSize != 0)
1554         return ELEMENT_TYPE_END;
1555
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;
1559
1560 #endif // !DACCESS_COMPILE
1561
1562     return hfaType;
1563 }
1564
1565 #ifdef FEATURE_HFA
1566 //
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.
1569 //
1570 VOID EEClass::CheckForNativeHFA()
1571 {
1572     STANDARD_VM_CONTRACT;
1573
1574     // No HFAs with inheritance
1575     if (!(GetMethodTable()->IsValueType() || (GetMethodTable()->GetParentMethodTable() == g_pObjectClass)))
1576         return;
1577
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())
1582         return;
1583
1584     CorElementType hfaType = GetLayoutInfo()->GetNativeHFATypeRaw();
1585     if (hfaType == ELEMENT_TYPE_END)
1586     {
1587         return;
1588     }
1589
1590     // All the above tests passed. It's HFA!
1591     GetLayoutInfo()->SetNativeHFAType(hfaType);
1592 }
1593 #endif // FEATURE_HFA
1594
1595 #ifdef FEATURE_64BIT_ALIGNMENT
1596 // Returns true iff the native view of this type requires 64-bit aligment.
1597 bool MethodTable::NativeRequiresAlign8()
1598 {
1599     LIMITED_METHOD_CONTRACT;
1600
1601     if (HasLayout())
1602     {
1603         return (GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers() >= 8);
1604     }
1605     return RequiresAlign8();
1606 }
1607 #endif // FEATURE_64BIT_ALIGNMENT
1608
1609 #ifndef DACCESS_COMPILE 
1610
1611 #ifdef FEATURE_COMINTEROP 
1612 //==========================================================================================
1613 TypeHandle MethodTable::GetCoClassForInterface()
1614 {
1615     CONTRACTL
1616     {
1617         THROWS;
1618         GC_TRIGGERS;
1619         INJECT_FAULT(COMPlusThrowOM(););
1620     }
1621     CONTRACTL_END
1622
1623     EEClass * pClass = GetClass();
1624
1625     if (!pClass->IsComClassInterface())
1626         return TypeHandle();
1627
1628     _ASSERTE(IsInterface());
1629
1630     TypeHandle th = pClass->GetCoClassForInterface();
1631     if (!th.IsNull())
1632         return th;
1633
1634     return SetupCoClassForInterface();
1635 }
1636
1637 //*******************************************************************************
1638 TypeHandle MethodTable::SetupCoClassForInterface()
1639 {
1640     CONTRACTL
1641     {
1642         THROWS;
1643         GC_TRIGGERS;
1644         INJECT_FAULT(COMPlusThrowOM(););
1645         PRECONDITION(IsComClassInterface());
1646
1647     }
1648     CONTRACTL_END
1649
1650     TypeHandle CoClassType;
1651     const BYTE *pVal = NULL;
1652     ULONG cbVal = 0;
1653
1654     if (!IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT types
1655     {
1656         HRESULT hr = GetCustomAttribute(WellKnownAttribute::CoClass, (const void **)&pVal, &cbVal);
1657         if (hr == S_OK)
1658         {
1659             CustomAttributeParser cap(pVal, cbVal);
1660
1661             IfFailThrow(cap.SkipProlog());
1662
1663             // Retrieve the COM source interface class name.
1664             ULONG       cbName;
1665             LPCUTF8     szName;
1666             IfFailThrow(cap.GetNonNullString(&szName, &cbName));
1667
1668             // Copy the name to a temporary buffer and NULL terminate it.
1669             StackSString ss(SString::Utf8, szName, cbName);
1670
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());
1674
1675             // Cache the coclass type
1676             g_IBCLogger.LogEEClassCOWTableAccess(this);
1677             GetClass_NoLogging()->SetCoClassForInterface(CoClassType);
1678         }
1679     }
1680     return CoClassType;
1681 }
1682
1683 //*******************************************************************************
1684 void MethodTable::GetEventInterfaceInfo(MethodTable **ppSrcItfClass, MethodTable **ppEvProvClass)
1685 {
1686     CONTRACTL
1687     {
1688         THROWS;
1689         GC_TRIGGERS;
1690         INJECT_FAULT(COMPlusThrowOM(););
1691     }
1692     CONTRACTL_END
1693
1694
1695     TypeHandle EventProvType;
1696     TypeHandle SrcItfType;
1697     const BYTE *pVal = NULL;
1698     ULONG cbVal = 0;
1699
1700     // Retrieve the ComEventProviderAttribute CA.
1701     HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COMEVENTINTERFACE_TYPE, (const void**)&pVal, &cbVal);
1702     if (FAILED(hr))
1703     {
1704         COMPlusThrowHR(hr);
1705     }
1706
1707     CustomAttributeParser cap(pVal, cbVal);
1708
1709     // Skip the CA type prefix.
1710     IfFailThrow(cap.SkipProlog());
1711
1712     // Retrieve the COM source interface class name.
1713     LPCUTF8 szName;
1714     ULONG   cbName;
1715     IfFailThrow(cap.GetNonNullString(&szName, &cbName));
1716
1717     // Copy the name to a temporary buffer and NULL terminate it.
1718     StackSString ss(SString::Utf8, szName, cbName);
1719
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());
1723
1724     // Retrieve the COM event provider class name.
1725     IfFailThrow(cap.GetNonNullString(&szName, &cbName));
1726
1727     // Copy the name to a temporary buffer and NULL terminate it.
1728     ss.SetUTF8(szName, cbName);
1729
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());
1733
1734     // Set the source interface and event provider classes.
1735     *ppSrcItfClass = SrcItfType.GetMethodTable();
1736     *ppEvProvClass = EventProvType.GetMethodTable();
1737 }
1738
1739 //*******************************************************************************
1740 TypeHandle MethodTable::GetDefItfForComClassItf()
1741 {
1742     CONTRACTL
1743     {
1744         THROWS;
1745         GC_TRIGGERS;
1746         INJECT_FAULT(COMPlusThrowOM(););
1747     }
1748     CONTRACTL_END
1749
1750     BAD_FORMAT_NOTHROW_ASSERT(GetClass()->IsComClassInterface());
1751
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();
1757     if (it.Next())
1758     {
1759         return TypeHandle(it.GetInterface());
1760     }
1761     else
1762     {
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);
1766     }
1767 }
1768
1769 #endif // FEATURE_COMINTEROP
1770
1771
1772 #endif // !DACCESS_COMPILE
1773
1774 //---------------------------------------------------------------------------------------
1775 //
1776 // Get the metadata token of the outer type for a nested type
1777 //
1778 // Return Value:
1779 //    The token of the outer class if this EEClass is nested, or mdTypeDefNil if the
1780 //    EEClass is not a nested type
1781 //
1782
1783 mdTypeDef MethodTable::GetEnclosingCl()
1784 {
1785     CONTRACTL
1786     {
1787         THROWS;
1788         GC_TRIGGERS;
1789         MODE_ANY;
1790     }
1791     CONTRACTL_END;
1792
1793     mdTypeDef tdEnclosing = mdTypeDefNil;
1794
1795     if (GetClass()->IsNested())
1796     {
1797         HRESULT hr = GetMDImport()->GetNestedClassProps(GetCl(), &tdEnclosing);
1798         if (FAILED(hr))
1799         {
1800             ThrowHR(hr, BFA_UNABLE_TO_GET_NESTED_PROPS);
1801         }
1802     }
1803
1804     return tdEnclosing;
1805 }
1806
1807 //*******************************************************************************
1808 //
1809 // Helper routines for the macros defined at the top of this class.
1810 // You probably should not use these functions directly.
1811 //
1812 template<typename RedirectFunctor>
1813 SString &MethodTable::_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf)
1814 {
1815     CONTRACTL {
1816         THROWS;
1817         GC_NOTRIGGER;
1818         INJECT_FAULT(COMPlusThrowOM(););
1819     } CONTRACTL_END;
1820
1821     ssBuf.Clear();
1822
1823     LPCUTF8 pszNamespace;
1824     LPCUTF8 pszName;
1825     pszName = GetFullyQualifiedNameInfo(&pszNamespace);
1826     if (pszName == NULL)
1827     {
1828         return ssBuf;
1829     }
1830
1831     StackSString ssName(SString::Utf8, pszName);
1832
1833     mdTypeDef mdEncl = GetCl();
1834     IMDInternalImport *pImport = GetMDImport();
1835
1836     // Check if the type is nested
1837     DWORD dwAttr;
1838     IfFailThrow(pImport->GetTypeDefProps(GetCl(), &dwAttr, NULL));
1839
1840     RedirectFunctor redirectFunctor;
1841     if (IsTdNested(dwAttr))
1842     {
1843         StackSString ssFullyQualifiedName;
1844         StackSString ssPath;
1845
1846         // Build the nesting chain.
1847         while (SUCCEEDED(pImport->GetNestedClassProps(mdEncl, &mdEncl)))
1848         {
1849             LPCUTF8 szEnclName;
1850             LPCUTF8 szEnclNameSpace;
1851             IfFailThrow(pImport->GetNameOfTypeDef(
1852                 mdEncl, 
1853                 &szEnclName, 
1854                 &szEnclNameSpace));
1855             
1856             ns::MakePath(ssPath, 
1857                 StackSString(SString::Utf8, redirectFunctor(szEnclNameSpace)), 
1858                 StackSString(SString::Utf8, szEnclName));
1859             ns::MakeNestedTypeName(ssFullyQualifiedName, ssPath, ssName);
1860
1861             ssName = ssFullyQualifiedName;
1862         }
1863     }
1864
1865     ns::MakePath(
1866         ssBuf, 
1867         StackSString(SString::Utf8, redirectFunctor(pszNamespace)), ssName);
1868
1869     return ssBuf;
1870 }
1871
1872 class PassThrough
1873 {
1874 public :
1875     LPCUTF8 operator() (LPCUTF8 szEnclNamespace)
1876     {
1877         LIMITED_METHOD_CONTRACT;
1878         
1879         return szEnclNamespace;    
1880     }
1881 };
1882
1883 SString &MethodTable::_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf)
1884 {
1885     LIMITED_METHOD_CONTRACT;
1886
1887     return _GetFullyQualifiedNameForClassNestedAwareInternal<PassThrough>(ssBuf);
1888 }
1889
1890 //*******************************************************************************
1891 SString &MethodTable::_GetFullyQualifiedNameForClass(SString &ssBuf)
1892 {
1893     CONTRACTL
1894     {
1895         THROWS;
1896         GC_NOTRIGGER;
1897         INJECT_FAULT(COMPlusThrowOM(););
1898     }
1899     CONTRACTL_END
1900     
1901     ssBuf.Clear();
1902     
1903     if (IsArray())
1904     {
1905         TypeDesc::ConstructName(GetInternalCorElementType(),
1906                                 GetApproxArrayElementTypeHandle(),
1907                                 GetRank(),
1908                                 ssBuf);
1909     }
1910     else if (!IsNilToken(GetCl()))
1911     {
1912         LPCUTF8 szNamespace;
1913         LPCUTF8 szName;
1914         IfFailThrow(GetMDImport()->GetNameOfTypeDef(GetCl(), &szName, &szNamespace));
1915         
1916         ns::MakePath(ssBuf,
1917                      StackSString(SString::Utf8, szNamespace),
1918                      StackSString(SString::Utf8, szName));
1919     }
1920     
1921     return ssBuf;
1922 }
1923
1924 //*******************************************************************************
1925 //
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
1928 // an error.
1929 //
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.
1934 //
1935 LPCUTF8 MethodTable::GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace)
1936 {
1937     CONTRACTL
1938     {
1939         NOTHROW;
1940         GC_NOTRIGGER;
1941         FORBID_FAULT;
1942     }
1943     CONTRACTL_END
1944
1945     if (IsArray())
1946     {
1947         *ppszNamespace = NULL;
1948         return NULL;
1949     }
1950     else
1951     {
1952         LPCUTF8 szName;
1953         if (FAILED(GetMDImport()->GetNameOfTypeDef(GetCl(), &szName, ppszNamespace)))
1954         {
1955             *ppszNamespace = NULL;
1956             return NULL;
1957         }
1958         return szName;
1959     }
1960 }
1961
1962 #ifndef DACCESS_COMPILE 
1963
1964 #ifdef FEATURE_COMINTEROP 
1965
1966 //*******************************************************************************
1967 CorIfaceAttr MethodTable::GetComInterfaceType()
1968 {
1969     CONTRACTL
1970     {
1971         THROWS;
1972         GC_NOTRIGGER;
1973         FORBID_FAULT;
1974     }
1975     CONTRACTL_END
1976
1977     // This should only be called on interfaces.
1978     BAD_FORMAT_NOTHROW_ASSERT(IsInterface());
1979
1980     // Check to see if we have already determined the COM interface type
1981     // of this interface.
1982     CorIfaceAttr ItfType = GetClass()->GetComInterfaceType();
1983
1984     if (ItfType != (CorIfaceAttr)-1)
1985         return ItfType;
1986
1987     if (IsProjectedFromWinRT())
1988     {
1989         // WinRT interfaces are always IInspectable-based
1990         ItfType = ifInspectable;
1991     }
1992     else
1993     {
1994         // Retrieve the interface type from the metadata.
1995         HRESULT hr = GetMDImport()->GetIfaceTypeOfTypeDef(GetCl(), (ULONG*)&ItfType);
1996         IfFailThrow(hr);
1997
1998         if (hr != S_OK)
1999         {
2000             // if not found in metadata, use the default
2001             ItfType = ifDual;
2002         }
2003     }
2004
2005     // Cache the interface type
2006     g_IBCLogger.LogEEClassCOWTableAccess(this);
2007     GetClass_NoLogging()->SetComInterfaceType(ItfType);
2008
2009     return ItfType;
2010 }
2011
2012 #endif // FEATURE_COMINTEROP
2013
2014 //*******************************************************************************
2015 void EEClass::GetBestFitMapping(MethodTable * pMT, BOOL *pfBestFitMapping, BOOL *pfThrowOnUnmappableChar)
2016 {
2017     CONTRACTL
2018     {
2019         THROWS; // OOM only
2020         GC_NOTRIGGER;
2021         MODE_ANY;
2022     }
2023     CONTRACTL_END;
2024
2025     EEClass * pClass = pMT->GetClass();
2026
2027     // lazy init
2028     if (!(pClass->m_VMFlags & VMFLAG_BESTFITMAPPING_INITED))
2029     {
2030         *pfBestFitMapping = FALSE;
2031         *pfThrowOnUnmappableChar = FALSE;
2032         
2033         ReadBestFitCustomAttribute(pMT->GetModule(), pMT->GetCl(), pfBestFitMapping, pfThrowOnUnmappableChar);
2034
2035         DWORD flags = VMFLAG_BESTFITMAPPING_INITED;
2036         if (*pfBestFitMapping) flags |= VMFLAG_BESTFITMAPPING;
2037         if (*pfThrowOnUnmappableChar) flags |= VMFLAG_THROWONUNMAPPABLECHAR;
2038
2039         FastInterlockOr(EnsureWritablePages(&pClass->m_VMFlags), flags);
2040     }
2041     else
2042     {
2043         *pfBestFitMapping = (pClass->m_VMFlags & VMFLAG_BESTFITMAPPING);
2044         *pfThrowOnUnmappableChar = (pClass->m_VMFlags & VMFLAG_THROWONUNMAPPABLECHAR);
2045     }
2046 }
2047
2048 #ifdef _DEBUG
2049
2050 //*******************************************************************************
2051 void MethodTable::DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug)
2052 {
2053     WRAPPER_NO_CONTRACT;  // It's a dev helper, who cares about contracts
2054
2055     EX_TRY
2056     {
2057         StackSString ssBuff;
2058
2059         DWORD cParentInstanceFields;
2060         DWORD i;
2061
2062         CONSISTENCY_CHECK(CheckLoadLevel(CLASS_LOAD_APPROXPARENTS));
2063
2064         MethodTable *pParentMT = GetParentMethodTable();
2065         if (pParentMT != NULL)
2066         {
2067             cParentInstanceFields = pParentMT->GetClass()->GetNumInstanceFields();
2068             DefineFullyQualifiedNameForClass();
2069             LPCUTF8 name = GetFullyQualifiedNameForClass(pParentMT);
2070             pParentMT->DebugRecursivelyDumpInstanceFields(name, debug);
2071         }
2072         else
2073         {
2074             cParentInstanceFields = 0;
2075         }
2076
2077         // Are there any new instance fields declared by this class?
2078         if (GetNumInstanceFields() > cParentInstanceFields)
2079         {
2080             // Display them
2081             if(debug) {
2082                 ssBuff.Printf(W("%S:\n"), pszClassName);
2083                 WszOutputDebugString(ssBuff.GetUnicode());
2084             }
2085             else {
2086                  LOG((LF_CLASSLOADER, LL_ALWAYS, "%s:\n", pszClassName));
2087             }
2088
2089             for (i = 0; i < (GetNumInstanceFields()-cParentInstanceFields); i++)
2090             {
2091                 FieldDesc *pFD = &GetClass()->GetFieldDescList()[i];
2092 #ifdef DEBUG_LAYOUT
2093                 printf("offset %s%3d %s\n", pFD->IsByValue() ? "byvalue " : "", pFD->GetOffset_NoLogging(), pFD->GetName());
2094 #endif
2095                 if(debug) {
2096                     ssBuff.Printf(W("offset %3d %S\n"), pFD->GetOffset_NoLogging(), pFD->GetName());
2097                     WszOutputDebugString(ssBuff.GetUnicode());
2098                 }
2099                 else {
2100                     LOG((LF_CLASSLOADER, LL_ALWAYS, "offset %3d %s\n", pFD->GetOffset_NoLogging(), pFD->GetName()));
2101                 }
2102             }
2103         }
2104     }
2105     EX_CATCH
2106     {
2107         if(debug)
2108         {
2109             WszOutputDebugString(W("<Exception Thrown>\n"));
2110         }
2111         else
2112         {
2113              LOG((LF_CLASSLOADER, LL_ALWAYS, "<Exception Thrown>\n"));
2114         }
2115     }
2116     EX_END_CATCH(SwallowAllExceptions);
2117 }
2118
2119 //*******************************************************************************
2120 void MethodTable::DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug)
2121 {
2122     WRAPPER_NO_CONTRACT;   // It's a dev helper, who cares about contracts
2123
2124     if (GetNumStaticFields() == 0 && GetNumInstanceFields() == 0)
2125         return;
2126     
2127     EX_TRY
2128     {
2129         StackSString ssBuff;
2130         
2131         DWORD i;
2132         DWORD cParentInstanceFields;
2133         
2134         CONSISTENCY_CHECK(CheckLoadLevel(CLASS_LOAD_APPROXPARENTS));
2135         
2136         if (GetParentMethodTable() != NULL)
2137             cParentInstanceFields = GetParentMethodTable()->GetNumInstanceFields();
2138         else
2139         {
2140             cParentInstanceFields = 0;
2141         }
2142         
2143         if (debug)
2144         {
2145             ssBuff.Printf(W("Field layout for '%S':\n\n"), pszClassName);
2146             WszOutputDebugString(ssBuff.GetUnicode());
2147         }
2148         else
2149         {
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));
2152         }
2153
2154         if (GetNumStaticFields() > 0)
2155         {
2156             if (debug)
2157             {
2158                 WszOutputDebugString(W("Static fields (stored at vtable offsets)\n"));
2159                 WszOutputDebugString(W("----------------------------------------\n"));
2160             }
2161             else
2162             {
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"));
2166             }
2167
2168             for (i = 0; i < GetNumStaticFields(); i++)
2169             {
2170                 FieldDesc *pFD = GetClass()->GetFieldDescList() + ((GetNumInstanceFields()-cParentInstanceFields) + i);
2171                 if(debug) {
2172                     ssBuff.Printf(W("offset %3d %S\n"), pFD->GetOffset_NoLogging(), pFD->GetName());
2173                     WszOutputDebugString(ssBuff.GetUnicode());
2174                 }
2175                 else
2176                 {
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()));
2179                 }
2180             }
2181         }
2182
2183         if (GetNumInstanceFields() > 0)
2184         {
2185             if (GetNumStaticFields()) {
2186                 if(debug) {
2187                     WszOutputDebugString(W("\n"));
2188                 }
2189                 else
2190                 {
2191                     //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2192                     LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
2193                 }
2194             }
2195             
2196             if (debug)
2197             {
2198                 WszOutputDebugString(W("Instance fields\n"));
2199                 WszOutputDebugString(W("---------------\n"));
2200             }
2201             else
2202             {
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"));
2206             }
2207             
2208             DebugRecursivelyDumpInstanceFields(pszClassName, debug);
2209         }
2210         
2211         if (debug)
2212         {
2213             WszOutputDebugString(W("\n"));
2214         }
2215         else
2216         {
2217             //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2218             LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
2219         }
2220     }
2221     EX_CATCH
2222     {
2223         if (debug)
2224         {
2225             WszOutputDebugString(W("<Exception Thrown>\n"));
2226         }
2227         else
2228         {
2229             //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2230              LOG((LF_ALWAYS, LL_ALWAYS, "<Exception Thrown>\n"));
2231         }
2232     }
2233     EX_END_CATCH(SwallowAllExceptions);
2234 } // MethodTable::DebugDumpFieldLayout
2235
2236 //*******************************************************************************
2237 void 
2238 MethodTable::DebugDumpGCDesc(
2239     LPCUTF8 pszClassName, 
2240     BOOL    fDebug)
2241 {
2242     WRAPPER_NO_CONTRACT;   // It's a dev helper, who cares about contracts
2243     
2244     EX_TRY
2245     {
2246         StackSString ssBuff;
2247         
2248         if (fDebug)
2249         {
2250             ssBuff.Printf(W("GC description for '%S':\n\n"), pszClassName);
2251             WszOutputDebugString(ssBuff.GetUnicode());
2252         }
2253         else
2254         {
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));
2257         }
2258         
2259         if (ContainsPointersOrCollectible())
2260         {
2261             CGCDescSeries *pSeries;
2262             CGCDescSeries *pHighest;
2263             
2264             if (fDebug)
2265             {
2266                 WszOutputDebugString(W("GCDesc:\n"));
2267             } else
2268             {
2269                 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2270                 LOG((LF_ALWAYS, LL_ALWAYS, "GCDesc:\n"));
2271             }
2272             
2273             pSeries  = CGCDesc::GetCGCDescFromMT(this)->GetLowestSeries();
2274             pHighest = CGCDesc::GetCGCDescFromMT(this)->GetHighestSeries();
2275             
2276             while (pSeries <= pHighest)
2277             {
2278                 if (fDebug)
2279                 {
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());
2286                 }
2287                 else
2288                 {
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()
2295                          ));
2296                 }
2297                 pSeries++;
2298             }
2299             
2300             if (fDebug)
2301             {
2302                 WszOutputDebugString(W("\n"));
2303             } else
2304             {
2305                 //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2306                 LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
2307             }
2308         }
2309     }
2310     EX_CATCH
2311     {
2312         if (fDebug)
2313         {
2314             WszOutputDebugString(W("<Exception Thrown>\n"));
2315         }
2316         else
2317         {
2318             //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad
2319             LOG((LF_ALWAYS, LL_ALWAYS, "<Exception Thrown>\n"));
2320         }
2321     }
2322     EX_END_CATCH(SwallowAllExceptions);
2323 } // MethodTable::DebugDumpGCDesc
2324
2325 #endif // _DEBUG
2326
2327 #ifdef FEATURE_COMINTEROP 
2328 //*******************************************************************************
2329 CorClassIfaceAttr MethodTable::GetComClassInterfaceType()
2330 {
2331     CONTRACTL
2332     {
2333         THROWS;
2334         GC_TRIGGERS;
2335         MODE_ANY;
2336         PRECONDITION(!IsInterface());
2337     }
2338     CONTRACTL_END
2339
2340     // If the type is an open generic type, then it is considered ClassInterfaceType.None.
2341     if (ContainsGenericVariables())
2342         return clsIfNone;
2343
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())
2347         return clsIfNone;
2348
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))
2352         return clsIfNone;
2353
2354     return ReadClassInterfaceTypeCustomAttribute(TypeHandle(this));
2355 }
2356 #endif // FEATURE_COMINTEROP
2357
2358 //---------------------------------------------------------------------------------------
2359 // 
2360 Substitution 
2361 MethodTable::GetSubstitutionForParent(
2362     const Substitution * pSubst)
2363 {
2364     CONTRACTL
2365     {
2366         THROWS;
2367         GC_NOTRIGGER;
2368         FORBID_FAULT;
2369     }
2370     CONTRACTL_END
2371     
2372     mdToken crExtends;
2373     DWORD   dwAttrClass;
2374     
2375     if (IsArray())
2376     {
2377         return Substitution(GetModule(), SigPointer(), pSubst);
2378     }
2379     
2380     IfFailThrow(GetMDImport()->GetTypeDefProps(
2381         GetCl(), 
2382         &dwAttrClass, 
2383         &crExtends));
2384     
2385     return Substitution(crExtends, GetModule(), pSubst);
2386 } // MethodTable::GetSubstitutionForParent
2387
2388 #endif //!DACCESS_COMPILE
2389
2390
2391 //*******************************************************************************
2392 #ifdef FEATURE_PREJIT
2393 DWORD EEClass::GetSize()
2394 {
2395     CONTRACTL
2396     {
2397         NOTHROW;
2398         GC_NOTRIGGER;
2399         FORBID_FAULT;
2400     }
2401     CONTRACTL_END;
2402
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));
2410 }
2411 #endif // FEATURE_PREJIT
2412
2413 #ifndef DACCESS_COMPILE 
2414 #ifdef FEATURE_COMINTEROP 
2415
2416 //
2417 // Implementations of SparseVTableMap methods.
2418 //
2419
2420 //*******************************************************************************
2421 SparseVTableMap::SparseVTableMap()
2422 {
2423     LIMITED_METHOD_CONTRACT;
2424
2425     // Note that this will also zero out all gaps. It is important for NGen determinism.
2426     ZeroMemory(this, sizeof(*this));
2427 }
2428
2429 //*******************************************************************************
2430 SparseVTableMap::~SparseVTableMap()
2431 {
2432     LIMITED_METHOD_CONTRACT;
2433
2434     if (m_MapList != NULL)
2435     {
2436         delete [] m_MapList;
2437         m_MapList = NULL;
2438     }
2439 }
2440
2441 //*******************************************************************************
2442 // Allocate or expand the mapping list for a new entry.
2443 void SparseVTableMap::AllocOrExpand()
2444 {
2445     STANDARD_VM_CONTRACT;
2446
2447     if (m_MapEntries == m_Allocated) {
2448
2449         Entry *maplist = new Entry[m_Allocated + MapGrow];
2450
2451         if (m_MapList != NULL)
2452             memcpy(maplist, m_MapList, m_MapEntries * sizeof(Entry));
2453
2454         m_Allocated += MapGrow;
2455         delete [] m_MapList;
2456         m_MapList = maplist;
2457     }
2458 }
2459
2460 //*******************************************************************************
2461 // While building mapping list, record a gap in VTable slot numbers.
2462 void SparseVTableMap::RecordGap(WORD StartMTSlot, WORD NumSkipSlots)
2463 {
2464     STANDARD_VM_CONTRACT;
2465
2466     _ASSERTE((StartMTSlot == 0) || (StartMTSlot > m_MTSlot));
2467     _ASSERTE(NumSkipSlots > 0);
2468
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;
2475         return;
2476     }
2477
2478     // We need an entry, allocate or expand the list as necessary.
2479     AllocOrExpand();
2480
2481     // Update the list with an entry describing the last non-gap in vtable
2482     // entries.
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;
2486
2487     m_VTSlot += (StartMTSlot - m_MTSlot) + NumSkipSlots;
2488     m_MTSlot = StartMTSlot;
2489
2490     m_MapEntries++;
2491 }
2492
2493 //*******************************************************************************
2494 // Finish creation of mapping list.
2495 void SparseVTableMap::FinalizeMapping(WORD TotalMTSlots)
2496 {
2497     STANDARD_VM_CONTRACT;
2498
2499     _ASSERTE(TotalMTSlots >= m_MTSlot);
2500
2501     // If mapping ended with a gap, we have nothing else to record.
2502     if (TotalMTSlots == m_MTSlot)
2503         return;
2504
2505     // Allocate or expand the list as necessary.
2506     AllocOrExpand();
2507
2508     // Update the list with an entry describing the last non-gap in vtable
2509     // entries.
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;
2513
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;
2517
2518     m_MapEntries++;
2519 }
2520
2521 //*******************************************************************************
2522 // Lookup a VTable slot number from a method table slot number.
2523 WORD SparseVTableMap::LookupVTSlot(WORD MTSlot)
2524 {
2525     CONTRACTL
2526     {
2527         NOTHROW;
2528         GC_NOTRIGGER;
2529         FORBID_FAULT;
2530     }
2531     CONTRACTL_END
2532
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;
2537
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))) {
2542             m_LastUsed = i;
2543             return (MTSlot - m_MapList[i].m_Start) + m_MapList[i].m_MapTo;
2544         }
2545     }
2546
2547     _ASSERTE(!"Invalid MethodTable slot");
2548     return ~0;
2549 }
2550
2551 //*******************************************************************************
2552 // Retrieve the number of slots in the vtable (both empty and full).
2553 WORD SparseVTableMap::GetNumVTableSlots()
2554 {
2555     LIMITED_METHOD_CONTRACT;
2556
2557     return m_VTSlot;
2558 }
2559
2560 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
2561 //*******************************************************************************
2562 void SparseVTableMap::Save(DataImage *image)
2563 {
2564     STANDARD_VM_CONTRACT;
2565
2566     image->StoreStructure(this, sizeof(SparseVTableMap),
2567                                     DataImage::ITEM_SPARSE_VTABLE_MAP_TABLE);
2568
2569     // Trim unused portion of the table
2570     m_Allocated = m_MapEntries;
2571
2572     image->StoreInternedStructure(m_MapList, m_Allocated * sizeof(Entry),
2573                                     DataImage::ITEM_SPARSE_VTABLE_MAP_ENTRIES);
2574 }
2575
2576 //*******************************************************************************
2577 void SparseVTableMap::Fixup(DataImage *image)
2578 {
2579     STANDARD_VM_CONTRACT;
2580
2581     image->FixupPointerField(this, offsetof(SparseVTableMap, m_MapList));
2582 }
2583 #endif //FEATURE_NATIVE_IMAGE_GENERATION
2584 #endif //FEATURE_COMINTEROP
2585
2586 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
2587
2588 //*******************************************************************************
2589 void EEClass::Save(DataImage *image, MethodTable *pMT)
2590 {
2591     CONTRACTL
2592     {
2593         STANDARD_VM_CHECK;
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());
2600     }
2601     CONTRACTL_END;
2602
2603     LOG((LF_ZAP, LL_INFO10000, "EEClass::Save %s (%p)\n", m_szDebugClassName, this));
2604
2605     m_fFieldsArePacked = GetPackedFields()->PackFields();
2606
2607     DWORD cbSize = GetSize();
2608
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     // ***************************************************************
2617
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;
2625
2626     // Save optional fields if we have any.
2627     if (HasOptionalFields())
2628         image->StoreStructure(GetOptionalFields(),
2629                               sizeof(EEClassOptionalFields),
2630                               item);
2631
2632 #ifdef _DEBUG 
2633     if (!image->IsStored(m_szDebugClassName))
2634         image->StoreStructure(m_szDebugClassName, (ULONG)(strlen(m_szDebugClassName)+1),
2635                               DataImage::ITEM_DEBUG,
2636                               1);
2637 #endif // _DEBUG
2638
2639 #ifdef FEATURE_COMINTEROP 
2640     if (GetSparseCOMInteropVTableMap() != NULL)
2641         GetSparseCOMInteropVTableMap()->Save(image);
2642 #endif // FEATURE_COMINTEROP
2643
2644     //
2645     // Save MethodDescs
2646     //
2647
2648     MethodDescChunk *chunk = GetChunks();
2649     if (chunk != NULL)
2650     {
2651         MethodDesc::SaveChunk methodDescSaveChunk(image);
2652
2653         MethodTable::IntroducedMethodIterator it(pMT, TRUE);
2654         for (; it.IsValid(); it.Next())
2655         {
2656             MethodDesc * pMD = it.GetMethodDesc();
2657
2658             // Do not save IL stubs that we have failed to generate code for
2659             if (pMD->IsILStub() && image->GetCodeAddress(pMD) == NULL)
2660                 continue;
2661
2662             methodDescSaveChunk.Append(pMD);
2663         }
2664
2665         ZapStoredStructure * pChunksNode = methodDescSaveChunk.Save();
2666         if (pChunksNode != NULL)    
2667             image->BindPointer(chunk, pChunksNode, 0);
2668
2669     }
2670
2671     //
2672     // Save FieldDescs
2673     //
2674
2675     SIZE_T fieldCount = FieldDescListSize(pMT);
2676
2677     if (fieldCount != 0)
2678     {
2679         FieldDesc *pFDStart = GetFieldDescList();
2680         FieldDesc *pFDEnd = pFDStart + fieldCount;
2681
2682         FieldDesc *pFD = pFDStart;
2683         while (pFD < pFDEnd)
2684         {
2685             pFD->PrecomputeNameHash();
2686             pFD++;
2687         }
2688
2689         ZapStoredStructure * pFDNode = image->StoreStructure(pFDStart, (ULONG)(fieldCount * sizeof(FieldDesc)),
2690                                         DataImage::ITEM_FIELD_DESC_LIST);
2691
2692         pFD = pFDStart;
2693         while (pFD < pFDEnd)
2694         {
2695             pFD->SaveContents(image);
2696             if (pFD != pFDStart)
2697                 image->BindPointer(pFD, pFDNode, (BYTE *)pFD - (BYTE *)pFDStart);
2698             pFD++;
2699         }
2700     }
2701
2702     //
2703     // Save MethodDescs
2704     //
2705
2706     if (HasLayout())
2707     {
2708         EEClassLayoutInfo *pInfo = &((LayoutEEClass*)this)->m_LayoutInfo;
2709
2710         if (pInfo->m_numCTMFields > 0)
2711         {
2712             ZapStoredStructure * pNode = image->StoreStructure(pInfo->GetFieldMarshalers(),
2713                                             pInfo->m_numCTMFields * MAXFIELDMARSHALERSIZE,
2714                                             DataImage::ITEM_FIELD_MARSHALERS);
2715
2716             for (UINT iField = 0; iField < pInfo->m_numCTMFields; iField++)
2717             {
2718                 FieldMarshaler *pFM = (FieldMarshaler*)((BYTE *)pInfo->GetFieldMarshalers() + iField * MAXFIELDMARSHALERSIZE);
2719                 pFM->Save(image);
2720
2721                 if (iField > 0)
2722                     image->BindPointer(pFM, pNode, iField * MAXFIELDMARSHALERSIZE);
2723             }
2724         }
2725     }
2726
2727     // Save dictionary layout information
2728     DictionaryLayout *pDictLayout = GetDictionaryLayout();
2729     if (pMT->IsSharedByGenericInstantiations() && pDictLayout != NULL)
2730     {
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()));
2734     }
2735
2736     if (GetVarianceInfo() != NULL)
2737         image->StoreInternedStructure(GetVarianceInfo(),
2738                               pMT->GetNumGenericArgs(),
2739                               DataImage::ITEM_CLASS_VARIANCE_INFO);
2740
2741     image->StoreStructure(this, cbSize, item);
2742
2743     if (pMT->IsInterface())
2744     {
2745         // Make sure our guid is computed
2746
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
2753         {
2754             GUID dummy;
2755             if (SUCCEEDED(pMT->GetGuidNoThrow(&dummy, TRUE, FALSE)))
2756             {
2757                 GuidInfo* pGuidInfo = pMT->GetGuidInfo();
2758                 _ASSERTE(pGuidInfo != NULL);
2759
2760                 image->StoreStructure(pGuidInfo, sizeof(GuidInfo),
2761                                       DataImage::ITEM_GUID_INFO);
2762
2763 #ifdef FEATURE_COMINTEROP
2764                 if (pMT->IsLegalNonArrayWinRTType())
2765                 {
2766                     Module *pModule = pMT->GetModule();
2767                     if (pModule->CanCacheWinRTTypeByGuid(pMT))
2768                     {
2769                         pModule->CacheWinRTTypeByGuid(pMT, pGuidInfo);
2770                     }
2771                 }
2772 #endif // FEATURE_COMINTEROP
2773             }
2774             else
2775             {
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);
2779             }
2780         }
2781     }
2782
2783 #ifdef FEATURE_COMINTEROP
2784     if (IsDelegate())
2785     {
2786         DelegateEEClass *pDelegateClass = (DelegateEEClass *)this;
2787         ComPlusCallInfo *pComInfo = pDelegateClass->m_pComPlusCallInfo;
2788
2789         if (pComInfo != NULL && pComInfo->ShouldSave(image))
2790         {
2791             image->StoreStructure(pDelegateClass->m_pComPlusCallInfo,
2792                                   sizeof(ComPlusCallInfo),
2793                                   item);
2794         }
2795     }
2796 #endif // FEATURE_COMINTEROP
2797
2798     LOG((LF_ZAP, LL_INFO10000, "EEClass::Save %s (%p) complete.\n", m_szDebugClassName, this));
2799 }
2800
2801 //*******************************************************************************
2802 DWORD EEClass::FieldDescListSize(MethodTable * pMT)
2803 {
2804     LIMITED_METHOD_CONTRACT;
2805
2806     EEClass * pClass = pMT->GetClass();
2807     DWORD fieldCount = pClass->GetNumInstanceFields() + pClass->GetNumStaticFields();
2808
2809     MethodTable * pParentMT = pMT->GetParentMethodTable();
2810     if (pParentMT != NULL)
2811         fieldCount -= pParentMT->GetNumInstanceFields();
2812     return fieldCount;
2813 }
2814
2815 //*******************************************************************************
2816 void EEClass::Fixup(DataImage *image, MethodTable *pMT)
2817 {
2818     CONTRACTL
2819     {
2820         STANDARD_VM_CHECK;
2821         PRECONDITION(this == pMT->GetClass());
2822         PRECONDITION(pMT->IsCanonicalMethodTable());
2823         PRECONDITION(pMT->IsFullyLoaded());
2824         PRECONDITION(image->IsStored(this));
2825     }
2826     CONTRACTL_END;
2827
2828     LOG((LF_ZAP, LL_INFO10000, "EEClass::Fixup %s (%p)\n", GetDebugClassName(), this));
2829
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));
2834
2835 #ifdef _DEBUG 
2836     image->FixupPointerField(this, offsetof(EEClass, m_szDebugClassName));
2837 #endif
2838
2839 #ifdef FEATURE_COMINTEROP 
2840     if (GetSparseCOMInteropVTableMap() != NULL)
2841     {
2842         image->FixupPointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pSparseVTableMap));
2843         GetSparseCOMInteropVTableMap()->Fixup(image);
2844     }
2845 #endif // FEATURE_COMINTEROP
2846
2847     DictionaryLayout *pDictLayout = GetDictionaryLayout();
2848     if (pDictLayout != NULL)
2849     {
2850         pDictLayout->Fixup(image, FALSE);
2851         image->FixupPointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pDictLayout));
2852     }
2853
2854     if (HasOptionalFields())
2855         image->FixupRelativePointerField(GetOptionalFields(), offsetof(EEClassOptionalFields, m_pVarianceInfo));
2856
2857     //
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
2860     // one.
2861     //
2862     image->FixupField(this, offsetof(EEClass, m_pMethodTable), pMT, 0, IMAGE_REL_BASED_RelativePointer);
2863
2864     //
2865     // Fixup MethodDescChunk and MethodDescs
2866     //
2867     MethodDescChunk* pChunks = GetChunks();
2868
2869     if (pChunks!= NULL && image->IsStored(pChunks))
2870     {
2871         image->FixupRelativePointerField(this, offsetof(EEClass, m_pChunks));
2872
2873         MethodTable::IntroducedMethodIterator it(pMT, TRUE);
2874         for (; it.IsValid(); it.Next())
2875         {
2876             MethodDesc * pMD = it.GetMethodDesc();
2877
2878             // Skip IL stubs that were not saved into the image
2879             if (pMD->IsILStub() && !image->IsStored(pMD))
2880                 continue;
2881
2882             it.GetMethodDesc()->Fixup(image);
2883         }
2884
2885     }
2886     else
2887     {
2888         image->ZeroPointerField(this, offsetof(EEClass, m_pChunks));
2889     }
2890
2891     //
2892     // Fixup FieldDescs
2893     //
2894
2895     SIZE_T fieldCount = FieldDescListSize(pMT);
2896
2897     if (fieldCount != 0)
2898     {
2899         image->FixupRelativePointerField(this, offsetof(EEClass, m_pFieldDescList));
2900
2901         FieldDesc *pField = GetFieldDescList();
2902         FieldDesc *pFieldEnd = pField + fieldCount;
2903         while (pField < pFieldEnd)
2904         {
2905             pField->Fixup(image);
2906             pField++;
2907         }
2908     }
2909
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));
2917 #endif
2918     image->ZeroPointerField(this, offsetof(EEClass, m_pccwTemplate));
2919 #endif // FEATURE_COMINTEROP
2920
2921     if (HasLayout())
2922     {
2923         image->FixupRelativePointerField(this, offsetof(LayoutEEClass, m_LayoutInfo.m_pFieldMarshalers));
2924
2925         EEClassLayoutInfo *pInfo = &((LayoutEEClass*)this)->m_LayoutInfo;
2926
2927         FieldMarshaler *pFM = pInfo->GetFieldMarshalers();
2928         FieldMarshaler *pFMEnd = (FieldMarshaler*) ((BYTE *)pFM + pInfo->m_numCTMFields*MAXFIELDMARSHALERSIZE);
2929         while (pFM < pFMEnd)
2930         {
2931             pFM->Fixup(image);
2932             ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2933         }
2934     }
2935     else if (IsDelegate())
2936     {
2937         image->FixupRelativePointerField(this, offsetof(DelegateEEClass, m_pInvokeMethod));
2938         image->FixupRelativePointerField(this, offsetof(DelegateEEClass, m_pBeginInvokeMethod));
2939         image->FixupRelativePointerField(this, offsetof(DelegateEEClass, m_pEndInvokeMethod));
2940
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));
2946
2947 #ifdef FEATURE_COMINTEROP
2948         DelegateEEClass *pDelegateClass = (DelegateEEClass *)this;
2949         ComPlusCallInfo *pComInfo = pDelegateClass->m_pComPlusCallInfo;
2950
2951         if (image->IsStored(pComInfo))
2952         {
2953             image->FixupPointerField(this, offsetof(DelegateEEClass, m_pComPlusCallInfo));
2954             pComInfo->Fixup(image);
2955         }
2956         else
2957         {
2958             image->ZeroPointerField(this, offsetof(DelegateEEClass, m_pComPlusCallInfo));
2959         }
2960 #endif // FEATURE_COMINTEROP
2961
2962         image->FixupPointerField(this, offsetof(DelegateEEClass, m_pForwardStubMD));
2963         image->FixupPointerField(this, offsetof(DelegateEEClass, m_pReverseStubMD));
2964     }
2965
2966     //
2967     // This field must be initialized at
2968     // load time
2969     //
2970
2971     if (IsInterface() && GetGuidInfo() != NULL)
2972         image->FixupRelativePointerField(this, offsetof(EEClass, m_pGuidInfo));
2973     else
2974         image->ZeroPointerField(this, offsetof(EEClass, m_pGuidInfo));
2975
2976     LOG((LF_ZAP, LL_INFO10000, "EEClass::Fixup %s (%p) complete.\n", GetDebugClassName(), this));
2977 }
2978 #endif // FEATURE_NATIVE_IMAGE_GENERATION
2979
2980
2981 //*******************************************************************************
2982 void EEClass::AddChunk (MethodDescChunk* pNewChunk)
2983 {
2984     STATIC_CONTRACT_NOTHROW;
2985     STATIC_CONTRACT_GC_NOTRIGGER;
2986     STATIC_CONTRACT_FORBID_FAULT;
2987
2988     _ASSERTE(pNewChunk->GetNextChunk() == NULL);
2989     pNewChunk->SetNextChunk(GetChunks());
2990     SetChunks(pNewChunk);
2991 }
2992
2993 //*******************************************************************************
2994 void EEClass::AddChunkIfItHasNotBeenAdded (MethodDescChunk* pNewChunk)
2995 {
2996     STATIC_CONTRACT_NOTHROW;
2997     STATIC_CONTRACT_GC_NOTRIGGER;
2998     STATIC_CONTRACT_FORBID_FAULT;
2999
3000     // return if the chunk has been added
3001     if (pNewChunk->GetNextChunk() != NULL)
3002         return;
3003
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();
3007     if (chunk != NULL)
3008     {
3009         while (chunk->GetNextChunk() != NULL)
3010             chunk = chunk->GetNextChunk();
3011
3012         if (chunk == pNewChunk)
3013             return;
3014     }
3015
3016     pNewChunk->SetNextChunk(GetChunks());
3017     SetChunks(pNewChunk);
3018 }
3019
3020 #endif // !DACCESS_COMPILE
3021
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()
3030 {
3031     CONTRACTL
3032     {
3033         NOTHROW;
3034         GC_NOTRIGGER;
3035         FORBID_FAULT;
3036     }
3037     CONTRACTL_END
3038
3039     m_iteratorType = 0;
3040     m_pFieldDescList = NULL;
3041     m_currField = -1;
3042     m_totalFields = 0;
3043 }
3044
3045 //*******************************************************************************
3046 void ApproxFieldDescIterator::Init(MethodTable *pMT, int iteratorType)
3047 {
3048     CONTRACTL
3049     {
3050         NOTHROW;
3051         GC_NOTRIGGER;
3052         FORBID_FAULT;
3053         SUPPORTS_DAC;
3054     }
3055     CONTRACTL_END
3056
3057     m_iteratorType = iteratorType;
3058     m_pFieldDescList = pMT->GetApproxFieldDescListRaw();
3059     m_currField = -1;
3060
3061     // This gets non-EnC fields.
3062     m_totalFields = pMT->GetNumIntroducedInstanceFields();
3063
3064     if (!(iteratorType & (int)INSTANCE_FIELDS))
3065     {
3066         // if not handling instances then skip them by setting curr to last one
3067         m_currField = m_totalFields - 1;
3068     }
3069
3070     if (iteratorType & (int)STATIC_FIELDS)
3071     {
3072         m_totalFields += pMT->GetNumStaticFields();
3073     }
3074 }
3075
3076 //*******************************************************************************
3077 PTR_FieldDesc ApproxFieldDescIterator::Next()
3078 {
3079     CONTRACTL
3080     {
3081         NOTHROW;
3082         GC_NOTRIGGER;
3083         FORBID_FAULT;
3084         SUPPORTS_DAC;
3085     }
3086     CONTRACTL_END
3087
3088     // This will iterate through all non-inherited and non-EnC fields.
3089     ++m_currField;
3090     if (m_currField >= m_totalFields)
3091     {
3092         return NULL;
3093     }
3094
3095     return m_pFieldDescList + m_currField;
3096 }
3097
3098 //*******************************************************************************
3099 bool
3100 DeepFieldDescIterator::NextClass()
3101 {
3102     WRAPPER_NO_CONTRACT;
3103
3104     if (m_curClass <= 0)
3105     {
3106         return false;
3107     }
3108
3109     if (m_numClasses <= 0) {
3110         _ASSERTE(m_numClasses > 0);
3111         return false;
3112     }
3113
3114     MethodTable * pMT;
3115
3116     //
3117     // If we're in the cache just grab the cache entry.
3118     //
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.
3122     //
3123
3124     if (--m_curClass < m_numClasses)
3125     {
3126         pMT = m_classes[m_curClass];
3127     }
3128     else
3129     {
3130         pMT = m_classes[m_numClasses - 1];
3131         int depthDiff = m_curClass - m_numClasses + 1;
3132         while (depthDiff--)
3133         {
3134             pMT = pMT->GetParentMethodTable();
3135         }
3136     }
3137
3138     m_fieldIter.Init(pMT, m_fieldIter.GetIteratorType());
3139     return true;
3140 }
3141
3142 //*******************************************************************************
3143 void
3144 DeepFieldDescIterator::Init(MethodTable* pMT, int iteratorType,
3145                             bool includeParents)
3146 {
3147     WRAPPER_NO_CONTRACT;
3148
3149     MethodTable * lastClass = NULL;
3150     int numClasses;
3151
3152     //
3153     // Walk up the parent chain, collecting
3154     // parent pointers and counting fields.
3155     //
3156
3157     numClasses = 0;
3158     m_numClasses = 0;
3159     m_deepTotalFields = 0;
3160     m_lastNextFromParentClass = false;
3161
3162     while (pMT)
3163     {
3164         if (m_numClasses < (int)NumItems(m_classes))
3165         {
3166             m_classes[m_numClasses++] = pMT;
3167         }
3168
3169         if ((iteratorType & ApproxFieldDescIterator::INSTANCE_FIELDS) != 0)
3170         {
3171             m_deepTotalFields += pMT->GetNumIntroducedInstanceFields();
3172         }
3173         if ((iteratorType & ApproxFieldDescIterator::STATIC_FIELDS) != 0)
3174         {
3175             m_deepTotalFields += pMT->GetNumStaticFields();
3176         }
3177
3178         numClasses++;
3179         lastClass = pMT;
3180
3181         if (includeParents)
3182         {
3183             pMT = pMT->GetParentMethodTable();
3184         }
3185         else
3186         {
3187             break;
3188         }
3189     }
3190
3191     // Start the per-class field iterator on the base-most parent.
3192     if (numClasses)
3193     {
3194         m_curClass = numClasses - 1;
3195         m_fieldIter.Init(lastClass, iteratorType);
3196     }
3197     else
3198     {
3199         m_curClass = 0;
3200     }
3201 }
3202
3203 //*******************************************************************************
3204 FieldDesc*
3205 DeepFieldDescIterator::Next()
3206 {
3207     WRAPPER_NO_CONTRACT;
3208
3209     FieldDesc* field;
3210
3211     do
3212     {
3213         m_lastNextFromParentClass = m_curClass > 0;
3214
3215         field = m_fieldIter.Next();
3216
3217         if (!field && !NextClass())
3218         {
3219             return NULL;
3220         }
3221     }
3222     while (!field);
3223
3224     return field;
3225 }
3226
3227 //*******************************************************************************
3228 bool
3229 DeepFieldDescIterator::Skip(int numSkip)
3230 {
3231     WRAPPER_NO_CONTRACT;
3232
3233     while (numSkip >= m_fieldIter.CountRemaining())
3234     {
3235         numSkip -= m_fieldIter.CountRemaining();
3236
3237         if (!NextClass())
3238         {
3239             return false;
3240         }
3241     }
3242
3243     while (numSkip--)
3244     {
3245         m_fieldIter.Next();
3246     }
3247
3248     return true;
3249 }
3250
3251 #ifdef DACCESS_COMPILE 
3252
3253 //*******************************************************************************
3254 void
3255 EEClass::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, MethodTable * pMT)
3256 {
3257     SUPPORTS_DAC;
3258     DAC_ENUM_DTHIS();
3259     EMEM_OUT(("MEM: %p EEClass\n", dac_cast<TADDR>(this)));
3260
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));
3265
3266     if (HasOptionalFields())
3267         DacEnumMemoryRegion(dac_cast<TADDR>(GetOptionalFields()), sizeof(EEClassOptionalFields));
3268
3269     if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
3270     {
3271         PTR_Module pModule = pMT->GetModule();
3272         if (pModule.IsValid())
3273         {
3274             pModule->EnumMemoryRegions(flags, true);
3275         }
3276         PTR_MethodDescChunk chunk = GetChunks();
3277         while (chunk.IsValid())
3278         {
3279             chunk->EnumMemoryRegions(flags);
3280             chunk = chunk->GetNextChunk();
3281         }
3282     }
3283
3284     PTR_FieldDesc pFieldDescList = GetFieldDescList();
3285     if (pFieldDescList.IsValid())
3286     {
3287         // add one to make sos's code happy.
3288         DacEnumMemoryRegion(dac_cast<TADDR>(pFieldDescList),
3289                             (pMT->GetNumIntroducedInstanceFields() +
3290                              GetNumStaticFields() + 1) *
3291                             sizeof(FieldDesc));
3292     }
3293
3294 }
3295
3296 #endif // DACCESS_COMPILE
3297
3298 // Get pointer to the packed fields structure attached to this instance.
3299 PTR_EEClassPackedFields EEClass::GetPackedFields()
3300 {
3301     LIMITED_METHOD_DAC_CONTRACT;
3302
3303     return dac_cast<PTR_EEClassPackedFields>(PTR_HOST_TO_TADDR(this) + m_cbFixedEEClassFields);
3304 }
3305
3306 // Get the value of the given field. Works regardless of whether the field is currently in its packed or
3307 // unpacked state.
3308 DWORD EEClass::GetPackableField(EEClassFieldId eField)
3309 {
3310     CONTRACTL
3311     {
3312         NOTHROW;
3313         GC_NOTRIGGER;
3314         MODE_ANY;
3315         SUPPORTS_DAC;
3316     }
3317     CONTRACTL_END;
3318
3319     return m_fFieldsArePacked ?
3320         GetPackedFields()->GetPackedField(eField) :
3321         GetPackedFields()->GetUnpackedField(eField);
3322 }
3323
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
3326 // immutable).
3327 void EEClass::SetPackableField(EEClassFieldId eField, DWORD dwValue)
3328 {
3329     CONTRACTL
3330     {
3331         NOTHROW;
3332         GC_NOTRIGGER;
3333         MODE_ANY;
3334     }
3335     CONTRACTL_END;
3336
3337     _ASSERTE(!m_fFieldsArePacked);
3338     GetPackedFields()->SetUnpackedField(eField, dwValue);
3339 }
3340
3341 #ifndef DACCESS_COMPILE
3342
3343 void EEClassLayoutInfo::SetOffsetsAndSortFields(
3344     IMDInternalImport* pInternalImport,
3345     const mdTypeDef cl,
3346     LayoutRawFieldInfo* pFieldInfoArray,
3347     const ULONG cInstanceFields,
3348     const BOOL fExplicitOffsets,
3349     const UINT32 cbAdjustedParentLayoutNativeSize,
3350     Module* pModule,
3351     LayoutRawFieldInfo** pSortArrayOut
3352 )
3353 {
3354     HRESULT hr;
3355     MD_CLASS_LAYOUT classlayout;
3356     hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
3357     if (FAILED(hr))
3358     {
3359         COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
3360     }
3361
3362     LayoutRawFieldInfo* pfwalk = pFieldInfoArray;
3363     mdFieldDef fd;
3364     ULONG ulOffset;
3365     while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
3366         &classlayout,
3367         &fd,
3368         &ulOffset)) &&
3369         fd != mdFieldDefNil)
3370     {
3371         // watch for the last entry: must be mdFieldDefNil
3372         while ((mdFieldDefNil != pfwalk->m_MD) && (pfwalk->m_MD < fd))
3373             pfwalk++;
3374
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;
3377
3378         if (!fExplicitOffsets)
3379         {
3380             // ulOffset is the sequence
3381             pfwalk->m_sequence = ulOffset;
3382         }
3383         else
3384         {
3385             // ulOffset is the explicit offset
3386             pfwalk->m_nativePlacement.m_offset = ulOffset;
3387             pfwalk->m_sequence = (ULONG)-1;
3388
3389             // Treat base class as an initial member.
3390             if (!SafeAddUINT32(&(pfwalk->m_nativePlacement.m_offset), cbAdjustedParentLayoutNativeSize))
3391                 COMPlusThrowOM();
3392         }
3393     }
3394     IfFailThrow(hr);
3395
3396     LayoutRawFieldInfo** pSortArrayEnd = pSortArrayOut;
3397     // now sort the array
3398     if (!fExplicitOffsets)
3399     {
3400         // sort sequential by ascending sequence
3401         for (ULONG i = 0; i < cInstanceFields; i++)
3402         {
3403             LayoutRawFieldInfo** pSortWalk = pSortArrayEnd;
3404             while (pSortWalk != pSortArrayOut)
3405             {
3406                 if (pFieldInfoArray[i].m_sequence >= (*(pSortWalk - 1))->m_sequence)
3407                     break;
3408
3409                 pSortWalk--;
3410             }
3411
3412             // pSortWalk now points to the target location for new LayoutRawFieldInfo*.
3413             MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
3414             *pSortWalk = &pFieldInfoArray[i];
3415             pSortArrayEnd++;
3416         }
3417     }
3418     else // no sorting for explicit layout
3419     {
3420         for (ULONG i = 0; i < cInstanceFields; i++)
3421         {
3422             if (pFieldInfoArray[i].m_MD != mdFieldDefNil)
3423             {
3424                 if (pFieldInfoArray[i].m_nativePlacement.m_offset == (UINT32)-1)
3425                 {
3426                     LPCUTF8 szFieldName;
3427                     if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName)))
3428                     {
3429                         szFieldName = "Invalid FieldDef record";
3430                     }
3431                     pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
3432                         cl,
3433                         szFieldName,
3434                         IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
3435                 }
3436                 else if ((INT)pFieldInfoArray[i].m_nativePlacement.m_offset < 0)
3437                 {
3438                     LPCUTF8 szFieldName;
3439                     if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName)))
3440                     {
3441                         szFieldName = "Invalid FieldDef record";
3442                     }
3443                     pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
3444                         cl,
3445                         szFieldName,
3446                         IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
3447                 }
3448             }
3449
3450             *pSortArrayEnd = &pFieldInfoArray[i];
3451             pSortArrayEnd++;
3452         }
3453     }
3454 }
3455
3456 void EEClassLayoutInfo::CalculateSizeAndFieldOffsets(
3457     const UINT32 parentSize,
3458     ULONG numInstanceFields,
3459     BOOL fExplicitOffsets,
3460     LayoutRawFieldInfo* const* pSortedFieldInfoArray,
3461     ULONG classSizeInMetadata,
3462     BYTE packingSize,
3463     BYTE parentAlignmentRequirement,
3464     BOOL calculatingNativeLayout,
3465     EEClassLayoutInfo* pEEClassLayoutInfoOut
3466 )
3467 {
3468     UINT32 cbCurOffset = parentSize;
3469     BYTE LargestAlignmentRequirement = max(1, min(packingSize, parentAlignmentRequirement));
3470
3471     // Start with the size inherited from the parent (if any).
3472     uint32_t calcTotalSize = parentSize;
3473
3474     LayoutRawFieldInfo* const* pSortWalk;
3475     ULONG i;
3476     for (pSortWalk = pSortedFieldInfoArray, i = numInstanceFields; i; i--, pSortWalk++)
3477     {
3478         LayoutRawFieldInfo* pfwalk = *pSortWalk;
3479         RawFieldPlacementInfo* placementInfo;
3480
3481         if (calculatingNativeLayout)
3482         {
3483             placementInfo = &pfwalk->m_nativePlacement;
3484         }
3485         else
3486         {
3487             placementInfo = &pfwalk->m_managedPlacement;
3488         }
3489
3490         BYTE alignmentRequirement = placementInfo->m_alignment;
3491
3492         alignmentRequirement = min(alignmentRequirement, packingSize);
3493
3494         LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
3495
3496         switch (alignmentRequirement)
3497         {
3498         case 1:
3499         case 2:
3500         case 4:
3501         case 8:
3502         case 16:
3503         case 32:
3504             break;
3505         default:
3506             COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
3507         }
3508
3509         if (!fExplicitOffsets)
3510         {
3511             // Insert enough padding to align the current data member.
3512             while (cbCurOffset % alignmentRequirement)
3513             {
3514                 if (!SafeAddUINT32(&cbCurOffset, 1))
3515                     COMPlusThrowOM();
3516             }
3517
3518             // if we overflow we will catch it below
3519             placementInfo->m_offset = cbCurOffset;
3520             cbCurOffset += placementInfo->m_size;
3521         }
3522
3523         uint32_t fieldEnd = placementInfo->m_offset + placementInfo->m_size;
3524         if (fieldEnd < placementInfo->m_offset)
3525             COMPlusThrowOM();
3526
3527         // size of the structure is the size of the last field.  
3528         if (fieldEnd > calcTotalSize)
3529             calcTotalSize = fieldEnd;
3530     }
3531
3532     if (classSizeInMetadata != 0)
3533     {
3534         ULONG classSize = classSizeInMetadata;
3535         if (!SafeAddULONG(&classSize, (ULONG)parentSize))
3536             COMPlusThrowOM();
3537
3538         // size must be large enough to accomodate layout. If not, we use the layout size instead.
3539         calcTotalSize = max(classSize, calcTotalSize);
3540     }
3541     else
3542     {
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;
3546
3547         if (calcTotalSize % LargestAlignmentRequirement != 0)
3548         {
3549             if (!SafeAddUINT32(&calcTotalSize, LargestAlignmentRequirement - (calcTotalSize % LargestAlignmentRequirement)))
3550                 COMPlusThrowOM();
3551         }
3552     }
3553
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)
3557         COMPlusThrowOM();
3558
3559     // This is a zero-sized struct - need to record the fact and bump it up to 1.
3560     if (calcTotalSize == 0)
3561     {
3562         pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
3563         calcTotalSize = 1;
3564     }
3565
3566     // The packingSize acts as a ceiling on all individual alignment
3567     // requirements so it follows that the largest alignment requirement
3568     // is also capped.
3569     _ASSERTE(LargestAlignmentRequirement <= packingSize);
3570
3571     if (calculatingNativeLayout)
3572     {
3573         pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
3574         pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
3575     }
3576     else
3577     {
3578         pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
3579         pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
3580     }
3581 }
3582
3583 //=======================================================================
3584 // Called from the clsloader to load up and summarize the field metadata
3585 // for layout classes.
3586 //
3587 // Warning: This function can load other classes (esp. for nested structs.)
3588 //=======================================================================
3589 #ifdef _PREFAST_
3590 #pragma warning(push)
3591 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3592 #endif
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
3610 )
3611 {
3612     CONTRACTL
3613     {
3614         THROWS;
3615         GC_TRIGGERS;
3616         MODE_ANY;
3617         INJECT_FAULT(COMPlusThrowOM());
3618         PRECONDITION(CheckPointer(pModule));
3619     }
3620     CONTRACTL_END;
3621
3622     // Internal interface for the NStruct being loaded.
3623     IMDInternalImport *pInternalImport = pModule->GetMDImport();
3624
3625 #ifdef _DEBUG
3626     LPCUTF8 szName; 
3627     LPCUTF8 szNamespace; 
3628     if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
3629     {
3630         szName = szNamespace = "Invalid TypeDef record";
3631     }
3632     
3633     if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
3634         CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
3635 #endif
3636
3637     // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
3638     // function exits.
3639     BOOL fDisqualifyFromManagedSequential; 
3640
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?
3645        )
3646     {
3647         fDisqualifyFromManagedSequential = FALSE;
3648     }
3649     else
3650     {
3651         fDisqualifyFromManagedSequential = TRUE;
3652     }
3653
3654
3655     BOOL fHasNonTrivialParent = pParentMT &&
3656                                 !pParentMT->IsObjectClass() &&
3657                                 !pParentMT->IsValueTypeClass();
3658
3659
3660     // Set some defaults based on the parent type of this type (if one exists).
3661     _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
3662
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;    
3671     
3672     BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
3673     UINT32 cbAdjustedParentLayoutNativeSize = 0;
3674     EEClassLayoutInfo *pParentLayoutInfo = NULL;
3675     if (fParentHasLayout)
3676     {
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;
3686         }
3687     }
3688
3689     ULONG cInstanceFields = 0;
3690
3691     ParseNativeTypeFlags nativeTypeFlags = ParseNativeTypeFlags::None;
3692 #ifdef FEATURE_COMINTEROP
3693     if (isWinRT)
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;
3699
3700     ParseFieldNativeTypes(
3701         pInternalImport,
3702         cl,
3703         phEnumField,
3704         cTotalFields,
3705         pModule,
3706         nativeTypeFlags,
3707         pTypeContext,
3708         &fDisqualifyFromManagedSequential,
3709         pInfoArrayOut,
3710         pEEClassLayoutInfoOut,
3711         &cInstanceFields
3712         DEBUGARG(szNamespace)
3713         DEBUGARG(szName)
3714         );
3715
3716     // Now compute the native size of each field
3717     for (LayoutRawFieldInfo* pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
3718     {
3719         pfwalk->m_nativePlacement.m_size = ((FieldMarshaler*) & (pfwalk->m_FieldMarshaler))->NativeSize();
3720         pfwalk->m_nativePlacement.m_alignment = ((FieldMarshaler*) & (pfwalk->m_FieldMarshaler))->AlignmentRequirement();
3721
3722 #ifdef _DEBUG
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())
3728         {
3729             _ASSERTE(pfwalk->m_managedPlacement.m_size == pfwalk->m_nativePlacement.m_size);
3730         }
3731 #endif
3732     }
3733     
3734     S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo*));
3735     if (cbSortArraySize.IsOverflow())
3736     {
3737         ThrowHR(COR_E_TYPELOAD);
3738     }
3739     LayoutRawFieldInfo** pSortArray = (LayoutRawFieldInfo * *)_alloca(cbSortArraySize.Value());
3740     SetOffsetsAndSortFields(pInternalImport, cl, pInfoArrayOut, cInstanceFields, fExplicitOffsets, cbAdjustedParentLayoutNativeSize, pModule, pSortArray);
3741
3742     // If this type has 
3743     if (pEEClassLayoutInfoOut->m_numCTMFields)
3744     {
3745         pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
3746
3747         // Bring in the parent's fieldmarshalers
3748         if (fHasNonTrivialParent)
3749         {
3750             CONSISTENCY_CHECK(fParentHasLayout);
3751             PREFAST_ASSUME(pParentLayoutInfo != NULL);  // See if (fParentHasLayout) branch above
3752
3753             UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
3754
3755             BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
3756             BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
3757
3758             for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
3759             {
3760                 FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
3761                 FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
3762
3763                 pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
3764             }
3765         }
3766
3767     }
3768
3769     ULONG classSizeInMetadata = 0;
3770     if (FAILED(pInternalImport->GetClassTotalSize(cl, &classSizeInMetadata)))
3771     {
3772         classSizeInMetadata = 0;
3773     }
3774     else
3775     {
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);
3780     }
3781
3782     BYTE parentAlignmentRequirement = 0;
3783     if (fParentHasLayout)
3784     {
3785         parentAlignmentRequirement = pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers();
3786     }
3787
3788     CalculateSizeAndFieldOffsets(
3789         cbAdjustedParentLayoutNativeSize,
3790         cInstanceFields,
3791         fExplicitOffsets,
3792         pSortArray,
3793         classSizeInMetadata,
3794         packingSize,
3795         parentAlignmentRequirement,
3796         /*calculatingNativeLayout*/ TRUE, pEEClassLayoutInfoOut);
3797
3798     // Calculate the managedsequential layout if the type is eligible.
3799     if (!fDisqualifyFromManagedSequential)
3800     {
3801         BYTE parentManagedAlignmentRequirement = 0;
3802         UINT32 parentSize = 0;
3803         if (pParentMT && pParentMT->IsManagedSequential())
3804         {
3805             parentManagedAlignmentRequirement = pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
3806             parentSize = pParentMT->GetNumInstanceFieldBytes();
3807         }
3808
3809         CalculateSizeAndFieldOffsets(
3810             parentSize,
3811             cInstanceFields,
3812             /* fExplicitOffsets */ FALSE,
3813             pSortArray,
3814             classSizeInMetadata,
3815             packingSize,
3816             parentManagedAlignmentRequirement,
3817             /*calculatingNativeLayout*/ FALSE,
3818             pEEClassLayoutInfoOut);
3819
3820 #ifdef _DEBUG
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
3824         // case.
3825         if (pEEClassLayoutInfoOut->IsBlittable())
3826         {
3827             _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
3828             _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
3829         }
3830 #endif
3831     }
3832
3833     pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
3834
3835 #ifdef _DEBUG
3836     {
3837         BOOL illegalMarshaler = FALSE;
3838         
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++)
3845         {
3846             LPCUTF8 fieldname;
3847             if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
3848             {
3849                 fieldname = "??";
3850             }
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"));
3854
3855             if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
3856                 illegalMarshaler = TRUE;             
3857         }
3858
3859         // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
3860         if (fHasNonTrivialParent)
3861         {
3862             FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
3863             for (UINT i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
3864             {
3865                 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
3866                     illegalMarshaler = TRUE;                                 
3867                 ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
3868             }
3869         }
3870         
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));
3873     }
3874 #endif
3875     return;
3876 }
3877 #ifdef _PREFAST_
3878 #pragma warning(pop)
3879 #endif // _PREFAST_
3880
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,
3888     const mdTypeDef cl,
3889     HENUMInternal* phEnumField,
3890     const ULONG cTotalFields,
3891     Module* pModule,
3892     ParseNativeTypeFlags nativeTypeFlags,
3893     const SigTypeContext* pTypeContext,
3894     BOOL* fDisqualifyFromManagedSequential,
3895     LayoutRawFieldInfo* pFieldInfoArrayOut,
3896     EEClassLayoutInfo* pEEClassLayoutInfoOut,
3897     ULONG* cInstanceFields
3898 #ifdef _DEBUG
3899     ,
3900     LPCUTF8 szNamespace,
3901     LPCUTF8 szName
3902 #endif
3903 )
3904 {
3905     HRESULT hr;
3906     mdFieldDef fd;
3907     ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
3908
3909     ULONG i;
3910     for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
3911     {
3912         DWORD dwFieldAttrs;
3913         ULONG rid = RidFromToken(fd);
3914
3915         if ((rid == 0) || (rid > maxRid))
3916         {
3917             COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
3918         }
3919
3920         IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
3921
3922         PCCOR_SIGNATURE pNativeType = NULL;
3923         ULONG cbNativeType;
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))
3927         {
3928             PCCOR_SIGNATURE pCOMSignature;
3929             ULONG       cbCOMSignature;
3930
3931             if (IsFdHasFieldMarshal(dwFieldAttrs))
3932             {
3933                 hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
3934                 if (FAILED(hr))
3935                 {
3936                     cbNativeType = 0;
3937                 }
3938             }
3939             else
3940             {
3941                 cbNativeType = 0;
3942             }
3943
3944             IfFailThrow(pInternalImport->GetSigOfFieldDef(fd, &cbCOMSignature, &pCOMSignature));
3945
3946             IfFailThrow(::validateTokenSig(fd, pCOMSignature, cbCOMSignature, dwFieldAttrs, pInternalImport));
3947
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;
3952
3953 #ifdef _DEBUG
3954             LPCUTF8 szFieldName;
3955             if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
3956             {
3957                 szFieldName = "Invalid FieldDef record";
3958             }
3959 #endif
3960
3961             ParseNativeType(pModule,
3962                 pCOMSignature,
3963                 cbCOMSignature,
3964                 nativeTypeFlags,
3965                 pFieldInfoArrayOut,
3966                 pNativeType,
3967                 cbNativeType,
3968                 cl,
3969                 pTypeContext,
3970                 fDisqualifyFromManagedSequential
3971 #ifdef _DEBUG
3972                 ,
3973                 szNamespace,
3974                 szName,
3975                 szFieldName
3976 #endif
3977             );
3978
3979             if (!IsFieldBlittable((FieldMarshaler*)(&pFieldInfoArrayOut->m_FieldMarshaler)))
3980                 pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
3981
3982             (*cInstanceFields)++;
3983             pFieldInfoArrayOut++;
3984         }
3985     }
3986
3987     _ASSERTE(i == cTotalFields);
3988
3989     // Set the number of fields here.
3990     pEEClassLayoutInfoOut->m_numCTMFields += *cInstanceFields;
3991     // NULL out the last entry
3992     pFieldInfoArrayOut->m_MD = mdFieldDefNil;
3993
3994 }
3995 #endif // DACCESS_COMPILE