private static void EnsureFieldLayoutLoadedForNonUniversalType(DefType type) { Debug.Assert(type.HasInstantiation); Debug.Assert(!type.ComputeTemplate().IsCanonicalSubtype(CanonicalFormKind.Universal)); if (type.NativeLayoutFields != null) { return; } // Look up the universal template for this type. Only the universal template has field layout // information, so we have to use it to parse the field layout. NativeLayoutInfoLoadContext universalLayoutLoadContext; NativeLayoutInfo universalLayoutInfo; NativeParser typeInfoParser = type.GetOrCreateTypeBuilderState().GetParserForUniversalNativeLayoutInfo(out universalLayoutLoadContext, out universalLayoutInfo); if (typeInfoParser.IsNull) { throw new TypeBuilder.MissingTemplateException(); } // Now parse that layout into the NativeLayoutFields array. NativeParser fieldLayoutParser = typeInfoParser.GetParserForBagElementKind(BagElementKind.FieldLayout); type.NativeLayoutFields = ParseFieldLayout(type, universalLayoutLoadContext, fieldLayoutParser); }
public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) { if (!type.IsTemplateUniversal() && (layoutKind == InstanceLayoutKind.TypeOnly)) { // Non universal generics can just use the template's layout DefType template = (DefType)type.ComputeTemplate(); return(_noMetadataFieldLayoutAlgorithm.ComputeInstanceLayout(template, InstanceLayoutKind.TypeOnly)); } // Only needed for universal generics, or when looking up an offset for a field for a universal generic LowLevelList <int> fieldOffsets; int[] position = ComputeTypeSizeAndAlignment(type, FieldLoadState.Instance, out fieldOffsets); int numInstanceFields = 0; foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields) { if (!field.IsStatic) { numInstanceFields++; } } int byteCountAlignment = position[InstanceAlignmentEntry]; byteCountAlignment = type.Context.Target.GetObjectAlignment(byteCountAlignment); ComputedInstanceFieldLayout layout = new ComputedInstanceFieldLayout() { Offsets = new FieldAndOffset[numInstanceFields], ByteCountAlignment = byteCountAlignment, ByteCountUnaligned = position[(int)NativeFormat.FieldStorage.Instance], PackValue = 0 // TODO, as we add more metadata handling logic, find out if its necessary to use a meaningful value here }; if (!type.IsValueType) { layout.FieldAlignment = type.Context.Target.PointerSize; layout.FieldSize = type.Context.Target.PointerSize; } else { layout.FieldAlignment = position[InstanceAlignmentEntry]; layout.FieldSize = MemoryHelpers.AlignUp(position[(int)NativeFormat.FieldStorage.Instance], layout.FieldAlignment); } int curInstanceField = 0; foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields) { if (!field.IsStatic) { layout.Offsets[curInstanceField] = new FieldAndOffset(field, fieldOffsets[curInstanceField]); curInstanceField++; } } return(layout); }
public unsafe override bool ComputeIsByRefLike(DefType type) { if (type.RetrieveRuntimeTypeHandleIfPossible()) { return(type.RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); } // Being ByRefLike is a property of the uninstantiated form of a type (so its set on all kinds of templates reliably) return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); }
private static void EnsureFieldLayoutLoadedForUniversalType(DefType type, NativeLayoutInfoLoadContext loadContext, NativeParser fieldLayoutParser) { Debug.Assert(type.HasInstantiation); Debug.Assert(type.ComputeTemplate().IsCanonicalSubtype(CanonicalFormKind.Universal)); if (type.NativeLayoutFields != null) { return; } type.NativeLayoutFields = ParseFieldLayout(type, loadContext, fieldLayoutParser); }
public unsafe override bool ComputeContainsGCPointers(DefType type) { if (type.IsTemplateCanonical()) { return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->HasGCPointers); } else { if (type.RetrieveRuntimeTypeHandleIfPossible()) { return(type.RuntimeTypeHandle.ToEETypePtr()->HasGCPointers); } return(type.GetOrCreateTypeBuilderState().InstanceGCLayout != null); } }
public unsafe override bool ComputeIsByRefLike(DefType type) { if (type.IsTemplateCanonical()) { return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); } else { if (type.RetrieveRuntimeTypeHandleIfPossible()) { return(type.RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); } throw new NotImplementedException(); } }
/// <summary> /// Get an enumerable list of the fields used for dynamic gc layout calculation. /// </summary> private IEnumerable <FieldDesc> GetFieldsForGCLayout() { DefType defType = (DefType)TypeBeingBuilt; IEnumerable <FieldDesc> fields; if (defType.ComputeTemplate(false) != null) { // we have native layout and a template. Use the NativeLayoutFields as that is the only complete // description of the fields available. (There may be metadata fields, but those aren't guaranteed // to be a complete set of fields due to reflection reduction. NativeLayoutFieldAlgorithm.EnsureFieldLayoutLoadedForGenericType(defType); fields = defType.NativeLayoutFields; } else { // The metadata case. We're loading the type from regular metadata, so use the regular metadata fields fields = defType.GetFields(); } return(fields); }
public unsafe override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) { if (type.Context.Target.Architecture == TargetArchitecture.ARM) { if (!type.IsValueType) { return(null); } // There is no reason to compute the entire field layout for the HFA type/flag if // the template type is not a universal generic type (information stored in rare flags on the EEType) TypeDesc templateType = type.ComputeTemplate(false); if (templateType != null && !templateType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { EEType *pEETemplate = templateType.GetRuntimeTypeHandle().ToEETypePtr(); if (!pEETemplate->IsHFA) { return(null); } if (pEETemplate->RequiresAlign8) { return(type.Context.GetWellKnownType(WellKnownType.Double)); } else { return(type.Context.GetWellKnownType(WellKnownType.Single)); } } // Once this is done, the NativeLayoutFields on the type are initialized EnsureFieldLayoutLoadedForGenericType((DefType)type); Debug.Assert(type.NativeLayoutFields != null); // Empty types are not HFA if (type.NativeLayoutFields.Length == 0) { return(null); } DefType currentHfaElementType = null; for (int i = 0; i < type.NativeLayoutFields.Length; i++) { TypeDesc fieldType = type.NativeLayoutFields[i].FieldType; if (type.NativeLayoutFields[i].FieldStorage != NativeFormat.FieldStorage.Instance) { continue; } DefType fieldDefType = fieldType as DefType; // HFA types cannot contain non-HFA types if (fieldDefType == null || !fieldDefType.IsHfa) { return(null); } Debug.Assert(fieldDefType.HfaElementType != null); if (currentHfaElementType == null) { currentHfaElementType = fieldDefType.HfaElementType; } else if (currentHfaElementType != fieldDefType.HfaElementType) { return(null); // If the field doesn't have the same HFA type as the one we've looked at before, the type cannot be HFA } } // If we didn't find any instance fields, then this can't be an HFA type if (currentHfaElementType == null) { return(null); } // Note that we check the total size, but do not perform any checks on number of fields: // - Type of fields can be HFA valuetype itself // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that // the valuetype is HFA and explicitly specified size int maxSize = currentHfaElementType.InstanceFieldSize.AsInt * currentHfaElementType.Context.Target.MaximumHfaElementCount; if (type.InstanceFieldSize.AsInt > maxSize) { return(null); } return(currentHfaElementType); } else { Debug.Assert( type.Context.Target.Architecture == TargetArchitecture.X86 || type.Context.Target.Architecture == TargetArchitecture.X64); return(null); } }
public unsafe override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) { // Use this constant to make the code below more laconic const ValueTypeShapeCharacteristics NotHA = ValueTypeShapeCharacteristics.None; Debug.Assert(type.IsValueType); TargetArchitecture targetArch = type.Context.Target.Architecture; if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64)) { return(NotHA); } if (!type.IsValueType) { return(NotHA); } // There is no reason to compute the entire field layout for the HA type/flag if // the template type is not a universal generic type (information stored in rare flags on the EEType) TypeDesc templateType = type.ComputeTemplate(false); if (templateType != null && !templateType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { EEType *pEETemplate = templateType.GetRuntimeTypeHandle().ToEETypePtr(); if (!pEETemplate->IsHFA) { return(NotHA); } if (pEETemplate->RequiresAlign8) { return(ValueTypeShapeCharacteristics.Float64Aggregate); } else { return(ValueTypeShapeCharacteristics.Float32Aggregate); } } // Once this is done, the NativeLayoutFields on the type are initialized EnsureFieldLayoutLoadedForGenericType((DefType)type); Debug.Assert(type.NativeLayoutFields != null); // Empty types are not HA if (type.NativeLayoutFields.Length == 0) { return(NotHA); } // Find the common HA element type if any ValueTypeShapeCharacteristics haResultType = NotHA; for (int i = 0; i < type.NativeLayoutFields.Length; i++) { TypeDesc fieldType = type.NativeLayoutFields[i].FieldType; if (type.NativeLayoutFields[i].FieldStorage != NativeFormat.FieldStorage.Instance) { continue; } // If a field isn't a DefType, then this type cannot be a HA type if (!(fieldType is DefType fieldDefType)) { return(NotHA); } // HA types cannot contain non-HA types ValueTypeShapeCharacteristics haFieldType = fieldDefType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask; if (haFieldType == NotHA) { return(NotHA); } if (haResultType == NotHA) { haResultType = haFieldType; } else if (haResultType != haFieldType) { return(NotHA); // If the field doesn't have the same HA type as the one we've looked at before, the type cannot be HA } } // If we didn't find any instance fields, then this can't be a HA type if (haResultType == NotHA) { return(NotHA); } int haElementSize = haResultType switch { ValueTypeShapeCharacteristics.Float32Aggregate => 4, ValueTypeShapeCharacteristics.Float64Aggregate => 8, ValueTypeShapeCharacteristics.Vector64Aggregate => 8, ValueTypeShapeCharacteristics.Vector128Aggregate => 16, _ => throw new ArgumentOutOfRangeException() }; // Note that we check the total size, but do not perform any checks on number of fields: // - Type of fields can be HA valuetype itself // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that // the valuetype is HFA and explicitly specified size int maxSize = haElementSize * type.Context.Target.MaxHomogeneousAggregateElementCount; if (type.InstanceFieldSize.AsInt > maxSize) { return(NotHA); } return(haResultType); } }