Port type system tests from CoreRT repo (#38128)
authorSimon Nattress <nattress@gmail.com>
Tue, 23 Jun 2020 03:34:44 +0000 (20:34 -0700)
committerGitHub <noreply@github.com>
Tue, 23 Jun 2020 03:34:44 +0000 (20:34 -0700)
Port the managed type system unit tests and wire them up to build.cmd -test so they run if the clr.tools subset is included in compilation.

Port enough USG layout and `Array<T>` support so we can keep their respective tests running in this repo.

47 files changed:
eng/Subsets.props
src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs [new file with mode: 0644]
src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs [new file with mode: 0644]
src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericTypes.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Hashcode.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InstanceFieldLayout.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InterfaceArrangements.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Platform.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/StaticFieldLayout.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/SyntheticVirtualOverride.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/TypeNameParsing.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/ValueTypeShapeCharacteristics.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/VirtualFunctionOverride.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/HashcodeTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILDisassemblerTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILDisassembler.il [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/InstanceFieldLayout.il [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/Main.il [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/StaticFieldLayout.il [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/VirtualFunctionOverride.il [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/StaticFieldLayoutTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestMetadataFieldLayoutAlgorithm.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TypeNameParsingTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ValueTypeShapeCharacteristicsTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/VirtualFunctionOverrideTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/WellKnownTypeTests.cs [new file with mode: 0644]
src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj

index a058a94..b27d1e5 100644 (file)
                              $(CoreClrProjectRoot)src\tools\dotnet-pgo\dotnet-pgo.csproj;
                              $(CoreClrProjectRoot)src\tools\r2rtest\R2RTest.csproj" Category="clr" BuildInParallel="true" />
     <ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\aot\crossgen2\crossgen2.csproj" Category="clr" />
+    <ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\aot\ILCompiler.TypeSystem.ReadyToRun.Tests\ILCompiler.TypeSystem.ReadyToRun.Tests.csproj" Test="true" Category="clr" Condition="'$(__DistroRid)' != 'linux-musl-x64'"/>
   </ItemGroup>
 
   <ItemGroup Condition="$(_subset.Contains('+clr.packages+'))">
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs
new file mode 100644 (file)
index 0000000..6d611fd
--- /dev/null
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+    /// <summary>
+    /// RuntimeInterfaces algorithm for for array types which are similar to a generic type
+    /// </summary>
+    public sealed class ArrayOfTRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm
+    {
+        /// <summary>
+        /// Open type to instantiate to get the interfaces associated with an array.
+        /// </summary>
+        private MetadataType _arrayOfTType;
+
+        /// <summary>
+        /// RuntimeInterfaces algorithm for for array types which are similar to a generic type
+        /// </summary>
+        /// <param name="arrayOfTType">Open type to instantiate to get the interfaces associated with an array.</param>
+        public ArrayOfTRuntimeInterfacesAlgorithm(MetadataType arrayOfTType)
+        {
+            _arrayOfTType = arrayOfTType;
+            Debug.Assert(!(arrayOfTType is InstantiatedType));
+        }
+
+        public override DefType[] ComputeRuntimeInterfaces(TypeDesc _type)
+        {
+            ArrayType arrayType = (ArrayType)_type;
+            Debug.Assert(arrayType.IsSzArray);
+            TypeDesc arrayOfTInstantiation = _arrayOfTType.MakeInstantiatedType(arrayType.ElementType);
+
+            return arrayOfTInstantiation.RuntimeInterfaces;
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs
new file mode 100644 (file)
index 0000000..ee7bcd9
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Internal.TypeSystem
+{
+    public static class ConstructedTypeRewritingHelpers
+    {
+        /// <summary>
+        /// Determine if the construction of a type contains one of a given set of types. This is a deep
+        /// scan. For instance, given type MyType&lt;SomeGeneric&lt;int[]&gt;&gt;, and a set of typesToFind
+        /// that includes int, this function will return true. Does not detect the open generics that may be
+        /// instantiated over in this type. IsConstructedOverType would return false if only passed MyType, 
+        /// or SomeGeneric for the above examplt.
+        /// </summary>
+        /// <param name="type">type to examine</param>
+        /// <param name="typesToFind">types to search for in the construction of type</param>
+        /// <returns>true if a type in typesToFind is found</returns>
+        public static bool IsConstructedOverType(this TypeDesc type, TypeDesc[] typesToFind)
+        {
+            int directDiscoveryIndex = Array.IndexOf(typesToFind, type);
+
+            if (directDiscoveryIndex != -1)
+                return true;
+
+            if (type.HasInstantiation)
+            {
+                for (int instantiationIndex = 0; instantiationIndex < type.Instantiation.Length; instantiationIndex++)
+                {
+                    if (type.Instantiation[instantiationIndex].IsConstructedOverType(typesToFind))
+                    {
+                        return true;
+                    }
+                }
+            }
+            else if (type.IsParameterizedType)
+            {
+                ParameterizedType parameterizedType = (ParameterizedType)type;
+                return parameterizedType.ParameterType.IsConstructedOverType(typesToFind);
+            }
+            else if (type.IsFunctionPointer)
+            {
+                MethodSignature functionPointerSignature = ((FunctionPointerType)type).Signature;
+                if (functionPointerSignature.ReturnType.IsConstructedOverType(typesToFind))
+                    return true;
+
+                for (int paramIndex = 0; paramIndex < functionPointerSignature.Length; paramIndex++)
+                {
+                    if (functionPointerSignature[paramIndex].IsConstructedOverType(typesToFind))
+                        return true;
+                }
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Replace some of the types in a type's construction with a new set of types. This function does not 
+        /// support any situation where there is an instantiated generic that is not represented by an 
+        /// InstantiatedType. Does not replace the open generics that may be instantiated over in this type.
+        /// 
+        /// For instance, Given MyType&lt;object, int[]&gt;,
+        ///  an array of types to replace such as {int,object}, and 
+        ///  an array of replacement types such as {string,__Canon}.
+        ///  The result shall be MyType&lt;__Canon, string[]&gt;
+        /// 
+        /// This function cannot be used to replace MyType in the above example.
+        /// </summary>
+        public static TypeDesc ReplaceTypesInConstructionOfType(this TypeDesc type, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
+        {
+            int directReplacementIndex = Array.IndexOf(typesToReplace, type);
+
+            if (directReplacementIndex != -1)
+                return replacementTypes[directReplacementIndex];
+
+            if (type.HasInstantiation)
+            {
+                TypeDesc[] newInstantiation = null;
+                Debug.Assert(type is InstantiatedType);
+                int instantiationIndex = 0;
+                for (; instantiationIndex < type.Instantiation.Length; instantiationIndex++)
+                {
+                    TypeDesc oldType = type.Instantiation[instantiationIndex];
+                    TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+                    if ((oldType != newType) || (newInstantiation != null))
+                    {
+                        if (newInstantiation == null)
+                        {
+                            newInstantiation = new TypeDesc[type.Instantiation.Length];
+                            for (int i = 0; i < instantiationIndex; i++)
+                                newInstantiation[i] = type.Instantiation[i];
+                        }
+                        newInstantiation[instantiationIndex] = newType;
+                    }
+                }
+                if (newInstantiation != null)
+                    return type.Context.GetInstantiatedType((MetadataType)type.GetTypeDefinition(), new Instantiation(newInstantiation));
+            }
+            else if (type.IsParameterizedType)
+            {
+                ParameterizedType parameterizedType = (ParameterizedType)type;
+                TypeDesc oldParameter = parameterizedType.ParameterType;
+                TypeDesc newParameter = oldParameter.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+                if (oldParameter != newParameter)
+                {
+                    if (type.IsArray)
+                    {
+                        ArrayType arrayType = (ArrayType)type;
+                        if (arrayType.IsSzArray)
+                            return type.Context.GetArrayType(newParameter);
+                        else
+                            return type.Context.GetArrayType(newParameter, arrayType.Rank);
+                    }
+                    else if (type.IsPointer)
+                    {
+                        return type.Context.GetPointerType(newParameter);
+                    }
+                    else if (type.IsByRef)
+                    {
+                        return type.Context.GetByRefType(newParameter);
+                    }
+                    Debug.Fail("Unknown form of type");
+                }
+            }
+            else if (type.IsFunctionPointer)
+            {
+                MethodSignature oldSig = ((FunctionPointerType)type).Signature;
+                MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(oldSig);
+                sigBuilder.ReturnType = oldSig.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+                for (int paramIndex = 0; paramIndex < oldSig.Length; paramIndex++)
+                    sigBuilder[paramIndex] = oldSig[paramIndex].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+
+                MethodSignature newSig = sigBuilder.ToSignature();
+                if (newSig != oldSig)
+                    return type.Context.GetFunctionPointerType(newSig);
+            }
+
+            return type;
+        }
+
+        /// <summary>
+        /// Replace some of the types in a method's construction with a new set of types.
+        /// Does not replace the open generics that may be instantiated over in this type.
+        /// 
+        /// For instance, Given MyType&lt;object, int[]&gt;.Function&lt;short&gt;(),
+        ///  an array of types to replace such as {int,short}, and 
+        ///  an array of replacement types such as {string,char}.
+        ///  The result shall be MyType&lt;object, string[]&gt;.Function&lt;char&gt;
+        /// 
+        /// This function cannot be used to replace MyType in the above example.
+        /// </summary>
+        public static MethodDesc ReplaceTypesInConstructionOfMethod(this MethodDesc method, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
+        {
+            TypeDesc newOwningType = method.OwningType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+            MethodDesc methodOnOwningType = null;
+            bool owningTypeChanged = false;
+            if (newOwningType == method.OwningType)
+            {
+                methodOnOwningType = method.GetMethodDefinition();
+            }
+            else
+            {
+                methodOnOwningType = TypeSystemHelpers.FindMethodOnExactTypeWithMatchingTypicalMethod(newOwningType, method);
+                owningTypeChanged = true;
+            }
+
+            MethodDesc result;
+            if (!method.HasInstantiation)
+            {
+                result = methodOnOwningType;
+            }
+            else
+            {
+                Debug.Assert(method is InstantiatedMethod);
+
+                TypeDesc[] newInstantiation = null;
+                int instantiationIndex = 0;
+                for (; instantiationIndex < method.Instantiation.Length; instantiationIndex++)
+                {
+                    TypeDesc oldType = method.Instantiation[instantiationIndex];
+                    TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+                    if ((oldType != newType) || (newInstantiation != null))
+                    {
+                        if (newInstantiation == null)
+                        {
+                            newInstantiation = new TypeDesc[method.Instantiation.Length];
+                            for (int i = 0; i < instantiationIndex; i++)
+                                newInstantiation[i] = method.Instantiation[i];
+                        }
+                        newInstantiation[instantiationIndex] = newType;
+                    }
+                }
+
+                if (newInstantiation != null)
+                    result = method.Context.GetInstantiatedMethod(methodOnOwningType, new Instantiation(newInstantiation));
+                else if (owningTypeChanged)
+                    result = method.Context.GetInstantiatedMethod(methodOnOwningType, method.Instantiation);
+                else
+                    result = method;
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs
new file mode 100644 (file)
index 0000000..2e66f33
--- /dev/null
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Internal.NativeFormat;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+    public class UniversalCanonLayoutAlgorithm : FieldLayoutAlgorithm
+    {
+        public static UniversalCanonLayoutAlgorithm Instance = new UniversalCanonLayoutAlgorithm();
+
+        private UniversalCanonLayoutAlgorithm() { }
+
+        public override bool ComputeContainsGCPointers(DefType type)
+        {
+            // This should never be called
+            throw new NotSupportedException();
+        }
+
+        public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
+        {
+            return new ComputedInstanceFieldLayout()
+            {
+                FieldSize = LayoutInt.Indeterminate,
+                FieldAlignment = LayoutInt.Indeterminate,
+                ByteCountUnaligned = LayoutInt.Indeterminate,
+                ByteCountAlignment = LayoutInt.Indeterminate,
+                Offsets = Array.Empty<FieldAndOffset>()
+            };
+        }
+
+        public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind)
+        {
+            return new ComputedStaticFieldLayout()
+            {
+                NonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+                GcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+                ThreadNonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+                ThreadGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+                Offsets = Array.Empty<FieldAndOffset>()
+            };
+        }
+
+        public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
+        {
+            return ValueTypeShapeCharacteristics.None;
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs
new file mode 100644 (file)
index 0000000..1ac2256
--- /dev/null
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Internal.TypeSystem.Ecma;
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class ArchitectureSpecificFieldLayoutTests
+    {
+        TestTypeSystemContext _contextX86;
+        ModuleDesc _testModuleX86;
+        TestTypeSystemContext _contextX64;
+        ModuleDesc _testModuleX64;
+        TestTypeSystemContext _contextARM;
+        ModuleDesc _testModuleARM;
+
+        public ArchitectureSpecificFieldLayoutTests()
+        {
+            _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly");
+            _contextX64.SetSystemModule(systemModuleX64);
+
+            _testModuleX64 = systemModuleX64;
+
+            _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM);
+            var systemModuleARM = _contextARM.CreateModuleForSimpleName("CoreTestAssembly");
+            _contextARM.SetSystemModule(systemModuleARM);
+
+            _testModuleARM = systemModuleARM;
+
+            _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86);
+            var systemModuleX86 = _contextX86.CreateModuleForSimpleName("CoreTestAssembly");
+            _contextX86.SetSystemModule(systemModuleX86);
+
+            _testModuleX86 = systemModuleX86;
+        }
+
+        [Fact]
+        public void TestInstanceLayoutDoubleBool()
+        {
+            MetadataType tX64 = _testModuleX64.GetType("Sequential", "ClassDoubleBool");
+            MetadataType tX86 = _testModuleX86.GetType("Sequential", "ClassDoubleBool");
+            MetadataType tARM = _testModuleARM.GetType("Sequential", "ClassDoubleBool");
+
+            Assert.Equal(0x8, tX64.InstanceByteAlignment.AsInt);
+            Assert.Equal(0x8, tARM.InstanceByteAlignment.AsInt);
+            Assert.Equal(0x4, tX86.InstanceByteAlignment.AsInt);
+
+            Assert.Equal(0x11, tX64.InstanceByteCountUnaligned.AsInt);
+            Assert.Equal(0x11, tARM.InstanceByteCountUnaligned.AsInt);
+            Assert.Equal(0x11, tX86.InstanceByteCountUnaligned.AsInt);
+
+            Assert.Equal(0x18, tX64.InstanceByteCount.AsInt);
+            Assert.Equal(0x18, tARM.InstanceByteCount.AsInt);
+            Assert.Equal(0x14, tX86.InstanceByteCount.AsInt);
+        }
+
+        [Fact]
+        public void TestInstanceLayoutBoolDoubleBool()
+        {
+            MetadataType tX64 = _testModuleX64.GetType("Sequential", "ClassBoolDoubleBool");
+            MetadataType tX86 = _testModuleX86.GetType("Sequential", "ClassBoolDoubleBool");
+            MetadataType tARM = _testModuleARM.GetType("Sequential", "ClassBoolDoubleBool");
+
+            Assert.Equal(0x8, tX64.InstanceByteAlignment.AsInt);
+            Assert.Equal(0x8, tARM.InstanceByteAlignment.AsInt);
+            Assert.Equal(0x4, tX86.InstanceByteAlignment.AsInt);
+
+            Assert.Equal(0x19, tX64.InstanceByteCountUnaligned.AsInt);
+            Assert.Equal(0x11, tARM.InstanceByteCountUnaligned.AsInt);
+            Assert.Equal(0x11, tX86.InstanceByteCountUnaligned.AsInt);
+
+            Assert.Equal(0x20, tX64.InstanceByteCount.AsInt);
+            Assert.Equal(0x18, tARM.InstanceByteCount.AsInt);
+            Assert.Equal(0x14, tX86.InstanceByteCount.AsInt);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs
new file mode 100644 (file)
index 0000000..c049418
--- /dev/null
@@ -0,0 +1,327 @@
+// Licensed to the.NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class CanonicalizationTests
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        private MetadataType _referenceType;
+        private MetadataType _otherReferenceType;
+        private MetadataType _structType;
+        private MetadataType _otherStructType;
+        private MetadataType _genericReferenceType;
+        private MetadataType _genericStructType;
+        private MetadataType _genericReferenceTypeWithThreeParams;
+        private MetadataType _genericStructTypeWithThreeParams;
+
+        public CanonicalizationTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+
+            _referenceType = _testModule.GetType("Canonicalization", "ReferenceType");
+            _otherReferenceType = _testModule.GetType("Canonicalization", "OtherReferenceType");
+            _structType = _testModule.GetType("Canonicalization", "StructType");
+            _otherStructType = _testModule.GetType("Canonicalization", "OtherStructType");
+            _genericReferenceType = _testModule.GetType("Canonicalization", "GenericReferenceType`1");
+            _genericStructType = _testModule.GetType("Canonicalization", "GenericStructType`1");
+            _genericReferenceTypeWithThreeParams = _testModule.GetType("Canonicalization", "GenericReferenceTypeWithThreeParams`3");
+            _genericStructTypeWithThreeParams = _testModule.GetType("Canonicalization", "GenericStructTypeWithThreeParams`3");
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestGenericTypes(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+
+            // Canonical forms of reference type over two different reference types are equivalent
+            var referenceOverReference = _genericReferenceType.MakeInstantiatedType(_referenceType);
+            var referenceOverOtherReference = _genericReferenceType.MakeInstantiatedType(_otherReferenceType);
+            Assert.Same(
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+                referenceOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+                referenceOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            var referenceOverReferenceOverReference = _genericReferenceType.MakeInstantiatedType(referenceOverReference);
+            Assert.Same(
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+                referenceOverReferenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+                referenceOverReferenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            var threeParamReferenceOverS1R1S1 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _referenceType, _structType);
+            var threeParamReferenceOverS1R2S1 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _otherReferenceType, _structType);
+            var threeParamReferenceOverS1R2S2 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _otherReferenceType, _otherStructType);
+            Assert.Same(
+                threeParamReferenceOverS1R1S1.ConvertToCanonForm(CanonicalFormKind.Specific),
+                threeParamReferenceOverS1R2S1.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                threeParamReferenceOverS1R1S1.ConvertToCanonForm(CanonicalFormKind.Universal),
+                threeParamReferenceOverS1R2S1.ConvertToCanonForm(CanonicalFormKind.Universal));
+            Assert.Same(
+                threeParamReferenceOverS1R1S1.ConvertToCanonForm(CanonicalFormKind.Universal),
+                threeParamReferenceOverS1R2S2.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Universal canonical forms of reference type over reference and value types are equivalent
+            var referenceOverStruct = _genericReferenceType.MakeInstantiatedType(_structType);
+            var referenceOverOtherStruct = _genericReferenceType.MakeInstantiatedType(_otherStructType);
+            Assert.Same(
+                referenceOverStruct.ConvertToCanonForm(CanonicalFormKind.Universal),
+                referenceOverOtherStruct.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Canon forms of reference type instantiated over a generic valuetype over any reference type
+            var genericStructOverReference = _genericStructType.MakeInstantiatedType(_referenceType);
+            var genericStructOverOtherReference = _genericStructType.MakeInstantiatedType(_otherReferenceType);
+            var referenceOverGenericStructOverReference = _genericReferenceType.MakeInstantiatedType(genericStructOverReference);
+            var referenceOverGenericStructOverOtherReference = _genericReferenceType.MakeInstantiatedType(genericStructOverOtherReference);
+            Assert.Same(
+                referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+                referenceOverGenericStructOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.NotSame(
+                referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+                referenceOverGenericStructOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+            Assert.Same(
+                referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Canon of a type instantiated over a signature variable is the same type when just canonicalizing as specific,
+            // but the universal canon form when performing universal canonicalization.
+            var genericStructOverSignatureVariable = _genericStructType.MakeInstantiatedType(_context.GetSignatureVariable(0, false));
+            Assert.Same(
+                genericStructOverSignatureVariable,
+                genericStructOverSignatureVariable.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.NotSame(
+                genericStructOverSignatureVariable,
+                genericStructOverSignatureVariable.ConvertToCanonForm(CanonicalFormKind.Universal));
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestGenericTypesNegative(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+
+            // Two different types instantiated over the same type are not canonically equivalent
+            var referenceOverReference = _genericReferenceType.MakeInstantiatedType(_referenceType);
+            var structOverReference = _genericStructType.MakeInstantiatedType(_referenceType);
+            Assert.NotSame(
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+                structOverReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.NotSame(
+                referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+                structOverReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Specific canonical forms of reference type over reference and value types are not equivalent
+            var referenceOverStruct = _genericReferenceType.MakeInstantiatedType(_structType);
+            var referenceOverOtherStruct = _genericReferenceType.MakeInstantiatedType(_otherStructType);
+            Assert.NotSame(
+                referenceOverStruct.ConvertToCanonForm(CanonicalFormKind.Specific),
+                referenceOverOtherStruct.ConvertToCanonForm(CanonicalFormKind.Specific));
+
+            var threeParamReferenceOverS1R2S1 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _otherReferenceType, _structType);
+            var threeParamReferenceOverS1R2S2 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _otherReferenceType, _otherStructType);
+            Assert.NotSame(
+                threeParamReferenceOverS1R2S1.ConvertToCanonForm(CanonicalFormKind.Specific),
+                threeParamReferenceOverS1R2S2.ConvertToCanonForm(CanonicalFormKind.Specific));
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestArrayTypes(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+
+            // Generic type instantiated over an array has the same canonical form as generic type over any other reference type
+            var genericStructOverArrayOfInt = _genericStructType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32).MakeArrayType());
+            var genericStructOverReferenceType = _genericStructType.MakeInstantiatedType(_referenceType);
+            Assert.Same(
+                genericStructOverArrayOfInt.ConvertToCanonForm(CanonicalFormKind.Specific),
+                genericStructOverReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                genericStructOverArrayOfInt.ConvertToCanonForm(CanonicalFormKind.Universal),
+                genericStructOverReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Canonical form of SzArray and Multidim array are not the same
+            var arrayOfReferenceType = _referenceType.MakeArrayType();
+            var mdArrayOfReferenceType = _referenceType.MakeArrayType(1);
+            Assert.NotSame(
+                arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific),
+                mdArrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.NotSame(
+                arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal),
+                mdArrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Canonical forms of arrays over different reference types are same
+            var arrayOfOtherReferenceType = _otherReferenceType.MakeArrayType();
+            Assert.Same(
+                arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific),
+                arrayOfOtherReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal),
+                arrayOfOtherReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+            // Canonical forms of arrays of value types are only same for universal canon form
+            var arrayOfStruct = _structType.MakeArrayType();
+            Assert.NotSame(
+                arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific),
+                arrayOfStruct.ConvertToCanonForm(CanonicalFormKind.Specific));
+            Assert.Same(
+                arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal),
+                arrayOfStruct.ConvertToCanonForm(CanonicalFormKind.Universal));
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestMethodsOnGenericTypes(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+
+            var referenceOverReference = _genericReferenceType.MakeInstantiatedType(_referenceType);
+            var referenceOverOtherReference = _genericReferenceType.MakeInstantiatedType(_otherReferenceType);
+            Assert.NotSame(
+                referenceOverReference.GetMethod("Method", null),
+                referenceOverOtherReference.GetMethod("Method", null));
+            Assert.Same(
+                referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                referenceOverOtherReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                referenceOverOtherReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+            var referenceOverStruct = _genericReferenceType.MakeInstantiatedType(_structType);
+            Assert.NotSame(
+                referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                referenceOverStruct.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                referenceOverStruct.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+            Assert.Same(
+                referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_otherReferenceType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_otherReferenceType).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+            Assert.NotSame(
+                referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+            Assert.NotSame(
+                referenceOverStruct.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                referenceOverStruct.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+            Assert.NotSame(
+                referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType),
+                referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestArrayMethods(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+
+            var arrayOfReferenceType = _referenceType.MakeArrayType(1);
+            var arrayOfOtherReferenceType = _otherReferenceType.MakeArrayType(1);
+
+            Assert.Same(
+                arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                arrayOfOtherReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                arrayOfOtherReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+            var arrayOfStruct = _structType.MakeArrayType(1);
+
+            Assert.NotSame(
+                arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+                arrayOfStruct.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+            Assert.Same(
+                arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+                arrayOfStruct.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestUpgradeToUniversalCanon(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+
+            var gstOverUniversalCanon = _genericStructType.MakeInstantiatedType(_context.UniversalCanonType);
+            var grtOverRtRtStOverUniversal = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _referenceType, _referenceType, gstOverUniversalCanon);
+            var grtOverRtRtStOverUniversalCanon = grtOverRtRtStOverUniversal.ConvertToCanonForm(CanonicalFormKind.Specific);
+
+            // Specific form gets upgraded to universal in the presence of universal canon.
+            // GenericReferenceTypeWithThreeParams<ReferenceType, ReferenceType, GenericStructType<__UniversalCanon>> is
+            // GenericReferenceTypeWithThreeParams<T__UniversalCanon, U__UniversalCanon, V__UniversalCanon>
+            Assert.Same(_context.UniversalCanonType, grtOverRtRtStOverUniversalCanon.Instantiation[0]);
+            Assert.Same(_context.UniversalCanonType, grtOverRtRtStOverUniversalCanon.Instantiation[2]);
+        }
+
+        [Theory]
+        [InlineData(CanonicalizationMode.Standard)]
+        [InlineData(CanonicalizationMode.RuntimeDetermined)]
+        public void TestDowngradeFromUniversalCanon(CanonicalizationMode algorithmType)
+        {
+            _context.CanonMode = algorithmType;
+            var grtOverUniversalCanon = _genericReferenceType.MakeInstantiatedType(_context.UniversalCanonType);
+            var gstOverGrtOverUniversalCanon = _genericStructType.MakeInstantiatedType(grtOverUniversalCanon);
+            var gstOverCanon = _genericStructType.MakeInstantiatedType(_context.CanonType);
+            Assert.Same(gstOverCanon, gstOverGrtOverUniversalCanon.ConvertToCanonForm(CanonicalFormKind.Specific));
+
+            var gstOverGstOverGrtOverUniversalCanon = _genericStructType.MakeInstantiatedType(gstOverGrtOverUniversalCanon);
+            var gstOverGstOverCanon = _genericStructType.MakeInstantiatedType(gstOverCanon);
+            Assert.Same(gstOverGstOverCanon, gstOverGstOverGrtOverUniversalCanon.ConvertToCanonForm(CanonicalFormKind.Specific));
+        }
+
+        [Fact]
+        public void TestCanonicalizationOfRuntimeDeterminedUniversalGeneric()
+        {
+            var gstOverUniversalCanon = _genericStructType.MakeInstantiatedType(_context.UniversalCanonType);
+            var rdtUniversalCanon = (RuntimeDeterminedType)gstOverUniversalCanon.ConvertToSharedRuntimeDeterminedForm().Instantiation[0];
+            Assert.Same(_context.UniversalCanonType, rdtUniversalCanon.CanonicalType);
+
+            var gstOverRdtUniversalCanon = _genericStructType.MakeInstantiatedType(rdtUniversalCanon);
+            Assert.Same(gstOverUniversalCanon, gstOverRdtUniversalCanon.ConvertToCanonForm(CanonicalFormKind.Specific));
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs
new file mode 100644 (file)
index 0000000..1d81c81
--- /dev/null
@@ -0,0 +1,219 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class CastingTests
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        public CastingTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestCastingInHierarchy()
+        {
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+            TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            TypeDesc uintType = _context.GetWellKnownType(WellKnownType.UInt32);
+
+            Assert.True(stringType.CanCastTo(objectType));
+            Assert.True(objectType.CanCastTo(objectType));
+            Assert.True(intType.CanCastTo(objectType));
+
+            Assert.False(objectType.CanCastTo(stringType));
+            Assert.False(intType.CanCastTo(uintType));
+            Assert.False(uintType.CanCastTo(intType));
+        }
+
+        [Fact]
+        public void TestInterfaceCasting()
+        {
+            TypeDesc iFooType = _testModule.GetType("Casting", "IFoo");
+            TypeDesc classImplementingIFooType =
+                _testModule.GetType("Casting", "ClassImplementingIFoo");
+            TypeDesc classImplementingIFooIndirectlyType =
+                _testModule.GetType("Casting", "ClassImplementingIFooIndirectly");
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            Assert.True(classImplementingIFooType.CanCastTo(iFooType));
+            Assert.True(classImplementingIFooIndirectlyType.CanCastTo(iFooType));
+            Assert.True(iFooType.CanCastTo(objectType));
+
+            Assert.False(objectType.CanCastTo(iFooType));
+        }
+        
+        [Fact]
+        public void TestSameSizeArrayTypeCasting()
+        {
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            TypeDesc uintType = _context.GetWellKnownType(WellKnownType.UInt32);
+            TypeDesc byteType = _context.GetWellKnownType(WellKnownType.Byte);
+            TypeDesc sbyteType = _context.GetWellKnownType(WellKnownType.SByte);
+            TypeDesc intPtrType = _context.GetWellKnownType(WellKnownType.IntPtr);
+            TypeDesc ulongType = _context.GetWellKnownType(WellKnownType.UInt64);
+
+            TypeDesc doubleType = _context.GetWellKnownType(WellKnownType.Double);
+            TypeDesc boolType = _context.GetWellKnownType(WellKnownType.Boolean);
+
+            TypeDesc intBasedEnumType = _testModule.GetType("Casting", "IntBasedEnum");
+            TypeDesc uintBasedEnumType = _testModule.GetType("Casting", "UIntBasedEnum");
+            TypeDesc shortBasedEnumType = _testModule.GetType("Casting", "ShortBasedEnum");
+
+            Assert.True(intType.MakeArrayType().CanCastTo(uintType.MakeArrayType()));
+            Assert.True(intType.MakeArrayType().CanCastTo(uintType.MakeArrayType(1)));
+            Assert.False(intType.CanCastTo(uintType));
+
+            Assert.True(byteType.MakeArrayType().CanCastTo(sbyteType.MakeArrayType()));
+            Assert.False(byteType.CanCastTo(sbyteType));
+
+            Assert.True(intPtrType.MakeArrayType().CanCastTo(ulongType.MakeArrayType()));
+            Assert.False(intPtrType.CanCastTo(ulongType));
+
+            // These are same size, but not allowed to cast
+            Assert.False(doubleType.MakeArrayType().CanCastTo(ulongType.MakeArrayType()));
+            Assert.False(boolType.MakeArrayType().CanCastTo(byteType.MakeArrayType()));
+
+            Assert.True(intBasedEnumType.MakeArrayType().CanCastTo(uintType.MakeArrayType()));
+            Assert.True(intBasedEnumType.MakeArrayType().CanCastTo(uintBasedEnumType.MakeArrayType()));
+            Assert.False(shortBasedEnumType.MakeArrayType().CanCastTo(intType.MakeArrayType()));
+        }
+
+        [Fact]
+        public void TestArrayInterfaceCasting()
+        {
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            MetadataType iListType = _context.SystemModule.GetType("System.Collections", "IList");
+            MetadataType iListOfTType = _context.SystemModule.GetType("System.Collections.Generic", "IList`1");
+
+            InstantiatedType iListOfIntType = iListOfTType.MakeInstantiatedType(intType);
+            TypeDesc intSzArrayType = intType.MakeArrayType();
+            TypeDesc intArrayType = intType.MakeArrayType(1);
+
+            Assert.True(intSzArrayType.CanCastTo(iListOfIntType));
+            Assert.True(intSzArrayType.CanCastTo(iListType));
+
+            Assert.False(intArrayType.CanCastTo(iListOfIntType));
+            Assert.True(intArrayType.CanCastTo(iListType));
+        }
+
+        [Fact]
+        public void TestArrayCasting()
+        {
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+            TypeDesc arrayType = _context.GetWellKnownType(WellKnownType.Array);
+            TypeDesc intSzArrayType = intType.MakeArrayType();
+            TypeDesc intArray1Type = intType.MakeArrayType(1);
+            TypeDesc intArray2Type = intType.MakeArrayType(2);
+            TypeDesc stringSzArrayType = stringType.MakeArrayType();
+            TypeDesc objectSzArrayType = objectType.MakeArrayType();
+
+            Assert.True(intSzArrayType.CanCastTo(intArray1Type));
+            Assert.False(intArray1Type.CanCastTo(intSzArrayType));
+
+            Assert.False(intArray1Type.CanCastTo(intArray2Type));
+
+            Assert.True(intSzArrayType.CanCastTo(arrayType));
+            Assert.True(intArray1Type.CanCastTo(arrayType));
+
+            Assert.True(stringSzArrayType.CanCastTo(objectSzArrayType));
+            Assert.False(intSzArrayType.CanCastTo(objectSzArrayType));
+        }
+
+        [Fact]
+        public void TestGenericParameterCasting()
+        {
+            TypeDesc paramWithNoConstraint =
+                _testModule.GetType("Casting", "ClassWithNoConstraint`1").Instantiation[0];
+            TypeDesc paramWithValueTypeConstraint =
+                _testModule.GetType("Casting", "ClassWithValueTypeConstraint`1").Instantiation[0];
+            TypeDesc paramWithInterfaceConstraint =
+                _testModule.GetType("Casting", "ClassWithInterfaceConstraint`1").Instantiation[0];
+
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+            TypeDesc valueTypeType = _context.GetWellKnownType(WellKnownType.ValueType);
+            TypeDesc iFooType = _testModule.GetType("Casting", "IFoo");
+            TypeDesc classImplementingIFooType = _testModule.GetType("Casting", "ClassImplementingIFoo");
+            TypeDesc classImplementingIFooIndirectlyType =
+                _testModule.GetType("Casting", "ClassImplementingIFooIndirectly");
+
+            Assert.True(paramWithNoConstraint.CanCastTo(objectType));
+            Assert.False(paramWithNoConstraint.CanCastTo(valueTypeType));
+            Assert.False(paramWithNoConstraint.CanCastTo(iFooType));
+            Assert.False(paramWithNoConstraint.CanCastTo(classImplementingIFooType));
+
+            Assert.True(paramWithValueTypeConstraint.CanCastTo(objectType));
+            Assert.True(paramWithValueTypeConstraint.CanCastTo(valueTypeType));
+            Assert.False(paramWithValueTypeConstraint.CanCastTo(iFooType));
+            Assert.False(paramWithValueTypeConstraint.CanCastTo(classImplementingIFooType));
+
+            Assert.True(paramWithInterfaceConstraint.CanCastTo(objectType));
+            Assert.False(paramWithInterfaceConstraint.CanCastTo(valueTypeType));
+            Assert.True(paramWithInterfaceConstraint.CanCastTo(iFooType));
+            Assert.False(paramWithInterfaceConstraint.CanCastTo(classImplementingIFooType));
+        }
+
+        [Fact]
+        public void TestVariantCasting()
+        {
+            TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+            TypeDesc exceptionType = _context.GetWellKnownType(WellKnownType.Exception);
+
+            TypeDesc stringSzArrayType = stringType.MakeArrayType();
+
+            MetadataType iEnumerableOfTType =
+                _context.SystemModule.GetType("System.Collections.Generic", "IEnumerable`1");
+            InstantiatedType iEnumerableOfObjectType = iEnumerableOfTType.MakeInstantiatedType(objectType);
+            InstantiatedType iEnumerableOfExceptionType = iEnumerableOfTType.MakeInstantiatedType(exceptionType);
+
+            Assert.True(stringSzArrayType.CanCastTo(iEnumerableOfObjectType));
+            Assert.False(stringSzArrayType.CanCastTo(iEnumerableOfExceptionType));
+
+            MetadataType iContravariantOfTType = _testModule.GetType("Casting", "IContravariant`1");
+            InstantiatedType iContravariantOfObjectType = iContravariantOfTType.MakeInstantiatedType(objectType);
+            InstantiatedType iEnumerableOfStringType = iEnumerableOfTType.MakeInstantiatedType(stringType);
+
+            Assert.True(iContravariantOfObjectType.CanCastTo(objectType));
+            Assert.True(iEnumerableOfStringType.CanCastTo(objectType));
+        }
+
+        [Fact]
+        public void TestNullableCasting()
+        {
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            MetadataType nullableType = (MetadataType)_context.GetWellKnownType(WellKnownType.Nullable);
+            TypeDesc nullableOfIntType = nullableType.MakeInstantiatedType(intType);
+
+            Assert.True(intType.CanCastTo(nullableOfIntType));
+        }
+
+        [Fact]
+        public void TestRecursiveCanCast()
+        {
+            // Tests the stack overflow protection in CanCastTo
+
+            TypeDesc classWithRecursiveImplementation = _testModule.GetType("Casting", "ClassWithRecursiveImplementation");
+            MetadataType iContravariantOfTType = (MetadataType)_testModule.GetType("Casting", "IContravariant`1");
+
+            TypeDesc testType = iContravariantOfTType.MakeInstantiatedType(classWithRecursiveImplementation);
+
+            Assert.False(classWithRecursiveImplementation.CanCastTo(testType));
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs
new file mode 100644 (file)
index 0000000..bcb9856
--- /dev/null
@@ -0,0 +1,359 @@
+// Licensed to the.NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class ConstraintsValidationTest
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        private MetadataType _iNonGenType;
+        private MetadataType _iGenType;
+        private MetadataType _arg1Type;
+        private MetadataType _arg2Type;
+        private MetadataType _arg3Type;
+        private MetadataType _structArgWithDefaultCtorType;
+        private MetadataType _structArgWithoutDefaultCtorType;
+        private MetadataType _classArgWithDefaultCtorType;
+        private MetadataType _classArgWithPrivateDefaultCtorType;
+        private MetadataType _abstractClassArgWithDefaultCtorType;
+        private MetadataType _classArgWithoutDefaultCtorType;
+        private MetadataType _referenceTypeConstraintType;
+        private MetadataType _defaultConstructorConstraintType;
+        private MetadataType _notNullableValueTypeConstraintType;
+        private MetadataType _simpleTypeConstraintType;
+        private MetadataType _doubleSimpleTypeConstraintType;
+        private MetadataType _simpleGenericConstraintType;
+        private MetadataType _complexGenericConstraint1Type;
+        private MetadataType _complexGenericConstraint2Type;
+        private MetadataType _complexGenericConstraint3Type;
+        private MetadataType _complexGenericConstraint4Type;
+        private MetadataType _multipleConstraintsType;
+
+        private MetadataType _genericMethodsType;
+        private MethodDesc _simpleGenericConstraintMethod;
+        private MethodDesc _complexGenericConstraintMethod;
+
+        public ConstraintsValidationTest()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+            
+            _testModule = systemModule;
+
+            _iNonGenType = _testModule.GetType("GenericConstraints", "INonGen");
+            _iGenType = _testModule.GetType("GenericConstraints", "IGen`1");
+            _arg1Type = _testModule.GetType("GenericConstraints", "Arg1");
+            _arg2Type = _testModule.GetType("GenericConstraints", "Arg2`1");
+            _arg3Type = _testModule.GetType("GenericConstraints", "Arg3`1");
+            _structArgWithDefaultCtorType = _testModule.GetType("GenericConstraints", "StructArgWithDefaultCtor");
+            _structArgWithoutDefaultCtorType = _testModule.GetType("GenericConstraints", "StructArgWithoutDefaultCtor");
+            _classArgWithDefaultCtorType = _testModule.GetType("GenericConstraints", "ClassArgWithDefaultCtor");
+            _classArgWithPrivateDefaultCtorType = _testModule.GetType("GenericConstraints", "ClassArgWithPrivateDefaultCtor");
+            _abstractClassArgWithDefaultCtorType = _testModule.GetType("GenericConstraints", "AbstractClassArgWithDefaultCtor");
+            _classArgWithoutDefaultCtorType = _testModule.GetType("GenericConstraints", "ClassArgWithoutDefaultCtor");
+
+            _referenceTypeConstraintType = _testModule.GetType("GenericConstraints", "ReferenceTypeConstraint`1");
+            _defaultConstructorConstraintType = _testModule.GetType("GenericConstraints", "DefaultConstructorConstraint`1");
+            _notNullableValueTypeConstraintType = _testModule.GetType("GenericConstraints", "NotNullableValueTypeConstraint`1");
+            _simpleTypeConstraintType = _testModule.GetType("GenericConstraints", "SimpleTypeConstraint`1");
+            _doubleSimpleTypeConstraintType = _testModule.GetType("GenericConstraints", "DoubleSimpleTypeConstraint`1");
+            _simpleGenericConstraintType = _testModule.GetType("GenericConstraints", "SimpleGenericConstraint`2");
+            _complexGenericConstraint1Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint1`2");
+            _complexGenericConstraint2Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint2`2");
+            _complexGenericConstraint3Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint3`2");
+            _complexGenericConstraint4Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint4`2");
+            _multipleConstraintsType = _testModule.GetType("GenericConstraints", "MultipleConstraints`2");
+
+            _genericMethodsType = _testModule.GetType("GenericConstraints", "GenericMethods");
+            _simpleGenericConstraintMethod = _genericMethodsType.GetMethod("SimpleGenericConstraintMethod", null);
+            _complexGenericConstraintMethod = _genericMethodsType.GetMethod("ComplexGenericConstraintMethod", null);
+        }
+
+        [Fact]
+        public void TestTypeConstraints()
+        {
+            TypeDesc instantiatedType;
+            MethodDesc instantiatedMethod;
+
+            MetadataType arg2OfInt = _arg2Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+            MetadataType arg2OfBool = _arg2Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Boolean));
+            MetadataType arg2OfObject = _arg2Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+
+            // ReferenceTypeConstraint
+            {
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_arg1Type);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_iNonGenType);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+                Assert.False(instantiatedType.CheckConstraints());
+            }
+
+            // DefaultConstructorConstraint
+            {
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_arg1Type);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_classArgWithDefaultCtorType);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_classArgWithPrivateDefaultCtorType);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_abstractClassArgWithDefaultCtorType);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_classArgWithoutDefaultCtorType);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                // Structs always have implicit default constructors
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_structArgWithoutDefaultCtorType);
+                Assert.True(instantiatedType.CheckConstraints());
+            }
+
+            // NotNullableValueTypeConstraint
+            {
+                instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_arg1Type);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                MetadataType nullable = (MetadataType)_context.GetWellKnownType(WellKnownType.Nullable);
+                MetadataType nullableOfInt = nullable.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+
+                instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(nullableOfInt);
+                Assert.False(instantiatedType.CheckConstraints());
+            }
+
+            // Special constraints instantiated with generic parameter
+            {
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_referenceTypeConstraintType.Instantiation[0]);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_defaultConstructorConstraintType.Instantiation[0]);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_notNullableValueTypeConstraintType.Instantiation[0]);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_notNullableValueTypeConstraintType.Instantiation[0]);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_arg2Type.Instantiation[0]);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_arg2Type.Instantiation[0]);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_arg2Type.Instantiation[0]);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_simpleTypeConstraintType.Instantiation[0]);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_simpleTypeConstraintType.Instantiation[0]);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_simpleTypeConstraintType.Instantiation[0]);
+                Assert.False(instantiatedType.CheckConstraints());
+            }
+
+            // SimpleTypeConstraint and DoubleSimpleTypeConstraint
+            foreach(var genType in new MetadataType[] { _simpleTypeConstraintType , _doubleSimpleTypeConstraintType })
+            {
+                instantiatedType = genType.MakeInstantiatedType(_arg1Type);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = genType.MakeInstantiatedType(_iNonGenType);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = genType.MakeInstantiatedType(_classArgWithDefaultCtorType);
+                Assert.False(instantiatedType.CheckConstraints());
+            }
+
+            // SimpleGenericConstraint
+            {
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _arg1Type);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _iNonGenType);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_classArgWithDefaultCtorType, _classArgWithoutDefaultCtorType);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.ValueType));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.ValueType));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.UInt16), _context.GetWellKnownType(WellKnownType.UInt32));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.UInt16), _context.GetWellKnownType(WellKnownType.ValueType));
+                Assert.True(instantiatedType.CheckConstraints());
+            }
+
+            // ComplexGenericConstraint1
+            {
+                instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(_arg1Type, _arg1Type /* uninteresting */);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(arg2OfInt, _arg1Type /* uninteresting */);
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(arg2OfBool, _arg1Type /* uninteresting */);
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(arg2OfObject, _arg1Type /* uninteresting */);
+                Assert.False(instantiatedType.CheckConstraints());
+            }
+
+            // ComplexGenericConstraint2
+            {
+                MetadataType arg2OfArg2OfInt = _arg2Type.MakeInstantiatedType(arg2OfInt);
+                MetadataType arg2OfArg2OfBool = _arg2Type.MakeInstantiatedType(arg2OfBool);
+                MetadataType arg2OfArg2OfObject = _arg2Type.MakeInstantiatedType(arg2OfObject);
+
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.Int32));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfInt, _context.GetWellKnownType(WellKnownType.Int32));
+                Assert.True(instantiatedType.CheckConstraints());
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfBool, _context.GetWellKnownType(WellKnownType.Int32));
+                Assert.False(instantiatedType.CheckConstraints());
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfObject, _context.GetWellKnownType(WellKnownType.Int32));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfInt, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.False(instantiatedType.CheckConstraints());
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfBool, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.False(instantiatedType.CheckConstraints());
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfObject, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfInt, _context.GetWellKnownType(WellKnownType.Boolean));
+                Assert.False(instantiatedType.CheckConstraints());
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfBool, _context.GetWellKnownType(WellKnownType.Boolean));
+                Assert.True(instantiatedType.CheckConstraints());
+                instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfObject, _context.GetWellKnownType(WellKnownType.Boolean));
+                Assert.False(instantiatedType.CheckConstraints());
+            }
+
+            // ComplexGenericConstraint3
+            {
+                MetadataType igenOfObject = _iGenType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+
+                instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(igenOfObject, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                // Variance-compatible instantiation argument
+                instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(igenOfObject, _context.GetWellKnownType(WellKnownType.String));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                // Type that implements the interface
+                var arg3OfObject = _arg3Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+                instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(arg3OfObject, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.True(instantiatedType.CheckConstraints());
+
+                // Type that implements a variant compatible interface
+                instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(arg3OfObject, _context.GetWellKnownType(WellKnownType.String));
+                Assert.True(instantiatedType.CheckConstraints());
+            }
+
+            // Constraints requiring InstantiationContext
+            {
+                // Instantiate type / method with own generic parameters
+                instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(_complexGenericConstraint3Type.Instantiation[0], _complexGenericConstraint3Type.Instantiation[1]);
+                Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(instantiatedType.Instantiation, default(Instantiation))));
+
+                instantiatedType = _complexGenericConstraint4Type.MakeInstantiatedType(_complexGenericConstraint4Type.Instantiation[0], _complexGenericConstraint4Type.Instantiation[1]);
+                Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(instantiatedType.Instantiation, default(Instantiation))));
+
+                instantiatedMethod = _simpleGenericConstraintMethod.MakeInstantiatedMethod(_simpleGenericConstraintMethod.Instantiation);
+                Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(default(Instantiation), instantiatedMethod.Instantiation)));
+
+                instantiatedMethod = _complexGenericConstraintMethod.MakeInstantiatedMethod(_complexGenericConstraintMethod.Instantiation);
+                Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(default(Instantiation), instantiatedMethod.Instantiation)));
+
+                // Instantiate type with generic parameters of method
+                instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_simpleGenericConstraintMethod.Instantiation);
+                Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(default(Instantiation), _simpleGenericConstraintMethod.Instantiation)));
+
+                instantiatedType = _complexGenericConstraint4Type.MakeInstantiatedType(_complexGenericConstraintMethod.Instantiation);
+                Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(default(Instantiation), _complexGenericConstraintMethod.Instantiation)));
+
+                // Instantiate method with generic parameters of type
+                instantiatedMethod = _simpleGenericConstraintMethod.MakeInstantiatedMethod(_simpleGenericConstraintType.Instantiation);
+                Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(_simpleGenericConstraintType.Instantiation, default(Instantiation))));
+
+                instantiatedMethod = _complexGenericConstraintMethod.MakeInstantiatedMethod(_complexGenericConstraint4Type.Instantiation);
+                Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(_complexGenericConstraint4Type.Instantiation, default(Instantiation))));
+            }
+
+            // MultipleConstraints
+            {
+                // Violate the class constraint
+                instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_structArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                // Violate the new() constraint
+                instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_classArgWithoutDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                // Violate the IGen<U> constraint
+                instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.False(instantiatedType.CheckConstraints());
+
+                // Satisfy all constraints
+                instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_classArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
+                Assert.True(instantiatedType.CheckConstraints());
+            }
+
+            // InvalidInstantiationArgs
+            {
+                var pointer = _context.GetWellKnownType(WellKnownType.Int16).MakePointerType();
+                var byref = _context.GetWellKnownType(WellKnownType.Int16).MakeByRefType();
+
+                Assert.False(_iGenType.Instantiation.CheckValidInstantiationArguments());
+
+                instantiatedType = _iGenType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Void));
+                Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+
+                instantiatedType = _iGenType.MakeInstantiatedType(pointer);
+                Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+
+                instantiatedType = _iGenType.MakeInstantiatedType(byref);
+                Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+
+                instantiatedType = _iGenType.MakeInstantiatedType(byref);
+                instantiatedType = _iGenType.MakeInstantiatedType(instantiatedType);
+                Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs
new file mode 100644 (file)
index 0000000..58c5b14
--- /dev/null
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Canonicalization
+{
+    class ReferenceType
+    {
+        void Method()
+        {
+        }
+
+        void GenericMethod<U>()
+        {
+        }
+    }
+
+    class OtherReferenceType
+    {
+    }
+
+    struct StructType
+    {
+        void Method()
+        {
+        }
+
+        void GenericMethod<U>()
+        {
+        }
+    }
+
+    struct OtherStructType
+    {
+    }
+
+    class GenericReferenceType<T>
+    {
+        void Method()
+        {
+        }
+
+        void GenericMethod<U>()
+        {
+        }
+    }
+
+    struct GenericStructType<T>
+    {
+        void Method()
+        {
+        }
+
+        void GenericMethod<U>()
+        {
+        }
+    }
+
+    class GenericReferenceTypeWithThreeParams<T, U, V>
+    {
+    }
+
+    class GenericStructTypeWithThreeParams<T, U, V>
+    {
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs
new file mode 100644 (file)
index 0000000..2ae42bd
--- /dev/null
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Casting
+{
+    interface IFoo { }
+
+    interface IContravariant<in T> { }
+
+    class ClassImplementingIFoo : IFoo { }
+
+    class ClassImplementingIFooIndirectly : ClassImplementingIFoo { }
+
+    enum IntBasedEnum : int { }
+
+    enum UIntBasedEnum : uint { }
+
+    enum ShortBasedEnum : short { }
+
+    class ClassWithNoConstraint<T> { }
+
+    class ClassWithValueTypeConstraint<T> where T : struct { }
+
+    class ClassWithInterfaceConstraint<T> where T : IFoo { }
+
+    class ClassWithRecursiveImplementation : IContravariant<IContravariant<ClassWithRecursiveImplementation>> { }
+}
\ No newline at end of file
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj
new file mode 100644 (file)
index 0000000..4c028c6
--- /dev/null
@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <AssemblyName>CoreTestAssembly</AssemblyName>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <IsCoreAssembly>true</IsCoreAssembly>
+    <SkipTestRun>true</SkipTestRun>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <!-- Don't add references to the netstandard platform since this is a core assembly -->
+    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+    <!-- CSC needs explicit metadata version when it has no core library to reference -->
+    <RuntimeMetadataVersion>v4.0.30319</RuntimeMetadataVersion>
+    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs
new file mode 100644 (file)
index 0000000..7b884ea
--- /dev/null
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 169 // Field 'blah' is never used
+
+namespace GCPointerMap
+{
+    [StructLayout(LayoutKind.Sequential)]
+    class ClassWithArrayFields
+    {
+        int[] a1;
+        string[] a2;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    class ClassWithStringField
+    {
+        static string dummy;
+        int i;
+        string s;
+        bool z;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    struct MixedStruct
+    {
+        public int X;
+        public object Y;
+        public int Z;
+        public byte U;
+        public object V;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    struct Struct4GcPointers
+    {
+        public object o1;
+        public object o2;
+        public object o3;
+        public object o4;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    struct Struct32GcPointers
+    {
+        public Struct4GcPointers x1;
+        public Struct4GcPointers x2;
+        public Struct4GcPointers x3;
+        public Struct4GcPointers x4;
+        public Struct4GcPointers x5;
+        public Struct4GcPointers x6;
+        public Struct4GcPointers x7;
+        public Struct4GcPointers x8;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    struct StructWithSameGCLayoutAsMixedStruct
+    {
+        MixedStruct s;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    struct DoubleMixedStructLayout
+    {
+        StructWithSameGCLayoutAsMixedStruct X;
+        MixedStruct Y;
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    struct ExplicitlyFarPointer
+    {
+        [FieldOffset(0)]
+        object X;
+
+        [FieldOffset(32 * 8)]
+        object Y;
+
+        [FieldOffset(40 * 8)]
+        object Z;
+
+        [FieldOffset(56 * 8)]
+        MixedStruct W;
+    }
+
+    class MixedStaticClass
+    {
+        object dummy1;
+        static object o;
+        static int dummy2;
+        const string dummy3 = "Hello";
+        static StructWithSameGCLayoutAsMixedStruct m1;
+        static MixedStruct m2;
+    }
+
+    class MixedThreadStaticClass
+    {
+        object dummy1;
+        static object dummy2;
+
+        [ThreadStatic]
+        static int i;
+
+        [ThreadStatic]
+        static StructWithSameGCLayoutAsMixedStruct m1;
+
+        [ThreadStatic]
+        static MixedStruct m2;
+
+        [ThreadStatic]
+        static object o;
+
+        [ThreadStatic]
+        static short s;
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs
new file mode 100644 (file)
index 0000000..8af3228
--- /dev/null
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace GenericConstraints
+{
+    public interface INonGen { }
+
+    public interface IGen<in T> { }
+
+    public class Arg1 : INonGen { }
+
+    public class Arg2<T> { }
+
+    public class Arg3<T> : IGen<T> { }
+
+    public struct StructArgWithDefaultCtor { }
+
+    public struct StructArgWithoutDefaultCtor
+    {
+        public StructArgWithoutDefaultCtor(int argument) { }
+    }
+
+    public class ClassArgWithDefaultCtor : IGen<object>
+    {
+        public ClassArgWithDefaultCtor() { }
+    }
+
+    public abstract class AbstractClassArgWithDefaultCtor : IGen<object>
+    {
+        public AbstractClassArgWithDefaultCtor() { }
+    }
+
+    public class ClassArgWithPrivateDefaultCtor : IGen<object>
+    {
+        private ClassArgWithPrivateDefaultCtor() { }
+    }
+
+    public class ClassArgWithoutDefaultCtor : IGen<object>
+    {
+        public ClassArgWithoutDefaultCtor(int argument) { }
+    }
+
+    public class ReferenceTypeConstraint<T> where T : class { }
+
+    public class DefaultConstructorConstraint<T> where T : new() { }
+
+    public class NotNullableValueTypeConstraint<T> where T : struct { }
+
+    public class SimpleTypeConstraint<T> where T : Arg1 { }
+
+    public class DoubleSimpleTypeConstraint<T> where T : Arg1, INonGen { }
+
+    public class SimpleGenericConstraint<T, U> where T : U { }
+
+    public class ComplexGenericConstraint1<T, U> where T : Arg2<int> { }
+
+    public class ComplexGenericConstraint2<T, U> where T : Arg2<Arg2<U>> { }
+
+    public class ComplexGenericConstraint3<T, U> where T : IGen<U> { }
+
+    public class ComplexGenericConstraint4<T, U> where T : U where U : IGen<T> { }
+
+    public class MultipleConstraints<T, U> where T : class, IGen<U>, new() { }
+
+    public class GenericMethods
+    {
+        public static void SimpleGenericConstraintMethod<T, U>() where T : U { }
+
+        public static void ComplexGenericConstraintMethod<T, U>() where T : U where U : IGen<T> { }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericTypes.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericTypes.cs
new file mode 100644 (file)
index 0000000..44bacfa
--- /dev/null
@@ -0,0 +1,96 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+namespace GenericTypes
+{
+    /// <summary>
+    /// Generic class to be used for testing.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public abstract class GenericClass<T>
+    {
+        /// <summary>
+        /// Purpose is to manipulate a method involving a generic parameter in its return type.
+        /// </summary>
+        public abstract T Foo();
+        /// <summary>
+        /// Purpose is to manipulate a method involving a generic parameter in its parameter list.
+        /// </summary>
+        public void Bar(T a)
+        {
+        }
+
+        ~GenericClass()
+        { }
+    }
+
+    public class DerivedGenericClass<T> : GenericClass<T>
+    {
+        public override sealed T Foo()
+        {
+            return default(T);
+        }
+    }
+    /// <summary>
+    /// Generic class with multiple parameters to be used for testing.
+    /// </summary>
+    public class TwoParamGenericClass<T,U>
+    {
+        /// <summary>
+        /// Purpose is to allow testing of the properties of non-generic methods on generic types
+        /// </summary>
+        public void NonGenericFunction()
+        {
+        }
+
+        /// <summary>
+        /// Purpose is to allow testing of the properties of generic methods on generic types
+        /// </summary>
+        public void GenericFunction<K, V>()
+        {
+        }
+    }
+
+    /// <summary>
+    /// Non-generic type which has a generic method in it
+    /// </summary>
+    public class NonGenericClass
+    {
+        /// <summary>
+        /// Purpose is to allow testing the properties of generic methods on nongeneric types
+        /// </summary>
+        /// <typeparam name="K"></typeparam>
+        /// <typeparam name="V"></typeparam>
+        public void GenericFunction<K, V>()
+        {
+        }
+    }
+
+    /// <summary>
+    /// Generic structure with 3 fields all defined by type parameters
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct GenStruct<A,B,C>
+    {
+        A _a;
+        B _b;
+        C _c;
+    }
+
+    public class GenClass<A>
+    {
+#pragma warning disable 169
+        A _a;
+#pragma warning restore 169
+    }
+
+    public class GenDerivedClass<A,B> : GenClass<A>
+    {
+#pragma warning disable 169
+        B _b;
+#pragma warning restore 169
+    }
+}
\ No newline at end of file
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Hashcode.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Hashcode.cs
new file mode 100644 (file)
index 0000000..21f68be
--- /dev/null
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Hashcode
+{
+    class NonNestedType
+    {
+        class NestedType
+        {
+
+        }
+
+        void GenericMethod<T>()
+        { }
+    }
+
+    class GenericType<X,Y>
+    {
+        void GenericMethod<T>()
+        {
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InstanceFieldLayout.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InstanceFieldLayout.cs
new file mode 100644 (file)
index 0000000..188d26d
--- /dev/null
@@ -0,0 +1,302 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 169
+
+namespace ContainsGCPointers
+{
+    struct NoPointers
+    {
+        int int1;
+        byte byte1;
+        char char1;
+    }
+
+    struct StillNoPointers
+    {
+        NoPointers noPointers1;
+        bool bool1;
+    }
+
+    class ClassNoPointers
+    {
+        char char1;
+    }
+
+    struct HasPointers
+    {
+        string string1;
+    }
+
+    struct FieldHasPointers
+    {
+        HasPointers hasPointers1;
+    }
+
+    class ClassHasPointers
+    {
+        ClassHasPointers classHasPointers1;
+    }
+
+    class BaseClassHasPointers : ClassHasPointers
+    {
+    }
+
+    public class ClassHasIntArray
+    {
+        int[] intArrayField;
+    }
+
+    public class ClassHasArrayOfClassType
+    {
+        ClassNoPointers[] classTypeArray;
+    }
+}
+
+namespace Explicit
+{
+    [StructLayout(LayoutKind.Explicit)]
+    class Class1
+    {
+        static int Stat;
+        [FieldOffset(4)]
+        bool Bar;
+        [FieldOffset(10)]
+        char Baz;
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    class Class2 : Class1
+    {
+        [FieldOffset(0)]
+        int Lol;
+        [FieldOffset(20)]
+        byte Omg;
+    }
+
+    [StructLayout(LayoutKind.Explicit, Size = 40)]
+    class ExplicitSize : Class1
+    {
+        [FieldOffset(0)]
+        int Lol;
+        [FieldOffset(20)]
+        byte Omg;
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    public class ExplicitEmptyClass
+    {
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    public struct ExplicitEmptyStruct
+    {
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    ref struct MisalignedPointer
+    {
+        [FieldOffset(2)]
+        public object O;
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    ref struct MisalignedByRef
+    {
+        [FieldOffset(2)]
+        public ByRefStruct O;
+    }
+
+    ref struct ByRefStruct
+    {
+    }
+}
+
+namespace Sequential
+{
+    [StructLayout(LayoutKind.Sequential)]
+    class Class1
+    {
+        int MyInt;
+        bool MyBool;
+        char MyChar;
+        string MyString;
+        byte[] MyByteArray;
+        Class1 MyClass1SelfRef;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    class Class2 : Class1
+    {
+        int MyInt2;
+    }
+
+    // [StructLayout(LayoutKind.Sequential)] is applied by default by the C# compiler
+    struct Struct0
+    {
+        bool b1;
+        bool b2;
+        bool b3;
+        int i1;
+        string s1;
+    }
+
+    // [StructLayout(LayoutKind.Sequential)] is applied by default by the C# compiler
+    struct Struct1
+    {
+        Struct0 MyStruct0;
+        bool MyBool;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public class ClassDoubleBool
+    {
+        double double1;
+        bool bool1;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public class ClassBoolDoubleBool
+    {
+        bool bool1;
+        double double1;
+        bool bool2;
+    }
+}
+
+namespace Auto
+{
+    [StructLayout(LayoutKind.Auto)]
+    struct StructWithBool
+    {
+        bool MyStructBool;
+    }
+
+    [StructLayout(LayoutKind.Auto)]
+    struct StructWithIntChar
+    {
+        char MyStructChar;
+        int MyStructInt;
+    }
+
+    [StructLayout(LayoutKind.Auto)]
+    struct StructWithChar
+    {
+        char MyStructChar;
+    }
+
+    class ClassContainingStructs
+    {
+        static int MyStaticInt;
+
+        StructWithBool MyStructWithBool;
+        bool MyBool1;
+        char MyChar1;
+        int MyInt;
+        double MyDouble;
+        long MyLong;
+        byte[] MyByteArray;
+        string MyString1;
+        bool MyBool2;
+        StructWithIntChar MyStructWithIntChar;
+        StructWithChar MyStructWithChar;
+    }
+
+    class BaseClass7BytesRemaining
+    {
+        bool MyBool1;
+        double MyDouble1;
+        long MyLong1;
+        byte[] MyByteArray1;
+        string MyString1;
+    }
+
+    class BaseClass4BytesRemaining
+    {
+        long MyLong1;
+        uint MyUint1;
+    }
+
+    class BaseClass3BytesRemaining
+    {
+        int MyInt1;
+        string MyString1;
+        bool MyBool1;
+    }
+
+    class OptimizePartial : BaseClass7BytesRemaining
+    {
+        bool OptBool;
+        char OptChar;
+        long NoOptLong;
+        string NoOptString;
+    }
+
+    class Optimize7Bools : BaseClass7BytesRemaining
+    {
+        bool OptBool1;
+        bool OptBool2;
+        bool OptBool3;
+        bool OptBool4;
+        bool OptBool5;
+        bool OptBool6;
+        bool OptBool7;
+        bool NoOptBool8;
+        string NoOptString;
+    }
+
+    class OptimizeAlignedFields : BaseClass7BytesRemaining
+    {
+        bool OptBool1;
+        bool OptBool2;
+        bool OptBool3;
+        bool NoOptBool4;
+        char OptChar1;
+        char OptChar2;
+        string NoOptString;
+    }
+
+    class OptimizeLargestField : BaseClass4BytesRemaining
+    {
+        bool NoOptBool;
+        char NoOptChar;
+        int OptInt;
+        string NoOptString;
+    }
+
+    class NoOptimizeMisaligned : BaseClass3BytesRemaining
+    {
+        char NoOptChar;
+        int NoOptInt;
+        string NoOptString;
+    }
+
+    class NoOptimizeCharAtSize2Alignment : BaseClass3BytesRemaining
+    {
+        char NoOptChar;
+    }
+
+    [StructLayout(LayoutKind.Auto, Pack = 1)]
+    struct MinPacking<T>
+    {
+        public byte _byte;
+        public T _value;
+    }
+}
+
+namespace IsByRefLike
+{
+    public ref struct ByRefLikeStruct
+    {
+        ByReference<object> ByRef;
+    }
+
+    public struct NotByRefLike
+    {
+        int X;
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InterfaceArrangements.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InterfaceArrangements.cs
new file mode 100644 (file)
index 0000000..c92aafd
--- /dev/null
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace InterfaceArrangements
+{
+    interface I1 { }
+
+    interface I2 : I1 { }
+    
+    interface IGen1<T> { }
+
+    class NoInterfaces { }
+
+    class OneInterface : I1 { }
+
+    class Base<T> : IGen1<T>, I1 { }
+
+    class Mid<U,V> : Base<U>, IGen1<V> { }
+
+    class DerivedFromMid : Mid<string, string>, IGen1<string> { }
+
+    interface IFoo<out U>
+    {
+        void IMethod();
+    }
+
+    class Foo : IFoo<string>, IFoo<int>
+    {
+        public virtual void IMethod() { }
+    }
+
+    class DerivedFromFoo : Foo, IFoo<string>, IFoo<int>
+    {
+        void IFoo<string>.IMethod() { }
+    }
+
+    class SuperDerivedFromFoo : DerivedFromFoo, IFoo<string>, IFoo<int>
+    {
+        void IFoo<int>.IMethod() { }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Platform.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Platform.cs
new file mode 100644 (file)
index 0000000..e61a165
--- /dev/null
@@ -0,0 +1,136 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#pragma warning disable 649
+#pragma warning disable 169
+
+namespace System
+{
+    // Dummy core types to allow us compiling this assembly as a core library so that the type
+    // system tests don't have a dependency on a real core library.
+
+    public class Object
+    {
+        internal IntPtr m_pEEType;
+
+        public virtual bool Equals(object other)
+        {
+            return false;
+        }
+
+        public virtual int GetHashCode()
+        {
+            return 0;
+        }
+
+        public virtual string ToString() { return null; }
+
+        ~Object()
+        {
+        }
+    }
+
+    public struct Void { }
+    public struct Boolean { }
+    public struct Char { }
+    public struct SByte { }
+    public struct Byte { }
+    public struct Int16 { }
+    public struct UInt16 { }
+    public struct Int32 { }
+    public struct UInt32 { }
+    public struct Int64 { }
+    public struct UInt64 { }
+    public struct IntPtr { }
+    public struct UIntPtr { }
+    public struct Single { }
+    public struct Double { }
+    public abstract class ValueType { }
+    public abstract class Enum : ValueType { }
+    public struct Nullable<T> where T : struct { }
+    
+    public sealed class String { }
+    public abstract class Array : System.Collections.IList { }
+    public abstract class Delegate { }
+    public abstract class MulticastDelegate : Delegate { }
+
+    public struct RuntimeTypeHandle { }
+    public struct RuntimeMethodHandle { }
+    public struct RuntimeFieldHandle { }
+
+    public class Attribute { }
+
+    public class ThreadStaticAttribute : Attribute { }
+
+    public class Array<T> : Array, System.Collections.Generic.IList<T> { }
+
+    public class Exception { }
+
+    public ref struct TypedReference
+    {
+        private readonly ByReference<byte> _value;
+        private readonly RuntimeTypeHandle _typeHandle;
+    }
+
+    public ref struct ByReference<T> { }
+}
+
+namespace System.Collections
+{
+    interface IEnumerable { }
+
+    interface ICollection : IEnumerable { }
+
+    interface IList : ICollection { }
+}
+
+namespace System.Collections.Generic
+{
+    interface IEnumerable<out T> { }
+
+    interface ICollection<T> : IEnumerable<T> { }
+
+    interface IList<T> : ICollection<T> { }
+}
+
+namespace System.Runtime.InteropServices
+{
+    public enum LayoutKind
+    {
+        Sequential = 0, // 0x00000008,
+        Explicit = 2, // 0x00000010,
+        Auto = 3, // 0x00000000,
+    }
+
+    public sealed class StructLayoutAttribute : Attribute
+    {
+        internal LayoutKind _val;
+
+        public StructLayoutAttribute(LayoutKind layoutKind)
+        {
+            _val = layoutKind;
+        }
+
+        public LayoutKind Value { get { return _val; } }
+        public int Pack;
+        public int Size;
+    }
+
+    public sealed class FieldOffsetAttribute : Attribute
+    {
+        private int _val;
+        public FieldOffsetAttribute(int offset)
+        {
+            _val = offset;
+        }
+        public int Value { get { return _val; } }
+    }
+}
+
+namespace System.Runtime.CompilerServices
+{
+    public sealed class IsByRefLikeAttribute : Attribute
+    {
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/StaticFieldLayout.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/StaticFieldLayout.cs
new file mode 100644 (file)
index 0000000..3fc670b
--- /dev/null
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+#pragma warning disable 169
+
+namespace StaticFieldLayout
+{
+    struct NoPointers
+    {
+        static int int1;
+        static byte byte1;
+        static char char1;
+    }
+
+    struct StillNoPointers
+    {
+        NoPointers noPointers1;
+        static bool bool1;
+    }
+
+    class ClassNoPointers
+    {
+        static int int1;
+        static byte byte1;
+        static char char1;
+    }
+
+    struct HasPointers
+    {
+        bool bool1;
+        static string string1;
+        static ClassNoPointers class1;
+        char char1;
+    }
+
+    class MixPointersAndNonPointers
+    {
+        static string string1;
+        static int int1;
+        static ClassNoPointers class1;
+        static int int2;
+        static string string2;
+    }
+
+    class EnsureInheritanceResetsStaticOffsets : MixPointersAndNonPointers
+    {
+        static int int3;
+        static string string3;
+    }
+
+    class LiteralFieldsDontAffectLayout
+    {
+        const int IntConstant = 0;
+        const string StringConstant = null;
+        static int Int1;
+        static string String1;
+    }
+
+    class RvaTestClass
+    {
+        static void RvaTest()
+        {
+            int[] foo = new int[] { 0, 1, 2, 3, 4, 45, 5, 5 };
+        }
+
+    }
+
+    struct StaticSelfRef
+    {
+        static StaticSelfRef selfRef1;
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/SyntheticVirtualOverride.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/SyntheticVirtualOverride.cs
new file mode 100644 (file)
index 0000000..326bf7d
--- /dev/null
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace SyntheticVirtualOverride
+{
+    struct StructWithNoEqualsAndGetHashCode
+    {
+    }
+
+    class ClassWithInjectedEqualsAndGetHashCode
+    {
+    }
+
+    class ClassOverridingEqualsAndGetHashCode : ClassWithInjectedEqualsAndGetHashCode
+    {
+        public override bool Equals(object other)
+        {
+            return false;
+        }
+
+        public override int GetHashCode()
+        {
+            return 0;
+        }
+    }
+
+    class ClassNotOverridingEqualsAndGetHashCode : ClassWithInjectedEqualsAndGetHashCode
+    {
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/TypeNameParsing.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/TypeNameParsing.cs
new file mode 100644 (file)
index 0000000..6010b2b
--- /dev/null
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+public class NonNamespaceQualifiedType
+{
+
+}
+
+namespace TypeNameParsing
+{
+    public class Generic<T>
+    {
+        public class NestedNongeneric
+        {
+        }
+
+        public class NestedGeneric<U>
+        {
+        }
+    }
+
+    public class VeryGeneric<T, U, V>
+    {
+    }
+
+    public class Simple
+    {
+        public class Nested
+        {
+            public class NestedTwice
+            {
+            }
+        }
+    }
+
+    public struct Struct
+    {
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/ValueTypeShapeCharacteristics.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/ValueTypeShapeCharacteristics.cs
new file mode 100644 (file)
index 0000000..92ca4cb
--- /dev/null
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+#pragma warning disable 169
+
+namespace ValueTypeShapeCharacteristics
+{
+    struct SimpleHfaFloatStruct
+    {
+        static int irrelevantField;
+        float field;
+    }
+
+    struct SimpleHfaFloatStructWithManyFields
+    {
+        float field1;
+        float field2;
+        float field3;
+        float field4;
+    }
+
+    struct SimpleHfaDoubleStruct
+    {
+        double field;
+        static int irrelevantField;
+    }
+
+    struct CompositeHfaFloatStruct
+    {
+        SimpleHfaFloatStruct field1;
+        float field2;
+        SimpleHfaFloatStruct field3;
+    }
+
+    struct CompositeHfaDoubleStruct
+    {
+        SimpleHfaDoubleStruct field1;
+        SimpleHfaDoubleStruct field2;
+        SimpleHfaDoubleStruct field3;
+        SimpleHfaDoubleStruct field4;
+    }
+
+    struct NonHAEmptyStruct
+    {
+    }
+
+    struct NonHAStruct
+    {
+        float field1;
+        int field2;
+    }
+
+    struct NonHAMixedStruct
+    {
+        float field1;
+        double field2;
+    }
+
+    struct NonHACompositeStruct
+    {
+        SimpleHfaDoubleStruct field1;
+        SimpleHfaFloatStruct field2;
+    }
+
+    struct NonHAStructWithManyFields
+    {
+        float field1;
+        float field2;
+        float field3;
+        float field4;
+        float field5;
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/VirtualFunctionOverride.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/VirtualFunctionOverride.cs
new file mode 100644 (file)
index 0000000..36aa307
--- /dev/null
@@ -0,0 +1,42 @@
+using System;
+
+namespace VirtualFunctionOverride
+{
+    interface IIFaceWithGenericMethod
+    {
+        void GenMethod<T>();
+    }
+
+    class HasMethodInterfaceOverrideOfGenericMethod : IIFaceWithGenericMethod
+    {
+        void IIFaceWithGenericMethod.GenMethod<T>() { }
+    }
+
+    class SimpleGeneric<T>
+    {
+        public override string ToString()
+        {
+            return null;
+        }
+    }
+
+    class BaseGenericWithOverload<T>
+    {
+        public virtual void MyMethod(string s) { }
+        public virtual void MyMethod(T s) { }
+    }
+
+    class DerivedGenericWithOverload<U> : BaseGenericWithOverload<U>
+    {
+        public override void MyMethod(string s) { }
+        public override void MyMethod(U s) { }
+    }
+
+    class ClassWithFinalizer
+    {
+        ~ClassWithFinalizer()
+        {
+
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs
new file mode 100644 (file)
index 0000000..4268fa1
--- /dev/null
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class GCPointerMapTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        public GCPointerMapTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X86);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestInstanceMap()
+        {
+            MetadataType classWithArrayFields = _testModule.GetType("GCPointerMap", "ClassWithArrayFields");
+            MetadataType classWithStringField = _testModule.GetType("GCPointerMap", "ClassWithStringField");
+            MetadataType mixedStruct = _testModule.GetType("GCPointerMap", "MixedStruct");
+            MetadataType structWithSameGCLayoutAsMixedStruct = _testModule.GetType("GCPointerMap", "StructWithSameGCLayoutAsMixedStruct");
+            MetadataType doubleMixedStructLayout = _testModule.GetType("GCPointerMap", "DoubleMixedStructLayout");
+            MetadataType explicitlyFarPointer = _testModule.GetType("GCPointerMap", "ExplicitlyFarPointer");
+            MetadataType struct32GcPointers = _testModule.GetType("GCPointerMap", "Struct32GcPointers");
+
+            {
+                var map = GCPointerMap.FromInstanceLayout(classWithArrayFields);
+                Assert.Equal(3, map.Size);
+                Assert.Equal("011", map.ToString());
+            }
+
+            {
+                var map = GCPointerMap.FromInstanceLayout(classWithStringField);
+                Assert.Equal(4, map.Size);
+                Assert.Equal("0010", map.ToString());
+            }
+
+            {
+                var map = GCPointerMap.FromInstanceLayout(mixedStruct);
+                Assert.Equal(5, map.Size);
+                Assert.Equal("01001", map.ToString());
+            }
+
+            {
+                var map1 = GCPointerMap.FromInstanceLayout(mixedStruct);
+                var map2 = GCPointerMap.FromInstanceLayout(structWithSameGCLayoutAsMixedStruct);
+                Assert.Equal(map1.Size, map2.Size);
+                Assert.Equal(map1.ToString(), map2.ToString());
+            }
+
+            {
+                var map = GCPointerMap.FromInstanceLayout(doubleMixedStructLayout);
+                Assert.Equal(10, map.Size);
+                Assert.Equal("0100101001", map.ToString());
+            }
+
+            {
+                var map = GCPointerMap.FromInstanceLayout(explicitlyFarPointer);
+                Assert.Equal(117, map.Size);
+                Assert.Equal("100000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000001001", map.ToString());
+            }
+
+            {
+                var map = GCPointerMap.FromInstanceLayout(struct32GcPointers);
+                Assert.Equal(32, map.Size);
+                Assert.Equal("11111111111111111111111111111111", map.ToString());
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs
new file mode 100644 (file)
index 0000000..2e881d7
--- /dev/null
@@ -0,0 +1,274 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Internal.TypeSystem;
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class GenericMethodTests
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        public GenericMethodTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        /// <summary>
+        /// Testing proper instantiation of types and methods involving generic parameters in their signature.
+        /// </summary>
+        [Fact]
+        public void TestInstantiation()
+        {
+            MetadataType t = _testModule.GetType("GenericTypes", "GenericClass`1");
+
+            // Verify that we get just type definitions.
+            Assert.NotNull(t);
+            Assert.True(t.IsTypeDefinition);
+            Assert.Equal(1, t.Instantiation.Length);
+            Assert.True(t.Instantiation[0].IsTypeDefinition);
+
+            // Verify that we got a method definition
+            MethodDesc fooMethod = t.GetMethods().First(m => m.Name == "Foo");
+            Assert.True(fooMethod.IsTypicalMethodDefinition);
+
+            // Verify that instantiating a method definition has no effect
+            MethodDesc instantiatedMethod = fooMethod.InstantiateSignature(new Instantiation(_context.GetWellKnownType(WellKnownType.Int32)), Instantiation.Empty);
+            Assert.Same(fooMethod, instantiatedMethod);
+
+            MetadataType instantiatedType = t.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+
+            // Verify properties of the instantiated type
+            Assert.NotNull(instantiatedType);
+            Assert.False(instantiatedType.IsTypeDefinition);
+            Assert.Equal(1, instantiatedType.Instantiation.Length);
+            Assert.Equal(_context.GetWellKnownType(WellKnownType.Int32), instantiatedType.Instantiation[0]);
+
+            // Verify that we get an instantiated method with the proper signature
+            MethodDesc fooInstantiatedMethod = instantiatedType.GetMethods().First(m => m.Name == "Foo");
+            Assert.False(fooInstantiatedMethod.IsTypicalMethodDefinition);
+            Assert.Equal(_context.GetWellKnownType(WellKnownType.Int32), fooInstantiatedMethod.Signature.ReturnType);
+            Assert.Same(fooInstantiatedMethod.GetTypicalMethodDefinition(), fooMethod);
+            // This is not a generic method, so they should be the same
+            Assert.Same(fooInstantiatedMethod.GetMethodDefinition(), fooInstantiatedMethod);
+
+            // Verify that instantiating a type definition has no effect
+            TypeDesc newType = t.InstantiateSignature(new Instantiation(_context.GetWellKnownType(WellKnownType.Int32)), Instantiation.Empty);
+            Assert.NotNull(newType);
+            Assert.Same(newType, t);
+        }
+
+        [Fact]
+        public void TestMethodAttributes()
+        {
+            MetadataType tGen = _testModule.GetType("GenericTypes", "GenericClass`1");
+            MetadataType tDerivedGen = _testModule.GetType("GenericTypes", "DerivedGenericClass`1");
+            InstantiatedType genOfInt = tGen.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+            InstantiatedType derivedGenOfInt = tDerivedGen.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+            MethodDesc fooInstantiatedMethod = genOfInt.GetMethods().First(m => m.Name == "Foo");
+            MethodDesc barInstantiatedMethod = genOfInt.GetMethods().First(m => m.Name == "Bar");
+            MethodDesc fooDerivedInstantiatedMethod = derivedGenOfInt.GetMethods().First(m => m.Name == "Foo");
+
+            Assert.False(barInstantiatedMethod.IsVirtual);
+            Assert.False(barInstantiatedMethod.IsNewSlot);
+            Assert.False(barInstantiatedMethod.IsFinal);
+            Assert.False(barInstantiatedMethod.IsAbstract);
+
+            Assert.True(fooInstantiatedMethod.IsVirtual);
+            Assert.True(fooInstantiatedMethod.IsNewSlot);
+            Assert.False(fooInstantiatedMethod.IsFinal);
+            Assert.True(fooInstantiatedMethod.IsAbstract);
+
+            Assert.True(fooDerivedInstantiatedMethod.IsVirtual);
+            Assert.False(fooDerivedInstantiatedMethod.IsNewSlot);
+            Assert.True(fooDerivedInstantiatedMethod.IsFinal);
+            Assert.False(fooDerivedInstantiatedMethod.IsAbstract);
+        }
+
+        [Fact]
+        public void TestFinalize()
+        {
+            MetadataType tGen = _testModule.GetType("GenericTypes", "GenericClass`1");
+            MetadataType tDerivedGen = _testModule.GetType("GenericTypes", "DerivedGenericClass`1");
+            InstantiatedType genOfInt = tGen.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+            InstantiatedType derivedGenOfInt = tDerivedGen.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+            MethodDesc finalizeInstantiatedMethod = genOfInt.GetMethods().First(m => m.Name == "Finalize");
+
+            Assert.Equal(finalizeInstantiatedMethod, genOfInt.GetFinalizer());
+            Assert.Equal(finalizeInstantiatedMethod, derivedGenOfInt.GetFinalizer());
+        }
+
+        /// <summary>
+        /// 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] { });
+            MethodDesc fooMethod = t.GetMethod("Foo", sig);
+            Assert.NotNull(fooMethod);
+        }
+
+        [Fact]
+        public void TestConstructedTypeAdjustment()
+        {
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+            TypeDesc charType = _context.GetWellKnownType(WellKnownType.Char);
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            MetadataType genericOpenType = _testModule.GetType("GenericTypes", "TwoParamGenericClass`2");
+
+            InstantiatedType genericOfCharObject = genericOpenType.MakeInstantiatedType(charType, objectType);
+            InstantiatedType genericOfCharString = genericOpenType.MakeInstantiatedType(charType, stringType);
+            InstantiatedType genericOfIntString = genericOpenType.MakeInstantiatedType(intType, stringType);
+            InstantiatedType genericOfIntObject = genericOpenType.MakeInstantiatedType(intType, objectType);
+
+            Assert.True(genericOfCharObject.IsConstructedOverType(new TypeDesc[] { charType }));
+            Assert.True(genericOfCharObject.IsConstructedOverType(new TypeDesc[] { objectType }));
+            Assert.False(genericOfCharObject.IsConstructedOverType(new TypeDesc[] { intType }));
+            Assert.False(genericOfCharObject.IsConstructedOverType(new TypeDesc[] { stringType }));
+            Assert.False(genericOfCharObject.IsConstructedOverType(new TypeDesc[] { genericOpenType }));
+
+            Assert.True(genericOfCharString.IsConstructedOverType(new TypeDesc[] { charType }));
+            Assert.False(genericOfCharString.IsConstructedOverType(new TypeDesc[] { objectType }));
+            Assert.False(genericOfCharString.IsConstructedOverType(new TypeDesc[] { intType }));
+            Assert.True(genericOfCharString.IsConstructedOverType(new TypeDesc[] { stringType }));
+
+            // Test direct replacement
+            TypeDesc testDirectReplaceAllTypes = genericOfCharObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType, objectType }, new TypeDesc[] { intType, stringType });
+            Assert.Equal(genericOfIntString, testDirectReplaceAllTypes);
+
+            // Test direct replacement where not all types are replaced
+            TypeDesc testDirectReplaceFirstType = genericOfCharObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType });
+            Assert.Equal(genericOfIntObject, testDirectReplaceFirstType);
+
+            TypeDesc testDirectReplaceSecondType = genericOfCharObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { objectType }, new TypeDesc[] { stringType });
+            Assert.Equal(genericOfCharString, testDirectReplaceSecondType);
+
+            // Test Arrays
+            TypeDesc arrayChar = _context.GetArrayType(charType);
+            Assert.False(arrayChar.IsMdArray);
+            Assert.True(arrayChar.IsSzArray);
+            Assert.True(arrayChar.IsArray);
+
+            TypeDesc arrayInt = _context.GetArrayType(intType);
+            Assert.False(arrayInt.IsMdArray);
+            Assert.True(arrayInt.IsSzArray);
+            Assert.True(arrayInt.IsArray);
+
+            InstantiatedType genericOfCharArrayObject = genericOpenType.MakeInstantiatedType(arrayChar, objectType);
+            InstantiatedType genericOfIntArrayObject = genericOpenType.MakeInstantiatedType(arrayInt, objectType);
+            TypeDesc testReplaceTypeInArrayInGeneric = genericOfCharArrayObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType });
+            Assert.Equal(genericOfIntArrayObject, testReplaceTypeInArrayInGeneric);
+
+            // Test multidimensional arrays
+            TypeDesc mdArrayChar = _context.GetArrayType(charType, 3);
+            Assert.True(mdArrayChar.IsMdArray);
+            Assert.False(mdArrayChar.IsSzArray);
+            Assert.True(mdArrayChar.IsArray);
+
+            TypeDesc mdArrayInt = _context.GetArrayType(intType, 3);
+            Assert.True(mdArrayInt.IsMdArray);
+            Assert.False(mdArrayInt.IsSzArray);
+            Assert.True(mdArrayInt.IsArray);
+
+            InstantiatedType genericOfCharMdArrayObject = genericOpenType.MakeInstantiatedType(mdArrayChar, objectType);
+            InstantiatedType genericOfIntMdArrayObject = genericOpenType.MakeInstantiatedType(mdArrayInt, objectType);
+            TypeDesc testReplaceTypeInMdArrayInGeneric = genericOfCharMdArrayObject.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType });
+            Assert.Equal(genericOfIntMdArrayObject, testReplaceTypeInMdArrayInGeneric);
+
+            // Test pointers
+            TypeDesc charPointer = _context.GetPointerType(charType);
+            TypeDesc intPointer = _context.GetPointerType(intType);
+            TypeDesc testReplaceTypeInPointer = charPointer.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType });
+            Assert.Equal(intPointer, testReplaceTypeInPointer);
+
+            Assert.True(charPointer.IsConstructedOverType(new TypeDesc[] { charType }));
+            Assert.False(charPointer.IsConstructedOverType(new TypeDesc[] { intType }));
+
+            // Test byref
+            TypeDesc charByRef = _context.GetByRefType(charType);
+            TypeDesc intByRef = _context.GetByRefType(intType);
+            TypeDesc testReplaceTypeInByRef = charByRef.ReplaceTypesInConstructionOfType(new TypeDesc[] { charType }, new TypeDesc[] { intType });
+            Assert.Equal(intByRef, testReplaceTypeInByRef);
+
+            Assert.True(charByRef.IsConstructedOverType(new TypeDesc[] { charType }));
+            Assert.False(charByRef.IsConstructedOverType(new TypeDesc[] { intType }));
+
+            // Test replace type entirely
+            TypeDesc testReplaceTypeEntirely = charByRef.ReplaceTypesInConstructionOfType(new TypeDesc[] { charByRef }, new TypeDesc[] { intByRef });
+            Assert.Equal(intByRef, testReplaceTypeEntirely);
+            Assert.True(charByRef.IsConstructedOverType(new TypeDesc[] { charByRef }));
+        }
+
+        [Fact]
+        public void TestConstructedMethodAdjustment()
+        {
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+            TypeDesc charType = _context.GetWellKnownType(WellKnownType.Char);
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            MetadataType genericOpenType = _testModule.GetType("GenericTypes", "TwoParamGenericClass`2");
+            MetadataType nonGenericType = _testModule.GetType("GenericTypes", "NonGenericClass");
+
+            MethodDesc nonGenericOnGeneric = genericOpenType.GetMethod("NonGenericFunction", null);
+            MethodDesc genericOnGeneric = genericOpenType.GetMethod("GenericFunction", null);
+            MethodDesc genericOnNonGeneric = nonGenericType.GetMethod("GenericFunction", null);
+
+            InstantiatedType genericIntString = genericOpenType.MakeInstantiatedType(intType, stringType);
+            InstantiatedType genericCharString = genericOpenType.MakeInstantiatedType(charType, stringType);
+            InstantiatedType genericCharObject = genericOpenType.MakeInstantiatedType(charType, objectType);
+
+            MethodDesc nonGenericOnGenericIntString = genericIntString.GetMethod("NonGenericFunction", null);
+            MethodDesc nonGenericOnGenericCharString = genericCharString.GetMethod("NonGenericFunction", null);
+            MethodDesc nonGenericOnGenericCharObject = genericCharObject.GetMethod("NonGenericFunction", null);
+
+            MethodDesc genericIntStringOnGenericIntString = genericIntString.GetMethod("GenericFunction", null).MakeInstantiatedMethod(intType, stringType);
+            MethodDesc genericCharStringOnGenericCharString = genericCharString.GetMethod("GenericFunction", null).MakeInstantiatedMethod(charType, stringType);
+            MethodDesc genericCharObjectOnGenericCharObject = genericCharObject.GetMethod("GenericFunction", null).MakeInstantiatedMethod(charType, objectType);
+
+            MethodDesc genericIntStringOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(intType, stringType);
+            MethodDesc genericCharStringOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(charType, stringType);
+            MethodDesc genericCharObjectOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(charType, objectType);
+
+            // Test complete replacement
+            MethodDesc testDirectReplacementNonGenericOnGeneric = nonGenericOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType });
+            Assert.Equal(nonGenericOnGenericCharObject, testDirectReplacementNonGenericOnGeneric);
+            MethodDesc testDirectReplacementGenericOnGeneric = genericIntStringOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType });
+            Assert.Equal(genericCharObjectOnGenericCharObject, testDirectReplacementGenericOnGeneric);
+            MethodDesc testDirectReplacementGenericOnNonGeneric = genericIntStringOnNonGeneric.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType });
+            Assert.Equal(genericCharObjectOnNonGeneric, testDirectReplacementGenericOnNonGeneric);
+
+            // Test replace first type in instantiation
+            MethodDesc testPartialReplacementNonGenericOnGeneric = nonGenericOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });
+            Assert.Equal(nonGenericOnGenericCharString, testPartialReplacementNonGenericOnGeneric);
+            MethodDesc testPartialReplacementGenericOnGeneric = genericIntStringOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });
+            Assert.Equal(genericCharStringOnGenericCharString, testPartialReplacementGenericOnGeneric);
+            MethodDesc testPartialReplacementGenericOnNonGeneric = genericIntStringOnNonGeneric.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });
+            Assert.Equal(genericCharStringOnNonGeneric, testPartialReplacementGenericOnNonGeneric);
+
+            // Test ArrayMethod case
+            ArrayType mdArrayChar = _context.GetArrayType(charType, 3);
+            ArrayType mdArrayInt = _context.GetArrayType(intType, 3);
+
+            MethodDesc getMethodOnMDIntArray = mdArrayInt.GetArrayMethod(ArrayMethodKind.Get);
+            MethodDesc getMethodOnMDCharArray = mdArrayChar.GetArrayMethod(ArrayMethodKind.Get);
+
+            MethodDesc testArrayMethodCase = getMethodOnMDIntArray.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });
+            Assert.Equal(getMethodOnMDCharArray, testArrayMethodCase);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/HashcodeTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/HashcodeTests.cs
new file mode 100644 (file)
index 0000000..1415d1d
--- /dev/null
@@ -0,0 +1,253 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Internal.TypeSystem;
+using Internal.NativeFormat;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class HashcodeTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        public HashcodeTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestMultidimensionalArrays()
+        {
+            DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array);
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            ArrayType objectMDArrayRank1 = _context.GetArrayType(objectType, 1);
+            ArrayType objectMDArrayRank2 = _context.GetArrayType(objectType, 2);
+            ArrayType objectMDArrayRank3 = _context.GetArrayType(objectType, 3);
+
+            Assert.Equal(TypeHashingAlgorithms.ComputeArrayTypeHashCode(objectType.GetHashCode(), 1), objectMDArrayRank1.GetHashCode());
+            Assert.Equal(TypeHashingAlgorithms.ComputeArrayTypeHashCode(objectType.GetHashCode(), 2), objectMDArrayRank2.GetHashCode());
+            Assert.Equal(TypeHashingAlgorithms.ComputeArrayTypeHashCode(objectType.GetHashCode(), 3), objectMDArrayRank3.GetHashCode());
+        }
+
+        [Fact]
+        public void TestSingleDimensionalArrays()
+        {
+            DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array);
+
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            ArrayType objectArray = _context.GetArrayType(objectType);
+
+            Assert.Equal(TypeHashingAlgorithms.ComputeArrayTypeHashCode(objectType.GetHashCode(), -1), objectArray.GetHashCode());
+        }
+
+        [Fact]
+        public void TestNonGenericTypes()
+        {
+            DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array);
+            MetadataType nonNestedType = (MetadataType)_testModule.GetType("Hashcode", "NonNestedType");
+            TypeDesc nestedType = nonNestedType.GetNestedType("NestedType");
+
+            int expectedNonNestedTypeHashcode = TypeHashingAlgorithms.ComputeNameHashCode("Hashcode.NonNestedType");
+            int expectedNestedTypeNameHashcode = TypeHashingAlgorithms.ComputeNameHashCode("NestedType");
+            int expectedNestedTypeHashcode = TypeHashingAlgorithms.ComputeNestedTypeHashCode(expectedNonNestedTypeHashcode, expectedNestedTypeNameHashcode);
+
+            Assert.Equal(expectedNonNestedTypeHashcode, nonNestedType.GetHashCode());
+            Assert.Equal(expectedNestedTypeHashcode, nestedType.GetHashCode());
+        }
+
+        [Fact]
+        void TestGenericTypes()
+        {
+            MetadataType ilistType = (MetadataType)_testModule.GetType("System.Collections.Generic", "IList`1");
+            DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array);
+            DefType ilistOfSystemArray = ilistType.MakeInstantiatedType(systemArrayType);
+
+            int expectedIListOfTHashcode = TypeHashingAlgorithms.ComputeNameHashCode("System.Collections.Generic.IList`1");
+            int expectedSystemArrayHashcode = TypeHashingAlgorithms.ComputeNameHashCode("System.Array");
+            Assert.Equal(expectedIListOfTHashcode, ilistType.GetHashCode());
+            Assert.Equal(TypeHashingAlgorithms.ComputeGenericInstanceHashCode(expectedIListOfTHashcode, new int[] { expectedSystemArrayHashcode }), ilistOfSystemArray.GetHashCode());
+        }
+
+        [Fact]
+        public void TestInstantiatedMethods()
+        {
+            MetadataType nonNestedType = (MetadataType)_testModule.GetType("Hashcode", "NonNestedType");
+            MetadataType genericType = (MetadataType)_testModule.GetType("Hashcode", "GenericType`2");
+            DefType intType = _context.GetWellKnownType(WellKnownType.Int32);
+            DefType stringType = _context.GetWellKnownType(WellKnownType.String);
+
+            MetadataType genericTypeOfIntString = genericType.MakeInstantiatedType(intType, stringType);
+            MetadataType genericTypeOfStringInt = genericType.MakeInstantiatedType(stringType, intType);
+
+            // build up expected hash codes for the above
+            int expHashNonNestedType = TypeHashingAlgorithms.ComputeNameHashCode("Hashcode.NonNestedType");
+            Assert.Equal(expHashNonNestedType, nonNestedType.GetHashCode());
+            int expHashGenType = TypeHashingAlgorithms.ComputeNameHashCode("Hashcode.GenericType`2");
+            Assert.Equal(expHashGenType, genericType.GetHashCode());
+            int expHashInt = TypeHashingAlgorithms.ComputeNameHashCode("System.Int32");
+            Assert.Equal(expHashInt, intType.GetHashCode());
+            int expHashString = TypeHashingAlgorithms.ComputeNameHashCode("System.String");
+            Assert.Equal(expHashString, stringType.GetHashCode());
+            int expHashGenTypeOfIS = TypeHashingAlgorithms.ComputeGenericInstanceHashCode(expHashGenType, new int[] { expHashInt, expHashString });
+            Assert.Equal(expHashGenTypeOfIS, genericTypeOfIntString.GetHashCode());
+            int expHashGenTypeOfSI = TypeHashingAlgorithms.ComputeGenericInstanceHashCode(expHashGenType, new int[] { expHashString, expHashInt });
+            Assert.Equal(expHashGenTypeOfSI, genericTypeOfStringInt.GetHashCode());
+
+            // Test that instantiated method's have the right hashes
+
+            int genMethodNameHash = TypeHashingAlgorithms.ComputeNameHashCode("GenericMethod");
+            int genMethodNameAndIHash = TypeHashingAlgorithms.ComputeGenericInstanceHashCode(genMethodNameHash, new int[] { expHashInt });
+            int genMethodNameAndSHash = TypeHashingAlgorithms.ComputeGenericInstanceHashCode(genMethodNameHash, new int[] { expHashString });
+
+
+            Action<MetadataType, int> testSequence = (MetadataType typeWithGenericMethod, int expectedTypeHash) =>
+            {
+                // Uninstantiated Generic method
+                MethodDesc genMethod = typeWithGenericMethod.GetMethod("GenericMethod", null);
+                Assert.Equal(TypeHashingAlgorithms.ComputeMethodHashCode(expectedTypeHash, genMethodNameHash), genMethod.GetHashCode());
+
+                // Instantiated over int
+                MethodDesc genMethodI = genMethod.MakeInstantiatedMethod(intType);
+                Assert.Equal(TypeHashingAlgorithms.ComputeMethodHashCode(expectedTypeHash, genMethodNameAndIHash), genMethodI.GetHashCode());
+
+                // Instantiated over string
+                MethodDesc genMethodS = genMethod.MakeInstantiatedMethod(stringType);
+                Assert.Equal(TypeHashingAlgorithms.ComputeMethodHashCode(expectedTypeHash, genMethodNameAndSHash), genMethodS.GetHashCode());
+
+                // Assert they aren't the same as the other hashes
+                Assert.NotEqual(genMethodI.GetHashCode(), genMethodS.GetHashCode());
+                Assert.NotEqual(genMethodI.GetHashCode(), genMethod.GetHashCode());
+                Assert.NotEqual(genMethodS.GetHashCode(), genMethod.GetHashCode());
+            };
+
+            // Test cases on non-generic type
+            testSequence(nonNestedType, expHashNonNestedType);
+
+            // Test cases on generic type
+            testSequence(genericType, expHashGenType);
+
+            // Test cases on instantiated generic type
+            testSequence(genericTypeOfIntString, expHashGenTypeOfIS);
+            testSequence(genericTypeOfStringInt, expHashGenTypeOfSI);
+        }
+
+        [Fact]
+        public void TestPointerTypes()
+        {
+            DefType intType = _context.GetWellKnownType(WellKnownType.Int32);
+
+            int expHashInt = TypeHashingAlgorithms.ComputeNameHashCode("System.Int32");
+            Assert.Equal(expHashInt, intType.GetHashCode());
+
+            int expHashIntPointer = TypeHashingAlgorithms.ComputePointerTypeHashCode(expHashInt);
+            TypeDesc intPointerType = _context.GetPointerType(intType);
+            Assert.Equal(expHashIntPointer, intPointerType.GetHashCode());
+        }
+
+        [Fact]
+        public void TestFunctionPointerTypes()
+        {
+            DefType intType = _context.GetWellKnownType(WellKnownType.Int32);
+            DefType objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            int expHashInt = TypeHashingAlgorithms.ComputeNameHashCode("System.Int32");
+            int expHashObject = TypeHashingAlgorithms.ComputeNameHashCode("System.Object");
+
+            int expHashFnPtr = TypeHashingAlgorithms.ComputeMethodSignatureHashCode(expHashInt, new[] { expHashObject });
+
+            MethodSignature fnPtrSig = new MethodSignature(MethodSignatureFlags.None, 0, intType, new TypeDesc[] { objectType });
+            var fnPtrType = _context.GetFunctionPointerType(fnPtrSig);
+            Assert.Equal(expHashFnPtr, fnPtrType.GetHashCode());
+        }
+
+        [Fact]
+        public void TestByRefTypes()
+        {
+            DefType intType = _context.GetWellKnownType(WellKnownType.Int32);
+
+            int expHashInt = TypeHashingAlgorithms.ComputeNameHashCode("System.Int32");
+            Assert.Equal(expHashInt, intType.GetHashCode());
+
+            int expHashIntByRef = TypeHashingAlgorithms.ComputeByrefTypeHashCode(expHashInt);
+            TypeDesc intByRefType = _context.GetByRefType(intType);
+            Assert.Equal(expHashIntByRef, intByRefType.GetHashCode());
+        }
+
+        [Fact]
+        public void TestHashCodeBuilder()
+        {
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xy");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xy"), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xyz");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xyz"), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xy");
+                builder.Append("");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xy"), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xy");
+                builder.Append(".");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xy."), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xyz");
+                builder.Append(".");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xyz."), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xy");
+                builder.Append("..");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xy.."), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xyz");
+                builder.Append("..");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xyz.."), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xy");
+                builder.Append(".");
+                builder.Append("Ab");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xy.Ab"), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xy");
+                builder.Append(".");
+                builder.Append("Abc");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xy.Abc"), builder.ToHashCode());
+            }
+
+            {
+                var builder = new TypeHashingAlgorithms.HashCodeBuilder("Xyz");
+                builder.Append(".");
+                builder.Append("Abc");
+                Assert.Equal(TypeHashingAlgorithms.ComputeNameHashCode("Xyz.Abc"), builder.ToHashCode());
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj
new file mode 100644 (file)
index 0000000..f4174a1
--- /dev/null
@@ -0,0 +1,58 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <AssemblyName>ILCompiler.TypeSystem.ReadyToRun.Tests</AssemblyName>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <Configurations>Debug;Release;Checked</Configurations>
+    <!-- This seems to be required for supporting assemblies to be copied into the output -->
+    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
+    <TestRunnerAdditionalArguments>-notrait category=failing</TestRunnerAdditionalArguments>
+    <!-- xunit.runner.visualstudio is restored for .NET Framework instead of Core-->
+    <NoWarn>$(NoWarn);NU1701</NoWarn>
+    <!-- By default the subdirectories containing CoreTestAssembly and ILTestAssembly would be 
+         included in compilation of this project -->
+    <EnableDefaultItems>false</EnableDefaultItems>
+  </PropertyGroup>
+
+  <ItemGroup>    
+    <PackageReference Include="xunit.core" Version="$(XUnitVersion)" ExcludeAssets="build" />
+    <PackageReference Include="Microsoft.DotNet.XUnitExtensions" Version="$(MicrosoftDotNetXUnitExtensionsVersion)" />
+    <PackageReference Include="System.Reflection.Metadata" Version="1.8.1" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\ILCompiler.TypeSystem.ReadyToRun\ILCompiler.TypeSystem.ReadyToRun.csproj" />
+    <!-- Make sure the test data gets built -->
+    <ProjectReference Include="CoreTestAssembly\CoreTestAssembly.csproj">
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <OutputItemType>Content</OutputItemType>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </ProjectReference>
+    <ProjectReference Include="ILTestAssembly\ILTestAssembly.ilproj">
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <OutputItemType>Content</OutputItemType>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ArchitectureSpecificFieldLayoutTests.cs" />
+    <Compile Include="CanonicalizationTests.cs" />
+    <Compile Include="ConstraintsValidationTest.cs" />
+    <Compile Include="GCPointerMapTests.cs" />
+    <Compile Include="GenericTypeAndMethodTests.cs" />
+    <Compile Include="CastingTests.cs" />
+    <Compile Include="HashcodeTests.cs" />
+    <Compile Include="ILDisassemblerTests.cs" />
+    <Compile Include="InterfacesTests.cs" />
+    <Compile Include="RuntimeDeterminedTypesTests.cs" />
+    <Compile Include="SyntheticVirtualOverrideTests.cs" />
+    <Compile Include="TestMetadataFieldLayoutAlgorithm.cs" />
+    <Compile Include="TypeNameParsingTests.cs" />
+    <Compile Include="UniversalGenericFieldLayoutTests.cs" />
+    <Compile Include="ValueTypeShapeCharacteristicsTests.cs" />
+    <Compile Include="VirtualFunctionOverrideTests.cs" />
+    <Compile Include="InstanceFieldLayoutTests.cs" />
+    <Compile Include="StaticFieldLayoutTests.cs" />
+    <Compile Include="TestTypeSystemContext.cs" />
+    <Compile Include="WellKnownTypeTests.cs" />
+  </ItemGroup>
+</Project>
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILDisassemblerTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILDisassemblerTests.cs
new file mode 100644 (file)
index 0000000..fc55923
--- /dev/null
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+
+using Internal.IL;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class ILDisassemblerTests
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        public ILDisassemblerTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = _context.GetModuleForSimpleName("ILTestAssembly");
+        }
+
+        [Fact]
+        public void TestGenericNameFormatting()
+        {
+            MetadataType testClass = _testModule.GetType("ILDisassembler", "TestGenericClass`1");
+            EcmaMethod testMethod = (EcmaMethod)testClass.GetMethod("TestMethod", null);
+            EcmaMethodIL methodIL = EcmaMethodIL.Create(testMethod);
+
+            Dictionary<int, string> interestingLines = new Dictionary<int, string>
+            {
+                { 4, "IL_0003:  ldstr       \"Hello \\\"World\\\"!\\n\"" },
+                { 9, "IL_000D:  call        instance void class ILDisassembler.TestGenericClass`1<!TClassParam>::VoidGenericMethod<string, valuetype ILDisassembler.TestStruct>(!!0, int32, native int, class ILDisassembler.TestClass&)" },
+                { 14, "IL_0017:  initobj     !TClassParam" },
+                { 16, "IL_001E:  call        !!0 class ILDisassembler.TestGenericClass`1<!TClassParam>::MethodParamGenericMethod<class ILDisassembler.TestClass>(class ILDisassembler.TestGenericClass`1<!!0>, class ILDisassembler.TestGenericClass`1/Nested<!0>, valuetype ILDisassembler.TestStruct*[], !0)" },
+                { 24, "IL_0030:  call        !!0 class ILDisassembler.TestGenericClass`1<!TClassParam>::MethodParamGenericMethod<!0>(class ILDisassembler.TestGenericClass`1<!!0>, class ILDisassembler.TestGenericClass`1/Nested<!0>, valuetype ILDisassembler.TestStruct*[], !0)" },
+                { 26, "IL_0036:  ldtoken     !TClassParam" },
+                { 28, "IL_003C:  ldtoken     valuetype [CoreTestAssembly]System.Nullable`1<int32>" },
+                { 31, "IL_0043:  ldc.r8      3.14" },
+                { 32, "IL_004C:  ldc.r4      1.68" },
+                { 34, "IL_0053:  call        instance valuetype ILDisassembler.TestStruct class ILDisassembler.TestGenericClass`1<!TClassParam>::NonGenericMethod(float64, float32, int16)" },
+                { 37, "IL_005A:  ldflda      !0 class ILDisassembler.TestGenericClass`1<!TClassParam>::somefield" },
+                { 41, "IL_0067:  stfld       class ILDisassembler.TestClass class ILDisassembler.TestGenericClass`1<!TClassParam>::otherfield" },
+                { 44, "IL_006E:  stfld       class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestClass>> class ILDisassembler.TestGenericClass`1<!TClassParam>::genericfield" },
+                { 47, "IL_0075:  stfld       !0[] class ILDisassembler.TestGenericClass`1<!TClassParam>::arrayfield" },
+                { 48, "IL_007A:  call        void ILDisassembler.TestClass::NonGenericMethod()" },
+                { 49, "IL_007F:  ldsflda     valuetype ILDisassembler.TestStruct ILDisassembler.TestClass::somefield" },
+                { 50, "IL_0084:  initobj     ILDisassembler.TestStruct" }
+            };
+
+            ILDisassembler disasm = new ILDisassembler(methodIL);
+
+            int numLines = 1;
+            while (disasm.HasNextInstruction)
+            {
+                string line = disasm.GetNextInstruction();
+                string expectedLine;
+                if (interestingLines.TryGetValue(numLines, out expectedLine))
+                {
+                    Assert.Equal(expectedLine, line);
+                }
+                numLines++;
+            }
+
+            Assert.Equal(52, numLines);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILDisassembler.il b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILDisassembler.il
new file mode 100644 (file)
index 0000000..56cb0a6
--- /dev/null
@@ -0,0 +1,181 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// While this is all expressible in C#, we need a deterministic IL to test the disassembler, hence
+// this is in IL.
+
+.class private sequential ansi sealed beforefieldinit ILDisassembler.TestStruct
+       extends [CoreTestAssembly]System.ValueType
+{
+  .pack 0
+  .size 1
+} // end of class ILDisassembler.TestStruct
+
+.class private auto ansi beforefieldinit ILDisassembler.TestClass
+       extends [CoreTestAssembly]System.Object
+{
+  .field public static valuetype ILDisassembler.TestStruct somefield
+  .method public hidebysig static void  NonGenericMethod() cil managed
+  {
+    // Code size       1 (0x1)
+    .maxstack  8
+    ret
+  } // end of method TestClass::NonGenericMethod
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    ldarg.0
+    call       instance void [CoreTestAssembly]System.Object::.ctor()
+    ret
+  } // end of method TestClass::.ctor
+
+} // end of class ILDisassembler.TestClass
+
+.class private auto ansi beforefieldinit ILDisassembler.TestGenericClass`1<TClassParam>
+       extends [CoreTestAssembly]System.Object
+{
+  .class auto ansi nested public beforefieldinit Nested<TClassParam>
+         extends [CoreTestAssembly]System.Object
+  {
+    .method public hidebysig specialname rtspecialname 
+            instance void  .ctor() cil managed
+    {
+      // Code size       7 (0x7)
+      .maxstack  8
+      ldarg.0
+      call       instance void [CoreTestAssembly]System.Object::.ctor()
+      ret
+    } // end of method Nested::.ctor
+
+  } // end of class Nested
+
+  .field private !TClassParam somefield
+  .field private class ILDisassembler.TestClass otherfield
+  .field private class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestClass>> genericfield
+  .field private !TClassParam[] arrayfield
+  .method public hidebysig instance void 
+          VoidGenericMethod<TMethodParam1,MethodParam2>(!!TMethodParam1 p,
+                                                        int32 x,
+                                                        native int y,
+                                                        class ILDisassembler.TestClass& z) cil managed
+  {
+    // Code size       1 (0x1)
+    .maxstack  8
+    ret
+  } // end of method TestGenericClass`1::VoidGenericMethod
+
+  .method public hidebysig static !!TMethodParam 
+          MethodParamGenericMethod<TMethodParam>(class ILDisassembler.TestGenericClass`1<!!TMethodParam> x,
+                                                 class ILDisassembler.TestGenericClass`1/Nested<!TClassParam> y,
+                                                 valuetype ILDisassembler.TestStruct*[] z,
+                                                 !TClassParam w) cil managed
+  {
+    // Code size       10 (0xa)
+    .maxstack  1
+    .locals init ([0] !!TMethodParam V_0)
+    ldloca.s   V_0
+    initobj    !!TMethodParam
+    ldloc.0
+    ret
+  } // end of method TestGenericClass`1::MethodParamGenericMethod
+
+  .method public hidebysig instance valuetype ILDisassembler.TestStruct 
+          NonGenericMethod(float64 x,
+                           float32 y,
+                           int16 z) cil managed
+  {
+    // Code size       10 (0xa)
+    .maxstack  1
+    .locals init ([0] valuetype ILDisassembler.TestStruct V_0)
+    ldloca.s   V_0
+    initobj    ILDisassembler.TestStruct
+    ldloc.0
+    ret
+  } // end of method TestGenericClass`1::NonGenericMethod
+
+  .method public hidebysig instance void 
+          TestMethod() cil managed
+  {
+    // Code size       162 (0xa2)
+    .maxstack  5
+    .locals init ([0] class ILDisassembler.TestClass t,
+             [1] !TClassParam V_1)
+    ldnull
+    stloc.0
+    ldarg.0
+    ldstr      "Hello \"World\"!\n"
+    ldc.i4.0
+    ldc.i4.0
+    conv.i
+    ldloca.s   t
+    call       instance void class ILDisassembler.TestGenericClass`1<!TClassParam>::VoidGenericMethod<string,valuetype ILDisassembler.TestStruct>(!!0,
+                                                                                                                                                 int32,
+                                                                                                                                                 native int,
+                                                                                                                                                 class ILDisassembler.TestClass&)
+    ldnull
+    ldnull
+    ldnull
+    ldloca.s   V_1
+    initobj    !TClassParam
+    ldloc.1
+    call       !!0 class ILDisassembler.TestGenericClass`1<!TClassParam>::MethodParamGenericMethod<class ILDisassembler.TestClass>(class ILDisassembler.TestGenericClass`1<!!0>,
+                                                                                                                                  class ILDisassembler.TestGenericClass`1/Nested<!0>,
+                                                                                                                                  valuetype ILDisassembler.TestStruct*[],
+                                                                                                                                  !0)
+    pop
+    ldnull
+    ldnull
+    ldnull
+    ldloca.s   V_1
+    initobj    !TClassParam
+    ldloc.1
+    call       !!0 class ILDisassembler.TestGenericClass`1<!TClassParam>::MethodParamGenericMethod<!0>(class ILDisassembler.TestGenericClass`1<!!0>,
+                                                                                                      class ILDisassembler.TestGenericClass`1/Nested<!0>,
+                                                                                                      valuetype ILDisassembler.TestStruct*[],
+                                                                                                      !0)
+    pop
+    ldtoken    !TClassParam
+    pop
+    ldtoken    valuetype [CoreTestAssembly]System.Nullable`1<int32>
+    pop
+    ldarg.0
+    ldc.r8     3.1400000000000001
+    ldc.r4     1.6799999
+    ldc.i4.s   42
+    call       instance valuetype ILDisassembler.TestStruct class ILDisassembler.TestGenericClass`1<!TClassParam>::NonGenericMethod(float64,
+                                                                                                                                   float32,
+                                                                                                                                   int16)
+    pop
+    ldarg.0
+    ldflda     !0 class ILDisassembler.TestGenericClass`1<!TClassParam>::somefield
+    initobj    !TClassParam
+    ldarg.0
+    ldnull
+    stfld      class ILDisassembler.TestClass class ILDisassembler.TestGenericClass`1<!TClassParam>::otherfield
+    ldarg.0
+    ldnull
+    stfld      class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestClass>> class ILDisassembler.TestGenericClass`1<!TClassParam>::genericfield
+    ldarg.0
+    ldnull
+    stfld      !0[] class ILDisassembler.TestGenericClass`1<!TClassParam>::arrayfield
+    call       void ILDisassembler.TestClass::NonGenericMethod()
+    ldsflda    valuetype ILDisassembler.TestStruct ILDisassembler.TestClass::somefield
+    initobj    ILDisassembler.TestStruct
+    ret
+  } // end of method TestGenericClass`1::TestMethod
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    ldarg.0
+    call       instance void [CoreTestAssembly]System.Object::.ctor()
+    ret
+  } // end of method TestGenericClass`1::.ctor
+
+} // end of class ILDisassembler.TestGenericClass`1
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj
new file mode 100644 (file)
index 0000000..3b75036
--- /dev/null
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk.IL">
+
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <AssemblyName>ILTestAssembly</AssemblyName>
+    <SkipTestRun>true</SkipTestRun>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <EnableDefaultItems>false</EnableDefaultItems>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <!-- Main has to be the first file. Do not put anything before Main.il -->
+    <Compile Include="Main.il" />
+
+    <Compile Include="ILDisassembler.il" />
+    <Compile Include="InstanceFieldLayout.il" />
+    <Compile Include="StaticFieldLayout.il" />
+    <Compile Include="VirtualFunctionOverride.il" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/InstanceFieldLayout.il b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/InstanceFieldLayout.il
new file mode 100644 (file)
index 0000000..2a07e9e
--- /dev/null
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.class public sequential ansi sealed beforefieldinit IsByRefLike.InvalidStruct
+       extends [CoreTestAssembly]System.ValueType
+{
+  .field private valuetype [CoreTestAssembly]System.ByReference`1<object> ByRef
+}
+
+.class public auto ansi beforefieldinit IsByRefLike.InvalidClass1
+       extends [CoreTestAssembly]System.Object
+{
+  .field private valuetype [CoreTestAssembly]System.ByReference`1<object> ByRef
+}
+
+.class public auto ansi beforefieldinit IsByRefLike.InvalidClass2
+       extends [CoreTestAssembly]System.Object
+{
+  .custom instance void [CoreTestAssembly]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( 01 00 00 00 ) 
+  .field private valuetype [CoreTestAssembly]System.ByReference`1<object> ByRef
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/Main.il b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/Main.il
new file mode 100644 (file)
index 0000000..dc7aef4
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.assembly extern CoreTestAssembly
+{
+}
+
+.assembly ILTestAssembly
+{
+}
+
+// Mark this as core library so that ILASM doesn't take the code paths that
+// 'fix' all the references to e.g. System.Object to be mscorlib.
+.mscorlib
+
+
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/StaticFieldLayout.il b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/StaticFieldLayout.il
new file mode 100644 (file)
index 0000000..ca2b748
--- /dev/null
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.class public auto ansi beforefieldinit StaticFieldLayout.RvaStatics
+       extends [CoreTestAssembly]System.Object
+{
+  .field private static int32 StaticInitedInt at D_00004000
+  .data D_00004000 = bytearray (12 34 56 78) 
+}
+
+.class public auto ansi beforefieldinit StaticFieldLayout.FunctionPointerType
+       extends [CoreTestAssembly]System.Object
+{
+  .field private static int32 StaticIntField;
+  .field private static method object *(object) StaticMethodField;
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/VirtualFunctionOverride.il b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/VirtualFunctionOverride.il
new file mode 100644 (file)
index 0000000..f0f2437
--- /dev/null
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.class public auto ansi beforefieldinit VirtualFunctionOverride.ExplicitOverride
+       extends [CoreTestAssembly]System.Object
+{
+  .method public virtual int32 MyGetHashCode()
+  {
+    .override [CoreTestAssembly]System.Object::GetHashCode
+
+    ldc.i4 42
+    ret
+  }
+}
+
+.class private auto ansi beforefieldinit VirtualFunctionOverride.MyBase
+       extends [CoreTestAssembly]System.Object
+{
+  .method public hidebysig newslot specialname virtual 
+          instance int32  get_foo() cil managed
+  {
+    ldc.i4 42
+    ret
+  }
+
+  .property instance int32 foo()
+  {
+    .get instance int32 VirtualFunctionOverride.MyBase::get_foo()
+  }
+}
+
+.class private auto ansi beforefieldinit VirtualFunctionOverride.MyDerived2
+       extends VirtualFunctionOverride.MyBase
+{
+  .method public hidebysig newslot specialname virtual 
+          instance int32  get_foo() cil managed
+  {
+    .override VirtualFunctionOverride.MyBase::get_foo
+    
+    ldc.i4 42
+    ret
+  }
+
+  .property instance int32 foo()
+  {
+    .get instance int32 VirtualFunctionOverride.MyDerived2::get_foo()
+  }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs
new file mode 100644 (file)
index 0000000..142abfd
--- /dev/null
@@ -0,0 +1,860 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class InstanceFieldLayoutTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+        ModuleDesc _ilTestModule;
+
+        public InstanceFieldLayoutTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+            _ilTestModule = _context.CreateModuleForSimpleName("ILTestAssembly");
+        }
+
+        [Fact]
+        public void TestExplicitLayout()
+        {
+            MetadataType t = _testModule.GetType("Explicit", "Class1");
+
+            // With 64bit, there should be 8 bytes for the System.Object EE data pointer +
+            // 10 bytes up until the offset of the char field + the char size of 2 + we 
+            // round up the whole instance size to the next pointer size (+4) = 24
+            Assert.Equal(24, t.InstanceByteCount.AsInt);
+
+            foreach (var field in t.GetFields())
+            {
+                if (field.IsStatic)
+                    continue;
+
+                if (field.Name == "Bar")
+                {
+                    // Bar has explicit offset 4 and is in a class (with S.O size overhead of <pointer size>)
+                    // Therefore it should have offset 4 + 8 = 12
+                  Assert.Equal(12, field.Offset.AsInt);
+                }
+                else if (field.Name == "Baz")
+                {
+                    // Baz has explicit offset 10. 10 + 8 = 18
+                    Assert.Equal(18, field.Offset.AsInt);
+                }
+                else
+                {
+                    Assert.True(false);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestExplicitLayoutThatIsEmpty()
+        {
+            var explicitEmptyClassType = _testModule.GetType("Explicit", "ExplicitEmptyClass");
+
+            // ExplicitEmpty class has 8 from System.Object overhead = 8
+            Assert.Equal(8, explicitEmptyClassType.InstanceByteCount.AsInt);
+
+            var explicitEmptyStructType = _testModule.GetType("Explicit", "ExplicitEmptyStruct");
+
+            // ExplicitEmpty class has 0 bytes in it... so instance field size gets pushed up to 1.
+            Assert.Equal(1, explicitEmptyStructType.InstanceFieldSize.AsInt);
+        }
+
+        [Fact]
+        public void TestExplicitTypeLayoutWithSize()
+        {
+            var explicitSizeType = _testModule.GetType("Explicit", "ExplicitSize");
+            Assert.Equal(48, explicitSizeType.InstanceByteCount.AsInt);
+        }
+
+        [Fact]
+        public void TestExplicitTypeLayoutWithInheritance()
+        {
+            MetadataType class2Type = _testModule.GetType("Explicit", "Class2");
+
+            // Class1 has size 24 which Class2 inherits from.  Class2 adds a byte at offset 20, so + 21
+            // = 45, rounding up to the next pointer size = 48
+            Assert.Equal(48, class2Type.InstanceByteCount.AsInt);
+
+            foreach (var f in class2Type.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                if (f.Name == "Lol")
+                {
+                    // First field after base class, with offset 0 so it should lie on the byte count of 
+                    // the base class = 24
+                    Assert.Equal(24, f.Offset.AsInt);
+                }
+                else if (f.Name == "Omg")
+                {
+                    // Offset 20 from base class byte count = 44
+                    Assert.Equal(44, f.Offset.AsInt);
+                }
+                else
+                {
+                    Assert.True(false);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestInvalidExplicitTypeLayout()
+        {
+            {
+                DefType type = _testModule.GetType("Explicit", "MisalignedPointer");
+                Assert.Throws<TypeSystemException.TypeLoadException>(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields));
+            }
+
+            {
+                DefType type = _testModule.GetType("Explicit", "MisalignedByRef");
+                Assert.Throws<TypeSystemException.TypeLoadException>(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields));
+            }
+        }
+
+        [Fact]
+        public void TestSequentialTypeLayout()
+        {
+            MetadataType class1Type = _testModule.GetType("Sequential", "Class1");
+
+            // Byte count
+            // Base Class       8
+            // MyInt            4
+            // MyBool           1 + 1 padding
+            // MyChar           2
+            // MyString         8
+            // MyByteArray      8
+            // MyClass1SelfRef  8
+            // -------------------
+            //                  40 (0x28)
+            Assert.Equal(0x28, class1Type.InstanceByteCount.AsInt);
+
+            foreach (var f in class1Type.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyInt":
+                        Assert.Equal(0x8, f.Offset.AsInt);
+                        break;
+                    case "MyBool":
+                        Assert.Equal(0xC, f.Offset.AsInt);
+                        break;
+                    case "MyChar":
+                        Assert.Equal(0xE, f.Offset.AsInt);
+                        break;
+                    case "MyString":
+                        Assert.Equal(0x10, f.Offset.AsInt);
+                        break;
+                    case "MyByteArray":
+                        Assert.Equal(0x18, f.Offset.AsInt);
+                        break;
+                    case "MyClass1SelfRef":
+                        Assert.Equal(0x20, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestSequentialTypeLayoutInheritance()
+        {
+            MetadataType class2Type = _testModule.GetType("Sequential", "Class2");
+
+            // Byte count
+            // Base Class       40
+            // MyInt2           4 + 4 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  48 (0x30)
+            Assert.Equal(0x30, class2Type.InstanceByteCount.AsInt);
+
+            foreach (var f in class2Type.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyInt2":
+                        Assert.Equal(0x28, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestSequentialTypeLayoutStruct()
+        {
+            MetadataType struct0Type = _testModule.GetType("Sequential", "Struct0");
+
+            // Byte count
+            // bool     b1      1
+            // bool     b2      1
+            // bool     b3      1 + 1 padding for int alignment
+            // int      i1      4
+            // string   s1      8
+            // -------------------
+            //                  16 (0x10)
+            Assert.Equal(0x10, struct0Type.InstanceByteCount.AsInt);
+
+            foreach (var f in struct0Type.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "b1":
+                        Assert.Equal(0x0, f.Offset.AsInt);
+                        break;
+                    case "b2":
+                        Assert.Equal(0x1, f.Offset.AsInt);
+                        break;
+                    case "b3":
+                        Assert.Equal(0x2, f.Offset.AsInt);
+                        break;
+                    case "i1":
+                        Assert.Equal(0x4, f.Offset.AsInt);
+                        break;
+                    case "s1":
+                        Assert.Equal(0x8, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        // Test that when a struct is used as a field, we use its instance byte size as the size (ie, treat it
+        // as a value type) and not a pointer size.
+        public void TestSequentialTypeLayoutStructEmbedded()
+        {
+            MetadataType struct1Type = _testModule.GetType("Sequential", "Struct1");
+
+            // Byte count
+            // struct   MyStruct0   16
+            // bool     MyBool      1
+            // -----------------------
+            //                      24 (0x18)
+            Assert.Equal(0x18, struct1Type.InstanceByteCount.AsInt);
+
+            foreach (var f in struct1Type.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyStruct0":
+                        Assert.Equal(0x0, f.Offset.AsInt);
+                        break;
+                    case "MyBool":
+                        Assert.Equal(0x10, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoLayoutStruct()
+        {
+            MetadataType structWithIntCharType = _testModule.GetType("Auto", "StructWithIntChar");
+
+            // Byte count
+            // MyStructInt       4
+            // MyStructChar      2
+            // -------------------
+            //                   8 (0x08)
+            Assert.Equal(0x08, structWithIntCharType.InstanceByteCount.AsInt);
+
+            foreach (var f in structWithIntCharType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyStructInt":
+                        Assert.Equal(0x00, f.Offset.AsInt);
+                        break;
+                    case "MyStructChar":
+                        Assert.Equal(0x04, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutClassContainingStructs()
+        {
+            MetadataType classContainingStructsType = _testModule.GetType("Auto", "ClassContainingStructs");
+
+            // Byte count
+            // Base Class           8
+            // MyByteArray          8
+            // MyString1            8
+            // MyDouble             8
+            // MyLong               8
+            // MyInt                4
+            // MyChar1              2
+            // MyBool1              1
+            // MyBool2              1
+            // MyStructWithBool     1 + 3 to align up to the next multiple of 4 after placing a value class
+            //                      4 byte padding to make offset % pointer size == 0 before placing the next value class
+            // MyStructWithIntChar  6 + 2 to align up to the next multiple of 4 after placing a value class
+            // MyStructWithChar     2 + 2 to align up to the next multiple of 4 after placing a value class + 4 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  72 (0x48)
+            Assert.Equal(0x48, classContainingStructsType.InstanceByteCount.AsInt);
+
+            foreach (var f in classContainingStructsType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyByteArray":
+                        Assert.Equal(0x08, f.Offset.AsInt);
+                        break;
+                    case "MyString1":
+                        Assert.Equal(0x10, f.Offset.AsInt);
+                        break;
+                    case "MyDouble":
+                        Assert.Equal(0x18, f.Offset.AsInt);
+                        break;
+                    case "MyLong":
+                        Assert.Equal(0x20, f.Offset.AsInt);
+                        break;
+                    case "MyInt":
+                        Assert.Equal(0x28, f.Offset.AsInt);
+                        break;
+                    case "MyChar1":
+                        Assert.Equal(0x2C, f.Offset.AsInt);
+                        break;
+                    case "MyBool1":
+                        Assert.Equal(0x2E, f.Offset.AsInt);
+                        break;
+                    case "MyBool2":
+                        Assert.Equal(0x2F, f.Offset.AsInt);
+                        break;
+                    case "MyStructWithBool":
+                        Assert.Equal(0x30, f.Offset.AsInt);
+                        break;
+                    case "MyStructWithIntChar":
+                        Assert.Equal(0x38, f.Offset.AsInt);
+                        break;
+                    case "MyStructWithChar":
+                        Assert.Equal(0x40, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutBaseClass7BytesRemaining()
+        {
+            MetadataType baseClass7BytesRemainingType = _testModule.GetType("Auto", "BaseClass7BytesRemaining");
+
+            // Byte count
+            // Base Class       8
+            // MyByteArray1     8
+            // MyString1        8
+            // MyDouble1        8
+            // MyLong1          8
+            // MyBool1          1 + 7 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  48 (0x30)
+            Assert.Equal(0x30, baseClass7BytesRemainingType.InstanceByteCount.AsInt);
+
+            foreach (var f in baseClass7BytesRemainingType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyByteArray1":
+                        Assert.Equal(0x08, f.Offset.AsInt);
+                        break;
+                    case "MyString1":
+                        Assert.Equal(0x10, f.Offset.AsInt);
+                        break;
+                    case "MyDouble1":
+                        Assert.Equal(0x18, f.Offset.AsInt);
+                        break;
+                    case "MyLong1":
+                        Assert.Equal(0x20, f.Offset.AsInt);
+                        break;
+                    case "MyBool1":
+                        Assert.Equal(0x28, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutBaseClass4BytesRemaining()
+        {
+            MetadataType baseClass4BytesRemainingType = _testModule.GetType("Auto", "BaseClass4BytesRemaining");
+
+            // Byte count
+            // Base Class       8
+            // MyLong1          8
+            // MyUint1          4 + 4 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  24 (0x18)
+            Assert.Equal(0x18, baseClass4BytesRemainingType.InstanceByteCount.AsInt);
+
+            foreach (var f in baseClass4BytesRemainingType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyLong1":
+                        Assert.Equal(0x08, f.Offset.AsInt);
+                        break;
+                    case "MyUint1":
+                        Assert.Equal(0x10, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutBaseClass3BytesRemaining()
+        {
+            MetadataType baseClass3BytesRemainingType = _testModule.GetType("Auto", "BaseClass3BytesRemaining");
+
+            // Byte count
+            // Base Class       8
+            // MyString1        8
+            // MyInt1           4
+            // MyBool1          1 + 3 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  24 (0x18)
+            Assert.Equal(0x18, baseClass3BytesRemainingType.InstanceByteCount.AsInt);
+
+            foreach (var f in baseClass3BytesRemainingType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "MyString1":
+                        Assert.Equal(0x08, f.Offset.AsInt);
+                        break;
+                    case "MyInt1":
+                        Assert.Equal(0x10, f.Offset.AsInt);
+                        break;
+                    case "MyBool1":
+                        Assert.Equal(0x14, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutOptimizePartial()
+        {
+            MetadataType optimizePartialType = _testModule.GetType("Auto", "OptimizePartial");
+
+            // Byte count
+            // Base Class       41 (unaligned)
+            // OptBool          1
+            // OptChar          2 + 4 byte padding to make class size % pointer size == 0
+            // NoOptString      8
+            // NoOptLong        8
+            // -------------------
+            //                  64 (0x40)
+            Assert.Equal(0x40, optimizePartialType.InstanceByteCount.AsInt);
+
+            foreach (var f in optimizePartialType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "OptBool":
+                        Assert.Equal(0x29, f.Offset.AsInt);
+                        break;
+                    case "OptChar":
+                        Assert.Equal(0x2A, f.Offset.AsInt);
+                        break;
+                    case "NoOptString":
+                        Assert.Equal(0x30, f.Offset.AsInt);
+                        break;
+                    case "NoOptLong":
+                        Assert.Equal(0x38, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutOptimize7Bools()
+        {
+            MetadataType optimize7BoolsType = _testModule.GetType("Auto", "Optimize7Bools");
+
+            // Byte count
+            // Base Class       41 (unaligned)
+            // OptBool1         1
+            // OptBool2         1
+            // OptBool3         1
+            // OptBool4         1
+            // OptBool5         1
+            // OptBool6         1
+            // OptBool7         1
+            // NoOptString      8
+            // NoOptBool8       1 + 7 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  64 (0x40)
+            Assert.Equal(0x40, optimize7BoolsType.InstanceByteCount.AsInt);
+
+            foreach (var f in optimize7BoolsType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "OptBool1":
+                        Assert.Equal(0x29, f.Offset.AsInt);
+                        break;
+                    case "OptBool2":
+                        Assert.Equal(0x2A, f.Offset.AsInt);
+                        break;
+                    case "OptBool3":
+                        Assert.Equal(0x2B, f.Offset.AsInt);
+                        break;
+                    case "OptBool4":
+                        Assert.Equal(0x2C, f.Offset.AsInt);
+                        break;
+                    case "OptBool5":
+                        Assert.Equal(0x2D, f.Offset.AsInt);
+                        break;
+                    case "OptBool6":
+                        Assert.Equal(0x2E, f.Offset.AsInt);
+                        break;
+                    case "OptBool7":
+                        Assert.Equal(0x2F, f.Offset.AsInt);
+                        break;
+                    case "NoOptString":
+                        Assert.Equal(0x30, f.Offset.AsInt);
+                        break;
+                    case "NoOptBool8":
+                        Assert.Equal(0x38, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutOptimizeAlignedFields()
+        {
+            MetadataType optimizeAlignedFieldsType = _testModule.GetType("Auto", "OptimizeAlignedFields");
+
+            // Byte count
+            // Base Class       41 (unaligned)
+            // OptBool1         1
+            // OptChar1         2
+            // OptChar2         2
+            // OptBool2         1
+            // OptBool3         1
+            // NoOptString      8
+            // NoOptBool4       1 + 7 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  64 (0x40)
+            Assert.Equal(0x40, optimizeAlignedFieldsType.InstanceByteCount.AsInt);
+
+            foreach (var f in optimizeAlignedFieldsType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "OptBool1":
+                        Assert.Equal(0x29, f.Offset.AsInt);
+                        break;
+                    case "OptChar1":
+                        Assert.Equal(0x2A, f.Offset.AsInt);
+                        break;
+                    case "OptChar2":
+                        Assert.Equal(0x2C, f.Offset.AsInt);
+                        break;
+                    case "OptBool2":
+                        Assert.Equal(0x2E, f.Offset.AsInt);
+                        break;
+                    case "OptBool3":
+                        Assert.Equal(0x2F, f.Offset.AsInt);
+                        break;
+                    case "NoOptString":
+                        Assert.Equal(0x30, f.Offset.AsInt);
+                        break;
+                    case "NoOptBool4":
+                        Assert.Equal(0x38, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutOptimizeLargestField()
+        {
+            MetadataType optimizeLargestFieldType = _testModule.GetType("Auto", "OptimizeLargestField");
+
+            // Byte count
+            // Base Class       20 (unaligned)
+            // OptInt           4
+            // NoOptString      8
+            // NoOptChar        2
+            // NoOptBool        1 + 5 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  40 (0x28)
+            Assert.Equal(0x28, optimizeLargestFieldType.InstanceByteCount.AsInt);
+
+            foreach (var f in optimizeLargestFieldType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "OptInt":
+                        Assert.Equal(0x14, f.Offset.AsInt);
+                        break;
+                    case "NoOptString":
+                        Assert.Equal(0x18, f.Offset.AsInt);
+                        break;
+                    case "NoOptChar":
+                        Assert.Equal(0x20, f.Offset.AsInt);
+                        break;
+                    case "NoOptBool":
+                        Assert.Equal(0x22, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutNoOptimizeMisaligned()
+        {
+            MetadataType noOptimizeMisalignedType = _testModule.GetType("Auto", "NoOptimizeMisaligned");
+
+            // Byte count
+            // Base Class       21 (unaligned) + 3 byte padding to make class size % pointer size == 0
+            // NoOptString      8
+            // NoOptInt         4
+            // NoOptChar        2 + 2 byte padding to make class size % pointer size == 0
+            // -------------------
+            //                  40 (0x28)
+            Assert.Equal(0x28, noOptimizeMisalignedType.InstanceByteCount.AsInt);
+
+            foreach (var f in noOptimizeMisalignedType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "NoOptString":
+                        Assert.Equal(0x18, f.Offset.AsInt);
+                        break;
+                    case "NoOptInt":
+                        Assert.Equal(0x20, f.Offset.AsInt);
+                        break;
+                    case "NoOptChar":
+                        Assert.Equal(0x24, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        [Fact]
+        public void TestAutoTypeLayoutNoOptimizeCharAtSize2Alignment()
+        {
+            MetadataType noOptimizeCharAtSize2AlignmentType = _testModule.GetType("Auto", "NoOptimizeCharAtSize2Alignment");
+
+            // Byte count
+            // Base Class       21 (unaligned) + 1 byte padding to align char
+            // NoOptChar        2
+            // -------------------
+            //                  24 (0x18)
+            Assert.Equal(0x18, noOptimizeCharAtSize2AlignmentType.InstanceByteCount.AsInt);
+
+            foreach (var f in noOptimizeCharAtSize2AlignmentType.GetFields())
+            {
+                if (f.IsStatic)
+                    continue;
+
+                switch (f.Name)
+                {
+                    case "NoOptChar":
+                        Assert.Equal(0x16, f.Offset.AsInt);
+                        break;
+                    default:
+                        Assert.True(false);
+                        break;
+                }
+            }
+        }
+
+        public static IEnumerable<object[]> AutoTypeLayoutMinPackingData()
+        {
+            yield return new object[] { WellKnownType.Boolean, 2 };
+            yield return new object[] { WellKnownType.Byte, 2 };
+            yield return new object[] { WellKnownType.Char, 4 };
+            yield return new object[] { WellKnownType.Double, 16 };
+            yield return new object[] { WellKnownType.Int16, 4 };
+            yield return new object[] { WellKnownType.Int32, 8 };
+            yield return new object[] { WellKnownType.Int64, 16 };
+            yield return new object[] { WellKnownType.IntPtr, 16 };
+            yield return new object[] { WellKnownType.Single, 8 };
+        }
+
+        [Theory]
+        [MemberData(nameof(AutoTypeLayoutMinPackingData))]
+        public void TestAutoTypeLayoutMinPacking(WellKnownType type, int expectedSize)
+        {
+            MetadataType minPackingType = _testModule.GetType("Auto", "MinPacking`1");
+            InstantiatedType inst = minPackingType.MakeInstantiatedType(_context.GetWellKnownType(type));
+            Assert.Equal(expectedSize, inst.InstanceFieldSize.AsInt);
+        }
+
+        [Fact]
+        public void TestTypeContainsGCPointers()
+        {
+            MetadataType type = _testModule.GetType("ContainsGCPointers", "NoPointers");
+            Assert.False(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "StillNoPointers");
+            Assert.False(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "ClassNoPointers");
+            Assert.False(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "HasPointers");
+            Assert.True(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "FieldHasPointers");
+            Assert.True(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "ClassHasPointers");
+            Assert.True(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "BaseClassHasPointers");
+            Assert.True(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "ClassHasIntArray");
+            Assert.True(type.ContainsGCPointers);
+
+            type = _testModule.GetType("ContainsGCPointers", "ClassHasArrayOfClassType");
+            Assert.True(type.ContainsGCPointers);
+        }
+
+        [Fact]
+        public void TestByRefLikeTypes()
+        {
+            {
+                DefType type = _context.GetWellKnownType(WellKnownType.TypedReference);
+                Assert.True(type.IsByRefLike);
+            }
+
+            {
+                DefType type = _context.GetWellKnownType(WellKnownType.ByReferenceOfT);
+                Assert.True(type.IsByRefLike);
+            }
+
+            {
+                DefType type = _testModule.GetType("IsByRefLike", "ByRefLikeStruct");
+                Assert.True(type.IsByRefLike);
+            }
+
+            {
+                DefType type = _testModule.GetType("IsByRefLike", "NotByRefLike");
+                Assert.False(type.IsByRefLike);
+            }
+        }
+
+        [Fact]
+        public void TestInvalidByRefLikeTypes()
+        {
+            {
+                DefType type = _ilTestModule.GetType("IsByRefLike", "InvalidClass1");
+                Assert.Throws<TypeSystemException.TypeLoadException>(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields));
+            }
+
+            {
+                DefType type = _ilTestModule.GetType("IsByRefLike", "InvalidClass2");
+                Assert.Throws<TypeSystemException.TypeLoadException>(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields));
+            }
+
+            {
+                DefType type = _ilTestModule.GetType("IsByRefLike", "InvalidStruct");
+                Assert.Throws<TypeSystemException.TypeLoadException>(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields));
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs
new file mode 100644 (file)
index 0000000..7f741fa
--- /dev/null
@@ -0,0 +1,191 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Linq;
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class InterfacesTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        public InterfacesTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestMultidimensionalArrays()
+        {
+            DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array);
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            ArrayType objectMDArray = _context.GetArrayType(objectType, 2);
+
+            // MD array should have the same set of interfaces as System.Array
+            Assert.Equal(systemArrayType.RuntimeInterfaces, objectMDArray.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestSingleDimensionalArrays()
+        {
+            DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array);
+            MetadataType systemIListOfTType = _testModule.GetType("System.Collections.Generic", "IList`1");
+
+            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+            ArrayType objectArray = _context.GetArrayType(objectType);
+
+            // The set of interfaces on an array shall start with the same set that exists on System.Array
+            for (int i = 0; i < systemArrayType.RuntimeInterfaces.Length; i++)
+            {
+                Assert.Equal(systemArrayType.RuntimeInterfaces[i], objectArray.RuntimeInterfaces[i]);
+            }
+
+            // The set of interfaces on an array of type T shall include IList<T>
+            TypeDesc ilistOfObject = systemIListOfTType.MakeInstantiatedType(objectType);
+            Assert.Contains(ilistOfObject, objectArray.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestNoInterface()
+        {
+            MetadataType noInterfacesType = _testModule.GetType("InterfaceArrangements", "NoInterfaces");
+            Assert.Empty(noInterfacesType.RuntimeInterfaces);
+        }
+
+
+        [Fact]
+        public void TestOneInterface()
+        {
+            MetadataType oneInterfacesType = _testModule.GetType("InterfaceArrangements", "OneInterface");
+            MetadataType i1Type = _testModule.GetType("InterfaceArrangements", "I1");
+
+            Assert.Equal(new DefType[] { i1Type }, oneInterfacesType.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestOverlappingInterfacesAtDerivation()
+        {
+            // This test tests that an explicit interface implementation on a type does not cause the
+            // set of runtime interfaces to get extra duplication
+            MetadataType derivedFromMidType = _testModule.GetType("InterfaceArrangements", "DerivedFromMid");
+            MetadataType igen1Type = _testModule.GetType("InterfaceArrangements", "IGen1`1");
+            TypeDesc stringType = _testModule.Context.GetWellKnownType(WellKnownType.String);
+            DefType igen1OfString = igen1Type.MakeInstantiatedType(stringType);
+            MetadataType i1Type = _testModule.GetType("InterfaceArrangements", "I1");
+
+            Assert.Equal(new DefType[] { igen1OfString, i1Type, igen1OfString }, derivedFromMidType.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestOverlappingGenericInterfaces()
+        {
+            // This test tests that the set of interfaces implemented on a generic type definition
+            // has the same arrangement regardless of instantiation
+            MetadataType midType = _testModule.GetType("InterfaceArrangements", "Mid`2");
+            MetadataType igen1Type = _testModule.GetType("InterfaceArrangements", "IGen1`1");
+            TypeDesc stringType = _testModule.Context.GetWellKnownType(WellKnownType.String);
+            TypeDesc objectType = _testModule.Context.GetWellKnownType(WellKnownType.Object);
+            DefType igen1OfString = igen1Type.MakeInstantiatedType(stringType);
+            DefType igen1OfObject = igen1Type.MakeInstantiatedType(objectType);
+            MetadataType i1Type = _testModule.GetType("InterfaceArrangements", "I1");
+
+            TypeDesc mid_string_string = midType.MakeInstantiatedType(stringType, stringType);
+            TypeDesc mid_string_object = midType.MakeInstantiatedType(stringType, objectType);
+            TypeDesc mid_object_string = midType.MakeInstantiatedType(objectType, stringType);
+            TypeDesc mid_object_object = midType.MakeInstantiatedType(objectType, objectType);
+
+            Assert.Equal(new DefType[] { igen1OfString, i1Type, igen1OfString }, mid_string_string.RuntimeInterfaces);
+            Assert.Equal(new DefType[] { igen1OfString, i1Type, igen1OfObject }, mid_string_object.RuntimeInterfaces);
+            Assert.Equal(new DefType[] { igen1OfObject, i1Type, igen1OfString }, mid_object_string.RuntimeInterfaces);
+            Assert.Equal(new DefType[] { igen1OfObject, i1Type, igen1OfObject }, mid_object_object.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestInterfaceRequiresImplmentation()
+        {
+            MetadataType i1Type = _testModule.GetType("InterfaceArrangements", "I1");
+            MetadataType i2Type = _testModule.GetType("InterfaceArrangements", "I2");
+
+            Assert.Empty(i1Type.RuntimeInterfaces);
+            Assert.Equal(i1Type.ExplicitlyImplementedInterfaces, i1Type.RuntimeInterfaces);
+
+            Assert.Equal(new DefType[] { i1Type }, i2Type.RuntimeInterfaces);
+            Assert.Equal(i2Type.ExplicitlyImplementedInterfaces, i2Type.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestPointerArrayInterfaces()
+        {
+            MetadataType systemArrayType = _testModule.GetType("System", "Array");
+            TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+            TypeDesc intPointerType = _context.GetPointerType(intType);
+
+            ArrayType intPointerArray = _context.GetArrayType(intPointerType);
+
+            // Pointer arrays should have the same set of interfaces as System.Array
+            Assert.Equal(systemArrayType.RuntimeInterfaces, intPointerArray.RuntimeInterfaces);
+        }
+
+        [Fact]
+        public void TestInterafaceMethodResolution()
+        {
+            MetadataType fooType = _testModule.GetType("InterfaceArrangements", "Foo");
+            MetadataType derivedType = _testModule.GetType("InterfaceArrangements", "DerivedFromFoo");
+            MetadataType superDerivedType = _testModule.GetType("InterfaceArrangements", "SuperDerivedFromFoo");
+
+            MetadataType ifooOfInt = _testModule.GetType("InterfaceArrangements", "IFoo`1").MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+            MetadataType ifooOfString = _testModule.GetType("InterfaceArrangements", "IFoo`1").MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.String));
+
+            MethodDesc ifooOfIntMethod = ifooOfInt.GetMethods().Where(m => m.Name == "IMethod").Single();
+            MethodDesc ifooOfStringMethod = ifooOfString.GetMethods().Where(m => m.Name == "IMethod").Single();
+
+            MethodDesc result;
+
+            // Resolve on type Foo
+            {
+                result = fooType.ResolveInterfaceMethodTarget(ifooOfIntMethod);
+                Assert.NotNull(result);
+                Assert.Equal(result.OwningType, fooType);
+
+                result = fooType.ResolveInterfaceMethodTarget(ifooOfStringMethod);
+                Assert.NotNull(result);
+                Assert.Equal(result.OwningType, fooType);
+            }
+
+            // Resolve on type DerivedFromFoo
+            {
+                result = derivedType.ResolveInterfaceMethodTarget(ifooOfIntMethod);
+                Assert.NotNull(result);
+                Assert.Equal(result.OwningType, fooType);
+
+                result = derivedType.ResolveInterfaceMethodTarget(ifooOfStringMethod);
+                Assert.NotNull(result);
+                Assert.Equal(result.OwningType, derivedType);
+            }
+
+
+            // Resolve on type SuperDerivedFromFoo
+            {
+                result = superDerivedType.ResolveInterfaceMethodTarget(ifooOfIntMethod);
+                Assert.NotNull(result);
+                Assert.Equal(result.OwningType, superDerivedType);
+
+                result = superDerivedType.ResolveInterfaceMethodTarget(ifooOfStringMethod);
+                Assert.NotNull(result);
+                Assert.Equal(result.OwningType, derivedType);
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs
new file mode 100644 (file)
index 0000000..876c1ce
--- /dev/null
@@ -0,0 +1,173 @@
+// Licensed to the.NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class RuntimeDeterminedTypesTests
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        private MetadataType _referenceType;
+        private MetadataType _otherReferenceType;
+        private MetadataType _structType;
+        private MetadataType _otherStructType;
+        private MetadataType _genericReferenceType;
+        private MetadataType _genericStructType;
+        private MetadataType _genericReferenceTypeWithThreeParams;
+        private MetadataType _genericStructTypeWithThreeParams;
+
+        public RuntimeDeterminedTypesTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+            
+            _testModule = systemModule;
+
+            _referenceType = _testModule.GetType("Canonicalization", "ReferenceType");
+            _otherReferenceType = _testModule.GetType("Canonicalization", "OtherReferenceType");
+            _structType = _testModule.GetType("Canonicalization", "StructType");
+            _otherStructType = _testModule.GetType("Canonicalization", "OtherStructType");
+            _genericReferenceType = _testModule.GetType("Canonicalization", "GenericReferenceType`1");
+            _genericStructType = _testModule.GetType("Canonicalization", "GenericStructType`1");
+            _genericReferenceTypeWithThreeParams = _testModule.GetType("Canonicalization", "GenericReferenceTypeWithThreeParams`3");
+            _genericStructTypeWithThreeParams = _testModule.GetType("Canonicalization", "GenericStructTypeWithThreeParams`3");
+        }
+
+        [Fact]
+        public void TestReferenceTypeConversionToSharedForm()
+        {
+            var grtOverRt = _genericReferenceType.MakeInstantiatedType(_referenceType);
+            var grtOverOtherRt = _genericReferenceType.MakeInstantiatedType(_otherReferenceType);
+            var grtOverRtShared = grtOverRt.ConvertToSharedRuntimeDeterminedForm();
+            var grtOverOtherRtShared = grtOverOtherRt.ConvertToSharedRuntimeDeterminedForm();
+
+            // GenericReferenceType<ReferenceType> and GenericReferenceType<OtherReferenceType> have the same shared form
+            Assert.Same(grtOverRtShared, grtOverOtherRtShared);
+
+            // The instantiation argument of the shared form is a runtime determined type
+            var typeArg = grtOverRtShared.Instantiation[0];
+            Assert.IsType<RuntimeDeterminedType>(typeArg);
+
+            // The canonical type used in the shared runtime form is __Canon
+            var runtimeDeterminedType = (RuntimeDeterminedType)typeArg;
+            Assert.Same(_context.CanonType, runtimeDeterminedType.CanonicalType);
+
+            // The shared runtime form details type is the T from the generic definition
+            Assert.Same(_genericReferenceType.Instantiation[0], runtimeDeterminedType.RuntimeDeterminedDetailsType);
+
+            // Canonical form of GenericReferenceType<T__Canon> is same as canonical form of GenericReferenceType<ReferenceType>
+            Assert.Same(
+                grtOverRtShared.ConvertToCanonForm(CanonicalFormKind.Specific),
+                grtOverRt.ConvertToCanonForm(CanonicalFormKind.Specific));
+
+            // GenericReferenceType<ReferenceType> and GenericReferenceType<StructType[]> have the same shared form
+            var grtOverArray = _genericReferenceType.MakeInstantiatedType(_structType.MakeArrayType());
+            var grtOverArrayShared = grtOverArray.ConvertToSharedRuntimeDeterminedForm();
+            Assert.Same(grtOverRtShared, grtOverArrayShared);
+
+            // Converting GenericReferenceType<StructType> to shared form is a no-op
+            var grtOverSt = _genericReferenceType.MakeInstantiatedType(_structType);
+            var grtOverStShared = grtOverSt.ConvertToSharedRuntimeDeterminedForm();
+            Assert.Same(grtOverStShared, grtOverSt);
+        }
+
+        [Fact]
+        public void TestLargeReferenceTypeConversionToSharedForm()
+        {
+            var grtOverRtStRt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _referenceType, _structType, _referenceType);
+            var grtOverRtStOtherRt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _referenceType, _structType, _otherReferenceType);
+            var grtOverRtStRtShared = grtOverRtStRt.ConvertToSharedRuntimeDeterminedForm();
+            var grtOverRtStOtherRtShared = grtOverRtStOtherRt.ConvertToSharedRuntimeDeterminedForm();
+
+            // GenericReferenceTypeWithThreeParams<ReferenceType, StructType, ReferenceType>
+            // GenericReferenceTypeWithThreeParams<ReferenceType, StructType, OtherReferenceType>
+            // have the same shared runtime form.
+            Assert.Same(grtOverRtStRtShared, grtOverRtStOtherRtShared);
+
+            var grtOverStRtSt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _referenceType, _structType);
+            var grtOverStOtherRtSt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _otherReferenceType, _structType);
+            var grtOverStRtStShared = grtOverStRtSt.ConvertToSharedRuntimeDeterminedForm();
+            var grtOverStOtherRtStShared = grtOverStOtherRtSt.ConvertToSharedRuntimeDeterminedForm();
+
+            // GenericReferenceTypeWithThreeParams<StructType, ReferenceType, StructType>
+            // GenericReferenceTypeWithThreeParams<StructType, OtherReferenceType, StructType>
+            // have the same shared runtime form.
+            Assert.Same(grtOverStRtStShared, grtOverStOtherRtStShared);
+
+            // GenericReferenceTypeWithThreeParams<StructType, ReferenceType, StructType>
+            // GenericReferenceTypeWithThreeParams<StructType, ReferenceType, OtherStructType>
+            // have different shared runtime form.
+            var grtOverStRtOtherSt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _structType, _referenceType, _otherStructType);
+            var grtOverStRtOtherStShared = grtOverStRtOtherSt.ConvertToSharedRuntimeDeterminedForm();
+            Assert.NotSame(grtOverStRtStShared, grtOverStRtOtherStShared);
+        }
+
+        [Fact]
+        public void TestUniversalCanonUpgrade()
+        {
+            var gstOverUniversalCanon = _genericStructType.MakeInstantiatedType(_context.UniversalCanonType);
+            var grtOverRtRtStOverUniversal = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _referenceType, _referenceType, gstOverUniversalCanon);
+            var grtOverRtRtStOverUniversalShared = grtOverRtRtStOverUniversal.ConvertToSharedRuntimeDeterminedForm();
+
+            // Shared runtime form of
+            // GenericReferenceTypeWithThreeParams<ReferenceType, ReferenceType, GenericStructType<__UniversalCanon>> is
+            // GenericReferenceTypeWithThreeParams<T__UniversalCanon, U__UniversalCanon, V__UniversalCanon>
+            var arg0 = grtOverRtRtStOverUniversalShared.Instantiation[0];
+            Assert.IsType<RuntimeDeterminedType>(arg0);
+            Assert.Same(_context.UniversalCanonType, ((RuntimeDeterminedType)arg0).CanonicalType);
+            var arg2 = grtOverRtRtStOverUniversalShared.Instantiation[2];
+            Assert.IsType<RuntimeDeterminedType>(arg2);
+            Assert.Same(_context.UniversalCanonType, ((RuntimeDeterminedType)arg2).CanonicalType);
+        }
+
+        [Fact]
+        public void TestSignatureInstantiation()
+        {
+            var grtOverRtStRt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _referenceType, _structType, _referenceType);
+            var grtOverRtStRtShared = grtOverRtStRt.ConvertToSharedRuntimeDeterminedForm();
+
+            // GenericReferenceTypeWithThreeParams<T__Canon, StructType, V__Canon> substituted over
+            // an instantiation of <ReferenceType, StructType, OtherReferenceType> is 
+            // GenericReferenceTypeWithThreeParams<ReferenceType, StructType, OtherReferenceType>
+            var grtOverRtStRtSharedInstantiated = grtOverRtStRtShared.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(
+                new Instantiation(_referenceType, _structType, _otherReferenceType),
+                Instantiation.Empty);
+
+            var grtOverRtStOtherRt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+                _referenceType, _structType, _otherReferenceType);
+
+            Assert.Same(grtOverRtStOtherRt, grtOverRtStRtSharedInstantiated);
+        }
+
+        [Fact]
+        public void TestInstantiationOverStructOverCanon()
+        {
+            var stOverCanon = _genericStructType.MakeInstantiatedType(_context.CanonType);
+            var grtOverStOverCanon = _genericReferenceType.MakeInstantiatedType(
+                stOverCanon);
+            var grtOverStOverCanonShared = grtOverStOverCanon.ConvertToSharedRuntimeDeterminedForm();
+
+            // GenericReferenceType<GenericStructType<__Canon>> converts to
+            // GenericReferenceType<T__GenericStructType<__Canon>>
+            var typeArg = grtOverStOverCanonShared.Instantiation[0];
+            Assert.IsType<RuntimeDeterminedType>(typeArg);
+            var runtimeDeterminedType = (RuntimeDeterminedType)typeArg;
+            Assert.Same(stOverCanon, runtimeDeterminedType.CanonicalType);
+            Assert.Same(_genericReferenceType.Instantiation[0], runtimeDeterminedType.RuntimeDeterminedDetailsType);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/StaticFieldLayoutTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/StaticFieldLayoutTests.cs
new file mode 100644 (file)
index 0000000..98a06c8
--- /dev/null
@@ -0,0 +1,307 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Linq;
+
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class StaticFieldLayoutTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        public StaticFieldLayoutTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestNoPointers()
+        {
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "NoPointers");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "int1":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    case "byte1":
+                        Assert.Equal(4, field.Offset.AsInt);
+                        break;
+                    case "char1":
+                        Assert.Equal(6, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestStillNoPointers()
+        {
+            //
+            // Test that static offsets ignore instance fields preceeding them
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "StillNoPointers");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "bool1":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestClassNoPointers()
+        {
+            //
+            // Ensure classes behave the same as structs when containing statics
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "ClassNoPointers");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "int1":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    case "byte1":
+                        Assert.Equal(4, field.Offset.AsInt);
+                        break;
+                    case "char1":
+                        Assert.Equal(6, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestHasPointers()
+        {
+            //
+            // Test a struct containing static types with pointers
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "HasPointers");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "string1":
+                        Assert.Equal(8, field.Offset.AsInt);
+                        break;
+                    case "class1":
+                        Assert.Equal(16, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestMixPointersAndNonPointers()
+        {
+            //
+            // Test that static fields with GC pointers get separate offsets from non-GC fields
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "MixPointersAndNonPointers");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "string1":
+                        Assert.Equal(8, field.Offset.AsInt);
+                        break;
+                    case "int1":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    case "class1":
+                        Assert.Equal(16, field.Offset.AsInt);
+                        break;
+                    case "int2":
+                        Assert.Equal(4, field.Offset.AsInt);
+                        break;
+                    case "string2":
+                        Assert.Equal(24, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestEnsureInheritanceResetsStaticOffsets()
+        {
+            //
+            // Test that when inheriting a class with static fields, the derived slice's static fields
+            // are again offset from 0
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "EnsureInheritanceResetsStaticOffsets");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "int3":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    case "string3":
+                        Assert.Equal(8, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestLiteralFieldsDontAffectLayout()
+        {
+            //
+            // Test that literal fields are not laid out.
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "LiteralFieldsDontAffectLayout");
+
+            Assert.Equal(4, t.GetFields().Count());
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "IntConstant":
+                    case "StringConstant":
+                        Assert.True(field.IsStatic);
+                        Assert.True(field.IsLiteral);
+                        break;
+                    case "Int1":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    case "String1":
+                        Assert.Equal(8, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestStaticSelfRef()
+        {
+            //
+            // Test that we can load a struct which has a static field referencing itself without
+            // going into an infinite loop
+            //
+
+            MetadataType t = _testModule.GetType("StaticFieldLayout", "StaticSelfRef");
+
+            foreach (var field in t.GetFields())
+            {
+                if (!field.IsStatic)
+                    continue;
+
+                switch (field.Name)
+                {
+                    case "selfRef1":
+                        Assert.Equal(0, field.Offset.AsInt);
+                        break;
+                    default:
+                        throw new Exception(field.Name);
+                }
+            }
+        }
+
+        [Fact]
+        public void TestRvaStatics()
+        {
+            //
+            // Test that an RVA mapped field has the right value for the offset.
+            //
+
+            var ilModule = _context.GetModuleForSimpleName("ILTestAssembly");
+            var t = ilModule.GetType("StaticFieldLayout", "RvaStatics");
+            var field = t.GetField("StaticInitedInt");
+
+            Assert.True(field.HasRva);
+
+            byte[] rvaData = ((EcmaField)field).GetFieldRvaData();
+
+            Assert.Equal(4, rvaData.Length);
+
+            int value = rvaData[0] |
+                rvaData[1] << 8 |
+                rvaData[2] << 16 |
+                rvaData[3] << 24;
+
+            Assert.Equal(0x78563412, value);
+        }
+
+        [Fact]
+        public void TestFunctionPointer()
+        {
+            //
+            // Test layout with a function pointer typed-field.
+            //
+
+            var ilModule = _context.GetModuleForSimpleName("ILTestAssembly");
+            var t = ilModule.GetType("StaticFieldLayout", "FunctionPointerType");
+            var field = t.GetField("StaticMethodField");
+
+            Assert.Equal(8, field.Offset.AsInt);
+            Assert.False(field.HasGCStaticBase);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs
new file mode 100644 (file)
index 0000000..ba6d57e
--- /dev/null
@@ -0,0 +1,239 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+
+namespace TypeSystemTests
+{
+    public class SyntheticVirtualOverrideTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        public SyntheticVirtualOverrideTests()
+        {
+            _context = new SyntheticVirtualOverrideTypeSystemContext();
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestStructEqualsAndGetHashCode()
+        {
+            //
+            // Tests that a struct with no Equals and GetHashCode overrides
+            // receive a synthetic implementation of these courtesy of the
+            // EqualsAndGetHashCodeProvidingAlgorithm.
+            //
+
+            MetadataType t = _testModule.GetType("SyntheticVirtualOverride", "StructWithNoEqualsAndGetHashCode");
+
+            Assert.DoesNotContain(t.GetMethods(), m => m.Name == "Equals");
+            Assert.DoesNotContain(t.GetMethods(), m => m.Name == "GetHashCode");
+
+            List<MethodDesc> introducedVirtualMethods = new List<MethodDesc>(t.GetAllMethods().Where(m => m.IsVirtual));
+            Assert.Equal(2, introducedVirtualMethods.Count);
+            Assert.Contains(introducedVirtualMethods, m => m.Name == "Equals");
+            Assert.Contains(introducedVirtualMethods, m => m.Name == "GetHashCode");
+            Assert.All(introducedVirtualMethods, m => { Assert.Same(t, m.OwningType); });
+
+            List<MethodDesc> virtualSlots = new List<MethodDesc>(t.EnumAllVirtualSlots());
+            Assert.All(virtualSlots, s => { Assert.True(s.OwningType.IsObject); });
+            Assert.Equal(4, virtualSlots.Count);
+
+            List<MethodDesc> vtable = virtualSlots.Select(s => t.FindVirtualFunctionTargetMethodOnObjectType(s)).ToList();
+
+            Assert.Contains(vtable, m => m.Name == "Equals" && m.OwningType == t);
+            Assert.Contains(vtable, m => m.Name == "GetHashCode" && m.OwningType == t);
+            Assert.Contains(vtable, m => m.Name == "Finalize" && m.OwningType.IsObject);
+            Assert.Contains(vtable, m => m.Name == "ToString" && m.OwningType.IsObject);
+        }
+
+        [Fact]
+        public void TestUnoverridenSyntheticEqualsAndGetHashCode()
+        {
+            //
+            // Tests that the synthetic implementation on a base class is propagated to
+            // derived classes.
+            //
+
+            MetadataType baseType = _testModule.GetType("SyntheticVirtualOverride", "ClassWithInjectedEqualsAndGetHashCode");
+            MetadataType t = _testModule.GetType("SyntheticVirtualOverride", "ClassNotOverridingEqualsAndGetHashCode");
+
+            List<MethodDesc> virtualSlots = new List<MethodDesc>(t.EnumAllVirtualSlots());
+            Assert.All(virtualSlots, s => { Assert.True(s.OwningType.IsObject); });
+            Assert.Equal(4, virtualSlots.Count);
+
+            List<MethodDesc> vtable = virtualSlots.Select(s => t.FindVirtualFunctionTargetMethodOnObjectType(s)).ToList();
+
+            Assert.Contains(vtable, m => m.Name == "Equals" && m.OwningType == baseType);
+            Assert.Contains(vtable, m => m.Name == "GetHashCode" && m.OwningType == baseType);
+            Assert.Contains(vtable, m => m.Name == "Finalize" && m.OwningType.IsObject);
+            Assert.Contains(vtable, m => m.Name == "ToString" && m.OwningType.IsObject);
+        }
+
+        [Fact]
+        public void TestOverridenSyntheticEqualsAndGetHashCode()
+        {
+            //
+            // Tests that the synthetic implementation on a base class can be overriden by
+            // derived classes.
+            //
+
+            MetadataType baseType = _testModule.GetType("SyntheticVirtualOverride", "ClassWithInjectedEqualsAndGetHashCode");
+            MetadataType t = _testModule.GetType("SyntheticVirtualOverride", "ClassOverridingEqualsAndGetHashCode");
+
+            List<MethodDesc> virtualSlots = new List<MethodDesc>(t.EnumAllVirtualSlots());
+            Assert.All(virtualSlots, s => { Assert.True(s.OwningType.IsObject); });
+            Assert.Equal(4, virtualSlots.Count);
+
+            List<MethodDesc> vtable = virtualSlots.Select(s => t.FindVirtualFunctionTargetMethodOnObjectType(s)).ToList();
+            
+            Assert.Contains(vtable, m => m.Name == "Equals" && m.OwningType == t);
+            Assert.Contains(vtable, m => m.Name == "GetHashCode" && m.OwningType == t);
+            Assert.Contains(vtable, m => m.Name == "Finalize" && m.OwningType.IsObject);
+            Assert.Contains(vtable, m => m.Name == "ToString" && m.OwningType.IsObject);
+        }
+
+        private class SyntheticVirtualOverrideTypeSystemContext : TestTypeSystemContext
+        {
+            private Dictionary<TypeDesc, MethodDesc> _getHashCodeMethods = new Dictionary<TypeDesc, MethodDesc>();
+            private Dictionary<TypeDesc, MethodDesc> _equalsMethods = new Dictionary<TypeDesc, MethodDesc>();
+
+            public SyntheticVirtualOverrideTypeSystemContext()
+                : base(TargetArchitecture.Unknown)
+            {
+            }
+
+            private MethodDesc GetGetHashCodeMethod(TypeDesc type)
+            {
+                MethodDesc result;
+                if (!_getHashCodeMethods.TryGetValue(type, out result))
+                {
+                    result = new SyntheticMethod(type, "GetHashCode",
+                        new MethodSignature(0, 0, type.Context.GetWellKnownType(WellKnownType.Int32), Array.Empty<TypeDesc>()));
+                    _getHashCodeMethods.Add(type, result);
+                }
+                return result;
+            }
+
+            private MethodDesc GetEqualsMethod(TypeDesc type)
+            {
+                MethodDesc result;
+                if (!_equalsMethods.TryGetValue(type, out result))
+                {
+                    result = new SyntheticMethod(type, "Equals",
+                        new MethodSignature(0, 0, type.Context.GetWellKnownType(WellKnownType.Boolean),
+                        new[] { type.Context.GetWellKnownType(WellKnownType.Object) }));
+                    _equalsMethods.Add(type, result);
+                }
+                return result;
+            }
+
+            protected override IEnumerable<MethodDesc> GetAllMethods(TypeDesc type)
+            {
+                MetadataType mdType = type as MetadataType;
+
+                if (mdType.Name == "StructWithNoEqualsAndGetHashCode"
+                    || mdType.Name == "ClassWithInjectedEqualsAndGetHashCode")
+                {
+                    yield return GetEqualsMethod(type);
+                    yield return GetGetHashCodeMethod(type);
+                }
+
+                foreach (var m in mdType.GetMethods())
+                    yield return m;
+            }
+        }
+
+        private class SyntheticMethod : MethodDesc
+        {
+            private TypeDesc _owningType;
+            private MethodSignature _signature;
+            private string _name;
+
+            public SyntheticMethod(TypeDesc owningType, string name, MethodSignature signature)
+            {
+                _owningType = owningType;
+                _signature = signature;
+                _name = name;
+            }
+
+            protected override int ClassCode
+            {
+                get
+                {
+                    throw new NotImplementedException();
+                }
+            }
+
+            protected override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer)
+            {
+                throw new NotImplementedException();
+            }
+
+            public override bool IsVirtual
+            {
+                get
+                {
+                    return true;
+                }
+            }
+
+            public override TypeSystemContext Context
+            {
+                get
+                {
+                    return _owningType.Context;
+                }
+            }
+
+            public override string Name
+            {
+                get
+                {
+                    return _name;
+                }
+            }
+
+            public override string DiagnosticName
+            {
+                get
+                {
+                    return _name;
+                }
+            }
+
+            public override TypeDesc OwningType
+            {
+                get
+                {
+                    return _owningType;
+                }
+            }
+
+            public override MethodSignature Signature
+            {
+                get
+                {
+                    return _signature;
+                }
+            }
+
+            public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
+            {
+                return false;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestMetadataFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestMetadataFieldLayoutAlgorithm.cs
new file mode 100644 (file)
index 0000000..ba96e1c
--- /dev/null
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+using Internal.TypeSystem;
+
+namespace TypeSystemTests
+{
+    class TestMetadataFieldLayoutAlgorithm : MetadataFieldLayoutAlgorithm
+    {
+        protected override void PrepareRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
+        {
+            // GC statics start with a pointer to the "EEType" that signals the size and GCDesc to the GC
+            layout.GcStatics.Size = context.Target.LayoutPointerSize;
+            layout.ThreadGcStatics.Size = context.Target.LayoutPointerSize;
+        }
+
+        protected override void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
+        {
+            // If the size of GCStatics is equal to the size set in PrepareRuntimeSpecificStaticFieldLayout, we
+            // don't have any GC statics
+            if (layout.GcStatics.Size == context.Target.LayoutPointerSize)
+            {
+                layout.GcStatics.Size = LayoutInt.Zero;
+            }
+            if (layout.ThreadGcStatics.Size == context.Target.LayoutPointerSize)
+            {
+                layout.ThreadGcStatics.Size = LayoutInt.Zero;
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs
new file mode 100644 (file)
index 0000000..913cdbf
--- /dev/null
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+using Internal.TypeSystem;
+using System.Reflection;
+using System.Reflection.PortableExecutable;
+using System.IO;
+
+namespace TypeSystemTests
+{
+    public enum CanonicalizationMode
+    {
+        Standard,
+        RuntimeDetermined,
+    }
+
+    class TestTypeSystemContext : MetadataTypeSystemContext
+    {
+        Dictionary<string, ModuleDesc> _modules = new Dictionary<string, ModuleDesc>(StringComparer.OrdinalIgnoreCase);
+
+        MetadataFieldLayoutAlgorithm _metadataFieldLayout = new TestMetadataFieldLayoutAlgorithm();
+        MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm();
+        ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm;
+        VirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm();
+        
+        public CanonicalizationMode CanonMode { get; set; } = CanonicalizationMode.RuntimeDetermined;
+
+        public TestTypeSystemContext(TargetArchitecture arch)
+            : base(new TargetDetails(arch, TargetOS.Unknown, TargetAbi.Unknown))
+        {
+        }
+
+        public ModuleDesc GetModuleForSimpleName(string simpleName)
+        {
+            ModuleDesc existingModule;
+            if (_modules.TryGetValue(simpleName, out existingModule))
+                return existingModule;
+
+            return CreateModuleForSimpleName(simpleName);
+        }
+
+        public ModuleDesc CreateModuleForSimpleName(string simpleName)
+        {
+            string bindingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+            string filePath = Path.Combine(bindingDirectory, simpleName + ".dll");
+            ModuleDesc module = Internal.TypeSystem.Ecma.EcmaModule.Create(this, new PEReader(File.OpenRead(filePath)), containingAssembly: null);
+            _modules.Add(simpleName, module);
+            return module;
+        }
+
+        public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, bool throwIfNotFound)
+        {
+            return GetModuleForSimpleName(name.Name);
+        }
+
+        public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type)
+        {
+            if (type == UniversalCanonType)
+                return UniversalCanonLayoutAlgorithm.Instance;
+
+            return _metadataFieldLayout;
+        }
+
+        protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type)
+        {
+            if (_arrayOfTRuntimeInterfacesAlgorithm == null)
+            {
+                _arrayOfTRuntimeInterfacesAlgorithm = new ArrayOfTRuntimeInterfacesAlgorithm(SystemModule.GetType("System", "Array`1"));
+            }
+            return _arrayOfTRuntimeInterfacesAlgorithm;
+        }
+
+        protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type)
+        {
+            return _metadataRuntimeInterfacesAlgorithm;
+        }
+
+        public override VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc type)
+        {
+            return _virtualMethodAlgorithm;
+        }
+
+        protected override Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed)
+        {
+            if (CanonMode == CanonicalizationMode.Standard)
+                return StandardCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed);
+            else
+                return RuntimeDeterminedCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed);
+        }
+
+        protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind)
+        {
+            if (CanonMode == CanonicalizationMode.Standard)
+                return StandardCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind);
+            else
+                return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind);
+        }
+
+        protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind)
+        {
+            if (CanonMode == CanonicalizationMode.Standard)
+                return StandardCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind);
+            else
+                return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, ref kind);
+        }
+
+        protected override bool ComputeHasGCStaticBase(FieldDesc field)
+        {
+            Debug.Assert(field.IsStatic);
+
+            if (field.IsThreadStatic)
+                return true;
+
+            TypeDesc fieldType = field.FieldType;
+            if (fieldType.IsValueType)
+                return ((DefType)fieldType).ContainsGCPointers;
+            else
+                return fieldType.IsGCPointer;
+
+        }
+
+        public override bool SupportsUniversalCanon => true;
+        public override bool SupportsCanon => true;
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TypeNameParsingTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TypeNameParsingTests.cs
new file mode 100644 (file)
index 0000000..392eb0b
--- /dev/null
@@ -0,0 +1,299 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class TypeNameParsingTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        string _coreAssemblyQualifier;
+
+        MetadataType _simpleType;
+        MetadataType _nestedType;
+        MetadataType _nestedTwiceType;
+
+        MetadataType _genericType;
+        MetadataType _nestedNongenericType;
+        MetadataType _nestedGenericType;
+
+        MetadataType _veryGenericType;
+
+        MetadataType _structType;
+
+        public TypeNameParsingTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+
+            // TODO-NICE: split test types into a separate, non-core, module
+            _testModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(_testModule);
+
+            _simpleType = _testModule.GetType("TypeNameParsing", "Simple");
+            _nestedType = _simpleType.GetNestedType("Nested");
+            _nestedTwiceType = _nestedType.GetNestedType("NestedTwice");
+
+            _genericType = _testModule.GetType("TypeNameParsing", "Generic`1");
+            _nestedGenericType = _genericType.GetNestedType("NestedGeneric`1");
+            _nestedNongenericType = _genericType.GetNestedType("NestedNongeneric");
+
+            _veryGenericType = _testModule.GetType("TypeNameParsing", "VeryGeneric`3");
+
+            _structType = _testModule.GetType("TypeNameParsing", "Struct");
+
+            _coreAssemblyQualifier = ((IAssemblyDesc)_testModule).GetName().FullName;
+        }
+
+        [Fact]
+        public void TestSimpleNames()
+        {
+            {
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple");
+                Assert.Equal(_simpleType, result);
+            }
+
+            {
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+Nested");
+                Assert.Equal(_nestedType, result);
+            }
+
+            {
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+Nested+NestedTwice");
+                Assert.Equal(_nestedTwiceType, result);
+            }
+
+            {
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("System.Int32, " + _coreAssemblyQualifier);
+                Assert.Equal(_context.GetWellKnownType(WellKnownType.Int32), result);
+            }
+
+            {
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.VeryGeneric`3");
+                Assert.Equal(_veryGenericType, result);
+            }
+        }
+
+        [Fact]
+        public void TestArrayTypes()
+        {
+            {
+                TypeDesc expected = _simpleType.MakeArrayType();
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple[]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _simpleType.MakeArrayType().MakeArrayType().MakeArrayType();
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple[][][]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _simpleType.MakeArrayType(2).MakeArrayType(3);
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple[,][,,]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _context.GetWellKnownType(WellKnownType.Int32).MakeArrayType();
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("System.Int32[], " + _coreAssemblyQualifier);
+                Assert.Equal(expected, result);
+            }
+        }
+
+        [Fact]
+        public void TestPointerTypes()
+        {
+            {
+                TypeDesc expected = _structType.MakePointerType();
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Struct*");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _structType.MakePointerType().MakePointerType();
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Struct**");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _context.GetWellKnownType(WellKnownType.Int32).MakePointerType();
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("System.Int32*, " + _coreAssemblyQualifier);
+                Assert.Equal(expected, result);
+            }
+        }
+
+        [Fact]
+        public void TestInstantiatedTypes()
+        {
+            var nullableType = (MetadataType)_context.GetWellKnownType(WellKnownType.Nullable);
+
+            {
+                TypeDesc expected = _genericType.MakeInstantiatedType(_simpleType);
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Generic`1[TypeNameParsing.Simple]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _veryGenericType.MakeInstantiatedType(
+                    _simpleType,
+                    _genericType.MakeInstantiatedType(_simpleType),
+                    _structType
+                );
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.VeryGeneric`3[TypeNameParsing.Simple,TypeNameParsing.Generic`1[TypeNameParsing.Simple],TypeNameParsing.Struct]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _genericType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Generic`1[[System.Object, " + _coreAssemblyQualifier + "]]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _veryGenericType.MakeInstantiatedType(
+                    _context.GetWellKnownType(WellKnownType.Object),
+                    _simpleType,
+                    _context.GetWellKnownType(WellKnownType.Int32)
+                );
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName(String.Format(
+                    "TypeNameParsing.VeryGeneric`3[[System.Object, {0}],TypeNameParsing.Simple,[System.Int32, {0}]]", _coreAssemblyQualifier));
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = nullableType.MakeInstantiatedType(_structType);
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName(String.Format(
+                    "System.Nullable`1[TypeNameParsing.Struct], {0}", _coreAssemblyQualifier));
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = nullableType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName(String.Format(
+                    "System.Nullable`1[[System.Int32, {0}]], {0}", _coreAssemblyQualifier));
+                Assert.Equal(expected, result);
+            }
+        }
+
+        [Fact]
+        public void TestMixed()
+        {
+            var nullableType = (MetadataType)_context.GetWellKnownType(WellKnownType.Nullable);
+
+            {
+                TypeDesc expected = _genericType.MakeInstantiatedType(_structType.MakePointerType().MakeArrayType());
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Generic`1[TypeNameParsing.Struct*[]]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _genericType.MakeInstantiatedType(_structType.MakePointerType().MakePointerType().MakeArrayType().MakeArrayType(2));
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Generic`1[TypeNameParsing.Struct**[][,]]");
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _nestedNongenericType.MakeInstantiatedType(
+                    nullableType.MakeInstantiatedType(_structType)
+                );
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName(String.Format(
+                    "TypeNameParsing.Generic`1+NestedNongeneric[[System.Nullable`1[TypeNameParsing.Struct], {0}]]", _coreAssemblyQualifier));
+                Assert.Equal(expected, result);
+            }
+
+            {
+                TypeDesc expected = _nestedGenericType.MakeInstantiatedType(
+                    nullableType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32)),
+                    _nestedType.MakeArrayType()
+                );
+                TypeDesc result = _testModule.GetTypeByCustomAttributeTypeName(String.Format(
+                    "TypeNameParsing.Generic`1+NestedGeneric`1[[System.Nullable`1[[System.Int32, {0}]], {0}],TypeNameParsing.Simple+Nested[]]", _coreAssemblyQualifier));
+                Assert.Equal(expected, result);
+            }
+        }
+
+        [Fact]
+        public void TestFailureWhenTypeIsMissing()
+        {
+            // Test throwing behavior
+            Assert.Throws<TypeSystemException.TypeLoadException>(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.SimpleButNotThere"));
+            Assert.Throws<TypeSystemException.TypeLoadException>(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.SimpleButNotThere+NonNamespaceQualifiedType"));
+            Assert.Throws<TypeSystemException.TypeLoadException>(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+NestedNotThere"));
+            Assert.Throws<TypeSystemException.TypeLoadException>(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+Nested+NestedTwiceNotThere"));
+            Assert.Throws<TypeSystemException.TypeLoadException>(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Generic`1[TypeNameParsing.SimpleButNotThere]"));
+
+            // Test returning null behavior
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.SimpleButNotThere", throwIfNotFound: false));
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.SimpleButNotThere+NonNamespaceQualifiedType", throwIfNotFound: false));
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+NestedNotThere", throwIfNotFound: false));
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+NestedNotThere+NonNamespaceQualifiedType", throwIfNotFound: false));
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+Nested+NestedTwiceNotThere", throwIfNotFound: false));
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+Nested+NonNamespaceQualifiedType", throwIfNotFound: false));
+            Assert.Null(_testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Generic`1[TypeNameParsing.SimpleButNotThere]", throwIfNotFound: false));
+        }
+
+        public IEnumerable<TypeDesc> GetTypesForRoundtripTest()
+        {
+            yield return _simpleType;
+            yield return _nestedType;
+            yield return _nestedTwiceType;
+            yield return _context.GetWellKnownType(WellKnownType.Int32);
+            yield return _veryGenericType;
+            yield return _simpleType.MakeArrayType();
+            yield return _simpleType.MakeArrayType().MakeArrayType();
+            yield return _simpleType.MakeArrayType(2).MakeArrayType(3);
+            yield return _context.GetWellKnownType(WellKnownType.Int32).MakeArrayType();
+            yield return _structType.MakePointerType();
+            yield return _context.GetWellKnownType(WellKnownType.Int32).MakePointerType().MakePointerType();
+            yield return _genericType.MakeInstantiatedType(_simpleType);
+            yield return _veryGenericType.MakeInstantiatedType(
+                    _simpleType,
+                    _genericType.MakeInstantiatedType(_simpleType),
+                    _structType
+                );
+            yield return _genericType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+            yield return _veryGenericType.MakeInstantiatedType(
+                    _context.GetWellKnownType(WellKnownType.Object),
+                    _simpleType,
+                    _context.GetWellKnownType(WellKnownType.Int32)
+                );
+            yield return ((MetadataType)_context.GetWellKnownType(WellKnownType.Nullable)).MakeInstantiatedType(_structType);
+            yield return _genericType.MakeInstantiatedType(_structType.MakePointerType().MakeArrayType());
+            yield return _nestedGenericType.MakeInstantiatedType(
+                    ((MetadataType)_context.GetWellKnownType(WellKnownType.Nullable)).MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32)),
+                    _nestedType.MakeArrayType()
+                );
+        }
+
+        [Fact]
+        public void TestRoundtripping()
+        {
+            foreach (TypeDesc type in GetTypesForRoundtripTest())
+            {
+                {
+                    var fmt = new CustomAttributeTypeNameFormatter((IAssemblyDesc)_testModule);
+                    string formatted = fmt.FormatName(type, true);
+                    TypeDesc roundTripped = _testModule.GetTypeByCustomAttributeTypeName(formatted);
+                    Assert.Equal(type, roundTripped);
+                }
+
+                {
+                    var fmt = new CustomAttributeTypeNameFormatter();
+                    string formatted = fmt.FormatName(type, true);
+                    TypeDesc roundTripped = _testModule.GetTypeByCustomAttributeTypeName(formatted);
+                    Assert.Equal(type, roundTripped);
+                }
+            }
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs
new file mode 100644 (file)
index 0000000..c55fb2d
--- /dev/null
@@ -0,0 +1,513 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class UniversalGenericFieldLayoutTests
+    {
+        TestTypeSystemContext _contextX86;
+        ModuleDesc _testModuleX86;
+        TestTypeSystemContext _contextX64;
+        ModuleDesc _testModuleX64;
+        TestTypeSystemContext _contextARM;
+        ModuleDesc _testModuleARM;
+
+        public UniversalGenericFieldLayoutTests()
+        {
+            // Architecture specific tests may use these contexts
+            _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly");
+            _contextX64.SetSystemModule(systemModuleX64);
+
+            _testModuleX64 = systemModuleX64;
+
+            _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM);
+            var systemModuleARM = _contextARM.CreateModuleForSimpleName("CoreTestAssembly");
+            _contextARM.SetSystemModule(systemModuleARM);
+
+            _testModuleARM = systemModuleARM;
+
+            _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86);
+            var systemModuleX86 = _contextX86.CreateModuleForSimpleName("CoreTestAssembly");
+            _contextX86.SetSystemModule(systemModuleX86);
+
+            _testModuleX86 = systemModuleX86;
+        }
+
+        [Fact]
+        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));
+        }
+
+        public static IEnumerable<object[]> GetTargetDetails()
+        {
+            yield return new object[] { new TargetDetails(TargetArchitecture.ARM, TargetOS.Unknown, TargetAbi.CoreRT) };
+            yield return new object[] { new TargetDetails(TargetArchitecture.ARM64, TargetOS.Unknown, TargetAbi.CoreRT) };
+            yield return new object[] { new TargetDetails(TargetArchitecture.X64, TargetOS.Unknown, TargetAbi.CoreRT) };
+            yield return new object[] { new TargetDetails(TargetArchitecture.X86, TargetOS.Unknown, TargetAbi.CoreRT) };
+            yield return new object[] { new TargetDetails(TargetArchitecture.Wasm32, TargetOS.Unknown, TargetAbi.CoreRT) };
+        }
+
+        [Theory]
+        [MemberData(nameof(GetTargetDetails))]
+        public void TestLayoutIntAlignUp(TargetDetails target)
+        {
+            // AlignUp testing
+            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(0), LayoutInt.AlignUp(new LayoutInt(0), new LayoutInt(8), target));
+
+            Assert.Equal(new LayoutInt(1), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(3), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(5), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(7), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(9), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(11), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(13), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(15), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(1), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(1), target));
+
+            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(2), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(6), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(10), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(14), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(2), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(2), target));
+
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(4), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(12), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(4), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(4), target));
+
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(1), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(2), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(3), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(4), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(5), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(6), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(7), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(8), LayoutInt.AlignUp(new LayoutInt(8), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(9), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(10), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(11), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(12), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(13), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(14), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(15), new LayoutInt(8), target));
+            Assert.Equal(new LayoutInt(16), LayoutInt.AlignUp(new LayoutInt(16), new LayoutInt(8), target));
+
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(1), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(2), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(3), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(4), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(5), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(6), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(7), LayoutInt.Indeterminate, target));
+            if (target.MaximumAlignment > 8)
+                Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(8), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(9), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(10), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(11), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(12), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(13), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(14), LayoutInt.Indeterminate, target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(15), LayoutInt.Indeterminate, target));
+            if (target.MaximumAlignment > 16)
+                Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(new LayoutInt(16), LayoutInt.Indeterminate, target));
+
+            // If we the value is aligned to the maximum supported alignment, we can consider it aligned no matter
+            // the value of the alignment.
+            Assert.Equal(new LayoutInt(target.MaximumAlignment), LayoutInt.AlignUp(new LayoutInt(target.MaximumAlignment), LayoutInt.Indeterminate, target));
+            Assert.Equal(new LayoutInt(target.MaximumAlignment * 2), LayoutInt.AlignUp(new LayoutInt(target.MaximumAlignment * 2), LayoutInt.Indeterminate, target));
+
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(1), target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(2), target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(4), target));
+            Assert.Equal(LayoutInt.Indeterminate, LayoutInt.AlignUp(LayoutInt.Indeterminate, new LayoutInt(8), target));
+        }
+
+
+        private void TestLayoutOfUniversalCanonTypeOnArchitecture(TypeSystemContext context)
+        {
+            // Assert all of the various layout information about the universal canon type itself
+            Assert.Equal(LayoutInt.Indeterminate, context.UniversalCanonType.InstanceFieldAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, context.UniversalCanonType.InstanceFieldSize);
+            Assert.Equal(LayoutInt.Indeterminate, context.UniversalCanonType.InstanceByteAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, context.UniversalCanonType.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, context.UniversalCanonType.InstanceByteCountUnaligned);
+            Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.GCStaticFieldAlignment);
+            Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.GCStaticFieldSize);
+            Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.NonGCStaticFieldAlignment);
+            Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.NonGCStaticFieldSize);
+            Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadGcStaticFieldAlignment);
+            Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadGcStaticFieldSize);
+        }
+        [Fact]
+        public void TestLayoutOfUniversalCanonType()
+        {
+            // Assert all of the various layout information about the universal canon type itself, do this for all architectures
+            TestLayoutOfUniversalCanonTypeOnArchitecture(_contextX86);
+            TestLayoutOfUniversalCanonTypeOnArchitecture(_contextX64);
+            TestLayoutOfUniversalCanonTypeOnArchitecture(_contextARM);
+        }
+
+        [Fact]
+        public void TestAllFieldsStructUniversalGeneric()
+        {
+            // Given a struct with all field universal, what is the layout?
+            MetadataType tGen;
+            InstantiatedType genOfUUU;
+            ModuleDesc testModule;
+            TypeSystemContext context;
+
+            // X64 testing
+            testModule = _testModuleX64;
+            context = _contextX64;
+
+            tGen = testModule.GetType("GenericTypes", "GenStruct`3");
+            genOfUUU = tGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType, context.UniversalCanonType);
+
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceFieldAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceFieldSize);
+            Assert.Equal(new LayoutInt(8), genOfUUU.InstanceByteAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteCountUnaligned);
+            Assert.Equal(0, genOfUUU.GetFields().First().Offset.AsInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.GetFields().ElementAt(1).Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.GetFields().ElementAt(2).Offset);
+
+            testModule = _testModuleX86;
+            context = _contextX86;
+
+            tGen = testModule.GetType("GenericTypes", "GenStruct`3");
+            genOfUUU = tGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType, context.UniversalCanonType);
+
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceFieldAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceFieldSize);
+            Assert.Equal(new LayoutInt(4), genOfUUU.InstanceByteAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteCountUnaligned);
+            Assert.Equal(0, genOfUUU.GetFields().First().Offset.AsInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.GetFields().ElementAt(1).Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.GetFields().ElementAt(2).Offset);
+
+            testModule = _testModuleARM;
+            context = _contextARM;
+
+            tGen = testModule.GetType("GenericTypes", "GenStruct`3");
+            genOfUUU = tGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType, context.UniversalCanonType);
+
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceFieldAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceFieldSize);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.InstanceByteCountUnaligned);
+            Assert.Equal(0, genOfUUU.GetFields().First().Offset.AsInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.GetFields().ElementAt(1).Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUUU.GetFields().ElementAt(2).Offset);
+        }
+
+        private void TestIndeterminatedNestedStructFieldPerContext(TypeSystemContext context, ModuleDesc testModule, out InstantiatedType genOfIntNestedInt, out InstantiatedType genOfLongNestedInt)
+        {
+            // Given a struct with all field universal, what is the layout?
+            MetadataType tGen = testModule.GetType("GenericTypes", "GenStruct`3");
+            InstantiatedType genOfUUU = tGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType, context.UniversalCanonType);
+            genOfIntNestedInt = tGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int32), genOfUUU, context.GetWellKnownType(WellKnownType.Int32));
+            genOfLongNestedInt = tGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int64), genOfUUU, context.GetWellKnownType(WellKnownType.Int32));
+
+            Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceFieldAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceFieldSize);
+            Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.InstanceByteCountUnaligned);
+            Assert.Equal(0, genOfIntNestedInt.GetFields().First().Offset.AsInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.GetFields().ElementAt(1).Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfIntNestedInt.GetFields().ElementAt(2).Offset);
+
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceFieldAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceFieldSize);
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceByteCountUnaligned);
+            Assert.Equal(0, genOfLongNestedInt.GetFields().First().Offset.AsInt);
+            if (context.Target.MaximumAlignment <= 8)
+            {
+                Assert.Equal(8, genOfLongNestedInt.GetFields().ElementAt(1).Offset.AsInt);
+            }
+            else
+            {
+                Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.GetFields().ElementAt(1).Offset);
+            }
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.GetFields().ElementAt(2).Offset);
+        }
+
+        [Fact]
+        public void TestIndeterminateNestedStructField()
+        {
+            InstantiatedType genOfIntNestedInt;
+            InstantiatedType genOfLongNestedInt;
+
+            TestIndeterminatedNestedStructFieldPerContext(_contextX64, _testModuleX64, out genOfIntNestedInt, out genOfLongNestedInt);
+            Assert.Equal(new LayoutInt(8), genOfLongNestedInt.InstanceByteAlignment);
+            Assert.Equal(new LayoutInt(8), genOfLongNestedInt.InstanceByteAlignment);
+            TestIndeterminatedNestedStructFieldPerContext(_contextX86, _testModuleX86, out genOfIntNestedInt, out genOfLongNestedInt);
+            Assert.Equal(new LayoutInt(4), genOfLongNestedInt.InstanceByteAlignment);
+            Assert.Equal(new LayoutInt(4), genOfLongNestedInt.InstanceByteAlignment);
+            TestIndeterminatedNestedStructFieldPerContext(_contextARM, _testModuleARM, out genOfIntNestedInt, out genOfLongNestedInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceByteAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, genOfLongNestedInt.InstanceByteAlignment);
+        }
+
+        private void AssertClassIndeterminateSize(TypeSystemContext context, MetadataType type, LayoutInt expectedIndeterminateByteAlignment)
+        {
+            Assert.Equal(context.Target.LayoutPointerSize, type.InstanceFieldAlignment);
+            Assert.Equal(context.Target.LayoutPointerSize, type.InstanceFieldSize);
+            Assert.Equal(expectedIndeterminateByteAlignment, type.InstanceByteAlignment);
+            Assert.Equal(LayoutInt.Indeterminate, type.InstanceByteCount);
+            Assert.Equal(LayoutInt.Indeterminate, type.InstanceByteCountUnaligned);
+        }
+
+        private void CommonClassLayoutTestBits(ModuleDesc testModule, 
+                                               TypeSystemContext context,
+                                               LayoutInt expectedIndeterminateByteAlignment,
+                                               out InstantiatedType genOfIU,
+                                               out InstantiatedType genOfLU,
+                                               out InstantiatedType genOfUU,
+                                               out InstantiatedType genOfUI,
+                                               out InstantiatedType genOfUL)
+        {
+            MetadataType tDerivedGen = testModule.GetType("GenericTypes", "GenDerivedClass`2");
+            genOfIU = tDerivedGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int32), context.UniversalCanonType);
+            genOfLU = tDerivedGen.MakeInstantiatedType(context.GetWellKnownType(WellKnownType.Int64), context.UniversalCanonType);
+            genOfUU = tDerivedGen.MakeInstantiatedType(context.UniversalCanonType, context.UniversalCanonType);
+
+            genOfUI = tDerivedGen.MakeInstantiatedType(context.UniversalCanonType, context.GetWellKnownType(WellKnownType.Int32));
+            genOfUL = tDerivedGen.MakeInstantiatedType(context.UniversalCanonType, context.GetWellKnownType(WellKnownType.Int64));
+
+            // Assert that the class as a whole is known to be of undefined size
+            AssertClassIndeterminateSize(context, genOfIU, expectedIndeterminateByteAlignment);
+            AssertClassIndeterminateSize(context, genOfLU, expectedIndeterminateByteAlignment);
+            AssertClassIndeterminateSize(context, genOfUU, expectedIndeterminateByteAlignment);
+            AssertClassIndeterminateSize(context, genOfUI, expectedIndeterminateByteAlignment);
+            AssertClassIndeterminateSize(context, genOfUL, expectedIndeterminateByteAlignment);
+        }
+
+        [Fact]
+        public void TestClassLayout()
+        {
+            // Tests class layout behavior with universal generics
+            // Tests handling universal base types as well as non-universal base types
+
+            InstantiatedType genOfIU;
+            InstantiatedType genOfLU;
+            InstantiatedType genOfUU;
+            InstantiatedType genOfUI;
+            InstantiatedType genOfUL;
+
+            ModuleDesc testModule;
+            TypeSystemContext context;
+
+            // X64 testing
+            testModule = _testModuleX64;
+            context = _contextX64;
+
+            CommonClassLayoutTestBits(testModule,
+                                      context,
+                                      new LayoutInt(8),
+                                      out genOfIU,
+                                      out genOfLU,
+                                      out genOfUU,
+                                      out genOfUI,
+                                      out genOfUL);
+
+            // On x64 first field offset is well known always
+            Assert.Equal(8, genOfIU.BaseType.GetFields().First().Offset.AsInt);
+            Assert.Equal(8, genOfLU.BaseType.GetFields().First().Offset.AsInt);
+            if (context.Target.MaximumAlignment <= 8)
+            {
+                Assert.Equal(8, genOfUU.BaseType.GetFields().First().Offset.AsInt);
+                Assert.Equal(8, genOfUI.BaseType.GetFields().First().Offset.AsInt);
+                Assert.Equal(8, genOfUL.BaseType.GetFields().First().Offset.AsInt);
+            }
+            else
+            {
+
+                Assert.Equal(LayoutInt.Indeterminate, genOfUU.BaseType.GetFields().First().Offset);
+                Assert.Equal(LayoutInt.Indeterminate, genOfUI.BaseType.GetFields().First().Offset);
+                Assert.Equal(LayoutInt.Indeterminate, genOfUL.BaseType.GetFields().First().Offset);
+            }
+
+            Assert.Equal(LayoutInt.Indeterminate, genOfIU.GetFields().First().Offset);
+            if (context.Target.MaximumAlignment <= 16)
+            {
+                Assert.Equal(16, genOfLU.GetFields().First().Offset.AsInt);
+            }
+            else
+            {
+                Assert.Equal(LayoutInt.Indeterminate, genOfLU.GetFields().First().Offset);
+            }
+            Assert.Equal(LayoutInt.Indeterminate, genOfUU.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUI.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUL.GetFields().First().Offset);
+
+            // X86 testing
+            testModule = _testModuleX86;
+            context = _contextX86;
+
+            CommonClassLayoutTestBits(testModule,
+                                      context,
+                                      new LayoutInt(4),
+                                      out genOfIU,
+                                      out genOfLU,
+                                      out genOfUU,
+                                      out genOfUI,
+                                      out genOfUL);
+
+            Assert.Equal(4, genOfIU.BaseType.GetFields().First().Offset.AsInt);
+            Assert.Equal(8, genOfLU.BaseType.GetFields().First().Offset.AsInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUU.BaseType.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUI.BaseType.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUL.BaseType.GetFields().First().Offset);
+
+            if (context.Target.MaximumAlignment <= 8)
+            {
+                Assert.Equal(8, genOfIU.GetFields().First().Offset.AsInt);
+            }
+            else
+            {
+                Assert.Equal(LayoutInt.Indeterminate, genOfIU.GetFields().First().Offset);
+            }
+            if (context.Target.MaximumAlignment <= 16)
+            {
+                Assert.Equal(16, genOfLU.GetFields().First().Offset.AsInt);
+            }
+            else
+            {
+                Assert.Equal(LayoutInt.Indeterminate, genOfLU.GetFields().First().Offset);
+            }
+            Assert.Equal(LayoutInt.Indeterminate, genOfUU.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUI.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUL.GetFields().First().Offset);
+
+            // ARM testing
+            testModule = _testModuleARM;
+            context = _contextARM;
+
+            CommonClassLayoutTestBits(testModule,
+                                      context,
+                                      LayoutInt.Indeterminate,
+                                      out genOfIU,
+                                      out genOfLU,
+                                      out genOfUU,
+                                      out genOfUI,
+                                      out genOfUL);
+
+            Assert.Equal(4, genOfIU.BaseType.GetFields().First().Offset.AsInt);
+            Assert.Equal(8, genOfLU.BaseType.GetFields().First().Offset.AsInt);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUU.BaseType.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUI.BaseType.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUL.BaseType.GetFields().First().Offset);
+
+            if (context.Target.MaximumAlignment <= 8)
+            {
+                Assert.Equal(8, genOfIU.GetFields().First().Offset.AsInt);
+            }
+            else
+            {
+                Assert.Equal(LayoutInt.Indeterminate, genOfIU.GetFields().First().Offset);
+            }
+            if (context.Target.MaximumAlignment <= 16)
+            {
+                Assert.Equal(16, genOfLU.GetFields().First().Offset.AsInt);
+            }
+            else
+            {
+                Assert.Equal(LayoutInt.Indeterminate, genOfLU.GetFields().First().Offset);
+            }
+            Assert.Equal(LayoutInt.Indeterminate, genOfUU.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUI.GetFields().First().Offset);
+            Assert.Equal(LayoutInt.Indeterminate, genOfUL.GetFields().First().Offset);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ValueTypeShapeCharacteristicsTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ValueTypeShapeCharacteristicsTests.cs
new file mode 100644 (file)
index 0000000..226148d
--- /dev/null
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class ValueTypeShapeCharacteristicsTests
+    {
+        const ValueTypeShapeCharacteristics Float32Aggregate = ValueTypeShapeCharacteristics.Float32Aggregate;
+        const ValueTypeShapeCharacteristics Float64Aggregate = ValueTypeShapeCharacteristics.Float64Aggregate;
+
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+
+        public ValueTypeShapeCharacteristicsTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.ARM);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestHfaPrimitives()
+        {
+            DefType singleType = _context.GetWellKnownType(WellKnownType.Single);
+            DefType doubleType = _context.GetWellKnownType(WellKnownType.Double);
+
+            Assert.True(singleType.IsHomogeneousAggregate);
+            Assert.Equal(Float32Aggregate, singleType.ValueTypeShapeCharacteristics);
+            
+            Assert.True(doubleType.IsHomogeneousAggregate);
+            Assert.Equal(Float64Aggregate, doubleType.ValueTypeShapeCharacteristics);
+        }
+
+        [Fact]
+        public void TestSimpleHfa()
+        {
+            var simpleHfaFloatStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "SimpleHfaFloatStruct");
+            Assert.True(simpleHfaFloatStruct.IsHomogeneousAggregate);
+            Assert.Equal(Float32Aggregate, simpleHfaFloatStruct.ValueTypeShapeCharacteristics);
+
+            var simpleHfaFloatStructWithManyFields = _testModule.GetType("ValueTypeShapeCharacteristics", "SimpleHfaFloatStructWithManyFields");
+            Assert.True(simpleHfaFloatStructWithManyFields.IsHomogeneousAggregate);
+            Assert.Equal(Float32Aggregate, simpleHfaFloatStructWithManyFields.ValueTypeShapeCharacteristics);
+
+            var simpleHfaDoubleStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "SimpleHfaDoubleStruct");
+            Assert.True(simpleHfaDoubleStruct.IsHomogeneousAggregate);
+            Assert.Equal(Float64Aggregate, simpleHfaDoubleStruct.ValueTypeShapeCharacteristics);
+        }
+
+        [Fact]
+        public void TestCompositeHfa()
+        {
+            var compositeHfaFloatStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "CompositeHfaFloatStruct");
+            Assert.True(compositeHfaFloatStruct.IsHomogeneousAggregate);
+            Assert.Equal(Float32Aggregate, compositeHfaFloatStruct.ValueTypeShapeCharacteristics);
+
+            var compositeHfaDoubleStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "CompositeHfaDoubleStruct");
+            Assert.True(compositeHfaDoubleStruct.IsHomogeneousAggregate);
+            Assert.Equal(Float64Aggregate, compositeHfaDoubleStruct.ValueTypeShapeCharacteristics);
+        }
+
+        [Fact]
+        public void TestHfaNegative()
+        {
+            var nonHAEmptyStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "NonHAEmptyStruct");
+            Assert.False(nonHAEmptyStruct.IsHomogeneousAggregate);
+
+            var nonHAStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "NonHAStruct");
+            Assert.False(nonHAStruct.IsHomogeneousAggregate);
+
+            var nonHAMixedStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "NonHAMixedStruct");
+            Assert.False(nonHAMixedStruct.IsHomogeneousAggregate);
+
+            var nonHACompositeStruct = _testModule.GetType("ValueTypeShapeCharacteristics", "NonHACompositeStruct");
+            Assert.False(nonHACompositeStruct.IsHomogeneousAggregate);
+
+            var nonHAStructWithManyFields = _testModule.GetType("ValueTypeShapeCharacteristics", "NonHAStructWithManyFields");
+            Assert.False(nonHAStructWithManyFields.IsHomogeneousAggregate);
+
+            var objectType = _context.GetWellKnownType(WellKnownType.Object);
+            Assert.False(objectType.IsHomogeneousAggregate);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/VirtualFunctionOverrideTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/VirtualFunctionOverrideTests.cs
new file mode 100644 (file)
index 0000000..b9bd29f
--- /dev/null
@@ -0,0 +1,148 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+
+namespace TypeSystemTests
+{
+    public class VirtualFunctionOverrideTests
+    {
+        TestTypeSystemContext _context;
+        ModuleDesc _testModule;
+        DefType _stringType;
+        DefType _voidType;
+
+        public VirtualFunctionOverrideTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+
+            _stringType = _context.GetWellKnownType(WellKnownType.String);
+            _voidType = _context.GetWellKnownType(WellKnownType.Void);
+        }
+
+        [Fact]
+        public void TestGenericMethodInterfaceMethodImplOverride()
+        {
+            //
+            // Ensure MethodImpl based overriding works for MethodSpecs
+            //
+
+            MetadataType interfaceType = _testModule.GetType("VirtualFunctionOverride", "IIFaceWithGenericMethod");
+            MethodDesc interfaceMethod = null;
+
+            foreach(MethodDesc m in interfaceType.GetMethods())
+            {
+                if (m.Name == "GenMethod")
+                {
+                    interfaceMethod = m;
+                    break;
+                }
+            }
+            Assert.NotNull(interfaceMethod);
+
+            MetadataType objectType = _testModule.GetType("VirtualFunctionOverride", "HasMethodInterfaceOverrideOfGenericMethod");
+            MethodDesc expectedVirtualMethod = null;
+            foreach (MethodDesc m in objectType.GetMethods())
+            {
+                if (m.Name.Contains("GenMethod"))
+                {
+                    expectedVirtualMethod = m;
+                    break;
+                }
+            }
+            Assert.NotNull(expectedVirtualMethod);
+
+            Assert.Equal(expectedVirtualMethod, objectType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod));
+        }
+
+        [Fact]
+        public void TestVirtualDispatchOnGenericType()
+        {
+            // Verifies that virtual dispatch to a non-generic method on a generic instantiation works
+            DefType objectType = _context.GetWellKnownType(WellKnownType.Object);
+            MethodSignature toStringSig = new MethodSignature(MethodSignatureFlags.None, 0, _stringType, Array.Empty<TypeDesc>());
+            MethodDesc objectToString = objectType.GetMethod("ToString", toStringSig);
+            Assert.NotNull(objectToString);
+            MetadataType openTestType = _testModule.GetType("VirtualFunctionOverride", "SimpleGeneric`1");
+            InstantiatedType testInstance = openTestType.MakeInstantiatedType(objectType);
+            MethodDesc targetOnInstance = testInstance.GetMethod("ToString", toStringSig);
+
+            MethodDesc targetMethod = testInstance.FindVirtualFunctionTargetMethodOnObjectType(objectToString);
+            Assert.Equal(targetOnInstance, targetMethod);        
+        }
+
+        [Fact]
+        public void TestVirtualDispatchOnGenericTypeWithOverload()
+        {
+            MetadataType openDerived = _testModule.GetType("VirtualFunctionOverride", "DerivedGenericWithOverload`1");
+            MetadataType derivedInstance = openDerived.MakeInstantiatedType(_stringType);
+            MetadataType baseInstance = (MetadataType)derivedInstance.BaseType;
+
+            MethodDesc baseNongenericOverload = baseInstance.GetMethod("MyMethod", new MethodSignature(MethodSignatureFlags.None, 0, _voidType, new TypeDesc[] { _stringType }));
+            MethodDesc derivedNongenericOverload = derivedInstance.GetMethod("MyMethod", new MethodSignature(MethodSignatureFlags.None, 0, _voidType, new TypeDesc[] { _stringType }));
+            MethodDesc nongenericTargetOverload = derivedInstance.FindVirtualFunctionTargetMethodOnObjectType(baseNongenericOverload);
+            Assert.Equal(derivedNongenericOverload, nongenericTargetOverload);
+
+            MethodDesc baseGenericOverload = baseInstance.GetMethod("MyMethod", new MethodSignature(MethodSignatureFlags.None, 0, _voidType, new TypeDesc[] { _context.GetSignatureVariable(0, false) }));
+            MethodDesc derivedGenericOverload = derivedInstance.GetMethod("MyMethod", new MethodSignature(MethodSignatureFlags.None, 0, _voidType, new TypeDesc[] { _context.GetSignatureVariable(0, false) }));
+            MethodDesc genericTargetOverload = derivedInstance.FindVirtualFunctionTargetMethodOnObjectType(baseGenericOverload);
+            Assert.Equal(derivedGenericOverload, genericTargetOverload);
+        }
+
+        [Fact]
+        public void TestFinalizeOverrideChecking()
+        {
+            MetadataType classWithFinalizer = _testModule.GetType("VirtualFunctionOverride", "ClassWithFinalizer");
+            DefType objectType = _testModule.Context.GetWellKnownType(WellKnownType.Object);
+            MethodDesc finalizeMethod = objectType.GetMethod("Finalize", new MethodSignature(MethodSignatureFlags.None, 0, _voidType, new TypeDesc[] { }));
+
+            MethodDesc actualFinalizer = classWithFinalizer.FindVirtualFunctionTargetMethodOnObjectType(finalizeMethod);
+            Assert.NotNull(actualFinalizer);
+            Assert.NotEqual(actualFinalizer, finalizeMethod);
+        }
+
+        [Fact]
+        public void TestExplicitOverride()
+        {
+            //
+            // Test that explicit virtual method overriding works.
+            //
+
+            var ilModule = _context.GetModuleForSimpleName("ILTestAssembly");
+            var explicitOverrideClass = ilModule.GetType("VirtualFunctionOverride", "ExplicitOverride");
+
+            var myGetHashCodeMethod = explicitOverrideClass.GetMethod("MyGetHashCode", null);
+
+            var objectGetHashCodeMethod = _context.GetWellKnownType(WellKnownType.Object).GetMethod("GetHashCode", null);
+
+            var foundOverride = explicitOverrideClass.FindVirtualFunctionTargetMethodOnObjectType(objectGetHashCodeMethod);
+
+            Assert.Equal(myGetHashCodeMethod, foundOverride);
+        }
+
+        [Fact]
+        public void TestFindBaseUnificationGroup()
+        {
+            var algo = new MetadataVirtualMethodAlgorithm();
+            var ilModule = _context.GetModuleForSimpleName("ILTestAssembly");
+            MetadataType myDerived2Type = ilModule.GetType("VirtualFunctionOverride", "MyDerived2");
+            Assert.NotNull(myDerived2Type);
+            MethodDesc method = myDerived2Type.GetMethod("get_foo", null);
+            Assert.NotNull(method);
+
+            MethodDesc virtualMethod = algo.FindVirtualFunctionTargetMethodOnObjectType(method, myDerived2Type);
+            Assert.NotNull(virtualMethod);
+            Assert.Equal(method, virtualMethod);
+        }
+    }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/WellKnownTypeTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/WellKnownTypeTests.cs
new file mode 100644 (file)
index 0000000..66a4741
--- /dev/null
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+    public class WellKnownTypeTests
+    {
+        private TestTypeSystemContext _context;
+        private ModuleDesc _testModule;
+
+        public WellKnownTypeTests()
+        {
+            _context = new TestTypeSystemContext(TargetArchitecture.X64);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule = systemModule;
+        }
+
+        [Fact]
+        public void TestIsValueType()
+        {
+            Assert.True(_context.GetWellKnownType(WellKnownType.Boolean).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Char).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.SByte).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Byte).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Int16).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UInt16).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Int32).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UInt32).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Int64).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UInt64).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.IntPtr).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UIntPtr).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Single).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Double).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.ValueType).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Enum).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Nullable).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Object).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.String).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Array).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.MulticastDelegate).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.RuntimeTypeHandle).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.RuntimeMethodHandle).IsValueType);
+            Assert.True(_context.GetWellKnownType(WellKnownType.RuntimeFieldHandle).IsValueType);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Exception).IsValueType);
+        }
+
+        [Fact]
+        public void TestIsPrimitive()
+        {
+            Assert.True(_context.GetWellKnownType(WellKnownType.Boolean).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Char).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.SByte).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Byte).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Int16).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UInt16).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Int32).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UInt32).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Int64).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UInt64).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.IntPtr).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.UIntPtr).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Single).IsPrimitive);
+            Assert.True(_context.GetWellKnownType(WellKnownType.Double).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.ValueType).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Enum).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Nullable).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Object).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.String).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Array).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.MulticastDelegate).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.RuntimeTypeHandle).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.RuntimeMethodHandle).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.RuntimeFieldHandle).IsPrimitive);
+            Assert.False(_context.GetWellKnownType(WellKnownType.Exception).IsPrimitive);
+        }
+
+        [Fact]
+        public void TestPrimitiveSizes()
+        {
+            Assert.Equal(1, _context.GetWellKnownType(WellKnownType.Boolean).InstanceFieldSize.AsInt);
+            Assert.Equal(2, _context.GetWellKnownType(WellKnownType.Char).InstanceFieldSize.AsInt);
+            Assert.Equal(1, _context.GetWellKnownType(WellKnownType.SByte).InstanceFieldSize.AsInt);
+            Assert.Equal(1, _context.GetWellKnownType(WellKnownType.Byte).InstanceFieldSize.AsInt);
+            Assert.Equal(2, _context.GetWellKnownType(WellKnownType.Int16).InstanceFieldSize.AsInt);
+            Assert.Equal(2, _context.GetWellKnownType(WellKnownType.UInt16).InstanceFieldSize.AsInt);
+            Assert.Equal(4, _context.GetWellKnownType(WellKnownType.Int32).InstanceFieldSize.AsInt);
+            Assert.Equal(4, _context.GetWellKnownType(WellKnownType.UInt32).InstanceFieldSize.AsInt);
+            Assert.Equal(8, _context.GetWellKnownType(WellKnownType.Int64).InstanceFieldSize.AsInt);
+            Assert.Equal(8, _context.GetWellKnownType(WellKnownType.UInt64).InstanceFieldSize.AsInt);
+            Assert.Equal(_context.Target.PointerSize, _context.GetWellKnownType(WellKnownType.IntPtr).InstanceFieldSize.AsInt);
+            Assert.Equal(_context.Target.PointerSize, _context.GetWellKnownType(WellKnownType.UIntPtr).InstanceFieldSize.AsInt);
+            Assert.Equal(4, _context.GetWellKnownType(WellKnownType.Single).InstanceFieldSize.AsInt);
+            Assert.Equal(8, _context.GetWellKnownType(WellKnownType.Double).InstanceFieldSize.AsInt);
+        }
+
+        [Fact]
+        public void TestModuleType()
+        {
+            Assert.True(_testModule.GetGlobalModuleType().IsModuleType);
+        }
+    }
+}
index 9b6bb76..c6266c6 100644 (file)
     <Compile Include="..\..\Common\TypeSystem\Common\AlignmentHelper.cs">
       <Link>Utilities\AlignmentHelper.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\ArrayOfTRuntimeInterfacesAlgorithm.cs">
+      <Link>Utilities\ArrayOfTRuntimeInterfacesAlgorithm.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\CastingHelper.cs">
       <Link>TypeSystem\Common\CastingHelper.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\ConstructedTypeRewritingHelpers.cs">
+      <Link>TypeSystem\Common\ConstructedTypeRewritingHelpers.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\ExplicitLayoutValidator.cs">
       <Link>TypeSystem\Common\ExplicitLayoutValidator.cs</Link>
     </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\ThrowHelper.Common.cs">
       <Link>TypeSystem\Common\ThrowHelper.Common.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\UniversalCanonLayoutAlgorithm.cs">
+      <Link>TypeSystem\Common\UniversalCanonLayoutAlgorithm.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\Utilities\CustomAttributeTypeNameFormatter.cs">
       <Link>Utilities\CustomAttributeTypeNameFormatter.cs</Link>
     </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\TypeHashingAlgorithms.cs">
       <Link>TypeSystem\Common\TypeHashingAlgorithms.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\TypeSystemConstraintsHelpers.cs">
+      <Link>TypeSystem\Common\TypeSystemConstraintsHelpers.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\TypeSystemContext.cs">
       <Link>TypeSystem\Common\TypeSystemContext.cs</Link>
     </Compile>