diff options
Diffstat (limited to 'tests/src/readytorun/tests')
-rw-r--r-- | tests/src/readytorun/tests/fieldgetter.il | 215 | ||||
-rw-r--r-- | tests/src/readytorun/tests/fieldgetter.ilproj | 30 | ||||
-rw-r--r-- | tests/src/readytorun/tests/generics.cs | 650 | ||||
-rw-r--r-- | tests/src/readytorun/tests/generics.csproj | 32 | ||||
-rw-r--r-- | tests/src/readytorun/tests/genericsload/callgenericctor.cs | 35 | ||||
-rw-r--r-- | tests/src/readytorun/tests/genericsload/callgenericctor.csproj | 50 | ||||
-rw-r--r-- | tests/src/readytorun/tests/genericsload/genericslib.il | 58 | ||||
-rw-r--r-- | tests/src/readytorun/tests/genericsload/genericslib.ilproj | 37 | ||||
-rw-r--r-- | tests/src/readytorun/tests/genericsload/usegenericfield.cs | 39 | ||||
-rw-r--r-- | tests/src/readytorun/tests/genericsload/usegenericfield.csproj | 50 | ||||
-rw-r--r-- | tests/src/readytorun/tests/main.cs | 494 | ||||
-rw-r--r-- | tests/src/readytorun/tests/mainv1.csproj | 56 | ||||
-rw-r--r-- | tests/src/readytorun/tests/mainv2.csproj | 59 | ||||
-rw-r--r-- | tests/src/readytorun/tests/test.cs | 412 | ||||
-rw-r--r-- | tests/src/readytorun/tests/testv1/test.csproj | 32 | ||||
-rw-r--r-- | tests/src/readytorun/tests/testv2/test.csproj | 32 |
16 files changed, 2281 insertions, 0 deletions
diff --git a/tests/src/readytorun/tests/fieldgetter.il b/tests/src/readytorun/tests/fieldgetter.il new file mode 100644 index 0000000000..c2eff200af --- /dev/null +++ b/tests/src/readytorun/tests/fieldgetter.il @@ -0,0 +1,215 @@ +// 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 System.Console { } +.assembly extern mscorlib { } +.assembly extern test { } + +.assembly fieldgetter { } +.module fieldgetter.dll + +//========================================================================================== + +.class public auto ansi beforefieldinit Gen`1<T> + extends [mscorlib]System.Object +{ + .field public int32 m_Field1 + .field public string m_Field2 + .field public !T m_Field3 + .field public static class [mscorlib]System.Collections.Generic.List`1<!T> m_Field4 + .field public static valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!T,int32> m_Field5 + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Gen`1::.ctor +} // end of class Gen`1 + +.class interface public abstract auto ansi IFieldGetter +{ + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field1() cil managed + { + } // end of method IFieldGetter::GetGenT_Field1 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field2() cil managed + { + } // end of method IFieldGetter::GetGenT_Field2 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field3() cil managed + { + } // end of method IFieldGetter::GetGenT_Field3 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field4() cil managed + { + } // end of method IFieldGetter::GetGenT_Field4 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field5() cil managed + { + } // end of method IFieldGetter::GetGenT_Field5 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field1() cil managed + { + } // end of method IFieldGetter::GetGenDllT_Field1 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field2() cil managed + { + } // end of method IFieldGetter::GetGenDllT_Field2 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field3() cil managed + { + } // end of method IFieldGetter::GetGenDllT_Field3 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field4() cil managed + { + } // end of method IFieldGetter::GetGenDllT_Field4 + + .method public hidebysig newslot abstract virtual + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field5() cil managed + { + } // end of method IFieldGetter::GetGenDllT_Field5 + +} // end of class IFieldGetter + +.class public auto ansi beforefieldinit FieldGetter`1<T> + extends [mscorlib]System.Object + implements IFieldGetter +{ + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field1() cil managed + { + ldtoken field int32 class Gen`1<!0>::m_Field1 + ldtoken class Gen`1<!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenT_Field1 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field2() cil managed + { + ldtoken field string class Gen`1<!0>::m_Field2 + ldtoken class Gen`1<!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenT_Field2 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field3() cil managed + { + ldtoken field !0 class Gen`1<!0>::m_Field3 + ldtoken class Gen`1<!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenT_Field3 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field4() cil managed + { + ldtoken field class [mscorlib]System.Collections.Generic.List`1<!0> class Gen`1<!0>::m_Field4 + ldtoken class Gen`1<!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenT_Field4 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenT_Field5() cil managed + { + ldtoken field valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!0,int32> class Gen`1<!0>::m_Field5 + ldtoken class Gen`1<!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenT_Field5 + + + + + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field1() cil managed + { + ldtoken field string class [test]MyGeneric`2<!0,!0>::m_Field1 + ldtoken class [test]MyGeneric`2<!0,!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenDllT_Field1 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field2() cil managed + { + ldtoken field !0 class [test]MyGeneric`2<!0,!0>::m_Field2 + ldtoken class [test]MyGeneric`2<!0,!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenDllT_Field2 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field3() cil managed + { + ldtoken field class [mscorlib]System.Collections.Generic.List`1<!0> class [test]MyGeneric`2<!0,!0>::m_Field3 + ldtoken class [test]MyGeneric`2<!0,!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenDllT_Field3 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field4() cil managed + { + ldtoken field valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!0,int32> class [test]MyGeneric`2<!0,!0>::m_Field4 + ldtoken class [test]MyGeneric`2<!0,!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenDllT_Field4 + + .method public hidebysig newslot virtual final + instance class [mscorlib]System.Reflection.FieldInfo + GetGenDllT_Field5() cil managed + { + ldtoken field int32 class [test]MyGeneric`2<!0,!0>::m_Field5 + ldtoken class [test]MyGeneric`2<!0,!0> + call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle) + ret + } // end of method FieldGetter`1::GetGenDllT_Field5 + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method FieldGetter`1::.ctor + +} // end of class FieldGetter`1 + diff --git a/tests/src/readytorun/tests/fieldgetter.ilproj b/tests/src/readytorun/tests/fieldgetter.ilproj new file mode 100644 index 0000000000..b3f2aa9e13 --- /dev/null +++ b/tests/src/readytorun/tests/fieldgetter.ilproj @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>fieldgetter</AssemblyName> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <CLRTestKind>SharedLibrary</CLRTestKind> + </PropertyGroup> + + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + + <ItemGroup> + <Compile Include="fieldgetter.il" /> + </ItemGroup> + + + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/readytorun/tests/generics.cs b/tests/src/readytorun/tests/generics.cs new file mode 100644 index 0000000000..4c41756305 --- /dev/null +++ b/tests/src/readytorun/tests/generics.cs @@ -0,0 +1,650 @@ +// 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.Globalization; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; + +class Program +{ + static int Main() + { + // Run all tests 3x times to exercise both slow and fast paths work + for (int i = 0; i < 3; i++) + RunAllTests(); + + Console.WriteLine(Assert.HasAssertFired ? "FAILED" : "PASSED"); + return Assert.HasAssertFired ? 1 : 100; + } + + static void RunAllTests() + { + RunTest1(); + RunTest2(); + RunTest3(); + RunTest4(); + RunTest5(); + RunTest6(); + RunTest7(); + } + + static void RunTest1() + { + var originalCultureInfo = CultureInfo.CurrentCulture; + + try + { + CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; + + DateTime dt = new DateTime(1776, 7, 4); + string dtString = dt.ToString(); + Assert.AreEqual(new GenClass1c<DateTime>(dt).ToStringEx(7), dtString + " 7"); + Assert.AreEqual(new GenClass1c<int>(1).ToStringEx(7), "1 7"); + Assert.AreEqual(new GenClass1c<long>(2).ToStringEx(7), "2 7"); + Assert.AreEqual(new GenClass1c<float>(3.14f).ToStringEx(7), "3.14 7"); + Assert.AreEqual(new GenClass1c<double>(4.13).ToStringEx(7), "4.13 7"); + Assert.AreEqual(new GenClass1c<int?>(9).ToString(), "9"); + + Assert.AreEqual(new GenClass2<DateTime, double>(dt, 3.1416).ToString(), dtString + " 3.1416"); + Assert.AreEqual(new GenClass2<DateTime, double>(dt, 3.1416).ToStringEx(7, 8), dtString + " 3.1416 7 8"); + Assert.AreEqual(new GenClass2<object, string>(new object(), "3.1416").ToString(), "System.Object 3.1416"); + Assert.AreEqual(new GenClass2<object, string>(new object(), "3.1416").ToStringEx(7L, 8L), "System.Object 3.1416 7 8"); + Assert.AreEqual(GetString(7.0, 8.0), "7 8"); + + var gen1a = new GenClass1a<object>(); + Assert.AreEqual(gen1a.CreateGenClass1b(), "GenClass1b`1[System.Object]"); + Assert.AreEqual(gen1a.CreateGenClass1bArray(), "GenClass1b`1[System.Object][]"); + + var gen1aInt = new GenClass1a<int>(); + var gen1bInt = new GenClass1b<int>(); + var gen1bLong = new GenClass1b<long>(); + Assert.AreEqual(gen1bInt.IsGenClass1a(gen1aInt).ToString(), "True"); + Assert.AreEqual(gen1bLong.IsGenClass1a(gen1aInt).ToString(), "False"); + Assert.AreEqual(gen1bInt.AsGenClass1a(gen1aInt)?.ToString() ?? "null", gen1aInt.ToString()); + Assert.AreEqual(gen1bLong.AsGenClass1a(gen1aInt)?.ToString() ?? "null", "null"); + + var gen1aString = new GenClass1a<string>(); + var gen1b = new GenClass1b<string>(); + Assert.AreEqual(gen1b.IsGenClass1a(gen1aString).ToString(), "True"); + Assert.AreEqual(gen1b.AsGenClass1a(gen1aString)?.ToString() ?? "null", gen1aString.ToString()); + Assert.AreEqual(GenClass1a<string>.CallVirtual(gen1b), "GenClass1b`1[System.String].VirtualMethod"); + Assert.AreEqual(GenClass1a<string>.CallInterface(gen1b), "GenClass1b`1[System.String].InterfaceMethod1"); + Assert.AreEqual(GenClass1a<string>.CallInterface(gen1b, "Test").ToString(), "GenClass1b`1[System.String]"); + + NormalClass n = new NormalClass(); + Assert.AreEqual(CallGenVirtMethod<int>(n).ToString(), "GenClass1a`1[System.Int32]"); + Assert.AreEqual(CallGenVirtMethod<int>(n, 42).ToString(), "System.Int32[]"); + Assert.AreEqual(CallGenVirtMethod<string>(n).ToString(), "GenClass1a`1[System.String]"); + Assert.AreEqual(CallGenVirtMethod<string>(n, "forty-two").ToString(), "System.String[]"); + } + finally + { + CultureInfo.CurrentCulture = originalCultureInfo; + } + } + + static void RunTest2() + { + var mi = new GenBase<MyClass0, int>(); + var ol = new GenBase<object, long>(); + + // LDTOKEN OF TYPE PARAMETERS TEST + Assert.AreEqual(mi.GetT(), "MyClass0"); + Assert.AreEqual(mi.GetU(), "System.Int32"); + Assert.AreEqual(ol.GetT(), "System.Object"); + Assert.AreEqual(ol.GetU(), "System.Int64"); + Assert.AreEqual(mi.GetT(), "MyClass0"); + Assert.AreEqual(mi.GetU(), "System.Int32"); + + Assert.AreEqual(mi.GetTArray(), "MyClass0[]"); + Assert.AreEqual(ol.GetTArray(), "System.Object[]"); + Assert.AreEqual(mi.GetTArray(), "MyClass0[]"); + Assert.AreEqual(mi.GetTBasedInst(), "MyGenClass2`1[MyGenClass1`1[MyClass0]]"); + Assert.AreEqual(ol.GetTBasedInst(), "MyGenClass2`1[MyGenClass1`1[System.Object]]"); + Assert.AreEqual(mi.GetTBasedInst(), "MyGenClass2`1[MyGenClass1`1[MyClass0]]"); + } + + static void RunTest3() + { + var mi = new GenBase<MyClass0, int>(); + var ol = new GenBase<object, long>(); + + // GENERIC INTERFACE CALL AND CASTING TEST + Assert.AreEqual(mi.IFaceCallTest(mi), "IFaceCallTest = IFooFunc - GenBase`2[MyClass0,System.Int32]"); + Assert.AreEqual(ol.IFaceCallTest(ol), "IFaceCallTest = IFooFunc - GenBase`2[System.Object,System.Int64]"); + Assert.AreEqual(mi.IFaceCallTest(mi), "IFaceCallTest = IFooFunc - GenBase`2[MyClass0,System.Int32]"); + + // LDTOKEN TEST + Assert.AreEqual(mi.LdTokenTest(), "LdTokenTest - System.Collections.Generic.Dictionary`2[MyClass0,System.Int32]"); + Assert.AreEqual(ol.LdTokenTest(), "LdTokenTest - System.Collections.Generic.Dictionary`2[System.Object,System.Int64]"); + Assert.AreEqual(mi.LdTokenTest(), "LdTokenTest - System.Collections.Generic.Dictionary`2[MyClass0,System.Int32]"); + + // DICTIONARY ACCESS FROM STATIC METHOD + Assert.AreEqual(GenBase<MyClass0, int>.StaticNonGenMethod(), "StaticNonGenMethod - System.Collections.Generic.List`1[MyClass0]"); + Assert.AreEqual(GenBase<object, long>.StaticNonGenMethod(), "StaticNonGenMethod - System.Collections.Generic.List`1[System.Object]"); + Assert.AreEqual(GenBase<MyClass0, int>.StaticNonGenMethod(), "StaticNonGenMethod - System.Collections.Generic.List`1[MyClass0]"); + Assert.AreEqual(GenBase<MyClass0, int>.StaticGenMethod<Type>(), "StaticGenMethod - System.Collections.Generic.Dictionary`2[System.Type,MyClass0]"); + Assert.AreEqual(GenBase<object, long>.StaticGenMethod<Type>(), "StaticGenMethod - System.Collections.Generic.Dictionary`2[System.Type,System.Object]"); + Assert.AreEqual(GenBase<MyClass0, int>.StaticGenMethod<Type>(), "StaticGenMethod - System.Collections.Generic.Dictionary`2[System.Type,MyClass0]"); + + // NEW TEST + Assert.AreEqual(mi.NewTest(), "NewTest - MyClass0 - MyGenClass1`1[MyClass0] - MyClass0[] - MyClass0[,] - MyGenClass3`1[MyClass0][] - MyGenClass3`1[MyClass0][,]"); + Assert.AreEqual(ol.NewTest(), "NewTest - System.Object - MyGenClass1`1[System.Object] - System.Object[] - System.Object[,] - MyGenClass3`1[System.Object][] - MyGenClass3`1[System.Object][,]"); + Assert.AreEqual(mi.NewTest(), "NewTest - MyClass0 - MyGenClass1`1[MyClass0] - MyClass0[] - MyClass0[,] - MyGenClass3`1[MyClass0][] - MyGenClass3`1[MyClass0][,]"); + } + + static void RunTest4() + { + // FIELDS TEST + var fobj1 = new GenBase<MyIdClass0, int>(); + var fobj2 = new GenBase<MyIdClass1, int>(); + GenBase<MyIdClass0, int>.SetFieldsTest(fobj1, new MyIdClass0("1"), new MyIdClass0("2"), new MyIdClass0("3"), 1, 2, 3); + GenBase<MyIdClass1, int>.SetFieldsTest(fobj2, new MyIdClass1("1"), new MyIdClass1("2"), new MyIdClass1("3"), 1, 2, 3); + + GenBase<MyIdClass0, int>.GetFieldsTest(fobj1, "MyIdClass0=1", "MyIdClass0=2", "MyIdClass0=3", 1, 2, 3); + GenBase<MyIdClass1, int>.GetFieldsTest(fobj2, "MyIdClass1=1", "MyIdClass1=2", "MyIdClass1=3", 1, 2, 3); + + Thread t = new Thread(new ThreadStart(() => + { + GenBase<MyIdClass0, int>.SetFieldsTest(fobj1, new MyIdClass0("11"), new MyIdClass0("22"), new MyIdClass0("33"), 11, 22, 33); + GenBase<MyIdClass1, int>.SetFieldsTest(fobj2, new MyIdClass1("11"), new MyIdClass1("22"), new MyIdClass1("33"), 11, 22, 33); + + GenBase<MyIdClass0, int>.GetFieldsTest(fobj1, "MyIdClass0=11", "MyIdClass0=22", "MyIdClass0=33", 11, 22, 33); + GenBase<MyIdClass1, int>.GetFieldsTest(fobj2, "MyIdClass1=11", "MyIdClass1=22", "MyIdClass1=33", 11, 22, 33); + })); + t.Start(); + t.Join(); + + GenBase<MyIdClass0, int>.GetFieldsTest(fobj1, "MyIdClass0=11", "MyIdClass0=22", "MyIdClass0=3", 11, 22, 3); + GenBase<MyIdClass1, int>.GetFieldsTest(fobj2, "MyIdClass1=11", "MyIdClass1=22", "MyIdClass1=3", 11, 22, 3); + } + + static void RunTest5() + { + // DELEGATES TEST + var fobj1 = new GenBase<MyIdClass0, int>(); + var fobj2 = new GenBase<MyIdClass1, int>(); + + Func<MyIdClass0, int, string>[] del1 = fobj1.GetDelegateTest(); + Func<MyIdClass1, int, string>[] del2 = fobj2.GetDelegateTest(); + Assert.AreEqual(del1[0](new MyIdClass0("1"), 1), "InstanceDelMethod(GenBase`2[MyIdClass0,System.Int32] - MyIdClass0=1 - 1)"); + Assert.AreEqual(del1[1](new MyIdClass0("2"), 2), "StaticDelMethod(MyIdClass0=2 - 2)"); + Assert.AreEqual(del2[0](new MyIdClass1("3"), 3), "InstanceDelMethod(GenBase`2[MyIdClass1,System.Int32] - MyIdClass1=3 - 3)"); + Assert.AreEqual(del2[1](new MyIdClass1("4"), 4), "StaticDelMethod(MyIdClass1=4 - 4)"); + Assert.AreEqual(del1[0](new MyIdClass0("5"), 5), "InstanceDelMethod(GenBase`2[MyIdClass0,System.Int32] - MyIdClass0=5 - 5)"); + Assert.AreEqual(del1[1](new MyIdClass0("6"), 6), "StaticDelMethod(MyIdClass0=6 - 6)"); + } + + static void RunTest6() + { + // BOXING AND NULLABLE TEST + var mi = new GenBase<MyClass0, int>(); + var ol = new GenBase<object, long>(); + + Assert.AreEqual(mi.BoxingAndNullableTest( + new MyGenClass1<KeyValuePair<MyClass0, int>>(), + new MyGenStruct1<Dictionary<MyClass0, int>>(), + new MyGenStruct1<Dictionary<MyClass0, int>>()), + "BoxingAndNullableTest - GenBase`2[MyClass0,System.Int32]::(MyGenClass1`1[System.Collections.Generic.KeyValuePair`2[MyClass0,System.Int32]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[MyClass0,System.Int32]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[MyClass0,System.Int32]])"); + Assert.AreEqual(ol.BoxingAndNullableTest( + new MyGenClass1<KeyValuePair<object, long>>(), + new MyGenStruct1<Dictionary<object, long>>(), + new MyGenStruct1<Dictionary<object, long>>()), + "BoxingAndNullableTest - GenBase`2[System.Object,System.Int64]::(MyGenClass1`1[System.Collections.Generic.KeyValuePair`2[System.Object,System.Int64]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[System.Object,System.Int64]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[System.Object,System.Int64]])"); + } + + static void RunTest7() + { + // GENERIC METHOD TEST + + Base b = new Base(); + var obj1 = new GenBase<MyClass1, int>(); + var obj2 = new GenBase<MyClass2, long>(); + + // LDTOKEN OF TYPE PARAMETERS TEST + Assert.AreEqual(b.GetT<string>().ToString(), "System.String"); + Assert.AreEqual(b.GetT<object>().ToString(), "System.Object"); + Assert.AreEqual(b.GetTArray<string>().ToString(), "System.String[]"); + Assert.AreEqual(b.GetTArray<object>().ToString(), "System.Object[]"); + Assert.AreEqual(b.GetTBasedInst<string>().ToString(), "MyGenClass2`1[MyGenClass1`1[System.String]]"); + Assert.AreEqual(b.GetTBasedInst<object>().ToString(), "MyGenClass2`1[MyGenClass1`1[System.Object]]"); + + Assert.AreEqual(b.GetT<MyClass1, int>(), "MyClass1"); + Assert.AreEqual(b.GetU<MyClass1, int>(), "System.Int32"); + Assert.AreEqual(b.GetT<MyClass2, long>(), "MyClass2"); + Assert.AreEqual(b.GetU<MyClass2, long>(), "System.Int64"); + + // GENERIC INTERFACE CALL AND CASTING TEST + Assert.AreEqual(b.IFaceCallTest<MyClass1, int>(obj1), "IFaceCallTest = IFooFunc - GenBase`2[MyClass1,System.Int32]"); + Assert.AreEqual(b.IFaceCallTest<MyClass2, long>(obj2), "IFaceCallTest = IFooFunc - GenBase`2[MyClass2,System.Int64]"); + + // LDTOKEN TEST + Assert.AreEqual(b.LdTokenTest<MyClass1, int>(), "System.Collections.Generic.Dictionary`2[MyClass1,System.Int32]"); + Assert.AreEqual(b.LdTokenTest<MyClass2, long>(), "System.Collections.Generic.Dictionary`2[MyClass2,System.Int64]"); + + // DICTIONARY ACCESS FROM STATIC METHOD + Assert.AreEqual(Base.StaticGenMethod<float, MyClass1>(), "StaticGenMethod - System.Collections.Generic.Dictionary`2[MyClass1,System.Single]"); + Assert.AreEqual(Base.StaticGenMethod<float, MyClass2>(), "StaticGenMethod - System.Collections.Generic.Dictionary`2[MyClass2,System.Single]"); + + // NEW TEST + Assert.AreEqual(b.NewTest<MyClass1, MyClass2>(), + "NewTest - MyClass1 - MyGenClass1`1[MyClass1] - MyClass1[] - MyClass1[,] - MyGenClass2`1[MyClass1][] - MyGenClass2`1[MyClass1][,]"); + Assert.AreEqual(b.NewTest<MyClass2, MyClass1>(), + "NewTest - MyClass2 - MyGenClass1`1[MyClass2] - MyClass2[] - MyClass2[,] - MyGenClass2`1[MyClass2][] - MyGenClass2`1[MyClass2][,]"); + + // BOXING AND NULLABLE TEST + Assert.AreEqual(b.BoxingAndNullableTest<MyClass0, int>( + new MyGenClass1<KeyValuePair<MyClass0, int>>(), + new MyGenStruct1<Dictionary<MyClass0, int>>(), + new MyGenStruct1<Dictionary<MyClass0, int>>()), + "BoxingAndNullableTest - Base::(MyGenClass1`1[System.Collections.Generic.KeyValuePair`2[MyClass0,System.Int32]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[MyClass0,System.Int32]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[MyClass0,System.Int32]])"); + Assert.AreEqual(b.BoxingAndNullableTest<object, int>( + new MyGenClass1<KeyValuePair<object, int>>(), + new MyGenStruct1<Dictionary<object, int>>(), + new MyGenStruct1<Dictionary<object, int>>()), + "BoxingAndNullableTest - Base::(MyGenClass1`1[System.Collections.Generic.KeyValuePair`2[System.Object,System.Int32]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[System.Object,System.Int32]] - MyGenStruct1`1[System.Collections.Generic.Dictionary`2[System.Object,System.Int32]])"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static string GetString<X, Y>(X x, Y y) + { + return string.Join(" ", x, y); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static GenClass1a<T> CallGenVirtMethod<T>(NormalClass n) + { + return n.GetGenClass1a<T>(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static IEnumerable<T> CallGenVirtMethod<T>(NormalClass n, object o) + { + return n.GetEnumerable<T>(o); + } +} + +interface IGenInterface<T> +{ + string InterfaceMethod1(); + IGenInterface<T> InterfaceMethod2<U>(U u); +} + +class GenClass1a<T> +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public string CreateGenClass1b() + { + var x = new GenClass1b<T>(); + return x.ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string CreateGenClass1bArray() + { + var x = new GenClass1b<T>[3]; + return x.ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static string CallVirtual(GenClass1b<T> x) + { + return x.VirtualMethod(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static string CallInterface(IGenInterface<T> x) + { + return x.InterfaceMethod1(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static IGenInterface<U> CallInterface<U, V>(IGenInterface<U> x, V v) + { + return x.InterfaceMethod2(v); + } +} + +class GenClass1b<T> : IGenInterface<T> +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public virtual string VirtualMethod() + { + return ToString() + ".VirtualMethod"; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public virtual string InterfaceMethod1() + { + return ToString() + ".InterfaceMethod1"; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public virtual IGenInterface<T> InterfaceMethod2<U>(U u) + { + return this; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public bool IsGenClass1a(object o) + { + return o is GenClass1a<T>; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public GenClass1a<T> AsGenClass1a(object o) + { + return o as GenClass1a<T>; + } +} + +class GenClass1c<T> where T : new() +{ + public T t; + + [MethodImpl(MethodImplOptions.NoInlining)] + public GenClass1c() + { + t = new T(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public GenClass1c(T _t) + { + t = _t; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public void SetT(object x) + { + t = (T)x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public override string ToString() + { + return t.ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string ToStringEx<X>(X x) + { + return string.Join(" ", t, x); + } +} + +class GenClass2<T, U> +{ + T t; + U u; + + [MethodImpl(MethodImplOptions.NoInlining)] + public GenClass2(T t, U u) + { + this.t = t; + this.u = u; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public override string ToString() + { + return t.ToString() + " " + u.ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string ToStringEx<X, Y>(X x, Y y) + { + return string.Join(" ", t, u, x, y); + } +} + +class NormalClass +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public virtual GenClass1a<T> GetGenClass1a<T>() + { + return new GenClass1a<T>(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public virtual IEnumerable<T> GetEnumerable<T>(object o) + { + T[] array = new T[1]; + array[0] = (T)o; + return array; + } +} + +public interface IFoo<T> { string IFooFunc(); } +public class MyClass0 { } +public class MyClass1 { } +public class MyClass2 { } +public class MyGenClass1<T> { public override string ToString() { return this.GetType().ToString(); } } +public class MyGenClass2<T> { public override string ToString() { return this.GetType().ToString(); } } +public class MyGenClass3<T> { public override string ToString() { return this.GetType().ToString(); } } +public struct MyGenStruct1<T> { public override string ToString() { return this.GetType().ToString(); } } +public class MyIdClass0 { string _id; public MyIdClass0() { } public MyIdClass0(string id) { _id = id; } public override string ToString() { return "MyIdClass0=" + _id; } } +public class MyIdClass1 { string _id; public MyIdClass1() { } public MyIdClass1(string id) { _id = id; } public override string ToString() { return "MyIdClass1=" + _id; } } + +public class GenBase<T, U> : IFoo<T> where T : new() +{ + public T m_fieldT; + public U m_fieldU; + public static T s_fieldT; + public static U s_fieldU; + [ThreadStatic] + public static T st_fieldT; + [ThreadStatic] + public static U st_fieldU; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void SetFieldsTest(GenBase<T, U> obj, T t1, T t2, T t3, U u1, U u2, U u3) + { + obj.m_fieldT = t1; + GenBase<T, U>.s_fieldT = t2; + GenBase<T, U>.st_fieldT = t3; + + obj.m_fieldU = u1; + GenBase<T, U>.s_fieldU = u2; + GenBase<T, U>.st_fieldU = u3; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void GetFieldsTest(GenBase<T, U> obj, string s1, string s2, string s3, U u1, U u2, U u3) + { + Assert.AreEqual(obj.m_fieldT.ToString(), s1); + Assert.AreEqual(GenBase<T, U>.s_fieldT.ToString(), s2); + Assert.AreEqual(GenBase<T, U>.st_fieldT.ToString(), s3); + + Assert.AreEqual(obj.m_fieldU, u1); + Assert.AreEqual(GenBase<T, U>.s_fieldU, u2); + Assert.AreEqual(GenBase<T, U>.st_fieldU, u3); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + // BUG BUG BUG: bad codegen when method is private + public string InstanceDelMethod(T t, U u) + { + return "InstanceDelMethod(" + this + " - " + t + " - " + u + ")"; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + // BUG BUG BUG: bad codegen when method is private + public static string StaticDelMethod(T t, U u) + { + return "StaticDelMethod(" + t + " - " + u + ")"; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public Func<T, U, string>[] GetDelegateTest() + { + Func<T, U, string> del1 = this.InstanceDelMethod; + Func<T, U, string> del2 = StaticDelMethod; + return new Func<T, U, string>[] { del1, del2 }; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string IFooFunc() + { + return "IFooFunc - " + this.ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string IFaceCallTest(object ifoo) + { + IFoo<T> i = (IFoo<T>)ifoo; + return "IFaceCallTest = " + i.IFooFunc(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetT() + { + return typeof(T).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetU() + { + return typeof(U).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetTArray() + { + return typeof(T[]).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetTBasedInst() + { + return typeof(MyGenClass2<MyGenClass1<T>>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string LdTokenTest() + { + return "LdTokenTest - " + typeof(Dictionary<T, U>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static string StaticNonGenMethod() + { + return "StaticNonGenMethod - " + typeof(List<T>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static string StaticGenMethod<V>() + { + return "StaticGenMethod - " + typeof(Dictionary<V, T>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string NewTest() + { + var a = new T(); + var b = new MyGenClass1<T>(); + var c = new T[10]; + var d = new T[30,30]; + var e = new MyGenClass3<T>[5]; + var f = new MyGenClass3<T>[5,13]; + return "NewTest - " + a + " - " + b + " - " + c + " - " + d + " - " + e + " - " + f; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string BoxingAndNullableTest(MyGenClass1<KeyValuePair<T,U>> t, MyGenStruct1<Dictionary<T,U>> u, MyGenStruct1<Dictionary<T,U>>? u2) + { + return "BoxingAndNullableTest - " + this + "::(" + t + " - " + u + " - " + u2 + ")"; + } +} + +public class Base +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetT<T>() + { + return typeof(T).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetT<T, U>() + { + return typeof(T).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetU<T, U>() + { + return typeof(U).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetTArray<T>() + { + return typeof(T[]).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string GetTBasedInst<T>() + { + return typeof(MyGenClass2<MyGenClass1<T>>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string IFaceCallTest<T, U>(object ifoo) + { + IFoo<T> i = (IFoo<T>)ifoo; + return "IFaceCallTest = " + i.IFooFunc(); + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + public string LdTokenTest<T, U>() + { + return typeof(Dictionary<T, U>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static string StaticGenMethod<T, U>() + { + return "StaticGenMethod - " + typeof(Dictionary<U, T>).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string NewTest<T, U>() where T : new() + { + var a = new T(); + var b = new MyGenClass1<T>(); + var c = new T[10]; + var d = new T[30, 30]; + var e = new MyGenClass2<T>[5]; + var f = new MyGenClass2<T>[5, 13]; + return "NewTest - " + a + " - " + b + " - " + c + " - " + d + " - " + e + " - " + f; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public string BoxingAndNullableTest<T, U>(MyGenClass1<KeyValuePair<T, U>> t, MyGenStruct1<Dictionary<T, U>> u, MyGenStruct1<Dictionary<T, U>>? u2) + { + return "BoxingAndNullableTest - " + this + "::(" + t + " - " + u + " - " + u2 + ")"; + } +} + +public static class Assert +{ + public static bool HasAssertFired; + + public static void AreEqual(Object actual, Object expected) + { + if (!(actual == null && expected == null) && !actual.Equals(expected)) + { + Console.WriteLine("Not equal!"); + Console.WriteLine("actual = " + actual.ToString()); + Console.WriteLine("expected = " + expected.ToString()); + HasAssertFired = true; + } + } +} diff --git a/tests/src/readytorun/tests/generics.csproj b/tests/src/readytorun/tests/generics.csproj new file mode 100644 index 0000000000..4ea64b30d6 --- /dev/null +++ b/tests/src/readytorun/tests/generics.csproj @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>generics</AssemblyName> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <OutputType>Exe</OutputType> + <CLRTestKind>BuildAndRun</CLRTestKind> + <CLRTestPriority>0</CLRTestPriority> + </PropertyGroup> + + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + + <ItemGroup> + <Compile Include="generics.cs" /> + </ItemGroup> + + + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/readytorun/tests/genericsload/callgenericctor.cs b/tests/src/readytorun/tests/genericsload/callgenericctor.cs new file mode 100644 index 0000000000..05e16afb3b --- /dev/null +++ b/tests/src/readytorun/tests/genericsload/callgenericctor.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.Runtime.CompilerServices; + +class Foo<T> +{ + [MethodImplAttribute(MethodImplOptions.NoInlining)] + internal void M() + { + new GenClass<T>(); + } +} + +class Program +{ + static int Main() + { + try + { + new Foo<string>().M(); + } + catch (Exception e) + { + Console.WriteLine("FAIL"); + return 101; + } + + Console.WriteLine("PASS"); + return 100; + } +} diff --git a/tests/src/readytorun/tests/genericsload/callgenericctor.csproj b/tests/src/readytorun/tests/genericsload/callgenericctor.csproj new file mode 100644 index 0000000000..0f73092f43 --- /dev/null +++ b/tests/src/readytorun/tests/genericsload/callgenericctor.csproj @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{7DECC55A-B584-4456-83BA-6C42A5B3B3CB}</ProjectGuid> + <OutputType>exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>BuildAndRun</CLRTestKind> + <DefineConstants>$(DefineConstants);STATIC;CORECLR</DefineConstants> + <ZapRequire>1</ZapRequire> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="genericslib.ilproj"> + <Project>{F74F55A1-DFCF-4C7C-B462-E96E1D0BB667}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Compile Include="callgenericctor.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <PropertyGroup> + <CLRTestBatchPreCommands><![CDATA[ +$(CLRTestBatchPreCommands) +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out genericslib.ni.dll genericslib.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out callgenericctor.ni.exe callgenericctor.exe +]]></CLRTestBatchPreCommands> + <BashCLRTestPreCommands><![CDATA[ +$(BashCLRTestPreCommands) +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out genericslib.ni.dll genericslib.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out callgenericctor.ni.exe callgenericctor.exe +]]></BashCLRTestPreCommands> + </PropertyGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/readytorun/tests/genericsload/genericslib.il b/tests/src/readytorun/tests/genericsload/genericslib.il new file mode 100644 index 0000000000..fdc2f408a3 --- /dev/null +++ b/tests/src/readytorun/tests/genericsload/genericslib.il @@ -0,0 +1,58 @@ +// 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 genericslib { } +.module genericslib.dll + +.assembly extern mscorlib { } + +// A module constructor that sets GenClass`1<string>::StaticField to true. +.method assembly specialname rtspecialname static + void .cctor() cil managed +{ + ldc.i4.1 + stsfld bool class GenClass`1<string>::StaticField + ret +} + +.class public auto ansi beforefieldinit GenClass`1<T> + extends [mscorlib]System.Object +{ + .field static public bool StaticField + + /* + public GenClass() + { + if (!StaticField) + throw new System.Exception(); + } + */ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + + ldsfld bool class GenClass`1<!T>::StaticField + brtrue.s OK + + newobj instance void [mscorlib]System.Exception::.ctor() + throw + + OK: ret + } + + /* + public static bool StaticMethod() + { + return StaticField; + } + */ + .method public hidebysig static bool StaticMethod() cil managed + { + ldsfld bool class GenClass`1<!T>::StaticField + ret + } +} diff --git a/tests/src/readytorun/tests/genericsload/genericslib.ilproj b/tests/src/readytorun/tests/genericsload/genericslib.ilproj new file mode 100644 index 0000000000..04548543af --- /dev/null +++ b/tests/src/readytorun/tests/genericsload/genericslib.ilproj @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>$(MSBuildProjectName)</AssemblyName> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>library</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>SharedLibrary</CLRTestKind> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + + </PropertyGroup> + <ItemGroup> + <Compile Include="genericslib.il" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project> diff --git a/tests/src/readytorun/tests/genericsload/usegenericfield.cs b/tests/src/readytorun/tests/genericsload/usegenericfield.cs new file mode 100644 index 0000000000..770334c6cf --- /dev/null +++ b/tests/src/readytorun/tests/genericsload/usegenericfield.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 System.Runtime.CompilerServices; + +class Foo<T> +{ + [MethodImplAttribute(MethodImplOptions.NoInlining)] + internal bool M() + { + return GenClass<T>.StaticField; + } +} + +class Program +{ + static int Main() + { + try + { + if (!new Foo<string>().M()) + { + Console.WriteLine("FAIL - bad result"); + return 102; + } + } + catch (Exception e) + { + Console.WriteLine("FAIL - exception caught"); + return 101; + } + + Console.WriteLine("PASS"); + return 100; + } +} diff --git a/tests/src/readytorun/tests/genericsload/usegenericfield.csproj b/tests/src/readytorun/tests/genericsload/usegenericfield.csproj new file mode 100644 index 0000000000..6b9e15a733 --- /dev/null +++ b/tests/src/readytorun/tests/genericsload/usegenericfield.csproj @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{7DECC55A-B584-4456-83BA-6C42A5B3B3CB}</ProjectGuid> + <OutputType>exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>BuildAndRun</CLRTestKind> + <DefineConstants>$(DefineConstants);STATIC;CORECLR</DefineConstants> + <ZapRequire>1</ZapRequire> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="genericslib.ilproj"> + <Project>{F74F55A1-DFCF-4C7C-B462-E96E1D0BB667}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Compile Include="usegenericfield.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <PropertyGroup> + <CLRTestBatchPreCommands><![CDATA[ +$(CLRTestBatchPreCommands) +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out genericslib.ni.dll genericslib.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out usegenericfield.ni.exe usegenericfield.exe +]]></CLRTestBatchPreCommands> + <BashCLRTestPreCommands><![CDATA[ +$(BashCLRTestPreCommands) +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out genericslib.ni.dll genericslib.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out usegenericfield.ni.exe usegenericfield.exe +]]></BashCLRTestPreCommands> + </PropertyGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/readytorun/tests/main.cs b/tests/src/readytorun/tests/main.cs new file mode 100644 index 0000000000..783c1fd3cb --- /dev/null +++ b/tests/src/readytorun/tests/main.cs @@ -0,0 +1,494 @@ +// 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.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +#if CORECLR +using System.Runtime.Loader; +#endif +using System.Reflection; +using System.IO; + +class InstanceFieldTest : MyClass +{ + public int Value; +} + +class InstanceFieldTest2 : InstanceFieldTest +{ + public int Value2; +} + +[StructLayout(LayoutKind.Sequential)] +class InstanceFieldTestWithLayout : MyClassWithLayout +{ + public int Value; +} + +class GrowingBase +{ + MyGrowingStruct s; +} + +class InheritingFromGrowingBase : GrowingBase +{ + public int x; +} + + +static class OpenClosedDelegateExtension +{ + public static string OpenClosedDelegateTarget(this string x, string foo) + { + return x + ", " + foo; + } +} + +class Program +{ + static void TestVirtualMethodCalls() + { + var o = new MyClass(); + Assert.AreEqual(o.VirtualMethod(), "Virtual method result"); + + var iface = (IMyInterface)o; + Assert.AreEqual(iface.InterfaceMethod(" "), "Interface result"); + Assert.AreEqual(MyClass.TestInterfaceMethod(iface, "+"), "Interface+result"); + } + + static void TestMovedVirtualMethods() + { + var o = new MyChildClass(); + + Assert.AreEqual(o.MovedToBaseClass(), "MovedToBaseClass"); + Assert.AreEqual(o.ChangedToVirtual(), "ChangedToVirtual"); + + if (!LLILCJitEnabled) + { + o = null; + + try + { + o.MovedToBaseClass(); + } + catch (NullReferenceException) + { + try + { + o.ChangedToVirtual(); + } + catch (NullReferenceException) + { + return; + } + } + + Assert.AreEqual("NullReferenceException", "thrown"); + } + } + + + static void TestConstrainedMethodCalls() + { + using (MyStruct s = new MyStruct()) + { + ((Object)s).ToString(); + } + + // Enum.GetHashCode optimization requires special treatment + // in native signature encoding + MyEnum e = MyEnum.Apple; + e.GetHashCode(); + } + + static void TestConstrainedMethodCalls_Unsupported() + { + MyStruct s = new MyStruct(); + s.ToString(); + } + + static void TestInterop() + { + // Verify both intra-module and inter-module PInvoke interop + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + MyClass.GetTickCount(); + } + else + { + MyClass.GetCurrentThreadId(); + } + + MyClass.TestInterop(); + } + + static void TestStaticFields() + { + MyClass.StaticObjectField = 894; + MyClass.StaticLongField = 4392854; + MyClass.StaticNullableGuidField = new Guid("0D7E505F-E767-4FEF-AEEC-3243A3005673"); + MyClass.ThreadStaticStringField = "Hello"; + MyClass.ThreadStaticIntField = 735; + MyClass.ThreadStaticDateTimeField = new DateTime(2011, 1, 1); + + MyClass.TestStaticFields(); + +#if false // TODO: Enable once LDFTN is supported + Task.Run(() => { + MyClass.ThreadStaticStringField = "Garbage"; + MyClass.ThreadStaticIntField = 0xBAAD; + MyClass.ThreadStaticDateTimeField = DateTime.Now; + }).Wait(); +#endif + + Assert.AreEqual(MyClass.StaticObjectField, 894 + 12345678 /* + 1234 */); + Assert.AreEqual(MyClass.StaticLongField, (long)(4392854 * 456 /* * 45 */)); + Assert.AreEqual(MyClass.StaticNullableGuidField, null); + Assert.AreEqual(MyClass.ThreadStaticStringField, "HelloWorld"); + Assert.AreEqual(MyClass.ThreadStaticIntField, 735/78); + Assert.AreEqual(MyClass.ThreadStaticDateTimeField, new DateTime(2011, 1, 1) + new TimeSpan(123)); + } + + static void TestPreInitializedArray() + { + var a = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; + + int sum = 0; + foreach (var e in a) sum += e; + Assert.AreEqual(sum, 1023); + } + + static void TestMultiDimmArray() + { + var a = new int[2,3,4]; + a[0,1,2] = a[0,0,0] + a[1,1,1]; + a.ToString(); + } + + static void TestGenericVirtualMethod() + { + var o = new MyGeneric<String, Object>(); + Assert.AreEqual(o.GenericVirtualMethod<Program, IEnumerable<String>>(), + "System.StringSystem.ObjectProgramSystem.Collections.Generic.IEnumerable`1[System.String]"); + } + + static void TestMovedGenericVirtualMethod() + { + var o = new MyChildGeneric<Object>(); + + Assert.AreEqual(o.MovedToBaseClass<WeakReference>(), typeof(List<WeakReference>).ToString()); + Assert.AreEqual(o.ChangedToVirtual<WeakReference>(), typeof(List<WeakReference>).ToString()); + + if (!LLILCJitEnabled) + { + o = null; + + try + { + o.MovedToBaseClass<WeakReference>(); + } + catch (NullReferenceException) + { + try + { + o.ChangedToVirtual<WeakReference>(); + } + catch (NullReferenceException) + { + return; + } + } + + Assert.AreEqual("NullReferenceException", "thrown"); + } + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestGenericNonVirtualMethod() + { + var c = new MyChildGeneric<string>(); + Assert.AreEqual(CallGeneric(c), "MyGeneric.NonVirtualMethod"); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static string CallGeneric<T>(MyGeneric<T, T> g) + { + return g.NonVirtualMethod(); + } + + static void TestGenericOverStruct() + { + var o1 = new MyGeneric<String, MyGrowingStruct>(); + Assert.AreEqual(o1.GenericVirtualMethod < MyChangingStruct, IEnumerable<Program>>(), + "System.StringMyGrowingStructMyChangingStructSystem.Collections.Generic.IEnumerable`1[Program]"); + + var o2 = new MyChildGeneric<MyChangingStruct>(); + Assert.AreEqual(o2.MovedToBaseClass<MyGrowingStruct>(), typeof(List<MyGrowingStruct>).ToString()); + Assert.AreEqual(o2.ChangedToVirtual<MyGrowingStruct>(), typeof(List<MyGrowingStruct>).ToString()); + } + + static void TestInstanceFields() + { + var t = new InstanceFieldTest2(); + t.Value = 123; + t.Value2 = 234; + t.InstanceField = 345; + + Assert.AreEqual(typeof(InstanceFieldTest).GetRuntimeField("Value").GetValue(t), 123); + Assert.AreEqual(typeof(InstanceFieldTest2).GetRuntimeField("Value2").GetValue(t), 234); + Assert.AreEqual(typeof(MyClass).GetRuntimeField("InstanceField").GetValue(t), 345); + } + + static void TestInstanceFieldsWithLayout() + { + var t = new InstanceFieldTestWithLayout(); + t.Value = 123; + + Assert.AreEqual(typeof(InstanceFieldTestWithLayout).GetRuntimeField("Value").GetValue(t), 123); + } + + static void TestInheritingFromGrowingBase() + { + var o = new InheritingFromGrowingBase(); + o.x = 6780; + Assert.AreEqual(typeof(InheritingFromGrowingBase).GetRuntimeField("x").GetValue(o), 6780); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestGrowingStruct() + { + MyGrowingStruct s = MyGrowingStruct.Construct(); + MyGrowingStruct.Check(ref s); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestChangingStruct() + { + MyChangingStruct s = MyChangingStruct.Construct(); + s.x++; + MyChangingStruct.Check(ref s); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestChangingHFAStruct() + { + MyChangingHFAStruct s = MyChangingHFAStruct.Construct(); + MyChangingHFAStruct.Check(s); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestGetType() + { + new MyClass().GetType().ToString(); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestStaticBaseCSE() + { + // There should be just one call to CORINFO_HELP_READYTORUN_STATIC_BASE + // in the generated code. + s++; + s++; + Assert.AreEqual(s, 2); + s = 0; + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestIsInstCSE() + { + // There should be just one call to CORINFO_HELP_READYTORUN_ISINSTANCEOF + // in the generated code. + object o1 = (s < 1) ? (object)"foo" : (object)1; + Assert.AreEqual(o1 is string, true); + Assert.AreEqual(o1 is string, true); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestCastClassCSE() + { + // There should be just one call to CORINFO_HELP_READYTORUN_CHKCAST + // in the generated code. + object o1 = (s < 1) ? (object)"foo" : (object)1; + string str1 = (string)o1; + string str2 = (string)o1; + Assert.AreEqual(str1, str2); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestRangeCheckElimination() + { + // Range checks for array accesses should be eliminated by the compiler. + int[] array = new int[5]; + array[2] = 2; + Assert.AreEqual(array[2], 2); + } + +#if CORECLR + class MyLoadContext : AssemblyLoadContext + { + public MyLoadContext() + { + } + + public void TestMultipleLoads() + { + Assembly a = LoadFromAssemblyPath(Path.Combine(Directory.GetCurrentDirectory(), "test.ni.dll")); + Assert.AreEqual(AssemblyLoadContext.GetLoadContext(a), this); + } + + protected override Assembly Load(AssemblyName an) + { + throw new NotImplementedException(); + } + } + + static void TestMultipleLoads() + { + if (!LLILCJitEnabled) { + // Runtime should be able to load the same R2R image in another load context, + // even though it will be treated as an IL-only image. + new MyLoadContext().TestMultipleLoads(); + } + } +#endif + + static void TestFieldLayoutNGenMixAndMatch() + { + // This test is verifying consistent field layout when ReadyToRun images are combined with NGen images + // "ngen install /nodependencies main.exe" to exercise the interesting case + var o = new ByteChildClass(67); + Assert.AreEqual(o.ChildByte, (byte)67); + } + + static void TestOpenClosedDelegate() + { + // This test is verifying the the fixups for open vs. closed delegate created against the same target + // method are encoded correctly. + + Func<string, string, object> idOpen = OpenClosedDelegateExtension.OpenClosedDelegateTarget; + Assert.AreEqual(idOpen("World", "foo"), "World, foo"); + + Func<string, object> idClosed = "World".OpenClosedDelegateTarget; + Assert.AreEqual(idClosed("hey"), "World, hey"); + } + + static void GenericLdtokenFieldsTest() + { + Func<FieldInfo, string> FieldFullName = (fi) => fi.FieldType + " " + fi.DeclaringType.ToString() + "::" + fi.Name; + + IFieldGetter getter1 = new FieldGetter<string>(); + IFieldGetter getter2 = new FieldGetter<object>(); + IFieldGetter getter3 = new FieldGetter<int>(); + + foreach (var instArg in new Type[]{typeof(String), typeof(object), typeof(int)}) + { + IFieldGetter getter = (IFieldGetter)Activator.CreateInstance(typeof(FieldGetter<>).MakeGenericType(instArg)); + + string expectedField1 = "System.Int32 Gen`1[???]::m_Field1".Replace("???", instArg.ToString()); + string expectedField2 = "System.String Gen`1[???]::m_Field2".Replace("???", instArg.ToString()); + string expectedField3 = "??? Gen`1[???]::m_Field3".Replace("???", instArg.ToString()); + string expectedField4 = "System.Collections.Generic.List`1[???] Gen`1[???]::m_Field4".Replace("???", instArg.ToString()); + string expectedField5 = "System.Collections.Generic.KeyValuePair`2[???,System.Int32] Gen`1[???]::m_Field5".Replace("???", instArg.ToString()); + + string expectedDllField1 = "System.String MyGeneric`2[???,???]::m_Field1".Replace("???", instArg.ToString()); + string expectedDllField2 = "??? MyGeneric`2[???,???]::m_Field2".Replace("???", instArg.ToString()); + string expectedDllField3 = "System.Collections.Generic.List`1[???] MyGeneric`2[???,???]::m_Field3".Replace("???", instArg.ToString()); + string expectedDllField4 = "System.Collections.Generic.KeyValuePair`2[???,System.Int32] MyGeneric`2[???,???]::m_Field4".Replace("???", instArg.ToString()); + string expectedDllField5 = "System.Int32 MyGeneric`2[???,???]::m_Field5".Replace("???", instArg.ToString()); + + Assert.AreEqual(expectedField1, FieldFullName(getter.GetGenT_Field1())); + Assert.AreEqual(expectedField2, FieldFullName(getter.GetGenT_Field2())); + Assert.AreEqual(expectedField3, FieldFullName(getter.GetGenT_Field3())); + Assert.AreEqual(expectedField4, FieldFullName(getter.GetGenT_Field4())); + Assert.AreEqual(expectedField5, FieldFullName(getter.GetGenT_Field5())); + + Assert.AreEqual(expectedDllField1, FieldFullName(getter.GetGenDllT_Field1())); + Assert.AreEqual(expectedDllField2, FieldFullName(getter.GetGenDllT_Field2())); + Assert.AreEqual(expectedDllField3, FieldFullName(getter.GetGenDllT_Field3())); + Assert.AreEqual(expectedDllField4, FieldFullName(getter.GetGenDllT_Field4())); + Assert.AreEqual(expectedDllField5, FieldFullName(getter.GetGenDllT_Field5())); + } + } + + static void RunAllTests() + { + TestVirtualMethodCalls(); + TestMovedVirtualMethods(); + + TestConstrainedMethodCalls(); + + TestConstrainedMethodCalls_Unsupported(); + + TestInterop(); + + TestStaticFields(); + + TestPreInitializedArray(); + + TestMultiDimmArray(); + + TestGenericVirtualMethod(); + TestMovedGenericVirtualMethod(); + TestGenericNonVirtualMethod(); + + TestGenericOverStruct(); + + TestInstanceFields(); + + TestInstanceFieldsWithLayout(); + + TestInheritingFromGrowingBase(); + + TestGrowingStruct(); + TestChangingStruct(); + TestChangingHFAStruct(); + + TestGetType(); + +#if CORECLR + TestMultipleLoads(); +#endif + + TestFieldLayoutNGenMixAndMatch(); + + TestStaticBaseCSE(); + + TestIsInstCSE(); + + TestCastClassCSE(); + + TestRangeCheckElimination(); + + TestOpenClosedDelegate(); + + GenericLdtokenFieldsTest(); + } + + static int Main() + { + // Code compiled by LLILC jit can't catch exceptions yet so the tests + // don't throw them if LLILC jit is enabled. This should be removed once + // exception catching is supported by LLILC jit. + string AltJitName = System.Environment.GetEnvironmentVariable("complus_altjitname"); + LLILCJitEnabled = + ((AltJitName != null) && AltJitName.ToLower().StartsWith("llilcjit") && + ((System.Environment.GetEnvironmentVariable("complus_altjit") != null) || + (System.Environment.GetEnvironmentVariable("complus_altjitngen") != null))); + + // Run all tests 3x times to exercise both slow and fast paths work + for (int i = 0; i < 3; i++) + RunAllTests(); + + Console.WriteLine("PASSED"); + return Assert.HasAssertFired ? 1 : 100; + } + + static bool LLILCJitEnabled; + + static int s; +} diff --git a/tests/src/readytorun/tests/mainv1.csproj b/tests/src/readytorun/tests/mainv1.csproj new file mode 100644 index 0000000000..cca0b4106b --- /dev/null +++ b/tests/src/readytorun/tests/mainv1.csproj @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{7DECC55A-B584-4456-83BA-6C42A5B3B3CB}</ProjectGuid> + <OutputType>exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>BuildAndRun</CLRTestKind> + <DefineConstants>$(DefineConstants);STATIC;CORECLR</DefineConstants> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="fieldgetter.ilproj" /> + <ProjectReference Include="testv1\test.csproj"> + <Project>{F74F55A1-DFCF-4C7C-B462-E96E1D0BB667}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Compile Include="main.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <PropertyGroup> + <CLRTestBatchPreCommands><![CDATA[ +$(CLRTestBatchPreCommands) +DEL test.dll +COPY /Y ..\testv1\test\test.dll test.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv1.ni.exe mainv1.exe +]]></CLRTestBatchPreCommands> + <BashCLRTestPreCommands><![CDATA[ +$(BashCLRTestPreCommands) +rm -f test.dll +cp ../testv1/test/test.dll test.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv1.ni.exe mainv1.exe +]]></BashCLRTestPreCommands> + </PropertyGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/readytorun/tests/mainv2.csproj b/tests/src/readytorun/tests/mainv2.csproj new file mode 100644 index 0000000000..acf898e7f9 --- /dev/null +++ b/tests/src/readytorun/tests/mainv2.csproj @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{840300BB-0DD2-4BD3-A3C1-51C92DD4ADAD}</ProjectGuid> + <OutputType>exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <DefineConstants>$(DefineConstants);STATIC;CORECLR</DefineConstants> + <CLRTestKind>BuildAndRun</CLRTestKind> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="fieldgetter.ilproj" /> + <ProjectReference Include="testv1\test.csproj" /> + </ItemGroup> + <ItemGroup> + <Compile Include="main.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <PropertyGroup> + <CLRTestBatchPreCommands><![CDATA[ +$(CLRTestBatchPreCommands) +DEL test.dll +COPY /Y ..\testv1\test\test.dll test.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv2.ni.exe mainv2.exe +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll +DEL test.dll +COPY /Y ..\testv2\test\test.dll test.dll +%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll +]]></CLRTestBatchPreCommands> + <BashCLRTestPreCommands><![CDATA[ +$(BashCLRTestPreCommands) +rm -f test.dll +cp ../testv1/test/test.dll test.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv2.ni.exe mainv2.exe +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll +rm -f test.dll +cp ../testv2/test/test.dll test.dll +$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll + +]]></BashCLRTestPreCommands> + </PropertyGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/readytorun/tests/test.cs b/tests/src/readytorun/tests/test.cs new file mode 100644 index 0000000000..8a6beaea15 --- /dev/null +++ b/tests/src/readytorun/tests/test.cs @@ -0,0 +1,412 @@ +// 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; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +public static class Assert +{ + public static bool HasAssertFired; + + public static void AreEqual(Object actual, Object expected) + { + if (!(actual == null && expected == null) && !actual.Equals(expected)) + { + Console.WriteLine("Not equal!"); + Console.WriteLine("actual = " + actual.ToString()); + Console.WriteLine("expected = " + expected.ToString()); + HasAssertFired = true; + } + } +} + +public interface IMyInterface +{ +#if V2 + // Adding new methods to interfaces is incompatible change, but we will make sure that it works anyway + void NewInterfaceMethod(); +#endif + + string InterfaceMethod(string s); +} + +public class MyClass : IMyInterface +{ +#if V2 + public int _field1; + public int _field2; + public int _field3; +#endif + public int InstanceField; + +#if V2 + public static Object StaticObjectField2; + + [ThreadStatic] public static String ThreadStaticStringField2; + + [ThreadStatic] public static int ThreadStaticIntField; + + public static Nullable<Guid> StaticNullableGuidField; + + public static Object StaticObjectField; + + [ThreadStatic] public static int ThreadStaticIntField2; + + public static long StaticLongField; + + [ThreadStatic] public static DateTime ThreadStaticDateTimeField2; + + public static long StaticLongField2; + + [ThreadStatic] public static DateTime ThreadStaticDateTimeField; + + public static Nullable<Guid> StaticNullableGuidField2; + + [ThreadStatic] public static String ThreadStaticStringField; +#else + public static Object StaticObjectField; + + public static long StaticLongField; + + public static Nullable<Guid> StaticNullableGuidField; + + [ThreadStatic] public static String ThreadStaticStringField; + + [ThreadStatic] public static int ThreadStaticIntField; + + [ThreadStatic] public static DateTime ThreadStaticDateTimeField; +#endif + + public MyClass() + { + } + +#if V2 + public virtual void NewVirtualMethod() + { + } + + public virtual void NewInterfaceMethod() + { + throw new Exception(); + } +#endif + + public virtual string VirtualMethod() + { + return "Virtual method result"; + } + + public virtual string InterfaceMethod(string s) + { + return "Interface" + s + "result"; + } + + public static string TestInterfaceMethod(IMyInterface i, string s) + { + return i.InterfaceMethod(s); + } + + public static void TestStaticFields() + { + StaticObjectField = (int)StaticObjectField + 12345678; + + StaticLongField *= 456; + + Assert.AreEqual(StaticNullableGuidField, new Guid("0D7E505F-E767-4FEF-AEEC-3243A3005673")); + StaticNullableGuidField = null; + + ThreadStaticStringField += "World"; + + ThreadStaticIntField /= 78; + + ThreadStaticDateTimeField = ThreadStaticDateTimeField + new TimeSpan(123); + + MyGeneric<int,int>.ThreadStatic = new Object(); + +#if false // TODO: Enable once LDFTN is supported + // Do some operations on static fields on a different thread to verify that we are not mixing thread-static and non-static + Task.Run(() => { + + StaticObjectField = (int)StaticObjectField + 1234; + + StaticLongField *= 45; + + ThreadStaticStringField = "Garbage"; + + ThreadStaticIntField = 0xBAAD; + + ThreadStaticDateTimeField = DateTime.Now; + + }).Wait(); +#endif + } + + [DllImport("api-ms-win-core-sysinfo-l1-1-0.dll")] + public extern static int GetTickCount(); + + [DllImport("libcoreclr")] + public extern static int GetCurrentThreadId(); + + static public void TestInterop() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + GetTickCount(); + } + else + { + GetCurrentThreadId(); + } + } + +#if V2 + public string MovedToBaseClass() + { + return "MovedToBaseClass"; + } +#endif + +#if V2 + public virtual string ChangedToVirtual() + { + return null; + } +#else + public string ChangedToVirtual() + { + return "ChangedToVirtual"; + } +#endif + +} + +public class MyChildClass : MyClass +{ + public MyChildClass() + { + } + +#if !V2 + public string MovedToBaseClass() + { + return "MovedToBaseClass"; + } +#endif + +#if V2 + public override string ChangedToVirtual() + { + return "ChangedToVirtual"; + } +#endif +} + + +public struct MyStruct : IDisposable +{ + int x; + +#if V2 + void IDisposable.Dispose() + { + } +#else + public void Dispose() + { + } +#endif +} + +public class MyGeneric<T,U> +{ +#if V2 + public object m_unused1; + public string m_Field1; + + public object m_unused2; + public T m_Field2; + + public object m_unused3; + public List<T> m_Field3; + + static public object m_unused4; + static public KeyValuePair<T, int> m_Field4; + + static public object m_unused5; + static public int m_Field5; + + public object m_unused6; + static public object m_unused7; +#else + public string m_Field1; + public T m_Field2; + public List<T> m_Field3; + static public KeyValuePair<T, int> m_Field4; + static public int m_Field5; +#endif + + [ThreadStatic] public static Object ThreadStatic; + + public MyGeneric() + { + } + + public virtual string GenericVirtualMethod<V,W>() + { + return typeof(T).ToString() + typeof(U).ToString() + typeof(V).ToString() + typeof(W).ToString(); + } + +#if V2 + public string MovedToBaseClass<W>() + { + typeof(Dictionary<W,W>).ToString(); + return typeof(List<W>).ToString(); + } +#endif + +#if V2 + public virtual string ChangedToVirtual<W>() + { + return null; + } +#else + public string ChangedToVirtual<W>() + { + return typeof(List<W>).ToString(); + } +#endif + + public string NonVirtualMethod() + { + return "MyGeneric.NonVirtualMethod"; + } +} + +public class MyChildGeneric<T> : MyGeneric<T,T> +{ + public MyChildGeneric() + { + } + +#if !V2 + public string MovedToBaseClass<W>() + { + return typeof(List<W>).ToString(); + } +#endif + +#if V2 + public override string ChangedToVirtual<W>() + { + typeof(Dictionary<Int32, W>).ToString(); + return typeof(List<W>).ToString(); + } +#endif +} + +[StructLayout(LayoutKind.Sequential)] +public class MyClassWithLayout +{ +#if V2 + public int _field1; + public int _field2; + public int _field3; +#endif +} + +public struct MyGrowingStruct +{ + int x; + int y; +#if V2 + Object o1; + Object o2; +#endif + + static public MyGrowingStruct Construct() + { + return new MyGrowingStruct() { x = 111, y = 222 }; + } + + public static void Check(ref MyGrowingStruct s) + { + Assert.AreEqual(s.x, 111); + Assert.AreEqual(s.y, 222); + } +} + +public struct MyChangingStruct +{ +#if V2 + public int y; + public int x; +#else + public int x; + public int y; +#endif + + static public MyChangingStruct Construct() + { + return new MyChangingStruct() { x = 111, y = 222 }; + } + + public static void Check(ref MyChangingStruct s) + { + Assert.AreEqual(s.x, 112); + Assert.AreEqual(s.y, 222); + } +} + +public struct MyChangingHFAStruct +{ +#if V2 + float x; + float y; +#else + int x; + int y; +#endif + static public MyChangingHFAStruct Construct() + { + return new MyChangingHFAStruct() { x = 12, y = 23 }; + } + + public static void Check(MyChangingHFAStruct s) + { +#if V2 + Assert.AreEqual(s.x, 12.0f); + Assert.AreEqual(s.y, 23.0f); +#else + Assert.AreEqual(s.x, 12); + Assert.AreEqual(s.y, 23); +#endif + } +} + +public class ByteBaseClass : List<byte> +{ + public byte BaseByte; +} +public class ByteChildClass : ByteBaseClass +{ + public byte ChildByte; + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public ByteChildClass(byte value) + { + ChildByte = 67; + } +} + +public enum MyEnum +{ + Apple = 1, + Banana = 2, + Orange = 3 +} diff --git a/tests/src/readytorun/tests/testv1/test.csproj b/tests/src/readytorun/tests/testv1/test.csproj new file mode 100644 index 0000000000..c56c53cad9 --- /dev/null +++ b/tests/src/readytorun/tests/testv1/test.csproj @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{F74F55A1-DFCF-4C7C-B462-E96E1D0BB667}</ProjectGuid> + <OutputType>library</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\..\</SolutionDir> + <DefineConstants>$(DefineConstants);STATIC;CORECLR</DefineConstants> + <CLRTestKind>SharedLibrary</CLRTestKind> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="..\test.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file diff --git a/tests/src/readytorun/tests/testv2/test.csproj b/tests/src/readytorun/tests/testv2/test.csproj new file mode 100644 index 0000000000..058a0d6346 --- /dev/null +++ b/tests/src/readytorun/tests/testv2/test.csproj @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>library</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\..\</SolutionDir> + <DefineConstants>$(DefineConstants);STATIC;CORECLR;V2</DefineConstants> + <CLRTestKind>SharedLibrary</CLRTestKind> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="..\test.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> |