From 5d30e6da71ccd780d5d491ed064be351e52f29e5 Mon Sep 17 00:00:00 2001 From: Ivan Povazan <55002338+ivanpovazan@users.noreply.github.com> Date: Fri, 11 Aug 2023 17:23:53 +0200 Subject: [PATCH] [mono] Support function pointer reflection introspection API (#89712) Fixes https://github.com/dotnet/runtime/issues/71095 --- .../FunctionPointerCallingConventionTests.cs | 9 +- .../tests/System/FunctionPointerEqualityTests.cs | 6 +- .../Common/tests/System/FunctionPointerTests.cs | 8 -- .../Common/tests/System/ModifiedTypeTests.cs | 137 ++++++++++++++----- .../tests/System/TestILAssembly/TestILAssembly.il | 15 +++ .../tests/ILLink.Descriptors.xml | 1 + .../System.Runtime/tests/ILLink.Descriptors.xml | 1 + .../System.Runtime/tests/System/ActivatorTests.cs | 9 +- .../tests/System/Reflection/TypeDelegatorTests.cs | 1 - .../CompilerServices/RuntimeHelpersTests.cs | 8 +- .../System/Type/FunctionPointerTests.Runtime.cs | 8 +- .../System.Runtime/tests/System/Type/TypeTests.cs | 9 +- .../src/System/Reflection/ModifiedType.Mono.cs | 145 ++++++++++++++++++++- .../src/System/Reflection/RuntimeFieldInfo.cs | 6 +- .../src/System/Reflection/RuntimeParameterInfo.cs | 6 +- .../src/System/Reflection/RuntimePropertyInfo.cs | 6 +- .../src/System/RuntimeType.Mono.cs | 76 +++++++++++ src/mono/mono/metadata/class.c | 18 +++ src/mono/mono/metadata/icall-decl.h | 4 + src/mono/mono/metadata/icall-def.h | 10 +- src/mono/mono/metadata/icall.c | 89 +++++++++++-- 21 files changed, 470 insertions(+), 102 deletions(-) diff --git a/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs b/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs index 27da316..ac7ec95 100644 --- a/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs @@ -15,7 +15,6 @@ namespace System.Tests.Types [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void ManagedCallingConvention(bool modified) { Type t = typeof(FunctionPointerHolder).Project(); @@ -36,7 +35,6 @@ namespace System.Tests.Types [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Stdcall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Thiscall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void UnmanagedCallConv_Param_Unmodified(string methodName) { Type t = typeof(FunctionPointerHolder).Project(); @@ -54,7 +52,6 @@ namespace System.Tests.Types [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Stdcall), typeof(CallConvStdcall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Thiscall), typeof(CallConvThiscall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall), typeof(CallConvFastcall))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void UnmanagedCallConv_Param_Modified(string methodName, Type callingConventionRuntime) { Type callingConvention = callingConventionRuntime.Project(); @@ -71,7 +68,7 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/90308", TestRuntimes.Mono)] public static unsafe void UnmanagedCallConvs_Return_Unmodified() { Type t = typeof(FunctionPointerHolder).Project(); @@ -91,7 +88,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void UnmanagedCallConvs_Return_Modified() { Type t = typeof(FunctionPointerHolder).Project(); @@ -118,7 +114,6 @@ namespace System.Tests.Types [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Stdcall_SuppressGCTransition))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Thiscall_SuppressGCTransition))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall_SuppressGCTransition))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void UnmanagedCallConv_PhysicalModifiers_Unmodified(string methodName) { Type t = typeof(FunctionPointerHolder).Project(); @@ -137,7 +132,6 @@ namespace System.Tests.Types [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Stdcall_SuppressGCTransition), typeof(CallConvStdcall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Thiscall_SuppressGCTransition), typeof(CallConvThiscall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall_SuppressGCTransition), typeof(CallConvFastcall))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void UnmanagedCallConv_PhysicalModifiers_Modified(string methodName, Type callingConventionRuntime) { Type suppressGcTransitionType = typeof(CallConvSuppressGCTransition).Project(); @@ -161,7 +155,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void GenericTypeParameter() { Type holder = typeof(FunctionPointerHolder).Project(); diff --git a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs index 47cac32..c718b6f 100644 --- a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs @@ -15,7 +15,6 @@ namespace System.Tests.Types private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void DifferentReturnValue() { Type t = typeof(FunctionPointerHolder).Project(); @@ -31,7 +30,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void ObjectEquals_ModifiedTypes() { Type holder = typeof(FunctionPointerHolder).Project(); @@ -47,7 +45,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void ObjectEquals_OneSideModifiedType() { Type holder = typeof(FunctionPointerHolder).Project(); @@ -65,7 +62,7 @@ namespace System.Tests.Types [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Stdcall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Thiscall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Fastcall))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/90308", TestRuntimes.Mono)] public static unsafe void CallingConvention_Unmodified(string methodName1, string methodName2) { Type t = typeof(FunctionPointerHolder).Project(); @@ -83,7 +80,6 @@ namespace System.Tests.Types [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Stdcall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Thiscall))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Fastcall))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void CallingConvention_Modified(string methodName1, string methodName2) { Type t = typeof(FunctionPointerHolder).Project(); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index 66458be..925c868 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -14,7 +14,6 @@ namespace System.Tests.Types private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void TypeMembers() { // Get an arbitrary function pointer @@ -116,7 +115,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void NonFunctionPointerThrows() { Assert.Throws(() => typeof(int).GetFunctionPointerCallingConventions()); @@ -125,7 +123,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void TestToString() { // Function pointer types are inline in metadata and can't be loaded independently so they do not support the @@ -146,7 +143,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerReturn() { Type t = typeof(FunctionPointerHolder).Project(); @@ -163,7 +159,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void RequiredModifiers() { Type t = typeof(FunctionPointerHolder).Project(); @@ -188,7 +183,6 @@ namespace System.Tests.Types "Double", "System.Double(System.String, System.Boolean*&, System.Tests.Types.FunctionPointerTests+FunctionPointerHolder+MyClass, System.Tests.Types.FunctionPointerTests+FunctionPointerHolder+MyStruct&)", "String", "Boolean*&", "MyClass", "MyStruct&")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void MethodInfo( string methodName, string methodToStringPostfix, @@ -216,7 +210,6 @@ namespace System.Tests.Types [Theory] [InlineData(nameof(FunctionPointerHolder.Prop_Int), "System.Int32()")] [InlineData(nameof(FunctionPointerHolder.Prop_MyClass), "System.Tests.Types.FunctionPointerTests+FunctionPointerHolder+MyClass()")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Property(string name, string expectedToString) { Type t = typeof(FunctionPointerHolder).Project(); @@ -235,7 +228,6 @@ namespace System.Tests.Types [Theory] [InlineData(nameof(FunctionPointerHolder.Field_Int), "System.Int32()")] [InlineData(nameof(FunctionPointerHolder.Field_MyClass), "System.Tests.Types.FunctionPointerTests+FunctionPointerHolder+MyClass()")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Field(string name, string expectedToString) { Type t = typeof(FunctionPointerHolder).Project(); diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index c4298069..0175ddc 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -17,7 +17,6 @@ namespace System.Tests.Types private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void TypeMembers() { FieldInfo fi = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings); @@ -153,7 +152,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_Modified() { Type volatileInt = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings).GetModifiedFieldType(); @@ -191,7 +189,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_Generic_Unmodified() { Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; @@ -212,7 +209,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_Generic_Modified() { Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); @@ -235,7 +231,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Methods_OpenGeneric_Unmodified() { MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); @@ -258,7 +253,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Methods_OpenGeneric_Modified() { MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); @@ -283,7 +277,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_Unmodified() { Type volatileInt = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings).FieldType; @@ -315,7 +308,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_Parameterized_Basic() { Type ptr_ptr_int = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_ptr_int), Bindings).GetModifiedFieldType(); @@ -336,7 +328,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_Parameterized_FcnPtr() { Type ptr_fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_fcnPtr), Bindings).GetModifiedFieldType(); @@ -367,7 +358,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Fields_VerifyIdempotency() { // Call these again to ensure any backing caching strategy works. @@ -378,7 +368,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void MethodParameters() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_P0IntOut), Bindings).GetParameters(); @@ -402,7 +391,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void ConstructorParameters_Unmodified() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); @@ -415,7 +403,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void ConstructorParameters_Modified() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); @@ -429,7 +416,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtrP0Out_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).GetModifiedFieldType(); @@ -440,7 +426,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtrP0Out_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).FieldType; @@ -451,7 +436,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Out_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).FieldType; @@ -464,7 +448,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Out_Modified() { // Modified @@ -479,7 +462,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).FieldType; @@ -493,7 +475,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).GetModifiedFieldType(); @@ -507,7 +488,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrRetP0Out), Bindings).FieldType; @@ -518,7 +498,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrRetP0Out), Bindings).GetModifiedFieldType(); @@ -530,7 +509,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_complex_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_complex), Bindings).FieldType; @@ -554,7 +532,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void FunctionPointerParameters_fcnPtr_complex_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_complex), Bindings).GetModifiedFieldType(); @@ -579,7 +556,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Property_FcnPtr_Complex_Unmodified() { Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).PropertyType; @@ -596,7 +572,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void Property_FcnPtr_Complex_Modified() { Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).GetModifiedPropertyType(); @@ -614,15 +589,17 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - public static unsafe void MethodWithGenericParameter_Unmodified() + public static unsafe void MethodWithGenericParameterWithModifiers_Unmodified() { MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MethodWithGenericParameter), Bindings); Assert.False(mi.ContainsGenericParameters); Type a1 = mi.GetParameters()[0].ParameterType; Assert.False(IsModifiedType(a1)); - Assert.Equal(typeof(Tuple).Project(), a1.Project()); + + // https://github.com/dotnet/runtime/issues/90308" + if (!PlatformDetection.IsMonoRuntime) + Assert.Equal(typeof(Tuple).Project(), a1.Project()); Type ga1 = a1.GetGenericArguments()[0]; Assert.False(IsModifiedType(ga1)); @@ -635,15 +612,17 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - public static unsafe void MethodWithGenericParameter_Modified() + public static unsafe void MethodWithGenericParameterWithModifiers_Modified() { MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MethodWithGenericParameter), Bindings); Assert.False(mi.ContainsGenericParameters); Type a1 = mi.GetParameters()[0].GetModifiedParameterType(); Assert.True(IsModifiedType(a1)); - Assert.Equal(typeof(Tuple).Project(), a1.UnderlyingSystemType.Project()); + + // https://github.com/dotnet/runtime/issues/90308" + if (!PlatformDetection.IsMonoRuntime) + Assert.Equal(typeof(Tuple).Project(), a1.UnderlyingSystemType.Project()); Type ga1 = a1.GetGenericArguments()[0]; Assert.True(IsModifiedType(ga1)); @@ -658,7 +637,98 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + public static unsafe void GenericFieldWithModifiers_Unmodified() + { + FieldInfo fi = typeof(GenericWithModifiers).Project().GetField(nameof(GenericWithModifiers.GenericField), Bindings); + + Type ft = fi.FieldType; + Assert.False(IsModifiedType(ft)); + + // https://github.com/dotnet/runtime/issues/90308" + if (!PlatformDetection.IsMonoRuntime) + Assert.Equal(typeof(Tuple).Project(), ft.Project()); + + Type ga1 = ft.GetGenericArguments()[0]; + Assert.False(IsModifiedType(ga1)); + Assert.Equal(typeof(int).Project(), ga1); + + Type ga2 = ft.GetGenericArguments()[1]; + Assert.False(IsModifiedType(ga2)); + Assert.Equal(typeof(bool).Project(), ga2); + Assert.Equal(0, ga2.GetOptionalCustomModifiers().Length); + } + + [Fact] + public static unsafe void GenericFieldWithModifiers_Modified() + { + FieldInfo fi = typeof(GenericWithModifiers).Project().GetField(nameof(GenericWithModifiers.GenericField), Bindings); + + Type ft = fi.GetModifiedFieldType(); + Assert.True(IsModifiedType(ft)); + + // https://github.com/dotnet/runtime/issues/90308" + if (!PlatformDetection.IsMonoRuntime) + Assert.Equal(typeof(Tuple).Project(), ft.UnderlyingSystemType.Project()); + + Type ga1 = ft.GetGenericArguments()[0]; + Assert.True(IsModifiedType(ga1)); + Assert.Equal(typeof(int).Project(), ga1.UnderlyingSystemType); + Assert.Equal(0, ga1.GetOptionalCustomModifiers().Length); + + Type ga2 = ft.GetGenericArguments()[1]; + Assert.True(IsModifiedType(ga2)); + Assert.Equal(typeof(bool).Project(), ga2.UnderlyingSystemType); + Assert.Equal(1, ga2.GetOptionalCustomModifiers().Length); + Assert.Equal(typeof(IsConst).Project(), ga2.GetOptionalCustomModifiers()[0]); + } + + [Fact] + public static unsafe void GenericPropertyWithModifiers_Unmodified() + { + PropertyInfo pi = typeof(GenericWithModifiers).Project().GetProperty(nameof(GenericWithModifiers.GenericProperty), Bindings); + + Type pt = pi.PropertyType; + Assert.False(IsModifiedType(pt)); + + // https://github.com/dotnet/runtime/issues/90308" + if (!PlatformDetection.IsMonoRuntime) + Assert.Equal(typeof(Tuple).Project(), pt.Project()); + + Type ga1 = pt.GetGenericArguments()[0]; + Assert.False(IsModifiedType(ga1)); + Assert.Equal(typeof(int).Project(), ga1); + + Type ga2 = pt.GetGenericArguments()[1]; + Assert.False(IsModifiedType(ga2)); + Assert.Equal(typeof(bool).Project(), ga2); + Assert.Equal(0, ga2.GetOptionalCustomModifiers().Length); + } + + [Fact] + public static unsafe void GenericPropertyWithModifiers_Modified() + { + PropertyInfo pi = typeof(GenericWithModifiers).Project().GetProperty(nameof(GenericWithModifiers.GenericProperty), Bindings); + + Type pt = pi.GetModifiedPropertyType(); + Assert.True(IsModifiedType(pt)); + + // https://github.com/dotnet/runtime/issues/90308" + if (!PlatformDetection.IsMonoRuntime) + Assert.Equal(typeof(Tuple).Project(), pt.UnderlyingSystemType.Project()); + + Type ga1 = pt.GetGenericArguments()[0]; + Assert.True(IsModifiedType(ga1)); + Assert.Equal(typeof(int).Project(), ga1.UnderlyingSystemType); + Assert.Equal(0, ga1.GetOptionalCustomModifiers().Length); + + Type ga2 = pt.GetGenericArguments()[1]; + Assert.True(IsModifiedType(ga2)); + Assert.Equal(typeof(bool).Project(), ga2.UnderlyingSystemType); + Assert.Equal(1, ga2.GetOptionalCustomModifiers().Length); + Assert.Equal(typeof(IsConst).Project(), ga2.GetOptionalCustomModifiers()[0]); + } + + [Fact] public static unsafe void GenericMethod_Unmodified() { MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.GenericMethod), Bindings); @@ -671,7 +741,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static unsafe void GenericMethod_Modified() { MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.GenericMethod), Bindings); @@ -684,7 +753,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static void ParameterConstraints1() { MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_GenericWithParameterConstraint1), Bindings); @@ -709,7 +777,6 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public static void ParameterConstraints2() { MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_GenericWithParameterConstraint2), Bindings); diff --git a/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il b/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il index ca2582b..0d974c6 100644 --- a/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il +++ b/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il @@ -42,5 +42,20 @@ IL_0000: nop IL_0001: ret } + + .field public class [System.Runtime]System.Tuple`2 GenericField + + .method public hidebysig specialname instance class [System.Runtime]System.Tuple`2 get_GenericField () cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class [System.Runtime]System.Tuple`2 System.Tests.GenericWithModifiers::GenericField + IL_0006: ret + } + + .property instance class [System.Runtime]System.Tuple`2 GenericProperty() + { + .get instance class [System.Runtime]System.Tuple`2 System.Tests.GenericWithModifiers::get_GenericField() + } } } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/ILLink.Descriptors.xml b/src/libraries/System.Reflection.MetadataLoadContext/tests/ILLink.Descriptors.xml index 10280d1..fdb5d5f 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/ILLink.Descriptors.xml +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/ILLink.Descriptors.xml @@ -5,4 +5,5 @@ ILLink completely trims it out. So, preserve it explicitly. --> + diff --git a/src/libraries/System.Runtime/tests/ILLink.Descriptors.xml b/src/libraries/System.Runtime/tests/ILLink.Descriptors.xml index cdcd5d8..4d1c687 100644 --- a/src/libraries/System.Runtime/tests/ILLink.Descriptors.xml +++ b/src/libraries/System.Runtime/tests/ILLink.Descriptors.xml @@ -1,3 +1,4 @@ + diff --git a/src/libraries/System.Runtime/tests/System/ActivatorTests.cs b/src/libraries/System.Runtime/tests/System/ActivatorTests.cs index b65b9b4..af251a5 100644 --- a/src/libraries/System.Runtime/tests/System/ActivatorTests.cs +++ b/src/libraries/System.Runtime/tests/System/ActivatorTests.cs @@ -198,13 +198,8 @@ namespace System.Tests yield return new object[] { typeof(int[]) }; yield return new object[] { typeof(int).MakeByRefType() }; yield return new object[] { typeof(int).MakePointerType() }; - - // https://github.com/dotnet/runtime/issues/71095 - if (!PlatformDetection.IsMonoRuntime) - { - yield return new object[] { FunctionPointerType() }; - static unsafe Type FunctionPointerType() => typeof(delegate*); - } + yield return new object[] { FunctionPointerType() }; + static unsafe Type FunctionPointerType() => typeof(delegate*); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs index c8fb4f3..e6fbc99 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs @@ -58,7 +58,6 @@ namespace System.Reflection.Tests } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] public void FunctionPointers() { Assert.True(new TypeDelegator(typeof(delegate*)).IsFunctionPointer); diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs index 5d24792..80bf194 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs @@ -228,12 +228,8 @@ namespace System.Runtime.CompilerServices.Tests yield return new[] { typeof(int).MakePointerType(), typeof(ArgumentException) }; // pointer yield return new[] { typeof(int).MakeByRefType(), typeof(ArgumentException) }; // byref - // https://github.com/dotnet/runtime/issues/71095 - if (!PlatformDetection.IsMonoRuntime) - { - yield return new[] { FunctionPointerType(), typeof(ArgumentException) }; // function pointer - static unsafe Type FunctionPointerType() => typeof(delegate*); - } + yield return new[] { FunctionPointerType(), typeof(ArgumentException) }; // function pointer + static unsafe Type FunctionPointerType() => typeof(delegate*); yield return new[] { typeof(ReadOnlySpan), typeof(NotSupportedException) }; // byref-like type yield return new[] { typeof(ArgIterator), typeof(NotSupportedException) }; // byref-like type diff --git a/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs b/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs index 4824f7e..d623c0c 100644 --- a/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs +++ b/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs @@ -12,7 +12,7 @@ namespace System.Tests.Types public partial class FunctionPointerTests { [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/90308", TestRuntimes.Mono)] public static unsafe void CompileTimeIdentity_Managed() { object obj = new delegate*[1]; @@ -27,7 +27,7 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/90308", TestRuntimes.Mono)] public static unsafe void CompileTimeIdentity_ManagedWithMods() { object obj = new delegate*[1]; @@ -42,7 +42,7 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/90308", TestRuntimes.Mono)] public static unsafe void CompileTimeIdentity_Unmanaged() { object obj = new delegate* unmanaged[MemberFunction][1]; @@ -59,7 +59,7 @@ namespace System.Tests.Types } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/90308", TestRuntimes.Mono)] public static unsafe void CompileTimeIdentity_UnmanagedIsPartOfIdentity() { object obj = new delegate* unmanaged[MemberFunction][1]; diff --git a/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs b/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs index 5fef826..ed4fd5e 100644 --- a/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs +++ b/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs @@ -964,13 +964,8 @@ namespace System.Tests yield return new object[] { typeof(void) }; yield return new object[] { typeof(object).MakeByRefType() }; yield return new object[] { typeof(int).MakePointerType() }; - - // https://github.com/dotnet/runtime/issues/71095 - if (!PlatformDetection.IsMonoRuntime) - { - yield return new object[] { FunctionPointerType() }; - static unsafe Type FunctionPointerType() => typeof(delegate*); - } + yield return new object[] { FunctionPointerType() }; + static unsafe Type FunctionPointerType() => typeof(delegate*); } [Theory] diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedType.Mono.cs index 7cf1313..9374b7f 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedType.Mono.cs @@ -5,16 +5,151 @@ namespace System.Reflection { internal partial class ModifiedType { + /// + /// Holds type signature information about the modified type + /// It can have two sources for signatures: + /// - SignatureHolderType - holds function pointer type signature + /// - SignatureHolderInfo - holds field/property/parameter type signature + /// This comes down of having three different scenarios: + /// 1. Only SignatureHolderInfo holds signature information, example: + /// volatile int intField; + /// 2. Only SignatureHolderType holds signature information, example: + /// delegate* unmanaged[Cdecl]<int> fptrField1; + /// 3. Both SignatureHolderType and SignatureHolderInfo hold signature information, example: + /// volatile delegate* unmanaged[Cdecl]<int> fptrField2; + /// NOTE: In scenario 3) the SignatureHolderInfo has higher priority for retrieving field data (like custom modifiers) + /// internal struct TypeSignature { + internal readonly RuntimeType? SignatureHolderType; + internal readonly object? SignatureHolderInfo; + internal int ParameterIndex; + + internal TypeSignature(RuntimeType signatureHolderType, int parameterIndex) + { + SignatureHolderType = signatureHolderType; + SignatureHolderInfo = null; + ParameterIndex = parameterIndex; + } + + internal TypeSignature(object signatureHolderInfo, int parameterIndex) + { + SignatureHolderType = null; + SignatureHolderInfo = signatureHolderInfo; + ParameterIndex = parameterIndex; + } + + internal TypeSignature(RuntimeType signatureHolderType, object signatureHolderInfo, int parameterIndex) + { + SignatureHolderType = signatureHolderType; + SignatureHolderInfo = signatureHolderInfo; + ParameterIndex = parameterIndex; + } + + internal bool TryGetCustomModifiersFromSignatureHolderInfo(bool required, out Type[] modifiers) + { + if (SignatureHolderInfo is null) + { + modifiers = Type.EmptyTypes; + return false; + } + else + { + switch (SignatureHolderInfo) + { + case RuntimeFieldInfo fieldInfo: + modifiers = fieldInfo.GetCustomModifiersFromModifiedType(!required, fieldInfo.FieldType.IsGenericType ? ParameterIndex : -1); + break; + case RuntimeParameterInfo parameterInfo: + modifiers = parameterInfo.GetCustomModifiersFromModifiedType(!required, parameterInfo.ParameterType.IsGenericType ? ParameterIndex : -1); + break; + case RuntimePropertyInfo propertyInfo: + modifiers = propertyInfo.GetCustomModifiersFromModifiedType(!required, propertyInfo.PropertyType.IsGenericType ? ParameterIndex : -1); + break; + default: + throw new Exception($"SignatureHolderInfo: {SignatureHolderInfo} is not recognized"); + } + return true; + } + } + + internal bool TryGetCustomModifiersFromSignatureHolderType(bool required, out Type[] modifiers) + { + if (SignatureHolderType is null) + { + modifiers = Type.EmptyTypes; + return false; + } + else + { + modifiers = SignatureHolderType.GetCustomModifiersFromFunctionPointer(ParameterIndex, optional: !required); + return true; + } + } + } + + internal static Type Create(Type sourceType, object sourceTypeInfo, int parameterIndex = 0) + { + var unmodifiedType = (RuntimeType)sourceType; + TypeSignature typeSignature; + + if (unmodifiedType.IsFunctionPointer) + typeSignature = new TypeSignature(unmodifiedType, sourceTypeInfo, parameterIndex); + else + typeSignature = new TypeSignature(sourceTypeInfo, parameterIndex); + + return Create(unmodifiedType, typeSignature); } -#pragma warning disable IDE0060 - internal Type GetTypeParameter(Type unmodifiedType, int index) => throw new NotSupportedException(); + // If the current unmodifiedType is a function pointer that means that the signature holder for the modified type + // (and all its children types) becomes the unmodifiedType. At the same time, if the current or parent unmodified + // types are function pointers, then SignatureHolderInfo becomes irrelevant as there is no more dependency on fetching + // custom modifiers from parent's field/param/property info. + // In all other cases, we pass parent's type signature information down the hierarchy. + internal Type GetTypeParameter(Type unmodifiedType, int index) + { + var parentUnmodifiedType = UnmodifiedType; + var childUnmodifiedType = (RuntimeType)unmodifiedType; + TypeSignature childTypeSignature; - internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() => throw new NotSupportedException(); + if (childUnmodifiedType.IsFunctionPointer) + { + childTypeSignature = new TypeSignature(childUnmodifiedType, index); + } + else + { + if (parentUnmodifiedType.IsFunctionPointer) + { + var parentSignatureHolderType = _typeSignature.SignatureHolderType ?? + throw new Exception($"Parent's {nameof(_typeSignature.SignatureHolderType)} cannot be null"); + childTypeSignature = new TypeSignature(parentSignatureHolderType, index); + } + else + { + var parentSignatureHolderInfo = _typeSignature.SignatureHolderInfo ?? + throw new Exception($"Parent's {nameof(_typeSignature.SignatureHolderInfo)} cannot be null"); + childTypeSignature = new TypeSignature(parentSignatureHolderInfo, index); + } + } - private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); -#pragma warning restore IDE0060 + return Create(childUnmodifiedType, childTypeSignature); + } + + internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() + { + if (_typeSignature.SignatureHolderType is null) + throw new Exception($"{nameof(_typeSignature.SignatureHolderType)} cannot be null when retrieving calling conventions from a function pointer type "); + return _typeSignature.SignatureHolderType.GetCallingConventionFromFunctionPointer(); + } + + private Type[] GetCustomModifiers(bool required) + { + if (_typeSignature.TryGetCustomModifiersFromSignatureHolderInfo(required, out var modifiersFromInfo)) + return modifiersFromInfo; + else if (_typeSignature.TryGetCustomModifiersFromSignatureHolderType(required, out var modifiersFromType)) + return modifiersFromType; + else + throw new Exception($"Failed to retrieve custom modifiers on a modified type: {this}"); + } } } diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index e88bc83..914ff57 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -291,12 +291,16 @@ namespace System.Reflection internal static extern int get_metadata_token(RuntimeFieldInfo monoField); [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern Type[] GetTypeModifiers(bool optional); + private extern Type[] GetTypeModifiers(bool optional, int genericArgumentPosition = -1); public override Type[] GetOptionalCustomModifiers() => GetCustomModifiers(true); public override Type[] GetRequiredCustomModifiers() => GetCustomModifiers(false); private Type[] GetCustomModifiers(bool optional) => GetTypeModifiers(optional) ?? Type.EmptyTypes; + + internal Type[] GetCustomModifiersFromModifiedType(bool optional, int genericArgumentPosition) => GetTypeModifiers(optional, genericArgumentPosition) ?? Type.EmptyTypes; + + public override Type GetModifiedFieldType() => ModifiedType.Create(FieldType, this); } } diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 42ae4ce..69f8537 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -394,7 +394,7 @@ namespace System.Reflection } [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern Type[] GetTypeModifiers(Type type, MemberInfo member, int position, bool optional); + internal static extern Type[] GetTypeModifiers(Type type, MemberInfo member, int position, bool optional, int genericArgumentPosition = -1); internal static ParameterInfo New(ParameterInfo pinfo, Type? type, MemberInfo member, int position) { @@ -422,5 +422,9 @@ namespace System.Reflection } private Type[] GetCustomModifiers(bool optional) => GetTypeModifiers(ParameterType, Member, Position, optional) ?? Type.EmptyTypes; + + internal Type[] GetCustomModifiersFromModifiedType(bool optional, int genericArgumentPosition) => GetTypeModifiers(ParameterType, Member, Position, optional, genericArgumentPosition) ?? Type.EmptyTypes; + + public override Type GetModifiedParameterType() => ModifiedType.Create(ParameterType, this, PositionImpl + 1); } } diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index c699248..1b5ac96 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -77,7 +77,7 @@ namespace System.Reflection PInfo req_info); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern Type[] GetTypeModifiers(RuntimePropertyInfo prop, bool optional); + internal static extern Type[] GetTypeModifiers(RuntimePropertyInfo prop, bool optional, int genericArgumentPosition = -1); [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern object get_default_value(RuntimePropertyInfo prop); @@ -506,5 +506,9 @@ namespace System.Reflection throw new ArgumentException(SR.Argument_FieldPropertyEventAndTypeHandleIncompatibility); return pi; } + + internal Type[] GetCustomModifiersFromModifiedType(bool optional, int genericArgumentPosition) => GetTypeModifiers(this, optional, genericArgumentPosition) ?? Type.EmptyTypes; + + public override Type GetModifiedPropertyType() => ModifiedType.Create(PropertyType, this); } } diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index 5405392..2308d3b 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -2400,6 +2400,82 @@ namespace System } } + public override bool IsFunctionPointer => RuntimeTypeHandle.IsFunctionPointer(this); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern bool IsUnmanagedFunctionPointerInternal(QCallTypeHandle type); + internal static bool IsUnmanagedFunctionPointerInternal(RuntimeType type) + { + return IsUnmanagedFunctionPointerInternal(new QCallTypeHandle(ref type)); + } + + public override bool IsUnmanagedFunctionPointer => IsUnmanagedFunctionPointerInternal(this); + + public override Type[] GetFunctionPointerParameterTypes() + { + Type[] parameters = FunctionPointerReturnAndParameterTypes(this, false); + return parameters.Length == 0 ? EmptyTypes : parameters; + } + + public override Type GetFunctionPointerReturnType() + { + return FunctionPointerReturnAndParameterTypes(this, true)[0]; + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern IntPtr FunctionPointerReturnAndParameterTypes(QCallTypeHandle type); + internal static Type[] FunctionPointerReturnAndParameterTypes(RuntimeType type, bool returnType) + { + if (!RuntimeTypeHandle.IsFunctionPointer(type)) + { + throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + } + + using (var arrayOfTypeHandles = new Mono.SafeGPtrArrayHandle(FunctionPointerReturnAndParameterTypes(new QCallTypeHandle(ref type)))) + { + int typeNum = returnType ? 1 : arrayOfTypeHandles.Length - 1; + var fPtrReturnAndParameterTypes = new Type[typeNum]; + + if (returnType) + { + var typeHandle = new RuntimeTypeHandle(arrayOfTypeHandles[0]); + fPtrReturnAndParameterTypes[0] = (RuntimeType)GetTypeFromHandle(typeHandle)!; + } + else + { + for (int i = 1; i < typeNum + 1; i++) + { + var typeHandle = new RuntimeTypeHandle(arrayOfTypeHandles[i]); + fPtrReturnAndParameterTypes[i-1] = (RuntimeType)GetTypeFromHandle(typeHandle)!; + } + } + return fPtrReturnAndParameterTypes; + } + } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern Type[] GetFunctionPointerTypeModifiers(QCallTypeHandle type, int position, bool optional); + + internal static Type[] GetFunctionPointerTypeModifiers(RuntimeType type, int position, bool optional) => GetFunctionPointerTypeModifiers(new QCallTypeHandle(ref type), position, optional) ?? Type.EmptyTypes; + + public Type[] GetCustomModifiersFromFunctionPointer(int position, bool optional) => GetFunctionPointerTypeModifiers(this, position, optional); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern byte GetCallingConventionFromFunctionPointerInternal(QCallTypeHandle type); + + internal static byte GetCallingConventionFromFunctionPointerInternal(RuntimeType type) => GetCallingConventionFromFunctionPointerInternal(new QCallTypeHandle(ref type)); + + public SignatureCallingConvention GetCallingConventionFromFunctionPointer() => (SignatureCallingConvention)GetCallingConventionFromFunctionPointerInternal(this); + + public override Type[] GetFunctionPointerCallingConventions() + { + if (!RuntimeTypeHandle.IsFunctionPointer(this)) + throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + + // Requires a modified type to return the modifiers. + return EmptyTypes; + } + internal override bool IsUserType { get diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 834921f..284e315 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -418,6 +418,24 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, mono_type_name_check_byref (type, str); break; + case MONO_TYPE_FNPTR: { + MonoTypeNameFormat nested_format; + + nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ? + MONO_TYPE_NAME_FORMAT_FULL_NAME : format; + + mono_type_get_name_recurse (type->data.method->ret, str, FALSE, nested_format); + + g_string_append_c (str, '('); + for (int i = 0; i < type->data.method->param_count; ++i) { + mono_type_get_name_recurse (type->data.method->params[i], str, FALSE, nested_format); + if (i != type->data.method->param_count - 1) + g_string_append (str, ", "); + } + g_string_append_c (str, ')'); + + break; + } default: klass = mono_class_from_mono_type_internal (type); if (m_class_get_nested_in (klass)) { diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index c090abc..704092c 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -215,6 +215,10 @@ ICALL_EXPORT MonoBoolean ves_icall_RuntimeTypeHandle_IsGenericTypeDefinition (Mo ICALL_EXPORT gint32 ves_icall_RuntimeType_GetGenericParameterPosition (MonoQCallTypeHandle type_handle); +ICALL_EXPORT gint8 ves_icall_RuntimeType_GetCallingConventionFromFunctionPointerInternal (MonoQCallTypeHandle type_handle); + +ICALL_EXPORT MonoBoolean ves_icall_RuntimeType_IsUnmanagedFunctionPointerInternal (MonoQCallTypeHandle type_handle); + ICALL_EXPORT int ves_icall_System_Enum_InternalGetCorElementType (MonoQCallTypeHandle type_handle); ICALL_EXPORT gint32 ves_icall_System_Array_GetCorElementTypeOfElementTypeInternal (MonoObjectHandleOnStack arr_handle); diff --git a/src/mono/mono/metadata/icall-def.h b/src/mono/mono/metadata/icall-def.h index c467100..cdb7553 100644 --- a/src/mono/mono/metadata/icall-def.h +++ b/src/mono/mono/metadata/icall-def.h @@ -384,7 +384,7 @@ ICALL_TYPE(MFIELD, "System.Reflection.RuntimeFieldInfo", MFIELD_1) HANDLES(MFIELD_1, "GetFieldOffset", ves_icall_RuntimeFieldInfo_GetFieldOffset, gint32, 1, (MonoReflectionField)) HANDLES(MFIELD_2, "GetParentType", ves_icall_RuntimeFieldInfo_GetParentType, MonoReflectionType, 2, (MonoReflectionField, MonoBoolean)) HANDLES(MFIELD_3, "GetRawConstantValue", ves_icall_RuntimeFieldInfo_GetRawConstantValue, MonoObject, 1, (MonoReflectionField)) -HANDLES(MFIELD_4, "GetTypeModifiers", ves_icall_System_Reflection_FieldInfo_GetTypeModifiers, MonoArray, 2, (MonoReflectionField, MonoBoolean)) +HANDLES(MFIELD_4, "GetTypeModifiers", ves_icall_System_Reflection_FieldInfo_GetTypeModifiers, MonoArray, 3, (MonoReflectionField, MonoBoolean, int)) HANDLES(MFIELD_5, "GetValueInternal", ves_icall_RuntimeFieldInfo_GetValueInternal, MonoObject, 2, (MonoReflectionField, MonoObject)) HANDLES(MFIELD_6, "ResolveType", ves_icall_RuntimeFieldInfo_ResolveType, MonoReflectionType, 1, (MonoReflectionField)) HANDLES(MFIELD_7, "SetValueInternal", ves_icall_RuntimeFieldInfo_SetValueInternal, void, 3, (MonoReflectionField, MonoObject, MonoObject)) @@ -421,10 +421,10 @@ HANDLES(MODULE_13, "get_MetadataToken", ves_icall_reflection_get_token, guint32, ICALL_TYPE(PARAMI, "System.Reflection.RuntimeParameterInfo", MPARAMI_1) HANDLES_REUSE_WRAPPER(MPARAMI_1, "GetMetadataToken", ves_icall_reflection_get_token) -HANDLES(MPARAMI_2, "GetTypeModifiers", ves_icall_RuntimeParameterInfo_GetTypeModifiers, MonoArray, 4, (MonoReflectionType, MonoObject, int, MonoBoolean)) +HANDLES(MPARAMI_2, "GetTypeModifiers", ves_icall_RuntimeParameterInfo_GetTypeModifiers, MonoArray, 5, (MonoReflectionType, MonoObject, int, MonoBoolean, int)) ICALL_TYPE(MPROP, "System.Reflection.RuntimePropertyInfo", MPROP_1) -HANDLES(MPROP_1, "GetTypeModifiers", ves_icall_RuntimePropertyInfo_GetTypeModifiers, MonoArray, 2, (MonoReflectionProperty, MonoBoolean)) +HANDLES(MPROP_1, "GetTypeModifiers", ves_icall_RuntimePropertyInfo_GetTypeModifiers, MonoArray, 3, (MonoReflectionProperty, MonoBoolean, int)) HANDLES(MPROP_2, "get_default_value", ves_icall_property_info_get_default_value, MonoObject, 1, (MonoReflectionProperty)) HANDLES_REUSE_WRAPPER(MPROP_3, "get_metadata_token", ves_icall_reflection_get_token) HANDLES(MPROP_4, "get_property_info", ves_icall_RuntimePropertyInfo_get_property_info, void, 3, (MonoReflectionProperty, MonoPropertyInfo_ref, PInfo)) @@ -492,12 +492,15 @@ HANDLES(MAHN_2, "ReboxToNullable", ves_icall_RuntimeMethodHandle_ReboxToNullable ICALL_TYPE(RT, "System.RuntimeType", RT_31) HANDLES(RT_31, "AllocateValueType", ves_icall_System_RuntimeType_AllocateValueType, void, 3, (MonoQCallTypeHandle, MonoObject, MonoObjectHandleOnStack)) HANDLES(RT_1, "CreateInstanceInternal", ves_icall_System_RuntimeType_CreateInstanceInternal, MonoObject, 1, (MonoQCallTypeHandle)) +HANDLES(RT_28, "FunctionPointerReturnAndParameterTypes", ves_icall_RuntimeType_FunctionPointerReturnAndParameterTypes, GPtrArray_ptr, 1, (MonoQCallTypeHandle)) +NOHANDLES(ICALL(RT_33, "GetCallingConventionFromFunctionPointerInternal", ves_icall_RuntimeType_GetCallingConventionFromFunctionPointerInternal)) HANDLES(RT_2, "GetConstructors_native", ves_icall_RuntimeType_GetConstructors_native, GPtrArray_ptr, 2, (MonoQCallTypeHandle, guint32)) HANDLES(RT_30, "GetCorrespondingInflatedMethod", ves_icall_RuntimeType_GetCorrespondingInflatedMethod, MonoReflectionMethod, 2, (MonoQCallTypeHandle, MonoReflectionMethod)) HANDLES(RT_21, "GetDeclaringMethod", ves_icall_RuntimeType_GetDeclaringMethod, void, 2, (MonoQCallTypeHandle, MonoObjectHandleOnStack)) HANDLES(RT_22, "GetDeclaringType", ves_icall_RuntimeType_GetDeclaringType, void, 2, (MonoQCallTypeHandle, MonoObjectHandleOnStack)) HANDLES(RT_3, "GetEvents_native", ves_icall_RuntimeType_GetEvents_native, GPtrArray_ptr, 3, (MonoQCallTypeHandle, char_ptr, guint32)) HANDLES(RT_5, "GetFields_native", ves_icall_RuntimeType_GetFields_native, GPtrArray_ptr, 4, (MonoQCallTypeHandle, char_ptr, guint32, guint32)) +HANDLES(RT_32, "GetFunctionPointerTypeModifiers", ves_icall_RuntimeType_GetFunctionPointerTypeModifiers, MonoArray, 3, (MonoQCallTypeHandle, gint32, MonoBoolean)) HANDLES(RT_6, "GetGenericArgumentsInternal", ves_icall_RuntimeType_GetGenericArgumentsInternal, void, 3, (MonoQCallTypeHandle, MonoObjectHandleOnStack, MonoBoolean)) NOHANDLES(ICALL(RT_9, "GetGenericParameterPosition", ves_icall_RuntimeType_GetGenericParameterPosition)) HANDLES(RT_10, "GetInterfaceMapData", ves_icall_RuntimeType_GetInterfaceMapData, void, 4, (MonoQCallTypeHandle, MonoQCallTypeHandle, MonoArrayOut, MonoArrayOut)) @@ -508,6 +511,7 @@ HANDLES(RT_24, "GetNamespace", ves_icall_RuntimeType_GetNamespace, void, 2, (Mon HANDLES(RT_13, "GetNestedTypes_native", ves_icall_RuntimeType_GetNestedTypes_native, GPtrArray_ptr, 4, (MonoQCallTypeHandle, char_ptr, guint32, guint32)) HANDLES(RT_14, "GetPacking", ves_icall_RuntimeType_GetPacking, void, 3, (MonoQCallTypeHandle, guint32_ref, guint32_ref)) HANDLES(RT_15, "GetPropertiesByName_native", ves_icall_RuntimeType_GetPropertiesByName_native, GPtrArray_ptr, 4, (MonoQCallTypeHandle, char_ptr, guint32, guint32)) +NOHANDLES(ICALL(RT_29, "IsUnmanagedFunctionPointerInternal", ves_icall_RuntimeType_IsUnmanagedFunctionPointerInternal)) HANDLES(RT_17, "MakeGenericType", ves_icall_RuntimeType_MakeGenericType, void, 3, (MonoReflectionType, MonoArray, MonoObjectHandleOnStack)) HANDLES(RT_19, "getFullName", ves_icall_System_RuntimeType_getFullName, void, 4, (MonoQCallTypeHandle, MonoObjectHandleOnStack, MonoBoolean, MonoBoolean)) HANDLES(RT_26, "make_array_type", ves_icall_RuntimeType_make_array_type, void, 3, (MonoQCallTypeHandle, int, MonoObjectHandleOnStack)) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index c4063cb..f3ef9b7 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -1906,6 +1906,9 @@ ves_icall_RuntimeTypeHandle_GetMetadataToken (MonoQCallTypeHandle type_handle, M { MonoType *type = type_handle.type; + if (type->type == MONO_TYPE_FNPTR) + return MONO_TOKEN_TYPE_DEF; // coreCLR expects 0x02000000 as the metadata token value for function pointers + MonoClass *mc = mono_class_from_mono_type_internal (type); if (!mono_class_init_internal (mc)) { mono_error_set_for_class_failure (error, mc); @@ -2009,14 +2012,25 @@ ves_icall_System_Reflection_RuntimePropertyInfo_internal_from_handle_type (MonoP return mono_property_get_object_handle (klass, handle, error); } +static MonoType* +get_generic_argument_type (MonoType* type, unsigned int generic_argument_position) +{ + g_assert (type->type == MONO_TYPE_GENERICINST); + g_assert (type->data.generic_class->context.class_inst->type_argc > generic_argument_position); + return type->data.generic_class->context.class_inst->type_argv [generic_argument_position]; +} + MonoArrayHandle -ves_icall_System_Reflection_FieldInfo_GetTypeModifiers (MonoReflectionFieldHandle field_h, MonoBoolean optional, MonoError *error) +ves_icall_System_Reflection_FieldInfo_GetTypeModifiers (MonoReflectionFieldHandle field_h, MonoBoolean optional, int generic_argument_position, MonoError *error) { MonoClassField *field = MONO_HANDLE_GETVAL (field_h, field); MonoType *type = mono_field_get_type_checked (field, error); return_val_if_nok (error, NULL_HANDLE_ARRAY); + if (generic_argument_position > -1) + type = get_generic_argument_type (type, (unsigned int)generic_argument_position); + return type_array_from_modifiers (type, optional, error); } @@ -2807,6 +2821,22 @@ ves_icall_RuntimeType_GetPacking (MonoQCallTypeHandle type_handle, guint32 *pack } } +gint8 +ves_icall_RuntimeType_GetCallingConventionFromFunctionPointerInternal (MonoQCallTypeHandle type_handle) +{ + MonoType *type = type_handle.type; + g_assert (type->type == MONO_TYPE_FNPTR); + // FIXME: Once we address: https://github.com/dotnet/runtime/issues/90308 this should not be needed anymore + return type->data.method->suppress_gc_transition ? MONO_CALL_UNMANAGED_MD : type->data.method->call_convention; +} + +MonoBoolean +ves_icall_RuntimeType_IsUnmanagedFunctionPointerInternal (MonoQCallTypeHandle type_handle) +{ + MonoType *type = type_handle.type; + return type->type == MONO_TYPE_FNPTR && type->data.method->pinvoke; +} + void ves_icall_RuntimeTypeHandle_GetElementType (MonoQCallTypeHandle type_handle, MonoObjectHandleOnStack res, MonoError *error) { @@ -2886,6 +2916,36 @@ ves_icall_RuntimeTypeHandle_IsByRefLike (MonoQCallTypeHandle type_handle, MonoEr return !!m_class_is_byreflike (klass); } +GPtrArray* +ves_icall_RuntimeType_FunctionPointerReturnAndParameterTypes (MonoQCallTypeHandle type_handle, MonoError *error) +{ + // FIXME: cache - possible on managed side + + MonoType *type = type_handle.type; + GPtrArray *res_array = g_ptr_array_new (); + + g_ptr_array_add (res_array, type->data.method->ret); + + for (int i = 0; i < type->data.method->param_count; ++i) + g_ptr_array_add (res_array, type->data.method->params[i]); + + return res_array; +} + +MonoArrayHandle +ves_icall_RuntimeType_GetFunctionPointerTypeModifiers (MonoQCallTypeHandle type_handle, int position, MonoBoolean optional, MonoError *error) +{ + MonoType *type = type_handle.type; + g_assert (type->type == MONO_TYPE_FNPTR); + if (position == 0) { + return type_array_from_modifiers (type->data.method->ret, optional, error); + } + else { + g_assert (type->data.method->param_count > position - 1); + return type_array_from_modifiers (type->data.method->params[position - 1], optional, error); + } +} + MonoBoolean ves_icall_RuntimeTypeHandle_IsComObject (MonoQCallTypeHandle type_handle, MonoError *error) { @@ -2972,15 +3032,15 @@ ves_icall_RuntimeType_GetName (MonoQCallTypeHandle type_handle, MonoObjectHandle MonoClass *klass = mono_class_from_mono_type_internal (type); // FIXME: this should be escaped in some scenarios with mono_identifier_escape_type_name_chars // Determining exactly when to do so is fairly difficult, so for now we don't bother to avoid regressions - const char *klass_name = m_class_get_name (klass); + const char *name = type->type == MONO_TYPE_FNPTR ? "" : m_class_get_name (klass); if (m_type_is_byref (type)) { - char *n = g_strdup_printf ("%s&", klass_name); + char *n = g_strdup_printf ("%s&", name); HANDLE_ON_STACK_SET (res, mono_string_new_checked (n, error)); g_free (n); } else { - HANDLE_ON_STACK_SET (res, mono_string_new_checked (klass_name, error)); + HANDLE_ON_STACK_SET (res, mono_string_new_checked (name, error)); } } @@ -2988,8 +3048,10 @@ void ves_icall_RuntimeType_GetNamespace (MonoQCallTypeHandle type_handle, MonoObjectHandleOnStack res, MonoError *error) { MonoType *type = type_handle.type; + if (type->type == MONO_TYPE_FNPTR) + return; + MonoClass *klass = mono_class_from_mono_type_internal (type); - MonoClass *elem; while (!m_class_is_enumtype (klass) && !mono_class_is_nullable (klass) && @@ -5084,7 +5146,7 @@ ves_icall_System_RuntimeType_getFullName (MonoQCallTypeHandle type_handle, MonoO if (!name) return; - if (full_name && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) { + if (full_name && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR || type->type == MONO_TYPE_FNPTR)) { g_free (name); return; } @@ -6492,7 +6554,7 @@ fail: } MonoArrayHandle -ves_icall_RuntimeParameterInfo_GetTypeModifiers (MonoReflectionTypeHandle rt, MonoObjectHandle member, int pos, MonoBoolean optional, MonoError *error) +ves_icall_RuntimeParameterInfo_GetTypeModifiers (MonoReflectionTypeHandle rt, MonoObjectHandle member, int position, MonoBoolean optional, int generic_argument_position, MonoError *error) { MonoType *type = MONO_HANDLE_GETVAL (rt, type); MonoClass *member_class = mono_handle_class (member); @@ -6514,10 +6576,13 @@ ves_icall_RuntimeParameterInfo_GetTypeModifiers (MonoReflectionTypeHandle rt, Mo } sig = mono_method_signature_internal (method); - if (pos == -1) + if (position == -1) type = sig->ret; else - type = sig->params [pos]; + type = sig->params [position]; + + if (generic_argument_position > -1) + type = get_generic_argument_type (type, (unsigned int)generic_argument_position); return type_array_from_modifiers (type, optional, error); } @@ -6537,13 +6602,17 @@ get_property_type (MonoProperty *prop) } MonoArrayHandle -ves_icall_RuntimePropertyInfo_GetTypeModifiers (MonoReflectionPropertyHandle property, MonoBoolean optional, MonoError *error) +ves_icall_RuntimePropertyInfo_GetTypeModifiers (MonoReflectionPropertyHandle property, MonoBoolean optional, int generic_argument_position, MonoError *error) { MonoProperty *prop = MONO_HANDLE_GETVAL (property, property); MonoType *type = get_property_type (prop); if (!type) return NULL_HANDLE_ARRAY; + + if (generic_argument_position > -1) + type = get_generic_argument_type (type, (unsigned int)generic_argument_position); + return type_array_from_modifiers (type, optional, error); } -- 2.7.4