From 5060c32bc93afb2c15328c16f5f284df14b0c731 Mon Sep 17 00:00:00 2001 From: Simon Nattress Date: Tue, 16 Jun 2020 17:23:31 -0700 Subject: [PATCH 1/4] xcopy type system tests --- .../ArchitectureSpecificFieldLayoutTests.cs | 87 ++ .../CanonicalizationTests.cs | 327 +++++++ .../CastingTests.cs | 219 +++++ .../ConstraintsValidationTest.cs | 359 ++++++++ .../CoreTestAssembly/Canonicalization.cs | 66 ++ .../CoreTestAssembly/Casting.cs | 28 + .../CoreTestAssembly/CoreTestAssembly.csproj | 27 + .../CoreTestAssembly/GCPointerMap.cs | 119 +++ .../CoreTestAssembly/GenericConstraints.cs | 72 ++ .../CoreTestAssembly/GenericTypes.cs | 96 ++ .../CoreTestAssembly/Hashcode.cs | 26 + .../CoreTestAssembly/InstanceFieldLayout.cs | 302 ++++++ .../CoreTestAssembly/InterfaceArrangements.cs | 45 + .../CoreTestAssembly/Platform.cs | 136 +++ .../CoreTestAssembly/StaticFieldLayout.cs | 75 ++ .../SyntheticVirtualOverride.cs | 33 + .../CoreTestAssembly/TypeNameParsing.cs | 40 + .../ValueTypeShapeCharacteristics.cs | 76 ++ .../VirtualFunctionOverride.cs | 42 + .../GCPointerMapTests.cs | 98 ++ .../GenericTypeAndMethodTests.cs | 274 ++++++ .../HashcodeTests.cs | 253 ++++++ ...ompiler.TypeSystem.ReadyToRun.Tests.csproj | 61 ++ .../ILDisassemblerTests.cs | 74 ++ .../ILTestAssembly/ILDisassembler.il | 181 ++++ .../ILTestAssembly/ILTestAssembly.ilproj | 21 + .../ILTestAssembly/InstanceFieldLayout.il | 22 + .../ILTestAssembly/Main.il | 17 + .../ILTestAssembly/StaticFieldLayout.il | 17 + .../ILTestAssembly/VirtualFunctionOverride.il | 49 + .../InstanceFieldLayoutTests.cs | 860 ++++++++++++++++++ .../InterfacesTests.cs | 191 ++++ .../RuntimeDeterminedTypesTests.cs | 173 ++++ .../StaticFieldLayoutTests.cs | 307 +++++++ .../SyntheticVirtualOverrideTests.cs | 231 +++++ .../TestMetadataFieldLayoutAlgorithm.cs | 35 + .../TestTypeSystemContext.cs | 127 +++ .../TypeNameParsingTests.cs | 299 ++++++ .../UniversalGenericFieldLayoutTests.cs | 513 +++++++++++ .../ValueTypeShapeCharacteristicsTests.cs | 91 ++ .../VirtualFunctionOverrideTests.cs | 148 +++ .../WellKnownTypeTests.cs | 110 +++ 42 files changed, 6327 insertions(+) create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericTypes.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Hashcode.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InstanceFieldLayout.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InterfaceArrangements.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Platform.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/StaticFieldLayout.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/SyntheticVirtualOverride.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/TypeNameParsing.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/ValueTypeShapeCharacteristics.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/VirtualFunctionOverride.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/HashcodeTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILDisassemblerTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILDisassembler.il create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/InstanceFieldLayout.il create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/Main.il create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/StaticFieldLayout.il create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/VirtualFunctionOverride.il create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/StaticFieldLayoutTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestMetadataFieldLayoutAlgorithm.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TypeNameParsingTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ValueTypeShapeCharacteristicsTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/VirtualFunctionOverrideTests.cs create mode 100644 src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/WellKnownTypeTests.cs 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 index 0000000000000..1ac22562f67e1 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs @@ -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 index 0000000000000..c04941848398a --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs @@ -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> is + // GenericReferenceTypeWithThreeParams + 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 index 0000000000000..1d81c8196441b --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs @@ -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 index 0000000000000..bcb985634b0e9 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs @@ -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 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 index 0000000000000..58c5b14596f13 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs @@ -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() + { + } + } + + class OtherReferenceType + { + } + + struct StructType + { + void Method() + { + } + + void GenericMethod() + { + } + } + + struct OtherStructType + { + } + + class GenericReferenceType + { + void Method() + { + } + + void GenericMethod() + { + } + } + + struct GenericStructType + { + void Method() + { + } + + void GenericMethod() + { + } + } + + class GenericReferenceTypeWithThreeParams + { + } + + class GenericStructTypeWithThreeParams + { + } +} 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 index 0000000000000..2ae42bd4b9a41 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs @@ -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 { } + + class ClassImplementingIFoo : IFoo { } + + class ClassImplementingIFooIndirectly : ClassImplementingIFoo { } + + enum IntBasedEnum : int { } + + enum UIntBasedEnum : uint { } + + enum ShortBasedEnum : short { } + + class ClassWithNoConstraint { } + + class ClassWithValueTypeConstraint where T : struct { } + + class ClassWithInterfaceConstraint where T : IFoo { } + + class ClassWithRecursiveImplementation : IContravariant> { } +} \ 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 index 0000000000000..efdb81aa49692 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj @@ -0,0 +1,27 @@ + + + + Library + CoreTestAssembly + false + true + true + + + + + + + + + + + + + + + + + + + \ 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 index 0000000000000..7b884ea7bdd30 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs @@ -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 index 0000000000000..8af3228393914 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs @@ -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 { } + + public class Arg1 : INonGen { } + + public class Arg2 { } + + public class Arg3 : IGen { } + + public struct StructArgWithDefaultCtor { } + + public struct StructArgWithoutDefaultCtor + { + public StructArgWithoutDefaultCtor(int argument) { } + } + + public class ClassArgWithDefaultCtor : IGen + { + public ClassArgWithDefaultCtor() { } + } + + public abstract class AbstractClassArgWithDefaultCtor : IGen + { + public AbstractClassArgWithDefaultCtor() { } + } + + public class ClassArgWithPrivateDefaultCtor : IGen + { + private ClassArgWithPrivateDefaultCtor() { } + } + + public class ClassArgWithoutDefaultCtor : IGen + { + public ClassArgWithoutDefaultCtor(int argument) { } + } + + public class ReferenceTypeConstraint where T : class { } + + public class DefaultConstructorConstraint where T : new() { } + + public class NotNullableValueTypeConstraint where T : struct { } + + public class SimpleTypeConstraint where T : Arg1 { } + + public class DoubleSimpleTypeConstraint where T : Arg1, INonGen { } + + public class SimpleGenericConstraint where T : U { } + + public class ComplexGenericConstraint1 where T : Arg2 { } + + public class ComplexGenericConstraint2 where T : Arg2> { } + + public class ComplexGenericConstraint3 where T : IGen { } + + public class ComplexGenericConstraint4 where T : U where U : IGen { } + + public class MultipleConstraints where T : class, IGen, new() { } + + public class GenericMethods + { + public static void SimpleGenericConstraintMethod() where T : U { } + + public static void ComplexGenericConstraintMethod() where T : U where U : IGen { } + } +} 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 index 0000000000000..44bacfaebda73 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericTypes.cs @@ -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 +{ + /// + /// Generic class to be used for testing. + /// + /// + public abstract class GenericClass + { + /// + /// Purpose is to manipulate a method involving a generic parameter in its return type. + /// + public abstract T Foo(); + /// + /// Purpose is to manipulate a method involving a generic parameter in its parameter list. + /// + public void Bar(T a) + { + } + + ~GenericClass() + { } + } + + public class DerivedGenericClass : GenericClass + { + public override sealed T Foo() + { + return default(T); + } + } + /// + /// Generic class with multiple parameters to be used for testing. + /// + public class TwoParamGenericClass + { + /// + /// Purpose is to allow testing of the properties of non-generic methods on generic types + /// + public void NonGenericFunction() + { + } + + /// + /// Purpose is to allow testing of the properties of generic methods on generic types + /// + public void GenericFunction() + { + } + } + + /// + /// Non-generic type which has a generic method in it + /// + public class NonGenericClass + { + /// + /// Purpose is to allow testing the properties of generic methods on nongeneric types + /// + /// + /// + public void GenericFunction() + { + } + } + + /// + /// Generic structure with 3 fields all defined by type parameters + /// + [StructLayout(LayoutKind.Sequential)] + public struct GenStruct + { + A _a; + B _b; + C _c; + } + + public class GenClass + { +#pragma warning disable 169 + A _a; +#pragma warning restore 169 + } + + public class GenDerivedClass : GenClass + { +#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 index 0000000000000..21f68be8c01c1 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Hashcode.cs @@ -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() + { } + } + + class GenericType + { + void GenericMethod() + { + } + } +} 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 index 0000000000000..188d26d8e1a56 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InstanceFieldLayout.cs @@ -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 + { + public byte _byte; + public T _value; + } +} + +namespace IsByRefLike +{ + public ref struct ByRefLikeStruct + { + ByReference 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 index 0000000000000..c92aafdeef655 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/InterfaceArrangements.cs @@ -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 { } + + class NoInterfaces { } + + class OneInterface : I1 { } + + class Base : IGen1, I1 { } + + class Mid : Base, IGen1 { } + + class DerivedFromMid : Mid, IGen1 { } + + interface IFoo + { + void IMethod(); + } + + class Foo : IFoo, IFoo + { + public virtual void IMethod() { } + } + + class DerivedFromFoo : Foo, IFoo, IFoo + { + void IFoo.IMethod() { } + } + + class SuperDerivedFromFoo : DerivedFromFoo, IFoo, IFoo + { + void IFoo.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 index 0000000000000..e61a165cd6cc3 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Platform.cs @@ -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 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 : Array, System.Collections.Generic.IList { } + + public class Exception { } + + public ref struct TypedReference + { + private readonly ByReference _value; + private readonly RuntimeTypeHandle _typeHandle; + } + + public ref struct ByReference { } +} + +namespace System.Collections +{ + interface IEnumerable { } + + interface ICollection : IEnumerable { } + + interface IList : ICollection { } +} + +namespace System.Collections.Generic +{ + interface IEnumerable { } + + interface ICollection : IEnumerable { } + + interface IList : ICollection { } +} + +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 index 0000000000000..3fc670b4d8388 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/StaticFieldLayout.cs @@ -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 index 0000000000000..326bf7dfccd7c --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/SyntheticVirtualOverride.cs @@ -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 index 0000000000000..6010b2b1f6bdf --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/TypeNameParsing.cs @@ -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 + { + public class NestedNongeneric + { + } + + public class NestedGeneric + { + } + } + + public class VeryGeneric + { + } + + 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 index 0000000000000..92ca4cb598f52 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/ValueTypeShapeCharacteristics.cs @@ -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 index 0000000000000..36aa307d1926b --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/VirtualFunctionOverride.cs @@ -0,0 +1,42 @@ +using System; + +namespace VirtualFunctionOverride +{ + interface IIFaceWithGenericMethod + { + void GenMethod(); + } + + class HasMethodInterfaceOverrideOfGenericMethod : IIFaceWithGenericMethod + { + void IIFaceWithGenericMethod.GenMethod() { } + } + + class SimpleGeneric + { + public override string ToString() + { + return null; + } + } + + class BaseGenericWithOverload + { + public virtual void MyMethod(string s) { } + public virtual void MyMethod(T s) { } + } + + class DerivedGenericWithOverload : BaseGenericWithOverload + { + 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 index 0000000000000..7193a800bd9ed --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs @@ -0,0 +1,98 @@ +// 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()); + } + } + + [Fact] + public void TestStaticMap() + { + MetadataType mixedStaticClass = _testModule.GetType("GCPointerMap", "MixedStaticClass"); + var map = GCPointerMap.FromStaticLayout(mixedStaticClass); + Assert.Equal(12, map.Size); + Assert.Equal("010100101001", map.ToString()); + } + + [Fact] + public void TestThreadStaticMap() + { + MetadataType mixedThreadStaticClass = _testModule.GetType("GCPointerMap", "MixedThreadStaticClass"); + var map = GCPointerMap.FromThreadStaticLayout(mixedThreadStaticClass); + Assert.Equal(14, map.Size); + Assert.Equal("00010010100110", 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 index 0000000000000..ddfe97e26b08a --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs @@ -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; + } + + /// + /// Testing proper instantiation of types and methods involving generic parameters in their signature. + /// + [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()); + } + + /// + /// Testing lookup up of a method in an instantiated type. + /// + [Fact] + [ActiveIssue(-1)] + 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 index 0000000000000..1415d1daed262 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/HashcodeTests.cs @@ -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 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 index 0000000000000..f1ef7772b0612 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj @@ -0,0 +1,61 @@ + + + + Library + TypeSystem.Tests + TypeSystem.Tests + netstandard2.0 + + $(NoWarn);NU1603 + + + + $(XUnitPackageVersion) + + + $(MicrosoftDotNetXUnitExtensionsVersion) + + + $(SystemReflectionMetadataVersion) + + + + + + + false + Content + PreserveNewest + Build;DebugSymbolsProjectOutputGroup + + + false + Content + PreserveNewest + Build + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 0000000000000..fc55923ae02c6 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILDisassemblerTests.cs @@ -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 interestingLines = new Dictionary + { + { 4, "IL_0003: ldstr \"Hello \\\"World\\\"!\\n\"" }, + { 9, "IL_000D: call instance void class ILDisassembler.TestGenericClass`1::VoidGenericMethod(!!0, int32, native int, class ILDisassembler.TestClass&)" }, + { 14, "IL_0017: initobj !TClassParam" }, + { 16, "IL_001E: call !!0 class ILDisassembler.TestGenericClass`1::MethodParamGenericMethod(class ILDisassembler.TestGenericClass`1, class ILDisassembler.TestGenericClass`1/Nested, valuetype ILDisassembler.TestStruct*[], !0)" }, + { 24, "IL_0030: call !!0 class ILDisassembler.TestGenericClass`1::MethodParamGenericMethod(class ILDisassembler.TestGenericClass`1, class ILDisassembler.TestGenericClass`1/Nested, valuetype ILDisassembler.TestStruct*[], !0)" }, + { 26, "IL_0036: ldtoken !TClassParam" }, + { 28, "IL_003C: ldtoken valuetype [CoreTestAssembly]System.Nullable`1" }, + { 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::NonGenericMethod(float64, float32, int16)" }, + { 37, "IL_005A: ldflda !0 class ILDisassembler.TestGenericClass`1::somefield" }, + { 41, "IL_0067: stfld class ILDisassembler.TestClass class ILDisassembler.TestGenericClass`1::otherfield" }, + { 44, "IL_006E: stfld class ILDisassembler.TestGenericClass`1> class ILDisassembler.TestGenericClass`1::genericfield" }, + { 47, "IL_0075: stfld !0[] class ILDisassembler.TestGenericClass`1::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 index 0000000000000..56cb0a6c8b0e4 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILDisassembler.il @@ -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 + extends [CoreTestAssembly]System.Object +{ + .class auto ansi nested public beforefieldinit Nested + 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> genericfield + .field private !TClassParam[] arrayfield + .method public hidebysig instance void + VoidGenericMethod(!!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(class ILDisassembler.TestGenericClass`1 x, + class ILDisassembler.TestGenericClass`1/Nested 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::VoidGenericMethod(!!0, + int32, + native int, + class ILDisassembler.TestClass&) + ldnull + ldnull + ldnull + ldloca.s V_1 + initobj !TClassParam + ldloc.1 + call !!0 class ILDisassembler.TestGenericClass`1::MethodParamGenericMethod(class ILDisassembler.TestGenericClass`1, + class ILDisassembler.TestGenericClass`1/Nested, + valuetype ILDisassembler.TestStruct*[], + !0) + pop + ldnull + ldnull + ldnull + ldloca.s V_1 + initobj !TClassParam + ldloc.1 + call !!0 class ILDisassembler.TestGenericClass`1::MethodParamGenericMethod(class ILDisassembler.TestGenericClass`1, + class ILDisassembler.TestGenericClass`1/Nested, + valuetype ILDisassembler.TestStruct*[], + !0) + pop + ldtoken !TClassParam + pop + ldtoken valuetype [CoreTestAssembly]System.Nullable`1 + pop + ldarg.0 + ldc.r8 3.1400000000000001 + ldc.r4 1.6799999 + ldc.i4.s 42 + call instance valuetype ILDisassembler.TestStruct class ILDisassembler.TestGenericClass`1::NonGenericMethod(float64, + float32, + int16) + pop + ldarg.0 + ldflda !0 class ILDisassembler.TestGenericClass`1::somefield + initobj !TClassParam + ldarg.0 + ldnull + stfld class ILDisassembler.TestClass class ILDisassembler.TestGenericClass`1::otherfield + ldarg.0 + ldnull + stfld class ILDisassembler.TestGenericClass`1> class ILDisassembler.TestGenericClass`1::genericfield + ldarg.0 + ldnull + stfld !0[] class ILDisassembler.TestGenericClass`1::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 index 0000000000000..bce9574f96624 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj @@ -0,0 +1,21 @@ + + + + + Library + ILTestAssembly + true + + + + + + + + + + + + + + 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 index 0000000000000..2a07e9e575a17 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/InstanceFieldLayout.il @@ -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 ByRef +} + +.class public auto ansi beforefieldinit IsByRefLike.InvalidClass1 + extends [CoreTestAssembly]System.Object +{ + .field private valuetype [CoreTestAssembly]System.ByReference`1 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 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 index 0000000000000..dc7aef4444b5c --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/Main.il @@ -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 index 0000000000000..ca2b748c09530 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/StaticFieldLayout.il @@ -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 index 0000000000000..f0f24379a5d26 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/VirtualFunctionOverride.il @@ -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 index 0000000000000..142abfdfa8422 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs @@ -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 ) + // 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(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields)); + } + + { + DefType type = _testModule.GetType("Explicit", "MisalignedByRef"); + Assert.Throws(() => 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 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(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields)); + } + + { + DefType type = _ilTestModule.GetType("IsByRefLike", "InvalidClass2"); + Assert.Throws(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields)); + } + + { + DefType type = _ilTestModule.GetType("IsByRefLike", "InvalidStruct"); + Assert.Throws(() => 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 index 0000000000000..7f741fabf0e43 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs @@ -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 + 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 index 0000000000000..876c1ce77ef8d --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs @@ -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 and GenericReferenceType 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(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 is same as canonical form of GenericReferenceType + Assert.Same( + grtOverRtShared.ConvertToCanonForm(CanonicalFormKind.Specific), + grtOverRt.ConvertToCanonForm(CanonicalFormKind.Specific)); + + // GenericReferenceType and GenericReferenceType have the same shared form + var grtOverArray = _genericReferenceType.MakeInstantiatedType(_structType.MakeArrayType()); + var grtOverArrayShared = grtOverArray.ConvertToSharedRuntimeDeterminedForm(); + Assert.Same(grtOverRtShared, grtOverArrayShared); + + // Converting GenericReferenceType 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 + // GenericReferenceTypeWithThreeParams + // 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 + // GenericReferenceTypeWithThreeParams + // have the same shared runtime form. + Assert.Same(grtOverStRtStShared, grtOverStOtherRtStShared); + + // GenericReferenceTypeWithThreeParams + // GenericReferenceTypeWithThreeParams + // 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> is + // GenericReferenceTypeWithThreeParams + var arg0 = grtOverRtRtStOverUniversalShared.Instantiation[0]; + Assert.IsType(arg0); + Assert.Same(_context.UniversalCanonType, ((RuntimeDeterminedType)arg0).CanonicalType); + var arg2 = grtOverRtRtStOverUniversalShared.Instantiation[2]; + Assert.IsType(arg2); + Assert.Same(_context.UniversalCanonType, ((RuntimeDeterminedType)arg2).CanonicalType); + } + + [Fact] + public void TestSignatureInstantiation() + { + var grtOverRtStRt = _genericReferenceTypeWithThreeParams.MakeInstantiatedType( + _referenceType, _structType, _referenceType); + var grtOverRtStRtShared = grtOverRtStRt.ConvertToSharedRuntimeDeterminedForm(); + + // GenericReferenceTypeWithThreeParams substituted over + // an instantiation of is + // GenericReferenceTypeWithThreeParams + 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> converts to + // GenericReferenceType> + var typeArg = grtOverStOverCanonShared.Instantiation[0]; + Assert.IsType(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 index 0000000000000..98a06c8abe3a1 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/StaticFieldLayoutTests.cs @@ -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 index 0000000000000..0058db8a6093e --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs @@ -0,0 +1,231 @@ +// 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 introducedVirtualMethods = new List(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 virtualSlots = new List(t.EnumAllVirtualSlots()); + Assert.All(virtualSlots, s => { Assert.True(s.OwningType.IsObject); }); + Assert.Equal(4, virtualSlots.Count); + + List 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 virtualSlots = new List(t.EnumAllVirtualSlots()); + Assert.All(virtualSlots, s => { Assert.True(s.OwningType.IsObject); }); + Assert.Equal(4, virtualSlots.Count); + + List 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 virtualSlots = new List(t.EnumAllVirtualSlots()); + Assert.All(virtualSlots, s => { Assert.True(s.OwningType.IsObject); }); + Assert.Equal(4, virtualSlots.Count); + + List 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 _getHashCodeMethods = new Dictionary(); + private Dictionary _equalsMethods = new Dictionary(); + + 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())); + _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 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 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 index 0000000000000..ba96e1c7da08e --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestMetadataFieldLayoutAlgorithm.cs @@ -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 index 0000000000000..fd6b61f6b33b1 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs @@ -0,0 +1,127 @@ +// 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.PortableExecutable; +using System.IO; + +namespace TypeSystemTests +{ + public enum CanonicalizationMode + { + Standard, + RuntimeDetermined, + } + + class TestTypeSystemContext : MetadataTypeSystemContext + { + Dictionary _modules = new Dictionary(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) + { + ModuleDesc module = Internal.TypeSystem.Ecma.EcmaModule.Create(this, new PEReader(File.OpenRead(simpleName + ".dll")), 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 index 0000000000000..392eb0bceb929 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TypeNameParsingTests.cs @@ -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(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.SimpleButNotThere")); + Assert.Throws(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.SimpleButNotThere+NonNamespaceQualifiedType")); + Assert.Throws(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+NestedNotThere")); + Assert.Throws(() => _testModule.GetTypeByCustomAttributeTypeName("TypeNameParsing.Simple+Nested+NestedTwiceNotThere")); + Assert.Throws(() => _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 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 index 0000000000000..c55fb2d5ec668 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs @@ -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(() => { return new LayoutInt(int.MinValue); }); + Assert.Throws(() => { 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(() => { 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(() => { return new LayoutInt(int.MaxValue) + LayoutInt.One; }); + Assert.Throws(() => { 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 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 index 0000000000000..226148d121d6d --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ValueTypeShapeCharacteristicsTests.cs @@ -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 index 0000000000000..b9bd29fb17b36 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/VirtualFunctionOverrideTests.cs @@ -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()); + 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 index 0000000000000..66a47410330b9 --- /dev/null +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/WellKnownTypeTests.cs @@ -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); + } + } +} From eda8c3551139db81ff0ef2a554a26d4840e3d71d Mon Sep 17 00:00:00 2001 From: Simon Nattress Date: Tue, 16 Jun 2020 21:12:53 -0700 Subject: [PATCH 2/4] Tests build and pass `build.cmd -test -s clr.tools -rc checked -a x64` builds the product and unit tests, and then runs the unit tests. --- eng/Subsets.props | 1 + .../Common/ConstructedTypeRewritingHelpers.cs | 209 ++++++++++++++++++ .../CastingTests.cs | 2 + .../CoreTestAssembly/CoreTestAssembly.csproj | 27 +-- .../GCPointerMapTests.cs | 18 -- .../GenericTypeAndMethodTests.cs | 2 +- ...ompiler.TypeSystem.ReadyToRun.Tests.csproj | 39 ++-- .../ILTestAssembly/ILTestAssembly.ilproj | 6 +- .../InterfacesTests.cs | 1 + .../SyntheticVirtualOverrideTests.cs | 8 + .../TestTypeSystemContext.cs | 18 +- .../UniversalGenericFieldLayoutTests.cs | 4 + .../ILCompiler.TypeSystem.ReadyToRun.csproj | 6 + 13 files changed, 265 insertions(+), 76 deletions(-) create mode 100644 src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs diff --git a/eng/Subsets.props b/eng/Subsets.props index a058a944b993a..db1d6b613acfb 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -150,6 +150,7 @@ $(CoreClrProjectRoot)src\tools\dotnet-pgo\dotnet-pgo.csproj; $(CoreClrProjectRoot)src\tools\r2rtest\R2RTest.csproj" Category="clr" BuildInParallel="true" /> + 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 index 0000000000000..ee7bcd978dc4e --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs @@ -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 + { + /// + /// 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<SomeGeneric<int[]>>, 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. + /// + /// type to examine + /// types to search for in the construction of type + /// true if a type in typesToFind is found + 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; + } + + /// + /// 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<object, int[]>, + /// 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<__Canon, string[]> + /// + /// This function cannot be used to replace MyType in the above example. + /// + 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; + } + + /// + /// 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<object, int[]>.Function<short>(), + /// 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<object, string[]>.Function<char> + /// + /// This function cannot be used to replace MyType in the above example. + /// + 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/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs index 1d81c8196441b..b16bb5c96f162 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs @@ -93,6 +93,7 @@ public void TestSameSizeArrayTypeCasting() } [Fact] + [ActiveIssue("corert port")] public void TestArrayInterfaceCasting() { TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32); @@ -169,6 +170,7 @@ public void TestGenericParameterCasting() } [Fact] + [ActiveIssue("corert port")] public void TestVariantCasting() { TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String); 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 index efdb81aa49692..d9917bb956c17 100644 --- 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 @@ -1,27 +1,16 @@ - - + Library CoreTestAssembly false true true + netstandard2.0 + + true + + v4.0.30319 + + false - - - - - - - - - - - - - - - - - \ No newline at end of file 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 index 7193a800bd9ed..4268fa18e77ba 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs @@ -76,23 +76,5 @@ public void TestInstanceMap() Assert.Equal("11111111111111111111111111111111", map.ToString()); } } - - [Fact] - public void TestStaticMap() - { - MetadataType mixedStaticClass = _testModule.GetType("GCPointerMap", "MixedStaticClass"); - var map = GCPointerMap.FromStaticLayout(mixedStaticClass); - Assert.Equal(12, map.Size); - Assert.Equal("010100101001", map.ToString()); - } - - [Fact] - public void TestThreadStaticMap() - { - MetadataType mixedThreadStaticClass = _testModule.GetType("GCPointerMap", "MixedThreadStaticClass"); - var map = GCPointerMap.FromThreadStaticLayout(mixedThreadStaticClass); - Assert.Equal(14, map.Size); - Assert.Equal("00010010100110", 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 index ddfe97e26b08a..2e881d7313fce 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GenericTypeAndMethodTests.cs @@ -110,7 +110,7 @@ public void TestFinalize() /// Testing lookup up of a method in an instantiated type. /// [Fact] - [ActiveIssue(-1)] + [ActiveIssue("")] public void TestMethodLookup() { MetadataType t = _testModule.GetType("GenericTypes", "GenericClass`1").MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32)); 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 index f1ef7772b0612..f4174a17b300a 100644 --- 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 @@ -1,38 +1,36 @@ - - + - Library - TypeSystem.Tests - TypeSystem.Tests + ILCompiler.TypeSystem.ReadyToRun.Tests netstandard2.0 - - $(NoWarn);NU1603 + Debug;Release;Checked + + true + -notrait category=failing + + $(NoWarn);NU1701 + + false - - - $(XUnitPackageVersion) - - - $(MicrosoftDotNetXUnitExtensionsVersion) - - - $(SystemReflectionMetadataVersion) - + + + + + + - + false Content PreserveNewest - Build;DebugSymbolsProjectOutputGroup false Content PreserveNewest - Build @@ -57,5 +55,4 @@ - 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 index bce9574f96624..3b75036f85917 100644 --- 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 @@ -1,10 +1,11 @@ - - + Library ILTestAssembly true + netstandard2.0 + false @@ -17,5 +18,4 @@ - 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 index 7f741fabf0e43..63635fcca3613 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs @@ -37,6 +37,7 @@ public void TestMultidimensionalArrays() } [Fact] + [ActiveIssue("corert port")] public void TestSingleDimensionalArrays() { DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array); 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 index 0058db8a6093e..ba6d57ec26752 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/SyntheticVirtualOverrideTests.cs @@ -206,6 +206,14 @@ public override string Name } } + public override string DiagnosticName + { + get + { + return _name; + } + } + public override TypeDesc OwningType { get 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 index fd6b61f6b33b1..fe9816d81f173 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using Internal.TypeSystem; +using System.Reflection; using System.Reflection.PortableExecutable; using System.IO; @@ -24,7 +25,6 @@ class TestTypeSystemContext : MetadataTypeSystemContext MetadataFieldLayoutAlgorithm _metadataFieldLayout = new TestMetadataFieldLayoutAlgorithm(); MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); - ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; VirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); public CanonicalizationMode CanonMode { get; set; } = CanonicalizationMode.RuntimeDetermined; @@ -45,7 +45,9 @@ public ModuleDesc GetModuleForSimpleName(string simpleName) public ModuleDesc CreateModuleForSimpleName(string simpleName) { - ModuleDesc module = Internal.TypeSystem.Ecma.EcmaModule.Create(this, new PEReader(File.OpenRead(simpleName + ".dll")), containingAssembly: null); + 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; } @@ -57,21 +59,9 @@ public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName 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; 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 index c55fb2d5ec668..aa58c37f709ed 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs @@ -226,6 +226,7 @@ private void TestLayoutOfUniversalCanonTypeOnArchitecture(TypeSystemContext cont Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadGcStaticFieldSize); } [Fact] + [ActiveIssue("corert port")] public void TestLayoutOfUniversalCanonType() { // Assert all of the various layout information about the universal canon type itself, do this for all architectures @@ -235,6 +236,7 @@ public void TestLayoutOfUniversalCanonType() } [Fact] + [ActiveIssue("corert port")] public void TestAllFieldsStructUniversalGeneric() { // Given a struct with all field universal, what is the layout? @@ -323,6 +325,7 @@ private void TestIndeterminatedNestedStructFieldPerContext(TypeSystemContext con } [Fact] + [ActiveIssue("corert port")] public void TestIndeterminateNestedStructField() { InstantiatedType genOfIntNestedInt; @@ -374,6 +377,7 @@ private void CommonClassLayoutTestBits(ModuleDesc testModule, } [Fact] + [ActiveIssue("corert port")] public void TestClassLayout() { // Tests class layout behavior with universal generics diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj index 9b6bb763c6d2e..3261a97633e75 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj @@ -115,6 +115,9 @@ TypeSystem\Common\CastingHelper.cs + + TypeSystem\Common\ConstructedTypeRewritingHelpers.cs + TypeSystem\Common\ExplicitLayoutValidator.cs @@ -274,6 +277,9 @@ TypeSystem\Common\TypeHashingAlgorithms.cs + + TypeSystem\Common\TypeSystemConstraintsHelpers.cs + TypeSystem\Common\TypeSystemContext.cs From 6f8ab45589217bb9ba91efe9315cb272a7ddf5a3 Mon Sep 17 00:00:00 2001 From: Simon Nattress Date: Fri, 19 Jun 2020 12:09:02 -0700 Subject: [PATCH 3/4] Port `Array` and USG layout algorithms Adds back another 5 passing tests --- .../ArrayOfTRuntimeInterfacesAlgorithm.cs | 39 ++++++++++++++ .../Common/UniversalCanonLayoutAlgorithm.cs | 54 +++++++++++++++++++ .../CastingTests.cs | 2 - .../CoreTestAssembly/CoreTestAssembly.csproj | 1 - .../InterfacesTests.cs | 1 - .../TestTypeSystemContext.cs | 19 +++++++ .../UniversalGenericFieldLayoutTests.cs | 4 -- .../ILCompiler.TypeSystem.ReadyToRun.csproj | 6 +++ 8 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs create mode 100644 src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs 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 index 0000000000000..6d611fd7db0f0 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs @@ -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 +{ + /// + /// RuntimeInterfaces algorithm for for array types which are similar to a generic type + /// + public sealed class ArrayOfTRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm + { + /// + /// Open type to instantiate to get the interfaces associated with an array. + /// + private MetadataType _arrayOfTType; + + /// + /// RuntimeInterfaces algorithm for for array types which are similar to a generic type + /// + /// Open type to instantiate to get the interfaces associated with an array. + 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/UniversalCanonLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs new file mode 100644 index 0000000000000..2e66f33b8f72a --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs @@ -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() + }; + } + + 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() + }; + } + + public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) + { + return ValueTypeShapeCharacteristics.None; + } + } +} 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 index b16bb5c96f162..1d81c8196441b 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs @@ -93,7 +93,6 @@ public void TestSameSizeArrayTypeCasting() } [Fact] - [ActiveIssue("corert port")] public void TestArrayInterfaceCasting() { TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32); @@ -170,7 +169,6 @@ public void TestGenericParameterCasting() } [Fact] - [ActiveIssue("corert port")] public void TestVariantCasting() { TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String); 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 index d9917bb956c17..4c028c607aca1 100644 --- 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 @@ -10,7 +10,6 @@ true v4.0.30319 - false \ No newline at end of file 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 index 63635fcca3613..7f741fabf0e43 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InterfacesTests.cs @@ -37,7 +37,6 @@ public void TestMultidimensionalArrays() } [Fact] - [ActiveIssue("corert port")] public void TestSingleDimensionalArrays() { DefType systemArrayType = _context.GetWellKnownType(WellKnownType.Array); 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 index fe9816d81f173..41f4f863e6e04 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs @@ -25,6 +25,9 @@ class TestTypeSystemContext : MetadataTypeSystemContext MetadataFieldLayoutAlgorithm _metadataFieldLayout = new TestMetadataFieldLayoutAlgorithm(); MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); +#if !READYTORUN + ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; +#endif VirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); public CanonicalizationMode CanonMode { get; set; } = CanonicalizationMode.RuntimeDetermined; @@ -59,9 +62,25 @@ public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) { +#if !READYTORUN + if (type == UniversalCanonType) + return UniversalCanonLayoutAlgorithm.Instance; +#endif + return _metadataFieldLayout; } +#if !READYTORUN + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) + { + if (_arrayOfTRuntimeInterfacesAlgorithm == null) + { + _arrayOfTRuntimeInterfacesAlgorithm = new ArrayOfTRuntimeInterfacesAlgorithm(SystemModule.GetType("System", "Array`1")); + } + return _arrayOfTRuntimeInterfacesAlgorithm; + } +#endif + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) { return _metadataRuntimeInterfacesAlgorithm; 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 index aa58c37f709ed..c55fb2d5ec668 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs @@ -226,7 +226,6 @@ private void TestLayoutOfUniversalCanonTypeOnArchitecture(TypeSystemContext cont Assert.Equal(LayoutInt.Zero, context.UniversalCanonType.ThreadGcStaticFieldSize); } [Fact] - [ActiveIssue("corert port")] public void TestLayoutOfUniversalCanonType() { // Assert all of the various layout information about the universal canon type itself, do this for all architectures @@ -236,7 +235,6 @@ public void TestLayoutOfUniversalCanonType() } [Fact] - [ActiveIssue("corert port")] public void TestAllFieldsStructUniversalGeneric() { // Given a struct with all field universal, what is the layout? @@ -325,7 +323,6 @@ private void TestIndeterminatedNestedStructFieldPerContext(TypeSystemContext con } [Fact] - [ActiveIssue("corert port")] public void TestIndeterminateNestedStructField() { InstantiatedType genOfIntNestedInt; @@ -377,7 +374,6 @@ private void CommonClassLayoutTestBits(ModuleDesc testModule, } [Fact] - [ActiveIssue("corert port")] public void TestClassLayout() { // Tests class layout behavior with universal generics diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj index 3261a97633e75..c6266c64df3b0 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj @@ -112,6 +112,9 @@ Utilities\AlignmentHelper.cs + + Utilities\ArrayOfTRuntimeInterfacesAlgorithm.cs + TypeSystem\Common\CastingHelper.cs @@ -148,6 +151,9 @@ TypeSystem\Common\ThrowHelper.Common.cs + + TypeSystem\Common\UniversalCanonLayoutAlgorithm.cs + Utilities\CustomAttributeTypeNameFormatter.cs From d98d9a2f52f16a87fdc8a28a252e94eca796abb2 Mon Sep 17 00:00:00 2001 From: Simon Nattress Date: Mon, 22 Jun 2020 15:28:43 -0700 Subject: [PATCH 4/4] Disable unit tests on linux-musl On Alpine x64, ildasm executable cannot be found. The Ilasm SDK seems to be missing linux-musl recognition in its targets: https://github.com/dotnet/runtime/blob/54625f377552300ce03100b4d1689af30395f9fd/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets#L32 --- eng/Subsets.props | 2 +- .../TestTypeSystemContext.cs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index db1d6b613acfb..b27d1e55a8bdd 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -150,7 +150,7 @@ $(CoreClrProjectRoot)src\tools\dotnet-pgo\dotnet-pgo.csproj; $(CoreClrProjectRoot)src\tools\r2rtest\R2RTest.csproj" Category="clr" BuildInParallel="true" /> - + 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 index 41f4f863e6e04..913cdbf8309bb 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs @@ -25,9 +25,7 @@ class TestTypeSystemContext : MetadataTypeSystemContext MetadataFieldLayoutAlgorithm _metadataFieldLayout = new TestMetadataFieldLayoutAlgorithm(); MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); -#if !READYTORUN ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; -#endif VirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); public CanonicalizationMode CanonMode { get; set; } = CanonicalizationMode.RuntimeDetermined; @@ -62,15 +60,12 @@ public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) { -#if !READYTORUN if (type == UniversalCanonType) return UniversalCanonLayoutAlgorithm.Instance; -#endif return _metadataFieldLayout; } -#if !READYTORUN protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) { if (_arrayOfTRuntimeInterfacesAlgorithm == null) @@ -79,7 +74,6 @@ protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNo } return _arrayOfTRuntimeInterfacesAlgorithm; } -#endif protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) {