public void LayoutIntTests() { Assert.Throws <ArgumentException>(() => { return(new LayoutInt(int.MinValue)); }); Assert.Throws <ArgumentException>(() => { return(new LayoutInt(-1)); }); Assert.Equal(LayoutInt.Zero, new LayoutInt(0)); Assert.Equal(LayoutInt.One, new LayoutInt(1)); Assert.True(LayoutInt.Zero == new LayoutInt(0)); Assert.True(LayoutInt.One == new LayoutInt(1)); Assert.False(LayoutInt.Zero == new LayoutInt(1)); Assert.False(LayoutInt.One == new LayoutInt(0)); #pragma warning disable 1718 // Allow comparison to same variable Assert.True(LayoutInt.Indeterminate == LayoutInt.Indeterminate); #pragma warning restore 1718 Assert.False(LayoutInt.Zero != new LayoutInt(0)); Assert.False(LayoutInt.One != new LayoutInt(1)); Assert.True(LayoutInt.Zero != new LayoutInt(1)); Assert.True(LayoutInt.One != new LayoutInt(0)); #pragma warning disable 1718 // Allow comparison to same variable Assert.False(LayoutInt.Indeterminate != LayoutInt.Indeterminate); #pragma warning restore 1718 Assert.Equal(0, new LayoutInt(0).AsInt); Assert.Equal(1, new LayoutInt(1).AsInt); Assert.Equal(Int32.MaxValue, new LayoutInt(Int32.MaxValue).AsInt); Assert.Throws <InvalidOperationException>(() => { return(LayoutInt.Indeterminate.AsInt); }); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Indeterminate + LayoutInt.Indeterminate); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.One + LayoutInt.Indeterminate); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Indeterminate + LayoutInt.One); Assert.Equal(new LayoutInt(2), LayoutInt.One + LayoutInt.One); Assert.Throws <OverflowException>(() => { return(new LayoutInt(int.MaxValue) + LayoutInt.One); }); Assert.Throws <OverflowException>(() => { return(new LayoutInt(int.MaxValue) + LayoutInt.One); }); Assert.Equal(LayoutInt.One, LayoutInt.Max(LayoutInt.One, LayoutInt.Zero)); Assert.Equal(LayoutInt.One, LayoutInt.Max(LayoutInt.Zero, LayoutInt.One)); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Max(LayoutInt.Indeterminate, LayoutInt.Zero)); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Max(LayoutInt.Zero, LayoutInt.Indeterminate)); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Max(LayoutInt.Indeterminate, LayoutInt.Indeterminate)); Assert.Equal(LayoutInt.Zero, LayoutInt.Min(LayoutInt.One, LayoutInt.Zero)); Assert.Equal(LayoutInt.Zero, LayoutInt.Min(LayoutInt.Zero, LayoutInt.One)); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Min(LayoutInt.Indeterminate, LayoutInt.Zero)); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Min(LayoutInt.Zero, LayoutInt.Indeterminate)); Assert.Equal(LayoutInt.Indeterminate, LayoutInt.Min(LayoutInt.Indeterminate, LayoutInt.Indeterminate)); }
// 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); }