Skip to content

Commit

Permalink
Fix type layout with explicitly sized structs and classes (#38632)
Browse files Browse the repository at this point in the history
- Mimic the alignment and other algorithms present in coreclr
- Add tests to crossgen2smoke to cover these scenarios
- Update type system unit tests so that they can run in VS
- Fix issue #38450
  • Loading branch information
davidwrighton authored Jul 1, 2020
1 parent c9c6cd8 commit a5198a7
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
type,
type.Context.Target.GetWellKnownTypeSize(type),
type.Context.Target.GetWellKnownTypeAlignment(type),
0,
out instanceByteSizeAndAlignment
);

Expand Down Expand Up @@ -358,13 +359,8 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
fieldOrdinal++;
}

if (type.IsValueType)
{
instanceSize = LayoutInt.Max(new LayoutInt(layoutMetadata.Size), instanceSize);
}

SizeAndAlignment instanceByteSizeAndAlignment;
var instanceSizeAndAlignment = ComputeInstanceSize(type, instanceSize, largestAlignmentRequired, out instanceByteSizeAndAlignment);
var instanceSizeAndAlignment = ComputeInstanceSize(type, instanceSize, largestAlignmentRequired, layoutMetadata.Size, out instanceByteSizeAndAlignment);

ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
Expand Down Expand Up @@ -407,13 +403,8 @@ protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(Metada
fieldOrdinal++;
}

if (type.IsValueType)
{
cumulativeInstanceFieldPos = LayoutInt.Max(cumulativeInstanceFieldPos, new LayoutInt(layoutMetadata.Size));
}

SizeAndAlignment instanceByteSizeAndAlignment;
var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, largestAlignmentRequirement, out instanceByteSizeAndAlignment);
var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, largestAlignmentRequirement, layoutMetadata.Size, out instanceByteSizeAndAlignment);

ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
Expand Down Expand Up @@ -675,7 +666,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
}

SizeAndAlignment instanceByteSizeAndAlignment;
var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, minAlign, out instanceByteSizeAndAlignment);
var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, minAlign, 0/* specified field size unused */, out instanceByteSizeAndAlignment);

ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
Expand Down Expand Up @@ -788,21 +779,40 @@ private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata lay
return layoutMetadata.PackingSize;
}

private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, out SizeAndAlignment byteCount)
private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, out SizeAndAlignment byteCount)
{
SizeAndAlignment result;

TargetDetails target = type.Context.Target;


// Pad the length of structs to be 1 if they are empty so we have no zero-length structures
if (type.IsValueType && instanceSize == LayoutInt.Zero)
{
instanceSize = LayoutInt.One;
}

TargetDetails target = type.Context.Target;

if (classLayoutSize != 0)
{
LayoutInt parentSize;
if (type.IsValueType)
parentSize = new LayoutInt(0);
else
parentSize = type.BaseType.InstanceByteCountUnaligned;

LayoutInt specifiedInstanceSize = parentSize + new LayoutInt(classLayoutSize);

instanceSize = LayoutInt.Max(specifiedInstanceSize, instanceSize);
}
else
{
if (type.IsValueType)
{
instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target);
}
}

if (type.IsValueType)
{
instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target);
result.Size = instanceSize;
result.Alignment = alignment;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Class2 : Class1
}

[StructLayout(LayoutKind.Explicit, Size = 40)]
class ExplicitSize : Class1
class ExplicitSize
{
[FieldOffset(0)]
int Lol;
Expand All @@ -92,6 +92,11 @@ public class ExplicitEmptyClass
{
}

[StructLayout(LayoutKind.Explicit, Size = 0)]
public class ExplicitEmptyClassSize0
{
}

[StructLayout(LayoutKind.Explicit)]
public struct ExplicitEmptyStruct
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,11 @@ public void TestFinalize()
/// Testing lookup up of a method in an instantiated type.
/// </summary>
[Fact]
[ActiveIssue("")]
public void TestMethodLookup()
{
MetadataType t = _testModule.GetType("GenericTypes", "GenericClass`1").MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));

MethodSignature sig = new MethodSignature(MethodSignatureFlags.None, 0, t.Instantiation[0], new TypeDesc[0] { });
MethodSignature sig = new MethodSignature(MethodSignatureFlags.None, 0, _context.GetSignatureVariable(0, false), new TypeDesc[0] { });
MethodDesc fooMethod = t.GetMethod("Foo", sig);
Assert.NotNull(fooMethod);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>ILCompiler.TypeSystem.ReadyToRun.Tests</AssemblyName>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<Configurations>Debug;Release;Checked</Configurations>
<!-- This seems to be required for supporting assemblies to be copied into the output -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Expand All @@ -11,6 +11,7 @@
<!-- By default the subdirectories containing CoreTestAssembly and ILTestAssembly would be
included in compilation of this project -->
<EnableDefaultItems>false</EnableDefaultItems>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit a5198a7

Please sign in to comment.