/// <summary> /// While computing layout, we don't generally compute the full field information. This function is used to /// gate how much of field layout to run /// </summary> /// <param name="fieldStorage">the conceptual location of the field</param> /// <param name="loadRequested">what sort of load was requested</param> /// <returns></returns> internal bool ShouldProcessField(NativeFormat.FieldStorage fieldStorage, FieldLoadState loadRequested) { if (fieldStorage == (int)NativeFormat.FieldStorage.Instance) { // Make sure we wanted to load instance fields. if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.None) { return(false); } } else if ((loadRequested & FieldLoadState.Statics) == FieldLoadState.None) { // Otherwise the field is a static, and we only want instance fields. return(false); } return(true); }
// The layout algorithm should probably compute results and let the caller set things internal unsafe LayoutInt[] ComputeTypeSizeAndAlignment(TypeDesc type, FieldLoadState loadRequested, out LowLevelList <LayoutInt> fieldOffsets) { fieldOffsets = null; TypeLoaderLogger.WriteLine("Laying out type " + type.ToString() + ". IsValueType: " + (type.IsValueType ? "true" : "false") + ". LoadRequested = " + ((int)loadRequested).LowLevelToString()); Debug.Assert(loadRequested != FieldLoadState.None); Debug.Assert(type is ArrayType || (type is DefType && ((DefType)type).HasInstantiation)); bool isArray = type is ArrayType; LayoutInt[] position = new LayoutInt[5]; LayoutInt alignRequired = LayoutInt.One; if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.Instance) { ComputeTypeSizeBeforeFields(type, out position[(int)NativeFormat.FieldStorage.Instance], out alignRequired); } if (!isArray) { // Once this is done, the NativeLayoutFields on the type are initialized EnsureFieldLayoutLoadedForGenericType((DefType)type); Debug.Assert(type.NativeLayoutFields != null); } int instanceFields = 0; if (!isArray && type.NativeLayoutFields.Length > 0) { fieldOffsets = new LowLevelList <LayoutInt>(type.NativeLayoutFields.Length); for (int i = 0; i < type.NativeLayoutFields.Length; i++) { TypeDesc fieldType = type.NativeLayoutFields[i].FieldType; int fieldStorage = (int)type.NativeLayoutFields[i].FieldStorage; if (!ShouldProcessField((NativeFormat.FieldStorage)fieldStorage, loadRequested)) { continue; } // For value types, we will attempt to get the size and alignment from // the runtime if possible, otherwise GetFieldSizeAndAlignment will // recurse to lay out nested struct fields. LayoutInt alignment; LayoutInt size; GetFieldSizeAlignment(fieldType, out size, out alignment); Debug.Assert(alignment.AsInt > 0); if (fieldStorage == (int)NativeFormat.FieldStorage.Instance) { instanceFields++; // Ensure alignment of type is sufficient for this field alignRequired = LayoutInt.Max(alignRequired, alignment); } position[fieldStorage] = LayoutInt.AlignUp(position[fieldStorage], alignment); TypeLoaderLogger.WriteLine(" --> Field type " + fieldType.ToString() + " storage " + ((uint)(type.NativeLayoutFields[i].FieldStorage)).LowLevelToString() + " offset " + position[fieldStorage].LowLevelToString() + " alignment " + alignment.LowLevelToString()); fieldOffsets.Add(position[fieldStorage]); position[fieldStorage] += size; } } // Pad the length of structs to be 1 if they are empty so we have no zero-length structures if ((position[(int)NativeFormat.FieldStorage.Instance] == LayoutInt.Zero) && type.IsValueType) { position[(int)NativeFormat.FieldStorage.Instance] = LayoutInt.One; } Debug.Assert(alignRequired == new LayoutInt(1) || alignRequired == new LayoutInt(2) || alignRequired == new LayoutInt(4) || alignRequired == new LayoutInt(8)); position[InstanceAlignmentEntry] = alignRequired; return(position); }
// The layout algorithm should probably compute results and let the caller set things internal unsafe int[] ComputeTypeSizeAndAlignment(TypeDesc type, FieldLoadState loadRequested, out LowLevelList<int> fieldOffsets) { fieldOffsets = null; TypeLoaderLogger.WriteLine("Laying out type " + type.ToString() + ". IsValueType: " + (type.IsValueType ? "true" : "false") + ". LoadRequested = " + ((int)loadRequested).LowLevelToString()); Debug.Assert(loadRequested != FieldLoadState.None); Debug.Assert(type is ArrayType || (type is DefType && ((DefType)type).HasInstantiation)); bool isArray = type is ArrayType; int[] position = new int[5]; int alignRequired = 1; if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.Instance) { ComputeTypeSizeBeforeFields(type, out position[(int)NativeFormat.FieldStorage.Instance], out alignRequired); } if (!isArray) { // Once this is done, the NativeLayoutFields on the type are initialized EnsureFieldLayoutLoadedForGenericType((DefType)type); Debug.Assert(type.NativeLayoutFields != null); } int instanceFields = 0; if (!isArray && type.NativeLayoutFields.Length > 0) { fieldOffsets = new LowLevelList<int>(type.NativeLayoutFields.Length); for (int i = 0; i < type.NativeLayoutFields.Length; i++) { TypeDesc fieldType = type.NativeLayoutFields[i].FieldType; int fieldStorage = (int)type.NativeLayoutFields[i].FieldStorage; if (!ShouldProcessField((NativeFormat.FieldStorage)fieldStorage, loadRequested)) continue; // For value types, we will attempt to get the size and alignment from // the runtime if possible, otherwise GetFieldSizeAndAlignment will // recurse to lay out nested struct fields. int alignment; int size; GetFieldSizeAlignment(fieldType, out size, out alignment); Debug.Assert(alignment > 0); if (fieldStorage == (int)NativeFormat.FieldStorage.Instance) { instanceFields++; // Ensure alignment of type is sufficient for this field if (alignRequired < alignment) alignRequired = alignment; } position[fieldStorage] = MemoryHelpers.AlignUp(position[fieldStorage], alignment); TypeLoaderLogger.WriteLine(" --> Field type " + fieldType.ToString() + " storage " + ((uint)(type.NativeLayoutFields[i].FieldStorage)).LowLevelToString() + " offset " + position[fieldStorage].LowLevelToString() + " alignment " + alignment.LowLevelToString()); fieldOffsets.Add(position[fieldStorage]); position[fieldStorage] += size; } } // Pad the length of structs to be 1 if they are empty so we have no zero-length structures if ((position[(int)NativeFormat.FieldStorage.Instance] == 0) && type.IsValueType) position[(int)NativeFormat.FieldStorage.Instance] = 1; Debug.Assert(alignRequired == 1 || alignRequired == 2 || alignRequired == 4 || alignRequired == 8); position[InstanceAlignmentEntry] = alignRequired; return position; }
/// <summary> /// While computing layout, we don't generally compute the full field information. This function is used to /// gate how much of field layout to run /// </summary> /// <param name="fieldStorage">the conceptual location of the field</param> /// <param name="loadRequested">what sort of load was requested</param> /// <returns></returns> internal bool ShouldProcessField(NativeFormat.FieldStorage fieldStorage, FieldLoadState loadRequested) { if (fieldStorage == (int)NativeFormat.FieldStorage.Instance) { // Make sure we wanted to load instance fields. if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.None) return false; } else if ((loadRequested & FieldLoadState.Statics) == FieldLoadState.None) { // Otherwise the field is a static, and we only want instance fields. return false; } return true; }