diff options
Diffstat (limited to 'tests/src/Simple/Reflection/Reflection.cs')
-rw-r--r-- | tests/src/Simple/Reflection/Reflection.cs | 367 |
1 files changed, 360 insertions, 7 deletions
diff --git a/tests/src/Simple/Reflection/Reflection.cs b/tests/src/Simple/Reflection/Reflection.cs index 322650a2c..86e47c39d 100644 --- a/tests/src/Simple/Reflection/Reflection.cs +++ b/tests/src/Simple/Reflection/Reflection.cs @@ -10,6 +10,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Reflection; [assembly: TestAssembly] @@ -43,6 +44,7 @@ internal class ReflectionTest TestCreateDelegate.Run(); TestInstanceFields.Run(); TestReflectionInvoke.Run(); + TestByRefReturnInvoke.Run(); return 100; } @@ -89,9 +91,34 @@ internal class ReflectionTest { return "Hello " + _world; } + +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] +#endif + public static unsafe string GetHelloPointer(char* ptr) + { + return "Hello " + unchecked((int)ptr); + } + +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] +#endif + public static unsafe string GetHelloPointerToo(char** ptr) + { + return "Hello " + unchecked((int)ptr); + } + +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] +#endif + public static unsafe bool* GetPointer(void* ptr, object dummyJustToMakeThisUseSharedThunk) + { + return (bool*)ptr; + } + } - public static void Run() + public static unsafe void Run() { Console.WriteLine(nameof(TestReflectionInvoke)); @@ -102,6 +129,9 @@ internal class ReflectionTest InvokeTests.GetHello(null); InvokeTests.GetHelloGeneric<int>(0); InvokeTests.GetHelloGeneric<double>(0); + InvokeTests.GetHelloPointer(null); + InvokeTests.GetHelloPointerToo(null); + InvokeTests.GetPointer(null, null); string unused; InvokeTests.GetHelloByRef(null, out unused); unused.ToString(); @@ -128,6 +158,31 @@ internal class ReflectionTest if ((string)args[1] != "Hello world") throw new Exception(); } + + { + MethodInfo helloPointerMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloPointer"); + string resultNull = (string)helloPointerMethod.Invoke(null, new object[] { null }); + if (resultNull != "Hello 0") + throw new Exception(); + + string resultVal = (string)helloPointerMethod.Invoke(null, new object[] { Pointer.Box((void*)42, typeof(char*)) }); + if (resultVal != "Hello 42") + throw new Exception(); + } + + { + MethodInfo helloPointerTooMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloPointerToo"); + string result = (string)helloPointerTooMethod.Invoke(null, new object[] { Pointer.Box((void*)85, typeof(char**)) }); + if (result != "Hello 85") + throw new Exception(); + } + + { + MethodInfo getPointerMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetPointer"); + object result = getPointerMethod.Invoke(null, new object[] { Pointer.Box((void*)2018, typeof(void*)), null }); + if (Pointer.Unbox(result) != (void*)2018) + throw new Exception(); + } } } @@ -384,7 +439,23 @@ internal class ReflectionTest } } + ref struct ByRefLike<T> + { + public readonly T Value; + + public ByRefLike(T value) + { + Value = value; + } + + public override string ToString() + { + return Value.ToString() + " " + typeof(T).ToString(); + } + } + delegate string ToStringDelegate(ref ByRefLike thisObj); + delegate string ToStringDelegate<T>(ref ByRefLike<T> thisObj); public static void Run() { @@ -396,15 +467,40 @@ internal class ReflectionTest default(ByRefLike).ToString(); ToStringDelegate s = null; s = s.Invoke; + default(ByRefLike<object>).ToString(); + ToStringDelegate<object> s2 = null; + s2 = s2.Invoke; } - Type byRefLikeType = GetTestType(nameof(TestByRefLikeTypeMethod), nameof(ByRefLike)); - MethodInfo toStringMethod = byRefLikeType.GetMethod("ToString"); - var toString = (ToStringDelegate)toStringMethod.CreateDelegate(typeof(ToStringDelegate)); + { + Type byRefLikeType = GetTestType(nameof(TestByRefLikeTypeMethod), nameof(ByRefLike)); + MethodInfo toStringMethod = byRefLikeType.GetMethod("ToString"); + var toString = (ToStringDelegate)toStringMethod.CreateDelegate(typeof(ToStringDelegate)); - ByRefLike foo = new ByRefLike(123); - if (toString(ref foo) != "123") - throw new Exception(); + ByRefLike foo = new ByRefLike(123); + if (toString(ref foo) != "123") + throw new Exception(); + } + + { + Type byRefLikeGenericType = typeof(ByRefLike<string>); + MethodInfo toStringGenericMethod = byRefLikeGenericType.GetMethod("ToString"); + var toStringGeneric = (ToStringDelegate<string>)toStringGenericMethod.CreateDelegate(typeof(ToStringDelegate<string>)); + + ByRefLike<string> fooGeneric = new ByRefLike<string>("Hello"); + if (toStringGeneric(ref fooGeneric) != "Hello System.String") + throw new Exception(); + } + + { + Type byRefLikeGenericType = typeof(ByRefLike<object>); + MethodInfo toStringGenericMethod = byRefLikeGenericType.GetMethod("ToString"); + var toStringGeneric = (ToStringDelegate<object>)toStringGenericMethod.CreateDelegate(typeof(ToStringDelegate<object>)); + + ByRefLike<object> fooGeneric = new ByRefLike<object>("Hello"); + if (toStringGeneric(ref fooGeneric) != "Hello System.Object") + throw new Exception(); + } } } @@ -501,6 +597,203 @@ internal class ReflectionTest } } + class TestByRefReturnInvoke + { + enum Mine { One = 2018 } + + [StructLayout(LayoutKind.Sequential)] + struct BigStruct { public ulong X, Y, Z, W, A, B, C, D; } + + public ref struct ByRefLike { } + + private sealed class TestClass<T> + { + private T _value; + + public TestClass(T value) { _value = value; } + public ref T RefReturningProp + { +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [MethodImpl(MethodImplOptions.NoInlining)] +#endif + get => ref _value; + } +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [MethodImpl(MethodImplOptions.NoInlining)] +#endif + public static unsafe ref ByRefLike ByRefLikeRefReturningMethod(ByRefLike* a) => ref *a; + } + + private sealed unsafe class TestClassIntPointer + { + private int* _value; + + public TestClassIntPointer(int* value) { _value = value; } + public ref int* RefReturningProp + { +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [MethodImpl(MethodImplOptions.NoInlining)] +#endif + get => ref _value; + } + public unsafe ref int* NullRefReturningProp + { +#if OPTIMIZED_MODE_WITHOUT_SCANNER + [MethodImpl(MethodImplOptions.NoInlining)] +#endif + get => ref *(int**)null; + } + } + + public static void TestRefReturnPropertyGetValue() + { + TestRefReturnInvoke('a', (p, t) => p.GetValue(t)); + TestRefReturnInvoke(Mine.One, (p, t) => p.GetValue(t)); + TestRefReturnInvoke("Hello", (p, t) => p.GetValue(t)); + TestRefReturnInvoke(new BigStruct { X = 123, D = 456 }, (p, t) => p.GetValue(t)); + TestRefReturnInvoke(new object(), (p, t) => p.GetValue(t)); + TestRefReturnInvoke((object)null, (p, t) => p.GetValue(t)); + } + + public static void TestRefReturnMethodInvoke() + { + TestRefReturnInvoke(Mine.One, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); + TestRefReturnInvoke("Hello", (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); + TestRefReturnInvoke(new BigStruct { X = 123, D = 456 }, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); + TestRefReturnInvoke(new object(), (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); + TestRefReturnInvoke((object)null, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); + } + + public static void TestRefReturnNullable() + { + TestRefReturnInvokeNullable<int>(42); + TestRefReturnInvokeNullable<Mine>(Mine.One); + TestRefReturnInvokeNullable<BigStruct>(new BigStruct { X = 987, D = 543 }); + } + + public static void TestRefReturnNullableNoValue() + { + TestRefReturnInvokeNullable<int>(default(int?)); + TestRefReturnInvokeNullable<Mine>(default(Mine?)); + TestRefReturnInvokeNullable<BigStruct>(default(BigStruct?)); + } + + public static unsafe void TestRefReturnOfPointer() + { + int* expected = (int*)0x1122334455667788; + TestClassIntPointer tc = new TestClassIntPointer(expected); + + if (string.Empty.Length > 0) + { + ((IntPtr)tc.RefReturningProp).ToString(); + } + + PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.RefReturningProp)); + object rv = p.GetValue(tc); + Assert.True(rv is Pointer); + int* actual = (int*)(Pointer.Unbox(rv)); + Assert.Equal((IntPtr)expected, (IntPtr)actual); + } + + public static unsafe void TestNullRefReturnOfPointer() + { + TestClassIntPointer tc = new TestClassIntPointer(null); + + if (string.Empty.Length > 0) + { + ((IntPtr)tc.NullRefReturningProp).ToString(); + } + + PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.NullRefReturningProp)); + Assert.NotNull(p); + Assert.Throws<NullReferenceException>(() => p.GetValue(tc)); + } + + public static unsafe void TestByRefLikeRefReturn() + { + if (string.Empty.Length > 0) + { + TestClass<int>.ByRefLikeRefReturningMethod(null); + } + + ByRefLike brl = new ByRefLike(); + ByRefLike* pBrl = &brl; + MethodInfo mi = typeof(TestClass<int>).GetMethod(nameof(TestClass<int>.ByRefLikeRefReturningMethod)); + try + { + // Don't use Assert.Throws because that will make a lambda and invalidate the pointer + object o = mi.Invoke(null, new object[] { Pointer.Box(pBrl, typeof(ByRefLike*)) }); + Assert.Fail(); + } + catch (NotSupportedException) + { + } + } + + private static void TestRefReturnInvoke<T>(T value, Func<PropertyInfo, TestClass<T>, object> invoker) + { + TestClass<T> tc = new TestClass<T>(value); + + if (String.Empty.Length > 0) + { + tc.RefReturningProp.ToString(); + } + + PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.RefReturningProp)); + object rv = invoker(p, tc); + if (rv != null) + { + Assert.Equal(typeof(T), rv.GetType()); + } + + if (typeof(T).IsValueType) + { + Assert.Equal(value, rv); + } + else + { + Assert.Same(value, rv); + } + } + + private static void TestRefReturnInvokeNullable<T>(T? nullable) where T : struct + { + TestClass<T?> tc = new TestClass<T?>(nullable); + + if (string.Empty.Length > 0) + { + tc.RefReturningProp.ToString(); + } + + PropertyInfo p = typeof(TestClass<T?>).GetProperty(nameof(TestClass<T?>.RefReturningProp)); + object rv = p.GetValue(tc); + if (rv != null) + { + Assert.Equal(typeof(T), rv.GetType()); + } + if (nullable.HasValue) + { + Assert.Equal(nullable.Value, rv); + } + else + { + Assert.Null(rv); + } + } + + public static void Run() + { + Console.WriteLine(nameof(TestByRefReturnInvoke)); + TestRefReturnPropertyGetValue(); + TestRefReturnMethodInvoke(); + TestRefReturnNullable(); + TestRefReturnNullableNoValue(); + TestRefReturnOfPointer(); + TestNullRefReturnOfPointer(); + TestByRefLikeRefReturn(); + } + } + #region Helpers private static Type GetTestType(string testName, string typeName) @@ -534,6 +827,66 @@ internal class ReflectionTest return true; } + class Assert + { + public static void Equal<T>(T expected, T actual) + { + if (object.ReferenceEquals(expected, actual)) + return; + + if ((object)expected == null || (object)actual == null) + throw new Exception(); + + if (!expected.Equals(actual)) + throw new Exception(); + } + + public static void Same<T>(T expected, T actual) + { + if (!object.ReferenceEquals(expected, actual)) + throw new Exception(); + } + + public static void Null(object x) + { + if (x != null) + throw new Exception(); + } + + public static void NotNull(object x) + { + if (x == null) + throw new Exception(); + } + + public static void True(bool x) + { + if (!x) + throw new Exception(); + } + + public static void Fail() + { + throw new Exception(); + } + + public static void Throws<T>(Action a) + { + try + { + a(); + } + catch (Exception ex) + { + if (ex.GetType() != typeof(T)) + throw new Exception(); + return; + } + + throw new Exception(); + } + } + #endregion } |