Split the phases of EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing (dotnet...
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Thu, 16 May 2019 17:39:33 +0000 (10:39 -0700)
committerGitHub <noreply@github.com>
Thu, 16 May 2019 17:39:33 +0000 (10:39 -0700)
* Split the phases of EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing into separate private static functions.

* Combine native and managed-sequential field offset and size calculations (since they are the exact same algorithm)

* Remove TypeLayoutHelper because it's was only used in CalculateSizeAndFieldOffsets after having combined the offset/size calculations.

* Remove unused members in LayoutRawFieldInfo.

* Comment boolean parameter.

* Add comments to parameters.

* Remove unused prototypes.

* Make sure we consistently use managed in the managed paths and native in the native paths.

* Add to m_numCTMFields instead of setting it (need to make sure we account for fields in a non-trivial parent).

* Track native alignment in a field.

* Refactor field placement info to remove lots of repeated branching.

* PR Feedback.

Commit migrated from https://github.com/dotnet/coreclr/commit/5885379686cd854361735a09907d654e80f44f05

src/coreclr/src/vm/class.cpp
src/coreclr/src/vm/class.h
src/coreclr/src/vm/fieldmarshaler.cpp
src/coreclr/src/vm/fieldmarshaler.h
src/coreclr/src/vm/methodtablebuilder.cpp

index fe765b0..abc1230 100644 (file)
@@ -3336,6 +3336,246 @@ void EEClass::SetPackableField(EEClassFieldId eField, DWORD dwValue)
 
 #ifndef DACCESS_COMPILE
 
+void EEClassLayoutInfo::SetOffsetsAndSortFields(
+    IMDInternalImport* pInternalImport,
+    const mdTypeDef cl,
+    LayoutRawFieldInfo* pFieldInfoArray,
+    const ULONG cInstanceFields,
+    const BOOL fExplicitOffsets,
+    const UINT32 cbAdjustedParentLayoutNativeSize,
+    Module* pModule,
+    LayoutRawFieldInfo** pSortArrayOut
+)
+{
+    HRESULT hr;
+    MD_CLASS_LAYOUT classlayout;
+    hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
+    if (FAILED(hr))
+    {
+        COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
+    }
+
+    LayoutRawFieldInfo* pfwalk = pFieldInfoArray;
+    mdFieldDef fd;
+    ULONG ulOffset;
+    while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
+        &classlayout,
+        &fd,
+        &ulOffset)) &&
+        fd != mdFieldDefNil)
+    {
+        // watch for the last entry: must be mdFieldDefNil
+        while ((mdFieldDefNil != pfwalk->m_MD) && (pfwalk->m_MD < fd))
+            pfwalk++;
+
+        // if we haven't found a matching token, it must be a static field with layout -- ignore it
+        if (pfwalk->m_MD != fd) continue;
+
+        if (!fExplicitOffsets)
+        {
+            // ulOffset is the sequence
+            pfwalk->m_sequence = ulOffset;
+        }
+        else
+        {
+            // ulOffset is the explicit offset
+            pfwalk->m_nativePlacement.m_offset = ulOffset;
+            pfwalk->m_sequence = (ULONG)-1;
+
+            // Treat base class as an initial member.
+            if (!SafeAddUINT32(&(pfwalk->m_nativePlacement.m_offset), cbAdjustedParentLayoutNativeSize))
+                COMPlusThrowOM();
+        }
+    }
+    IfFailThrow(hr);
+
+    LayoutRawFieldInfo** pSortArrayEnd = pSortArrayOut;
+    // now sort the array
+    if (!fExplicitOffsets)
+    {
+        // sort sequential by ascending sequence
+        for (ULONG i = 0; i < cInstanceFields; i++)
+        {
+            LayoutRawFieldInfo** pSortWalk = pSortArrayEnd;
+            while (pSortWalk != pSortArrayOut)
+            {
+                if (pFieldInfoArray[i].m_sequence >= (*(pSortWalk - 1))->m_sequence)
+                    break;
+
+                pSortWalk--;
+            }
+
+            // pSortWalk now points to the target location for new LayoutRawFieldInfo*.
+            MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
+            *pSortWalk = &pFieldInfoArray[i];
+            pSortArrayEnd++;
+        }
+    }
+    else // no sorting for explicit layout
+    {
+        for (ULONG i = 0; i < cInstanceFields; i++)
+        {
+            if (pFieldInfoArray[i].m_MD != mdFieldDefNil)
+            {
+                if (pFieldInfoArray[i].m_nativePlacement.m_offset == (UINT32)-1)
+                {
+                    LPCUTF8 szFieldName;
+                    if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName)))
+                    {
+                        szFieldName = "Invalid FieldDef record";
+                    }
+                    pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
+                        cl,
+                        szFieldName,
+                        IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
+                }
+                else if ((INT)pFieldInfoArray[i].m_nativePlacement.m_offset < 0)
+                {
+                    LPCUTF8 szFieldName;
+                    if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName)))
+                    {
+                        szFieldName = "Invalid FieldDef record";
+                    }
+                    pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
+                        cl,
+                        szFieldName,
+                        IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
+                }
+            }
+
+            *pSortArrayEnd = &pFieldInfoArray[i];
+            pSortArrayEnd++;
+        }
+    }
+}
+
+void EEClassLayoutInfo::CalculateSizeAndFieldOffsets(
+    const UINT32 parentSize,
+    ULONG numInstanceFields,
+    BOOL fExplicitOffsets,
+    LayoutRawFieldInfo* const* pSortedFieldInfoArray,
+    ULONG classSizeInMetadata,
+    BYTE packingSize,
+    BYTE parentAlignmentRequirement,
+    BOOL calculatingNativeLayout,
+    EEClassLayoutInfo* pEEClassLayoutInfoOut
+)
+{
+    UINT32 cbCurOffset = parentSize;
+    BYTE LargestAlignmentRequirement = max(1, min(packingSize, parentAlignmentRequirement));
+
+    // Start with the size inherited from the parent (if any).
+    uint32_t calcTotalSize = parentSize;
+
+    LayoutRawFieldInfo* const* pSortWalk;
+    ULONG i;
+    for (pSortWalk = pSortedFieldInfoArray, i = numInstanceFields; i; i--, pSortWalk++)
+    {
+        LayoutRawFieldInfo* pfwalk = *pSortWalk;
+        RawFieldPlacementInfo* placementInfo;
+
+        if (calculatingNativeLayout)
+        {
+            placementInfo = &pfwalk->m_nativePlacement;
+        }
+        else
+        {
+            placementInfo = &pfwalk->m_managedPlacement;
+        }
+
+        BYTE alignmentRequirement = placementInfo->m_alignment;
+
+        alignmentRequirement = min(alignmentRequirement, packingSize);
+
+        LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
+
+        switch (alignmentRequirement)
+        {
+        case 1:
+        case 2:
+        case 4:
+        case 8:
+        case 16:
+        case 32:
+            break;
+        default:
+            COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
+        }
+
+        if (!fExplicitOffsets)
+        {
+            // Insert enough padding to align the current data member.
+            while (cbCurOffset % alignmentRequirement)
+            {
+                if (!SafeAddUINT32(&cbCurOffset, 1))
+                    COMPlusThrowOM();
+            }
+
+            // if we overflow we will catch it below
+            placementInfo->m_offset = cbCurOffset;
+            cbCurOffset += placementInfo->m_size;
+        }
+
+        uint32_t fieldEnd = placementInfo->m_offset + placementInfo->m_size;
+        if (fieldEnd < placementInfo->m_offset)
+            COMPlusThrowOM();
+
+        // size of the structure is the size of the last field.  
+        if (fieldEnd > calcTotalSize)
+            calcTotalSize = fieldEnd;
+    }
+
+    if (classSizeInMetadata != 0)
+    {
+        ULONG classSize = classSizeInMetadata;
+        if (!SafeAddULONG(&classSize, (ULONG)parentSize))
+            COMPlusThrowOM();
+
+        // size must be large enough to accomodate layout. If not, we use the layout size instead.
+        calcTotalSize = max(classSize, calcTotalSize);
+    }
+    else
+    {
+        // There was no class size given in metadata, so let's round up to a multiple of the alignment requirement
+        // to make array allocations of this structure simple to keep aligned.
+        calcTotalSize += (LargestAlignmentRequirement - calcTotalSize % LargestAlignmentRequirement) % LargestAlignmentRequirement;
+
+        if (calcTotalSize % LargestAlignmentRequirement != 0)
+        {
+            if (!SafeAddUINT32(&calcTotalSize, LargestAlignmentRequirement - (calcTotalSize % LargestAlignmentRequirement)))
+                COMPlusThrowOM();
+        }
+    }
+
+    // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
+    // that we don't expose some overflow bug later on.
+    if (calcTotalSize >= MAX_SIZE_FOR_INTEROP && calculatingNativeLayout)
+        COMPlusThrowOM();
+
+    // This is a zero-sized struct - need to record the fact and bump it up to 1.
+    if (calcTotalSize == 0)
+    {
+        pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
+        calcTotalSize = 1;
+    }
+
+    // The packingSize acts as a ceiling on all individual alignment
+    // requirements so it follows that the largest alignment requirement
+    // is also capped.
+    _ASSERTE(LargestAlignmentRequirement <= packingSize);
+
+    if (calculatingNativeLayout)
+    {
+        pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
+        pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
+    }
+    else
+    {
+        pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
+        pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
+    }
+}
+
 //=======================================================================
 // Called from the clsloader to load up and summarize the field metadata
 // for layout classes.
@@ -3375,7 +3615,6 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
     }
     CONTRACTL_END;
 
-    HRESULT hr;
     // Internal interface for the NStruct being loaded.
     IMDInternalImport *pInternalImport = pModule->GetMDImport();
 
@@ -3414,18 +3653,9 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
                                 !pParentMT->IsValueTypeClass();
 
 
-    //====================================================================
-    // First, some validation checks.
-    //====================================================================
+    // Set some defaults based on the parent type of this type (if one exists).
     _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
 
-    MD_CLASS_LAYOUT classlayout;
-    hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
-    if (FAILED(hr))
-    {
-        COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
-    }
-
     pEEClassLayoutInfoOut->m_numCTMFields        = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0;
     pEEClassLayoutInfoOut->SetFieldMarshalers(NULL);
     pEEClassLayoutInfoOut->SetIsBlittable(TRUE);
@@ -3433,28 +3663,11 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
         pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable());
     pEEClassLayoutInfoOut->SetIsZeroSized(FALSE);    
     pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE);
-    pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;
-
-    LayoutRawFieldInfo *pfwalk = pInfoArrayOut;
-    
-    S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo *));
-    if (cbSortArraySize.IsOverflow())
-    {
-        ThrowHR(COR_E_TYPELOAD);
-    }
-    LayoutRawFieldInfo **pSortArray = (LayoutRawFieldInfo **)_alloca(cbSortArraySize.Value());
-    LayoutRawFieldInfo **pSortArrayEnd = pSortArray;
-    
-    ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
+    pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;    
     
-    
-    //=====================================================================
-    // Phase 1: Figure out the NFT of each field based on both the CLR
-    // signature of the field and the FieldMarshaler metadata. 
-    //=====================================================================
     BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
     UINT32 cbAdjustedParentLayoutNativeSize = 0;
-    EEClassLayoutInfo *pParentLayoutInfo = NULL;;
+    EEClassLayoutInfo *pParentLayoutInfo = NULL;
     if (fParentHasLayout)
     {
         pParentLayoutInfo = pParentMT->GetLayoutInfo();
@@ -3469,208 +3682,60 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
         }
     }
 
-    mdFieldDef fd;
-    ULONG i;
     ULONG cInstanceFields = 0;
-    for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
-    {
-        DWORD dwFieldAttrs;
-        ULONG rid = RidFromToken(fd);
-
-        if((rid == 0)||(rid > maxRid))
-        {
-            COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
-        }
-
-        IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
-        
-        PCCOR_SIGNATURE pNativeType = NULL;
-        ULONG cbNativeType;
-        // We ignore marshaling data attached to statics and literals,
-        // since these do not contribute to instance data.
-        if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
-        {
-            PCCOR_SIGNATURE pCOMSignature;
-            ULONG       cbCOMSignature;
 
-            if (IsFdHasFieldMarshal(dwFieldAttrs))
-            {
-                hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
-                if (FAILED(hr))
-                    cbNativeType = 0;
-            }
-            else
-                cbNativeType = 0;
-            
-            IfFailThrow(pInternalImport->GetSigOfFieldDef(fd,&cbCOMSignature, &pCOMSignature));
-            
-            IfFailThrow(::validateTokenSig(fd,pCOMSignature,cbCOMSignature,dwFieldAttrs,pInternalImport));
-            
-            // fill the appropriate entry in pInfoArrayOut
-            pfwalk->m_MD = fd;
-            pfwalk->m_offset = (UINT32) -1;
-            pfwalk->m_sequence = 0;
-
-#ifdef _DEBUG
-            LPCUTF8 szFieldName;
-            if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
-            {
-                szFieldName = "Invalid FieldDef record";
-            }
-#endif
-
-            ParseNativeTypeFlags flags = ParseNativeTypeFlags::None;
+    ParseNativeTypeFlags nativeTypeFlags = ParseNativeTypeFlags::None;
 #ifdef FEATURE_COMINTEROP
-            if (isWinRT)
-                flags = ParseNativeTypeFlags::IsWinRT;
-            else // WinRT types have nlType == nltAnsi but should be treated as Unicode
+    if (isWinRT)
+        nativeTypeFlags = ParseNativeTypeFlags::IsWinRT;
+    else // WinRT types have nlType == nltAnsi but should be treated as Unicode
 #endif // FEATURE_COMINTEROP
-            if (nlType == nltAnsi)
-                flags =  ParseNativeTypeFlags::IsAnsi;
-
-            ParseNativeType(pModule,
-                            pCOMSignature,
-                            cbCOMSignature,
-                            flags,
-                            pfwalk,
-                            pNativeType,
-                            cbNativeType,
-                            pInternalImport,
-                            cl,
-                            pTypeContext,
-                            &fDisqualifyFromManagedSequential
-#ifdef _DEBUG
-                            ,
-                            szNamespace,
-                            szName,
-                            szFieldName
-#endif
-                                );
-
-            if (!IsFieldBlittable((FieldMarshaler*)(&pfwalk->m_FieldMarshaler)))
-                pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
-
-            cInstanceFields++;
-            pfwalk++;
-        }
-    }
-
-    _ASSERTE(i == cTotalFields);
+        if (nlType == nltAnsi)
+            nativeTypeFlags = ParseNativeTypeFlags::IsAnsi;
+
+    ParseFieldNativeTypes(
+        pInternalImport,
+        cl,
+        phEnumField,
+        cTotalFields,
+        pModule,
+        nativeTypeFlags,
+        pTypeContext,
+        &fDisqualifyFromManagedSequential,
+        pInfoArrayOut,
+        pEEClassLayoutInfoOut,
+        &cInstanceFields
+        DEBUGARG(szNamespace)
+        DEBUGARG(szName)
+        );
 
-    // NULL out the last entry
-    pfwalk->m_MD = mdFieldDefNil;
-    
-    
-    //
-    // fill in the layout information 
-    //
-    
-    // pfwalk points to the beginging of the array
-    pfwalk = pInfoArrayOut;
-
-    ULONG ulOffset;
-    while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
-                                     &classlayout,
-                                     &fd,
-                                     &ulOffset)) &&
-                                     fd != mdFieldDefNil)
+    // Now compute the native size of each field
+    for (LayoutRawFieldInfo* pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
     {
-        // watch for the last entry: must be mdFieldDefNil
-        while ((mdFieldDefNil != pfwalk->m_MD)&&(pfwalk->m_MD < fd))
-            pfwalk++;
-
-        // if we haven't found a matching token, it must be a static field with layout -- ignore it
-        if(pfwalk->m_MD != fd) continue;
-
-        if (!fExplicitOffsets)
-        {
-            // ulOffset is the sequence
-            pfwalk->m_sequence = ulOffset;
-        }
-        else
-        {
-            // ulOffset is the explicit offset
-            pfwalk->m_offset = ulOffset;
-            pfwalk->m_sequence = (ULONG) -1;
+        pfwalk->m_nativePlacement.m_size = ((FieldMarshaler*) & (pfwalk->m_FieldMarshaler))->NativeSize();
+        pfwalk->m_nativePlacement.m_alignment = ((FieldMarshaler*) & (pfwalk->m_FieldMarshaler))->AlignmentRequirement();
 
-            // Treat base class as an initial member.
-            if (!SafeAddUINT32(&(pfwalk->m_offset), cbAdjustedParentLayoutNativeSize))
-                COMPlusThrowOM();
-        }
-    }
-    IfFailThrow(hr);
-
-    // now sort the array
-    if (!fExplicitOffsets)
-    { 
-        // sort sequential by ascending sequence
-        for (i = 0; i < cInstanceFields; i++)
-        {
-            LayoutRawFieldInfo**pSortWalk = pSortArrayEnd;
-            while (pSortWalk != pSortArray)
-            {
-                if (pInfoArrayOut[i].m_sequence >= (*(pSortWalk-1))->m_sequence)
-                    break;
-
-                pSortWalk--;
-            }
-
-            // pSortWalk now points to the target location for new FieldInfo.
-            MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
-            *pSortWalk = &pInfoArrayOut[i];
-            pSortArrayEnd++;
-        }
-    }
-    else // no sorting for explicit layout
-    {
-        for (i = 0; i < cInstanceFields; i++)
+#ifdef _DEBUG
+        // @perf: If the type is blittable, the managed and native layouts have to be identical
+        // so they really shouldn't be calculated twice. Until this code has been well tested and
+        // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
+        // case. The managed size is only calculated in the managed-sequential case.
+        if (!fDisqualifyFromManagedSequential && pEEClassLayoutInfoOut->IsBlittable())
         {
-            if(pInfoArrayOut[i].m_MD != mdFieldDefNil)
-            {
-                if (pInfoArrayOut[i].m_offset == (UINT32)-1)
-                {
-                    LPCUTF8 szFieldName;
-                    if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
-                    {
-                        szFieldName = "Invalid FieldDef record";
-                    }
-                    pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, 
-                                                                   cl,
-                                                                   szFieldName,
-                                                                   IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
-                }
-                else if ((INT)pInfoArrayOut[i].m_offset < 0)
-                {
-                    LPCUTF8 szFieldName;
-                    if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
-                    {
-                        szFieldName = "Invalid FieldDef record";
-                    }
-                    pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, 
-                                                                   cl,
-                                                                   szFieldName,
-                                                                   IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
-                }
-            }
-                
-            *pSortArrayEnd = &pInfoArrayOut[i];
-            pSortArrayEnd++;
+            _ASSERTE(pfwalk->m_managedPlacement.m_size == pfwalk->m_nativePlacement.m_size);
         }
+#endif
     }
-
-    //=====================================================================
-    // Phase 2: Compute the native size (in bytes) of each field.
-    // Store this in pInfoArrayOut[].cbNativeSize;
-    //=====================================================================
-
-    // Now compute the native size of each field
-    for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
+    
+    S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo*));
+    if (cbSortArraySize.IsOverflow())
     {
-        pEEClassLayoutInfoOut->m_numCTMFields++;
-
-        pfwalk->m_cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize();
+        ThrowHR(COR_E_TYPELOAD);
     }
+    LayoutRawFieldInfo** pSortArray = (LayoutRawFieldInfo * *)_alloca(cbSortArraySize.Value());
+    SetOffsetsAndSortFields(pInternalImport, cl, pInfoArrayOut, cInstanceFields, fExplicitOffsets, cbAdjustedParentLayoutNativeSize, pModule, pSortArray);
 
+    // If this type has 
     if (pEEClassLayoutInfoOut->m_numCTMFields)
     {
         pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
@@ -3697,293 +3762,62 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
 
     }
 
-
-    //=====================================================================
-    // Phase 3: If FieldMarshaler requires autooffsetting, compute the offset
-    // of each field and the size of the total structure. We do the layout
-    // according to standard VC layout rules:
-    //
-    //   Each field has an alignment requirement. The alignment-requirement
-    //   of a scalar field is the smaller of its size and the declared packsize.
-    //   The alignment-requirement of a struct field is the smaller of the
-    //   declared packsize and the largest of the alignment-requirement
-    //   of its fields. The alignment requirement of an array is that
-    //   of one of its elements.
-    //
-    //   In addition, each struct gets padding at the end to ensure
-    //   that an array of such structs contain no unused space between
-    //   elements.
-    //=====================================================================
+    ULONG classSizeInMetadata = 0;
+    if (FAILED(pInternalImport->GetClassTotalSize(cl, &classSizeInMetadata)))
     {
-        BYTE   LargestAlignmentRequirement = 1;
-        UINT32 cbCurOffset = 0;
-
-        // Treat base class as an initial member.
-        if (!SafeAddUINT32(&cbCurOffset, cbAdjustedParentLayoutNativeSize))
-            COMPlusThrowOM();
-
-        if (fParentHasLayout)
-        {
-            BYTE alignmentRequirement;
-            
-            alignmentRequirement = min(packingSize, pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers());
-    
-            LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);                                          
-        }
-
-        // Start with the size inherited from the parent (if any).
-        unsigned calcTotalSize = cbAdjustedParentLayoutNativeSize;
-     
-        LayoutRawFieldInfo **pSortWalk;
-        for (pSortWalk = pSortArray, i=cInstanceFields; i; i--, pSortWalk++)
-        {
-            pfwalk = *pSortWalk;
-    
-            BYTE alignmentRequirement = static_cast<BYTE>(((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->AlignmentRequirement());
-            if (!(alignmentRequirement == 1 ||
-                     alignmentRequirement == 2 ||
-                     alignmentRequirement == 4 ||
-                  alignmentRequirement == 8 ||
-                  alignmentRequirement == 16 ||
-                  alignmentRequirement == 32))
-            {
-                COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
-            }
-    
-            alignmentRequirement = min(alignmentRequirement, packingSize);
-    
-            LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
-    
-            // This assert means I forgot to special-case some NFT in the
-            // above switch.
-            _ASSERTE(alignmentRequirement <= 32);
-    
-            // Check if this field is overlapped with other(s)
-            pfwalk->m_fIsOverlapped = FALSE;
-            if (fExplicitOffsets) {
-                LayoutRawFieldInfo *pfwalk1;
-                DWORD dwBegin = pfwalk->m_offset;
-                DWORD dwEnd = dwBegin+pfwalk->m_cbNativeSize;
-                for (pfwalk1 = pInfoArrayOut; pfwalk1 < pfwalk; pfwalk1++)
-                {
-                    if((pfwalk1->m_offset >= dwEnd) || (pfwalk1->m_offset+pfwalk1->m_cbNativeSize <= dwBegin)) continue;
-                    pfwalk->m_fIsOverlapped = TRUE;
-                    pfwalk1->m_fIsOverlapped = TRUE;
-                }
-            }
-            else
-            {
-                // Insert enough padding to align the current data member.
-                while (cbCurOffset % alignmentRequirement)
-                {
-                    if (!SafeAddUINT32(&cbCurOffset, 1))
-                        COMPlusThrowOM();
-                }
-    
-                // Insert current data member.
-                pfwalk->m_offset = cbCurOffset;
-    
-                // if we overflow we will catch it below
-                cbCurOffset += pfwalk->m_cbNativeSize;
-            } 
-    
-            unsigned fieldEnd = pfwalk->m_offset + pfwalk->m_cbNativeSize;
-            if (fieldEnd < pfwalk->m_offset)
-                COMPlusThrowOM();
-    
-                // size of the structure is the size of the last field.  
-            if (fieldEnd > calcTotalSize)
-                calcTotalSize = fieldEnd;
-        }
-    
-        ULONG clstotalsize = 0;
-        if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
-        {
-            clstotalsize = 0;
-        }
-        
-        if (clstotalsize != 0)
-        {
-            if (!SafeAddULONG(&clstotalsize, (ULONG)cbAdjustedParentLayoutNativeSize))
-                COMPlusThrowOM();
-    
-            // size must be large enough to accomodate layout. If not, we use the layout size instead.
-            if (clstotalsize < calcTotalSize)
-            {
-                clstotalsize = calcTotalSize;
-            }
-            calcTotalSize = clstotalsize;   // use the size they told us 
-        } 
-        else
-        {
-            // The did not give us an explict size, so lets round up to a good size (for arrays) 
-            while (calcTotalSize % LargestAlignmentRequirement != 0)
-            {
-                if (!SafeAddUINT32(&calcTotalSize, 1))
-                    COMPlusThrowOM();
-            }
-        }
-        
-        // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
-        // that we don't expose some overflow bug later on.
-        if (calcTotalSize >= MAX_SIZE_FOR_INTEROP)
-            COMPlusThrowOM();
-
-        // This is a zero-sized struct - need to record the fact and bump it up to 1.
-        if (calcTotalSize == 0)
-        {
-            pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
-            calcTotalSize = 1;
-        }
-    
-        pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
-    
-        // The packingSize acts as a ceiling on all individual alignment
-        // requirements so it follows that the largest alignment requirement
-        // is also capped.
-        _ASSERTE(LargestAlignmentRequirement <= packingSize);
-        pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
+        classSizeInMetadata = 0;
     }
 
+    BYTE parentAlignmentRequirement = 0;
+    if (fParentHasLayout)
+    {
+        parentAlignmentRequirement = pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers();
+    }
 
+    CalculateSizeAndFieldOffsets(
+        cbAdjustedParentLayoutNativeSize,
+        cInstanceFields,
+        fExplicitOffsets,
+        pSortArray,
+        classSizeInMetadata,
+        packingSize,
+        parentAlignmentRequirement,
+        /*calculatingNativeLayout*/ TRUE, pEEClassLayoutInfoOut);
 
-    //=====================================================================
-    // Phase 4: Now we do the same thing again for managedsequential layout.
-    //=====================================================================
+    // Calculate the managedsequential layout if the type is eligible.
     if (!fDisqualifyFromManagedSequential)
     {
-        BYTE   LargestAlignmentRequirement = 1;
-        UINT32 cbCurOffset = 0;
-    
+        BYTE parentManagedAlignmentRequirement = 0;
+        UINT32 parentSize = 0;
         if (pParentMT && pParentMT->IsManagedSequential())
         {
-            // Treat base class as an initial member.
-            if (!SafeAddUINT32(&cbCurOffset, pParentMT->GetNumInstanceFieldBytes()))
-                COMPlusThrowOM();
-    
-            BYTE alignmentRequirement = 0;
-                
-            alignmentRequirement = min(packingSize, pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers);
-    
-            LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);                                          
+            parentManagedAlignmentRequirement = pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
+            parentSize = pParentMT->GetNumInstanceFieldBytes();
         }
-    
-        // The current size of the structure as a whole, we start at 1, because we disallow 0 sized structures.
-        // NOTE: We do not need to do the same checking for zero-sized types as phase 3 because only ValueTypes
-        //       can be ManagedSequential and ValueTypes can not be inherited from.
-        unsigned calcTotalSize = 1;
-     
-        LayoutRawFieldInfo **pSortWalk;
-        for (pSortWalk = pSortArray, i=cInstanceFields; i; i--, pSortWalk++)
-        {
-            pfwalk = *pSortWalk;
-    
-            BYTE alignmentRequirement = ((BYTE)(pfwalk->m_managedAlignmentReq));
-            if (!(alignmentRequirement == 1 ||
-                     alignmentRequirement == 2 ||
-                     alignmentRequirement == 4 ||
-                  alignmentRequirement == 8 ||
-                  alignmentRequirement == 16 ||
-                  alignmentRequirement == 32))
-            {
-                COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
-            }
-            
-            alignmentRequirement = min(alignmentRequirement, packingSize);
-            
-            LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
-            
-            _ASSERTE(alignmentRequirement <= 32);
-            
-            // Insert enough padding to align the current data member.
-            while (cbCurOffset % alignmentRequirement)
-            {
-                if (!SafeAddUINT32(&cbCurOffset, 1))
-                    COMPlusThrowOM();
-            }
-            
-            // Insert current data member.
-            pfwalk->m_managedOffset = cbCurOffset;
-            
-            // if we overflow we will catch it below
-            cbCurOffset += pfwalk->m_managedSize;
-            
-            unsigned fieldEnd = pfwalk->m_managedOffset + pfwalk->m_managedSize;
-            if (fieldEnd < pfwalk->m_managedOffset)
-                COMPlusThrowOM();
-            
-                // size of the structure is the size of the last field.  
-            if (fieldEnd > calcTotalSize)
-                calcTotalSize = fieldEnd;
-            
-#ifdef _DEBUG
-            // @perf: If the type is blittable, the managed and native layouts have to be identical
-            // so they really shouldn't be calculated twice. Until this code has been well tested and
-            // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
-            // case.
-            if (pEEClassLayoutInfoOut->IsBlittable())
-            {
-                _ASSERTE(pfwalk->m_managedOffset == pfwalk->m_offset);
-                _ASSERTE(pfwalk->m_managedSize   == pfwalk->m_cbNativeSize);
-            }
-#endif
-        } //for
-        
-        ULONG clstotalsize = 0;
-        if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
-        {
-            clstotalsize = 0;
-        }
-        
-        if (clstotalsize != 0)
-        {
-            pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE);
-            
-            if (pParentMT && pParentMT->IsManagedSequential())
-            {
-                // Treat base class as an initial member.
-                UINT32 parentSize = pParentMT->GetNumInstanceFieldBytes();
-                if (!SafeAddULONG(&clstotalsize, parentSize))
-                    COMPlusThrowOM();
-            }
-    
-            // size must be large enough to accomodate layout. If not, we use the layout size instead.
-            if (clstotalsize < calcTotalSize)
-            {
-                clstotalsize = calcTotalSize;
-            }
-            calcTotalSize = clstotalsize;   // use the size they told us 
-        } 
-        else
-        {
-            // The did not give us an explict size, so lets round up to a good size (for arrays) 
-            while (calcTotalSize % LargestAlignmentRequirement != 0)
-            {
-                if (!SafeAddUINT32(&calcTotalSize, 1))
-                    COMPlusThrowOM();
-            }
-        } 
-    
-        pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
 
-        // The packingSize acts as a ceiling on all individual alignment
-        // requirements so it follows that the largest alignment requirement
-        // is also capped.
-        _ASSERTE(LargestAlignmentRequirement <= packingSize);
-        pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
+        CalculateSizeAndFieldOffsets(
+            parentSize,
+            cInstanceFields,
+            /* fExplicitOffsets */ FALSE,
+            pSortArray,
+            classSizeInMetadata,
+            packingSize,
+            parentManagedAlignmentRequirement,
+            /*calculatingNativeLayout*/ FALSE,
+            pEEClassLayoutInfoOut);
 
 #ifdef _DEBUG
-            // @perf: If the type is blittable, the managed and native layouts have to be identical
-            // so they really shouldn't be calculated twice. Until this code has been well tested and
-            // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
-            // case.
-            if (pEEClassLayoutInfoOut->IsBlittable())
-            {
-                _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
-                _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
-            }
+        // @perf: If the type is blittable, the managed and native layouts have to be identical
+        // so they really shouldn't be calculated twice. Until this code has been well tested and
+        // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
+        // case.
+        if (pEEClassLayoutInfoOut->IsBlittable())
+        {
+            _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
+            _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
+        }
 #endif
-    } //if
+    }
 
     pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
 
@@ -3996,14 +3830,14 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
         LOG((LF_INTEROP, LL_INFO100000, "Packsize      = %lu\n", (ULONG)packingSize));
         LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers)));
         LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n"));
-        for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
+        for (LayoutRawFieldInfo* pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
         {
             LPCUTF8 fieldname;
             if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
             {
                 fieldname = "??";
             }
-            LOG((LF_INTEROP, LL_INFO100000, "+%-5lu  ", (ULONG)(pfwalk->m_offset)));
+            LOG((LF_INTEROP, LL_INFO100000, "+%-5lu  ", (ULONG)(pfwalk->m_nativePlacement.m_offset)));
             LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname));
             LOG((LF_INTEROP, LL_INFO100000, "\n"));
 
@@ -4015,7 +3849,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
         if (fHasNonTrivialParent)
         {
             FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
-            for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
+            for (UINT i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
             {
                 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
                     illegalMarshaler = TRUE;                                 
@@ -4032,4 +3866,120 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
 #ifdef _PREFAST_
 #pragma warning(pop)
 #endif // _PREFAST_
+
+//=====================================================================
+// ParseNativeFieldTypes:
+// Figure out the native field type of each field based on both the CLR
+// signature of the field and the FieldMarshaler metadata. 
+//=====================================================================
+void EEClassLayoutInfo::ParseFieldNativeTypes(
+    IMDInternalImport* pInternalImport,
+    const mdTypeDef cl,
+    HENUMInternal* phEnumField,
+    const ULONG cTotalFields,
+    Module* pModule,
+    ParseNativeTypeFlags nativeTypeFlags,
+    const SigTypeContext* pTypeContext,
+    BOOL* fDisqualifyFromManagedSequential,
+    LayoutRawFieldInfo* pFieldInfoArrayOut,
+    EEClassLayoutInfo* pEEClassLayoutInfoOut,
+    ULONG* cInstanceFields
+#ifdef _DEBUG
+    ,
+    LPCUTF8 szNamespace,
+    LPCUTF8 szName
+#endif
+)
+{
+    HRESULT hr;
+    mdFieldDef fd;
+    ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
+
+    ULONG i;
+    for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
+    {
+        DWORD dwFieldAttrs;
+        ULONG rid = RidFromToken(fd);
+
+        if ((rid == 0) || (rid > maxRid))
+        {
+            COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
+        }
+
+        IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
+
+        PCCOR_SIGNATURE pNativeType = NULL;
+        ULONG cbNativeType;
+        // We ignore marshaling data attached to statics and literals,
+        // since these do not contribute to instance data.
+        if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
+        {
+            PCCOR_SIGNATURE pCOMSignature;
+            ULONG       cbCOMSignature;
+
+            if (IsFdHasFieldMarshal(dwFieldAttrs))
+            {
+                hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
+                if (FAILED(hr))
+                {
+                    cbNativeType = 0;
+                }
+            }
+            else
+            {
+                cbNativeType = 0;
+            }
+
+            IfFailThrow(pInternalImport->GetSigOfFieldDef(fd, &cbCOMSignature, &pCOMSignature));
+
+            IfFailThrow(::validateTokenSig(fd, pCOMSignature, cbCOMSignature, dwFieldAttrs, pInternalImport));
+
+            // fill the appropriate entry in pInfoArrayOut
+            pFieldInfoArrayOut->m_MD = fd;
+            pFieldInfoArrayOut->m_nativePlacement.m_offset = (UINT32)-1;
+            pFieldInfoArrayOut->m_sequence = 0;
+
+#ifdef _DEBUG
+            LPCUTF8 szFieldName;
+            if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
+            {
+                szFieldName = "Invalid FieldDef record";
+            }
+#endif
+
+            ParseNativeType(pModule,
+                pCOMSignature,
+                cbCOMSignature,
+                nativeTypeFlags,
+                pFieldInfoArrayOut,
+                pNativeType,
+                cbNativeType,
+                pInternalImport,
+                cl,
+                pTypeContext,
+                fDisqualifyFromManagedSequential
+#ifdef _DEBUG
+                ,
+                szNamespace,
+                szName,
+                szFieldName
+#endif
+            );
+
+            if (!IsFieldBlittable((FieldMarshaler*)(&pFieldInfoArrayOut->m_FieldMarshaler)))
+                pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
+
+            (*cInstanceFields)++;
+            pFieldInfoArrayOut++;
+        }
+    }
+
+    _ASSERTE(i == cTotalFields);
+
+    // Set the number of fields here.
+    pEEClassLayoutInfoOut->m_numCTMFields += *cInstanceFields;
+    // NULL out the last entry
+    pFieldInfoArrayOut->m_MD = mdFieldDefNil;
+
+}
 #endif // DACCESS_COMPILE
index 680755e..8d5e73f 100644 (file)
@@ -96,6 +96,7 @@ class LoadingEntry_LockHolder;
 class   DispatchMapBuilder;
 class LoaderAllocator;
 class ComCallWrapperTemplate;
+enum class ParseNativeTypeFlags : int;
 
 typedef DPTR(DictionaryLayout) PTR_DictionaryLayout;
 typedef DPTR(FieldMarshaler) PTR_FieldMarshaler;
@@ -356,16 +357,15 @@ class EEClassLayoutInfo
        BOOL fExplicitOffsets,       // explicit offsets?
        MethodTable *pParentMT,       // the loaded superclass
        ULONG cTotalFields,              // total number of fields (instance and static)
-       HENUMInternal *phEnumField,  // enumerator for field
+       HENUMInternal *phEnumField,  // enumerator for fields
        Module* pModule,             // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
        const SigTypeContext *pTypeContext,          // Type parameters for NStruct being loaded
        EEClassLayoutInfo *pEEClassLayoutInfoOut,  // caller-allocated structure to fill in.
-       LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in.  Needs room for cMember+1 elements
+       LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in.  Needs room for cTotalFields+1 elements
        LoaderAllocator * pAllocator,
        AllocMemTracker    *pamTracker
     );
 
-
     friend class ClassLoader;
     friend class EEClass;
     friend class MethodTableBuilder;
@@ -374,12 +374,54 @@ class EEClassLayoutInfo
 #endif
 
     private:
+        static void ParseFieldNativeTypes(
+            IMDInternalImport* pInternalImport,
+            const mdTypeDef cl, // cl of the NStruct being loaded
+            HENUMInternal* phEnumField, // enumerator for fields
+            const ULONG cTotalFields,
+            Module* pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
+            ParseNativeTypeFlags nativeTypeFlags,
+            const SigTypeContext* pTypeContext, // Type parameters for NStruct being loaded
+            BOOL* fDisqualifyFromManagedSequential,
+            LayoutRawFieldInfo* pFieldInfoArrayOut, // caller-allocated array to fill in.  Needs room for cTotalFields+1 elements
+            EEClassLayoutInfo* pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
+            ULONG* cInstanceFields // [out] number of instance fields
+#ifdef _DEBUG
+            ,
+            LPCUTF8 szNamespace,
+            LPCUTF8 szName
+#endif
+        );
+
+        static void SetOffsetsAndSortFields(
+            IMDInternalImport* pInternalImport,
+            const mdTypeDef cl,
+            LayoutRawFieldInfo* pFieldInfoArray, // An array of LayoutRawFieldInfos.
+            const ULONG cInstanceFields,
+            const BOOL fExplicitOffsets,
+            const UINT32 cbAdjustedParentLayoutNativeSize,
+            Module* pModule, // Module that defines the scope for the type-load
+            LayoutRawFieldInfo** pSortArrayOut // A caller-allocated array to fill in with pointers to elements in pFieldInfoArray in ascending order when sequential layout, and declaration order otherwise.
+        );
+
+        static void CalculateSizeAndFieldOffsets(
+            const UINT32 parentSize,
+            ULONG numInstanceFields,
+            BOOL fExplicitOffsets,
+            LayoutRawFieldInfo* const* pSortedFieldInfoArray, // An array of pointers to LayoutRawFieldInfo's in ascending order when sequential layout.
+            ULONG classSizeInMetadata,
+            BYTE packingSize,
+            BYTE parentAlignmentRequirement,
+            BOOL calculatingNativeLayout,
+            EEClassLayoutInfo* pEEClassLayoutInfoOut // A pointer to a caller-allocated EEClassLayoutInfo that we are filling in.
+        );
+
         // size (in bytes) of fixed portion of NStruct.
         UINT32      m_cbNativeSize;
         UINT32      m_cbManagedSize;
 
     public:
-        // 1,2,4 or 8: this is equal to the largest of the alignment requirements
+        // this is equal to the largest of the alignment requirements
         // of each of the EEClass's members. If the NStruct extends another NStruct,
         // the base NStruct is treated as the first member for the purpose of
         // this calculation.
index 0629525..0d994c1 100644 (file)
@@ -142,7 +142,7 @@ do                                                      \
         // This type may qualify for ManagedSequential. Collect managed size and alignment info.
         if (CorTypeInfo::IsPrimitiveType(corElemType))
         {
-            pfwalk->m_managedSize = ((UINT32)CorTypeInfo::Size(corElemType)); // Safe cast - no primitive type is larger than 4gb!
+            pfwalk->m_managedPlacement.m_size = ((UINT32)CorTypeInfo::Size(corElemType)); // Safe cast - no primitive type is larger than 4gb!
 #if defined(_TARGET_X86_) && defined(UNIX_X86_ABI)
             switch (corElemType)
             {
@@ -151,24 +151,24 @@ do                                                      \
                 case ELEMENT_TYPE_U8:
                 case ELEMENT_TYPE_R8:
                 {
-                    pfwalk->m_managedAlignmentReq = 4;
+                    pfwalk->m_managedPlacement.m_alignment = 4;
                     break;
                 }
 
                 default:
                 {
-                    pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize;
+                    pfwalk->m_managedPlacement.m_alignment = pfwalk->m_managedPlacement.m_size;
                     break;
                 }
             }
 #else // _TARGET_X86_ && UNIX_X86_ABI
-            pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize;
+            pfwalk->m_managedPlacement.m_alignment = pfwalk->m_managedPlacement.m_size;
 #endif
         }
         else if (corElemType == ELEMENT_TYPE_PTR)
         {
-            pfwalk->m_managedSize = TARGET_POINTER_SIZE;
-            pfwalk->m_managedAlignmentReq = TARGET_POINTER_SIZE;
+            pfwalk->m_managedPlacement.m_size = TARGET_POINTER_SIZE;
+            pfwalk->m_managedPlacement.m_alignment = TARGET_POINTER_SIZE;
         }
         else if (corElemType == ELEMENT_TYPE_VALUETYPE)
         {
@@ -177,10 +177,10 @@ do                                                      \
                                                                     TRUE);
             if (pNestedType.GetMethodTable()->IsManagedSequential())
             {
-                pfwalk->m_managedSize = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes());
+                pfwalk->m_managedPlacement.m_size = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes());
 
                 _ASSERTE(pNestedType.GetMethodTable()->HasLayout()); // If it is ManagedSequential(), it also has Layout but doesn't hurt to check before we do a cast!
-                pfwalk->m_managedAlignmentReq = pNestedType.GetMethodTable()->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers;
+                pfwalk->m_managedPlacement.m_alignment = pNestedType.GetMethodTable()->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers;
             }
             else
             {
index 67ac994..e3e0509 100644 (file)
@@ -33,7 +33,7 @@
 // Forward refernces
 class FieldDesc;
 class MethodTable;
-
+class FieldMarshaler;
 class FieldMarshaler_NestedLayoutClass;
 class FieldMarshaler_NestedValueClass;
 class FieldMarshaler_StringUni;
@@ -87,8 +87,7 @@ enum NStructFieldType
 //=======================================================================
 #define DEFAULT_PACKING_SIZE 32
 
-
-enum class ParseNativeTypeFlags
+enum class ParseNativeTypeFlags : int
 {
     None    = 0x00,
     IsAnsi  = 0x01,
@@ -125,6 +124,17 @@ BOOL IsFieldBlittable(FieldMarshaler* pFM);
 BOOL IsStructMarshalable(TypeHandle th);
 
 //=======================================================================
+// This structure contains information about where a field is placed in a structure, as well as it's size and alignment.
+// It is used as part of type-loading to determine native layout and (where applicable) managed sequential layout.
+//=======================================================================
+struct RawFieldPlacementInfo
+{
+    UINT32 m_offset;
+    UINT32 m_size;
+    UINT32 m_alignment;
+};
+
+//=======================================================================
 // The classloader stores an intermediate representation of the layout
 // metadata in an array of these structures. The dual-pass nature
 // is a bit extra overhead but building this structure requiring loading
@@ -134,34 +144,24 @@ BOOL IsStructMarshalable(TypeHandle th);
 //
 // Each redirected field gets one entry in LayoutRawFieldInfo.
 // The array is terminated by one dummy record whose m_MD == mdMemberDefNil.
-// WARNING!! Before you change this struct see the comment above the m_FieldMarshaler field
 //=======================================================================
 struct LayoutRawFieldInfo
 {
     mdFieldDef  m_MD;             // mdMemberDefNil for end of array
     UINT8       m_nft;            // NFT_* value
-    UINT32      m_offset;         // native offset of field
-    UINT32      m_cbNativeSize;   // native size of field in bytes
+    RawFieldPlacementInfo m_nativePlacement; // Description of the native field placement
     ULONG       m_sequence;       // sequence # from metadata
-    BOOL        m_fIsOverlapped;
-
-
-    //----- Post v1.0 addition: The LayoutKind.Sequential attribute now affects managed layout as well.
-    //----- So we need to keep a parallel set of layout data for the managed side. The Size and AlignmentReq
-    //----- is redundant since we can figure it out from the sig but since we're already accessing the sig
-    //----- in ParseNativeType, we might as well capture it at that time.
-    UINT32      m_managedSize;    // managed size of field
-    UINT32      m_managedAlignmentReq; // natural alignment of field
-    UINT32      m_managedOffset;  // managed offset of field
-    UINT32      m_pad;            // needed to keep m_FieldMarshaler 8-byte aligned
-
-    // WARNING!
-    // We in-place create a field marshaler in the following
-    // memory, so keep it 8-byte aligned or 
-    // the vtable pointer initialization will cause a 
-    // misaligned memory write on IA64.
-    // The entire struct's size must also be multiple of 8 bytes
-    struct
+
+
+    // The LayoutKind.Sequential attribute now affects managed layout as well.
+    // So we need to keep a parallel set of layout data for the managed side. The Size and AlignmentReq
+    // is redundant since we can figure it out from the sig but since we're already accessing the sig
+    // in ParseNativeType, we might as well capture it at that time.
+    RawFieldPlacementInfo m_managedPlacement;
+
+    // This field is needs to be 8-byte aligned
+    // to ensure that the FieldMarshaler vtable pointer is aligned correctly.
+    alignas(8) struct
     {
         private:
             char m_space[MAXFIELDMARSHALERSIZE];
index e8a7e93..91a888a 100644 (file)
@@ -4182,7 +4182,7 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
                     pSrcFieldMarshaler->CopyTo(pNextFieldMarshaler, MAXFIELDMARSHALERSIZE);
 
                     pNextFieldMarshaler->SetFieldDesc(pFD);
-                    pNextFieldMarshaler->SetExternalOffset(pwalk->m_offset);
+                    pNextFieldMarshaler->SetExternalOffset(pwalk->m_nativePlacement.m_offset);
 
                     ((BYTE*&)pNextFieldMarshaler) += MAXFIELDMARSHALERSIZE;
                     break;
@@ -4220,7 +4220,7 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
                     (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
 
                 if (pLayoutFieldInfo)
-                    IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
+                    IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_nativePlacement.m_offset));
                 else
                     pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS);
             }
@@ -4229,7 +4229,7 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
                 (DWORD_PTR &)pFD->m_pMTOfEnclosingClass =
                     (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes();
 
-                IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
+                IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedPlacement.m_offset));
             }
             else
             {
@@ -4250,9 +4250,9 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
             // mark it as either GC or non-GC and as unplaced; it will get placed later on in an optimized way.
 
             if ((IsBlittable() || HasExplicitFieldOffsetLayout()) && !fIsStatic)
-                IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_offset));
+                IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_nativePlacement.m_offset));
             else if (IsManagedSequential() && !fIsStatic)
-                IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedOffset));
+                IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_managedPlacement.m_offset));
             else if (bCurrentFieldIsGCPointer)
                 pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR);
             else