summaryrefslogtreecommitdiff
path: root/src/vm/class.cpp
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>2019-03-04 13:15:28 -0800
committerGitHub <noreply@github.com>2019-03-04 13:15:28 -0800
commit1278da1f480e664b5afd1b62f2be74424dbefbb8 (patch)
tree5feccfd6491e70205b6158bea5400e16b4117f1f /src/vm/class.cpp
parentfd3afcaf0dc0ace3f84d0412c128f4e64c419105 (diff)
downloadcoreclr-1278da1f480e664b5afd1b62f2be74424dbefbb8.tar.gz
coreclr-1278da1f480e664b5afd1b62f2be74424dbefbb8.tar.bz2
coreclr-1278da1f480e664b5afd1b62f2be74424dbefbb8.zip
Move EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing to class.cpp (#22932)
Move `EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing` to class.cpp and out of fieldmarshaler.cpp. This change co-locates `EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing` with the rest of the implementation of `EEClassLayoutInfo`. Additionally, this PR separates out the field blittability check into a separate function instead of burying it in `CollectLayoutFieldMetadataThrowing`. Finally, it adds a small optimization in the field marshaler implementations where if a field's native size is statically known, the code returns that value instead of calling into one of the FieldMarshaler "virtual" calls. Originally part of #21415, but extracted out to make that PR smaller.
Diffstat (limited to 'src/vm/class.cpp')
-rw-r--r--src/vm/class.cpp700
1 files changed, 700 insertions, 0 deletions
diff --git a/src/vm/class.cpp b/src/vm/class.cpp
index 5ec3721ac7..1e551a9c5d 100644
--- a/src/vm/class.cpp
+++ b/src/vm/class.cpp
@@ -3195,3 +3195,703 @@ void EEClass::SetPackableField(EEClassFieldId eField, DWORD dwValue)
_ASSERTE(!m_fFieldsArePacked);
GetPackedFields()->SetUnpackedField(eField, dwValue);
}
+
+#ifndef DACCESS_COMPILE
+
+//=======================================================================
+// Called from the clsloader to load up and summarize the field metadata
+// for layout classes.
+//
+// Warning: This function can load other classes (esp. for nested structs.)
+//=======================================================================
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
+ mdTypeDef cl, // cl of the NStruct being loaded
+ BYTE packingSize, // packing size (from @dll.struct)
+ BYTE nlType, // nltype (from @dll.struct)
+#ifdef FEATURE_COMINTEROP
+ BOOL isWinRT, // Is the type a WinRT type
+#endif // FEATURE_COMINTEROP
+ BOOL fExplicitOffsets, // explicit offsets?
+ MethodTable *pParentMT, // the loaded superclass
+ ULONG cTotalFields, // total number of fields (instance and static)
+ HENUMInternal *phEnumField, // enumerator for field
+ 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
+ LoaderAllocator *pAllocator,
+ AllocMemTracker *pamTracker
+)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ HRESULT hr;
+ // Internal interface for the NStruct being loaded.
+ IMDInternalImport *pInternalImport = pModule->GetMDImport();
+
+#ifdef _DEBUG
+ LPCUTF8 szName;
+ LPCUTF8 szNamespace;
+ if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
+ {
+ szName = szNamespace = "Invalid TypeDef record";
+ }
+
+ if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
+ CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
+#endif
+
+ // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
+ // function exits.
+ BOOL fDisqualifyFromManagedSequential;
+
+ // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be
+ // ManagedSequential. Other issues checked below might also disqualify the type.
+ if ( (!fExplicitOffsets) && // Is it marked sequential?
+ (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype?
+ )
+ {
+ fDisqualifyFromManagedSequential = FALSE;
+ }
+ else
+ {
+ fDisqualifyFromManagedSequential = TRUE;
+ }
+
+
+ BOOL fHasNonTrivialParent = pParentMT &&
+ !pParentMT->IsObjectClass() &&
+ !pParentMT->IsValueTypeClass();
+
+
+ //====================================================================
+ // First, some validation checks.
+ //====================================================================
+ _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);
+ if (fHasNonTrivialParent)
+ 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);
+
+
+ //=====================================================================
+ // 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;;
+ if (fParentHasLayout)
+ {
+ pParentLayoutInfo = pParentMT->GetLayoutInfo();
+ // Treat base class as an initial member.
+ cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize();
+ // If the parent was originally a zero-sized explicit type but
+ // got bumped up to a size of 1 for compatibility reasons, then
+ // we need to remove the padding, but ONLY for inheritance situations.
+ if (pParentLayoutInfo->IsZeroSized()) {
+ CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1);
+ cbAdjustedParentLayoutNativeSize = 0;
+ }
+ }
+
+ 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;
+#ifdef FEATURE_COMINTEROP
+ if (isWinRT)
+ flags = 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);
+
+ // 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)
+ {
+ // 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;
+
+ // 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++)
+ {
+ 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++;
+ }
+ }
+
+ //=====================================================================
+ // 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++)
+ {
+ pEEClassLayoutInfoOut->m_numCTMFields++;
+
+ pfwalk->m_cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize();
+ }
+
+ if (pEEClassLayoutInfoOut->m_numCTMFields)
+ {
+ pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
+
+ // Bring in the parent's fieldmarshalers
+ if (fHasNonTrivialParent)
+ {
+ CONSISTENCY_CHECK(fParentHasLayout);
+ PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above
+
+ UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
+
+ BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
+ BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
+
+ for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
+ {
+ FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
+ FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
+
+ pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
+ }
+ }
+
+ }
+
+
+ //=====================================================================
+ // 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.
+ //=====================================================================
+ {
+ 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;
+ }
+
+
+
+ //=====================================================================
+ // Phase 4: Now we do the same thing again for managedsequential layout.
+ //=====================================================================
+ if (!fDisqualifyFromManagedSequential)
+ {
+ BYTE LargestAlignmentRequirement = 1;
+ UINT32 cbCurOffset = 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);
+ }
+
+ // 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;
+
+#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);
+ }
+#endif
+ } //if
+
+ pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
+
+#ifdef _DEBUG
+ {
+ BOOL illegalMarshaler = FALSE;
+
+ LOG((LF_INTEROP, LL_INFO100000, "\n\n"));
+ LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName));
+ 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++)
+ {
+ 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, "%s", fieldname));
+ LOG((LF_INTEROP, LL_INFO100000, "\n"));
+
+ if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
+ illegalMarshaler = TRUE;
+ }
+
+ // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
+ if (fHasNonTrivialParent)
+ {
+ FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
+ for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
+ {
+ if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
+ illegalMarshaler = TRUE;
+ ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
+ }
+ }
+
+ LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize)));
+ LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable"), szNamespace, szName));
+ }
+#endif
+ return;
+}
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif // _PREFAST_
+#endif // DACCESS_COMPILE