From 173b84d72727793d3ec35e60365c3f1b417d7487 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 31 May 2022 11:59:19 -0500 Subject: [PATCH 01/20] Add reflection introspection support for function pointers --- .../System.Private.CoreLib.csproj | 5 + .../src/System/Reflection/MdImport.cs | 22 -- .../ModifiedFunctionPointerType.CoreCLR.cs | 19 + .../System/Reflection/ModifiedType.CoreCLR.cs | 54 +++ .../src/System/Reflection/RtFieldInfo.cs | 18 +- .../System/Reflection/RuntimeParameterInfo.cs | 10 + .../System/Reflection/RuntimePropertyInfo.cs | 12 +- .../src/System/RuntimeHandles.cs | 43 +-- .../src/System/RuntimeType.CoreCLR.cs | 83 +++- src/coreclr/inc/sigparser.h | 14 +- .../src/System.Private.CoreLib.csproj | 6 +- .../ModifiedFunctionPointerType.NativeAot.cs | 10 + .../Reflection/ModifiedType.NativeAot.cs | 12 + .../MetadataReaderExtensions.NativeFormat.cs | 5 +- .../General/TypeResolver.NativeFormat.cs | 3 +- src/coreclr/utilcode/sigparser.cpp | 185 +++++++++ src/coreclr/vm/clsload.cpp | 2 +- src/coreclr/vm/ecalllist.h | 4 + src/coreclr/vm/runtimehandles.cpp | 164 +++++++- src/coreclr/vm/runtimehandles.h | 21 +- src/coreclr/vm/sigformat.cpp | 3 +- src/coreclr/vm/siginfo.cpp | 160 +++++--- src/coreclr/vm/siginfo.hpp | 6 + src/coreclr/vm/typedesc.cpp | 41 ++ src/coreclr/vm/typedesc.h | 36 +- src/coreclr/vm/typehandle.cpp | 3 +- src/coreclr/vm/typehandle.h | 2 + src/coreclr/vm/typehandle.inl | 3 +- src/coreclr/vm/typekey.h | 2 +- src/coreclr/vm/typestring.cpp | 74 +++- src/coreclr/vm/typestring.h | 1 + ...FunctionPointerTests.CallingConventions.cs | 189 +++++++++ .../System/FunctionPointerTests.Identity.cs | 130 +++++++ .../tests/System/FunctionPointerTests.cs | 319 +++++++++++++++ .../Common/tests/System/ModifiedTypeTests.cs | 362 ++++++++++++++++++ .../FunctionPointerHolder.cs | 18 + .../TestFunctionPointerAssembly.csproj | 11 + .../tests/StackTraceTests.cs | 4 +- .../src/Resources/Strings.resx | 3 + .../System.Private.CoreLib.Shared.projitems | 8 +- .../src/System/Reflection/FieldInfo.cs | 2 + .../Reflection/MdSigCallingConvention.cs | 31 ++ .../Reflection/ModifiedContainerType.cs | 44 +++ .../Reflection/ModifiedFunctionPointerType.cs | 117 ++++++ .../System/Reflection/ModifiedGenericType.cs | 55 +++ .../Reflection/ModifiedStandaloneType.cs | 28 ++ .../src/System/Reflection/ModifiedType.cs | 161 ++++++++ .../src/System/Reflection/ParameterInfo.cs | 2 + .../src/System/Reflection/PropertyInfo.cs | 1 + .../src/System/Reflection/TypeDelegator.cs | 7 + .../System.Private.CoreLib/src/System/Type.cs | 14 +- .../Decoding/SignatureDecoderTests.cs | 4 + .../System.Reflection.MetadataLoadContext.sln | 7 + .../src/Resources/Strings.resx | 8 +- ...stem.Reflection.MetadataLoadContext.csproj | 12 +- .../TypeLoading/Constructors/RoConstructor.cs | 5 - .../Constructors/RoDefinitionConstructor.cs | 1 - .../Constructors/RoSyntheticConstructor.cs | 2 - .../TypeLoading/Fields/Ecma/EcmaField.cs | 11 +- .../Reflection/TypeLoading/Fields/RoField.cs | 43 ++- .../TypeLoading/General/CoreType.cs | 10 + .../General/Ecma/EcmaModifiedTypeProvider.cs | 20 - .../EcmaSignatureTypeProviderForToString.cs | 21 +- .../General/Ecma/EcmaWrappedTypeProvider.cs | 6 +- .../Reflection/TypeLoading/General/Helpers.cs | 47 +-- .../TypeLoading/General/Sentinels.cs | 1 - .../General/TypeExtensions.netcoreapp.cs | 9 +- .../General/TypeExtensions.netstandard.cs | 15 + .../TypeLoading/General/Utf8Constants.cs | 4 + .../MethodBase/Ecma/EcmaMethodDecoder.cs | 13 - .../TypeLoading/MethodBase/IMethodDecoder.cs | 1 - .../TypeLoading/MethodBase/IRoMethodBase.cs | 1 - .../Methods/RoConstructedGenericMethod.cs | 1 - .../TypeLoading/Methods/RoDefinitionMethod.cs | 3 - .../TypeLoading/Methods/RoMethod.cs | 5 - .../TypeLoading/Methods/RoSyntheticMethod.cs | 2 - .../Modules/Ecma/EcmaModule.TypeProvider.cs | 21 +- .../Parameters/RoMethodParameter.cs | 29 +- .../TypeLoading/Parameters/RoParameter.cs | 2 +- .../Parameters/RoPropertyIndexParameter.cs | 1 + .../Properties/Ecma/EcmaProperty.cs | 11 +- .../TypeLoading/Properties/RoProperty.cs | 38 +- .../RuntimeTypeInfo.BindingFlags.cs | 2 +- .../TypeLoading/RuntimeTypeInfo.GetMember.cs | 2 +- .../RuntimeTypeInfo.TypeComponentsCache.cs | 3 +- .../TypeLoading/Types/RoArrayType.cs | 4 +- .../TypeLoading/Types/RoByRefType.cs | 4 +- .../Types/RoConstructedGenericType.cs | 9 +- .../TypeLoading/Types/RoDefinitionType.cs | 11 +- .../Types/RoFunctionPointerType.cs | 200 ++++++++++ .../Types/RoGenericParameterType.cs | 8 +- .../TypeLoading/Types/RoHasElementType.cs | 4 + .../Types/RoModifiedContainerType.cs | 25 ++ .../Types/RoModifiedFunctionPointerType.cs | 97 +++++ .../Types/RoModifiedGenericType.cs | 35 ++ .../Types/RoModifiedStandaloneType.cs | 15 + .../TypeLoading/Types/RoModifiedType.cs | 58 ++- .../TypeLoading/Types/RoPointerType.cs | 6 +- .../TypeLoading/Types/RoStubType.cs | 8 +- .../TypeLoading/Types/RoType.GetInterface.cs | 2 +- .../TypeLoading/Types/RoType.ModifiedType.cs | 77 ++++ .../Types/RoType.TypeClassification.cs | 2 +- .../Reflection/TypeLoading/Types/RoType.cs | 64 +++- .../TypeLoading/Types/RoTypeDelegator.cs | 96 +++++ .../TypeLoading/Types/RoWrappedType.cs | 2 +- ...eflection.MetadataLoadContext.Tests.csproj | 15 +- .../src/SampleMetadata/SampleMetadata.cs | 2 +- .../FunctionPointerTestsExtensions.cs | 23 ++ .../src/TestUtils/TestUtils.JittedRuntimes.cs | 10 +- .../tests/src/Tests/Method/MethodTests.cs | 1 - .../tests/MethodInfoTests.cs | 57 ++- .../ConvertToLibraryImportAnalyzerTests.cs | 3 +- .../System.Runtime/System.Runtime.sln | 3 + .../System.Runtime/ref/System.Runtime.cs | 21 +- .../tests/System.Runtime.Tests.csproj | 9 +- .../FunctionPointerTestsExtensions.cs | 27 ++ .../System/Reflection/TypeDelegatorTests.cs | 17 + .../Type/FunctionPointerTests.Runtime.cs | 88 +++++ .../System.Private.CoreLib.csproj | 5 + .../ModifiedFunctionPointerType.Mono.cs | 10 + .../System/Reflection/ModifiedType.Mono.cs | 12 + src/tests/reflection/ldtoken/modifiers.il | 35 +- 122 files changed, 3624 insertions(+), 331 deletions(-) create mode 100644 src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs create mode 100644 src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs create mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs create mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs create mode 100644 src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs create mode 100644 src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs create mode 100644 src/libraries/Common/tests/System/FunctionPointerTests.cs create mode 100644 src/libraries/Common/tests/System/ModifiedTypeTests.cs create mode 100644 src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs create mode 100644 src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs delete mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaModifiedTypeProvider.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedGenericType.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedStandaloneType.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.ModifiedType.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs create mode 100644 src/libraries/System.Runtime/tests/System/Reflection/FunctionPointerTestsExtensions.cs create mode 100644 src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs create mode 100644 src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs create mode 100644 src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedType.Mono.cs diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index 1dd98e1293225f..dc33ba5fdb7459 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -191,6 +191,8 @@ + + @@ -243,6 +245,9 @@ + + Common\System\Collections\Generic\ArrayBuilder.cs + diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs index df7ef1ba31d074..98f6eeebf4c55c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs @@ -8,28 +8,6 @@ namespace System.Reflection { - [Flags] - internal enum MdSigCallingConvention : byte - { - CallConvMask = 0x0f, // Calling convention is bottom 4 bits - - Default = 0x00, - C = 0x01, - StdCall = 0x02, - ThisCall = 0x03, - FastCall = 0x04, - Vararg = 0x05, - Field = 0x06, - LocalSig = 0x07, - Property = 0x08, - Unmanaged = 0x09, - GenericInst = 0x0a, // generic method instantiation - - Generic = 0x10, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) - HasThis = 0x20, // Top bit indicates a 'this' parameter - ExplicitThis = 0x40, // This parameter is explicitly in the signature - } - [Flags] internal enum PInvokeAttributes { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs new file mode 100644 index 00000000000000..e20f23b8c96eae --- /dev/null +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal partial class ModifiedFunctionPointerType + { + private MdSigCallingConvention GetCallingConvention() + { + Signature? signature = GetSignature(); + if (signature != null) + { + return (MdSigCallingConvention)signature.GetCallingConventionFromFunctionPointer(RootSignatureParameterIndex, NestedSignatureIndex); + } + + return MdSigCallingConvention.Default; + } + } +} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs new file mode 100644 index 00000000000000..a4c8ba7b131acd --- /dev/null +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal partial class ModifiedType + { + private Signature? _signature; + + /// + /// Called from FieldInfo, PropertyInfo and ParameterInfo to create a modified type tree. + /// + public static ModifiedType Create(Type unmodifiedType, Type[] requiredModifiers, Type[] optionalModifiers, Signature? signature, int rootSignatureParameterIndex) + { + ModifiedType modifiedType; + + if (unmodifiedType.IsFunctionPointer) + { + modifiedType = new ModifiedFunctionPointerType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + } + else if (unmodifiedType.HasElementType) + { + modifiedType = new ModifiedContainerType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + } + else if (unmodifiedType.IsGenericType) + { + modifiedType = new ModifiedGenericType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + } + else + { + modifiedType = new ModifiedStandaloneType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + } + + modifiedType._signature = signature; + return modifiedType; + } + + public Signature? GetSignature() => Root._signature; + + private Type[] GetCustomModifiers(bool required) + { + if (_nestedSignatureParameterIndex >= 0) + { + Signature? signature = GetSignature(); + if (signature != null) + { + return signature.GetCustomModifiers(RootSignatureParameterIndex, required, _nestedSignatureIndex, _nestedSignatureParameterIndex) ?? EmptyTypes; + } + } + + return EmptyTypes; + } + } +} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs index 388d49354486f8..9f8f0b09ad3dd3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs @@ -252,19 +252,31 @@ public override Type FieldType [MethodImpl(MethodImplOptions.NoInlining)] private RuntimeType InitializeFieldType() { - return m_fieldType = new Signature(this, m_declaringType).FieldType; + return m_fieldType = GetSignature().FieldType; } public override Type[] GetRequiredCustomModifiers() { - return new Signature(this, m_declaringType).GetCustomModifiers(1, true); + return GetSignature().GetCustomModifiers(1, true); } public override Type[] GetOptionalCustomModifiers() { - return new Signature(this, m_declaringType).GetCustomModifiers(1, false); + return GetSignature().GetCustomModifiers(1, false); } + internal Signature GetSignature() => new Signature(this, m_declaringType); + + public override Type GetModifiedFieldType() + { + Signature sig = GetSignature(); + return ModifiedType.Create( + FieldType, + sig.GetCustomModifiers(1, true), + sig.GetCustomModifiers(1, false), + sig, + rootSignatureParameterIndex: 1); + } #endregion } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index cec302e60a0143..a3c8aaf178efeb 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -440,6 +440,16 @@ public override Type[] GetOptionalCustomModifiers() m_signature.GetCustomModifiers(PositionImpl + 1, false); } + public override Type GetModifiedParameterType() + { + return ModifiedType.Create( + unmodifiedType: ParameterType, + GetRequiredCustomModifiers(), + GetOptionalCustomModifiers(), + m_signature, + rootSignatureParameterIndex: PositionImpl + 1); + } + #endregion #region ICustomAttributeProvider diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index a6b97f36353b85..fc37e7562a568d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -79,7 +79,7 @@ internal bool EqualsSig(RuntimePropertyInfo target) { // @Asymmetry - Legacy policy is to remove duplicate properties, including hidden properties. // The comparison is done by name and by sig. The EqualsSig comparison is expensive - // but forutnetly it is only called when an inherited property is hidden by name or + // but fortunately it is only called when an inherited property is hidden by name or // when an interfaces declare properies with the same signature. // Note that we intentionally don't resolve generic arguments so that we don't treat // signatures that only match in certain instantiations as duplicates. This has the @@ -205,6 +205,16 @@ public override Type[] GetOptionalCustomModifiers() return Signature.GetCustomModifiers(0, false); } + public override Type GetModifiedPropertyType() + { + return ModifiedType.Create( + PropertyType, + GetRequiredCustomModifiers(), + GetOptionalCustomModifiers(), + Signature, + rootSignatureParameterIndex: 0); + } + internal object GetConstantValue(bool raw) { object? defaultValue = MdConstant.GetValue(GetRuntimeModule().MetadataImport, m_token, PropertyType.TypeHandle, raw); diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index b924242cfe7462..cbc6e9fac63379 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -159,6 +159,12 @@ internal static bool IsSZArray(RuntimeType type) return corElemType == CorElementType.ELEMENT_TYPE_SZARRAY; } + internal static bool IsFunctionPointer(RuntimeType type) + { + CorElementType corElemType = GetCorElementType(type); + return corElemType == CorElementType.ELEMENT_TYPE_FNPTR; + } + internal static bool HasElementType(RuntimeType type) { CorElementType corElemType = GetCorElementType(type); @@ -360,6 +366,12 @@ public ModuleHandle GetModuleHandle() [MethodImpl(MethodImplOptions.InternalCall)] internal static extern RuntimeMethodHandleInternal GetMethodAt(RuntimeType type, int slot); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern Type[] GetArgumentTypesFromFunctionPointer(RuntimeType type); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool IsUnmanagedFunctionPointer(RuntimeType type); + // This is managed wrapper for MethodTable::IntroducedMethodIterator internal struct IntroducedMethodEnumerator { @@ -1557,28 +1569,6 @@ internal static MetadataImport GetMetadataImport(RuntimeModule module) internal sealed unsafe class Signature { - #region Definitions - internal enum MdSigCallingConvention : byte - { - Generics = 0x10, - HasThis = 0x20, - ExplicitThis = 0x40, - CallConvMask = 0x0F, - Default = 0x00, - C = 0x01, - StdCall = 0x02, - ThisCall = 0x03, - FastCall = 0x04, - Vararg = 0x05, - Field = 0x06, - LocalSig = 0x07, - Property = 0x08, - Unmanaged = 0x09, - GenericInst = 0x0A, - Max = 0x0B, - } - #endregion - #region FCalls [MemberNotNull(nameof(m_arguments))] [MemberNotNull(nameof(m_returnTypeORfieldType))] @@ -1586,7 +1576,6 @@ internal enum MdSigCallingConvention : byte private extern void GetSignature( void* pCorSig, int cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo? methodHandle, RuntimeType? declaringType); - #endregion #region Private Data Members @@ -1646,7 +1635,13 @@ public Signature(void* pCorSig, int cCorSig, RuntimeType declaringType) internal static extern bool CompareSig(Signature sig1, Signature sig2); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern Type[] GetCustomModifiers(int position, bool required); + internal extern Type[] GetCustomModifiers(int rootSignatureParameterIndex, bool required, int nestedSignatureIndex = -1, int nestedSignatureParameterIndex = -1); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern byte GetCallingConventionFromFunctionPointer(int rootSignatureParameterIndex, int nestedSignatureIndex); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern bool IsUnmanagedFunctionPointer(); #endregion } diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 342ce64ad15ca7..159d711d72d348 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -1010,7 +1010,7 @@ private void PopulateLiteralFields(Filter filter, RuntimeType declaringType, ref #endregion RuntimeFieldInfo runtimeFieldInfo = - new MdFieldInfo(tkField, fieldAttributes, declaringType.TypeHandle, m_runtimeTypeCache, bindingFlags); + new MdFieldInfo(tkField, fieldAttributes, declaringType.TypeHandle, m_runtimeTypeCache, bindingFlags); list.Add(runtimeFieldInfo); } @@ -1535,12 +1535,32 @@ private MemberInfoCache GetMemberCache(ref MemberInfoCache? m_cache) #region Internal Members + + /// + /// Generic cache for rare scenario specific data. It is used to cache either Enum names, Enum values, the Activator cache or a function pointer. + /// internal object? GenericCache { get => m_genericCache; set => m_genericCache = value; } + internal Type[] FunctionPointerReturnAndParameterTypes + { + get + { + Debug.Assert(m_runtimeType.IsFunctionPointer); + Type[]? value = (Type[]?)GenericCache; + if (value == null) + { + GenericCache = value = RuntimeTypeHandle.GetArgumentTypesFromFunctionPointer(m_runtimeType); + Debug.Assert(value.Length > 0); + } + + return value; + } + } + internal bool DomainInitialized { get => m_bIsDomainInitialized; @@ -1564,6 +1584,11 @@ internal bool DomainInitialized if (!m_runtimeType.GetRootElementType().IsGenericTypeDefinition && m_runtimeType.ContainsGenericParameters) return null; + // Exclude function pointer; it requires a grammar update and parsing support for Type.GetType() and friends. + // See https://learn.microsoft.com/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names. + if (m_runtimeType.IsFunctionPointer) + return null; + // No assembly. return ConstructName(ref m_fullname, TypeNameFormatFlags.FormatNamespace | TypeNameFormatFlags.FormatFullInst); @@ -1576,12 +1601,16 @@ internal bool DomainInitialized } } - internal string GetNameSpace() + internal string? GetNameSpace() { // @Optimization - Use ConstructName to populate m_namespace if (m_namespace == null) { Type type = m_runtimeType; + + if (type.IsFunctionPointer) + return null; + type = type.GetRootElementType(); while (type.IsNested) @@ -3350,7 +3379,8 @@ public override string? AssemblyQualifiedName { string? fullname = FullName; - // FullName is null if this type contains generic parameters but is not a generic type definition. + // FullName is null if this type contains generic parameters but is not a generic type definition + // or if it is a function pointer. if (fullname == null) return null; @@ -3362,7 +3392,7 @@ public override string? Namespace { get { - string ns = Cache.GetNameSpace(); + string? ns = Cache.GetNameSpace(); if (string.IsNullOrEmpty(ns)) { return null; @@ -3693,6 +3723,51 @@ private CheckValueStatus TryChangeTypeSpecial( #endregion + #region Function Pointer + public override bool IsFunctionPointer => RuntimeTypeHandle.IsFunctionPointer(this); + public override bool IsUnmanagedFunctionPointer => RuntimeTypeHandle.IsUnmanagedFunctionPointer(this); + + public override Type[] GetFunctionPointerCallingConventions() + { + if (!IsFunctionPointer) + { + throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + } + + // Requires a modified type to return the modifiers. + return EmptyTypes; + } + + public override Type[] GetFunctionPointerParameterTypes() + { + if (!IsFunctionPointer) + { + throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + } + + Type[] parameters = Cache.FunctionPointerReturnAndParameterTypes; + Debug.Assert(parameters.Length != 0); + + if (parameters.Length == 1) + { + return EmptyTypes; + } + + return ModifiedType.CloneArray(parameters, 1); + } + + public override Type GetFunctionPointerReturnType() + { + if (!IsFunctionPointer) + { + throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + } + + Debug.Assert(Cache.FunctionPointerReturnAndParameterTypes.Length != 0); + return Cache.FunctionPointerReturnAndParameterTypes[0]; + } + #endregion + #endregion public override string ToString() => GetCachedName(TypeNameKind.ToString)!; diff --git a/src/coreclr/inc/sigparser.h b/src/coreclr/inc/sigparser.h index 417660e2df4c2a..267dcdec023b04 100644 --- a/src/coreclr/inc/sigparser.h +++ b/src/coreclr/inc/sigparser.h @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // // sigparser.h -// - -// #ifndef _H_SIGPARSER #define _H_SIGPARSER @@ -724,8 +721,19 @@ class SigParser __checkReturn HRESULT SkipSignature(); +private: + + __checkReturn + HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished); + public: + //------------------------------------------------------------------------ + // Move to the specified signature (immediately follows an ELEMENT_TYPE_FNPTR) + //------------------------------------------------------------------------ + __checkReturn + HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind); + //------------------------------------------------------------------------ // Return pointer // PLEASE DON'T USE THIS. diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 550978d492ae6f..7576b66a6d6857 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ - + true @@ -162,6 +162,8 @@ + + @@ -495,7 +497,7 @@ - + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs new file mode 100644 index 00000000000000..bd1dda86aabd46 --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal partial class ModifiedFunctionPointerType + { + private MdSigCallingConvention GetCallingConvention() => throw new NotSupportedException(); + } +} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs new file mode 100644 index 00000000000000..4eeb6acb7bf2e8 --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal partial class ModifiedType + { +#pragma warning disable IDE0060 + private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); +#pragma warning restore IDE0060 + } +} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs index 3ceed387846887..8d9e6cde0dbed6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs @@ -18,6 +18,7 @@ using Internal.Metadata.NativeFormat; using NativeFormatAssemblyFlags = global::Internal.Metadata.NativeFormat.AssemblyFlags; +using NativeFormatModifiedType = global::Internal.Metadata.NativeFormat.ModifiedType; namespace System.Reflection.Runtime.General { @@ -151,7 +152,7 @@ internal static Type[] GetCustomModifiers(this Handle handle, MetadataReader rea LowLevelList customModifiers = new LowLevelList(); do { - ModifiedType modifiedType = handle.ToModifiedTypeHandle(reader).GetModifiedType(reader); + NativeFormatModifiedType modifiedType = handle.ToModifiedTypeHandle(reader).GetModifiedType(reader); if (optional == modifiedType.IsOptional) { Type customModifier = modifiedType.ModifierType.Resolve(reader, typeContext); @@ -174,7 +175,7 @@ public static Handle SkipCustomModifiers(this Handle handle, MetadataReader read do { - ModifiedType modifiedType = handle.ToModifiedTypeHandle(reader).GetModifiedType(reader); + NativeFormatModifiedType modifiedType = handle.ToModifiedTypeHandle(reader).GetModifiedType(reader); handle = modifiedType.Type; handleType = handle.HandleType; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs index e6b89326e13cde..9fa839648d08ce 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs @@ -17,6 +17,7 @@ using Internal.Reflection.Core.Execution; using Internal.Metadata.NativeFormat; +using NativeFormatModifiedType = global::Internal.Metadata.NativeFormat.ModifiedType; namespace System.Reflection.Runtime.General { @@ -45,7 +46,7 @@ internal static RuntimeTypeInfo Resolve(this Handle typeDefRefOrSpec, MetadataRe return typeDefRefOrSpec.ToTypeSpecificationHandle(reader).TryResolveTypeSignature(reader, typeContext, ref exception); else if (handleType == HandleType.ModifiedType) { - ModifiedType modifiedType = typeDefRefOrSpec.ToModifiedTypeHandle(reader).GetModifiedType(reader); + NativeFormatModifiedType modifiedType = typeDefRefOrSpec.ToModifiedTypeHandle(reader).GetModifiedType(reader); return modifiedType.Type.TryResolve(reader, typeContext, ref exception); } else diff --git a/src/coreclr/utilcode/sigparser.cpp b/src/coreclr/utilcode/sigparser.cpp index 99fbe0a083acee..6bbb12f6061acd 100644 --- a/src/coreclr/utilcode/sigparser.cpp +++ b/src/coreclr/utilcode/sigparser.cpp @@ -192,3 +192,188 @@ HRESULT SigParser::SkipSignature() return hr; } + +HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind) +{ + CONTRACTL + { + INSTANCE_CHECK; + NOTHROW; + GC_NOTRIGGER; + FORBID_FAULT; + SUPPORTS_DAC; + } + CONTRACTL_END + + BOOL isFinished = FALSE; + HRESULT hr = MoveToNewSignature(indexToFind, 0, &isFinished); + if (isFinished == FALSE) + { + return META_E_BAD_SIGNATURE; + } + + return hr; +} + +HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished) +{ + CONTRACTL + { + INSTANCE_CHECK; + NOTHROW; + GC_NOTRIGGER; + FORBID_FAULT; + SUPPORTS_DAC; + } + CONTRACTL_END + + CorElementType typ; + HRESULT hr = GetElemType(&typ); + IfFailRet(hr); + + if (!CorIsPrimitiveType(typ)) + { + switch ((DWORD)typ) + { + default: + return META_E_BAD_SIGNATURE; + break; + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_MVAR: + IfFailRet(GetData(NULL)); // Skip variable number + break; + case ELEMENT_TYPE_VAR_ZAPSIG: + IfFailRet(GetData(NULL)); // Skip RID + break; + case ELEMENT_TYPE_OBJECT: + case ELEMENT_TYPE_STRING: + case ELEMENT_TYPE_TYPEDBYREF: + case ELEMENT_TYPE_CANON_ZAPSIG: + break; + + case ELEMENT_TYPE_BYREF: //fallthru + case ELEMENT_TYPE_PTR: + case ELEMENT_TYPE_PINNED: + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: + IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + + if (*isFinished) + return S_OK; + + break; + + case ELEMENT_TYPE_VALUETYPE: //fallthru + case ELEMENT_TYPE_CLASS: + IfFailRet(GetToken(NULL)); // Skip RID + break; + + case ELEMENT_TYPE_MODULE_ZAPSIG: + IfFailRet(GetData(NULL)); // Skip index + IfFailRet(SkipExactlyOne()); // Skip type + break; + + case ELEMENT_TYPE_FNPTR: + if (indexToFind == currentIndex) + { + *isFinished = TRUE; + return S_OK; + } + + currentIndex++; + + // Skip calling convention + uint32_t uCallConv; + IfFailRet(GetCallingConvInfo(&uCallConv)); + if ((uCallConv == IMAGE_CEE_CS_CALLCONV_FIELD) || + (uCallConv == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)) + { + return META_E_BAD_SIGNATURE; + } + + // Skip type parameter count + if (uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) + IfFailRet(GetData(NULL)); + + // Get arg count; + uint32_t fpArgCnt; + IfFailRet(GetData(&fpArgCnt)); + + // Handle return type + IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + + // Handle args + while (fpArgCnt--) + { + IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + + if (*isFinished) + return S_OK; + } + + break; + + case ELEMENT_TYPE_ARRAY: + { + IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); // Element type + if (*isFinished) + return S_OK; + + uint32_t rank; + IfFailRet(GetData(&rank)); // Get rank + if (rank) + { + uint32_t nsizes; + IfFailRet(GetData(&nsizes)); // Get # of sizes + while (nsizes--) + { + IfFailRet(GetData(NULL)); // Skip size + } + + uint32_t nlbounds; + IfFailRet(GetData(&nlbounds)); // Get # of lower bounds + while (nlbounds--) + { + IfFailRet(GetData(NULL)); // Skip lower bounds + } + } + + } + break; + + case ELEMENT_TYPE_SENTINEL: + // Should be unreachable since GetElem strips it + break; + + case ELEMENT_TYPE_INTERNAL: + IfFailRet(GetPointer(NULL)); + break; + + case ELEMENT_TYPE_GENERICINST: + if (indexToFind == currentIndex) + { + *isFinished = TRUE; + return S_OK; + } + + currentIndex++; + + IfFailRet(SkipExactlyOne()); // Skip generic type + + // Handle args + uint32_t argCnt; + IfFailRet(GetData(&argCnt)); + while (argCnt--) + { + IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + + if (*isFinished) + return S_OK; + } + + break; + } + } + + return hr; +} diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index 3dd797e4c6ea8e..d07242abc4e4ce 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -2966,9 +2966,9 @@ TypeHandle ClassLoader::CreateTypeHandleForTypeKey(TypeKey* pKey, AllocMemTracke else if (pKey->GetKind() == ELEMENT_TYPE_FNPTR) { Module *pLoaderModule = ComputeLoaderModule(pKey); + PREFIX_ASSUME(pLoaderModule != NULL); pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(NULL, Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs() + 1)); - PREFIX_ASSUME(pLoaderModule!=NULL); DWORD numArgs = pKey->GetNumArgs(); BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(FnPtrTypeDesc)) + S_SIZE_T(sizeof(TypeHandle)) * S_SIZE_T(numArgs))); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 3ea41a8e3d888f..816e99a79d2c95 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -164,6 +164,9 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("IsGenericVariable", RuntimeTypeHandle::IsGenericVariable) FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables) FCFuncElement("SatisfiesConstraints", RuntimeTypeHandle::SatisfiesConstraints) + FCFuncElement("GetArgumentTypesFromFunctionPointer", RuntimeTypeHandle::GetArgumentTypesFromFunctionPointer) + FCFuncElement("IsUnmanagedFunctionPointer", RuntimeTypeHandle::IsUnmanagedFunctionPointer) + #ifdef FEATURE_COMINTEROP FCFuncElement("AllocateComObject", RuntimeTypeHandle::AllocateComObject) #endif // FEATURE_COMINTEROP @@ -202,6 +205,7 @@ FCFuncEnd() FCFuncStart(gSignatureNative) FCFuncElement("GetSignature", SignatureNative::GetSignature) FCFuncElement("GetCustomModifiers", SignatureNative::GetCustomModifiers) + FCFuncElement("GetCallingConventionFromFunctionPointer", SignatureNative::GetCallingConventionFromFunctionPointer) FCFuncElement("CompareSig", SignatureNative::CompareSig) FCFuncEnd() diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 0cbfa4835f0343..9a42332ab93b79 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -338,7 +338,6 @@ FCIMPL1(AssemblyBaseObject*, RuntimeTypeHandle::GetAssembly, ReflectClassBaseObj } FCIMPLEND - FCIMPL1(FC_BOOL_RET, RuntimeFieldHandle::AcquiresContextFromThis, FieldDesc* pField) { CONTRACTL { @@ -876,6 +875,67 @@ FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsByRefLike, ReflectClassBaseObject *pTy } FCIMPLEND +FCIMPL1(Object *, RuntimeTypeHandle::GetArgumentTypesFromFunctionPointer, ReflectClassBaseObject *pTypeUNSAFE) +{ + CONTRACTL { + FCALL_CHECK; + PRECONDITION(CheckPointer(pTypeUNSAFE)); + } + CONTRACTL_END; + + struct + { + PTRARRAYREF retVal; + } gc; + + gc.retVal = NULL; + + REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); + TypeHandle typeHandle = refType->GetType(); + if (!typeHandle.IsFnPtrType()) + FCThrowRes(kArgumentException, W("Arg_InvalidHandle")); + + FnPtrTypeDesc* fnPtr = typeHandle.AsFnPtrType(); + + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); + { + MethodTable *pMT = CoreLibBinder::GetClass(CLASS__TYPE); + TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(pMT), ELEMENT_TYPE_SZARRAY); + DWORD cArgs = fnPtr->GetNumArgs(); + gc.retVal = (PTRARRAYREF) AllocateSzArray(arrayHandle, cArgs + 1); + + for (DWORD position = 0; position <= cArgs; position++) + { + TypeHandle typeHandle = fnPtr->GetRetAndArgTypes()[position]; + OBJECTREF refType = typeHandle.GetManagedClassObject(); + gc.retVal->SetAt(position, refType); + } + } + HELPER_METHOD_FRAME_END(); + + return OBJECTREFToObject(gc.retVal); +} +FCIMPLEND + +FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsUnmanagedFunctionPointer, ReflectClassBaseObject *pTypeUNSAFE); +{ + CONTRACTL { + FCALL_CHECK; + PRECONDITION(CheckPointer(pTypeUNSAFE)); + } + CONTRACTL_END; + + REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); + TypeHandle typeHandle = refType->GetType(); + if (!typeHandle.IsFnPtrType()) + FCThrowRes(kArgumentException, W("Arg_InvalidHandle")); + + FnPtrTypeDesc* fnPtr = typeHandle.AsFnPtrType(); + BOOL unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_UNMANAGED) == IMAGE_CEE_CS_CALLCONV_UNMANAGED; + FC_RETURN_BOOL(unmanaged); +} +FCIMPLEND + extern "C" BOOL QCALLTYPE RuntimeTypeHandle_IsVisible(QCall::TypeHandle pTypeHandle) { CONTRACTL @@ -1760,8 +1820,12 @@ FCIMPL1(INT32, RuntimeMethodHandle::GetSlot, MethodDesc *pMethod) { } FCIMPLEND -FCIMPL3(Object *, SignatureNative::GetCustomModifiers, SignatureNative* pSignatureUNSAFE, - INT32 parameter, CLR_BOOL fRequired) +FCIMPL5(Object *, SignatureNative::GetCustomModifiers, + SignatureNative* pSignatureUNSAFE, + INT32 rootSignatureParameterIndex, + CLR_BOOL fRequired, + INT32 nestedSignatureIndex, + INT32 nestedSignatureParameterIndex) { CONTRACTL { FCALL_CHECK; @@ -1779,38 +1843,54 @@ FCIMPL3(Object *, SignatureNative::GetCustomModifiers, SignatureNative* pSignatu HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); { - BYTE callConv = *(BYTE*)gc.pSig->GetCorSig(); SigTypeContext typeContext; gc.pSig->GetTypeContext(&typeContext); - MetaSig sig(gc.pSig->GetCorSig(), - gc.pSig->GetCorSigSize(), - gc.pSig->GetModule(), - &typeContext, - (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD ? MetaSig::sigField : MetaSig::sigMember); + MetaSig sig = MetaSig(gc.pSig->GetCorSig(), + gc.pSig->GetCorSigSize(), + gc.pSig->GetModule(), + &typeContext, + (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD ? MetaSig::sigField : MetaSig::sigMember); + _ASSERTE(callConv == sig.GetCallingConventionInfo()); + PRECONDITION(sig.GetCallingConvention() != IMAGE_CEE_CS_CALLCONV_FIELD || rootSignatureParameterIndex == 1); SigPointer argument(NULL, 0); - PRECONDITION(sig.GetCallingConvention() != IMAGE_CEE_CS_CALLCONV_FIELD || parameter == 1); - - if (parameter == 0) + if (rootSignatureParameterIndex == 0) { argument = sig.GetReturnProps(); } else { - for(INT32 i = 0; i < parameter; i++) + for(INT32 i = 0; i < rootSignatureParameterIndex; i++) sig.NextArg(); argument = sig.GetArgProps(); } + if (nestedSignatureIndex >= 0) + { + sig.MoveToNewSignature(argument, nestedSignatureIndex); + + if (nestedSignatureParameterIndex == 0) + { + argument = sig.GetReturnProps(); + } + else + { + for(INT32 i = 0; i < nestedSignatureParameterIndex; i++) + sig.NextArg(); + + argument = sig.GetArgProps(); + } + } + + // @todo: why is this commented out? //if (parameter < 0 || parameter > (INT32)sig.NumFixedArgs()) // FCThrowResVoid(kArgumentNullException, W("Arg_ArgumentOutOfRangeException")); SigPointer sp = argument; - Module* pModule = sig.GetModule(); INT32 cMods = 0; CorElementType cmodType; @@ -1842,6 +1922,7 @@ FCIMPL3(Object *, SignatureNative::GetCustomModifiers, SignatureNative* pSignatu // modifiers now that we know how long they should be. sp = argument; + Module* pModule = sig.GetModule(); MethodTable *pMT = CoreLibBinder::GetClass(CLASS__TYPE); TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(pMT), ELEMENT_TYPE_SZARRAY); @@ -1874,6 +1955,60 @@ FCIMPL3(Object *, SignatureNative::GetCustomModifiers, SignatureNative* pSignatu } FCIMPLEND +FCIMPL3(FC_INT8_RET, SignatureNative::GetCallingConventionFromFunctionPointer, + SignatureNative* pSignatureUNSAFE, + INT32 rootSignatureParameterIndex, + INT32 nestedSignatureIndex) +{ + struct + { + SIGNATURENATIVEREF pSig; + } gc; + + gc.pSig = (SIGNATURENATIVEREF)pSignatureUNSAFE; + BYTE retVal = 0; + + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); + { + BYTE callConv = *(BYTE*)gc.pSig->GetCorSig(); + SigTypeContext typeContext; + gc.pSig->GetTypeContext(&typeContext); + MetaSig sig = MetaSig(gc.pSig->GetCorSig(), + gc.pSig->GetCorSigSize(), + gc.pSig->GetModule(), + &typeContext, + (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD ? MetaSig::sigField : MetaSig::sigMember); + + _ASSERTE(callConv == sig.GetCallingConventionInfo()); + PRECONDITION(sig.GetCallingConvention() != IMAGE_CEE_CS_CALLCONV_FIELD || rootSignatureParameterIndex == 1); + + SigPointer argument(NULL, 0); + + if (nestedSignatureIndex >= 0) + { + if (rootSignatureParameterIndex == 0) + { + argument = sig.GetReturnProps(); + } + else + { + for(INT32 i = 0; i < rootSignatureParameterIndex; i++) + sig.NextArg(); + + argument = sig.GetArgProps(); + } + + sig.MoveToNewSignature(argument, nestedSignatureIndex); + } + + retVal = sig.GetCallingConventionInfo() & IMAGE_CEE_CS_CALLCONV_MASK; + } + HELPER_METHOD_FRAME_END(); + + return (FC_INT8_RET)(retVal); +} +FCIMPLEND + FCIMPL1(INT32, RuntimeMethodHandle::GetMethodDef, ReflectMethodObject *pMethodUNSAFE) { CONTRACTL { FCALL_CHECK; @@ -1975,6 +2110,7 @@ FCIMPL6(void, SignatureNative::GetSignature, pMethod, declType.GetClassOrArrayInstantiation(), pMethod->LoadMethodInstantiation(), &typeContext); else SigTypeContext::InitTypeContext(declType, &typeContext); + MetaSig msig(pCorSig, cCorSig, pModule, &typeContext, (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD ? MetaSig::sigField : MetaSig::sigMember); diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 2db8a56288fc37..4255184a6de3b2 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - - #ifndef _RUNTIMEHANDLES_H_ #define _RUNTIMEHANDLES_H_ @@ -138,6 +136,9 @@ class RuntimeTypeHandle { static FCDECL1(FC_BOOL_RET, IsInterface, ReflectClassBaseObject* pType); static FCDECL1(FC_BOOL_RET, IsByRefLike, ReflectClassBaseObject* pType); + static FCDECL1(Object *, GetArgumentTypesFromFunctionPointer, ReflectClassBaseObject *pTypeUNSAFE); + static FCDECL1(FC_BOOL_RET, IsUnmanagedFunctionPointer, ReflectClassBaseObject *pTypeUNSAFE); + static FCDECL2(FC_BOOL_RET, CanCastTo, ReflectClassBaseObject *pType, ReflectClassBaseObject *pTarget); static FCDECL2(FC_BOOL_RET, IsInstanceOfType, ReflectClassBaseObject *pType, Object *object); @@ -373,9 +374,20 @@ class SignatureNative : public Object PCCOR_SIGNATURE pCorSig, DWORD cCorSig, FieldDesc *pFieldDesc, ReflectMethodObject *pMethodUNSAFE, ReflectClassBaseObject *pDeclaringType); - static FCDECL3(Object *, GetCustomModifiers, SignatureNative* pSig, INT32 parameter, CLR_BOOL fRequired); - static FCDECL2(FC_BOOL_RET, CompareSig, SignatureNative* pLhs, SignatureNative* pRhs); + static FCDECL5(Object *, GetCustomModifiers, + SignatureNative* pSig, + INT32 rootSignatureParameterIndex, + CLR_BOOL fRequired, + INT32 nestedSignatureIndex, + INT32 nestedSignatureParameterIndex); + + static FCDECL2(FC_BOOL_RET, CompareSig, SignatureNative* pLhs, SignatureNative* pRhs); + + static FCDECL3(FC_INT8_RET, GetCallingConventionFromFunctionPointer, + SignatureNative* pSig, + INT32 rootSignatureParameterIndex, + INT32 nestedSignatureIndex); BOOL HasThis() { LIMITED_METHOD_CONTRACT; return (m_managedCallingConvention & CALLCONV_HasThis); } INT32 NumFixedArgs() { WRAPPER_NO_CONTRACT; return m_PtrArrayarguments->GetNumComponents(); } @@ -556,4 +568,3 @@ class ReflectionPointer : public Object }; #endif - diff --git a/src/coreclr/vm/sigformat.cpp b/src/coreclr/vm/sigformat.cpp index 52ac7f9ad3192c..e76a198bd71534 100644 --- a/src/coreclr/vm/sigformat.cpp +++ b/src/coreclr/vm/sigformat.cpp @@ -545,12 +545,11 @@ void SigFormat::AddType(TypeHandle th) AddType(pRetAndArgTypes[i+1]); if (i != (cArgs - 1)) - AddString(", "); + AddString(", "); } if ((pTD->GetCallConv() & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG) { AddString(", "); - AddString("..."); } AddString(")"); diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index c35e9148fec355..9e11fbdce41bae 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -615,9 +615,7 @@ void MetaSig::Init( } } - m_pStart = psig; - m_flags = 0; // Reset the iterator fields @@ -661,7 +659,7 @@ MetaSig::MetaSig(MethodDesc *pMD, Instantiation classInst, Instantiation methodI DWORD cbSigSize; pMD->GetSig(&pSig, &cbSigSize); - Init(pSig, cbSigSize, pMD->GetModule(),&typeContext); + Init(pSig, cbSigSize, pMD->GetModule(), &typeContext); if (pMD->RequiresInstArg()) SetHasParamTypeArg(); @@ -682,7 +680,7 @@ MetaSig::MetaSig(MethodDesc *pMD, TypeHandle declaringType) DWORD cbSigSize; pMD->GetSig(&pSig, &cbSigSize); - Init(pSig, cbSigSize, pMD->GetModule(),&typeContext); + Init(pSig, cbSigSize, pMD->GetModule(), &typeContext); if (pMD->RequiresInstArg()) SetHasParamTypeArg(); @@ -865,6 +863,42 @@ MetaSig::SkipArg() } } +//--------------------------------------------------------------------------------------- +// +// Move to the specified signature in a type tree. +HRESULT +MetaSig::MoveToNewSignature(SigPointer start, INT32 index) +{ + CONTRACTL + { + INSTANCE_CHECK; + NOTHROW; + MODE_ANY; + GC_NOTRIGGER; + FORBID_FAULT; + SUPPORTS_DAC; + } + CONTRACTL_END + + m_pLastType = m_pWalk; + + HRESULT hr = start.MoveToNewSignature(index); + if (FAILED(hr)) + { + m_pWalk = m_pLastType; + return hr; + } + + SigTypeContext typeContext = m_typeContext; + + PCCOR_SIGNATURE pSig; + uint32_t cbSigSize; + start.GetSignature(&pSig, &cbSigSize); + + Init(pSig, cbSigSize, m_pModule, &typeContext, sigMember); + return hr; +} + //--------------------------------------------------------------------------------------- // // reset: goto start pos @@ -1481,9 +1515,9 @@ TypeHandle SigPointer::GetTypeHandleThrowing( { if (TypeFromToken(typeToken) == mdtTypeRef) { - loadedType = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_VOID)); - thRet = loadedType; - break; + loadedType = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_VOID)); + thRet = loadedType; + break; } } @@ -1535,8 +1569,8 @@ TypeHandle SigPointer::GetTypeHandleThrowing( pZapSigContext); if (elemType.IsNull()) { - thRet = elemType; - break; + thRet = elemType; + break; } uint32_t rank = 0; @@ -1547,7 +1581,7 @@ TypeHandle SigPointer::GetTypeHandleThrowing( _ASSERTE(0 < rank); } thRet = ClassLoader::LoadArrayTypeThrowing(elemType, typ, rank, fLoadTypes, level); - break; + break; } case ELEMENT_TYPE_PINNED: @@ -1559,7 +1593,7 @@ TypeHandle SigPointer::GetTypeHandleThrowing( dropGenericArgumentLevel, pSubst, pZapSigContext); - break; + break; case ELEMENT_TYPE_BYREF: case ELEMENT_TYPE_PTR: @@ -1577,69 +1611,91 @@ TypeHandle SigPointer::GetTypeHandleThrowing( } else { - thRet = ClassLoader::LoadPointerOrByrefTypeThrowing(typ, baseType, fLoadTypes, level); + thRet = ClassLoader::LoadPointerOrByrefTypeThrowing(typ, baseType, fLoadTypes, level); } - break; + break; } case ELEMENT_TYPE_FNPTR: - { + { #ifndef DACCESS_COMPILE - uint32_t uCallConv = 0; - IfFailThrowBF(psig.GetData(&uCallConv), BFA_BAD_SIGNATURE, pOrigModule); + uint32_t uCallConv = 0; + IfFailThrowBF(psig.GetData(&uCallConv), BFA_BAD_SIGNATURE, pOrigModule); - if ((uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD) - THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_A_FIELD, pOrigModule); + if ((uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD) + THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_A_FIELD, pOrigModule); - if ((uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) > 0) - THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_GENERIC, pOrigModule); + if ((uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) > 0) + THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_GENERIC, pOrigModule); - // Get arg count; - uint32_t cArgs = 0; - IfFailThrowBF(psig.GetData(&cArgs), BFA_BAD_SIGNATURE, pOrigModule); + // Get the arg count. + uint32_t cArgs = 0; + IfFailThrowBF(psig.GetData(&cArgs), BFA_BAD_SIGNATURE, pOrigModule); - uint32_t cAllocaSize; - if (!ClrSafeInt::addition(cArgs, 1, cAllocaSize) || - !ClrSafeInt::multiply(cAllocaSize, sizeof(TypeHandle), cAllocaSize)) - { - ThrowHR(COR_E_OVERFLOW); - } + uint32_t cAllocaSize; + if (!ClrSafeInt::addition(cArgs, 1, cAllocaSize) || + !ClrSafeInt::multiply(cAllocaSize, sizeof(TypeHandle), cAllocaSize)) + { + ThrowHR(COR_E_OVERFLOW); + } - TypeHandle *retAndArgTypes = (TypeHandle*) _alloca(cAllocaSize); - bool fReturnTypeOrParameterNotLoaded = false; + TypeHandle *retAndArgTypes = (TypeHandle*) _alloca(cAllocaSize); + bool fReturnTypeOrParameterNotLoaded = false; - for (unsigned i = 0; i <= cArgs; i++) + SigPointer psigModReread = psig; + for (unsigned i = 0; i <= cArgs; i++) + { + // A runtime function pointer should only have an unmanaged\managed status, and not + // the specific unmanaged CALLCONV_ value. + switch (uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) { - retAndArgTypes[i] = psig.GetTypeHandleThrowing(pOrigModule, - pTypeContext, - fLoadTypes, - level, - dropGenericArgumentLevel, - pSubst, - pZapSigContext); - if (retAndArgTypes[i].IsNull()) - { - thRet = TypeHandle(); - fReturnTypeOrParameterNotLoaded = true; - break; - } - - IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule); + case IMAGE_CEE_CS_CALLCONV_C: + case IMAGE_CEE_CS_CALLCONV_STDCALL: + case IMAGE_CEE_CS_CALLCONV_THISCALL: + case IMAGE_CEE_CS_CALLCONV_FASTCALL: + // Strip the calling convention. + uCallConv &= ~IMAGE_CEE_CS_CALLCONV_MASK; + // Treat as unmanaged. + uCallConv |= IMAGE_CEE_CS_CALLCONV_UNMANAGED; } - if (fReturnTypeOrParameterNotLoaded) + // Lookup type handle. + retAndArgTypes[i] = psig.GetTypeHandleThrowing(pOrigModule, + pTypeContext, + fLoadTypes, + level, + dropGenericArgumentLevel, + pSubst, + pZapSigContext); + + if (retAndArgTypes[i].IsNull()) { + thRet = TypeHandle(); + fReturnTypeOrParameterNotLoaded = true; break; } - // Now make the function pointer type - thRet = ClassLoader::LoadFnptrTypeThrowing((BYTE) uCallConv, cArgs, retAndArgTypes, fLoadTypes, level); + IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule); + } + + if (fReturnTypeOrParameterNotLoaded) + { + break; + } + + // Find an existing function pointer or make a new one + thRet = ClassLoader::LoadFnptrTypeThrowing( + (BYTE) uCallConv, + cArgs, + retAndArgTypes, + fLoadTypes, + level); #else DacNotImpl(); - thRet = TypeHandle(); + thRet = TypeHandle(); #endif break; - } + } case ELEMENT_TYPE_INTERNAL : { diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index 585fdb2071ef19..9fae45472dc760 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -570,6 +570,12 @@ class MetaSig //------------------------------------------------------------------ void SkipArg(); + //------------------------------------------------------------------ + // Move to the specified new signature in a type tree and + // re-initialize. + //------------------------------------------------------------------ + HRESULT MoveToNewSignature(SigPointer start, INT32 index); + //------------------------------------------------------------------ // Returns a read-only SigPointer for the m_pLastType set by one // of NextArg() or SkipArg() diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index 08b65beacc3b34..fe69f958dd4db8 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -507,6 +507,47 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject() #endif // #ifndef DACCESS_COMPILE +#ifndef DACCESS_COMPILE + +OBJECTREF FnPtrTypeDesc::GetManagedClassObject() +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + + INJECT_FAULT(COMPlusThrowOM()); + + PRECONDITION(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR); + } + CONTRACTL_END; + + if (m_hExposedClassObject == NULL) { + REFLECTCLASSBASEREF refClass = NULL; + GCPROTECT_BEGIN(refClass); + refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass); + + LoaderAllocator *pLoaderAllocator = GetLoaderAllocator(); + TypeHandle th = TypeHandle(this); + ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th); + ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject()); + + // Let all threads fight over who wins using InterlockedCompareExchange. + // Only the winner can set m_hExposedClassObject from NULL. + LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass); + + if (InterlockedCompareExchangeT(&m_hExposedClassObject, hExposedClassObject, static_cast(NULL))) + { + pLoaderAllocator->FreeHandle(hExposedClassObject); + } + + GCPROTECT_END(); + } + return GetManagedClassObjectIfExists(); +} + +#endif // #ifndef DACCESS_COMPILE + BOOL TypeDesc::IsRestored() { STATIC_CONTRACT_NOTHROW; diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index c4a0a83043e593..fe228deedd30be 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -3,10 +3,7 @@ // // File: typedesc.h // - - // - // // ============================================================================ @@ -25,7 +22,7 @@ class TypeHandleList; ParamTypeDescs only include byref, array and pointer types. They do NOT - include instantaitions of generic types, which are represented by MethodTables. + include instantiations of generic types, which are represented by MethodTables. */ @@ -43,7 +40,7 @@ class TypeDesc #endif // This is the ELEMENT_TYPE* that would be used in the type sig for this type - // For enums this is the uderlying type + // For enums this is the underlying type inline CorElementType GetInternalCorElementType() { LIMITED_METHOD_DAC_CONTRACT; @@ -543,7 +540,36 @@ class FnPtrTypeDesc : public TypeDesc void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); #endif //DACCESS_COMPILE + OBJECTREF GetManagedClassObject(); + + OBJECTREF GetManagedClassObjectIfExists() + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + OBJECTREF objRet = NULL; + GET_LOADERHANDLE_VALUE_FAST(GetLoaderAllocator(), m_hExposedClassObject, &objRet); + return objRet; + } + + OBJECTREF GetManagedClassObjectFast() + { + LIMITED_METHOD_CONTRACT; + + OBJECTREF objRet = NULL; + LoaderAllocator::GetHandleValueFast(m_hExposedClassObject, &objRet); + return objRet; + } + protected: + // Handle back to the internal reflection Type object + LOADERHANDLE m_hExposedClassObject; + // Number of arguments DWORD m_NumArgs; diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index e3834add43d654..17c7790dfaf10b 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -1156,8 +1156,7 @@ OBJECTREF TypeHandle::GetManagedClassObject() const return ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObject(); case ELEMENT_TYPE_FNPTR: - // A function pointer is mapped into typeof(IntPtr). It results in a loss of information. - return CoreLibBinder::GetElementType(ELEMENT_TYPE_I)->GetManagedClassObject(); + return ((FnPtrTypeDesc*)AsTypeDesc())->GetManagedClassObject(); default: _ASSERTE(!"Bad Element Type"); diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h index 037bc10205e17b..38251e8d9cbe35 100644 --- a/src/coreclr/vm/typehandle.h +++ b/src/coreclr/vm/typehandle.h @@ -486,6 +486,8 @@ class TypeHandle // PTR BOOL IsPointer() const; + BOOL IsUnmanagedFunctionPointer() const; + // True if this type *is* a formal generic type parameter or any component of it is a formal generic type parameter BOOL ContainsGenericVariables(BOOL methodOnly=FALSE) const; diff --git a/src/coreclr/vm/typehandle.inl b/src/coreclr/vm/typehandle.inl index bd98e25ab0e231..dca823aff6d161 100644 --- a/src/coreclr/vm/typehandle.inl +++ b/src/coreclr/vm/typehandle.inl @@ -265,8 +265,7 @@ FORCEINLINE OBJECTREF TypeHandle::GetManagedClassObjectFast() const break; case ELEMENT_TYPE_FNPTR: - // A function pointer is mapped into typeof(IntPtr). It results in a loss of information. - o = CoreLibBinder::GetElementType(ELEMENT_TYPE_I)->GetManagedClassObjectIfExists(); + o = dac_cast(AsTypeDesc())->GetManagedClassObjectFast(); break; default: diff --git a/src/coreclr/vm/typekey.h b/src/coreclr/vm/typekey.h index 57044cc5f7aaaf..2d42a92613895d 100644 --- a/src/coreclr/vm/typekey.h +++ b/src/coreclr/vm/typekey.h @@ -142,7 +142,7 @@ class TypeKey SUPPORTS_DAC; } CONTRACTL_END; - if (m_kind == ELEMENT_TYPE_CLASS) + if (m_kind == ELEMENT_TYPE_CLASS || m_kind == ELEMENT_TYPE_FNPTR) return PTR_Module(u.asClass.m_pModule); else if (CorTypeInfo::IsModifier_NoThrow(m_kind) || m_kind == ELEMENT_TYPE_VALUETYPE) return GetElementType().GetModule(); diff --git a/src/coreclr/vm/typestring.cpp b/src/coreclr/vm/typestring.cpp index 0a05972721a1a2..88550d898378a8 100644 --- a/src/coreclr/vm/typestring.cpp +++ b/src/coreclr/vm/typestring.cpp @@ -223,6 +223,36 @@ HRESULT TypeNameBuilder::AddName(LPCWSTR szName, LPCWSTR szNamespace) return hr; } +HRESULT TypeNameBuilder::AddNameNoEscaping(LPCWSTR szName) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!szName) + return Fail(); + + if (!CheckParseState(ParseStateSTART | ParseStateNAME)) + return Fail(); + + HRESULT hr = S_OK; + + m_parseState = ParseStateNAME; + + if (m_bNestedName) + Append(W('+')); + + m_bNestedName = TRUE; + + Append(szName); + + return hr; +} + HRESULT TypeNameBuilder::OpenGenericArguments() { WRAPPER_NO_CONTRACT; @@ -760,8 +790,48 @@ void TypeString::AppendType(TypeNameBuilder& tnb, TypeHandle ty, Instantiation t // ...or function pointer else if (ty.IsFnPtrType()) { - // Don't attempt to format this currently, it may trigger GC due to fixups. - tnb.AddName(W("(fnptr)")); + // Currently function pointers return NULL for FullName and AssemblyQualifiedName and "" for Name. + // We need a grammar update in order to support parsing. + // See https://learn.microsoft.com/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names + if (format & FormatNamespace) + { + FnPtrTypeDesc* fnPtr = ty.AsFnPtrType(); + TypeHandle *retAndArgTypes = fnPtr->GetRetAndArgTypesPointer(); + + StackSString ss; + AppendType(ss, retAndArgTypes[0], format); + + SString ssOpening(SString::Literal, "("); + ss += ssOpening; + + SString ssComma(SString::Literal, ", "); + DWORD cArgs = fnPtr->GetNumArgs(); + for (DWORD i = 1; i <= cArgs; i++) + { + if (i != 1) + ss += ssComma; + + AppendType(ss, retAndArgTypes[i], format); + } + + if ((fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG) + { + if (cArgs) + ss += ssComma; + + SString ssEllipsis(SString::Literal, "..."); + ss += ssEllipsis; + } + + SString ssClosing(SString::Literal, ")"); + ss += ssClosing; + + tnb.AddNameNoEscaping(ss); + } + else + { + tnb.AddNameNoEscaping(W("")); + } } // ...otherwise it's just a plain type def or an instantiated type diff --git a/src/coreclr/vm/typestring.h b/src/coreclr/vm/typestring.h index f003984633c35e..0fdca90c389a4d 100644 --- a/src/coreclr/vm/typestring.h +++ b/src/coreclr/vm/typestring.h @@ -43,6 +43,7 @@ class TypeNameBuilder HRESULT CloseGenericArgument(); HRESULT AddName(LPCWSTR szName); HRESULT AddName(LPCWSTR szName, LPCWSTR szNamespace); + HRESULT AddNameNoEscaping(LPCWSTR szName); HRESULT AddPointer(); HRESULT AddByRef(); HRESULT AddSzArray(); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs b/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs new file mode 100644 index 00000000000000..b9af7cde22a332 --- /dev/null +++ b/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using System.Reflection.Tests; +using System.Runtime.CompilerServices; +using Xunit; + +namespace System.Tests.Types +{ + public partial class FunctionPointerTests + { + [Theory] + [InlineData(true)] + [InlineData(false)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestManagedCallingConvention(bool modified) + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(nameof(FunctionPointerHolder.MethodCallConv_Managed), Bindings); + Type fnPtrType = modified ? m.GetParameters()[0].ParameterType : m.GetParameters()[0].GetModifiedParameterType(); + + Type[] callConvs = fnPtrType.GetFunctionPointerCallingConventions(); + Assert.Equal(0, callConvs.Length); + Assert.False(fnPtrType.IsUnmanagedFunctionPointer); + + Type returnType = fnPtrType.GetFunctionPointerReturnType(); + Assert.Equal(0, returnType.GetOptionalCustomModifiers().Length); + Assert.Equal(0, returnType.GetRequiredCustomModifiers().Length); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl))] + [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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestUnmanagedCallConv_Param_Unmodified(string methodName) + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(methodName, Bindings); + + Type fnPtrType = m.GetParameters()[0].ParameterType; + Assert.True(fnPtrType.IsUnmanagedFunctionPointer); + Assert.Equal(0, fnPtrType.GetFunctionPointerReturnType().GetOptionalCustomModifiers().Length); + Assert.Equal(0, fnPtrType.GetFunctionPointerReturnType().GetRequiredCustomModifiers().Length); + Assert.Equal(0, fnPtrType.GetFunctionPointerCallingConventions().Length); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), typeof(CallConvCdecl))] + [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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestUnmanagedCallConv_Param_Modified(string methodName, Type callingConventionRuntime) + { + Type callingConvention = callingConventionRuntime.Project(); + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(methodName, Bindings); + + Type fnPtrType = m.GetParameters()[0].GetModifiedParameterType(); + Assert.True(fnPtrType.IsUnmanagedFunctionPointer); + Assert.Equal(0, fnPtrType.GetFunctionPointerReturnType().GetOptionalCustomModifiers().Length); + Assert.Equal(0, fnPtrType.GetFunctionPointerReturnType().GetRequiredCustomModifiers().Length); + Type[] callConvs = fnPtrType.GetFunctionPointerCallingConventions(); + Assert.Equal(1, callConvs.Length); + Assert.Equal(callingConvention, callConvs[0]); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestUnmanagedCallConvs_Return_Unmodified() + { + Type t = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.MethodUnmanagedReturnValue_DifferentCallingConventions1), Bindings); + Type fcnPtr1 = m1.ReturnType; + Assert.True(fcnPtr1.IsUnmanagedFunctionPointer); + + MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.MethodUnmanagedReturnValue_DifferentCallingConventions2), Bindings); + Type fcnPtr2 = m2.ReturnType; + Assert.True(fcnPtr2.IsUnmanagedFunctionPointer); + + Assert.Equal(0, fcnPtr1.GetFunctionPointerCallingConventions().Length); + Assert.Equal(0, fcnPtr2.GetFunctionPointerCallingConventions().Length); + + // Assert.Same(fcnPtr1, fcnPtr2); NOT TRUE FOR MLC + Assert.True(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestUnmanagedCallConvs_Return_Modified() + { + Type t = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.MethodUnmanagedReturnValue_DifferentCallingConventions1), Bindings); + Type fcnPtr1 = m1.ReturnParameter.GetModifiedParameterType(); + Assert.True(fcnPtr1.IsUnmanagedFunctionPointer); + + MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.MethodUnmanagedReturnValue_DifferentCallingConventions2), Bindings); + Type fcnPtr2 = m2.ReturnParameter.GetModifiedParameterType(); + Assert.True(fcnPtr2.IsUnmanagedFunctionPointer); + + Assert.NotSame(fcnPtr1, fcnPtr2); + Assert.False(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); + + Type retType = fcnPtr1.GetFunctionPointerReturnType(); + Assert.True(typeof(int).Project().IsFunctionPointerEqual(retType.UnderlyingSystemType)); + + Type[] modOpts = fcnPtr1.GetFunctionPointerReturnType().GetOptionalCustomModifiers(); + Assert.Equal(2, modOpts.Length); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl_SuppressGCTransition))] + [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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestUnmanagedCallConv_PhysicalModifiers_Unmodified(string methodName) + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(methodName, Bindings); + + Type fnPtrType = m.GetParameters()[0].ParameterType; + Assert.True(fnPtrType.IsUnmanagedFunctionPointer); + + Assert.Equal(0, fnPtrType.GetFunctionPointerCallingConventions().Length); + Assert.Equal(0, fnPtrType.GetOptionalCustomModifiers().Length); + Assert.Equal(0, fnPtrType.GetRequiredCustomModifiers().Length); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl_SuppressGCTransition), typeof(CallConvCdecl))] + [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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestUnmanagedCallConv_PhysicalModifiers_Modified(string methodName, Type callingConventionRuntime) + { + Type suppressGcTransitionType = typeof(CallConvSuppressGCTransition).Project(); + Type callingConvention = callingConventionRuntime.Project(); + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(methodName, Bindings); + + Type fnPtrType = m.GetParameters()[0].GetModifiedParameterType(); + Assert.True(fnPtrType.IsUnmanagedFunctionPointer); + + Type[] callConvs = fnPtrType.GetFunctionPointerCallingConventions(); + Assert.Equal(2, callConvs.Length); + Assert.Equal(suppressGcTransitionType, callConvs[0]); + Assert.Equal(callingConvention, callConvs[1]); + + Type returnType = fnPtrType.GetFunctionPointerReturnType(); + Assert.Equal(2, returnType.GetOptionalCustomModifiers().Length); + Assert.Equal(suppressGcTransitionType, returnType.GetOptionalCustomModifiers()[0]); + Assert.Equal(callingConvention, returnType.GetOptionalCustomModifiers()[1]); + Assert.Equal(0, returnType.GetRequiredCustomModifiers().Length); + } + + public unsafe partial class FunctionPointerHolder + { + public delegate* unmanaged[Cdecl, MemberFunction] MethodUnmanagedReturnValue_DifferentCallingConventions1() => default; + public delegate* unmanaged[Stdcall, MemberFunction] MethodUnmanagedReturnValue_DifferentCallingConventions2() => default; + + // Methods to verify calling conventions and synthesized modopts. + // The non-SuppressGCTransition variants are encoded with the CallKind byte. + // The SuppressGCTransition variants are encoded as modopts (CallKind is "Unmananged"). + public void MethodCallConv_Managed(delegate* managed f) { } + public void MethodCallConv_Cdecl(delegate* unmanaged[Cdecl] f) { } + public void MethodCallConv_Cdecl_SuppressGCTransition(delegate* unmanaged[Cdecl, SuppressGCTransition] f) { } + public void MethodCallConv_Stdcall(delegate* unmanaged[Stdcall] f) { } + public void MethodCallConv_Stdcall_SuppressGCTransition(delegate* unmanaged[Stdcall, SuppressGCTransition] f) { } + public void MethodCallConv_Thiscall(delegate* unmanaged[Thiscall] f) { } + public void MethodCallConv_Thiscall_SuppressGCTransition(delegate* unmanaged[Thiscall, SuppressGCTransition] f) { } + public void MethodCallConv_Fastcall(delegate* unmanaged[Fastcall] f) { } + public void MethodCallConv_Fastcall_SuppressGCTransition(delegate* unmanaged[Fastcall, SuppressGCTransition] f) { } + } + } +} diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs b/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs new file mode 100644 index 00000000000000..325e4b3a64e18e --- /dev/null +++ b/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using System.Reflection.Tests; +using Xunit; + +namespace System.Tests.Types +{ + // Also see ModifiedTypeTests which tests custom modifiers. + // Unmodified Type instances are cached and keyed by the runtime. + // Modified Type instances are created for each member. + public partial class FunctionPointerTests + { + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionUnmanagedPointerReturn_DifferentReturnValue() + { + Type t = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.MethodUnmanagedReturnValue1), Bindings); + Type fcnPtr1 = m1.ReturnType; + Assert.True(fcnPtr1.IsFunctionPointer); + + MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.MethodUnmanagedReturnValue2), Bindings); + Type fcnPtr2 = m2.ReturnType; + Assert.True(fcnPtr2.IsFunctionPointer); + Assert.False(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.Field_Int), nameof(FunctionPointerHolder.Field_DateOnly))] + [InlineData(nameof(FunctionPointerHolder.Field_DateOnly), nameof(FunctionPointerHolder.Field_Int))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestSigEqualityInDifferentModule_Field(string name, string otherName) + { + Type fph1 = typeof(FunctionPointerHolder).Project(); + Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); + Assert.True(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph2, name))); + + // Verify other combinations fail + Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); + Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); + Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); + Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); + + static Type GetFuncPtr(Type owner, string name) => owner.GetField(name, Bindings).FieldType; + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.Prop_Int), nameof(FunctionPointerHolder.Prop_DateOnly))] + [InlineData(nameof(FunctionPointerHolder.Prop_DateOnly), nameof(FunctionPointerHolder.Prop_Int))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestSigEqualityInDifferentModule_Property(string name, string otherName) + { + Type fph1 = typeof(FunctionPointerHolder).Project(); + Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); + Assert.True(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph2, name))); + + // Verify other combinations fail + Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); + Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); + Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); + Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); + + static Type GetFuncPtr(Type owner, string name) => owner.GetProperty(name, Bindings).PropertyType; + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodReturnValue_Int), nameof(FunctionPointerHolder.MethodReturnValue_DateOnly))] + [InlineData(nameof(FunctionPointerHolder.MethodReturnValue_DateOnly), nameof(FunctionPointerHolder.MethodReturnValue_Int))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestSigEqualityInDifferentModule_MethodReturn(string name, string otherName) + { + Type fph1 = typeof(FunctionPointerHolder).Project(); + Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); + Assert.True(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph2, name))); + + // Verify other combinations fail + Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); + Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); + Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); + Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); + + static Type GetFuncPtr(Type owner, string name) => owner.GetMethod(name, Bindings).ReturnParameter.ParameterType; + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Cdecl_SuppressGCTransition))] + [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/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void CallingConventionIdentity_Unmodified(string methodName1, string methodName2) + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m1 = t.GetMethod(methodName1, Bindings); + MethodInfo m2 = t.GetMethod(methodName2, Bindings); + + Type fnPtrType1 = m1.GetParameters()[0].ParameterType; + Type fnPtrType2 = m2.GetParameters()[0].ParameterType; + + Assert.True(fnPtrType1.IsFunctionPointerEqual(fnPtrType2)); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Cdecl_SuppressGCTransition))] + [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/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void CallingConventionIdentity_Modified(string methodName1, string methodName2) + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m1 = t.GetMethod(methodName1, Bindings); + MethodInfo m2 = t.GetMethod(methodName2, Bindings); + + Type fnPtrType1 = m1.GetParameters()[0].GetModifiedParameterType(); + Type fnPtrType2 = m2.GetParameters()[0].GetModifiedParameterType(); + + Assert.True(fnPtrType1.IsFunctionPointerNotEqual(fnPtrType2)); + } + } +} diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs new file mode 100644 index 00000000000000..efc096d77f0e20 --- /dev/null +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -0,0 +1,319 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using System.Reflection; +using System.Reflection.Tests; +using Xunit; + +namespace System.Tests.Types +{ + // Also see ModifiedTypeTests which tests custom modifiers. + public partial class FunctionPointerTests + { + 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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestTypeMembers() + { + // Get an arbitrary function pointer + TypeInfo t = (TypeInfo)typeof(FunctionPointerHolder).Project().GetField(nameof(FunctionPointerHolder.ToString_1), Bindings).FieldType; + + // Function pointer relevant members: + Assert.Equal("System.Void()", t.ToString()); + Assert.Null(t.FullName); + Assert.Null(t.AssemblyQualifiedName); + Assert.Equal(string.Empty, t.Name); + Assert.Null(t.Namespace); + Assert.True(t.IsFunctionPointer); + Assert.False(t.IsPointer); // A function pointer is not compatible with IsPointer semantics. + Assert.False(t.IsUnmanagedFunctionPointer); + + // Common for all function pointers: + Assert.NotNull(t.Assembly); + Assert.Equal(TypeAttributes.Public, t.Attributes); + Assert.Null(t.BaseType); + Assert.False(t.ContainsGenericParameters); + Assert.False(t.ContainsGenericParameters); + Assert.False(t.DeclaredConstructors.Any()); + Assert.False(t.DeclaredEvents.Any()); + Assert.False(t.DeclaredFields.Any()); + Assert.False(t.DeclaredMembers.Any()); + Assert.False(t.DeclaredMethods.Any()); + Assert.False(t.DeclaredNestedTypes.Any()); + Assert.False(t.DeclaredProperties.Any()); + Assert.Null(t.DeclaringType); + Assert.Equal(Guid.Empty, t.GUID); + Assert.Throws(() => t.GenericParameterAttributes); + Assert.Throws(() => t.GenericParameterPosition); + Assert.Equal(0, t.GenericTypeArguments.Length); + Assert.Equal(0, t.GenericTypeParameters.Length); + Assert.False(t.HasElementType); + Assert.False(t.IsAbstract); + Assert.True(t.IsAnsiClass); + Assert.False(t.IsArray); + Assert.False(t.IsAutoClass); + Assert.True(t.IsAutoLayout); + Assert.False(t.IsByRef); + Assert.False(t.IsByRefLike); + Assert.False(t.IsCOMObject); + Assert.True(t.IsClass); + Assert.False(t.IsAbstract); + Assert.False(t.IsConstructedGenericType); + Assert.False(t.IsContextful); + Assert.False(t.IsEnum); + Assert.False(t.IsExplicitLayout); + Assert.False(t.IsGenericMethodParameter); + Assert.False(t.IsGenericParameter); + Assert.False(t.IsGenericType); + Assert.False(t.IsGenericTypeDefinition); + Assert.False(t.IsGenericTypeParameter); + Assert.False(t.IsImport); + Assert.False(t.IsInterface); + Assert.False(t.IsLayoutSequential); + Assert.False(t.IsMarshalByRef); + Assert.False(t.IsNested); + Assert.False(t.IsNestedAssembly); + Assert.False(t.IsNestedFamANDAssem); + Assert.False(t.IsNestedFamORAssem); + Assert.False(t.IsNestedFamily); + Assert.False(t.IsNestedPrivate); + Assert.False(t.IsNestedPublic); + Assert.False(t.IsNotPublic); + Assert.False(t.IsPrimitive); + Assert.True(t.IsPublic); + Assert.False(t.IsSZArray); + Assert.False(t.IsSealed); + + if (FunctionPointerTestsExtensions.IsMetadataLoadContext) + { + Assert.Throws(() => t.IsSecurityCritical); + Assert.Throws(() => t.IsSecuritySafeCritical); + Assert.Throws(() => t.IsSecurityTransparent); + } + else + { + Assert.True(t.IsSecurityCritical); + Assert.False(t.IsSecuritySafeCritical); + Assert.False(t.IsSecurityTransparent); + } + + Assert.False(t.IsSerializable); + Assert.False(t.IsSignatureType); + Assert.False(t.IsSpecialName); + Assert.False(t.IsTypeDefinition); + Assert.False(t.IsUnicodeClass); + Assert.False(t.IsValueType); + Assert.False(t.IsVariableBoundArray); + Assert.True(t.IsVisible); + Assert.Equal(MemberTypes.TypeInfo, t.MemberType); + Assert.True(t.MetadataToken != 0); + Assert.NotNull(t.Module); + Assert.Null(t.ReflectedType); + Assert.Null(t.TypeInitializer); + + // Select methods + Assert.Throws(() => t.GetArrayRank()); + Assert.Null(t.GetElementType()); + } + + private static void MyMethod(){} + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestNonFunctionPointerThrows() + { + Assert.Throws(() => typeof(int).GetFunctionPointerCallingConventions()); + Assert.Throws(() => typeof(int).GetFunctionPointerParameterTypes()); + Assert.Throws(() => typeof(int).GetFunctionPointerReturnType()); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestToString() + { + // Function pointer types are inline in metadata and can't be loaded independently so they do not support the + // MetadataLoadContext Type.Project() test extension so we use fields and project on the owning class. + Assert.Equal("System.Void()", GetType(1).ToString()); // delegate* + Assert.Equal("System.Void()", GetType(2).ToString()); // delegate*unmanaged + Assert.Equal("System.Int32()", GetType(3).ToString()); // delegate* + Assert.Equal("System.Int32()*", GetType(4).ToString()); // delegate** + Assert.Equal("System.Int32()[]", GetType(5).ToString()); // delegate*[] + Assert.Equal("System.Int32()", GetType(6). + GetElementType().ToString()); // delegate*[] + Assert.Equal("System.Int32()*[]", GetType(7).ToString()); // delegate**[] + Assert.Equal("System.Int32()()", GetType(8).ToString()); // delegate*> + Assert.Equal("System.Boolean(System.String(System.Int32))", + GetType(9).ToString()); // delegate*, bool> + + Type GetType(int i) => typeof(FunctionPointerHolder).Project().GetField("ToString_" + i, Bindings).FieldType; + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerReturn() + { + Type t = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.MethodReturnValue1), Bindings); + Type fcnPtr1 = m1.ReturnType; + Assert.True(fcnPtr1.IsFunctionPointer); + + MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.MethodReturnValue2), Bindings); + Type fcnPtr2 = m2.ReturnType; + Assert.True(fcnPtr2.IsFunctionPointer); + + Assert.True(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestRequiredModifiers() + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(nameof(FunctionPointerHolder.RequiredModifiers), Bindings); + Type fcnPtr1 = m.ReturnParameter.GetModifiedParameterType(); + + Type[] parameters = fcnPtr1.GetFunctionPointerParameterTypes(); + Assert.Equal(2, parameters.Length); + Assert.Equal(1, parameters[0].GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(Runtime.InteropServices.InAttribute).Project(), parameters[0].GetRequiredCustomModifiers()[0]); + Assert.Equal(1, parameters[1].GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(Runtime.InteropServices.OutAttribute).Project(), parameters[1].GetRequiredCustomModifiers()[0]); + } + + [Theory] + [InlineData(nameof(FunctionPointerHolder.MethodReturnValue1), + "MethodReturnValue1()", + "Int32", + "System.Int32()")] + [InlineData(nameof(FunctionPointerHolder.SeveralArguments), + "SeveralArguments()", + "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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestMethodInfo( + string methodName, + string methodToStringPostfix, + string expectedFcnPtrReturnName, + string expectedFcnPtrFullName, + params string[] expectedArgNames) + { + Type t = typeof(FunctionPointerHolder).Project(); + MethodInfo m = t.GetMethod(methodName, Bindings); + Assert.Equal(expectedFcnPtrFullName + " " + methodToStringPostfix, m.ToString()); + + Type fnPtrType = m.ReturnParameter.GetModifiedParameterType(); + Assert.Null(fnPtrType.FullName); + Assert.Null(fnPtrType.AssemblyQualifiedName); + Assert.Equal("", fnPtrType.Name); + + VerifyArg(fnPtrType.GetFunctionPointerReturnType(), expectedFcnPtrReturnName); + + for (int i = 0; i < expectedArgNames.Length; i++) + { + VerifyArg(fnPtrType.GetFunctionPointerParameterTypes()[i], expectedArgNames[i]); + } + + static void VerifyArg(Type paramType, string expected) + { + Assert.Equal(expected, paramType.Name); + Assert.Null(paramType.DeclaringType); + } + } + + [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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestProperty(string name, string expectedToString) + { + Type t = typeof(FunctionPointerHolder).Project(); + PropertyInfo p = t.GetProperty(name, Bindings); + Assert.Equal(expectedToString + " " + name, p.ToString()); + + Type fnPtrType = p.PropertyType; + Assert.Equal(expectedToString, fnPtrType.ToString()); + VerifyFieldOrProperty(fnPtrType, isModified: false); + + fnPtrType = p.GetModifiedPropertyType(); + Assert.Equal(expectedToString, fnPtrType.ToString()); + VerifyFieldOrProperty(fnPtrType, isModified: true); + } + + [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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestField(string name, string expectedToString) + { + Type t = typeof(FunctionPointerHolder).Project(); + FieldInfo f = t.GetField(name, Bindings); + Assert.Equal(expectedToString + " " + name, f.ToString()); + + Type fnPtrType = f.FieldType; + Assert.Equal(expectedToString, fnPtrType.ToString()); + VerifyFieldOrProperty(fnPtrType, isModified: false); + + fnPtrType = f.GetModifiedFieldType(); + Assert.Equal(expectedToString, fnPtrType.ToString()); + VerifyFieldOrProperty(fnPtrType, isModified: true); + } + + private static void VerifyFieldOrProperty(Type fnPtrType, bool isModified) + { + Assert.Null(fnPtrType.FullName); + Assert.Null(fnPtrType.AssemblyQualifiedName); + Assert.Equal("", fnPtrType.Name); + Assert.Null(fnPtrType.DeclaringType); + Assert.Null(fnPtrType.BaseType); + Assert.Equal(Type.EmptyTypes, fnPtrType.GetFunctionPointerCallingConventions()); + Assert.Equal(Type.EmptyTypes, fnPtrType.GetFunctionPointerReturnType().GetRequiredCustomModifiers()); + } + + public unsafe partial class FunctionPointerHolder + { + public delegate* ToString_1; + public delegate*unmanaged ToString_2; + public delegate* ToString_3; + public delegate** ToString_4; + public delegate*[] ToString_5; + public delegate*[] ToString_6; + public delegate**[] ToString_7; + public delegate*> ToString_8; + public delegate*, bool> ToString_9; + + public delegate* managed Field_Int; + public delegate* managed Field_DateOnly; // Verify non-primitive + public delegate* managed Field_MyClass; + public delegate* managed Prop_Int { get; } + public delegate* managed Prop_DateOnly { get; } + public delegate* managed Prop_MyClass { get; } + public delegate* managed MethodReturnValue_Int() => default; + public delegate* managed MethodReturnValue_DateOnly() => default; + public delegate* unmanaged MethodUnmanagedReturnValue_Int() => default; + public delegate* unmanaged MethodUnmanagedReturnValue_DateOnly() => default; + + public delegate* managed MethodReturnValue1() => default; + public delegate* managed MethodReturnValue2() => default; + public delegate* unmanaged MethodUnmanagedReturnValue1() => default; + public delegate* unmanaged MethodUnmanagedReturnValue2() => default; + + public delegate* unmanaged[Stdcall, MemberFunction] SeveralArguments() => default; + public delegate* RequiredModifiers() => default; + + public class MyClass { } + public struct MyStruct { } + } + } +} diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs new file mode 100644 index 00000000000000..707218873097b2 --- /dev/null +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -0,0 +1,362 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using System.Reflection.Tests; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +namespace System.Tests.Types +{ + public partial class ModifiedTypeTests + { + 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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_Modified() + { + Type volatileInt = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings).GetModifiedFieldType(); + Verify(volatileInt); + + Type volatileIntArray = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileIntArray), Bindings).GetModifiedFieldType(); + Verify(volatileIntArray); + + Type volatileIntPointer = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileIntPointer), Bindings).GetModifiedFieldType(); + Verify(volatileIntPointer); + Type volatileIntPointerElementType = volatileIntPointer.GetElementType(); + Assert.True(IsModifiedType(volatileIntPointerElementType)); + Assert.True(ReferenceEquals(volatileIntPointerElementType.UnderlyingSystemType, typeof(int).Project())); + Assert.Equal(0, volatileIntPointerElementType.UnderlyingSystemType.GetRequiredCustomModifiers().Length); + Assert.Equal(0, volatileIntPointerElementType.UnderlyingSystemType.GetOptionalCustomModifiers().Length); + + Type volatileFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileFcnPtr), Bindings).GetModifiedFieldType(); + Verify(volatileFcnPtr); + Assert.True(IsModifiedType(volatileFcnPtr.GetFunctionPointerReturnType())); + Assert.Equal(1, volatileFcnPtr.GetFunctionPointerParameterTypes().Length); + Assert.True(IsModifiedType(volatileFcnPtr.GetFunctionPointerParameterTypes()[0])); + + void Verify(Type type) + { + Assert.True(IsModifiedType(type)); + + Assert.Equal(1, type.GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(IsVolatile).Project(), type.GetRequiredCustomModifiers()[0]); + + Assert.Equal(0, type.GetOptionalCustomModifiers().Length); + + Assert.Equal(0, type.UnderlyingSystemType.GetRequiredCustomModifiers().Length); + Assert.Equal(0, type.UnderlyingSystemType.GetOptionalCustomModifiers().Length); + } + } + + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_Generic_Unmodified() + { + Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; + Assert.True(arrayGenericFcnPtr.IsGenericType); + Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); // generic is closed + Assert.False(IsModifiedType(arrayGenericFcnPtr)); + + Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; + Assert.False(IsModifiedType(genericParam)); + + Type nestedFcnPtr = genericParam.GetElementType(); + Assert.False(IsModifiedType(nestedFcnPtr)); + + Assert.Equal(1, nestedFcnPtr.GetFunctionPointerParameterTypes().Length); + Type paramType = nestedFcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.False(IsModifiedType(paramType)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_Generic_Modified() + { + Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); + Assert.True(IsModifiedType(arrayGenericFcnPtr)); + Assert.True(arrayGenericFcnPtr.IsGenericType); + Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); // generic is closed + + Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; + Assert.True(IsModifiedType(genericParam)); + + Type nestedFcnPtr = genericParam.GetElementType(); + Assert.True(IsModifiedType(nestedFcnPtr)); + + Assert.Equal(1, nestedFcnPtr.GetFunctionPointerParameterTypes().Length); + Type paramType = nestedFcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.True(IsModifiedType(paramType)); + + Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_Unmodified() + { + Type volatileInt = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings).FieldType; + Verify(volatileInt); + + Type volatileIntArray = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileIntArray), Bindings).FieldType; + Verify(volatileIntArray); + + Type volatileIntPointer = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileIntPointer), Bindings).FieldType; + Verify(volatileIntPointer); + Type volatileIntPointerElementType = volatileIntPointer.GetElementType(); + Assert.False(IsModifiedType(volatileIntPointerElementType)); + Assert.True(ReferenceEquals(volatileIntPointerElementType, typeof(int).Project())); + Assert.Equal(0, volatileIntPointerElementType.GetRequiredCustomModifiers().Length); + Assert.Equal(0, volatileIntPointerElementType.GetOptionalCustomModifiers().Length); + + Type volatileFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileFcnPtr), Bindings).FieldType; + Verify(volatileFcnPtr); + Assert.False(IsModifiedType(volatileFcnPtr.GetFunctionPointerReturnType())); + Assert.Equal(1, volatileFcnPtr.GetFunctionPointerParameterTypes().Length); + Assert.False(IsModifiedType(volatileFcnPtr.GetFunctionPointerParameterTypes()[0])); + + void Verify(Type type) + { + Assert.False(IsModifiedType(type)); + Assert.Equal(0, type.GetRequiredCustomModifiers().Length); + Assert.Equal(0, type.GetOptionalCustomModifiers().Length); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_Nested_Basic() + { + Type ptr_ptr_int = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_ptr_int), Bindings).GetModifiedFieldType(); + Verify(ptr_ptr_int); + Assert.True(ptr_ptr_int.UnderlyingSystemType.IsPointer); + + Type array_ptr_int = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._array_ptr_int), Bindings).GetModifiedFieldType(); + Verify(array_ptr_int); + Assert.True(array_ptr_int.UnderlyingSystemType.IsArray); + + void Verify(Type type) + { + Assert.True(IsModifiedType(type)); + Assert.False(IsModifiedType(type.UnderlyingSystemType)); + Assert.True(IsModifiedType(type.GetElementType())); + Assert.Equal(typeof(int).Project(), ptr_ptr_int.GetElementType().UnderlyingSystemType.GetElementType()); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_Nested_FcnPtr() + { + Type ptr_fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_fcnPtr), Bindings).GetModifiedFieldType(); + Assert.True(ptr_fcnPtr.IsPointer); + Assert.True(IsModifiedType(ptr_fcnPtr)); + Verify(ptr_fcnPtr.GetElementType()); + + Type array_ptr_fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._array_ptr_fcnPtr), Bindings).GetModifiedFieldType(); + Assert.True(array_ptr_fcnPtr.IsArray); + Assert.True(IsModifiedType(array_ptr_fcnPtr)); + Assert.True(array_ptr_fcnPtr.GetElementType().IsPointer); + Assert.True(IsModifiedType(array_ptr_fcnPtr.GetElementType())); + Verify(array_ptr_fcnPtr.GetElementType().GetElementType()); + + Type fcnPtr_fcnPtrReturn = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrReturn), Bindings).GetModifiedFieldType(); + Assert.True(fcnPtr_fcnPtrReturn.GetFunctionPointerReturnType().IsFunctionPointer); + Assert.True(IsModifiedType(fcnPtr_fcnPtrReturn.GetFunctionPointerReturnType())); + Verify(fcnPtr_fcnPtrReturn.GetFunctionPointerReturnType()); + + void Verify(Type type) + { + Assert.True(IsModifiedType(type)); + Assert.True(type.IsFunctionPointer); + Assert.Equal(0, type.GetFunctionPointerParameterTypes().Length); + Assert.NotSame(typeof(void).Project(), type.GetFunctionPointerReturnType()); + Assert.Same(typeof(void).Project(), type.GetFunctionPointerReturnType().UnderlyingSystemType); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFields_VerifyIdempotency() + { + // Call these again to ensure any backing caching strategy works. + TestFields_Modified(); + TestFields_Unmodified(); + TestFields_Nested_Basic(); + TestFields_Nested_FcnPtr(); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestMethodParameters() + { + ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_P0IntOut), Bindings).GetParameters(); + Assert.True(IsModifiedType(parameters[0].GetModifiedParameterType())); + + parameters = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_P0FcnPtrOut), Bindings).GetParameters(); + Type[] fnParameters = parameters[0].GetModifiedParameterType().GetFunctionPointerParameterTypes(); + Assert.Equal(1, fnParameters.Length); + Assert.Equal(typeof(OutAttribute).Project(), fnParameters[0].GetRequiredCustomModifiers()[0]); + + ParameterInfo returnParameter = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.InitProperty_Int), Bindings).GetSetMethod().ReturnParameter; + Assert.Equal(1, returnParameter.GetRequiredCustomModifiers().Length); + Assert.Equal(1, returnParameter.GetModifiedParameterType().GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(IsExternalInit).Project(), returnParameter.GetModifiedParameterType().GetRequiredCustomModifiers()[0]); + + returnParameter = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr), Bindings).GetGetMethod().ReturnParameter; + Assert.True(returnParameter.ParameterType.IsFunctionPointer); + Assert.Equal(0, returnParameter.ParameterType.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); + Assert.Equal(1, returnParameter.GetModifiedParameterType().GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(OutAttribute).Project(), returnParameter.GetModifiedParameterType().GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers()[0]); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestConstructorParameters() + { + ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); + + Type param0 = parameters[0].ParameterType; + Assert.True(param0.IsFunctionPointer); + Assert.False(IsModifiedType(param0)); + Type[] mods = param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers(); + Assert.Equal(0, mods.Length); + + param0 = parameters[0].GetModifiedParameterType(); + Assert.True(param0.IsFunctionPointer); + Assert.True(IsModifiedType(param0)); + mods = param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers(); + Assert.Equal(1, mods.Length); + Assert.Equal(typeof(OutAttribute).Project(), mods[0]); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out() + { + Type fcnPtr; + + fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).GetModifiedFieldType(); + Verify(fcnPtr); + Assert.True(IsModifiedType(fcnPtr)); + Assert.Equal(typeof(int).Project().MakeByRefType(), fcnPtr.GetFunctionPointerParameterTypes()[0].UnderlyingSystemType); + + fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).FieldType; + Verify(fcnPtr); + Assert.False(IsModifiedType(fcnPtr)); + Assert.Equal(typeof(int).Project().MakeByRefType(), fcnPtr.GetFunctionPointerParameterTypes()[0]); + + void Verify(Type type) + { + Assert.True(type.IsFunctionPointer); + Assert.Equal(1, type.GetFunctionPointerParameterTypes().Length); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters__fcnPtr_fcnPtrP0Out() + { + Type fcnPtr; + Type param0; + + fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).GetModifiedFieldType(); + param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Verify(param0); + Assert.True(IsModifiedType(param0)); + Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0].UnderlyingSystemType); + Assert.Equal(1, param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(OutAttribute).Project(), param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers()[0]); + + fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).FieldType; + param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Verify(param0); + Assert.False(IsModifiedType(param0)); + Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0]); + Assert.Equal(0, param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); + + void Verify(Type type) + { + Assert.True(type.IsFunctionPointer); + Assert.Equal(1, type.GetFunctionPointerParameterTypes().Length); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref() + { + Type fcnPtr; + Type param0; + + fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).GetModifiedFieldType(); + param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Verify(param0); + Assert.True(IsModifiedType(param0)); + Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0].UnderlyingSystemType); + + fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).FieldType; + param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Verify(param0); + Assert.False(IsModifiedType(param0)); + Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0]); + + void Verify(Type type) + { + Assert.True(type.IsFunctionPointer); + Assert.Equal(1, type.GetFunctionPointerParameterTypes().Length); + } + } + + private static bool IsModifiedType(Type type) + { + return !ReferenceEquals(type, type.UnderlyingSystemType); + } + + public unsafe class ModifiedTypeHolder + { + public ModifiedTypeHolder(delegate* d) { } + + public static volatile int _volatileInt; + public static volatile int[] _volatileIntArray; + public static volatile int* _volatileIntPointer; + public static volatile delegate* unmanaged[Cdecl] _volatileFcnPtr; + + // Although function pointers can't be used in generics directly, they can be undirectly + // through an array or pointer. + public static volatile Tuple[]> _arrayGenericFcnPtr; + + public static int** _ptr_ptr_int; + public static int*[] _array_ptr_int; + public static delegate** _ptr_fcnPtr; + public static delegate**[] _array_ptr_fcnPtr; + public static delegate*> _fcnPtr_fcnPtrReturn; + + public static void M_P0IntOut(out int i) { i = 42; } + public static void M_P0FcnPtrOut(delegate* fp) { } + + public int InitProperty_Int { get; init; } + public static delegate* Property_FcnPtr { get; set; } + + public static delegate* FcnPtrP0Out { get; set; } + public static delegate* _fcnPtrP0Out; + public static delegate*, void> _fcnPtr_fcnPtrP0Out; + public static delegate*, void> _fcnPtr_fcnPtrP0Ref; + } + } +} diff --git a/src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs b/src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs new file mode 100644 index 00000000000000..0013f93e0f9abf --- /dev/null +++ b/src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Reflection; +using System.Threading; + +public unsafe class FunctionPointerHolderSeparateModule +{ + public delegate* managed Field_Int; + public delegate* managed Field_DateOnly; // Verify non-primitive which will have its own Rid + public delegate* managed Prop_Int { get; } + public delegate* managed Prop_DateOnly { get; } + public delegate* managed MethodReturnValue_Int() => default; + public delegate* managed MethodReturnValue_DateOnly() => default; + public delegate* unmanaged MethodUnmanagedReturnValue_Int() => default; + public delegate* unmanaged MethodUnmanagedReturnValue_DateOnly() => default; +} diff --git a/src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj b/src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj new file mode 100644 index 00000000000000..0a8720fa6bbdae --- /dev/null +++ b/src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj @@ -0,0 +1,11 @@ + + + true + 1.0.0.0 + $(NetCoreAppCurrent) + True + + + + + diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs index 8dc832cd3e42d9..53be5c90e30090 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs @@ -316,9 +316,9 @@ public void ToString_NullFrame_ThrowsNullReferenceException() [ActiveIssue("https://github.com/dotnet/runtime/issues/11354", TestRuntimes.Mono)] public unsafe void ToString_FunctionPointerSignature() { - // This is sepate from ToString_Invoke_ReturnsExpected since unsafe cannot be used for iterators + // This is separate from ToString_Invoke_ReturnsExpected since unsafe cannot be used for iterators var stackTrace = FunctionPointerParameter(null); - Assert.Contains("System.Diagnostics.Tests.StackTraceTests.FunctionPointerParameter(IntPtr x)", stackTrace.ToString()); + Assert.Contains("System.Diagnostics.Tests.StackTraceTests.FunctionPointerParameter(*() x)", stackTrace.ToString()); } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index dd206f893724ab..56832c3e728565 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3992,4 +3992,7 @@ The value may not contain directory separator characters. + + Method may only be called on a Type for which Type.IsFunctionPointer is true. + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 24b9d04497aa84..8887d1d994f457 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -660,11 +660,13 @@ + + @@ -675,8 +677,12 @@ - + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs index a2090f56d483a1..a544be89c423ed 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/FieldInfo.cs @@ -74,6 +74,8 @@ protected FieldInfo() { } public virtual object? GetRawConstantValue() { throw new NotSupportedException(SR.NotSupported_AbstractNonCLS); } + public virtual Type GetModifiedFieldType() => throw new NotSupportedException(); + public virtual Type[] GetOptionalCustomModifiers() { throw NotImplemented.ByDesign; } public virtual Type[] GetRequiredCustomModifiers() { throw NotImplemented.ByDesign; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs new file mode 100644 index 00000000000000..eaa3aa2be4c9a0 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + /// + /// Represents the first byte of a method signature. + /// Calling conventions have been extended into modopts for Unmanaged. + /// + [Flags] + internal enum MdSigCallingConvention : byte + { + CallConvMask = 0x0f, // Calling convention is bottom 4 bits + + Default = 0x00, + C = 0x01, + StdCall = 0x02, + ThisCall = 0x03, + FastCall = 0x04, + Vararg = 0x05, + Field = 0x06, + LocalSig = 0x07, + Property = 0x08, + Unmanaged = 0x09, + GenericInst = 0x0a, // generic method instantiation + + Generic = 0x10, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) + HasThis = 0x20, // Top bit indicates a 'this' parameter + ExplicitThis = 0x40, // This parameter is explicitly in the signature + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs new file mode 100644 index 00000000000000..9733cab76202cb --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Reflection +{ + /// + /// An array, pointer or reference type. + /// + internal sealed class ModifiedContainerType : ModifiedType + { + private readonly ModifiedType? _elementModifiedType; + + /// + /// Create a root node. + /// + public ModifiedContainerType( + Type containerType, + Type[] requiredModifiers, + Type[] optionalModifiers, + int rootSignatureParameterIndex) : base(containerType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) + { + Debug.Assert(containerType.HasElementType); + _elementModifiedType = Create(containerType.GetElementType()!, this, nestedSignatureIndex: 0, nestedSignatureParameterIndex: -1); + } + + /// + /// Create a child node. + /// + public ModifiedContainerType( + Type containerType, + ModifiedType root, + int nestedSignatureIndex, + int nestedSignatureParamterIndex) + : base(containerType, root, nestedSignatureIndex, nestedSignatureParamterIndex) + { + Debug.Assert(containerType.HasElementType); + _elementModifiedType = Create(containerType.GetElementType()!, root, nestedSignatureIndex, nestedSignatureParamterIndex); + } + + public override Type? GetElementType() => _elementModifiedType; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs new file mode 100644 index 00000000000000..20e61defcc3269 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -0,0 +1,117 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Reflection +{ + internal sealed partial class ModifiedFunctionPointerType : ModifiedType + { + private const string CallingConventionTypePrefix = "System.Runtime.CompilerServices.CallConv"; + + private readonly ModifiedType[] _parameterTypes; + private readonly ModifiedType _returnType; + private Type[]? _callingConventions; + + /// + /// Create a root node. + /// + public ModifiedFunctionPointerType( + Type functionPointerType, + Type[] requiredModifiers, + Type[] optionalModifiers, + int rootSignatureParameterIndex) + : base(functionPointerType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) + { + Debug.Assert(functionPointerType.IsFunctionPointer); + _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), this, nestedSignatureIndex: 0, nestedSignatureParameterIndex: 0); + _parameterTypes = CreateParameters(functionPointerType.GetFunctionPointerParameterTypes(), this, nestedSignatureIndex: 0); + } + + /// + /// Create a child node. + /// + public ModifiedFunctionPointerType( + Type functionPointerType, + ModifiedType root, + int nestedSignatureIndex, + int nestedSignatureParameterIndex) + : base(functionPointerType, root, nestedSignatureIndex, nestedSignatureParameterIndex) + { + Debug.Assert(functionPointerType.IsFunctionPointer); + _parameterTypes = CreateParameters(functionPointerType.GetFunctionPointerParameterTypes(), root, nestedSignatureIndex + 1); + _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), root, nestedSignatureIndex + 1, nestedSignatureParameterIndex: 0); + } + + public override Type GetFunctionPointerReturnType() => _returnType; + public override Type[] GetFunctionPointerParameterTypes() => CloneArray(_parameterTypes); + + public override Type[] GetFunctionPointerCallingConventions() + { + _callingConventions ??= CreateCallingConventions(); + return CloneArray(_callingConventions); + } + + private static ModifiedType[] CreateParameters(Type[] parameterTypes, ModifiedType root, int nestedSignatureIndex) + { + int count = parameterTypes.Length; + ModifiedType[] modifiedTypes = new ModifiedType[count]; + for (int i = 0; i < count; i++) + { + modifiedTypes[i] = Create(parameterTypes[i], root, nestedSignatureIndex, nestedSignatureParameterIndex: i + 1); + } + + return modifiedTypes; + } + + private Type[] CreateCallingConventions() + { + Type[] returnTypeOptionalModifiers = GetFunctionPointerReturnType().GetOptionalCustomModifiers(); + + ArrayBuilder builder = default; + + bool foundCallingConvention = false; + + for (int i = 0; i < returnTypeOptionalModifiers.Length; i++) + { + Type type = returnTypeOptionalModifiers[i]; + if (type.FullName!.StartsWith(CallingConventionTypePrefix, StringComparison.Ordinal)) + { + builder.Add(type); + + if (type == typeof(CallConvCdecl) || + type == typeof(CallConvFastcall) || + type == typeof(CallConvStdcall) || + type == typeof(CallConvThiscall)) + { + foundCallingConvention = true; + } + } + } + + if (!foundCallingConvention) + { + // Normalize the calling conventions by manufacturing a type. + switch (GetCallingConvention()) + { + case MdSigCallingConvention.C: + builder.Add(typeof(CallConvCdecl)); + break; + case MdSigCallingConvention.StdCall: + builder.Add(typeof(CallConvStdcall)); + break; + case MdSigCallingConvention.ThisCall: + builder.Add(typeof(CallConvThiscall)); + break; + case MdSigCallingConvention.FastCall: + builder.Add(typeof(CallConvFastcall)); + break; + } + } + + return builder.Count == 0 ? EmptyTypes : builder.ToArray(); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs new file mode 100644 index 00000000000000..6f4f5e41980eef --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Reflection +{ + internal sealed partial class ModifiedGenericType : ModifiedType + { + private readonly ModifiedType[] _argumentTypes; + + /// + /// Create a root node. + /// + public ModifiedGenericType( + Type genericType, + Type[] requiredModifiers, + Type[] optionalModifiers, + int rootSignatureParameterIndex) + : base(genericType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) + { + Debug.Assert(genericType.IsGenericType); + _argumentTypes = CreateArguments(genericType.GetGenericArguments(), this, nestedSignatureIndex: 0); + } + + /// + /// Create a child node. + /// + public ModifiedGenericType( + Type genericType, + ModifiedType root, + int nestedSignatureIndex, + int nestedSignatureParameterIndex) + : base(genericType, root, nestedSignatureIndex, nestedSignatureParameterIndex) + { + Debug.Assert(genericType.IsGenericType); + _argumentTypes = CreateArguments(genericType.GetGenericArguments(), root, nestedSignatureIndex + 1); + } + + public override Type[] GetGenericArguments() => CloneArray(_argumentTypes); + public override bool IsGenericType => true; + + private static ModifiedType[] CreateArguments(Type[] argumentTypes, ModifiedType root, int nestedSignatureIndex) + { + int count = argumentTypes.Length; + ModifiedType[] modifiedTypes = new ModifiedType[count]; + for (int i = 0; i < count; i++) + { + modifiedTypes[i] = Create(argumentTypes[i], root, nestedSignatureIndex, nestedSignatureParameterIndex: i + 1); + } + + return modifiedTypes; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs new file mode 100644 index 00000000000000..5f8d0f7648a60e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal sealed class ModifiedStandaloneType : ModifiedType + { + /// + /// Create a root node. + /// + public ModifiedStandaloneType( + Type delegatingType, + Type[] requiredModifiers, + Type[] optionalModifiers, + int rootSignatureParameterIndex) + : base(delegatingType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) { } + + /// + /// Create a child node. + /// + public ModifiedStandaloneType( + Type delegatingType, + ModifiedType? root, + int nestedSignatureIndex, + int nestedSignatureParameterIndex) + : base(delegatingType, root, nestedSignatureIndex, nestedSignatureParameterIndex) { } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs new file mode 100644 index 00000000000000..abda9f83f00013 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Reflection +{ + /// + /// Base class for all modified types. + /// Design supports code sharing between different runtimes and lazy loading of custom modifiers. + /// + internal abstract partial class ModifiedType : TypeDelegator + { + private readonly ModifiedType? _root; + + // These 3 fields, in order, determine the lookup hierarchy for custom modifiers. + // The native tree traveral must match the managed semantics in order to indexes to match up. + protected readonly int _rootSignatureParameterIndex; + private readonly int _nestedSignatureIndex; + private readonly int _nestedSignatureParameterIndex; + + protected Type[]? _requiredModifiers; + protected Type[]? _optionalModifiers; + + /// + /// Create a root node. + /// + protected ModifiedType( + Type unmodifiedType, + Type[]? requiredModifiers, + Type[]? optionalModifiers, + int rootSignatureParameterIndex) : base(unmodifiedType) + { + _root = this; + _requiredModifiers = requiredModifiers; + _optionalModifiers = optionalModifiers; + _rootSignatureParameterIndex = rootSignatureParameterIndex; + _nestedSignatureParameterIndex = -1; + } + + /// + /// Create a child node. + /// + protected ModifiedType( + Type unmodifiedType, + ModifiedType? root, + int nestedSignatureIndex, + int nestedSignatureParameterIndex) : base(unmodifiedType) + { + _rootSignatureParameterIndex = -1; + _root = root; + _nestedSignatureIndex = nestedSignatureIndex; + _nestedSignatureParameterIndex = nestedSignatureParameterIndex; + } + + /// + /// Factory to create a child node recursively. + /// A type tree is formed due to arrays and pointers having an element type, function pointers + /// having a return type and parameter types and generic types having argument types. + /// + public static ModifiedType Create( + Type unmodifiedType, + ModifiedType root, + int nestedSignatureIndex, + int nestedSignatureParameterIndex) + { + ModifiedType modifiedType; + + if (unmodifiedType.IsFunctionPointer) + { + modifiedType = new ModifiedFunctionPointerType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + } + else if (unmodifiedType.HasElementType) + { + modifiedType = new ModifiedContainerType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + } + else if (unmodifiedType.IsGenericType) + { + modifiedType = new ModifiedGenericType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + } + else + { + modifiedType = new ModifiedStandaloneType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + } + + return modifiedType; + } + + /// + /// The root signature's parameter index (0 for properties, 1 for fields, 0..n for methods). + /// A value of -1 means the value is not used because the node is not a root. + /// + protected int RootSignatureParameterIndex => Root._rootSignatureParameterIndex; + + /// + /// The nested signature's index into the recursive type tree. + /// A signature exists for function pointers and generic types. + /// + // For delegate*[]: 0 for the function pointer since nested by the array + // For delegate*>: -1 for the outer (since not nested); 0 for the inner + // For delegate*>[]: 0 for the outer; 1 for the inner + protected int NestedSignatureIndex => _nestedSignatureIndex; + + /// + /// From a given signature from , which parameter index does + /// the node belong to. 0 for return; 1..n for parameters. + /// A value of -1 means the value is not used because the node is not a signature parameter. + /// /// + protected int NestedSignatureParameterIndex => _nestedSignatureParameterIndex; + + /// + /// The root node which contains the signature reference and _rootSignatureParameterIndex. + /// + public ModifiedType Root + { + get + { + Debug.Assert( _root != null ); + return _root; + } + } + + public override Type[] GetRequiredCustomModifiers() + { + _requiredModifiers ??= GetCustomModifiers(required: true); + return CloneArray(_requiredModifiers); + } + + public override Type[] GetOptionalCustomModifiers() + { + _optionalModifiers ??= GetCustomModifiers(required: false); + return CloneArray(_optionalModifiers); + } + + // TypeDelegator doesn't forward these the way we want: + public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. + public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. + public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. + public override bool Equals(Type? other) // Not forwarded. + { + if (other is ModifiedType otherModifiedType) + { + return ReferenceEquals(this, otherModifiedType); + } + + return false; + } + + public static T[] CloneArray(T[] original, int start = 0) + { + if (original.Length == 0) + { + return original; + } + + T[] copy = new T[original.Length - start]; + Array.Copy(sourceArray: original, sourceIndex: start, destinationArray: copy, destinationIndex: 0, length: original.Length - start); + return copy; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs index 319c7070d10b50..5a92ca202fc878 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs @@ -42,6 +42,8 @@ public virtual object[] GetCustomAttributes(Type attributeType, bool inherit) return Array.Empty(); } + public virtual Type GetModifiedParameterType() => throw new NotSupportedException(); + public virtual Type[] GetOptionalCustomModifiers() => Type.EmptyTypes; public virtual Type[] GetRequiredCustomModifiers() => Type.EmptyTypes; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs index 89f398f1f91725..24c1196334a8b0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs @@ -33,6 +33,7 @@ protected PropertyInfo() { } public MethodInfo? GetSetMethod() => GetSetMethod(nonPublic: false); public abstract MethodInfo? GetSetMethod(bool nonPublic); + public virtual Type GetModifiedPropertyType() => throw new NotSupportedException(); public virtual Type[] GetOptionalCustomModifiers() => Type.EmptyTypes; public virtual Type[] GetRequiredCustomModifiers() => Type.EmptyTypes; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs index ce3e75cde26061..99d560db28ded4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs @@ -84,6 +84,10 @@ public TypeDelegator([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes. [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] public override FieldInfo[] GetFields(BindingFlags bindingAttr) => typeImpl.GetFields(bindingAttr); + public override Type[] GetFunctionPointerCallingConventions() => typeImpl.GetFunctionPointerCallingConventions(); + public override Type[] GetFunctionPointerParameterTypes() => typeImpl.GetFunctionPointerParameterTypes(); + public override Type GetFunctionPointerReturnType() => typeImpl.GetFunctionPointerReturnType(); + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] public override Type? GetInterface(string name, bool ignoreCase) => typeImpl.GetInterface(name, ignoreCase); @@ -146,6 +150,9 @@ public TypeDelegator([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes. public override bool IsCollectible => typeImpl.IsCollectible; + public override bool IsFunctionPointer => typeImpl.IsFunctionPointer; + public override bool IsUnmanagedFunctionPointer => typeImpl.IsUnmanagedFunctionPointer; + public override Type? GetElementType() => typeImpl.GetElementType(); protected override bool HasElementTypeImpl() => typeImpl.HasElementType; diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 270f3d2348b4ba..28fd7905e57727 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -53,6 +53,9 @@ protected Type() { } public virtual bool IsByRefLike { [Intrinsic] get => throw new NotSupportedException(SR.NotSupported_SubclassOverride); } + public virtual bool IsFunctionPointer => false; + public virtual bool IsUnmanagedFunctionPointer => false; + public bool HasElementType => HasElementTypeImpl(); protected abstract bool HasElementTypeImpl(); public abstract Type? GetElementType(); @@ -60,9 +63,12 @@ protected Type() { } public virtual int GetArrayRank() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); public virtual Type GetGenericTypeDefinition() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); - public virtual Type[] GenericTypeArguments => (IsGenericType && !IsGenericTypeDefinition) ? GetGenericArguments() : Type.EmptyTypes; + public virtual Type[] GenericTypeArguments => (IsGenericType && !IsGenericTypeDefinition) ? GetGenericArguments() : EmptyTypes; public virtual Type[] GetGenericArguments() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); + public virtual Type[] GetOptionalCustomModifiers() => EmptyTypes; + public virtual Type[] GetRequiredCustomModifiers() => EmptyTypes; + public virtual int GenericParameterPosition => throw new InvalidOperationException(SR.Arg_NotGenericParameter); public virtual GenericParameterAttributes GenericParameterAttributes => throw new NotSupportedException(); public virtual Type[] GetGenericParameterConstraints() @@ -126,7 +132,7 @@ public virtual Type[] GetGenericParameterConstraints() public ConstructorInfo? TypeInitializer { [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - get => GetConstructorImpl(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, Type.EmptyTypes, null); + get => GetConstructorImpl(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, EmptyTypes, null); } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] @@ -201,6 +207,10 @@ public ConstructorInfo? TypeInitializer [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] public abstract FieldInfo[] GetFields(BindingFlags bindingAttr); + public virtual Type[] GetFunctionPointerCallingConventions() => throw new NotSupportedException(); + public virtual Type GetFunctionPointerReturnType() => throw new NotSupportedException(); + public virtual Type[] GetFunctionPointerParameterTypes() => throw new NotSupportedException(); + [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicMethods | diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/SignatureDecoderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/SignatureDecoderTests.cs index ca8187a2793dad..616045dd05cad4 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/SignatureDecoderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/SignatureDecoderTests.cs @@ -238,6 +238,8 @@ public void ByReference(ref int i) { } public struct Nested { } public Nested Property { get { throw null; } } public event EventHandler Event { add { } remove { } } + public delegate* managed ManagedFunctionPointer; + public delegate* unmanaged[Stdcall] NativeFunctionPointer; } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] @@ -326,6 +328,8 @@ private static Dictionary GetExpectedFieldSignatures() { "Array", "int32[0...,0...]" }, { "GenericTypeParameter", "!T" }, { "GenericInstantiation", $"[{MetadataReaderTestHelpers.CollectionsAssemblyName}]System.Collections.Generic.List`1" }, + { "ManagedFunctionPointer", "method bool *(int32)" }, + { "NativeFunctionPointer", "method bool *(int32)" }, }; } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln index 702ac482ae494d..9580f272000443 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln +++ b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln @@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.MetadataL EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.MetadataLoadContext.Tests", "tests\System.Reflection.MetadataLoadContext.Tests.csproj", "{D28B6414-C82C-4BDE-B8BB-A4E3297A0651}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{F85BDD51-AC29-4D8D-8257-C509BED9A448}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{4361CEFA-8238-4247-9CC5-D99DF794843C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{7393C7CD-4C31-4B1C-96DC-1D46D240538A}" @@ -73,6 +75,10 @@ Global {D28B6414-C82C-4BDE-B8BB-A4E3297A0651}.Debug|Any CPU.Build.0 = Debug|Any CPU {D28B6414-C82C-4BDE-B8BB-A4E3297A0651}.Release|Any CPU.ActiveCfg = Release|Any CPU {D28B6414-C82C-4BDE-B8BB-A4E3297A0651}.Release|Any CPU.Build.0 = Release|Any CPU + {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Release|Any CPU.Build.0 = Release|Any CPU {4361CEFA-8238-4247-9CC5-D99DF794843C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4361CEFA-8238-4247-9CC5-D99DF794843C}.Debug|Any CPU.Build.0 = Debug|Any CPU {4361CEFA-8238-4247-9CC5-D99DF794843C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -92,6 +98,7 @@ Global GlobalSection(NestedProjects) = preSolution {6A69770F-4F95-411F-ACAE-2B902EB62161} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {D28B6414-C82C-4BDE-B8BB-A4E3297A0651} = {F45DECCA-03D3-4087-AB01-F099C027DC33} + {F85BDD51-AC29-4D8D-8257-C509BED9A448} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {22BDB23C-24DE-4C3C-9A18-A048C445EDC1} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} {E524DAF8-3F2C-4EC5-833D-E7D182055A66} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} {7AE8D7FD-6CEE-4F70-8675-0896AA6487BD} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx b/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx index d5a40f23b31697..f0ca801c005d15 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + $(NoWarn);SYSLIB0005;SYSLIB0037 - - + + @@ -65,6 +63,7 @@ + @@ -72,6 +71,12 @@ + + + + + + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs index 9f01b3b5efcb2f..56fc1ddfbaf698 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs @@ -561,5 +561,5 @@ public class ClassWithDefaultMember1 where T : ClassWithDefaultMember1 public class PublicClass { internal class InternalNestedClass { } - } + } } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs new file mode 100644 index 00000000000000..f4029c86b4ce77 --- /dev/null +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The runtime has the name spacespace and methods. +namespace System.Tests.Types +{ + internal static class FunctionPointerTestsExtensions + { + public static Type Project(this Type type) => Reflection.Tests.TestUtils.Project(type); + + public static bool IsMetadataLoadContext => true; + + /// + /// Do a type comparison; RO Types compare via == or .Equals, not ReferenceEquals + /// + public static bool IsFunctionPointerEqual(this Type type, Type other) => type == other && type.Equals(other); + + /// + /// Do a type comparison; RO Types compare via == or .Equals, not ReferenceEquals + /// + public static bool IsFunctionPointerNotEqual(this Type type, Type other) => type != other && !type.Equals(other); + } +} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs index cdbd7d4f6ec1fc..6f8aab95926ab0 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs @@ -10,12 +10,16 @@ internal static partial class TestUtils { // Given a runtime Type, load up the equivalent in the Test MetataLoadContext. This is for test-writing convenience so // that tests can write "typeof(TestClass).Project()" and get the benefits of compile-time typename checking and Intellisense. - // It also opens the possibility of sharing Reflection tests between different type providers with minimal fuss. + // It supports sharing Reflection tests with different type providers such as the runtime. public static Type Project(this Type type) { if (type == null) return null; + // Function pointers don't support Type.GetType() so they can't be dynamically created. + if (type.IsFunctionPointer) + throw new NotSupportedException("Function pointers don't support Project()"); + Assembly assembly = type.Assembly; string location = assembly.Location; if (PlatformDetection.IsNotBrowser && (location == null || location == string.Empty)) @@ -27,8 +31,8 @@ public static Type Project(this Type type) Assembly projectedAssembly = s_assemblyDict.GetOrAdd(assembly, delegate (Assembly a) { - // The core assembly we're using might not be the one powering the runtime. Make sure we project to the core assembly the MetataLoadContext - // is using. + // The core assembly we're using might not be the one powering the runtime. + // Make sure we project to the core assembly the MetataLoadContext is using. if (a == typeof(object).Assembly) { TestMetadataLoadContext.LoadFromStream(CreateStreamForCoreAssembly()); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs index 6f0f25ae95a637..1fab77de7cc4ea 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs @@ -248,7 +248,6 @@ public static unsafe void TestCustomModifiers1() { using (MetadataLoadContext lc = new MetadataLoadContext(new CoreMetadataAssemblyResolver(), "mscorlib")) { - Assembly a = lc.LoadFromByteArray(TestData.s_CustomModifiersImage); Type t = a.GetType("N", throwOnError: true); Type reqA = a.GetType("ReqA", throwOnError: true); diff --git a/src/libraries/System.Reflection/tests/MethodInfoTests.cs b/src/libraries/System.Reflection/tests/MethodInfoTests.cs index 92e5af098a6725..886194492c50ea 100644 --- a/src/libraries/System.Reflection/tests/MethodInfoTests.cs +++ b/src/libraries/System.Reflection/tests/MethodInfoTests.cs @@ -6,6 +6,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Xunit; +using Xunit.Sdk; namespace System.Reflection.Tests { @@ -205,7 +206,6 @@ public void EqualsTest(Type type1, string name1, Type type2, string name2, bool [InlineData("DummyMethod1", "DummyMethod1", true)] //Verify two different MethodInfo objects are not equal [InlineData("DummyMethod1", "DummyMethod2", false)] - public void Equality1(string str1, string str2, bool expected) { MethodInfo mi1 = GetMethod(typeof(MethodInfoTests), str1); @@ -894,6 +894,36 @@ private static void SecondCall(MethodInfo mi) Assert.Contains("TestAssembly", asm.ToString()); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + private static unsafe void TestFunctionPointers() + { + void* fn = FunctionPointerMethods.GetFunctionPointer(); + + // Sanity checks for direct invocation. + Assert.True(FunctionPointerMethods.GetFunctionPointer()(42)); + Assert.True(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 42)); + Assert.True(FunctionPointerMethods.CallFcnPtr_Void(fn, 42)); + Assert.False(FunctionPointerMethods.GetFunctionPointer()(41)); + Assert.False(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 41)); + Assert.False(FunctionPointerMethods.CallFcnPtr_Void(fn, 41)); + + MethodInfo m; + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_FP)); + // System.ArgumentException : Object of type 'System.IntPtr' cannot be converted to type 'System.Boolean(System.Int32)' + Assert.Throws(() => m.Invoke(null, new object[] { (IntPtr)fn, 42 })); + Assert.Throws(() => m.Invoke(null, new object[] { (IntPtr)fn, 41 })); + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_IntPtr)); + Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 })); + Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 })); + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void)); + Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 })); + Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 })); + } + //Methods for Reflection Metadata private void DummyMethod1(string str, int iValue, long lValue) { @@ -1292,6 +1322,31 @@ static YesNo NonNullableEnumDefaultYes(YesNo yesNo = YesNo.Yes) return yesNo; } } + + public static class FunctionPointerMethods + { + public static bool CallMe(int i) + { + return i == 42; + } + + public static unsafe bool CallFcnPtr_FP(delegate* fn, int value) + { + return fn(value); + } + + public static unsafe bool CallFcnPtr_IntPtr(IntPtr fn, int value) + { + return ((delegate*)fn)(value); + } + + public static unsafe bool CallFcnPtr_Void(void* fn, int value) + { + return ((delegate*)fn)(value); + } + + public static unsafe delegate* GetFunctionPointer() => &CallMe; + } #pragma warning restore 0414 } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs index da3ce81fd3a4cc..9f2966143321e2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs @@ -35,7 +35,8 @@ public static IEnumerable NoMarshallingRequiredTypes() => new[] new object[] { typeof(int*) }, new object[] { typeof(bool*) }, new object[] { typeof(char*) }, - new object[] { typeof(delegate* ) }, + // See issue https://github.com/dotnet/runtime/issues/71891 + // new object[] { typeof(delegate* ) }, new object[] { typeof(IntPtr) }, new object[] { typeof(ConsoleKey) }, // enum }; diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index feabc27b0576d5..cffe488d654fd3 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -41,6 +41,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.ReflectionIn EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCollectibleAssembly", "tests\TestCollectibleAssembly\TestCollectibleAssembly.csproj", "{C230AC88-A377-4BEB-824F-AB174C14DC86}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{B7975A39-2E87-4C6C-A7EC-1F5926676800}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLoadAssembly", "tests\TestLoadAssembly\TestLoadAssembly.csproj", "{1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.TestModule", "tests\TestModule\System.Reflection.TestModule.ilproj", "{0F83B07B-2E3F-4708-BE6D-7A8DA8168803}" @@ -544,6 +546,7 @@ Global {C3F25EEF-04B4-407A-960B-0C1CE9C04430} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {47E26787-7C27-4572-AD8B-868DE44E2C48} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {C230AC88-A377-4BEB-824F-AB174C14DC86} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} + {B7975A39-2E87-4C6C-A7EC-1F5926676800} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {0F83B07B-2E3F-4708-BE6D-7A8DA8168803} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 850f132bcb7767..0457c28f2079e6 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -5791,6 +5791,7 @@ protected Type() { } public bool IsContextful { get { throw null; } } public virtual bool IsEnum { get { throw null; } } public bool IsExplicitLayout { get { throw null; } } + public virtual bool IsFunctionPointer { get { throw null; } } public virtual bool IsGenericMethodParameter { get { throw null; } } public virtual bool IsGenericParameter { get { throw null; } } public virtual bool IsGenericType { get { throw null; } } @@ -5821,6 +5822,7 @@ protected Type() { } public virtual bool IsSZArray { get { throw null; } } public virtual bool IsTypeDefinition { get { throw null; } } public bool IsUnicodeClass { get { throw null; } } + public virtual bool IsUnmanagedFunctionPointer { get { throw null; } } public bool IsValueType { get { throw null; } } public virtual bool IsVariableBoundArray { get { throw null; } } public bool IsVisible { get { throw null; } } @@ -5879,6 +5881,9 @@ protected Type() { } public System.Reflection.FieldInfo[] GetFields() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] public abstract System.Reflection.FieldInfo[] GetFields(System.Reflection.BindingFlags bindingAttr); + public virtual System.Type[] GetFunctionPointerCallingConventions() { throw null; } + public virtual System.Type[] GetFunctionPointerParameterTypes() { throw null; } + public virtual System.Type GetFunctionPointerReturnType() { throw null; } public virtual System.Type[] GetGenericArguments() { throw null; } public virtual System.Type[] GetGenericParameterConstraints() { throw null; } public virtual System.Type GetGenericTypeDefinition() { throw null; } @@ -5941,6 +5946,7 @@ protected Type() { } public System.Type[] GetNestedTypes() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)] public abstract System.Type[] GetNestedTypes(System.Reflection.BindingFlags bindingAttr); + public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] public System.Reflection.PropertyInfo[] GetProperties() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] @@ -5961,6 +5967,7 @@ protected Type() { } public System.Reflection.PropertyInfo? GetProperty(string name, System.Type[] types) { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] protected abstract System.Reflection.PropertyInfo? GetPropertyImpl(string name, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, System.Type? returnType, System.Type[]? types, System.Reflection.ParameterModifier[]? modifiers); + public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } public new System.Type GetType() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The type might be removed")] public static System.Type? GetType(string typeName) { throw null; } @@ -6016,14 +6023,14 @@ protected Type() { } protected abstract bool IsPrimitiveImpl(); public virtual bool IsSubclassOf(System.Type c) { throw null; } protected virtual bool IsValueTypeImpl() { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The code for an array of the specified type might not be available.")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("The code for an array of the specified type might not be available.")] public virtual System.Type MakeArrayType() { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The code for an array of the specified type might not be available.")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("The code for an array of the specified type might not be available.")] public virtual System.Type MakeArrayType(int rank) { throw null; } public virtual System.Type MakeByRefType() { throw null; } public static System.Type MakeGenericMethodParameter(int position) { throw null; } public static System.Type MakeGenericSignatureType(System.Type genericTypeDefinition, params System.Type[] typeArguments) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")] + [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("The native code for this instantiation might not be available at runtime.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] public virtual System.Type MakeGenericType(params System.Type[] typeArguments) { throw null; } public virtual System.Type MakePointerType() { throw null; } @@ -11161,6 +11168,7 @@ protected FieldInfo() { } public static System.Reflection.FieldInfo GetFieldFromHandle(System.RuntimeFieldHandle handle) { throw null; } public static System.Reflection.FieldInfo GetFieldFromHandle(System.RuntimeFieldHandle handle, System.RuntimeTypeHandle declaringType) { throw null; } public override int GetHashCode() { throw null; } + public virtual Type GetModifiedFieldType() { throw null; } public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } public virtual object? GetRawConstantValue() { throw null; } public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } @@ -11587,6 +11595,7 @@ protected ParameterInfo() { } public virtual object[] GetCustomAttributes(bool inherit) { throw null; } public virtual object[] GetCustomAttributes(System.Type attributeType, bool inherit) { throw null; } public virtual System.Collections.Generic.IList GetCustomAttributesData() { throw null; } + public virtual Type GetModifiedParameterType() { throw null; } public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } public object GetRealObject(System.Runtime.Serialization.StreamingContext context) { throw null; } public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } @@ -11662,6 +11671,7 @@ protected PropertyInfo() { } public abstract System.Reflection.ParameterInfo[] GetIndexParameters(); public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } public virtual object? GetRawConstantValue() { throw null; } + public virtual Type GetModifiedPropertyType() { throw null; } public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } public System.Reflection.MethodInfo? GetSetMethod() { throw null; } public abstract System.Reflection.MethodInfo? GetSetMethod(bool nonPublic); @@ -11797,10 +11807,12 @@ public TypeDelegator([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers public override bool IsByRefLike { get { throw null; } } public override bool IsCollectible { get { throw null; } } public override bool IsConstructedGenericType { get { throw null; } } + public override bool IsFunctionPointer { get { throw null; } } public override bool IsGenericMethodParameter { get { throw null; } } public override bool IsGenericTypeParameter { get { throw null; } } public override bool IsSZArray { get { throw null; } } public override bool IsTypeDefinition { get { throw null; } } + public override bool IsUnmanagedFunctionPointer { get { throw null; } } public override bool IsVariableBoundArray { get { throw null; } } public override int MetadataToken { get { throw null; } } public override System.Reflection.Module Module { get { throw null; } } @@ -11826,6 +11838,9 @@ public TypeDelegator([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers public override System.Reflection.FieldInfo? GetField(string name, System.Reflection.BindingFlags bindingAttr) { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)] public override System.Reflection.FieldInfo[] GetFields(System.Reflection.BindingFlags bindingAttr) { throw null; } + public override System.Type[] GetFunctionPointerCallingConventions() { throw null; } + public override System.Type[] GetFunctionPointerParameterTypes() { throw null; } + public override System.Type GetFunctionPointerReturnType() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.Interfaces)] [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.Interfaces)] public override System.Type? GetInterface(string name, bool ignoreCase) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index cdc2c7f54ffc85..9f08b4e8106502 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -22,7 +22,11 @@ + + + + @@ -147,7 +151,7 @@ - + @@ -157,6 +161,7 @@ + @@ -216,6 +221,7 @@ + @@ -332,6 +338,7 @@ + diff --git a/src/libraries/System.Runtime/tests/System/Reflection/FunctionPointerTestsExtensions.cs b/src/libraries/System.Runtime/tests/System/Reflection/FunctionPointerTestsExtensions.cs new file mode 100644 index 00000000000000..9d629f42cb0c1d --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Reflection/FunctionPointerTestsExtensions.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection.Tests +{ + internal static class FunctionPointerTestsExtensions + { + /// + /// A noop to allow tests to be shared with MetadataLoadContext. + /// + public static Type Project(this Type type) => type; + + public static bool IsMetadataLoadContext => false; + + /// + /// Check for type equality using all 3 equality checks + /// + public static bool IsFunctionPointerEqual(this Type type, Type other) => + (type == other) && type.Equals(other) && ReferenceEquals(type, other); + + /// + /// Check for type equality using all 3 equality checks + /// + public static bool IsFunctionPointerNotEqual(this Type type, Type other) => + (type != other) && !type.Equals(other) && !ReferenceEquals(type, other); + } +} diff --git a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs index ca6dccd6a8c9bb..298bf5067ca1a3 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/TypeDelegatorTests.cs @@ -43,15 +43,32 @@ public void Properties() Assert.False(new TypeDelegator(typeof(IComparable)).IsValueType); Assert.False(new TypeDelegator(typeof(IComparable)).IsEnum); Assert.True(new TypeDelegator(typeof(IComparable)).IsInterface); + Assert.False(new TypeDelegator(typeof(IComparable)).IsFunctionPointer); Assert.True(new TypeDelegator(typeof(TypeDelegatorTests)).IsClass); Assert.False(new TypeDelegator(typeof(TypeDelegatorTests)).IsValueType); Assert.False(new TypeDelegator(typeof(TypeDelegatorTests)).IsInterface); + Assert.False(new TypeDelegator(typeof(IComparable)).IsFunctionPointer); Assert.False(new TypeDelegator(typeof(TypeCode)).IsClass); Assert.False(new TypeDelegator(typeof(TypeCode)).IsInterface); Assert.True(new TypeDelegator(typeof(TypeCode)).IsValueType); Assert.True(new TypeDelegator(typeof(TypeCode)).IsEnum); + Assert.False(new TypeDelegator(typeof(IComparable)).IsFunctionPointer); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public void FunctionPointers() + { + Assert.True(new TypeDelegator(typeof(delegate*)).IsFunctionPointer); + Assert.True(new TypeDelegator(typeof(delegate* unmanaged)).IsUnmanagedFunctionPointer); + Assert.NotNull(new TypeDelegator(typeof(delegate*)).GetFunctionPointerCallingConventions()); + Assert.NotNull(new TypeDelegator(typeof(delegate*)).GetFunctionPointerParameterTypes()); + Assert.NotNull(new TypeDelegator(typeof(delegate*)).GetFunctionPointerReturnType()); + Assert.NotNull(new TypeDelegator(typeof(delegate*)).GetRequiredCustomModifiers()); + Assert.NotNull(new TypeDelegator(typeof(delegate*)).GetOptionalCustomModifiers()); } public static IEnumerable SZArrayOrNotTypes() diff --git a/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs b/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs new file mode 100644 index 00000000000000..463b3ff4127fb0 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Tests.Types +{ + // These are runtime-specific tests not shared with MetadataLoadContext. + // Using arrays in the manner below allows for use of the "is" keyword. + // The use of 'object' will call into the runtime to compare but using a strongly-typed variable + // causes C# to hard-code the result. + public partial class FunctionPointerTests + { + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void CompileTimeIdentity_Managed() + { + object obj = new delegate*[1]; + Assert.True(obj is delegate*[]); + Assert.False(obj is delegate*[]); + + var fn = new delegate*[1]; + Assert.True(fn is delegate*[]); +#pragma warning disable CS0184 // 'is' expression's given expression is never of the provided type + Assert.False(fn is delegate*[]); +#pragma warning restore CS0184 + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void CompileTimeIdentity_ManagedWithMods() + { + object obj = new delegate*[1]; + Assert.True(obj is delegate*[]); + Assert.True(obj is delegate*[]); + + var fn = new delegate*[1]; +#pragma warning disable CS0184 + Assert.False(fn is delegate*[]); + Assert.False(fn is delegate*[]); +#pragma warning restore CS0184 + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void CompileTimeIdentity_Unmanaged() + { + object obj = new delegate* unmanaged[MemberFunction][1]; + Assert.True(obj is delegate* unmanaged[]); + Assert.True(obj is delegate* unmanaged[SuppressGCTransition][]); + Assert.True(obj is delegate* unmanaged[MemberFunction, SuppressGCTransition][]); + + var fn = new delegate* unmanaged[MemberFunction][1]; +#pragma warning disable CS0184 + Assert.False(fn is delegate* unmanaged[]); + Assert.False(fn is delegate* unmanaged[SuppressGCTransition][]); + Assert.False(fn is delegate* unmanaged[MemberFunction, SuppressGCTransition][]); +#pragma warning restore CS0184 + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void CompileTimeIdentity_UnmanagedIsPartOfIdentity() + { + object obj = new delegate* unmanaged[MemberFunction][1]; + Assert.False(obj is delegate*[]); + + var fn = new delegate* unmanaged[MemberFunction][1]; +#pragma warning disable CS0184 + Assert.False(fn is delegate*[]); +#pragma warning restore CS0184 + + object obj2 = new delegate* unmanaged[Cdecl][1]; + Assert.False(obj2 is delegate*[]); + + var fn2 = new delegate* unmanaged[Cdecl][1]; +#pragma warning disable CS0184 + Assert.False(fn2 is delegate*[]); +#pragma warning restore CS0184 + } + } +} + + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 50d60902a91bf7..b2a999682a2582 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -212,6 +212,8 @@ + + @@ -273,6 +275,9 @@ + + CommonSystem\Collections\Generic\ArrayBuilder.cs + diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs new file mode 100644 index 00000000000000..bd1dda86aabd46 --- /dev/null +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal partial class ModifiedFunctionPointerType + { + private MdSigCallingConvention GetCallingConvention() => throw new NotSupportedException(); + } +} 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 new file mode 100644 index 00000000000000..4eeb6acb7bf2e8 --- /dev/null +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedType.Mono.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + internal partial class ModifiedType + { +#pragma warning disable IDE0060 + private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); +#pragma warning restore IDE0060 + } +} diff --git a/src/tests/reflection/ldtoken/modifiers.il b/src/tests/reflection/ldtoken/modifiers.il index 5b0ea00e458a0a..5786f8dc8fb86f 100644 --- a/src/tests/reflection/ldtoken/modifiers.il +++ b/src/tests/reflection/ldtoken/modifiers.il @@ -6,8 +6,8 @@ .method private hidebysig static int32 Main() cil managed { - .locals init (valuetype [System.Runtime]System.RuntimeTypeHandle) .entrypoint + .locals init (valuetype [System.Runtime]System.RuntimeTypeHandle) ldtoken string[] stloc.0 @@ -59,6 +59,39 @@ UIntArrayModifiedUIntArrayOK: ret MyStructPtrModifiedMyStructPtrOK: + ldtoken method int32 *() + stloc.0 + ldloca 0 + ldtoken method int32 modopt(MyModifier) *() + + call instance bool valuetype [System.Runtime]System.RuntimeTypeHandle::Equals(valuetype [System.Runtime]System.RuntimeTypeHandle) + brtrue ModifiersNotPartOfFunctionPointerIdentityOK + ldc.i4.6 + ret +ModifiersNotPartOfFunctionPointerIdentityOK: + + ldtoken method unmanaged cdecl int32 *() + stloc.0 + ldloca 0 + ldtoken method unmanaged stdcall int32 *() + + call instance bool valuetype [System.Runtime]System.RuntimeTypeHandle::Equals(valuetype [System.Runtime]System.RuntimeTypeHandle) + brtrue CallKindNotPartOfFunctionPointerIdentityOK + ldc.i4.7 + ret +CallKindNotPartOfFunctionPointerIdentityOK: + + ldtoken method unmanaged cdecl int32 *() + stloc.0 + ldloca 0 + ldtoken method int32 *() + call instance bool valuetype [System.Runtime]System.RuntimeTypeHandle::Equals(valuetype [System.Runtime]System.RuntimeTypeHandle) + // Managed vs. unmanaged part of identity + brfalse ManagedVsUnmanagedIsPartOfFunctionPointerIdentityOK + ldc.i4.8 + ret + +ManagedVsUnmanagedIsPartOfFunctionPointerIdentityOK: ldc.i4 100 ret } From e546ee2fa5faac1eae642aeab543715906c2a8fc Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 23 Jan 2023 08:31:21 -0600 Subject: [PATCH 02/20] Fix compiler issue; test MLC to NetFramework --- src/coreclr/inc/sigparser.h | 4 ++-- ...ystem.Reflection.MetadataLoadContext.Tests.csproj | 12 +++++------- .../tests/src/Tests/Method/MethodTests.cs | 1 + 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/coreclr/inc/sigparser.h b/src/coreclr/inc/sigparser.h index 267dcdec023b04..f46d67939ba43d 100644 --- a/src/coreclr/inc/sigparser.h +++ b/src/coreclr/inc/sigparser.h @@ -724,7 +724,7 @@ class SigParser private: __checkReturn - HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished); + HRESULT MoveToNewSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished); public: @@ -732,7 +732,7 @@ class SigParser // Move to the specified signature (immediately follows an ELEMENT_TYPE_FNPTR) //------------------------------------------------------------------------ __checkReturn - HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind); + HRESULT MoveToNewSignature(uint32_t indexToFind); //------------------------------------------------------------------------ // Return pointer diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index bf64f1ff548b76..e4decf36f99f08 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -1,14 +1,18 @@ true - $(NetCoreAppCurrent) + $(NetCoreAppCurrent);$(NetFrameworkMinimum) $(NoWarn);SYSLIB0005;SYSLIB0037 + + + + @@ -71,12 +75,6 @@ - - - - - - diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs index 1fab77de7cc4ea..6f0f25ae95a637 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Method/MethodTests.cs @@ -248,6 +248,7 @@ public static unsafe void TestCustomModifiers1() { using (MetadataLoadContext lc = new MetadataLoadContext(new CoreMetadataAssemblyResolver(), "mscorlib")) { + Assembly a = lc.LoadFromByteArray(TestData.s_CustomModifiersImage); Type t = a.GetType("N", throwOnError: true); Type reqA = a.GetType("ReqA", throwOnError: true); From 36e07d66dcbf8863c67f5c3036aec2fd005bbe85 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 23 Jan 2023 11:45:38 -0600 Subject: [PATCH 03/20] Fix compile issue; prep for review --- src/coreclr/inc/sigparser.h | 4 +- src/coreclr/utilcode/sigparser.cpp | 25 ++++----- src/coreclr/vm/ecalllist.h | 4 +- src/coreclr/vm/runtimehandles.cpp | 4 +- src/coreclr/vm/sigformat.cpp | 3 +- src/coreclr/vm/siginfo.cpp | 40 +++++++-------- src/coreclr/vm/siginfo.hpp | 2 +- src/coreclr/vm/typekey.h | 2 +- ...FunctionPointerTests.CallingConventions.cs | 1 - .../Common/tests/System/ModifiedTypeTests.cs | 51 ++++++++++++++++++- .../Reflection/ModifiedContainerType.cs | 2 +- .../Reflection/ModifiedFunctionPointerType.cs | 2 +- .../System/Reflection/ModifiedGenericType.cs | 10 ++-- .../src/System/Reflection/ModifiedType.cs | 3 +- ...eflection.MetadataLoadContext.Tests.csproj | 5 +- .../System.Runtime/System.Runtime.sln | 18 +++++++ 16 files changed, 118 insertions(+), 58 deletions(-) diff --git a/src/coreclr/inc/sigparser.h b/src/coreclr/inc/sigparser.h index f46d67939ba43d..deac2e6fe24140 100644 --- a/src/coreclr/inc/sigparser.h +++ b/src/coreclr/inc/sigparser.h @@ -724,7 +724,7 @@ class SigParser private: __checkReturn - HRESULT MoveToNewSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished); + HRESULT MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished); public: @@ -732,7 +732,7 @@ class SigParser // Move to the specified signature (immediately follows an ELEMENT_TYPE_FNPTR) //------------------------------------------------------------------------ __checkReturn - HRESULT MoveToNewSignature(uint32_t indexToFind); + HRESULT MoveToSignature(uint32_t indexToFind); //------------------------------------------------------------------------ // Return pointer diff --git a/src/coreclr/utilcode/sigparser.cpp b/src/coreclr/utilcode/sigparser.cpp index 6bbb12f6061acd..7331f9e2d0961e 100644 --- a/src/coreclr/utilcode/sigparser.cpp +++ b/src/coreclr/utilcode/sigparser.cpp @@ -193,7 +193,7 @@ HRESULT SigParser::SkipSignature() return hr; } -HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind) +HRESULT SigParser::MoveToSignature(uint32_t indexToFind) { CONTRACTL { @@ -206,7 +206,7 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind) CONTRACTL_END BOOL isFinished = FALSE; - HRESULT hr = MoveToNewSignature(indexToFind, 0, &isFinished); + HRESULT hr = MoveToSignature(indexToFind, 0, &isFinished); if (isFinished == FALSE) { return META_E_BAD_SIGNATURE; @@ -215,7 +215,7 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind) return hr; } -HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished) +HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished) { CONTRACTL { @@ -256,7 +256,7 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentInde case ELEMENT_TYPE_PINNED: case ELEMENT_TYPE_SZARRAY: case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: - IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); if (*isFinished) return S_OK; @@ -300,12 +300,12 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentInde IfFailRet(GetData(&fpArgCnt)); // Handle return type - IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); // Handle args while (fpArgCnt--) { - IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); if (*isFinished) return S_OK; @@ -315,7 +315,7 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentInde case ELEMENT_TYPE_ARRAY: { - IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); // Element type + IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); // Element type if (*isFinished) return S_OK; @@ -350,14 +350,7 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentInde break; case ELEMENT_TYPE_GENERICINST: - if (indexToFind == currentIndex) - { - *isFinished = TRUE; - return S_OK; - } - - currentIndex++; - + // To support modifiers on generics, apply similar logic here from the ELEMENT_TYPE_FNPTR case. IfFailRet(SkipExactlyOne()); // Skip generic type // Handle args @@ -365,7 +358,7 @@ HRESULT SigParser::MoveToNewSignature(uint32_t indexToFind, uint32_t currentInde IfFailRet(GetData(&argCnt)); while (argCnt--) { - IfFailRet(MoveToNewSignature(indexToFind, currentIndex, isFinished)); + IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); if (*isFinished) return S_OK; diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 816e99a79d2c95..a8977232d798f9 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -203,9 +203,9 @@ FCFuncStart(gMetaDataImport) FCFuncEnd() FCFuncStart(gSignatureNative) - FCFuncElement("GetSignature", SignatureNative::GetSignature) - FCFuncElement("GetCustomModifiers", SignatureNative::GetCustomModifiers) FCFuncElement("GetCallingConventionFromFunctionPointer", SignatureNative::GetCallingConventionFromFunctionPointer) + FCFuncElement("GetCustomModifiers", SignatureNative::GetCustomModifiers) + FCFuncElement("GetSignature", SignatureNative::GetSignature) FCFuncElement("CompareSig", SignatureNative::CompareSig) FCFuncEnd() diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 9a42332ab93b79..c9f8adaf019e59 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1871,7 +1871,7 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, if (nestedSignatureIndex >= 0) { - sig.MoveToNewSignature(argument, nestedSignatureIndex); + sig.MoveToSignature(argument, nestedSignatureIndex); if (nestedSignatureParameterIndex == 0) { @@ -1998,7 +1998,7 @@ FCIMPL3(FC_INT8_RET, SignatureNative::GetCallingConventionFromFunctionPointer, argument = sig.GetArgProps(); } - sig.MoveToNewSignature(argument, nestedSignatureIndex); + sig.MoveToSignature(argument, nestedSignatureIndex); } retVal = sig.GetCallingConventionInfo() & IMAGE_CEE_CS_CALLCONV_MASK; diff --git a/src/coreclr/vm/sigformat.cpp b/src/coreclr/vm/sigformat.cpp index e76a198bd71534..52ac7f9ad3192c 100644 --- a/src/coreclr/vm/sigformat.cpp +++ b/src/coreclr/vm/sigformat.cpp @@ -545,11 +545,12 @@ void SigFormat::AddType(TypeHandle th) AddType(pRetAndArgTypes[i+1]); if (i != (cArgs - 1)) - AddString(", "); + AddString(", "); } if ((pTD->GetCallConv() & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_VARARG) { AddString(", "); + AddString("..."); } AddString(")"); diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index 9e11fbdce41bae..86b1a70c2b371f 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -867,7 +867,7 @@ MetaSig::SkipArg() // // Move to the specified signature in a type tree. HRESULT -MetaSig::MoveToNewSignature(SigPointer start, INT32 index) +MetaSig::MoveToSignature(SigPointer start, INT32 index) { CONTRACTL { @@ -882,7 +882,7 @@ MetaSig::MoveToNewSignature(SigPointer start, INT32 index) m_pLastType = m_pWalk; - HRESULT hr = start.MoveToNewSignature(index); + HRESULT hr = start.MoveToSignature(index); if (FAILED(hr)) { m_pWalk = m_pLastType; @@ -895,6 +895,8 @@ MetaSig::MoveToNewSignature(SigPointer start, INT32 index) uint32_t cbSigSize; start.GetSignature(&pSig, &cbSigSize); + // To support modifiers on generic types, create a MetaSigKind::sigGeneric as pass + // that instead of sigMember for generic types. Init(pSig, cbSigSize, m_pModule, &typeContext, sigMember); return hr; } @@ -1645,20 +1647,6 @@ TypeHandle SigPointer::GetTypeHandleThrowing( SigPointer psigModReread = psig; for (unsigned i = 0; i <= cArgs; i++) { - // A runtime function pointer should only have an unmanaged\managed status, and not - // the specific unmanaged CALLCONV_ value. - switch (uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) - { - case IMAGE_CEE_CS_CALLCONV_C: - case IMAGE_CEE_CS_CALLCONV_STDCALL: - case IMAGE_CEE_CS_CALLCONV_THISCALL: - case IMAGE_CEE_CS_CALLCONV_FASTCALL: - // Strip the calling convention. - uCallConv &= ~IMAGE_CEE_CS_CALLCONV_MASK; - // Treat as unmanaged. - uCallConv |= IMAGE_CEE_CS_CALLCONV_UNMANAGED; - } - // Lookup type handle. retAndArgTypes[i] = psig.GetTypeHandleThrowing(pOrigModule, pTypeContext, @@ -1683,13 +1671,21 @@ TypeHandle SigPointer::GetTypeHandleThrowing( break; } + // Only have an unmanaged\managed status, and not the unmanaged CALLCONV_ value. + switch (uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) + { + case IMAGE_CEE_CS_CALLCONV_C: + case IMAGE_CEE_CS_CALLCONV_STDCALL: + case IMAGE_CEE_CS_CALLCONV_THISCALL: + case IMAGE_CEE_CS_CALLCONV_FASTCALL: + // Strip the calling convention. + uCallConv &= ~IMAGE_CEE_CS_CALLCONV_MASK; + // Normalize to unmanaged. + uCallConv |= IMAGE_CEE_CS_CALLCONV_UNMANAGED; + } + // Find an existing function pointer or make a new one - thRet = ClassLoader::LoadFnptrTypeThrowing( - (BYTE) uCallConv, - cArgs, - retAndArgTypes, - fLoadTypes, - level); + thRet = ClassLoader::LoadFnptrTypeThrowing((BYTE) uCallConv, cArgs, retAndArgTypes, fLoadTypes, level); #else DacNotImpl(); thRet = TypeHandle(); diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index 9fae45472dc760..db2df4e124dcce 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -574,7 +574,7 @@ class MetaSig // Move to the specified new signature in a type tree and // re-initialize. //------------------------------------------------------------------ - HRESULT MoveToNewSignature(SigPointer start, INT32 index); + HRESULT MoveToSignature(SigPointer start, INT32 index); //------------------------------------------------------------------ // Returns a read-only SigPointer for the m_pLastType set by one diff --git a/src/coreclr/vm/typekey.h b/src/coreclr/vm/typekey.h index 2d42a92613895d..57044cc5f7aaaf 100644 --- a/src/coreclr/vm/typekey.h +++ b/src/coreclr/vm/typekey.h @@ -142,7 +142,7 @@ class TypeKey SUPPORTS_DAC; } CONTRACTL_END; - if (m_kind == ELEMENT_TYPE_CLASS || m_kind == ELEMENT_TYPE_FNPTR) + if (m_kind == ELEMENT_TYPE_CLASS) return PTR_Module(u.asClass.m_pModule); else if (CorTypeInfo::IsModifier_NoThrow(m_kind) || m_kind == ELEMENT_TYPE_VALUETYPE) return GetElementType().GetModule(); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs b/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs index b9af7cde22a332..f389d3fc2af4c8 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs @@ -89,7 +89,6 @@ public static unsafe void TestUnmanagedCallConvs_Return_Unmodified() Assert.Equal(0, fcnPtr1.GetFunctionPointerCallingConventions().Length); Assert.Equal(0, fcnPtr2.GetFunctionPointerCallingConventions().Length); - // Assert.Same(fcnPtr1, fcnPtr2); NOT TRUE FOR MLC Assert.True(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); } diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index 707218873097b2..a8c821300ae114 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -60,13 +60,14 @@ public static unsafe void TestFields_Generic_Unmodified() { Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; Assert.True(arrayGenericFcnPtr.IsGenericType); - Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); // generic is closed + Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); Assert.False(IsModifiedType(arrayGenericFcnPtr)); Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; Assert.False(IsModifiedType(genericParam)); Type nestedFcnPtr = genericParam.GetElementType(); + Assert.True(nestedFcnPtr.IsFunctionPointer); Assert.False(IsModifiedType(nestedFcnPtr)); Assert.Equal(1, nestedFcnPtr.GetFunctionPointerParameterTypes().Length); @@ -82,12 +83,13 @@ public static unsafe void TestFields_Generic_Modified() Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); Assert.True(IsModifiedType(arrayGenericFcnPtr)); Assert.True(arrayGenericFcnPtr.IsGenericType); - Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); // generic is closed + Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; Assert.True(IsModifiedType(genericParam)); Type nestedFcnPtr = genericParam.GetElementType(); + Assert.True(nestedFcnPtr.IsFunctionPointer); Assert.True(IsModifiedType(nestedFcnPtr)); Assert.Equal(1, nestedFcnPtr.GetFunctionPointerParameterTypes().Length); @@ -97,6 +99,50 @@ public static unsafe void TestFields_Generic_Modified() Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestMethods_OpenGeneric_Unmodified() + { + MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); + Assert.Equal(1, mi.GetGenericArguments().Length); + Type p0 = mi.GetGenericArguments()[0]; + Assert.True(p0.IsGenericMethodParameter); + Assert.False(IsModifiedType(p0)); + + Type p1 = mi.GetParameters()[1].ParameterType.GetElementType(); + Assert.True(p1.IsFunctionPointer); + Assert.False(p1.IsGenericTypeParameter); + Assert.False(IsModifiedType(p1)); + + Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); + Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + Assert.False(IsModifiedType(paramType)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestMethods_OpenGeneric_Modified() + { + MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); + Assert.Equal(1, mi.GetGenericArguments().Length); + Type p0 = mi.GetGenericArguments()[0]; + Assert.True(p0.IsGenericMethodParameter); + Assert.False(IsModifiedType(p0)); + + Type p1 = mi.GetParameters()[1].GetModifiedParameterType().GetElementType(); + Assert.True(p1.IsFunctionPointer); + Assert.False(p1.IsGenericTypeParameter); + Assert.True(IsModifiedType(p1)); + + Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); + Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + Assert.True(IsModifiedType(paramType)); + + Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); + } + [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -349,6 +395,7 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } + public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs index 9733cab76202cb..167c59a912872e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs @@ -22,7 +22,7 @@ public ModifiedContainerType( int rootSignatureParameterIndex) : base(containerType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) { Debug.Assert(containerType.HasElementType); - _elementModifiedType = Create(containerType.GetElementType()!, this, nestedSignatureIndex: 0, nestedSignatureParameterIndex: -1); + _elementModifiedType = Create(containerType.GetElementType()!, this, nestedSignatureIndex: -1, nestedSignatureParameterIndex: -1); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index 20e61defcc3269..d332c38b06b559 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -41,8 +41,8 @@ public ModifiedFunctionPointerType( : base(functionPointerType, root, nestedSignatureIndex, nestedSignatureParameterIndex) { Debug.Assert(functionPointerType.IsFunctionPointer); - _parameterTypes = CreateParameters(functionPointerType.GetFunctionPointerParameterTypes(), root, nestedSignatureIndex + 1); _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), root, nestedSignatureIndex + 1, nestedSignatureParameterIndex: 0); + _parameterTypes = CreateParameters(functionPointerType.GetFunctionPointerParameterTypes(), root, nestedSignatureIndex + 1); } public override Type GetFunctionPointerReturnType() => _returnType; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index 6f4f5e41980eef..f55b69aff1d877 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -20,7 +20,8 @@ public ModifiedGenericType( : base(genericType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) { Debug.Assert(genericType.IsGenericType); - _argumentTypes = CreateArguments(genericType.GetGenericArguments(), this, nestedSignatureIndex: 0); + // To support modifiers on generic types, pass nestedSignatureIndex:0. + _argumentTypes = CreateArguments(genericType.GetGenericArguments(), this, nestedSignatureIndex: -1); } /// @@ -34,11 +35,11 @@ public ModifiedGenericType( : base(genericType, root, nestedSignatureIndex, nestedSignatureParameterIndex) { Debug.Assert(genericType.IsGenericType); - _argumentTypes = CreateArguments(genericType.GetGenericArguments(), root, nestedSignatureIndex + 1); + // To support modifiers on generic types, pass nestedSignatureIndex+1 here. + _argumentTypes = CreateArguments(genericType.GetGenericArguments(), root, nestedSignatureIndex); } public override Type[] GetGenericArguments() => CloneArray(_argumentTypes); - public override bool IsGenericType => true; private static ModifiedType[] CreateArguments(Type[] argumentTypes, ModifiedType root, int nestedSignatureIndex) { @@ -46,7 +47,8 @@ private static ModifiedType[] CreateArguments(Type[] argumentTypes, ModifiedType ModifiedType[] modifiedTypes = new ModifiedType[count]; for (int i = 0; i < count; i++) { - modifiedTypes[i] = Create(argumentTypes[i], root, nestedSignatureIndex, nestedSignatureParameterIndex: i + 1); + // To support modifiers on generic types, pass an index value for nestedSignatureParameterIndex. + modifiedTypes[i] = Create(argumentTypes[i], root, nestedSignatureIndex, nestedSignatureParameterIndex: -1); } return modifiedTypes; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index abda9f83f00013..f48f2af0f3f2e0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -134,8 +134,9 @@ public override Type[] GetOptionalCustomModifiers() // TypeDelegator doesn't forward these the way we want: public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. - public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. + public override bool IsGenericType => typeImpl.IsGenericType; public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. + public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. public override bool Equals(Type? other) // Not forwarded. { if (other is ModifiedType otherModifiedType) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index e4decf36f99f08..eea4bab0ac73ce 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -9,7 +9,6 @@ - @@ -78,6 +77,10 @@ + + + + diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index cffe488d654fd3..20891dd9c2af26 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -372,6 +372,24 @@ Global {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x64.Build.0 = Release|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x86.ActiveCfg = Release|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x86.Build.0 = Release|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|Any CPU.Build.0 = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x64.ActiveCfg = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x64.Build.0 = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x86.ActiveCfg = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x86.Build.0 = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x64.ActiveCfg = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x64.Build.0 = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x86.ActiveCfg = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x86.Build.0 = Debug|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|Any CPU.Build.0 = Release|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x64.ActiveCfg = Release|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x64.Build.0 = Release|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x86.ActiveCfg = Release|Any CPU + {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x86.Build.0 = Release|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x64.ActiveCfg = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x86.ActiveCfg = Debug|Any CPU From e755c1cf19770782701a81e822a9d2efef9cd728 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 23 Jan 2023 13:19:40 -0600 Subject: [PATCH 04/20] Compile issue with MLC under certain conditions --- ...stem.Reflection.MetadataLoadContext.csproj | 5 +- .../General/TypeExtensions.netcoreapp.cs | 4 +- .../General/TypeExtensions.netcoreapp.v7.cs | 70 +++++++++++++++++++ .../General/TypeExtensions.netstandard.cs | 3 +- ...eflection.MetadataLoadContext.Tests.csproj | 8 +-- 5 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index c6872d3d1a271e..46d90835e56e57 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) System.Reflection @@ -80,7 +80,8 @@ - + + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.cs index 6c6baea9a5079a..6ddb2717b1b9cc 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.cs @@ -17,9 +17,7 @@ internal static class NetCoreApiEmulators } /// - /// Another layer of base types. - /// For NetStandard, these base types add the NetCore apis to NetStandard so code interacting with "RoTypes" and friends can - /// happily code to the full NetCore surface area. + /// Another layer of base types. Empty for NetCore. /// internal abstract class LeveledTypeInfo : TypeInfo { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs new file mode 100644 index 00000000000000..7f6fd6933e0724 --- /dev/null +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// This file makes NetStandard Reflection's "subclassing" surface area look as much like NetCore as possible so the rest of the code can be written without #if's. + +namespace System.Reflection.TypeLoading +{ + internal static class NetCoreApiEmulators + { + // On NetCore, call the real thing. + + public static bool IsSignatureType(this Type type) => type.IsSignatureType; + public static bool IsSZArray(this Type type) => type.IsSZArray; + public static bool IsVariableBoundArray(this Type type) => type.IsVariableBoundArray; + public static bool IsGenericMethodParameter(this Type type) => type.IsGenericMethodParameter; + public static Type MakeSignatureGenericType(this Type genericTypeDefinition, Type[] typeArguments) => Type.MakeGenericSignatureType(genericTypeDefinition, typeArguments); + } + + /// + /// Another layer of base types. + /// For <= 7.0 of NetCore, these base types add newer NetCore apis. + /// + internal abstract class LeveledTypeInfo : TypeInfo + { + protected LeveledTypeInfo() : base() { } + + public abstract bool IsFunctionPointer { get; } + public abstract bool IsUnmanagedFunctionPointer { get; } + public abstract Type[] GetFunctionPointerCallingConventions(); + public abstract Type[] GetFunctionPointerParameterTypes(); + public abstract Type GetFunctionPointerReturnType(); + public abstract Type[] GetOptionalCustomModifiers(); + public abstract Type[] GetRequiredCustomModifiers(); + } + + internal abstract class LeveledAssembly : Assembly + { + } + + internal abstract class LeveledConstructorInfo : ConstructorInfo + { + } + + internal abstract class LeveledMethodInfo : MethodInfo + { + } + + internal abstract class LeveledEventInfo : EventInfo + { + } + + internal abstract class LeveledFieldInfo : FieldInfo + { + public abstract Type GetModifiedFieldType(); + } + + internal abstract class LeveledParameterInfo : ParameterInfo + { + public abstract Type GetModifiedParameterType(); + } + + internal abstract class LeveledPropertyInfo : PropertyInfo + { + public abstract Type GetModifiedPropertyType(); + } + + internal abstract class LeveledCustomAttributeData : CustomAttributeData + { + } +} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs index 13c01eb9e7e1cd..4bac8efacd3694 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs @@ -22,7 +22,8 @@ internal static class NetCoreApiEmulators /// /// Another layer of base types. For NetCore, these base types are all but empty. For NetStandard, these base types add the NetCore apis to NetStandard - /// so code interacting with "RoTypes" and friends can happily code to the full NetCore surface area. + /// so code interacting with "RoTypes" and friends can happily code to the full NetCore surface area. For <=7.0 of NetCore + // these add new members that were introduced in 8.0. /// /// On NetStandard (and pre-2.2 NetCore), the TypeInfo constructor is not exposed so we cannot derive directly from TypeInfo. /// But we *can* derive from TypeDelegator which derives from TypeInfo. Since we're overriding (almost) every method, diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index eea4bab0ac73ce..7f29f8df21b711 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -7,11 +7,8 @@ $(NoWarn);SYSLIB0005;SYSLIB0037 - - - @@ -66,7 +63,6 @@ - @@ -79,7 +75,11 @@ + + + + From b3b64ffcd5838f7e6adba1643d74c4ab9056e709 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 23 Jan 2023 15:26:44 -0600 Subject: [PATCH 05/20] compile issue cont'd; lazy load mods on root --- .../System/Reflection/ModifiedType.CoreCLR.cs | 36 ++++++++----- .../src/System/Reflection/RtFieldInfo.cs | 6 +-- .../System/Reflection/RuntimeParameterInfo.cs | 3 +- .../System/Reflection/RuntimePropertyInfo.cs | 3 +- .../Reflection/ModifiedType.NativeAot.cs | 2 +- .../Common/tests/System/ModifiedTypeTests.cs | 12 +++-- .../tests/StackTraceTests.cs | 3 +- .../Reflection/ModifiedContainerType.cs | 5 +- .../Reflection/ModifiedFunctionPointerType.cs | 5 +- .../System/Reflection/ModifiedGenericType.cs | 5 +- .../Reflection/ModifiedStandaloneType.cs | 5 +- .../src/System/Reflection/ModifiedType.cs | 52 +++++++++++++++---- .../General/TypeExtensions.netcoreapp.v7.cs | 2 +- .../General/TypeExtensions.netstandard.cs | 2 +- .../Type/FunctionPointerTests.Runtime.cs | 4 +- .../System/Reflection/ModifiedType.Mono.cs | 2 +- 16 files changed, 93 insertions(+), 54 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs index a4c8ba7b131acd..5ea932a40a26d6 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -1,34 +1,45 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; + namespace System.Reflection { internal partial class ModifiedType { - private Signature? _signature; + private Signature? _signature; // CoreClr-specific class. /// /// Called from FieldInfo, PropertyInfo and ParameterInfo to create a modified type tree. /// - public static ModifiedType Create(Type unmodifiedType, Type[] requiredModifiers, Type[] optionalModifiers, Signature? signature, int rootSignatureParameterIndex) + public static ModifiedType Create( + Type unmodifiedType, + object rootFieldParameterOrProperty, + Signature? signature, + int rootSignatureParameterIndex) { + Debug.Assert( + rootFieldParameterOrProperty is FieldInfo || + rootFieldParameterOrProperty is ParameterInfo || + rootFieldParameterOrProperty is PropertyInfo); + ModifiedType modifiedType; if (unmodifiedType.IsFunctionPointer) { - modifiedType = new ModifiedFunctionPointerType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + modifiedType = new ModifiedFunctionPointerType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); } else if (unmodifiedType.HasElementType) { - modifiedType = new ModifiedContainerType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + modifiedType = new ModifiedContainerType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); } else if (unmodifiedType.IsGenericType) { - modifiedType = new ModifiedGenericType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + modifiedType = new ModifiedGenericType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); } else { - modifiedType = new ModifiedStandaloneType(unmodifiedType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex); + modifiedType = new ModifiedStandaloneType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); } modifiedType._signature = signature; @@ -37,15 +48,14 @@ public static ModifiedType Create(Type unmodifiedType, Type[] requiredModifiers, public Signature? GetSignature() => Root._signature; - private Type[] GetCustomModifiers(bool required) + private Type[] GetCustomModifiersFromSignature(bool required) { - if (_nestedSignatureParameterIndex >= 0) + Debug.Assert(_nestedSignatureParameterIndex >= 0); + + Signature? signature = GetSignature(); + if (signature != null) { - Signature? signature = GetSignature(); - if (signature != null) - { - return signature.GetCustomModifiers(RootSignatureParameterIndex, required, _nestedSignatureIndex, _nestedSignatureParameterIndex) ?? EmptyTypes; - } + return signature.GetCustomModifiers(RootSignatureParameterIndex, required, _nestedSignatureIndex, _nestedSignatureParameterIndex) ?? EmptyTypes; } return EmptyTypes; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs index 9f8f0b09ad3dd3..655a0f2765f1df 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs @@ -269,12 +269,10 @@ public override Type[] GetOptionalCustomModifiers() public override Type GetModifiedFieldType() { - Signature sig = GetSignature(); return ModifiedType.Create( FieldType, - sig.GetCustomModifiers(1, true), - sig.GetCustomModifiers(1, false), - sig, + this, + GetSignature(), rootSignatureParameterIndex: 1); } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index a3c8aaf178efeb..e16718d9b324a1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -444,8 +444,7 @@ public override Type GetModifiedParameterType() { return ModifiedType.Create( unmodifiedType: ParameterType, - GetRequiredCustomModifiers(), - GetOptionalCustomModifiers(), + this, m_signature, rootSignatureParameterIndex: PositionImpl + 1); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index fc37e7562a568d..7b78be17a6938c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -209,8 +209,7 @@ public override Type GetModifiedPropertyType() { return ModifiedType.Create( PropertyType, - GetRequiredCustomModifiers(), - GetOptionalCustomModifiers(), + this, Signature, rootSignatureParameterIndex: 0); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs index 4eeb6acb7bf2e8..c34525cb2e78b7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs @@ -6,7 +6,7 @@ namespace System.Reflection internal partial class ModifiedType { #pragma warning disable IDE0060 - private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); + private Type[] GetCustomModifiersFromSignature(bool required) => throw new NotSupportedException(); #pragma warning restore IDE0060 } } diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index a8c821300ae114..aad2694776cb01 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -52,7 +52,8 @@ void Verify(Type type) } } - + // NOTE: commented out due to compiler issue on NativeAOT: + /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -74,7 +75,10 @@ public static unsafe void TestFields_Generic_Unmodified() Type paramType = nestedFcnPtr.GetFunctionPointerParameterTypes()[0]; Assert.False(IsModifiedType(paramType)); } + */ + // NOTE: commented out due to compiler issue on NativeAOT + /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -98,6 +102,7 @@ public static unsafe void TestFields_Generic_Modified() Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } + */ [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -383,9 +388,10 @@ public ModifiedTypeHolder(delegate* d) { } public static volatile int* _volatileIntPointer; public static volatile delegate* unmanaged[Cdecl] _volatileFcnPtr; - // Although function pointers can't be used in generics directly, they can be undirectly + // Although function pointers can't be used in generics directly, they can be used indirectly // through an array or pointer. - public static volatile Tuple[]> _arrayGenericFcnPtr; + // NOTE: commented out due to compiler issue on NativeAOT: + // public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; public static int*[] _array_ptr_int; diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs index 53be5c90e30090..3aae34cc629efe 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs @@ -318,7 +318,8 @@ public unsafe void ToString_FunctionPointerSignature() { // This is separate from ToString_Invoke_ReturnsExpected since unsafe cannot be used for iterators var stackTrace = FunctionPointerParameter(null); - Assert.Contains("System.Diagnostics.Tests.StackTraceTests.FunctionPointerParameter(*() x)", stackTrace.ToString()); + // Function pointers have no Name. + Assert.Contains("System.Diagnostics.Tests.StackTraceTests.FunctionPointerParameter( x)", stackTrace.ToString()); } [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs index 167c59a912872e..3cbb94373b8859 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs @@ -17,9 +17,8 @@ internal sealed class ModifiedContainerType : ModifiedType /// public ModifiedContainerType( Type containerType, - Type[] requiredModifiers, - Type[] optionalModifiers, - int rootSignatureParameterIndex) : base(containerType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) + object rootFieldParameterOrProperty, + int rootSignatureParameterIndex) : base(containerType, rootFieldParameterOrProperty, rootSignatureParameterIndex) { Debug.Assert(containerType.HasElementType); _elementModifiedType = Create(containerType.GetElementType()!, this, nestedSignatureIndex: -1, nestedSignatureParameterIndex: -1); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index d332c38b06b559..466c6853a642e6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -20,10 +20,9 @@ internal sealed partial class ModifiedFunctionPointerType : ModifiedType /// public ModifiedFunctionPointerType( Type functionPointerType, - Type[] requiredModifiers, - Type[] optionalModifiers, + object rootFieldParameterOrProperty, int rootSignatureParameterIndex) - : base(functionPointerType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) + : base(functionPointerType, rootFieldParameterOrProperty, rootSignatureParameterIndex) { Debug.Assert(functionPointerType.IsFunctionPointer); _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), this, nestedSignatureIndex: 0, nestedSignatureParameterIndex: 0); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index f55b69aff1d877..cd335729f29e37 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -14,10 +14,9 @@ internal sealed partial class ModifiedGenericType : ModifiedType /// public ModifiedGenericType( Type genericType, - Type[] requiredModifiers, - Type[] optionalModifiers, + object rootFieldParameterOrProperty, int rootSignatureParameterIndex) - : base(genericType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) + : base(genericType, rootFieldParameterOrProperty, rootSignatureParameterIndex) { Debug.Assert(genericType.IsGenericType); // To support modifiers on generic types, pass nestedSignatureIndex:0. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs index 5f8d0f7648a60e..bf5558602a863a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs @@ -10,10 +10,9 @@ internal sealed class ModifiedStandaloneType : ModifiedType /// public ModifiedStandaloneType( Type delegatingType, - Type[] requiredModifiers, - Type[] optionalModifiers, + object rootFieldParameterOrProperty, int rootSignatureParameterIndex) - : base(delegatingType, requiredModifiers, optionalModifiers, rootSignatureParameterIndex) { } + : base(delegatingType, rootFieldParameterOrProperty, rootSignatureParameterIndex) { } /// /// Create a child node. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index f48f2af0f3f2e0..4b0178b3c04d9b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -12,6 +12,7 @@ namespace System.Reflection internal abstract partial class ModifiedType : TypeDelegator { private readonly ModifiedType? _root; + private object? _rootFieldParameterOrProperty; // These 3 fields, in order, determine the lookup hierarchy for custom modifiers. // The native tree traveral must match the managed semantics in order to indexes to match up. @@ -19,21 +20,16 @@ internal abstract partial class ModifiedType : TypeDelegator private readonly int _nestedSignatureIndex; private readonly int _nestedSignatureParameterIndex; - protected Type[]? _requiredModifiers; - protected Type[]? _optionalModifiers; - /// /// Create a root node. /// protected ModifiedType( Type unmodifiedType, - Type[]? requiredModifiers, - Type[]? optionalModifiers, + object rootFieldParameterOrProperty, int rootSignatureParameterIndex) : base(unmodifiedType) { _root = this; - _requiredModifiers = requiredModifiers; - _optionalModifiers = optionalModifiers; + _rootFieldParameterOrProperty = rootFieldParameterOrProperty; _rootSignatureParameterIndex = rootSignatureParameterIndex; _nestedSignatureParameterIndex = -1; } @@ -122,14 +118,48 @@ public ModifiedType Root public override Type[] GetRequiredCustomModifiers() { - _requiredModifiers ??= GetCustomModifiers(required: true); - return CloneArray(_requiredModifiers); + // No caching is performed; as is the case with FieldInfo.GetCustomModifiers etc. + return GetCustomModifiers(required: true); } public override Type[] GetOptionalCustomModifiers() { - _optionalModifiers ??= GetCustomModifiers(required: false); - return CloneArray(_optionalModifiers); + // No caching is performed; as is the case with FieldInfo.GetCustomModifiers etc. + return GetCustomModifiers(required: false); + } + + private Type[] GetCustomModifiers(bool required) + { + Type[] modifiers = EmptyTypes; + + if (_nestedSignatureParameterIndex >= 0) + { + modifiers = GetCustomModifiersFromSignature(required); + } + else if (ReferenceEquals(this, Root)) + { + object? obj = _rootFieldParameterOrProperty; + Debug.Assert(obj is not null); + + if (obj is FieldInfo fieldInfo) + { + modifiers = required ? fieldInfo.GetRequiredCustomModifiers() : fieldInfo.GetOptionalCustomModifiers(); + } + else if (obj is ParameterInfo parameterInfo) + { + modifiers = required ? parameterInfo.GetRequiredCustomModifiers() : parameterInfo.GetOptionalCustomModifiers(); + } + else if (obj is PropertyInfo propertyInfo) + { + modifiers = required ? propertyInfo.GetRequiredCustomModifiers() : propertyInfo.GetOptionalCustomModifiers(); + } + else + { + Debug.Assert(false); + } + } + + return modifiers; } // TypeDelegator doesn't forward these the way we want: diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs index 7f6fd6933e0724..75d0a2ea6ab429 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs @@ -18,7 +18,7 @@ internal static class NetCoreApiEmulators /// /// Another layer of base types. - /// For <= 7.0 of NetCore, these base types add newer NetCore apis. + /// For pre-8.0 of NetCore, these base types add newer NetCore apis. /// internal abstract class LeveledTypeInfo : TypeInfo { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs index 4bac8efacd3694..08693eb67514b9 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs @@ -22,7 +22,7 @@ internal static class NetCoreApiEmulators /// /// Another layer of base types. For NetCore, these base types are all but empty. For NetStandard, these base types add the NetCore apis to NetStandard - /// so code interacting with "RoTypes" and friends can happily code to the full NetCore surface area. For <=7.0 of NetCore + /// so code interacting with "RoTypes" and friends can happily code to the full NetCore surface area. For pre-8.0 of NetCore // these add new members that were introduced in 8.0. /// /// On NetStandard (and pre-2.2 NetCore), the TypeInfo constructor is not exposed so we cannot derive directly from TypeInfo. 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 463b3ff4127fb0..eca621b5938eee 100644 --- a/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs +++ b/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs @@ -7,8 +7,8 @@ namespace System.Tests.Types { // These are runtime-specific tests not shared with MetadataLoadContext. // Using arrays in the manner below allows for use of the "is" keyword. - // The use of 'object' will call into the runtime to compare but using a strongly-typed variable - // causes C# to hard-code the result. + // The use of 'object' will call into the runtime to compare but using a strongly-typed + // function pointer without 'object' causes C# to hard-code the result. public partial class FunctionPointerTests { [Fact] 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 4eeb6acb7bf2e8..c34525cb2e78b7 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 @@ -6,7 +6,7 @@ namespace System.Reflection internal partial class ModifiedType { #pragma warning disable IDE0060 - private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); + private Type[] GetCustomModifiersFromSignature(bool required) => throw new NotSupportedException(); #pragma warning restore IDE0060 } } From 3aef789861f118dc222421d2c2a8319bad732ef0 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 23 Jan 2023 18:59:49 -0600 Subject: [PATCH 06/20] compile issues cont'd; prepare for review --- .../ModifiedFunctionPointerType.CoreCLR.cs | 2 +- .../System/Reflection/ModifiedType.CoreCLR.cs | 52 +++++-------- .../src/System/Reflection/RtFieldInfo.cs | 10 +-- .../System/Reflection/RuntimeParameterInfo.cs | 11 +-- .../System/Reflection/RuntimePropertyInfo.cs | 12 +-- .../src/System/RuntimeType.CoreCLR.cs | 6 +- src/coreclr/vm/clsload.cpp | 1 - src/coreclr/vm/runtimehandles.cpp | 1 + src/coreclr/vm/siginfo.cpp | 4 +- .../Common/tests/System/ModifiedTypeTests.cs | 9 ++- .../Reflection/ModifiedContainerType.cs | 6 +- .../Reflection/ModifiedFunctionPointerType.cs | 9 +-- .../System/Reflection/ModifiedGenericType.cs | 7 +- .../Reflection/ModifiedStandaloneType.cs | 7 +- .../src/System/Reflection/ModifiedType.cs | 75 ++++++++++--------- ...stem.Reflection.MetadataLoadContext.csproj | 2 +- .../General/TypeExtensions.netcoreapp.v7.cs | 2 +- .../General/TypeExtensions.netstandard.cs | 4 +- .../Types/RoFunctionPointerType.cs | 3 - .../Types/RoModifiedContainerType.cs | 1 - .../Types/RoModifiedFunctionPointerType.cs | 2 +- .../Types/RoModifiedGenericType.cs | 2 +- .../TypeLoading/Types/RoTypeDelegator.cs | 5 +- .../src/SampleMetadata/SampleMetadata.cs | 2 +- .../FunctionPointerTestsExtensions.cs | 2 +- .../src/TestUtils/TestUtils.JittedRuntimes.cs | 2 +- .../System.Runtime/ref/System.Runtime.cs | 6 +- 27 files changed, 105 insertions(+), 140 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs index e20f23b8c96eae..c98c82bb383068 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs @@ -8,7 +8,7 @@ internal partial class ModifiedFunctionPointerType private MdSigCallingConvention GetCallingConvention() { Signature? signature = GetSignature(); - if (signature != null) + if (signature is not null) { return (MdSigCallingConvention)signature.GetCallingConventionFromFunctionPointer(RootSignatureParameterIndex, NestedSignatureIndex); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs index 5ea932a40a26d6..da840a38b05e45 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -7,41 +7,14 @@ namespace System.Reflection { internal partial class ModifiedType { - private Signature? _signature; // CoreClr-specific class. + private Signature? _signature; // Signature is a CoreClr-specific class. /// /// Called from FieldInfo, PropertyInfo and ParameterInfo to create a modified type tree. /// - public static ModifiedType Create( - Type unmodifiedType, - object rootFieldParameterOrProperty, - Signature? signature, - int rootSignatureParameterIndex) + public static ModifiedType Create(Type unmodifiedType, int rootSignatureParameterIndex, Signature? signature) { - Debug.Assert( - rootFieldParameterOrProperty is FieldInfo || - rootFieldParameterOrProperty is ParameterInfo || - rootFieldParameterOrProperty is PropertyInfo); - - ModifiedType modifiedType; - - if (unmodifiedType.IsFunctionPointer) - { - modifiedType = new ModifiedFunctionPointerType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); - } - else if (unmodifiedType.HasElementType) - { - modifiedType = new ModifiedContainerType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); - } - else if (unmodifiedType.IsGenericType) - { - modifiedType = new ModifiedGenericType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); - } - else - { - modifiedType = new ModifiedStandaloneType(unmodifiedType, rootFieldParameterOrProperty, rootSignatureParameterIndex); - } - + ModifiedType modifiedType = Create(unmodifiedType, rootSignatureParameterIndex); modifiedType._signature = signature; return modifiedType; } @@ -52,13 +25,26 @@ private Type[] GetCustomModifiersFromSignature(bool required) { Debug.Assert(_nestedSignatureParameterIndex >= 0); + Type[] modifiers; Signature? signature = GetSignature(); - if (signature != null) + if (signature is not null) + { + if (ReferenceEquals(this, Root)) + { + // For a root node, which is a Type (not a parameter), ask for the root-level modifiers. + modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required); + } + else + { + modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required, _nestedSignatureIndex, _nestedSignatureParameterIndex); + } + } + else { - return signature.GetCustomModifiers(RootSignatureParameterIndex, required, _nestedSignatureIndex, _nestedSignatureParameterIndex) ?? EmptyTypes; + modifiers = EmptyTypes; } - return EmptyTypes; + return modifiers; } } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs index 655a0f2765f1df..dff37dc199ce33 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs @@ -267,14 +267,8 @@ public override Type[] GetOptionalCustomModifiers() internal Signature GetSignature() => new Signature(this, m_declaringType); - public override Type GetModifiedFieldType() - { - return ModifiedType.Create( - FieldType, - this, - GetSignature(), - rootSignatureParameterIndex: 1); - } + public override Type GetModifiedFieldType() => + ModifiedType.Create(FieldType, rootSignatureParameterIndex: 1, GetSignature()); #endregion } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index e16718d9b324a1..f24a83b6ba4b29 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -440,14 +440,11 @@ public override Type[] GetOptionalCustomModifiers() m_signature.GetCustomModifiers(PositionImpl + 1, false); } - public override Type GetModifiedParameterType() - { - return ModifiedType.Create( + public override Type GetModifiedParameterType() => + ModifiedType.Create( unmodifiedType: ParameterType, - this, - m_signature, - rootSignatureParameterIndex: PositionImpl + 1); - } + rootSignatureParameterIndex: PositionImpl + 1, + m_signature); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 7b78be17a6938c..f3d378e1a755e8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -205,14 +205,10 @@ public override Type[] GetOptionalCustomModifiers() return Signature.GetCustomModifiers(0, false); } - public override Type GetModifiedPropertyType() - { - return ModifiedType.Create( - PropertyType, - this, - Signature, - rootSignatureParameterIndex: 0); - } + public override Type GetModifiedPropertyType() => ModifiedType.Create( + PropertyType, + rootSignatureParameterIndex: 0, + Signature); internal object GetConstantValue(bool raw) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 159d711d72d348..92cbbe6e86afc8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -1537,7 +1537,8 @@ private MemberInfoCache GetMemberCache(ref MemberInfoCache? m_cache) /// - /// Generic cache for rare scenario specific data. It is used to cache either Enum names, Enum values, the Activator cache or a function pointer. + /// Generic cache for rare scenario specific data. It is used to cache either Enum names, Enum values, + /// the Activator cache or function pointer parameters. /// internal object? GenericCache { @@ -3746,7 +3747,7 @@ public override Type[] GetFunctionPointerParameterTypes() } Type[] parameters = Cache.FunctionPointerReturnAndParameterTypes; - Debug.Assert(parameters.Length != 0); + Debug.Assert(parameters.Length > 0); if (parameters.Length == 1) { @@ -3763,7 +3764,6 @@ public override Type GetFunctionPointerReturnType() throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); } - Debug.Assert(Cache.FunctionPointerReturnAndParameterTypes.Length != 0); return Cache.FunctionPointerReturnAndParameterTypes[0]; } #endregion diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index d07242abc4e4ce..fb3ee11b74b57d 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -958,7 +958,6 @@ void DECLSPEC_NORETURN ClassLoader::ThrowTypeLoadException(TypeKey *pKey, #endif - TypeHandle ClassLoader::LoadConstructedTypeThrowing(TypeKey *pKey, LoadTypesFlag fLoadTypes /*= LoadTypes*/, ClassLoadLevel level /*=CLASS_LOADED*/, diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index c9f8adaf019e59..2ffaeaa56b8743 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1869,6 +1869,7 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, argument = sig.GetArgProps(); } + // Check if we need to move and\or switch to a function pointer signature. if (nestedSignatureIndex >= 0) { sig.MoveToSignature(argument, nestedSignatureIndex); diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index 86b1a70c2b371f..2584aacdda228a 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -895,8 +895,8 @@ MetaSig::MoveToSignature(SigPointer start, INT32 index) uint32_t cbSigSize; start.GetSignature(&pSig, &cbSigSize); - // To support modifiers on generic types, create a MetaSigKind::sigGeneric as pass - // that instead of sigMember for generic types. + // To support modifiers on generic types, create a 'MetaSigKind::sigGeneric' and pass + // that instead of 'MetaSigKind::sigMember' for generic types. Init(pSig, cbSigSize, m_pModule, &typeContext, sigMember); return hr; } diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index aad2694776cb01..2e00e71496d931 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -104,6 +104,8 @@ public static unsafe void TestFields_Generic_Modified() } */ + // NOTE: commented out due to compiler issue on NativeAOT + /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -124,7 +126,10 @@ public static unsafe void TestMethods_OpenGeneric_Unmodified() Type paramType = p1.GetFunctionPointerParameterTypes()[0]; Assert.False(IsModifiedType(paramType)); } + */ + // NOTE: commented out due to compiler issue on NativeAOT + /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -147,6 +152,7 @@ public static unsafe void TestMethods_OpenGeneric_Modified() Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } + */ [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -401,7 +407,8 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } - public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } + // NOTE: commented out due to compiler issue on NativeAOT: + // public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs index 3cbb94373b8859..2380d63577a009 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs @@ -15,10 +15,8 @@ internal sealed class ModifiedContainerType : ModifiedType /// /// Create a root node. /// - public ModifiedContainerType( - Type containerType, - object rootFieldParameterOrProperty, - int rootSignatureParameterIndex) : base(containerType, rootFieldParameterOrProperty, rootSignatureParameterIndex) + public ModifiedContainerType(Type containerType, int rootSignatureParameterIndex) + : base(containerType, rootSignatureParameterIndex) { Debug.Assert(containerType.HasElementType); _elementModifiedType = Create(containerType.GetElementType()!, this, nestedSignatureIndex: -1, nestedSignatureParameterIndex: -1); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index 466c6853a642e6..7c3c1e291849a7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -18,11 +18,8 @@ internal sealed partial class ModifiedFunctionPointerType : ModifiedType /// /// Create a root node. /// - public ModifiedFunctionPointerType( - Type functionPointerType, - object rootFieldParameterOrProperty, - int rootSignatureParameterIndex) - : base(functionPointerType, rootFieldParameterOrProperty, rootSignatureParameterIndex) + public ModifiedFunctionPointerType(Type functionPointerType, int rootSignatureParameterIndex) + : base(functionPointerType, rootSignatureParameterIndex, nestedSignatureIndex: 0) { Debug.Assert(functionPointerType.IsFunctionPointer); _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), this, nestedSignatureIndex: 0, nestedSignatureParameterIndex: 0); @@ -37,7 +34,7 @@ public ModifiedFunctionPointerType( ModifiedType root, int nestedSignatureIndex, int nestedSignatureParameterIndex) - : base(functionPointerType, root, nestedSignatureIndex, nestedSignatureParameterIndex) + : base(functionPointerType, root, nestedSignatureIndex + 1, nestedSignatureParameterIndex) { Debug.Assert(functionPointerType.IsFunctionPointer); _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), root, nestedSignatureIndex + 1, nestedSignatureParameterIndex: 0); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index cd335729f29e37..c1da1966ffaa1e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -12,11 +12,8 @@ internal sealed partial class ModifiedGenericType : ModifiedType /// /// Create a root node. /// - public ModifiedGenericType( - Type genericType, - object rootFieldParameterOrProperty, - int rootSignatureParameterIndex) - : base(genericType, rootFieldParameterOrProperty, rootSignatureParameterIndex) + public ModifiedGenericType(Type genericType, int rootSignatureParameterIndex) + : base(genericType, rootSignatureParameterIndex) { Debug.Assert(genericType.IsGenericType); // To support modifiers on generic types, pass nestedSignatureIndex:0. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs index bf5558602a863a..3dd0625b8f3a7c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs @@ -8,11 +8,8 @@ internal sealed class ModifiedStandaloneType : ModifiedType /// /// Create a root node. /// - public ModifiedStandaloneType( - Type delegatingType, - object rootFieldParameterOrProperty, - int rootSignatureParameterIndex) - : base(delegatingType, rootFieldParameterOrProperty, rootSignatureParameterIndex) { } + public ModifiedStandaloneType(Type delegatingType, int rootSignatureParameterIndex) + : base(delegatingType, rootSignatureParameterIndex) { } /// /// Create a child node. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index 4b0178b3c04d9b..541d9559047f30 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -12,10 +12,9 @@ namespace System.Reflection internal abstract partial class ModifiedType : TypeDelegator { private readonly ModifiedType? _root; - private object? _rootFieldParameterOrProperty; // These 3 fields, in order, determine the lookup hierarchy for custom modifiers. - // The native tree traveral must match the managed semantics in order to indexes to match up. + // The native tree traveral must match the managed semantics in order for indexes to match up. protected readonly int _rootSignatureParameterIndex; private readonly int _nestedSignatureIndex; private readonly int _nestedSignatureParameterIndex; @@ -23,17 +22,41 @@ internal abstract partial class ModifiedType : TypeDelegator /// /// Create a root node. /// - protected ModifiedType( - Type unmodifiedType, - object rootFieldParameterOrProperty, - int rootSignatureParameterIndex) : base(unmodifiedType) + protected ModifiedType(Type unmodifiedType, int rootSignatureParameterIndex, int nestedSignatureIndex = -1) : base(unmodifiedType) { _root = this; - _rootFieldParameterOrProperty = rootFieldParameterOrProperty; _rootSignatureParameterIndex = rootSignatureParameterIndex; + _nestedSignatureIndex = nestedSignatureIndex; _nestedSignatureParameterIndex = -1; } + /// + /// Create a root node; called by a runtime-specific factory method. + /// + protected static ModifiedType Create(Type unmodifiedType, int rootSignatureParameterIndex) + { + ModifiedType modifiedType; + + if (unmodifiedType.IsFunctionPointer) + { + modifiedType = new ModifiedFunctionPointerType(unmodifiedType, rootSignatureParameterIndex); + } + else if (unmodifiedType.HasElementType) + { + modifiedType = new ModifiedContainerType(unmodifiedType, rootSignatureParameterIndex); + } + else if (unmodifiedType.IsGenericType) + { + modifiedType = new ModifiedGenericType(unmodifiedType, rootSignatureParameterIndex); + } + else + { + modifiedType = new ModifiedStandaloneType(unmodifiedType, rootSignatureParameterIndex); + } + + return modifiedType; + } + /// /// Create a child node. /// @@ -118,53 +141,31 @@ public ModifiedType Root public override Type[] GetRequiredCustomModifiers() { - // No caching is performed; as is the case with FieldInfo.GetCustomModifiers etc. + // No caching is performed; as is the case with FieldInfo.GetCustomModifiers and friends. return GetCustomModifiers(required: true); } public override Type[] GetOptionalCustomModifiers() { - // No caching is performed; as is the case with FieldInfo.GetCustomModifiers etc. + // No caching is performed; as is the case with FieldInfo.GetCustomModifiers and friends. return GetCustomModifiers(required: false); } private Type[] GetCustomModifiers(bool required) { - Type[] modifiers = EmptyTypes; - - if (_nestedSignatureParameterIndex >= 0) - { - modifiers = GetCustomModifiersFromSignature(required); - } - else if (ReferenceEquals(this, Root)) + // Modifiers only exist on the root (field\parameter\property) or on signature types + // which currently are just function pointers. + if (ReferenceEquals(this, Root) || _nestedSignatureParameterIndex >= 0) { - object? obj = _rootFieldParameterOrProperty; - Debug.Assert(obj is not null); - - if (obj is FieldInfo fieldInfo) - { - modifiers = required ? fieldInfo.GetRequiredCustomModifiers() : fieldInfo.GetOptionalCustomModifiers(); - } - else if (obj is ParameterInfo parameterInfo) - { - modifiers = required ? parameterInfo.GetRequiredCustomModifiers() : parameterInfo.GetOptionalCustomModifiers(); - } - else if (obj is PropertyInfo propertyInfo) - { - modifiers = required ? propertyInfo.GetRequiredCustomModifiers() : propertyInfo.GetOptionalCustomModifiers(); - } - else - { - Debug.Assert(false); - } + return GetCustomModifiersFromSignature(required); } - return modifiers; + return EmptyTypes; } // TypeDelegator doesn't forward these the way we want: public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. - public override bool IsGenericType => typeImpl.IsGenericType; + public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. public override bool Equals(Type? other) // Not forwarded. diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index 46d90835e56e57..631ca77f1d70ed 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -138,7 +138,6 @@ - @@ -146,6 +145,7 @@ + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs index 75d0a2ea6ab429..555b3f1e7de0b9 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs @@ -18,7 +18,7 @@ internal static class NetCoreApiEmulators /// /// Another layer of base types. - /// For pre-8.0 of NetCore, these base types add newer NetCore apis. + /// For pre-8.0 NetCore, these base types add newer NetCore apis. /// internal abstract class LeveledTypeInfo : TypeInfo { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs index 08693eb67514b9..d838f7762ba98f 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netstandard.cs @@ -22,8 +22,8 @@ internal static class NetCoreApiEmulators /// /// Another layer of base types. For NetCore, these base types are all but empty. For NetStandard, these base types add the NetCore apis to NetStandard - /// so code interacting with "RoTypes" and friends can happily code to the full NetCore surface area. For pre-8.0 of NetCore - // these add new members that were introduced in 8.0. + /// so code interacting with "RoTypes" and friends can happily code to the full NetCore surface area. For pre-8.0 NetCore + /// these add new members that were introduced in 8.0. /// /// On NetStandard (and pre-2.2 NetCore), the TypeInfo constructor is not exposed so we cannot derive directly from TypeInfo. /// But we *can* derive from TypeDelegator which derives from TypeInfo. Since we're overriding (almost) every method, diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs index e708c897259871..4bb7def083ad97 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs @@ -63,10 +63,7 @@ internal static SignatureCallingConvention GetCallingConvention(MethodSignature< case SignatureCallingConvention.StdCall: case SignatureCallingConvention.ThisCall: case SignatureCallingConvention.FastCall: - isUnmanaged = true; - break; case SignatureCallingConvention.Unmanaged: - // There is no CallConvUnmanaged type. isUnmanaged = true; break; } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs index c0edac515165d7..4a92bdf9177291 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs @@ -16,7 +16,6 @@ internal sealed class RoModifiedContainerType : RoModifiedType public RoModifiedContainerType(RoType unmodifiedType) : base(unmodifiedType) { Debug.Assert(unmodifiedType.HasElementType); - _elementModifiedType = Create(unmodifiedType.GetRoElementType()!); } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs index af6241e9596eb8..a5194f98992588 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs @@ -8,7 +8,7 @@ namespace System.Reflection { /// - /// A function pointer type that is modified and maintains its inner modified parameter types and return type. + /// A function pointer type that is modified and contains modified parameter and return types. /// internal sealed class RoModifiedFunctionPointerType : RoModifiedType { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedGenericType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedGenericType.cs index f15c8a3683c396..c6f85568c42ca1 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedGenericType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedGenericType.cs @@ -7,7 +7,7 @@ namespace System.Reflection { /// - /// A function pointer type that is modified and maintains its inner modified parameter types and return type. + /// A generic type that is modified and contains modified parameter types. /// internal sealed class RoModifiedGenericType : RoModifiedType { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs index 746b4558512aeb..d7f545b659dba6 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs @@ -8,9 +8,8 @@ namespace System.Reflection.TypeLoading { // Similar to TypeDelegator, wraps an instance of a Type (in this case, RoType) and delegates calls to it. - // TypeDelegator cannot be used since it cannot derive from RoType. - // This is only used by function pointers which are based on method signatures which the MetadataReader - // instantiates with the "modified type" pattern of chained types to represent custom modifiers. + // TypeDelegator cannot be used since it does not derive from RoType, and RoType is required to be used + // with MetadataReader interfaces. internal abstract class RoTypeDelegator : RoType { private RoType _typeImpl; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs index 56fc1ddfbaf698..9f01b3b5efcb2f 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/SampleMetadata/SampleMetadata.cs @@ -561,5 +561,5 @@ public class ClassWithDefaultMember1 where T : ClassWithDefaultMember1 public class PublicClass { internal class InternalNestedClass { } - } + } } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs index f4029c86b4ce77..2c650327d8c029 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// The runtime has the name spacespace and methods. +// The runtime tests have the name spacespace and methods to facilitate sharing. namespace System.Tests.Types { internal static class FunctionPointerTestsExtensions diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs index 6f8aab95926ab0..a24d7112344f87 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs @@ -10,7 +10,7 @@ internal static partial class TestUtils { // Given a runtime Type, load up the equivalent in the Test MetataLoadContext. This is for test-writing convenience so // that tests can write "typeof(TestClass).Project()" and get the benefits of compile-time typename checking and Intellisense. - // It supports sharing Reflection tests with different type providers such as the runtime. + // It supports sharing Reflection tests with different type providers such as the various runtimes. public static Type Project(this Type type) { if (type == null) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 0457c28f2079e6..967fe7569e4364 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -11168,7 +11168,7 @@ protected FieldInfo() { } public static System.Reflection.FieldInfo GetFieldFromHandle(System.RuntimeFieldHandle handle) { throw null; } public static System.Reflection.FieldInfo GetFieldFromHandle(System.RuntimeFieldHandle handle, System.RuntimeTypeHandle declaringType) { throw null; } public override int GetHashCode() { throw null; } - public virtual Type GetModifiedFieldType() { throw null; } + public virtual System.Type GetModifiedFieldType() { throw null; } public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } public virtual object? GetRawConstantValue() { throw null; } public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } @@ -11595,7 +11595,7 @@ protected ParameterInfo() { } public virtual object[] GetCustomAttributes(bool inherit) { throw null; } public virtual object[] GetCustomAttributes(System.Type attributeType, bool inherit) { throw null; } public virtual System.Collections.Generic.IList GetCustomAttributesData() { throw null; } - public virtual Type GetModifiedParameterType() { throw null; } + public virtual System.Type GetModifiedParameterType() { throw null; } public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } public object GetRealObject(System.Runtime.Serialization.StreamingContext context) { throw null; } public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } @@ -11671,7 +11671,7 @@ protected PropertyInfo() { } public abstract System.Reflection.ParameterInfo[] GetIndexParameters(); public virtual System.Type[] GetOptionalCustomModifiers() { throw null; } public virtual object? GetRawConstantValue() { throw null; } - public virtual Type GetModifiedPropertyType() { throw null; } + public virtual System.Type GetModifiedPropertyType() { throw null; } public virtual System.Type[] GetRequiredCustomModifiers() { throw null; } public System.Reflection.MethodInfo? GetSetMethod() { throw null; } public abstract System.Reflection.MethodInfo? GetSetMethod(bool nonPublic); From f76c75dff31537a28208060c734dee688265039e Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 24 Jan 2023 12:22:42 -0600 Subject: [PATCH 07/20] Remove Node back reference; fix edge case test failure --- .../System/Reflection/ModifiedType.CoreCLR.cs | 45 +++-- .../src/System/Reflection/RtFieldInfo.cs | 2 +- .../System/Reflection/RuntimeParameterInfo.cs | 6 +- .../System/Reflection/RuntimePropertyInfo.cs | 6 +- .../Reflection/ModifiedType.NativeAot.cs | 2 +- .../Reflection/ModifiedContainerType.cs | 34 ++-- .../Reflection/ModifiedFunctionPointerType.cs | 63 +++---- .../System/Reflection/ModifiedGenericType.cs | 50 +++--- .../Reflection/ModifiedStandaloneType.cs | 25 +-- .../src/System/Reflection/ModifiedType.cs | 155 +++++++----------- .../src/TestUtils/TestUtils.JittedRuntimes.cs | 2 + .../System/Reflection/ModifiedType.Mono.cs | 2 +- 12 files changed, 179 insertions(+), 213 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs index da840a38b05e45..12fcd35079db23 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -1,50 +1,47 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; - namespace System.Reflection { internal partial class ModifiedType { - private Signature? _signature; // Signature is a CoreClr-specific class. - /// /// Called from FieldInfo, PropertyInfo and ParameterInfo to create a modified type tree. /// - public static ModifiedType Create(Type unmodifiedType, int rootSignatureParameterIndex, Signature? signature) - { - ModifiedType modifiedType = Create(unmodifiedType, rootSignatureParameterIndex); - modifiedType._signature = signature; - return modifiedType; - } - - public Signature? GetSignature() => Root._signature; + public static ModifiedType CreateRoot( + Type unmodifiedType, + object? signatureProvider, + int rootSignatureParameterIndex) => Create( + unmodifiedType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex: -1, + nestedSignatureParameterIndex: -1, + isRoot: true); - private Type[] GetCustomModifiersFromSignature(bool required) + private Type[] GetCustomModifiers(bool required) { - Debug.Assert(_nestedSignatureParameterIndex >= 0); - - Type[] modifiers; + Type[] modifiers = EmptyTypes; Signature? signature = GetSignature(); if (signature is not null) { - if (ReferenceEquals(this, Root)) + if (IsRoot) { - // For a root node, which is a Type (not a parameter), ask for the root-level modifiers. + // For a root node, which is the original field\parameter\property Type, get the root-level modifiers. modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required); } - else + else if (NestedSignatureParameterIndex >= 0) { - modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required, _nestedSignatureIndex, _nestedSignatureParameterIndex); + modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required, NestedSignatureIndex, NestedSignatureParameterIndex); } } - else - { - modifiers = EmptyTypes; - } return modifiers; } + + internal Signature? GetSignature() + { + return (Signature?)SignatureProvider; // Signature is a CoreClr-specific class. + } } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs index dff37dc199ce33..cb22177945bd2e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs @@ -268,7 +268,7 @@ public override Type[] GetOptionalCustomModifiers() internal Signature GetSignature() => new Signature(this, m_declaringType); public override Type GetModifiedFieldType() => - ModifiedType.Create(FieldType, rootSignatureParameterIndex: 1, GetSignature()); + ModifiedType.CreateRoot(FieldType, GetSignature(), rootSignatureParameterIndex: 1); #endregion } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index f24a83b6ba4b29..b8a8f76d771090 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -441,10 +441,10 @@ public override Type[] GetOptionalCustomModifiers() } public override Type GetModifiedParameterType() => - ModifiedType.Create( + ModifiedType.CreateRoot( unmodifiedType: ParameterType, - rootSignatureParameterIndex: PositionImpl + 1, - m_signature); + m_signature, + rootSignatureParameterIndex: PositionImpl + 1); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index f3d378e1a755e8..dd891c20b081b0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -205,10 +205,10 @@ public override Type[] GetOptionalCustomModifiers() return Signature.GetCustomModifiers(0, false); } - public override Type GetModifiedPropertyType() => ModifiedType.Create( + public override Type GetModifiedPropertyType() => ModifiedType.CreateRoot( PropertyType, - rootSignatureParameterIndex: 0, - Signature); + Signature, + rootSignatureParameterIndex: 0); internal object GetConstantValue(bool raw) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs index c34525cb2e78b7..4eeb6acb7bf2e8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs @@ -6,7 +6,7 @@ namespace System.Reflection internal partial class ModifiedType { #pragma warning disable IDE0060 - private Type[] GetCustomModifiersFromSignature(bool required) => throw new NotSupportedException(); + private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); #pragma warning restore IDE0060 } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs index 2380d63577a009..7df9ae22de39e4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs @@ -12,28 +12,28 @@ internal sealed class ModifiedContainerType : ModifiedType { private readonly ModifiedType? _elementModifiedType; - /// - /// Create a root node. - /// - public ModifiedContainerType(Type containerType, int rootSignatureParameterIndex) - : base(containerType, rootSignatureParameterIndex) - { - Debug.Assert(containerType.HasElementType); - _elementModifiedType = Create(containerType.GetElementType()!, this, nestedSignatureIndex: -1, nestedSignatureParameterIndex: -1); - } - - /// - /// Create a child node. - /// public ModifiedContainerType( Type containerType, - ModifiedType root, + object? signatureProvider, + int rootSignatureParameterIndex, int nestedSignatureIndex, - int nestedSignatureParamterIndex) - : base(containerType, root, nestedSignatureIndex, nestedSignatureParamterIndex) + int nestedSignatureParameterIndex, + bool isRoot) + : base( + containerType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot) { Debug.Assert(containerType.HasElementType); - _elementModifiedType = Create(containerType.GetElementType()!, root, nestedSignatureIndex, nestedSignatureParamterIndex); + _elementModifiedType = Create( + containerType.GetElementType()!, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex : -1); } public override Type? GetElementType() => _elementModifiedType; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index 7c3c1e291849a7..1c4fd179660c1c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -15,30 +15,43 @@ internal sealed partial class ModifiedFunctionPointerType : ModifiedType private readonly ModifiedType _returnType; private Type[]? _callingConventions; - /// - /// Create a root node. - /// - public ModifiedFunctionPointerType(Type functionPointerType, int rootSignatureParameterIndex) - : base(functionPointerType, rootSignatureParameterIndex, nestedSignatureIndex: 0) - { - Debug.Assert(functionPointerType.IsFunctionPointer); - _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), this, nestedSignatureIndex: 0, nestedSignatureParameterIndex: 0); - _parameterTypes = CreateParameters(functionPointerType.GetFunctionPointerParameterTypes(), this, nestedSignatureIndex: 0); - } - - /// - /// Create a child node. - /// public ModifiedFunctionPointerType( Type functionPointerType, - ModifiedType root, + object? signatureProvider, + int rootSignatureParameterIndex, int nestedSignatureIndex, - int nestedSignatureParameterIndex) - : base(functionPointerType, root, nestedSignatureIndex + 1, nestedSignatureParameterIndex) + int nestedSignatureParameterIndex, + bool isRoot) + : base( + functionPointerType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex + 1, + nestedSignatureParameterIndex, + isRoot) { Debug.Assert(functionPointerType.IsFunctionPointer); - _returnType = Create(functionPointerType.GetFunctionPointerReturnType(), root, nestedSignatureIndex + 1, nestedSignatureParameterIndex: 0); - _parameterTypes = CreateParameters(functionPointerType.GetFunctionPointerParameterTypes(), root, nestedSignatureIndex + 1); + _returnType = Create( + functionPointerType.GetFunctionPointerReturnType(), + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex + 1, + nestedSignatureParameterIndex: 0); + + Type[] parameters = functionPointerType.GetFunctionPointerParameterTypes(); + int count = parameters.Length; + ModifiedType[] modifiedTypes = new ModifiedType[count]; + for (int i = 0; i < count; i++) + { + modifiedTypes[i] = Create( + parameters[i], + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex + 1, + nestedSignatureParameterIndex: i + 1); + } + + _parameterTypes = modifiedTypes; } public override Type GetFunctionPointerReturnType() => _returnType; @@ -50,18 +63,6 @@ public override Type[] GetFunctionPointerCallingConventions() return CloneArray(_callingConventions); } - private static ModifiedType[] CreateParameters(Type[] parameterTypes, ModifiedType root, int nestedSignatureIndex) - { - int count = parameterTypes.Length; - ModifiedType[] modifiedTypes = new ModifiedType[count]; - for (int i = 0; i < count; i++) - { - modifiedTypes[i] = Create(parameterTypes[i], root, nestedSignatureIndex, nestedSignatureParameterIndex: i + 1); - } - - return modifiedTypes; - } - private Type[] CreateCallingConventions() { Type[] returnTypeOptionalModifiers = GetFunctionPointerReturnType().GetOptionalCustomModifiers(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index c1da1966ffaa1e..72f963f763e8e9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -9,45 +9,39 @@ internal sealed partial class ModifiedGenericType : ModifiedType { private readonly ModifiedType[] _argumentTypes; - /// - /// Create a root node. - /// - public ModifiedGenericType(Type genericType, int rootSignatureParameterIndex) - : base(genericType, rootSignatureParameterIndex) - { - Debug.Assert(genericType.IsGenericType); - // To support modifiers on generic types, pass nestedSignatureIndex:0. - _argumentTypes = CreateArguments(genericType.GetGenericArguments(), this, nestedSignatureIndex: -1); - } - - /// - /// Create a child node. - /// public ModifiedGenericType( Type genericType, - ModifiedType root, + object? signatureProvider, + int rootSignatureParameterIndex, int nestedSignatureIndex, - int nestedSignatureParameterIndex) - : base(genericType, root, nestedSignatureIndex, nestedSignatureParameterIndex) + int nestedSignatureParameterIndex, + bool isRoot) + : base( + genericType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, // To support modifiers on generic types, pass nestedSignatureIndex+1 + nestedSignatureParameterIndex, + isRoot) { Debug.Assert(genericType.IsGenericType); - // To support modifiers on generic types, pass nestedSignatureIndex+1 here. - _argumentTypes = CreateArguments(genericType.GetGenericArguments(), root, nestedSignatureIndex); - } - public override Type[] GetGenericArguments() => CloneArray(_argumentTypes); - - private static ModifiedType[] CreateArguments(Type[] argumentTypes, ModifiedType root, int nestedSignatureIndex) - { - int count = argumentTypes.Length; + Type[] genericArguments = genericType.GetGenericArguments(); + int count = genericArguments.Length; ModifiedType[] modifiedTypes = new ModifiedType[count]; for (int i = 0; i < count; i++) { - // To support modifiers on generic types, pass an index value for nestedSignatureParameterIndex. - modifiedTypes[i] = Create(argumentTypes[i], root, nestedSignatureIndex, nestedSignatureParameterIndex: -1); + modifiedTypes[i] = Create( + genericArguments[i], + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, // To support modifiers on generic types, pass nestedSignatureIndex+1 + nestedSignatureParameterIndex: -1); // To support modifiers on generic types, pass index value. } - return modifiedTypes; + _argumentTypes = modifiedTypes; } + + public override Type[] GetGenericArguments() => CloneArray(_argumentTypes); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs index 3dd0625b8f3a7c..e7691ed68bc0e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs @@ -5,20 +5,21 @@ namespace System.Reflection { internal sealed class ModifiedStandaloneType : ModifiedType { - /// - /// Create a root node. - /// - public ModifiedStandaloneType(Type delegatingType, int rootSignatureParameterIndex) - : base(delegatingType, rootSignatureParameterIndex) { } - - /// - /// Create a child node. - /// public ModifiedStandaloneType( Type delegatingType, - ModifiedType? root, + object? signtureProvider, + int rootSignatureParameterIndex, int nestedSignatureIndex, - int nestedSignatureParameterIndex) - : base(delegatingType, root, nestedSignatureIndex, nestedSignatureParameterIndex) { } + int nestedSignatureParameterIndex, + bool isRoot) + : base( + delegatingType, + signtureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot) + { + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index 541d9559047f30..ba56aa884f1b7e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; - namespace System.Reflection { /// @@ -11,133 +9,118 @@ namespace System.Reflection /// internal abstract partial class ModifiedType : TypeDelegator { - private readonly ModifiedType? _root; + private readonly object? _signatureProvider; // These 3 fields, in order, determine the lookup hierarchy for custom modifiers. // The native tree traveral must match the managed semantics in order for indexes to match up. - protected readonly int _rootSignatureParameterIndex; + private readonly int _rootSignatureParameterIndex; private readonly int _nestedSignatureIndex; private readonly int _nestedSignatureParameterIndex; - /// - /// Create a root node. - /// - protected ModifiedType(Type unmodifiedType, int rootSignatureParameterIndex, int nestedSignatureIndex = -1) : base(unmodifiedType) - { - _root = this; - _rootSignatureParameterIndex = rootSignatureParameterIndex; - _nestedSignatureIndex = nestedSignatureIndex; - _nestedSignatureParameterIndex = -1; - } - - /// - /// Create a root node; called by a runtime-specific factory method. - /// - protected static ModifiedType Create(Type unmodifiedType, int rootSignatureParameterIndex) - { - ModifiedType modifiedType; - - if (unmodifiedType.IsFunctionPointer) - { - modifiedType = new ModifiedFunctionPointerType(unmodifiedType, rootSignatureParameterIndex); - } - else if (unmodifiedType.HasElementType) - { - modifiedType = new ModifiedContainerType(unmodifiedType, rootSignatureParameterIndex); - } - else if (unmodifiedType.IsGenericType) - { - modifiedType = new ModifiedGenericType(unmodifiedType, rootSignatureParameterIndex); - } - else - { - modifiedType = new ModifiedStandaloneType(unmodifiedType, rootSignatureParameterIndex); - } - - return modifiedType; - } + private bool _isRoot; - /// - /// Create a child node. - /// protected ModifiedType( Type unmodifiedType, - ModifiedType? root, + object? signatureProvider, + int rootSignatureParameterIndex, int nestedSignatureIndex, - int nestedSignatureParameterIndex) : base(unmodifiedType) + int nestedSignatureParameterIndex, + bool isRoot) : base(unmodifiedType) { - _rootSignatureParameterIndex = -1; - _root = root; + _signatureProvider = signatureProvider; + _rootSignatureParameterIndex = rootSignatureParameterIndex; _nestedSignatureIndex = nestedSignatureIndex; _nestedSignatureParameterIndex = nestedSignatureParameterIndex; + _isRoot = isRoot; } /// - /// Factory to create a child node recursively. + /// Factory to create a node recursively based on the underlying, unmodified type. /// A type tree is formed due to arrays and pointers having an element type, function pointers - /// having a return type and parameter types and generic types having argument types. + /// having a return type and parameter types, and generic types having argument types. /// - public static ModifiedType Create( + protected static ModifiedType Create( Type unmodifiedType, - ModifiedType root, + object? signatureProvider, + int rootSignatureParameterIndex, int nestedSignatureIndex, - int nestedSignatureParameterIndex) + int nestedSignatureParameterIndex, + bool isRoot = false) { ModifiedType modifiedType; if (unmodifiedType.IsFunctionPointer) { - modifiedType = new ModifiedFunctionPointerType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + modifiedType = new ModifiedFunctionPointerType( + unmodifiedType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot); } else if (unmodifiedType.HasElementType) { - modifiedType = new ModifiedContainerType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + modifiedType = new ModifiedContainerType( + unmodifiedType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot); } else if (unmodifiedType.IsGenericType) { - modifiedType = new ModifiedGenericType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + modifiedType = new ModifiedGenericType( + unmodifiedType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot); } else { - modifiedType = new ModifiedStandaloneType(unmodifiedType, root, nestedSignatureIndex, nestedSignatureParameterIndex); + modifiedType = new ModifiedStandaloneType( + unmodifiedType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot); } return modifiedType; } + /// - /// The root signature's parameter index (0 for properties, 1 for fields, 0..n for methods). - /// A value of -1 means the value is not used because the node is not a root. + /// The runtime-specific information to look up a signature, such as 'Signature' class or a type handle. /// - protected int RootSignatureParameterIndex => Root._rootSignatureParameterIndex; + protected object? SignatureProvider => _signatureProvider; /// - /// The nested signature's index into the recursive type tree. - /// A signature exists for function pointers and generic types. + /// Part 1 of 3 to determine the lookup hierarchy for custom modifiers. + /// Specifies the root signature's parameter index (0 for properties, 1 for fields, 0..n for methods). /// - // For delegate*[]: 0 for the function pointer since nested by the array - // For delegate*>: -1 for the outer (since not nested); 0 for the inner - // For delegate*>[]: 0 for the outer; 1 for the inner - protected int NestedSignatureIndex => _nestedSignatureIndex; + protected int RootSignatureParameterIndex => _rootSignatureParameterIndex; /// - /// From a given signature from , which parameter index does - /// the node belong to. 0 for return; 1..n for parameters. - /// A value of -1 means the value is not used because the node is not a signature parameter. - /// /// - protected int NestedSignatureParameterIndex => _nestedSignatureParameterIndex; + /// Part 2 of 3 to determine the lookup hierarchy for custom modifiers. + /// Specifies the nested signature's index into the recursive type tree which was the running count + /// for each signature node as it was created. + /// A value of -1 means the node is not nested under any signature. + /// + protected int NestedSignatureIndex => _nestedSignatureIndex; /// - /// The root node which contains the signature reference and _rootSignatureParameterIndex. + /// Part 3 of 3 to determine the lookup hierarchy for custom modifiers. + /// Specifies the parameter index from a given signature node. 0 for return; 1..n for parameters. + /// A value of -1 means the node is not a signature parameter. /// - public ModifiedType Root - { - get - { - Debug.Assert( _root != null ); - return _root; - } - } + protected int NestedSignatureParameterIndex => _nestedSignatureParameterIndex; + + protected virtual bool IsRoot => _isRoot; public override Type[] GetRequiredCustomModifiers() { @@ -151,18 +134,6 @@ public override Type[] GetOptionalCustomModifiers() return GetCustomModifiers(required: false); } - private Type[] GetCustomModifiers(bool required) - { - // Modifiers only exist on the root (field\parameter\property) or on signature types - // which currently are just function pointers. - if (ReferenceEquals(this, Root) || _nestedSignatureParameterIndex >= 0) - { - return GetCustomModifiersFromSignature(required); - } - - return EmptyTypes; - } - // TypeDelegator doesn't forward these the way we want: public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs index a24d7112344f87..d483dd47c3c511 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.JittedRuntimes.cs @@ -16,9 +16,11 @@ public static Type Project(this Type type) if (type == null) return null; +#if NET8_0_OR_GREATER // Function pointers don't support Type.GetType() so they can't be dynamically created. if (type.IsFunctionPointer) throw new NotSupportedException("Function pointers don't support Project()"); +#endif Assembly assembly = type.Assembly; string location = assembly.Location; 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 c34525cb2e78b7..4eeb6acb7bf2e8 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 @@ -6,7 +6,7 @@ namespace System.Reflection internal partial class ModifiedType { #pragma warning disable IDE0060 - private Type[] GetCustomModifiersFromSignature(bool required) => throw new NotSupportedException(); + private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); #pragma warning restore IDE0060 } } From 73b15b3c4395ecb9bc4f2e5f67cdad85539ae35e Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 24 Jan 2023 17:32:28 -0600 Subject: [PATCH 08/20] Increase test coverage; add missing recursive check --- src/coreclr/utilcode/sigparser.cpp | 5 +- .../Common/tests/System/ModifiedTypeTests.cs | 242 ++++++++++++------ 2 files changed, 169 insertions(+), 78 deletions(-) diff --git a/src/coreclr/utilcode/sigparser.cpp b/src/coreclr/utilcode/sigparser.cpp index 7331f9e2d0961e..a671473adec8b8 100644 --- a/src/coreclr/utilcode/sigparser.cpp +++ b/src/coreclr/utilcode/sigparser.cpp @@ -301,12 +301,13 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, // Handle return type IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); + if (*isFinished) + return S_OK; // Handle args while (fpArgCnt--) { IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); - if (*isFinished) return S_OK; } @@ -337,7 +338,6 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, IfFailRet(GetData(NULL)); // Skip lower bounds } } - } break; @@ -359,7 +359,6 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, while (argCnt--) { IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); - if (*isFinished) return S_OK; } diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index 2e00e71496d931..820dca7003a68a 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -9,6 +9,8 @@ namespace System.Tests.Types { + // The "_Unmodified" tests use GetXxxType() and are essentially a baseline since they don't return modifiers. + // The "_Modified" tests are based on the same types but use GetModifiedXxxType() in order to return the modifiers. public partial class ModifiedTypeTests { private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; @@ -52,7 +54,7 @@ void Verify(Type type) } } - // NOTE: commented out due to compiler issue on NativeAOT: + // NOTE: commented out due to compiler issue on NativeAOT: #81117 /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -67,18 +69,15 @@ public static unsafe void TestFields_Generic_Unmodified() Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; Assert.False(IsModifiedType(genericParam)); - Type nestedFcnPtr = genericParam.GetElementType(); - Assert.True(nestedFcnPtr.IsFunctionPointer); - Assert.False(IsModifiedType(nestedFcnPtr)); + Type fcnPtr = genericParam.GetElementType(); + Assert.True(fcnPtr.IsFunctionPointer); + Assert.False(IsModifiedType(fcnPtr)); - Assert.Equal(1, nestedFcnPtr.GetFunctionPointerParameterTypes().Length); - Type paramType = nestedFcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); + Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; Assert.False(IsModifiedType(paramType)); } - */ - // NOTE: commented out due to compiler issue on NativeAOT - /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -92,20 +91,17 @@ public static unsafe void TestFields_Generic_Modified() Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; Assert.True(IsModifiedType(genericParam)); - Type nestedFcnPtr = genericParam.GetElementType(); - Assert.True(nestedFcnPtr.IsFunctionPointer); - Assert.True(IsModifiedType(nestedFcnPtr)); + Type fcnPtr = genericParam.GetElementType(); + Assert.True(fcnPtr.IsFunctionPointer); + Assert.True(IsModifiedType(fcnPtr)); - Assert.Equal(1, nestedFcnPtr.GetFunctionPointerParameterTypes().Length); - Type paramType = nestedFcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); + Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; Assert.True(IsModifiedType(paramType)); Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } - */ - // NOTE: commented out due to compiler issue on NativeAOT - /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -126,10 +122,7 @@ public static unsafe void TestMethods_OpenGeneric_Unmodified() Type paramType = p1.GetFunctionPointerParameterTypes()[0]; Assert.False(IsModifiedType(paramType)); } - */ - // NOTE: commented out due to compiler issue on NativeAOT - /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -190,7 +183,7 @@ void Verify(Type type) [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Nested_Basic() + public static unsafe void TestFields_Parameterized_Basic() { Type ptr_ptr_int = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_ptr_int), Bindings).GetModifiedFieldType(); Verify(ptr_ptr_int); @@ -212,7 +205,7 @@ void Verify(Type type) [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Nested_FcnPtr() + public static unsafe void TestFields_Parameterized_FcnPtr() { Type ptr_fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_fcnPtr), Bindings).GetModifiedFieldType(); Assert.True(ptr_fcnPtr.IsPointer); @@ -249,8 +242,8 @@ public static unsafe void TestFields_VerifyIdempotency() // Call these again to ensure any backing caching strategy works. TestFields_Modified(); TestFields_Unmodified(); - TestFields_Nested_Basic(); - TestFields_Nested_FcnPtr(); + TestFields_Parameterized_Basic(); + TestFields_Parameterized_FcnPtr(); } [Fact] @@ -281,7 +274,7 @@ public static unsafe void TestMethodParameters() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestConstructorParameters() + public static unsafe void TestConstructorParameters_Unmodified() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); @@ -290,11 +283,19 @@ public static unsafe void TestConstructorParameters() Assert.False(IsModifiedType(param0)); Type[] mods = param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers(); Assert.Equal(0, mods.Length); + } - param0 = parameters[0].GetModifiedParameterType(); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestConstructorParameters_Modified() + { + ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); + + Type param0 = parameters[0].GetModifiedParameterType(); Assert.True(param0.IsFunctionPointer); Assert.True(IsModifiedType(param0)); - mods = param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers(); + Type[] mods = param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers(); Assert.Equal(1, mods.Length); Assert.Equal(typeof(OutAttribute).Project(), mods[0]); } @@ -302,84 +303,169 @@ public static unsafe void TestConstructorParameters() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out() + public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out_Unmodified() { - Type fcnPtr; - - fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).GetModifiedFieldType(); - Verify(fcnPtr); + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).GetModifiedFieldType(); + Assert.True(fcnPtr.IsFunctionPointer); + Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); Assert.True(IsModifiedType(fcnPtr)); Assert.Equal(typeof(int).Project().MakeByRefType(), fcnPtr.GetFunctionPointerParameterTypes()[0].UnderlyingSystemType); + } - fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).FieldType; - Verify(fcnPtr); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out_Modified() + { + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).FieldType; + Assert.True(fcnPtr.IsFunctionPointer); + Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); Assert.False(IsModifiedType(fcnPtr)); Assert.Equal(typeof(int).Project().MakeByRefType(), fcnPtr.GetFunctionPointerParameterTypes()[0]); - - void Verify(Type type) - { - Assert.True(type.IsFunctionPointer); - Assert.Equal(1, type.GetFunctionPointerParameterTypes().Length); - } } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters__fcnPtr_fcnPtrP0Out() + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Out_Unmodified() { - Type fcnPtr; - Type param0; + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).FieldType; + Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.True(param0.IsFunctionPointer); + Assert.Equal(1, param0.GetFunctionPointerParameterTypes().Length); + Assert.False(IsModifiedType(param0)); + Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0]); + Assert.Equal(0, param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); + } - fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).GetModifiedFieldType(); - param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; - Verify(param0); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Out_Modified() + { + // Modified + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).GetModifiedFieldType(); + Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.True(param0.IsFunctionPointer); + Assert.Equal(1, param0.GetFunctionPointerParameterTypes().Length); Assert.True(IsModifiedType(param0)); Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0].UnderlyingSystemType); Assert.Equal(1, param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); Assert.Equal(typeof(OutAttribute).Project(), param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers()[0]); + } - fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).FieldType; - param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; - Verify(param0); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Unmodified() + { + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).FieldType; + Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.True(param0.IsFunctionPointer); + Assert.Equal(1, param0.GetFunctionPointerParameterTypes().Length); Assert.False(IsModifiedType(param0)); Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0]); - Assert.Equal(0, param0.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers().Length); - - void Verify(Type type) - { - Assert.True(type.IsFunctionPointer); - Assert.Equal(1, type.GetFunctionPointerParameterTypes().Length); - } + Assert.Equal(0, param0.GetRequiredCustomModifiers().Length); + Assert.Equal(0, param0.GetOptionalCustomModifiers().Length); } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref() + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Modified() { - Type fcnPtr; - Type param0; - - fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).GetModifiedFieldType(); - param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; - Verify(param0); + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).GetModifiedFieldType(); + Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.True(param0.IsFunctionPointer); + Assert.Equal(1, param0.GetFunctionPointerParameterTypes().Length); Assert.True(IsModifiedType(param0)); Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0].UnderlyingSystemType); + Assert.Equal(0, param0.GetRequiredCustomModifiers().Length); + Assert.Equal(0, param0.GetOptionalCustomModifiers().Length); + } - fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).FieldType; - param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; - Verify(param0); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Unmodified() + { + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrRetP0Out), Bindings).FieldType; + Type param0 = fcnPtr.GetFunctionPointerReturnType().GetFunctionPointerParameterTypes()[0]; Assert.False(IsModifiedType(param0)); - Assert.Equal(typeof(int).Project().MakeByRefType(), param0.GetFunctionPointerParameterTypes()[0]); + Assert.Equal(0, param0.GetRequiredCustomModifiers().Length); + Assert.Equal(0, param0.GetOptionalCustomModifiers().Length); + } - void Verify(Type type) - { - Assert.True(type.IsFunctionPointer); - Assert.Equal(1, type.GetFunctionPointerParameterTypes().Length); - } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Modified() + { + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrRetP0Out), Bindings).GetModifiedFieldType(); + Type param0 = fcnPtr.GetFunctionPointerReturnType().GetFunctionPointerParameterTypes()[0]; + Assert.True(IsModifiedType(param0)); + Assert.Equal(typeof(int).Project().MakeByRefType(), param0.UnderlyingSystemType); + Assert.Equal(1, param0.GetRequiredCustomModifiers().Length); + Assert.Equal(0, param0.GetOptionalCustomModifiers().Length); } - + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_deep_Unmodified() + { + //public static delegate*< + // delegate*, + // delegate*>[][], + // delegate*>>, // Target is the 'ref bool' + // delegate*> _deep; + + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._deep), Bindings).FieldType; + Assert.Equal("System.SByte()(System.Byte(), System.Void(System.Int32)()[][], System.Void(System.Int32, System.String, System.Boolean&)()())", fcnPtr.ToString()); + + Type l1 = fcnPtr.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()()", l1.ToString()); + + Type l2 = l1.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()", l2.ToString()); + + Type l3 = l2.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)", l3.ToString()); + + Type target = l3.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Boolean&", target.ToString()); + + Assert.False(IsModifiedType(target)); + Assert.Equal(0, target.GetRequiredCustomModifiers().Length); + Assert.Equal(0, target.GetOptionalCustomModifiers().Length); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TestFunctionPointerParameters_fcnPtr_deep_Modified() + { + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._deep), Bindings).GetModifiedFieldType(); + Assert.Equal("System.SByte()(System.Byte(), System.Void(System.Int32)()[][], System.Void(System.Int32, System.String, System.Boolean&)()())", fcnPtr.ToString()); + + Type l1 = fcnPtr.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()()", l1.ToString()); + + Type l2 = l1.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()", l2.ToString()); + + Type l3 = l2.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)", l3.ToString()); + + Type target = l3.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Boolean&", target.ToString()); + + Assert.True(IsModifiedType(target)); + Assert.Equal(1, target.GetRequiredCustomModifiers().Length); + Assert.Equal(0, target.GetOptionalCustomModifiers().Length); + Assert.Equal(typeof(OutAttribute).Project(), target.GetRequiredCustomModifiers()[0]); + } + private static bool IsModifiedType(Type type) { return !ReferenceEquals(type, type.UnderlyingSystemType); @@ -396,7 +482,7 @@ public ModifiedTypeHolder(delegate* d) { } // Although function pointers can't be used in generics directly, they can be used indirectly // through an array or pointer. - // NOTE: commented out due to compiler issue on NativeAOT: + // NOTE: commented out due to compiler issue on NativeAOT: #81117 // public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; @@ -407,7 +493,7 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } - // NOTE: commented out due to compiler issue on NativeAOT: + // NOTE: commented out due to compiler issue on NativeAOT: #81117 // public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } @@ -417,6 +503,12 @@ public static void M_P0FcnPtrOut(delegate* fp) { } public static delegate* _fcnPtrP0Out; public static delegate*, void> _fcnPtr_fcnPtrP0Out; public static delegate*, void> _fcnPtr_fcnPtrP0Ref; + public static delegate*> _fcnPtr_fcnPtrRetP0Out; + public static delegate*< + delegate*, + delegate*>[][], + delegate*>>, + delegate*> _deep; } } } From 1361142cfddd21b6da790c79e85c887dd1c02621 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Wed, 25 Jan 2023 22:09:44 -0600 Subject: [PATCH 09/20] Various feedback; support mods on generic type parameters --- .../src/System/Reflection/MdImport.cs | 22 ++ .../ModifiedFunctionPointerType.CoreCLR.cs | 6 +- .../System/Reflection/ModifiedType.CoreCLR.cs | 8 +- src/coreclr/inc/sigparser.h | 6 +- .../ModifiedFunctionPointerType.NativeAot.cs | 2 +- src/coreclr/utilcode/sigparser.cpp | 48 ++-- src/coreclr/vm/runtimehandles.cpp | 6 +- src/coreclr/vm/siginfo.cpp | 36 ++- src/coreclr/vm/siginfo.hpp | 5 +- ...FunctionPointerTests.CallingConventions.cs | 14 +- .../System/FunctionPointerTests.Identity.cs | 8 +- .../tests/System/FunctionPointerTests.cs | 16 +- .../Common/tests/System/ModifiedTypeTests.cs | 225 +++++++++++++----- .../GenericWithModifiers.cs | 11 + .../GenericWithModifiers.il | 39 +++ .../TestReflectionILAssembly.ilproj | 10 + .../System.Private.CoreLib.Shared.projitems | 4 +- .../Reflection/MdSigCallingConvention.cs | 31 --- .../Reflection/ModifiedContainerType.cs | 6 +- .../Reflection/ModifiedFunctionPointerType.cs | 73 ++---- .../System/Reflection/ModifiedGenericType.cs | 9 +- .../Reflection/ModifiedHasElementType.cs | 41 ++++ .../src/System/Reflection/ModifiedType.cs | 15 +- .../Reflection/SignatureCallingConvention.cs | 19 ++ .../System.Reflection.MetadataLoadContext.sln | 7 + ...stem.Reflection.MetadataLoadContext.csproj | 8 +- ...ns.netcoreapp.cs => TypeExtensions.net.cs} | 0 ...etcoreapp.v7.cs => TypeExtensions.net7.cs} | 0 .../Types/RoModifiedFunctionPointerType.cs | 56 ++--- ...nerType.cs => RoModifiedHasElementType.cs} | 4 +- .../TypeLoading/Types/RoModifiedType.cs | 2 +- ...eflection.MetadataLoadContext.Tests.csproj | 1 + .../System.Runtime/System.Runtime.sln | 21 ++ .../tests/System.Runtime.Tests.csproj | 5 +- .../ModifiedFunctionPointerType.Mono.cs | 2 +- 35 files changed, 510 insertions(+), 256 deletions(-) create mode 100644 src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs create mode 100644 src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il create mode 100644 src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureCallingConvention.cs rename src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/{TypeExtensions.netcoreapp.cs => TypeExtensions.net.cs} (100%) rename src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/{TypeExtensions.netcoreapp.v7.cs => TypeExtensions.net7.cs} (100%) rename src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/{RoModifiedContainerType.cs => RoModifiedHasElementType.cs} (80%) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs index 98f6eeebf4c55c..df7ef1ba31d074 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs @@ -8,6 +8,28 @@ namespace System.Reflection { + [Flags] + internal enum MdSigCallingConvention : byte + { + CallConvMask = 0x0f, // Calling convention is bottom 4 bits + + Default = 0x00, + C = 0x01, + StdCall = 0x02, + ThisCall = 0x03, + FastCall = 0x04, + Vararg = 0x05, + Field = 0x06, + LocalSig = 0x07, + Property = 0x08, + Unmanaged = 0x09, + GenericInst = 0x0a, // generic method instantiation + + Generic = 0x10, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) + HasThis = 0x20, // Top bit indicates a 'this' parameter + ExplicitThis = 0x40, // This parameter is explicitly in the signature + } + [Flags] internal enum PInvokeAttributes { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs index c98c82bb383068..8b65e0a6d03df1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs @@ -5,15 +5,15 @@ namespace System.Reflection { internal partial class ModifiedFunctionPointerType { - private MdSigCallingConvention GetCallingConvention() + private SignatureCallingConvention GetCallingConvention() { Signature? signature = GetSignature(); if (signature is not null) { - return (MdSigCallingConvention)signature.GetCallingConventionFromFunctionPointer(RootSignatureParameterIndex, NestedSignatureIndex); + return (SignatureCallingConvention)signature.GetCallingConventionFromFunctionPointer(RootSignatureParameterIndex, NestedSignatureIndex); } - return MdSigCallingConvention.Default; + return SignatureCallingConvention.Default; } } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs index 12fcd35079db23..f3c7df701fd15e 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -11,13 +11,17 @@ internal partial class ModifiedType public static ModifiedType CreateRoot( Type unmodifiedType, object? signatureProvider, - int rootSignatureParameterIndex) => Create( + int rootSignatureParameterIndex) + { + int nestedSignatureIndex = -1; + return Create( unmodifiedType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex: -1, + ref nestedSignatureIndex, nestedSignatureParameterIndex: -1, isRoot: true); + } private Type[] GetCustomModifiers(bool required) { diff --git a/src/coreclr/inc/sigparser.h b/src/coreclr/inc/sigparser.h index deac2e6fe24140..49044b4a040b35 100644 --- a/src/coreclr/inc/sigparser.h +++ b/src/coreclr/inc/sigparser.h @@ -724,15 +724,15 @@ class SigParser private: __checkReturn - HRESULT MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished); + HRESULT MoveToSignature(uint32_t indexToFind, uint32_t* pCurrentIndex, bool* pIsFinished, CorElementType* pSignatureType); public: //------------------------------------------------------------------------ - // Move to the specified signature (immediately follows an ELEMENT_TYPE_FNPTR) + // Move to the specified signature //------------------------------------------------------------------------ __checkReturn - HRESULT MoveToSignature(uint32_t indexToFind); + HRESULT MoveToSignature(uint32_t indexToFind, CorElementType* pSignatureType); //------------------------------------------------------------------------ // Return pointer diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs index bd1dda86aabd46..2c143398e1f593 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs @@ -5,6 +5,6 @@ namespace System.Reflection { internal partial class ModifiedFunctionPointerType { - private MdSigCallingConvention GetCallingConvention() => throw new NotSupportedException(); + private SignatureCallingConvention GetCallingConvention() => throw new NotSupportedException(); } } diff --git a/src/coreclr/utilcode/sigparser.cpp b/src/coreclr/utilcode/sigparser.cpp index a671473adec8b8..12927a5ddbce0e 100644 --- a/src/coreclr/utilcode/sigparser.cpp +++ b/src/coreclr/utilcode/sigparser.cpp @@ -193,7 +193,7 @@ HRESULT SigParser::SkipSignature() return hr; } -HRESULT SigParser::MoveToSignature(uint32_t indexToFind) +HRESULT SigParser::MoveToSignature(uint32_t indexToFind, CorElementType* pSignatureType) { CONTRACTL { @@ -205,9 +205,10 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind) } CONTRACTL_END - BOOL isFinished = FALSE; - HRESULT hr = MoveToSignature(indexToFind, 0, &isFinished); - if (isFinished == FALSE) + bool isFinished = false; + uint32_t currentIndex = 0; + HRESULT hr = MoveToSignature(indexToFind, ¤tIndex, &isFinished, pSignatureType); + if (isFinished == false) { return META_E_BAD_SIGNATURE; } @@ -215,7 +216,7 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind) return hr; } -HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, BOOL* isFinished) +HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t* pCurrentIndex, bool* pIsFinished, CorElementType* pSignatureType) { CONTRACTL { @@ -256,9 +257,9 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, case ELEMENT_TYPE_PINNED: case ELEMENT_TYPE_SZARRAY: case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: - IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); + IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); - if (*isFinished) + if (*pIsFinished) return S_OK; break; @@ -274,13 +275,14 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, break; case ELEMENT_TYPE_FNPTR: - if (indexToFind == currentIndex) + if (indexToFind == *pCurrentIndex) { - *isFinished = TRUE; + *pIsFinished = TRUE; + *pSignatureType = ELEMENT_TYPE_FNPTR; return S_OK; } - currentIndex++; + (*pCurrentIndex)++; // Skip calling convention uint32_t uCallConv; @@ -300,15 +302,15 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, IfFailRet(GetData(&fpArgCnt)); // Handle return type - IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); - if (*isFinished) + IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); + if (*pIsFinished) return S_OK; // Handle args while (fpArgCnt--) { - IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); - if (*isFinished) + IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); + if (*pIsFinished) return S_OK; } @@ -316,8 +318,8 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, case ELEMENT_TYPE_ARRAY: { - IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); // Element type - if (*isFinished) + IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); + if (*pIsFinished) return S_OK; uint32_t rank; @@ -350,7 +352,15 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, break; case ELEMENT_TYPE_GENERICINST: - // To support modifiers on generics, apply similar logic here from the ELEMENT_TYPE_FNPTR case. + if (indexToFind == *pCurrentIndex) + { + *pIsFinished = TRUE; + *pSignatureType = ELEMENT_TYPE_GENERICINST; + return S_OK; + } + + (*pCurrentIndex)++; + IfFailRet(SkipExactlyOne()); // Skip generic type // Handle args @@ -358,8 +368,8 @@ HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t currentIndex, IfFailRet(GetData(&argCnt)); while (argCnt--) { - IfFailRet(MoveToSignature(indexToFind, currentIndex, isFinished)); - if (*isFinished) + IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); + if (*pIsFinished) return S_OK; } diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 2ffaeaa56b8743..1435d056b92a7d 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1846,7 +1846,7 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, BYTE callConv = *(BYTE*)gc.pSig->GetCorSig(); SigTypeContext typeContext; gc.pSig->GetTypeContext(&typeContext); - MetaSig sig = MetaSig(gc.pSig->GetCorSig(), + MetaSig sig(gc.pSig->GetCorSig(), gc.pSig->GetCorSigSize(), gc.pSig->GetModule(), &typeContext, @@ -1869,7 +1869,7 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, argument = sig.GetArgProps(); } - // Check if we need to move and\or switch to a function pointer signature. + // Check if we need to move and\or switch to a function pointer or generic method signature. if (nestedSignatureIndex >= 0) { sig.MoveToSignature(argument, nestedSignatureIndex); @@ -1892,6 +1892,7 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, // FCThrowResVoid(kArgumentNullException, W("Arg_ArgumentOutOfRangeException")); SigPointer sp = argument; + Module* pModule = sig.GetModule(); INT32 cMods = 0; CorElementType cmodType; @@ -1923,7 +1924,6 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, // modifiers now that we know how long they should be. sp = argument; - Module* pModule = sig.GetModule(); MethodTable *pMT = CoreLibBinder::GetClass(CLASS__TYPE); TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(pMT), ELEMENT_TYPE_SZARRAY); diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index 2584aacdda228a..0cefe74749546b 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -608,6 +608,15 @@ void MetaSig::Init( m_pRetType = SigPointer(NULL, 0); break; } + case sigGeneric: + { + IfFailGo(psig.SkipExactlyOne()); // Skip generic type + + uint32_t data = 0; + IfFailGo(psig.GetData(&data)); // Store number of arguments. + m_nArgs = data; + break; + } default: { UNREACHABLE(); @@ -865,7 +874,7 @@ MetaSig::SkipArg() //--------------------------------------------------------------------------------------- // -// Move to the specified signature in a type tree. +// Move to the specified signature. HRESULT MetaSig::MoveToSignature(SigPointer start, INT32 index) { @@ -882,7 +891,8 @@ MetaSig::MoveToSignature(SigPointer start, INT32 index) m_pLastType = m_pWalk; - HRESULT hr = start.MoveToSignature(index); + CorElementType signatureType = CorElementType::ELEMENT_TYPE_END; + HRESULT hr = start.MoveToSignature(index, &signatureType); if (FAILED(hr)) { m_pWalk = m_pLastType; @@ -895,9 +905,24 @@ MetaSig::MoveToSignature(SigPointer start, INT32 index) uint32_t cbSigSize; start.GetSignature(&pSig, &cbSigSize); - // To support modifiers on generic types, create a 'MetaSigKind::sigGeneric' and pass - // that instead of 'MetaSigKind::sigMember' for generic types. - Init(pSig, cbSigSize, m_pModule, &typeContext, sigMember); + // Select the right signature type to re-initialize. + MetaSigKind kind; + if (signatureType == ELEMENT_TYPE_FNPTR) + { + kind = sigMember; + } + else if (signatureType == ELEMENT_TYPE_GENERICINST) + { + kind = sigGeneric; + } + else + { + UNREACHABLE(); + m_pWalk = m_pLastType; + return BFA_INVALID_TOKEN_TYPE; + } + + Init(pSig, cbSigSize, m_pModule, &typeContext, kind); return hr; } @@ -1644,7 +1669,6 @@ TypeHandle SigPointer::GetTypeHandleThrowing( TypeHandle *retAndArgTypes = (TypeHandle*) _alloca(cAllocaSize); bool fReturnTypeOrParameterNotLoaded = false; - SigPointer psigModReread = psig; for (unsigned i = 0; i <= cArgs; i++) { // Lookup type handle. diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index db2df4e124dcce..8ce406710378fc 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -487,6 +487,7 @@ class MetaSig sigMember, sigLocalVars, sigField, + sigGeneric }; //------------------------------------------------------------------ @@ -571,8 +572,8 @@ class MetaSig void SkipArg(); //------------------------------------------------------------------ - // Move to the specified new signature in a type tree and - // re-initialize. + // Move to the specified new signature and re-initialize to the + // new signature type. //------------------------------------------------------------------ HRESULT MoveToSignature(SigPointer start, INT32 index); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs b/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs index f389d3fc2af4c8..4271d42e1ae4cb 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs @@ -15,7 +15,7 @@ public partial class FunctionPointerTests [InlineData(false)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestManagedCallingConvention(bool modified) + public static unsafe void ManagedCallingConvention(bool modified) { Type t = typeof(FunctionPointerHolder).Project(); MethodInfo m = t.GetMethod(nameof(FunctionPointerHolder.MethodCallConv_Managed), Bindings); @@ -37,7 +37,7 @@ public static unsafe void TestManagedCallingConvention(bool modified) [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestUnmanagedCallConv_Param_Unmodified(string methodName) + public static unsafe void UnmanagedCallConv_Param_Unmodified(string methodName) { Type t = typeof(FunctionPointerHolder).Project(); MethodInfo m = t.GetMethod(methodName, Bindings); @@ -56,7 +56,7 @@ public static unsafe void TestUnmanagedCallConv_Param_Unmodified(string methodNa [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall), typeof(CallConvFastcall))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestUnmanagedCallConv_Param_Modified(string methodName, Type callingConventionRuntime) + public static unsafe void UnmanagedCallConv_Param_Modified(string methodName, Type callingConventionRuntime) { Type callingConvention = callingConventionRuntime.Project(); Type t = typeof(FunctionPointerHolder).Project(); @@ -74,7 +74,7 @@ public static unsafe void TestUnmanagedCallConv_Param_Modified(string methodName [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestUnmanagedCallConvs_Return_Unmodified() + public static unsafe void UnmanagedCallConvs_Return_Unmodified() { Type t = typeof(FunctionPointerHolder).Project(); @@ -95,7 +95,7 @@ public static unsafe void TestUnmanagedCallConvs_Return_Unmodified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestUnmanagedCallConvs_Return_Modified() + public static unsafe void UnmanagedCallConvs_Return_Modified() { Type t = typeof(FunctionPointerHolder).Project(); @@ -124,7 +124,7 @@ public static unsafe void TestUnmanagedCallConvs_Return_Modified() [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall_SuppressGCTransition))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestUnmanagedCallConv_PhysicalModifiers_Unmodified(string methodName) + public static unsafe void UnmanagedCallConv_PhysicalModifiers_Unmodified(string methodName) { Type t = typeof(FunctionPointerHolder).Project(); MethodInfo m = t.GetMethod(methodName, Bindings); @@ -144,7 +144,7 @@ public static unsafe void TestUnmanagedCallConv_PhysicalModifiers_Unmodified(str [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Fastcall_SuppressGCTransition), typeof(CallConvFastcall))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestUnmanagedCallConv_PhysicalModifiers_Modified(string methodName, Type callingConventionRuntime) + public static unsafe void UnmanagedCallConv_PhysicalModifiers_Modified(string methodName, Type callingConventionRuntime) { Type suppressGcTransitionType = typeof(CallConvSuppressGCTransition).Project(); Type callingConvention = callingConventionRuntime.Project(); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs b/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs index 325e4b3a64e18e..1be48aa79da203 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs @@ -15,7 +15,7 @@ public partial class FunctionPointerTests [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionUnmanagedPointerReturn_DifferentReturnValue() + public static unsafe void FunctionUnmanagedPointerReturn_DifferentReturnValue() { Type t = typeof(FunctionPointerHolder).Project(); @@ -34,7 +34,7 @@ public static unsafe void TestFunctionUnmanagedPointerReturn_DifferentReturnValu [InlineData(nameof(FunctionPointerHolder.Field_DateOnly), nameof(FunctionPointerHolder.Field_Int))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestSigEqualityInDifferentModule_Field(string name, string otherName) + public static unsafe void SigEqualityInDifferentModule_Field(string name, string otherName) { Type fph1 = typeof(FunctionPointerHolder).Project(); Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); @@ -54,7 +54,7 @@ public static unsafe void TestSigEqualityInDifferentModule_Field(string name, st [InlineData(nameof(FunctionPointerHolder.Prop_DateOnly), nameof(FunctionPointerHolder.Prop_Int))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestSigEqualityInDifferentModule_Property(string name, string otherName) + public static unsafe void SigEqualityInDifferentModule_Property(string name, string otherName) { Type fph1 = typeof(FunctionPointerHolder).Project(); Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); @@ -74,7 +74,7 @@ public static unsafe void TestSigEqualityInDifferentModule_Property(string name, [InlineData(nameof(FunctionPointerHolder.MethodReturnValue_DateOnly), nameof(FunctionPointerHolder.MethodReturnValue_Int))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestSigEqualityInDifferentModule_MethodReturn(string name, string otherName) + public static unsafe void SigEqualityInDifferentModule_MethodReturn(string name, string otherName) { Type fph1 = typeof(FunctionPointerHolder).Project(); Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index efc096d77f0e20..f793415dc938c6 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -16,7 +16,7 @@ public partial class FunctionPointerTests [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestTypeMembers() + public static unsafe void TypeMembers() { // Get an arbitrary function pointer TypeInfo t = (TypeInfo)typeof(FunctionPointerHolder).Project().GetField(nameof(FunctionPointerHolder.ToString_1), Bindings).FieldType; @@ -119,12 +119,10 @@ public static unsafe void TestTypeMembers() Assert.Null(t.GetElementType()); } - private static void MyMethod(){} - [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestNonFunctionPointerThrows() + public static unsafe void NonFunctionPointerThrows() { Assert.Throws(() => typeof(int).GetFunctionPointerCallingConventions()); Assert.Throws(() => typeof(int).GetFunctionPointerParameterTypes()); @@ -156,7 +154,7 @@ public static unsafe void TestToString() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerReturn() + public static unsafe void FunctionPointerReturn() { Type t = typeof(FunctionPointerHolder).Project(); @@ -174,7 +172,7 @@ public static unsafe void TestFunctionPointerReturn() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestRequiredModifiers() + public static unsafe void RequiredModifiers() { Type t = typeof(FunctionPointerHolder).Project(); MethodInfo m = t.GetMethod(nameof(FunctionPointerHolder.RequiredModifiers), Bindings); @@ -200,7 +198,7 @@ public static unsafe void TestRequiredModifiers() "String", "Boolean*&", "MyClass", "MyStruct&")] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestMethodInfo( + public static unsafe void MethodInfo( string methodName, string methodToStringPostfix, string expectedFcnPtrReturnName, @@ -235,7 +233,7 @@ static void VerifyArg(Type paramType, string expected) [InlineData(nameof(FunctionPointerHolder.Prop_MyClass), "System.Tests.Types.FunctionPointerTests+FunctionPointerHolder+MyClass()")] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestProperty(string name, string expectedToString) + public static unsafe void Property(string name, string expectedToString) { Type t = typeof(FunctionPointerHolder).Project(); PropertyInfo p = t.GetProperty(name, Bindings); @@ -255,7 +253,7 @@ public static unsafe void TestProperty(string name, string expectedToString) [InlineData(nameof(FunctionPointerHolder.Field_MyClass), "System.Tests.Types.FunctionPointerTests+FunctionPointerHolder+MyClass()")] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestField(string name, string expectedToString) + public static unsafe void Field(string name, string expectedToString) { Type t = typeof(FunctionPointerHolder).Project(); FieldInfo f = t.GetField(name, Bindings); diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index 820dca7003a68a..a5f84eae0d79bc 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -18,7 +18,7 @@ public partial class ModifiedTypeTests [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Modified() + public static unsafe void Fields_Modified() { Type volatileInt = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings).GetModifiedFieldType(); Verify(volatileInt); @@ -59,7 +59,7 @@ void Verify(Type type) [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Generic_Unmodified() + public static unsafe void Fields_Generic_Unmodified() { Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; Assert.True(arrayGenericFcnPtr.IsGenericType); @@ -81,7 +81,7 @@ public static unsafe void TestFields_Generic_Unmodified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Generic_Modified() + public static unsafe void Fields_Generic_Modified() { Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); Assert.True(IsModifiedType(arrayGenericFcnPtr)); @@ -98,14 +98,14 @@ public static unsafe void TestFields_Generic_Modified() Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; Assert.True(IsModifiedType(paramType)); - + Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestMethods_OpenGeneric_Unmodified() + public static unsafe void Methods_OpenGeneric_Unmodified() { MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); Assert.Equal(1, mi.GetGenericArguments().Length); @@ -117,16 +117,16 @@ public static unsafe void TestMethods_OpenGeneric_Unmodified() Assert.True(p1.IsFunctionPointer); Assert.False(p1.IsGenericTypeParameter); Assert.False(IsModifiedType(p1)); - Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + Assert.Equal(0, paramType.GetRequiredCustomModifiers().Length); Assert.False(IsModifiedType(paramType)); } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095",TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestMethods_OpenGeneric_Modified() + public static unsafe void Methods_OpenGeneric_Modified() { MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); Assert.Equal(1, mi.GetGenericArguments().Length); @@ -142,7 +142,7 @@ public static unsafe void TestMethods_OpenGeneric_Modified() Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); Type paramType = p1.GetFunctionPointerParameterTypes()[0]; Assert.True(IsModifiedType(paramType)); - + Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } */ @@ -150,7 +150,7 @@ public static unsafe void TestMethods_OpenGeneric_Modified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Unmodified() + public static unsafe void Fields_Unmodified() { Type volatileInt = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings).FieldType; Verify(volatileInt); @@ -183,7 +183,7 @@ void Verify(Type type) [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Parameterized_Basic() + public static unsafe void Fields_Parameterized_Basic() { Type ptr_ptr_int = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_ptr_int), Bindings).GetModifiedFieldType(); Verify(ptr_ptr_int); @@ -205,7 +205,7 @@ void Verify(Type type) [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_Parameterized_FcnPtr() + public static unsafe void Fields_Parameterized_FcnPtr() { Type ptr_fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._ptr_fcnPtr), Bindings).GetModifiedFieldType(); Assert.True(ptr_fcnPtr.IsPointer); @@ -237,19 +237,19 @@ void Verify(Type type) [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFields_VerifyIdempotency() + public static unsafe void Fields_VerifyIdempotency() { // Call these again to ensure any backing caching strategy works. - TestFields_Modified(); - TestFields_Unmodified(); - TestFields_Parameterized_Basic(); - TestFields_Parameterized_FcnPtr(); + Fields_Modified(); + Fields_Unmodified(); + Fields_Parameterized_Basic(); + Fields_Parameterized_FcnPtr(); } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestMethodParameters() + public static unsafe void MethodParameters() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_P0IntOut), Bindings).GetParameters(); Assert.True(IsModifiedType(parameters[0].GetModifiedParameterType())); @@ -274,7 +274,7 @@ public static unsafe void TestMethodParameters() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestConstructorParameters_Unmodified() + public static unsafe void ConstructorParameters_Unmodified() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); @@ -288,7 +288,7 @@ public static unsafe void TestConstructorParameters_Unmodified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestConstructorParameters_Modified() + public static unsafe void ConstructorParameters_Modified() { ParameterInfo[] parameters = typeof(ModifiedTypeHolder).Project().GetConstructors()[0].GetParameters(); @@ -303,7 +303,7 @@ public static unsafe void TestConstructorParameters_Modified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out_Unmodified() + public static unsafe void FunctionPointerParameters_fcnPtrP0Out_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).GetModifiedFieldType(); Assert.True(fcnPtr.IsFunctionPointer); @@ -315,7 +315,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out_Unmodified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out_Modified() + public static unsafe void FunctionPointerParameters_fcnPtrP0Out_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtrP0Out), Bindings).FieldType; Assert.True(fcnPtr.IsFunctionPointer); @@ -327,7 +327,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtrP0Out_Modified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Out_Unmodified() + public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Out_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).FieldType; Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; @@ -341,7 +341,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Out_Unmod [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Out_Modified() + public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Out_Modified() { // Modified Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Out), Bindings).GetModifiedFieldType(); @@ -357,7 +357,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Out_Modif [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Unmodified() + public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).FieldType; Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; @@ -372,7 +372,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Unmod [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Modified() + public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrP0Ref), Bindings).GetModifiedFieldType(); Type param0 = fcnPtr.GetFunctionPointerParameterTypes()[0]; @@ -387,7 +387,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrP0Ref_Modif [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Unmodified() + public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Unmodified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrRetP0Out), Bindings).FieldType; Type param0 = fcnPtr.GetFunctionPointerReturnType().GetFunctionPointerParameterTypes()[0]; @@ -399,7 +399,7 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Un [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Modified() + public static unsafe void FunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Modified() { Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_fcnPtrRetP0Out), Bindings).GetModifiedFieldType(); Type param0 = fcnPtr.GetFunctionPointerReturnType().GetFunctionPointerParameterTypes()[0]; @@ -412,27 +412,21 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_fcnPtrRetP0Ref_Mo [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_deep_Unmodified() + public static unsafe void FunctionPointerParameters_fcnPtr_complex_Unmodified() { - //public static delegate*< - // delegate*, - // delegate*>[][], - // delegate*>>, // Target is the 'ref bool' - // delegate*> _deep; - - Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._deep), Bindings).FieldType; + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_complex), Bindings).FieldType; Assert.Equal("System.SByte()(System.Byte(), System.Void(System.Int32)()[][], System.Void(System.Int32, System.String, System.Boolean&)()())", fcnPtr.ToString()); - Type l1 = fcnPtr.GetFunctionPointerParameterTypes()[2]; - Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()()", l1.ToString()); + Type f1 = fcnPtr.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()()", f1.ToString()); - Type l2 = l1.GetFunctionPointerReturnType(); - Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()", l2.ToString()); + Type f2 = f1.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()", f2.ToString()); - Type l3 = l2.GetFunctionPointerReturnType(); - Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)", l3.ToString()); + Type f3 = f2.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)", f3.ToString()); - Type target = l3.GetFunctionPointerParameterTypes()[2]; + Type target = f3.GetFunctionPointerParameterTypes()[2]; Assert.Equal("System.Boolean&", target.ToString()); Assert.False(IsModifiedType(target)); @@ -443,21 +437,21 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_deep_Unmodified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void TestFunctionPointerParameters_fcnPtr_deep_Modified() + public static unsafe void FunctionPointerParameters_fcnPtr_complex_Modified() { - Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._deep), Bindings).GetModifiedFieldType(); + Type fcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._fcnPtr_complex), Bindings).GetModifiedFieldType(); Assert.Equal("System.SByte()(System.Byte(), System.Void(System.Int32)()[][], System.Void(System.Int32, System.String, System.Boolean&)()())", fcnPtr.ToString()); - Type l1 = fcnPtr.GetFunctionPointerParameterTypes()[2]; - Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()()", l1.ToString()); + Type f1 = fcnPtr.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()()", f1.ToString()); - Type l2 = l1.GetFunctionPointerReturnType(); - Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()", l2.ToString()); + Type f2 = f1.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)()", f2.ToString()); - Type l3 = l2.GetFunctionPointerReturnType(); - Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)", l3.ToString()); + Type f3 = f2.GetFunctionPointerReturnType(); + Assert.Equal("System.Void(System.Int32, System.String, System.Boolean&)", f3.ToString()); - Type target = l3.GetFunctionPointerParameterTypes()[2]; + Type target = f3.GetFunctionPointerParameterTypes()[2]; Assert.Equal("System.Boolean&", target.ToString()); Assert.True(IsModifiedType(target)); @@ -466,6 +460,92 @@ public static unsafe void TestFunctionPointerParameters_fcnPtr_deep_Modified() Assert.Equal(typeof(OutAttribute).Project(), target.GetRequiredCustomModifiers()[0]); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Property_FcnPtr_Complex_Unmodified() + { + Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).PropertyType; + Type f1 = mt.GetElementType(); + Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); + + Type f2 = f1.GetFunctionPointerParameterTypes()[1]; + Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); + + Type target = f2.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Int64()", target.ToString()); + + Assert.Equal(0, target.GetFunctionPointerCallingConventions().Length); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Property_FcnPtr_Complex_Modified() + { + Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).GetModifiedPropertyType(); + + Type f1 = mt.GetElementType(); + Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); + + Type f2 = f1.GetFunctionPointerParameterTypes()[1]; + Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); + + Type target = f2.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Int64()", target.ToString()); + Assert.Equal(1, target.GetFunctionPointerCallingConventions().Length); + Assert.Equal(typeof(CallConvCdecl).Project(), target.GetFunctionPointerCallingConventions()[0]); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void GenericMethodWithModifiers_Unmodified() + { + MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MyMethodWithGeneric), Bindings); + + Type a1 = mi.GetParameters()[0].ParameterType; + Assert.False(IsModifiedType(a1)); + Assert.Equal(typeof(Tuple).Project(), a1); + + Type ga1 = a1.GetGenericArguments()[0]; + Assert.False(IsModifiedType(ga1)); + Assert.Equal(typeof(int).Project(), ga1); + + Type ga2 = a1.GetGenericArguments()[1]; + Assert.Equal(typeof(bool).Project(), ga2); + + // Currently the modified types leak out in this case and return the modifiers. + if (!FunctionPointerTestsExtensions.IsMetadataLoadContext) + { + Assert.False(IsModifiedType(ga2)); + Assert.Equal(0, ga2.GetOptionalCustomModifiers().Length); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void GenericMethodWithModifiers_Modified() + { + MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MyMethodWithGeneric), Bindings); + + Type a1 = mi.GetParameters()[0].GetModifiedParameterType(); + Assert.True(IsModifiedType(a1)); + Assert.Equal(typeof(Tuple).Project(), a1.UnderlyingSystemType); + + Type ga1 = a1.GetGenericArguments()[0]; + Assert.True(IsModifiedType(ga1)); + Assert.Equal(typeof(int).Project(), ga1.UnderlyingSystemType); + Assert.Equal(0, ga1.GetOptionalCustomModifiers().Length); + + Type ga2 = a1.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]); + } + private static bool IsModifiedType(Type type) { return !ReferenceEquals(type, type.UnderlyingSystemType); @@ -483,7 +563,7 @@ public ModifiedTypeHolder(delegate* d) { } // Although function pointers can't be used in generics directly, they can be used indirectly // through an array or pointer. // NOTE: commented out due to compiler issue on NativeAOT: #81117 - // public static volatile Tuple[]> _arrayGenericFcnPtr; + //public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; public static int*[] _array_ptr_int; @@ -494,21 +574,48 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } // NOTE: commented out due to compiler issue on NativeAOT: #81117 - // public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } + //public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } + public delegate* + < + delegate*, // p0 + delegate* // p1 + < + delegate*, // p0 + delegate*, // p1 + delegate* unmanaged[Cdecl], // p2 + void // ret + >, + bool // ret + >[] Property_FcnPtr_Complex { get; } public static delegate* FcnPtrP0Out { get; set; } public static delegate* _fcnPtrP0Out; public static delegate*, void> _fcnPtr_fcnPtrP0Out; public static delegate*, void> _fcnPtr_fcnPtrP0Ref; public static delegate*> _fcnPtr_fcnPtrRetP0Out; - public static delegate*< - delegate*, - delegate*>[][], - delegate*>>, - delegate*> _deep; + + public static delegate* + < + delegate*, // p0 + delegate* // p1 + < + delegate* // ret + >[][], + delegate* // p2 + < + delegate* // ret + < + delegate* // ret + < + int, string, out bool, void // p0-3 + > + > + >, + delegate* // ret + > _fcnPtr_complex; } } } diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs new file mode 100644 index 00000000000000..b0e6e8948725a5 --- /dev/null +++ b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +public class GenericWithModifiers +{ + // The 'const' modifier is not available in C#, so we generate IL with "IsConst" modopt. + public void MyMethodWithGeneric(Tuple t) { } + +} diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il new file mode 100644 index 00000000000000..57ca0f56d417b6 --- /dev/null +++ b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il @@ -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. + +.assembly extern System.Runtime +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A) + .ver 4:0:0:0 +} + +.assembly TestReflectionILAssembly +{ + .ver 1:0:0:0 +} + +.module TestReflectionILAssembly.dll + +.namespace System.Tests +{ + .class public auto ansi beforefieldinit GenericWithModifiers + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } + + .method public hidebysig instance void MyMethodWithGeneric(class [System.Runtime]System.Tuple`2 t) cil managed + { + .maxstack 8 + IL_0000: nop + IL_0001: ret + } + } +} diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj b/src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj new file mode 100644 index 00000000000000..15ff9670cfb8a4 --- /dev/null +++ b/src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj @@ -0,0 +1,10 @@ + + + 1.0.0.0 + netstandard2.0 + Microsoft + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 8887d1d994f457..33f9189f938077 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -666,7 +666,6 @@ - @@ -678,8 +677,8 @@ + - @@ -708,6 +707,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs deleted file mode 100644 index eaa3aa2be4c9a0..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MdSigCallingConvention.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Reflection -{ - /// - /// Represents the first byte of a method signature. - /// Calling conventions have been extended into modopts for Unmanaged. - /// - [Flags] - internal enum MdSigCallingConvention : byte - { - CallConvMask = 0x0f, // Calling convention is bottom 4 bits - - Default = 0x00, - C = 0x01, - StdCall = 0x02, - ThisCall = 0x03, - FastCall = 0x04, - Vararg = 0x05, - Field = 0x06, - LocalSig = 0x07, - Property = 0x08, - Unmanaged = 0x09, - GenericInst = 0x0a, // generic method instantiation - - Generic = 0x10, // Generic method sig with explicit number of type arguments (precedes ordinary parameter count) - HasThis = 0x20, // Top bit indicates a 'this' parameter - ExplicitThis = 0x40, // This parameter is explicitly in the signature - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs index 7df9ae22de39e4..871e7118e78281 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs @@ -10,13 +10,13 @@ namespace System.Reflection /// internal sealed class ModifiedContainerType : ModifiedType { - private readonly ModifiedType? _elementModifiedType; + private readonly ModifiedType _elementModifiedType; public ModifiedContainerType( Type containerType, object? signatureProvider, int rootSignatureParameterIndex, - int nestedSignatureIndex, + ref int nestedSignatureIndex, int nestedSignatureParameterIndex, bool isRoot) : base( @@ -32,7 +32,7 @@ public ModifiedContainerType( containerType.GetElementType()!, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, + ref nestedSignatureIndex, nestedSignatureParameterIndex : -1); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index 1c4fd179660c1c..994e9727c6d6f6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -13,20 +13,19 @@ internal sealed partial class ModifiedFunctionPointerType : ModifiedType private readonly ModifiedType[] _parameterTypes; private readonly ModifiedType _returnType; - private Type[]? _callingConventions; public ModifiedFunctionPointerType( Type functionPointerType, object? signatureProvider, int rootSignatureParameterIndex, - int nestedSignatureIndex, + ref int nestedSignatureIndex, int nestedSignatureParameterIndex, bool isRoot) : base( functionPointerType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex + 1, + ++nestedSignatureIndex, nestedSignatureParameterIndex, isRoot) { @@ -35,7 +34,7 @@ public ModifiedFunctionPointerType( functionPointerType.GetFunctionPointerReturnType(), signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex + 1, + ref nestedSignatureIndex, nestedSignatureParameterIndex: 0); Type[] parameters = functionPointerType.GetFunctionPointerParameterTypes(); @@ -47,7 +46,7 @@ public ModifiedFunctionPointerType( parameters[i], signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex + 1, + ref nestedSignatureIndex, nestedSignatureParameterIndex: i + 1); } @@ -59,53 +58,33 @@ public ModifiedFunctionPointerType( public override Type[] GetFunctionPointerCallingConventions() { - _callingConventions ??= CreateCallingConventions(); - return CloneArray(_callingConventions); - } - - private Type[] CreateCallingConventions() - { - Type[] returnTypeOptionalModifiers = GetFunctionPointerReturnType().GetOptionalCustomModifiers(); - ArrayBuilder builder = default; - bool foundCallingConvention = false; - - for (int i = 0; i < returnTypeOptionalModifiers.Length; i++) + // Normalize the calling conventions by manufacturing a type. + switch (GetCallingConvention()) { - Type type = returnTypeOptionalModifiers[i]; - if (type.FullName!.StartsWith(CallingConventionTypePrefix, StringComparison.Ordinal)) - { - builder.Add(type); - - if (type == typeof(CallConvCdecl) || - type == typeof(CallConvFastcall) || - type == typeof(CallConvStdcall) || - type == typeof(CallConvThiscall)) + case SignatureCallingConvention.Cdecl: + builder.Add(typeof(CallConvCdecl)); + break; + case SignatureCallingConvention.StdCall: + builder.Add(typeof(CallConvStdcall)); + break; + case SignatureCallingConvention.ThisCall: + builder.Add(typeof(CallConvThiscall)); + break; + case SignatureCallingConvention.FastCall: + builder.Add(typeof(CallConvFastcall)); + break; + case SignatureCallingConvention.Unmanaged: + // For the above cases, there will be no other custom calling convention modifiers. + foreach (Type type in GetFunctionPointerReturnType().GetOptionalCustomModifiers()) { - foundCallingConvention = true; + if (type.FullName!.StartsWith(CallingConventionTypePrefix, StringComparison.Ordinal)) + { + builder.Add(type); + } } - } - } - - if (!foundCallingConvention) - { - // Normalize the calling conventions by manufacturing a type. - switch (GetCallingConvention()) - { - case MdSigCallingConvention.C: - builder.Add(typeof(CallConvCdecl)); - break; - case MdSigCallingConvention.StdCall: - builder.Add(typeof(CallConvStdcall)); - break; - case MdSigCallingConvention.ThisCall: - builder.Add(typeof(CallConvThiscall)); - break; - case MdSigCallingConvention.FastCall: - builder.Add(typeof(CallConvFastcall)); - break; - } + break; } return builder.Count == 0 ? EmptyTypes : builder.ToArray(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index 72f963f763e8e9..6abdd151688f67 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -13,14 +13,14 @@ public ModifiedGenericType( Type genericType, object? signatureProvider, int rootSignatureParameterIndex, - int nestedSignatureIndex, + ref int nestedSignatureIndex, int nestedSignatureParameterIndex, bool isRoot) : base( genericType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, // To support modifiers on generic types, pass nestedSignatureIndex+1 + ++nestedSignatureIndex, nestedSignatureParameterIndex, isRoot) { @@ -35,8 +35,9 @@ public ModifiedGenericType( genericArguments[i], signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, // To support modifiers on generic types, pass nestedSignatureIndex+1 - nestedSignatureParameterIndex: -1); // To support modifiers on generic types, pass index value. + ref nestedSignatureIndex, + // Since generic signatures don't have a return type, we use +1 here. + nestedSignatureParameterIndex: i + 1); } _argumentTypes = modifiedTypes; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs new file mode 100644 index 00000000000000..f72c025f4c32da --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System.Reflection +{ + /// + /// An array, pointer or reference type. + /// + internal sealed class ModifiedHasElementType : ModifiedType + { + private readonly ModifiedType? _elementModifiedType; + + public ModifiedHasElementType( + Type containerType, + object? signatureProvider, + int rootSignatureParameterIndex, + ref int nestedSignatureIndex, + int nestedSignatureParameterIndex, + bool isRoot) + : base( + containerType, + signatureProvider, + rootSignatureParameterIndex, + nestedSignatureIndex, + nestedSignatureParameterIndex, + isRoot) + { + Debug.Assert(containerType.HasElementType); + _elementModifiedType = Create( + containerType.GetElementType()!, + signatureProvider, + rootSignatureParameterIndex, + ref nestedSignatureIndex, + nestedSignatureParameterIndex : -1); + } + + public override Type? GetElementType() => _elementModifiedType; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index ba56aa884f1b7e..a3c5f75cd3ffa0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -12,7 +12,7 @@ internal abstract partial class ModifiedType : TypeDelegator private readonly object? _signatureProvider; // These 3 fields, in order, determine the lookup hierarchy for custom modifiers. - // The native tree traveral must match the managed semantics in order for indexes to match up. + // The native tree traversal must match the managed semantics in order for indexes to match up. private readonly int _rootSignatureParameterIndex; private readonly int _nestedSignatureIndex; private readonly int _nestedSignatureParameterIndex; @@ -43,7 +43,7 @@ protected static ModifiedType Create( Type unmodifiedType, object? signatureProvider, int rootSignatureParameterIndex, - int nestedSignatureIndex, + ref int nestedSignatureIndex, int nestedSignatureParameterIndex, bool isRoot = false) { @@ -55,17 +55,17 @@ protected static ModifiedType Create( unmodifiedType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, + ref nestedSignatureIndex, nestedSignatureParameterIndex, isRoot); } else if (unmodifiedType.HasElementType) { - modifiedType = new ModifiedContainerType( + modifiedType = new ModifiedHasElementType( unmodifiedType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, + ref nestedSignatureIndex, nestedSignatureParameterIndex, isRoot); } @@ -75,7 +75,7 @@ protected static ModifiedType Create( unmodifiedType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, + ref nestedSignatureIndex, nestedSignatureParameterIndex, isRoot); } @@ -85,7 +85,7 @@ protected static ModifiedType Create( unmodifiedType, signatureProvider, rootSignatureParameterIndex, - nestedSignatureIndex, + nestedSignatureIndex, // Passing byref is not necessary; no more recursion. nestedSignatureParameterIndex, isRoot); } @@ -137,6 +137,7 @@ public override Type[] GetOptionalCustomModifiers() // TypeDelegator doesn't forward these the way we want: public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. + public override Type GetGenericTypeDefinition() => typeImpl.GetGenericTypeDefinition(); // not forwarded; we don't wrap public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. public override bool Equals(Type? other) // Not forwarded. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureCallingConvention.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureCallingConvention.cs new file mode 100644 index 00000000000000..3d261eca72588a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureCallingConvention.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection +{ + /// + /// Values from the "CallKind" byte dealing with calling conventions used by reflection. + /// Calling conventions have since been extended into modopts for Unmanaged. + /// + internal enum SignatureCallingConvention : byte + { + Default = 0, + Cdecl = 1, + StdCall = 2, + ThisCall = 3, + FastCall = 4, + Unmanaged = 9, + } +} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln index 9580f272000443..d97438e639aade 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln +++ b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln @@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.MetadataL EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{F85BDD51-AC29-4D8D-8257-C509BED9A448}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestReflectionILAssembly", "..\Common\tests\System\TestReflectionILAssembly\TestReflectionILAssembly.ilproj", "{6DA9926C-8763-42A2-A51A-EDF8684C80A8}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{4361CEFA-8238-4247-9CC5-D99DF794843C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{7393C7CD-4C31-4B1C-96DC-1D46D240538A}" @@ -43,6 +45,10 @@ Global {6A69770F-4F95-411F-ACAE-2B902EB62161}.Debug|Any CPU.Build.0 = Debug|Any CPU {6A69770F-4F95-411F-ACAE-2B902EB62161}.Release|Any CPU.ActiveCfg = Release|Any CPU {6A69770F-4F95-411F-ACAE-2B902EB62161}.Release|Any CPU.Build.0 = Release|Any CPU + {6DA9926C-8763-42A2-A51A-EDF8684C80A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DA9926C-8763-42A2-A51A-EDF8684C80A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DA9926C-8763-42A2-A51A-EDF8684C80A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DA9926C-8763-42A2-A51A-EDF8684C80A8}.Release|Any CPU.Build.0 = Release|Any CPU {22BDB23C-24DE-4C3C-9A18-A048C445EDC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {22BDB23C-24DE-4C3C-9A18-A048C445EDC1}.Debug|Any CPU.Build.0 = Debug|Any CPU {22BDB23C-24DE-4C3C-9A18-A048C445EDC1}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -99,6 +105,7 @@ Global {6A69770F-4F95-411F-ACAE-2B902EB62161} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {D28B6414-C82C-4BDE-B8BB-A4E3297A0651} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {F85BDD51-AC29-4D8D-8257-C509BED9A448} = {F45DECCA-03D3-4087-AB01-F099C027DC33} + {6DA9926C-8763-42A2-A51A-EDF8684C80A8} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {22BDB23C-24DE-4C3C-9A18-A048C445EDC1} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} {E524DAF8-3F2C-4EC5-833D-E7D182055A66} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} {7AE8D7FD-6CEE-4F70-8675-0896AA6487BD} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index 631ca77f1d70ed..51e221440c6d5c 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) System.Reflection @@ -80,8 +80,8 @@ - - + + @@ -133,7 +133,7 @@ - + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.net.cs similarity index 100% rename from src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.cs rename to src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.net.cs diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.net7.cs similarity index 100% rename from src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.netcoreapp.v7.cs rename to src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/TypeExtensions.net7.cs diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs index a5194f98992588..850a7a2750d453 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedFunctionPointerType.cs @@ -52,43 +52,31 @@ private Type[] CreateCallingConventions(Type[] returnTypeOptionalModifiers, RoFu { List builder = new(returnTypeOptionalModifiers.Length + 1); - bool foundCallingConvention = false; - - for (int i = 0; i < returnTypeOptionalModifiers.Length; i++) + // Normalize the calling conventions by manufacturing a type. + switch (functionPointerType.CallKind) { - Type type = returnTypeOptionalModifiers[i]; - if (type.FullName!.StartsWith(CallingConventionTypePrefix, StringComparison.Ordinal)) - { - builder.Add(type); - - if (type == CDeclType || - type == StdCallType || - type == ThisCallType || - type == FastCallType) + case Metadata.SignatureCallingConvention.CDecl: + builder.Add(CDeclType); + break; + case Metadata.SignatureCallingConvention.StdCall: + builder.Add(StdCallType); + break; + case Metadata.SignatureCallingConvention.ThisCall: + builder.Add(ThisCallType); + break; + case Metadata.SignatureCallingConvention.FastCall: + builder.Add(FastCallType); + break; + case Metadata.SignatureCallingConvention.Unmanaged: + for (int i = 0; i < returnTypeOptionalModifiers.Length; i++) { - foundCallingConvention = true; + Type type = returnTypeOptionalModifiers[i]; + if (type.FullName!.StartsWith(CallingConventionTypePrefix, StringComparison.Ordinal)) + { + builder.Add(type); + } } - } - } - - if (!foundCallingConvention) - { - // Normalize the calling conventions by manufacturing a type. - switch (functionPointerType.CallKind) - { - case Metadata.SignatureCallingConvention.CDecl: - builder.Add(CDeclType); - break; - case Metadata.SignatureCallingConvention.StdCall: - builder.Add(StdCallType); - break; - case Metadata.SignatureCallingConvention.ThisCall: - builder.Add(ThisCallType); - break; - case Metadata.SignatureCallingConvention.FastCall: - builder.Add(FastCallType); - break; - } + break; } return builder.Count == 0 ? EmptyTypes : builder.ToArray(); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedHasElementType.cs similarity index 80% rename from src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs rename to src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedHasElementType.cs index 4a92bdf9177291..0e146e5922c31e 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedContainerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedHasElementType.cs @@ -9,11 +9,11 @@ namespace System.Reflection /// /// An array, pointer or reference type that is modified. /// - internal sealed class RoModifiedContainerType : RoModifiedType + internal sealed class RoModifiedHasElementType : RoModifiedType { private RoModifiedType? _elementModifiedType; - public RoModifiedContainerType(RoType unmodifiedType) : base(unmodifiedType) + public RoModifiedHasElementType(RoType unmodifiedType) : base(unmodifiedType) { Debug.Assert(unmodifiedType.HasElementType); _elementModifiedType = Create(unmodifiedType.GetRoElementType()!); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs index 6138c7b9ae6593..83094bc6845947 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs @@ -33,7 +33,7 @@ public static RoModifiedType Create(RoType unmodifiedType) } else if (unmodifiedType.HasElementType) { - modifiedType = new RoModifiedContainerType(unmodifiedType); + modifiedType = new RoModifiedHasElementType(unmodifiedType); } else { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index 7f29f8df21b711..82be945597ab5c 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -75,6 +75,7 @@ + diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index 20891dd9c2af26..b539b4e3108b9e 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -41,6 +41,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.ReflectionIn EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCollectibleAssembly", "tests\TestCollectibleAssembly\TestCollectibleAssembly.csproj", "{C230AC88-A377-4BEB-824F-AB174C14DC86}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestReflectionILAssembly", "..\Common\tests\System\TestReflectionILAssembly\TestReflectionILAssembly.ilproj", "{AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{B7975A39-2E87-4C6C-A7EC-1F5926676800}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLoadAssembly", "tests\TestLoadAssembly\TestLoadAssembly.csproj", "{1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}" @@ -267,6 +269,24 @@ Global {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Release|x64.Build.0 = Release|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Release|x86.ActiveCfg = Release|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Release|x86.Build.0 = Release|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Checked|Any CPU.Build.0 = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Checked|x64.ActiveCfg = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Checked|x64.Build.0 = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Checked|x86.ActiveCfg = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Checked|x86.Build.0 = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Debug|x64.ActiveCfg = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Debug|x64.Build.0 = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Debug|x86.ActiveCfg = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Debug|x86.Build.0 = Debug|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Release|Any CPU.Build.0 = Release|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Release|x64.ActiveCfg = Release|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Release|x64.Build.0 = Release|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Release|x86.ActiveCfg = Release|Any CPU + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}.Release|x86.Build.0 = Release|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|x64.ActiveCfg = Debug|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|x86.ActiveCfg = Debug|Any CPU @@ -568,6 +588,7 @@ Global {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {0F83B07B-2E3F-4708-BE6D-7A8DA8168803} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} + {AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} {F6A8185B-07C6-401D-9B40-3C560239E05F} = {28140562-A65A-48E9-ABAB-53BA939084F0} {EC777939-BE30-4ED9-9FE1-451DD7472467} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 9f08b4e8106502..1a3ccd5e2853d2 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser true @@ -338,7 +338,8 @@ - + + diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs index bd1dda86aabd46..2c143398e1f593 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs @@ -5,6 +5,6 @@ namespace System.Reflection { internal partial class ModifiedFunctionPointerType { - private MdSigCallingConvention GetCallingConvention() => throw new NotSupportedException(); + private SignatureCallingConvention GetCallingConvention() => throw new NotSupportedException(); } } From 64a987ececa2603c7aee8f0849391e01bd6cf3a4 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 26 Jan 2023 09:35:31 -0600 Subject: [PATCH 10/20] Fix MLC edge case; Native AOT test enable\disable --- .../Common/tests/System/ModifiedTypeTests.cs | 47 +++++++++---------- .../Reflection/TypeLoading/General/Helpers.cs | 5 +- .../Types/RoConstructedGenericType.cs | 1 + .../Types/RoFunctionPointerType.cs | 2 +- .../Reflection/TypeLoading/Types/RoType.cs | 5 +- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index a5f84eae0d79bc..b969ed66c5a8ad 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -54,8 +54,6 @@ void Verify(Type type) } } - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -145,7 +143,6 @@ public static unsafe void Methods_OpenGeneric_Modified() Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } - */ [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -460,6 +457,8 @@ public static unsafe void FunctionPointerParameters_fcnPtr_complex_Modified() Assert.Equal(typeof(OutAttribute).Project(), target.GetRequiredCustomModifiers()[0]); } + // NOTE: commented out due to compiler issue on NativeAOT: #81117 + /* [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -496,6 +495,7 @@ public static unsafe void Property_FcnPtr_Complex_Modified() Assert.Equal(1, target.GetFunctionPointerCallingConventions().Length); Assert.Equal(typeof(CallConvCdecl).Project(), target.GetFunctionPointerCallingConventions()[0]); } + */ [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -513,14 +513,9 @@ public static unsafe void GenericMethodWithModifiers_Unmodified() Assert.Equal(typeof(int).Project(), ga1); Type ga2 = a1.GetGenericArguments()[1]; + Assert.False(IsModifiedType(ga2)); Assert.Equal(typeof(bool).Project(), ga2); - - // Currently the modified types leak out in this case and return the modifiers. - if (!FunctionPointerTestsExtensions.IsMetadataLoadContext) - { - Assert.False(IsModifiedType(ga2)); - Assert.Equal(0, ga2.GetOptionalCustomModifiers().Length); - } + Assert.Equal(0, ga2.GetOptionalCustomModifiers().Length); } [Fact] @@ -562,8 +557,7 @@ public ModifiedTypeHolder(delegate* d) { } // Although function pointers can't be used in generics directly, they can be used indirectly // through an array or pointer. - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - //public static volatile Tuple[]> _arrayGenericFcnPtr; + public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; public static int*[] _array_ptr_int; @@ -573,23 +567,24 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - //public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } + public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } - public delegate* - < - delegate*, // p0 - delegate* // p1 - < - delegate*, // p0 - delegate*, // p1 - delegate* unmanaged[Cdecl], // p2 - void // ret - >, - bool // ret - >[] Property_FcnPtr_Complex { get; } + + // NOTE: commented out due to compiler issue on NativeAOT: #81117 + //public delegate* + //< + // delegate*, // p0 + // delegate* // p1 + // < + // delegate*, // p0 + // delegate*, // p1 + // delegate* unmanaged[Cdecl], // p2 + // void // ret + // >, + // bool // ret + //>[] Property_FcnPtr_Complex { get; } public static delegate* FcnPtrP0Out { get; set; } public static delegate* _fcnPtrP0Out; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs index 384e049e730104..9de7d560950f40 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs @@ -28,7 +28,10 @@ internal static class Helpers } [return: NotNullIfNotNull(nameof(original))] - public static Type[]? CloneArrayToUnmodified(this Type[]? original) + // Converts an array of modified types to unmodified types when unmodified are requested. + // This prevents inconsistencies such as allowing modifiers to be returned. + // This doesn't affect performance since we need to clone arrays anyway before returning to the caller. + public static Type[]? CloneArrayToUnmodifiedTypes(this Type[]? original) { if (original == null) return null; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.cs index 25d76f397f8a52..e97c5e9351adb1 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.cs @@ -121,6 +121,7 @@ public sealed override string ToString() internal sealed override RoType[] GetGenericTypeParametersNoCopy() => Array.Empty(); internal sealed override RoType[] GetGenericTypeArgumentsNoCopy() => _genericTypeArguments; protected internal sealed override RoType[] GetGenericArgumentsNoCopy() => _genericTypeArguments; + public sealed override Type[] GetGenericArguments() => _genericTypeArguments.CloneArrayToUnmodifiedTypes(); [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] public sealed override Type MakeGenericType(params Type[] typeArguments) => throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this)); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs index 4bb7def083ad97..40847efb0b1cd6 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs @@ -47,7 +47,7 @@ internal RoFunctionPointerType(EcmaModule module, MethodSignature signat public sealed override bool IsFunctionPointer => true; public sealed override bool IsUnmanagedFunctionPointer => _isUnmanaged; public sealed override Type GetFunctionPointerReturnType() => _returnType.UnderlyingSystemType; - public sealed override Type[] GetFunctionPointerParameterTypes() => _parameterTypes.CloneArrayToUnmodified(); + public sealed override Type[] GetFunctionPointerParameterTypes() => _parameterTypes.CloneArrayToUnmodifiedTypes(); protected sealed override string? ComputeFullName() => null; protected sealed override string ComputeName() => string.Empty; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 22c50ba8c62177..2e8a52290f5700 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -106,7 +106,10 @@ public override Type[] GetFunctionPointerCallingConventions() // .NET 2.0 apis for detecting/deconstructing generic type definition/constructed generic types. public sealed override bool IsGenericType => IsConstructedGenericType || IsGenericTypeDefinition; - public sealed override Type[] GetGenericArguments() => GetGenericArgumentsNoCopy().CloneArray(); + + // Don't seal since we may need to convert any modified types to unmodified. + public override Type[] GetGenericArguments() => GetGenericArgumentsNoCopy().CloneArray(); + protected internal abstract RoType[] GetGenericArgumentsNoCopy(); // Naming From 5f8a81e315962de3de4323dd956a1931040b358d Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 26 Jan 2023 12:26:29 -0600 Subject: [PATCH 11/20] Native AOT test enable\disable; add a generic test --- .../Common/tests/System/ModifiedTypeTests.cs | 213 ++++++++++-------- .../GenericWithModifiers.il | 9 +- 2 files changed, 133 insertions(+), 89 deletions(-) diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index b969ed66c5a8ad..284f8be70eb0ce 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -100,49 +100,56 @@ public static unsafe void Fields_Generic_Modified() Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); } - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void Methods_OpenGeneric_Unmodified() - { - MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); - Assert.Equal(1, mi.GetGenericArguments().Length); - Type p0 = mi.GetGenericArguments()[0]; - Assert.True(p0.IsGenericMethodParameter); - Assert.False(IsModifiedType(p0)); - - Type p1 = mi.GetParameters()[1].ParameterType.GetElementType(); - Assert.True(p1.IsFunctionPointer); - Assert.False(p1.IsGenericTypeParameter); - Assert.False(IsModifiedType(p1)); - Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); - Type paramType = p1.GetFunctionPointerParameterTypes()[0]; - Assert.Equal(0, paramType.GetRequiredCustomModifiers().Length); - Assert.False(IsModifiedType(paramType)); - } - - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095",TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void Methods_OpenGeneric_Modified() - { - MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); - Assert.Equal(1, mi.GetGenericArguments().Length); - Type p0 = mi.GetGenericArguments()[0]; - Assert.True(p0.IsGenericMethodParameter); - Assert.False(IsModifiedType(p0)); - - Type p1 = mi.GetParameters()[1].GetModifiedParameterType().GetElementType(); - Assert.True(p1.IsFunctionPointer); - Assert.False(p1.IsGenericTypeParameter); - Assert.True(IsModifiedType(p1)); - - Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); - Type paramType = p1.GetFunctionPointerParameterTypes()[0]; - Assert.True(IsModifiedType(paramType)); - Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); - Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); - } + // NOTE: commented out due to compiler issue on NativeAOT: #81117 + //[Fact] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + //public static unsafe void Methods_OpenGeneric_Unmodified() + //{ + // MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); + // Assert.Equal(1, mi.GetGenericArguments().Length); + // Type p0 = mi.GetGenericArguments()[0]; + // Assert.True(p0.IsGenericMethodParameter); + // Assert.False(IsModifiedType(p0)); + + // Type arr = mi.GetParameters()[1].ParameterType; + // Assert.False(IsModifiedType(arr)); + + // Type p1 = arr.GetElementType(); + // Assert.True(p1.IsFunctionPointer); + // Assert.False(p1.IsGenericTypeParameter); + // Assert.False(IsModifiedType(p1)); + // Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); + // Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + // Assert.Equal(0, paramType.GetRequiredCustomModifiers().Length); + // Assert.False(IsModifiedType(paramType)); + //} + + //[Fact] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095",TestRuntimes.Mono)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + //public static unsafe void Methods_OpenGeneric_Modified() + //{ + // MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); + // Assert.Equal(1, mi.GetGenericArguments().Length); + // Type p0 = mi.GetGenericArguments()[0]; + // Assert.True(p0.IsGenericMethodParameter); + // Assert.False(IsModifiedType(p0)); + + // Type arr = mi.GetParameters()[1].GetModifiedParameterType(); + // Assert.True(IsModifiedType(arr)); + + // Type p1 = arr.GetElementType(); + // Assert.True(p1.IsFunctionPointer); + // Assert.False(p1.IsGenericTypeParameter); + // Assert.True(IsModifiedType(p1)); + + // Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); + // Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + // Assert.True(IsModifiedType(paramType)); + // Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); + // Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); + //} [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -458,51 +465,50 @@ public static unsafe void FunctionPointerParameters_fcnPtr_complex_Modified() } // NOTE: commented out due to compiler issue on NativeAOT: #81117 - /* - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void Property_FcnPtr_Complex_Unmodified() - { - Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).PropertyType; - Type f1 = mt.GetElementType(); - Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); - - Type f2 = f1.GetFunctionPointerParameterTypes()[1]; - Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); - - Type target = f2.GetFunctionPointerParameterTypes()[2]; - Assert.Equal("System.Int64()", target.ToString()); - - Assert.Equal(0, target.GetFunctionPointerCallingConventions().Length); - } - - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void Property_FcnPtr_Complex_Modified() - { - Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).GetModifiedPropertyType(); - - Type f1 = mt.GetElementType(); - Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); - - Type f2 = f1.GetFunctionPointerParameterTypes()[1]; - Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); - - Type target = f2.GetFunctionPointerParameterTypes()[2]; - Assert.Equal("System.Int64()", target.ToString()); - Assert.Equal(1, target.GetFunctionPointerCallingConventions().Length); - Assert.Equal(typeof(CallConvCdecl).Project(), target.GetFunctionPointerCallingConventions()[0]); - } - */ + //[Fact] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + //public static unsafe void Property_FcnPtr_Complex_Unmodified() + //{ + // Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).PropertyType; + // Type f1 = mt.GetElementType(); + // Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); + + // Type f2 = f1.GetFunctionPointerParameterTypes()[1]; + // Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); + + // Type target = f2.GetFunctionPointerParameterTypes()[2]; + // Assert.Equal("System.Int64()", target.ToString()); + + // Assert.Equal(0, target.GetFunctionPointerCallingConventions().Length); + //} + + //[Fact] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + //public static unsafe void Property_FcnPtr_Complex_Modified() + //{ + // Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).GetModifiedPropertyType(); + + // Type f1 = mt.GetElementType(); + // Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); + + // Type f2 = f1.GetFunctionPointerParameterTypes()[1]; + // Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); + + // Type target = f2.GetFunctionPointerParameterTypes()[2]; + // Assert.Equal("System.Int64()", target.ToString()); + // Assert.Equal(1, target.GetFunctionPointerCallingConventions().Length); + // Assert.Equal(typeof(CallConvCdecl).Project(), target.GetFunctionPointerCallingConventions()[0]); + //} [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void GenericMethodWithModifiers_Unmodified() + public static unsafe void MethodWithGenericParameter_Unmodified() { - MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MyMethodWithGeneric), Bindings); + MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MethodWithGenericParameter), Bindings); + Assert.False(mi.ContainsGenericParameters); Type a1 = mi.GetParameters()[0].ParameterType; Assert.False(IsModifiedType(a1)); @@ -521,9 +527,10 @@ public static unsafe void GenericMethodWithModifiers_Unmodified() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void GenericMethodWithModifiers_Modified() + public static unsafe void MethodWithGenericParameter_Modified() { - MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MyMethodWithGeneric), Bindings); + MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.MethodWithGenericParameter), Bindings); + Assert.False(mi.ContainsGenericParameters); Type a1 = mi.GetParameters()[0].GetModifiedParameterType(); Assert.True(IsModifiedType(a1)); @@ -541,6 +548,34 @@ public static unsafe void GenericMethodWithModifiers_Modified() Assert.Equal(typeof(IsConst).Project(), ga2.GetOptionalCustomModifiers()[0]); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void GenericMethod_Unmodified() + { + MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.GenericMethod), Bindings); + Assert.True(mi.ContainsGenericParameters); + + Type a1 = mi.GetParameters()[0].ParameterType; + Assert.False(IsModifiedType(a1)); + Assert.True(a1.ContainsGenericParameters); + Assert.Equal(0, a1.GetOptionalCustomModifiers().Length); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void GenericMethod_Modified() + { + MethodInfo mi = typeof(GenericWithModifiers).Project().GetMethod(nameof(GenericWithModifiers.GenericMethod), Bindings); + Assert.True(mi.ContainsGenericParameters); + + Type a1 = mi.GetParameters()[0].GetModifiedParameterType(); + Assert.True(IsModifiedType(a1)); + Assert.True(a1.ContainsGenericParameters); + Assert.Equal(1, a1.GetOptionalCustomModifiers().Length); + } + private static bool IsModifiedType(Type type) { return !ReferenceEquals(type, type.UnderlyingSystemType); @@ -555,8 +590,8 @@ public ModifiedTypeHolder(delegate* d) { } public static volatile int* _volatileIntPointer; public static volatile delegate* unmanaged[Cdecl] _volatileFcnPtr; - // Although function pointers can't be used in generics directly, they can be used indirectly - // through an array or pointer. + // Although function pointer types can't be used as generic parameters, they can be used indirectly + // as an array element type. public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; @@ -567,7 +602,9 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } - public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } + + // NOTE: commented out due to compiler issue on NativeAOT: #81117 + //public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il index 57ca0f56d417b6..b54ccae300ea30 100644 --- a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il +++ b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il @@ -29,7 +29,14 @@ IL_0007: ret } - .method public hidebysig instance void MyMethodWithGeneric(class [System.Runtime]System.Tuple`2 t) cil managed + .method public hidebysig instance void MethodWithGenericParameter(class [System.Runtime]System.Tuple`2 t) cil managed + { + .maxstack 8 + IL_0000: nop + IL_0001: ret + } + + .method public hidebysig instance void GenericMethod(!!T modopt([System.Runtime]System.Runtime.CompilerServices.IsConst) t) cil managed { .maxstack 8 IL_0000: nop From 2df9d2b161bdfd6fc02e58f5805158c18e47dc1e Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 26 Jan 2023 16:18:41 -0600 Subject: [PATCH 12/20] Native AOT test enable\disable; fix missing overload --- .../Common/tests/System/ModifiedTypeTests.cs | 85 ++++++++++--------- .../GenericWithModifiers.cs | 11 --- .../src/System/Reflection/ModifiedType.cs | 11 +-- 3 files changed, 50 insertions(+), 57 deletions(-) delete mode 100644 src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index 284f8be70eb0ce..cc3537b8ca2755 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Reflection; using System.Reflection.Tests; using System.Runtime.CompilerServices; @@ -54,53 +55,54 @@ void Verify(Type type) } } - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void Fields_Generic_Unmodified() - { - Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; - Assert.True(arrayGenericFcnPtr.IsGenericType); - Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); - Assert.False(IsModifiedType(arrayGenericFcnPtr)); + // NOTE: the below tests commented out due to compiler issue on NativeAOT: #81117 - Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; - Assert.False(IsModifiedType(genericParam)); + //[Fact] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + //public static unsafe void Fields_Generic_Unmodified() + //{ + // Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; + // Assert.True(arrayGenericFcnPtr.IsGenericType); + // Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); + // Assert.False(IsModifiedType(arrayGenericFcnPtr)); - Type fcnPtr = genericParam.GetElementType(); - Assert.True(fcnPtr.IsFunctionPointer); - Assert.False(IsModifiedType(fcnPtr)); + // Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; + // Assert.False(IsModifiedType(genericParam)); - Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); - Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; - Assert.False(IsModifiedType(paramType)); - } + // Type fcnPtr = genericParam.GetElementType(); + // Assert.True(fcnPtr.IsFunctionPointer); + // Assert.False(IsModifiedType(fcnPtr)); - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void Fields_Generic_Modified() - { - Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); - Assert.True(IsModifiedType(arrayGenericFcnPtr)); - Assert.True(arrayGenericFcnPtr.IsGenericType); - Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); + // Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); + // Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; + // Assert.False(IsModifiedType(paramType)); + //} - Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; - Assert.True(IsModifiedType(genericParam)); + //[Fact] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + //public static unsafe void Fields_Generic_Modified() + //{ + // Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); + // Assert.True(IsModifiedType(arrayGenericFcnPtr)); + // Assert.True(arrayGenericFcnPtr.IsGenericType); + // Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); - Type fcnPtr = genericParam.GetElementType(); - Assert.True(fcnPtr.IsFunctionPointer); - Assert.True(IsModifiedType(fcnPtr)); + // Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; + // Assert.True(IsModifiedType(genericParam)); - Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); - Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; - Assert.True(IsModifiedType(paramType)); - Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); - Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); - } + // Type fcnPtr = genericParam.GetElementType(); + // Assert.True(fcnPtr.IsFunctionPointer); + // Assert.True(IsModifiedType(fcnPtr)); + + // Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); + // Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; + // Assert.True(IsModifiedType(paramType)); + // Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); + // Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); + //} - // NOTE: commented out due to compiler issue on NativeAOT: #81117 //[Fact] //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -592,7 +594,8 @@ public ModifiedTypeHolder(delegate* d) { } // Although function pointer types can't be used as generic parameters, they can be used indirectly // as an array element type. - public static volatile Tuple[]> _arrayGenericFcnPtr; + // NOTE: commented out due to compiler issue on NativeAOT: #81117 + //public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; public static int*[] _array_ptr_int; @@ -647,7 +650,7 @@ public static delegate* > >, delegate* // ret - > _fcnPtr_complex; + > _fcnPtr_complex; } } } diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs b/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs deleted file mode 100644 index b0e6e8948725a5..00000000000000 --- a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -public class GenericWithModifiers -{ - // The 'const' modifier is not available in C#, so we generate IL with "IsConst" modopt. - public void MyMethodWithGeneric(Tuple t) { } - -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index a3c5f75cd3ffa0..c8d746c6da730d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -135,11 +135,7 @@ public override Type[] GetOptionalCustomModifiers() } // TypeDelegator doesn't forward these the way we want: - public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. - public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. - public override Type GetGenericTypeDefinition() => typeImpl.GetGenericTypeDefinition(); // not forwarded; we don't wrap - public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. - public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. + public override bool ContainsGenericParameters => typeImpl.ContainsGenericParameters; // not forwarded. public override bool Equals(Type? other) // Not forwarded. { if (other is ModifiedType otherModifiedType) @@ -149,6 +145,11 @@ public override bool Equals(Type? other) // Not forwarded. return false; } + public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. + public override Type GetGenericTypeDefinition() => typeImpl.GetGenericTypeDefinition(); // not forwarded. + public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. + public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. + public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. public static T[] CloneArray(T[] original, int start = 0) { From 0a6ff32ad5961fe5a8f57fcac30d4bf8d387eafa Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 27 Jan 2023 14:46:06 -0600 Subject: [PATCH 13/20] Add TODOs based on review discussion; MLC field optimization --- .../src/System/Reflection/ModifiedType.cs | 2 + ...stem.Reflection.MetadataLoadContext.csproj | 1 - .../TypeLoading/Types/RoModifiedType.cs | 57 ++++++++++++++ .../TypeLoading/Types/RoType.ModifiedType.cs | 77 ------------------- .../Reflection/TypeLoading/Types/RoType.cs | 4 + .../TypeLoading/Types/RoTypeDelegator.cs | 3 + 6 files changed, 66 insertions(+), 78 deletions(-) delete mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.ModifiedType.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index c8d746c6da730d..9ca87446edf67f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -7,6 +7,8 @@ namespace System.Reflection /// Base class for all modified types. /// Design supports code sharing between different runtimes and lazy loading of custom modifiers. /// + // TODO (PR REVIEW COMMENT): no longer derive from TypeDelegator and throw NSE for members + // that can directly or indirectly return an unmodified Type. internal abstract partial class ModifiedType : TypeDelegator { private readonly object? _signatureProvider; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index 51e221440c6d5c..d3cff8244b2ca3 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -143,7 +143,6 @@ - diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs index 83094bc6845947..3e733a060147d3 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection.TypeLoading; @@ -12,6 +14,11 @@ namespace System.Reflection /// internal abstract class RoModifiedType : RoTypeDelegator { + private List? _requiredModifiersBuilder; + private List? _optionalModifiersBuilder; + private Type[]? _requiredModifiers; + private Type[]? _optionalModifiers; + protected RoModifiedType(RoType unmodifiedType) : base(unmodifiedType) { } public static RoModifiedType Create(RoType unmodifiedType) @@ -43,6 +50,56 @@ public static RoModifiedType Create(RoType unmodifiedType) return modifiedType; } + public void AddRequiredModifier(Type type) + { + Debug.Assert(_requiredModifiers == null); + _requiredModifiersBuilder ??= new List(); + _requiredModifiersBuilder.Add(type); + } + + public void AddOptionalModifier(Type type) + { + Debug.Assert(_optionalModifiers == null); + _optionalModifiersBuilder ??= new List(); + _optionalModifiersBuilder.Add(type); + } + + public override Type[] GetRequiredCustomModifiers() + { + if (_requiredModifiers == null) + { + if (_requiredModifiersBuilder == null) + { + _requiredModifiers = EmptyTypes; + } + else + { + _requiredModifiers = _requiredModifiersBuilder.ToArray(); + _requiredModifiersBuilder = null; + } + } + + return Helpers.CloneArray(_requiredModifiers); + } + + public override Type[] GetOptionalCustomModifiers() + { + if (_optionalModifiers == null) + { + if (_optionalModifiersBuilder == null) + { + _optionalModifiers = EmptyTypes; + } + else + { + _optionalModifiers = _optionalModifiersBuilder.ToArray(); + _optionalModifiersBuilder = null; + } + } + + return Helpers.CloneArray(_optionalModifiers); + } + public sealed override bool Equals([NotNullWhen(true)] object? obj) { if (!(obj is RoFunctionPointerType otherModifiedType)) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.ModifiedType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.ModifiedType.cs deleted file mode 100644 index 8cf60ed45ede0c..00000000000000 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.ModifiedType.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Diagnostics; - -namespace System.Reflection.TypeLoading -{ - internal partial class RoType - { - private List? _requiredModifiersBuilder; - private List? _optionalModifiersBuilder; - private Type[]? _requiredModifiers; - private Type[]? _optionalModifiers; - - public void InitializeModifiers(Type[] requiredModifiers, Type[] optionalModifiers) - { - Debug.Assert(_requiredModifiersBuilder == null ); - Debug.Assert(_optionalModifiersBuilder == null); - Debug.Assert(_requiredModifiers == null); - Debug.Assert(_optionalModifiers == null); - - _requiredModifiers = requiredModifiers; - _optionalModifiers = optionalModifiers; - } - - public void AddRequiredModifier(Type type) - { - Debug.Assert(_requiredModifiers == null); - _requiredModifiersBuilder ??= new List(); - _requiredModifiersBuilder.Add(type); - } - - public void AddOptionalModifier(Type type) - { - Debug.Assert(_optionalModifiers == null); - _optionalModifiersBuilder ??= new List(); - _optionalModifiersBuilder.Add(type); - } - - public override Type[] GetRequiredCustomModifiers() - { - if (_requiredModifiers == null) - { - if (_requiredModifiersBuilder == null) - { - _requiredModifiers = EmptyTypes; - } - else - { - _requiredModifiers = _requiredModifiersBuilder.ToArray(); - _requiredModifiersBuilder = null; - } - } - - return Helpers.CloneArray(_requiredModifiers); - } - - public override Type[] GetOptionalCustomModifiers() - { - if (_optionalModifiers == null) - { - if (_optionalModifiersBuilder == null) - { - _optionalModifiers = EmptyTypes; - } - else - { - _optionalModifiers = _optionalModifiersBuilder.ToArray(); - _optionalModifiersBuilder = null; - } - } - - return Helpers.CloneArray(_optionalModifiers); - } - } -} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 2e8a52290f5700..0e5b30db95ad19 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -81,6 +81,10 @@ public override Type[] GetFunctionPointerCallingConventions() public abstract override Type GetFunctionPointerReturnType(); public abstract override Type[] GetFunctionPointerParameterTypes(); + // RoModifiedType overrides these. + public override Type[] GetOptionalCustomModifiers() => EmptyTypes; + public override Type[] GetRequiredCustomModifiers() => EmptyTypes; + public abstract override bool ContainsGenericParameters { get; } // Applies if IsGenericTypeDefinition == true diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs index d7f545b659dba6..f4b1708316bd9e 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// TODO (PR REVIEW COMMENT): remove this file and throw NSE from RoModifiedType for members +// that can directly or indirectly return an unmodified Type. + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute; From 8c06d3c908b5e8cdad23d05c780a30f42058a155 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 31 Jan 2023 11:08:01 -0800 Subject: [PATCH 14/20] Replace nested signature indices by TypeSignature type --- .../System.Private.CoreLib.csproj | 1 - .../ModifiedFunctionPointerType.CoreCLR.cs | 19 -- .../System/Reflection/ModifiedType.CoreCLR.cs | 56 ++-- .../src/System/Reflection/RtFieldInfo.cs | 2 +- .../System/Reflection/RuntimeParameterInfo.cs | 5 +- .../System/Reflection/RuntimePropertyInfo.cs | 5 +- .../src/System/RuntimeHandles.cs | 12 +- .../src/System/RuntimeType.CoreCLR.cs | 2 +- src/coreclr/inc/sigparser.h | 13 +- .../src/System.Private.CoreLib.csproj | 3 +- .../ModifiedFunctionPointerType.NativeAot.cs | 10 - .../Reflection/ModifiedType.NativeAot.cs | 8 + src/coreclr/utilcode/sigparser.cpp | 196 +------------- src/coreclr/vm/ecalllist.h | 6 +- src/coreclr/vm/runtimehandles.cpp | 250 +++++++++++------- src/coreclr/vm/runtimehandles.h | 20 +- src/coreclr/vm/siginfo.cpp | 63 ----- src/coreclr/vm/siginfo.hpp | 7 - .../System.Private.CoreLib.Shared.projitems | 3 +- .../Reflection/ModifiedContainerType.cs | 41 --- .../Reflection/ModifiedFunctionPointerType.cs | 68 +++-- .../System/Reflection/ModifiedGenericType.cs | 49 ++-- .../Reflection/ModifiedHasElementType.cs | 38 ++- .../Reflection/ModifiedStandaloneType.cs | 25 -- .../src/System/Reflection/ModifiedType.cs | 114 +------- .../System.Private.CoreLib.csproj | 1 - .../ModifiedFunctionPointerType.Mono.cs | 10 - .../System/Reflection/ModifiedType.Mono.cs | 8 + 28 files changed, 293 insertions(+), 742 deletions(-) delete mode 100644 src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs delete mode 100644 src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index 7b6523f010cdd7..ac9e8d9c3a7c5f 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -190,7 +190,6 @@ - diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs deleted file mode 100644 index 8b65e0a6d03df1..00000000000000 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.CoreCLR.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Reflection -{ - internal partial class ModifiedFunctionPointerType - { - private SignatureCallingConvention GetCallingConvention() - { - Signature? signature = GetSignature(); - if (signature is not null) - { - return (SignatureCallingConvention)signature.GetCallingConventionFromFunctionPointer(RootSignatureParameterIndex, NestedSignatureIndex); - } - - return SignatureCallingConvention.Default; - } - } -} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs index f3c7df701fd15e..71bedbb52caf19 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -5,47 +5,31 @@ namespace System.Reflection { internal partial class ModifiedType { - /// - /// Called from FieldInfo, PropertyInfo and ParameterInfo to create a modified type tree. - /// - public static ModifiedType CreateRoot( - Type unmodifiedType, - object? signatureProvider, - int rootSignatureParameterIndex) + internal struct TypeSignature { - int nestedSignatureIndex = -1; - return Create( - unmodifiedType, - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex: -1, - isRoot: true); + internal Signature? _signature; + internal int _offset; } - private Type[] GetCustomModifiers(bool required) - { - Type[] modifiers = EmptyTypes; - Signature? signature = GetSignature(); - if (signature is not null) + internal Type GetTypeParameter(Type unmodifiedType, int index) => + Create(unmodifiedType, new TypeSignature() { - if (IsRoot) - { - // For a root node, which is the original field\parameter\property Type, get the root-level modifiers. - modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required); - } - else if (NestedSignatureParameterIndex >= 0) - { - modifiers = signature.GetCustomModifiers(RootSignatureParameterIndex, required, NestedSignatureIndex, NestedSignatureParameterIndex); - } - } + _signature = _typeSignature._signature, + _offset = _typeSignature._signature?.GetTypeParameterFromOffset(_typeSignature._offset, index) ?? 0 + }); - return modifiers; - } + internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() => + _typeSignature._signature?.GetCallingConventionFromFunctionPointerAtOffset(_typeSignature._offset) ?? default; - internal Signature? GetSignature() - { - return (Signature?)SignatureProvider; // Signature is a CoreClr-specific class. - } + internal static Type Create(Type unmodifiedType, Signature? signature, int parameterIndex = 0) => + Create(unmodifiedType, new TypeSignature() + { + _signature = signature, + _offset = signature?.GetParameterOffset(parameterIndex) ?? 0 + }); + + private Type[] GetCustomModifiers(bool required) => + (_typeSignature._signature != null) ? + _typeSignature._signature.GetCustomModifiersAtOffset(_typeSignature._offset, required) : Type.EmptyTypes; } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs index cb22177945bd2e..54b04e77bd281d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RtFieldInfo.cs @@ -268,7 +268,7 @@ public override Type[] GetOptionalCustomModifiers() internal Signature GetSignature() => new Signature(this, m_declaringType); public override Type GetModifiedFieldType() => - ModifiedType.CreateRoot(FieldType, GetSignature(), rootSignatureParameterIndex: 1); + ModifiedType.Create(FieldType, GetSignature()); #endregion } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index b8a8f76d771090..1a7eae373f9c50 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -441,10 +441,7 @@ public override Type[] GetOptionalCustomModifiers() } public override Type GetModifiedParameterType() => - ModifiedType.CreateRoot( - unmodifiedType: ParameterType, - m_signature, - rootSignatureParameterIndex: PositionImpl + 1); + ModifiedType.Create(unmodifiedType: ParameterType, m_signature, parameterIndex: PositionImpl + 1); #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index dd891c20b081b0..d617b32d8b3ae4 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -205,10 +205,7 @@ public override Type[] GetOptionalCustomModifiers() return Signature.GetCustomModifiers(0, false); } - public override Type GetModifiedPropertyType() => ModifiedType.CreateRoot( - PropertyType, - Signature, - rootSignatureParameterIndex: 0); + public override Type GetModifiedPropertyType() => ModifiedType.Create(PropertyType, Signature); internal object GetConstantValue(bool raw) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index cbc6e9fac63379..5ecca78f07172f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -1634,14 +1634,20 @@ public Signature(void* pCorSig, int cCorSig, RuntimeType declaringType) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool CompareSig(Signature sig1, Signature sig2); + internal Type[] GetCustomModifiers(int parameterIndex, bool required) => + GetCustomModifiersAtOffset(GetParameterOffset(parameterIndex), required); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern int GetParameterOffset(int parameterIndex); + [MethodImpl(MethodImplOptions.InternalCall)] - internal extern Type[] GetCustomModifiers(int rootSignatureParameterIndex, bool required, int nestedSignatureIndex = -1, int nestedSignatureParameterIndex = -1); + internal extern int GetTypeParameterFromOffset(int offset, int index); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern byte GetCallingConventionFromFunctionPointer(int rootSignatureParameterIndex, int nestedSignatureIndex); + internal extern SignatureCallingConvention GetCallingConventionFromFunctionPointerAtOffset(int offset); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern bool IsUnmanagedFunctionPointer(); + internal extern Type[] GetCustomModifiersAtOffset(int offset, bool required); #endregion } diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 92cbbe6e86afc8..2b5cb9270a8a3f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -3754,7 +3754,7 @@ public override Type[] GetFunctionPointerParameterTypes() return EmptyTypes; } - return ModifiedType.CloneArray(parameters, 1); + return parameters.AsSpan(1).ToArray(); } public override Type GetFunctionPointerReturnType() diff --git a/src/coreclr/inc/sigparser.h b/src/coreclr/inc/sigparser.h index 49044b4a040b35..4446a37e372b52 100644 --- a/src/coreclr/inc/sigparser.h +++ b/src/coreclr/inc/sigparser.h @@ -713,7 +713,7 @@ class SigParser // the arguments. //------------------------------------------------------------------------ __checkReturn - HRESULT SkipMethodHeaderSignature(uint32_t *pcArgs); + HRESULT SkipMethodHeaderSignature(uint32_t *pcArgs, bool skipReturnType = true); //------------------------------------------------------------------------ // Skip a sub signature (as immediately follows an ELEMENT_TYPE_FNPTR). @@ -721,19 +721,8 @@ class SigParser __checkReturn HRESULT SkipSignature(); -private: - - __checkReturn - HRESULT MoveToSignature(uint32_t indexToFind, uint32_t* pCurrentIndex, bool* pIsFinished, CorElementType* pSignatureType); - public: - //------------------------------------------------------------------------ - // Move to the specified signature - //------------------------------------------------------------------------ - __checkReturn - HRESULT MoveToSignature(uint32_t indexToFind, CorElementType* pSignatureType); - //------------------------------------------------------------------------ // Return pointer // PLEASE DON'T USE THIS. diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 702d7d30a87f2d..652cf7cc4c1d57 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ - + true @@ -154,7 +154,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs deleted file mode 100644 index 2c143398e1f593..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.NativeAot.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Reflection -{ - internal partial class ModifiedFunctionPointerType - { - private SignatureCallingConvention GetCallingConvention() => throw new NotSupportedException(); - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs index 4eeb6acb7bf2e8..7cf1313aed901e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/ModifiedType.NativeAot.cs @@ -5,7 +5,15 @@ namespace System.Reflection { internal partial class ModifiedType { + internal struct TypeSignature + { + } + #pragma warning disable IDE0060 + internal Type GetTypeParameter(Type unmodifiedType, int index) => throw new NotSupportedException(); + + internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() => throw new NotSupportedException(); + private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); #pragma warning restore IDE0060 } diff --git a/src/coreclr/utilcode/sigparser.cpp b/src/coreclr/utilcode/sigparser.cpp index 12927a5ddbce0e..272b97ae68b88b 100644 --- a/src/coreclr/utilcode/sigparser.cpp +++ b/src/coreclr/utilcode/sigparser.cpp @@ -126,7 +126,7 @@ HRESULT SigParser::SkipExactlyOne() // HRESULT SigParser::SkipMethodHeaderSignature( - uint32_t * pcArgs) + uint32_t * pcArgs, bool skipReturnType /*= true*/) { CONTRACTL { @@ -157,8 +157,11 @@ SigParser::SkipMethodHeaderSignature( // Get arg count; IfFailRet(GetData(pcArgs)); - // Skip return type; - IfFailRet(SkipExactlyOne()); + if (skipReturnType) + { + // Skip return type; + IfFailRet(SkipExactlyOne()); + } return hr; } // SigParser::SkipMethodHeaderSignature @@ -192,190 +195,3 @@ HRESULT SigParser::SkipSignature() return hr; } - -HRESULT SigParser::MoveToSignature(uint32_t indexToFind, CorElementType* pSignatureType) -{ - CONTRACTL - { - INSTANCE_CHECK; - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - SUPPORTS_DAC; - } - CONTRACTL_END - - bool isFinished = false; - uint32_t currentIndex = 0; - HRESULT hr = MoveToSignature(indexToFind, ¤tIndex, &isFinished, pSignatureType); - if (isFinished == false) - { - return META_E_BAD_SIGNATURE; - } - - return hr; -} - -HRESULT SigParser::MoveToSignature(uint32_t indexToFind, uint32_t* pCurrentIndex, bool* pIsFinished, CorElementType* pSignatureType) -{ - CONTRACTL - { - INSTANCE_CHECK; - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - SUPPORTS_DAC; - } - CONTRACTL_END - - CorElementType typ; - HRESULT hr = GetElemType(&typ); - IfFailRet(hr); - - if (!CorIsPrimitiveType(typ)) - { - switch ((DWORD)typ) - { - default: - return META_E_BAD_SIGNATURE; - break; - case ELEMENT_TYPE_VAR: - case ELEMENT_TYPE_MVAR: - IfFailRet(GetData(NULL)); // Skip variable number - break; - case ELEMENT_TYPE_VAR_ZAPSIG: - IfFailRet(GetData(NULL)); // Skip RID - break; - case ELEMENT_TYPE_OBJECT: - case ELEMENT_TYPE_STRING: - case ELEMENT_TYPE_TYPEDBYREF: - case ELEMENT_TYPE_CANON_ZAPSIG: - break; - - case ELEMENT_TYPE_BYREF: //fallthru - case ELEMENT_TYPE_PTR: - case ELEMENT_TYPE_PINNED: - case ELEMENT_TYPE_SZARRAY: - case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: - IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); - - if (*pIsFinished) - return S_OK; - - break; - - case ELEMENT_TYPE_VALUETYPE: //fallthru - case ELEMENT_TYPE_CLASS: - IfFailRet(GetToken(NULL)); // Skip RID - break; - - case ELEMENT_TYPE_MODULE_ZAPSIG: - IfFailRet(GetData(NULL)); // Skip index - IfFailRet(SkipExactlyOne()); // Skip type - break; - - case ELEMENT_TYPE_FNPTR: - if (indexToFind == *pCurrentIndex) - { - *pIsFinished = TRUE; - *pSignatureType = ELEMENT_TYPE_FNPTR; - return S_OK; - } - - (*pCurrentIndex)++; - - // Skip calling convention - uint32_t uCallConv; - IfFailRet(GetCallingConvInfo(&uCallConv)); - if ((uCallConv == IMAGE_CEE_CS_CALLCONV_FIELD) || - (uCallConv == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)) - { - return META_E_BAD_SIGNATURE; - } - - // Skip type parameter count - if (uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) - IfFailRet(GetData(NULL)); - - // Get arg count; - uint32_t fpArgCnt; - IfFailRet(GetData(&fpArgCnt)); - - // Handle return type - IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); - if (*pIsFinished) - return S_OK; - - // Handle args - while (fpArgCnt--) - { - IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); - if (*pIsFinished) - return S_OK; - } - - break; - - case ELEMENT_TYPE_ARRAY: - { - IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); - if (*pIsFinished) - return S_OK; - - uint32_t rank; - IfFailRet(GetData(&rank)); // Get rank - if (rank) - { - uint32_t nsizes; - IfFailRet(GetData(&nsizes)); // Get # of sizes - while (nsizes--) - { - IfFailRet(GetData(NULL)); // Skip size - } - - uint32_t nlbounds; - IfFailRet(GetData(&nlbounds)); // Get # of lower bounds - while (nlbounds--) - { - IfFailRet(GetData(NULL)); // Skip lower bounds - } - } - } - break; - - case ELEMENT_TYPE_SENTINEL: - // Should be unreachable since GetElem strips it - break; - - case ELEMENT_TYPE_INTERNAL: - IfFailRet(GetPointer(NULL)); - break; - - case ELEMENT_TYPE_GENERICINST: - if (indexToFind == *pCurrentIndex) - { - *pIsFinished = TRUE; - *pSignatureType = ELEMENT_TYPE_GENERICINST; - return S_OK; - } - - (*pCurrentIndex)++; - - IfFailRet(SkipExactlyOne()); // Skip generic type - - // Handle args - uint32_t argCnt; - IfFailRet(GetData(&argCnt)); - while (argCnt--) - { - IfFailRet(MoveToSignature(indexToFind, pCurrentIndex, pIsFinished, pSignatureType)); - if (*pIsFinished) - return S_OK; - } - - break; - } - } - - return hr; -} diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index a8977232d798f9..dbe466bbec7efe 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -203,10 +203,12 @@ FCFuncStart(gMetaDataImport) FCFuncEnd() FCFuncStart(gSignatureNative) - FCFuncElement("GetCallingConventionFromFunctionPointer", SignatureNative::GetCallingConventionFromFunctionPointer) - FCFuncElement("GetCustomModifiers", SignatureNative::GetCustomModifiers) FCFuncElement("GetSignature", SignatureNative::GetSignature) FCFuncElement("CompareSig", SignatureNative::CompareSig) + FCFuncElement("GetParameterOffset", SignatureNative::GetParameterOffset) + FCFuncElement("GetTypeParameterFromOffset", SignatureNative::GetTypeParameterFromOffset) + FCFuncElement("GetCustomModifiersAtOffset", SignatureNative::GetCustomModifiersAtOffset) + FCFuncElement("GetCallingConventionFromFunctionPointerAtOffset", SignatureNative::GetCallingConventionFromFunctionPointerAtOffset) FCFuncEnd() FCFuncStart(gRuntimeMethodHandle) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 1435d056b92a7d..000ee98c086068 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1820,79 +1820,179 @@ FCIMPL1(INT32, RuntimeMethodHandle::GetSlot, MethodDesc *pMethod) { } FCIMPLEND -FCIMPL5(Object *, SignatureNative::GetCustomModifiers, - SignatureNative* pSignatureUNSAFE, - INT32 rootSignatureParameterIndex, - CLR_BOOL fRequired, - INT32 nestedSignatureIndex, - INT32 nestedSignatureParameterIndex) +FCIMPL2(INT32, SignatureNative::GetParameterOffset, SignatureNative* pSignatureUNSAFE, INT32 parameterIndex) { - CONTRACTL { - FCALL_CHECK; - } - CONTRACTL_END; + FCALL_CONTRACT; struct { SIGNATURENATIVEREF pSig; - PTRARRAYREF retVal; } gc; gc.pSig = (SIGNATURENATIVEREF)pSignatureUNSAFE; - gc.retVal = NULL; + + INT32 offset = 0; HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); { - BYTE callConv = *(BYTE*)gc.pSig->GetCorSig(); - SigTypeContext typeContext; - gc.pSig->GetTypeContext(&typeContext); - MetaSig sig(gc.pSig->GetCorSig(), - gc.pSig->GetCorSigSize(), - gc.pSig->GetModule(), - &typeContext, - (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD ? MetaSig::sigField : MetaSig::sigMember); - - _ASSERTE(callConv == sig.GetCallingConventionInfo()); - PRECONDITION(sig.GetCallingConvention() != IMAGE_CEE_CS_CALLCONV_FIELD || rootSignatureParameterIndex == 1); + SigPointer sp(gc.pSig->GetCorSig(), gc.pSig->GetCorSigSize()); - SigPointer argument(NULL, 0); + uint32_t callConv = 0; + IfFailThrow(sp.GetCallingConvInfo(&callConv)); - if (rootSignatureParameterIndex == 0) + if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_FIELD) { - argument = sig.GetReturnProps(); + if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + IfFailThrow(sp.GetData(NULL)); + } + + uint32_t numArgs; + IfFailThrow(sp.GetData(&numArgs)); + _ASSERTE((uint32_t)parameterIndex <= numArgs); + + for (int i = 0; i < parameterIndex; i++) + IfFailThrow(sp.SkipExactlyOne()); } else { - for(INT32 i = 0; i < rootSignatureParameterIndex; i++) - sig.NextArg(); - - argument = sig.GetArgProps(); + _ASSERTE(parameterIndex == 0); } - // Check if we need to move and\or switch to a function pointer or generic method signature. - if (nestedSignatureIndex >= 0) - { - sig.MoveToSignature(argument, nestedSignatureIndex); + offset = (INT32)(sp.GetPtr() - gc.pSig->GetCorSig()); + } + HELPER_METHOD_FRAME_END(); - if (nestedSignatureParameterIndex == 0) - { - argument = sig.GetReturnProps(); - } - else - { - for(INT32 i = 0; i < nestedSignatureParameterIndex; i++) - sig.NextArg(); + return offset; +} +FCIMPLEND - argument = sig.GetArgProps(); - } +FCIMPL3(INT32, SignatureNative::GetTypeParameterFromOffset, SignatureNative* pSignatureUNSAFE, INT32 offset, INT32 index) +{ + FCALL_CONTRACT; + + struct + { + SIGNATURENATIVEREF pSig; + } gc; + + if (offset < 0) + { + _ASSERTE(offset == -1); + return offset; + } + + gc.pSig = (SIGNATURENATIVEREF)pSignatureUNSAFE; + + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); + { + SigPointer sp(gc.pSig->GetCorSig() + offset, gc.pSig->GetCorSigSize() - offset); + + CorElementType etype; + IfFailThrow(sp.GetElemType(&etype)); + + uint32_t argCnt; + + switch (etype) + { + case ELEMENT_TYPE_FNPTR: + IfFailThrow(sp.SkipMethodHeaderSignature(&argCnt, /* skipReturnType */ false)); + _ASSERTE((uint32_t)index <= argCnt); + break; + case ELEMENT_TYPE_GENERICINST: + IfFailThrow(sp.SkipExactlyOne()); + + IfFailThrow(sp.GetData(&argCnt)); + _ASSERTE((uint32_t)index < argCnt); + break; + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_BYREF: + case ELEMENT_TYPE_PTR: + _ASSERTE(index == 0); + break; + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_MVAR: + offset = -1; // Use offset -1 to signal method substituted method variable. We do not have full signature for those. + goto Done; + default: + _ASSERTE(false); // Unexpected element type + offset = -1; + goto Done; } - // @todo: why is this commented out? - //if (parameter < 0 || parameter > (INT32)sig.NumFixedArgs()) - // FCThrowResVoid(kArgumentNullException, W("Arg_ArgumentOutOfRangeException")); + for (int i = 0; i < index; i++) + IfFailThrow(sp.SkipExactlyOne()); + + offset = (INT32)(sp.GetPtr() - gc.pSig->GetCorSig()); + Done: ; + } + HELPER_METHOD_FRAME_END(); + + return offset; +} +FCIMPLEND + +FCIMPL2(FC_INT8_RET, SignatureNative::GetCallingConventionFromFunctionPointerAtOffset, SignatureNative* pSignatureUNSAFE, INT32 offset) +{ + FCALL_CONTRACT; + + struct + { + SIGNATURENATIVEREF pSig; + } gc; + + if (offset < 0) + { + _ASSERTE(offset == -1); + return 0; + } + + gc.pSig = (SIGNATURENATIVEREF)pSignatureUNSAFE; + + uint32_t callConv = 0; + + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); + { + SigPointer sp(gc.pSig->GetCorSig() + offset, gc.pSig->GetCorSigSize() - offset); + + CorElementType etype; + IfFailThrow(sp.GetElemType(&etype)); + _ASSERTE(etype == ELEMENT_TYPE_FNPTR); + + IfFailThrow(sp.GetCallingConv(&callConv)); + } + HELPER_METHOD_FRAME_END(); + + return (FC_INT8_RET)(callConv); +} +FCIMPLEND + +FCIMPL3(Object *, SignatureNative::GetCustomModifiersAtOffset, + SignatureNative* pSignatureUNSAFE, + INT32 offset, + CLR_BOOL fRequired) +{ + FCALL_CONTRACT; + + struct + { + SIGNATURENATIVEREF pSig; + PTRARRAYREF retVal; + } gc; + + gc.pSig = (SIGNATURENATIVEREF)pSignatureUNSAFE; + gc.retVal = NULL; + + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); + { + SigTypeContext typeContext; + gc.pSig->GetTypeContext(&typeContext); + + SigPointer argument(gc.pSig->GetCorSig() + offset, gc.pSig->GetCorSigSize() - offset); SigPointer sp = argument; - Module* pModule = sig.GetModule(); + Module* pModule = gc.pSig->GetModule(); INT32 cMods = 0; CorElementType cmodType; @@ -1956,60 +2056,6 @@ FCIMPL5(Object *, SignatureNative::GetCustomModifiers, } FCIMPLEND -FCIMPL3(FC_INT8_RET, SignatureNative::GetCallingConventionFromFunctionPointer, - SignatureNative* pSignatureUNSAFE, - INT32 rootSignatureParameterIndex, - INT32 nestedSignatureIndex) -{ - struct - { - SIGNATURENATIVEREF pSig; - } gc; - - gc.pSig = (SIGNATURENATIVEREF)pSignatureUNSAFE; - BYTE retVal = 0; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - { - BYTE callConv = *(BYTE*)gc.pSig->GetCorSig(); - SigTypeContext typeContext; - gc.pSig->GetTypeContext(&typeContext); - MetaSig sig = MetaSig(gc.pSig->GetCorSig(), - gc.pSig->GetCorSigSize(), - gc.pSig->GetModule(), - &typeContext, - (callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD ? MetaSig::sigField : MetaSig::sigMember); - - _ASSERTE(callConv == sig.GetCallingConventionInfo()); - PRECONDITION(sig.GetCallingConvention() != IMAGE_CEE_CS_CALLCONV_FIELD || rootSignatureParameterIndex == 1); - - SigPointer argument(NULL, 0); - - if (nestedSignatureIndex >= 0) - { - if (rootSignatureParameterIndex == 0) - { - argument = sig.GetReturnProps(); - } - else - { - for(INT32 i = 0; i < rootSignatureParameterIndex; i++) - sig.NextArg(); - - argument = sig.GetArgProps(); - } - - sig.MoveToSignature(argument, nestedSignatureIndex); - } - - retVal = sig.GetCallingConventionInfo() & IMAGE_CEE_CS_CALLCONV_MASK; - } - HELPER_METHOD_FRAME_END(); - - return (FC_INT8_RET)(retVal); -} -FCIMPLEND - FCIMPL1(INT32, RuntimeMethodHandle::GetMethodDef, ReflectMethodObject *pMethodUNSAFE) { CONTRACTL { FCALL_CHECK; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 4255184a6de3b2..195f5a6379ef47 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -375,19 +375,15 @@ class SignatureNative : public Object FieldDesc *pFieldDesc, ReflectMethodObject *pMethodUNSAFE, ReflectClassBaseObject *pDeclaringType); - static FCDECL5(Object *, GetCustomModifiers, - SignatureNative* pSig, - INT32 rootSignatureParameterIndex, - CLR_BOOL fRequired, - INT32 nestedSignatureIndex, - INT32 nestedSignatureParameterIndex); - static FCDECL2(FC_BOOL_RET, CompareSig, SignatureNative* pLhs, SignatureNative* pRhs); - - static FCDECL3(FC_INT8_RET, GetCallingConventionFromFunctionPointer, - SignatureNative* pSig, - INT32 rootSignatureParameterIndex, - INT32 nestedSignatureIndex); + + static FCDECL2(INT32, GetParameterOffset, SignatureNative* pSig, INT32 parameterIndex); + + static FCDECL3(INT32, GetTypeParameterFromOffset, SignatureNative* pSig, INT32 offset, INT32 index); + + static FCDECL2(FC_INT8_RET, GetCallingConventionFromFunctionPointerAtOffset, SignatureNative* pSig, INT32 offset); + + static FCDECL3(Object *, GetCustomModifiersAtOffset, SignatureNative* pSig, INT32 offset, CLR_BOOL fRequired); BOOL HasThis() { LIMITED_METHOD_CONTRACT; return (m_managedCallingConvention & CALLCONV_HasThis); } INT32 NumFixedArgs() { WRAPPER_NO_CONTRACT; return m_PtrArrayarguments->GetNumComponents(); } diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index 0cefe74749546b..0a15fbb91488fe 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -608,15 +608,6 @@ void MetaSig::Init( m_pRetType = SigPointer(NULL, 0); break; } - case sigGeneric: - { - IfFailGo(psig.SkipExactlyOne()); // Skip generic type - - uint32_t data = 0; - IfFailGo(psig.GetData(&data)); // Store number of arguments. - m_nArgs = data; - break; - } default: { UNREACHABLE(); @@ -872,60 +863,6 @@ MetaSig::SkipArg() } } -//--------------------------------------------------------------------------------------- -// -// Move to the specified signature. -HRESULT -MetaSig::MoveToSignature(SigPointer start, INT32 index) -{ - CONTRACTL - { - INSTANCE_CHECK; - NOTHROW; - MODE_ANY; - GC_NOTRIGGER; - FORBID_FAULT; - SUPPORTS_DAC; - } - CONTRACTL_END - - m_pLastType = m_pWalk; - - CorElementType signatureType = CorElementType::ELEMENT_TYPE_END; - HRESULT hr = start.MoveToSignature(index, &signatureType); - if (FAILED(hr)) - { - m_pWalk = m_pLastType; - return hr; - } - - SigTypeContext typeContext = m_typeContext; - - PCCOR_SIGNATURE pSig; - uint32_t cbSigSize; - start.GetSignature(&pSig, &cbSigSize); - - // Select the right signature type to re-initialize. - MetaSigKind kind; - if (signatureType == ELEMENT_TYPE_FNPTR) - { - kind = sigMember; - } - else if (signatureType == ELEMENT_TYPE_GENERICINST) - { - kind = sigGeneric; - } - else - { - UNREACHABLE(); - m_pWalk = m_pLastType; - return BFA_INVALID_TOKEN_TYPE; - } - - Init(pSig, cbSigSize, m_pModule, &typeContext, kind); - return hr; -} - //--------------------------------------------------------------------------------------- // // reset: goto start pos diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index 8ce406710378fc..585fdb2071ef19 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -487,7 +487,6 @@ class MetaSig sigMember, sigLocalVars, sigField, - sigGeneric }; //------------------------------------------------------------------ @@ -571,12 +570,6 @@ class MetaSig //------------------------------------------------------------------ void SkipArg(); - //------------------------------------------------------------------ - // Move to the specified new signature and re-initialize to the - // new signature type. - //------------------------------------------------------------------ - HRESULT MoveToSignature(SigPointer start, INT32 index); - //------------------------------------------------------------------ // Returns a read-only SigPointer for the m_pLastType set by one // of NextArg() or SkipArg() diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index eb7db04ac43f33..505751f0141019 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -688,7 +688,6 @@ - @@ -2565,4 +2564,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs deleted file mode 100644 index 871e7118e78281..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedContainerType.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; - -namespace System.Reflection -{ - /// - /// An array, pointer or reference type. - /// - internal sealed class ModifiedContainerType : ModifiedType - { - private readonly ModifiedType _elementModifiedType; - - public ModifiedContainerType( - Type containerType, - object? signatureProvider, - int rootSignatureParameterIndex, - ref int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot) - : base( - containerType, - signatureProvider, - rootSignatureParameterIndex, - nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot) - { - Debug.Assert(containerType.HasElementType); - _elementModifiedType = Create( - containerType.GetElementType()!, - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex : -1); - } - - public override Type? GetElementType() => _elementModifiedType; - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index 994e9727c6d6f6..18d967bbb466dc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Threading; namespace System.Reflection { @@ -11,57 +12,48 @@ internal sealed partial class ModifiedFunctionPointerType : ModifiedType { private const string CallingConventionTypePrefix = "System.Runtime.CompilerServices.CallConv"; - private readonly ModifiedType[] _parameterTypes; - private readonly ModifiedType _returnType; + private Type[]? _parameterTypes; + private Type? _returnType; - public ModifiedFunctionPointerType( - Type functionPointerType, - object? signatureProvider, - int rootSignatureParameterIndex, - ref int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot) - : base( - functionPointerType, - signatureProvider, - rootSignatureParameterIndex, - ++nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot) + internal ModifiedFunctionPointerType(Type unmodifiedType, TypeSignature typeSignature) + : base(unmodifiedType, typeSignature) { - Debug.Assert(functionPointerType.IsFunctionPointer); - _returnType = Create( - functionPointerType.GetFunctionPointerReturnType(), - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex: 0); + Debug.Assert(unmodifiedType.IsFunctionPointer); + } + + public override Type GetFunctionPointerReturnType() + { + return _returnType ?? Initialize(); - Type[] parameters = functionPointerType.GetFunctionPointerParameterTypes(); - int count = parameters.Length; - ModifiedType[] modifiedTypes = new ModifiedType[count]; - for (int i = 0; i < count; i++) + Type Initialize() { - modifiedTypes[i] = Create( - parameters[i], - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex: i + 1); + Interlocked.CompareExchange(ref _returnType, GetTypeParameter(typeImpl.GetFunctionPointerReturnType(), 0), null); + return _returnType!; } - - _parameterTypes = modifiedTypes; } - public override Type GetFunctionPointerReturnType() => _returnType; - public override Type[] GetFunctionPointerParameterTypes() => CloneArray(_parameterTypes); + public override Type[] GetFunctionPointerParameterTypes() + { + return (Type[])(_parameterTypes ?? Initialize()).Clone(); + + Type[] Initialize() + { + Type[] parameterTypes = typeImpl.GetFunctionPointerParameterTypes(); + for (int i = 0; i < parameterTypes.Length; i++) + { + parameterTypes[i] = GetTypeParameter(parameterTypes[i], i + 1); + } + Interlocked.CompareExchange(ref _parameterTypes, parameterTypes, null); + return _parameterTypes!; + } + } public override Type[] GetFunctionPointerCallingConventions() { ArrayBuilder builder = default; // Normalize the calling conventions by manufacturing a type. - switch (GetCallingConvention()) + switch (GetCallingConventionFromFunctionPointer()) { case SignatureCallingConvention.Cdecl: builder.Add(typeof(CallConvCdecl)); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index 6abdd151688f67..1dbd90c56751d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -2,47 +2,34 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Threading; namespace System.Reflection { internal sealed partial class ModifiedGenericType : ModifiedType { - private readonly ModifiedType[] _argumentTypes; + private Type[]? _genericArguments; - public ModifiedGenericType( - Type genericType, - object? signatureProvider, - int rootSignatureParameterIndex, - ref int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot) - : base( - genericType, - signatureProvider, - rootSignatureParameterIndex, - ++nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot) + internal ModifiedGenericType(Type unmodifiedType, TypeSignature typeSignature) + : base(unmodifiedType, typeSignature) { - Debug.Assert(genericType.IsGenericType); + Debug.Assert(unmodifiedType.IsGenericType); + } + + public override Type[] GetGenericArguments() + { + return (Type[])(_genericArguments ?? Initialize()).Clone(); - Type[] genericArguments = genericType.GetGenericArguments(); - int count = genericArguments.Length; - ModifiedType[] modifiedTypes = new ModifiedType[count]; - for (int i = 0; i < count; i++) + Type[] Initialize() { - modifiedTypes[i] = Create( - genericArguments[i], - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - // Since generic signatures don't have a return type, we use +1 here. - nestedSignatureParameterIndex: i + 1); + Type[] genericArguments = typeImpl.GetGenericArguments(); + for (int i = 0; i < genericArguments.Length; i++) + { + genericArguments[i] = GetTypeParameter(genericArguments[i], i); + } + Interlocked.CompareExchange(ref _genericArguments, genericArguments, null); + return _genericArguments!; } - - _argumentTypes = modifiedTypes; } - - public override Type[] GetGenericArguments() => CloneArray(_argumentTypes); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs index f72c025f4c32da..cc8e180883263a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Threading; namespace System.Reflection { @@ -10,32 +11,23 @@ namespace System.Reflection /// internal sealed class ModifiedHasElementType : ModifiedType { - private readonly ModifiedType? _elementModifiedType; + private Type? _elementType; - public ModifiedHasElementType( - Type containerType, - object? signatureProvider, - int rootSignatureParameterIndex, - ref int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot) - : base( - containerType, - signatureProvider, - rootSignatureParameterIndex, - nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot) + internal ModifiedHasElementType(Type unmodifiedType, TypeSignature typeSignature) + : base(unmodifiedType, typeSignature) { - Debug.Assert(containerType.HasElementType); - _elementModifiedType = Create( - containerType.GetElementType()!, - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex : -1); + Debug.Assert(unmodifiedType.HasElementType); } - public override Type? GetElementType() => _elementModifiedType; + public override Type? GetElementType() + { + return _elementType ?? Initialize(); + + Type Initialize() + { + Interlocked.CompareExchange(ref _elementType, GetTypeParameter(typeImpl.GetElementType()!, 0), null); + return _elementType!; + } + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs deleted file mode 100644 index e7691ed68bc0e5..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedStandaloneType.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Reflection -{ - internal sealed class ModifiedStandaloneType : ModifiedType - { - public ModifiedStandaloneType( - Type delegatingType, - object? signtureProvider, - int rootSignatureParameterIndex, - int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot) - : base( - delegatingType, - signtureProvider, - rootSignatureParameterIndex, - nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot) - { - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index 9ca87446edf67f..5f34b86a254812 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -4,36 +4,19 @@ namespace System.Reflection { /// - /// Base class for all modified types. + /// Base class for modified types and standalone modified type. /// Design supports code sharing between different runtimes and lazy loading of custom modifiers. /// // TODO (PR REVIEW COMMENT): no longer derive from TypeDelegator and throw NSE for members // that can directly or indirectly return an unmodified Type. - internal abstract partial class ModifiedType : TypeDelegator + internal partial class ModifiedType : TypeDelegator { - private readonly object? _signatureProvider; + private readonly TypeSignature _typeSignature; - // These 3 fields, in order, determine the lookup hierarchy for custom modifiers. - // The native tree traversal must match the managed semantics in order for indexes to match up. - private readonly int _rootSignatureParameterIndex; - private readonly int _nestedSignatureIndex; - private readonly int _nestedSignatureParameterIndex; - - private bool _isRoot; - - protected ModifiedType( - Type unmodifiedType, - object? signatureProvider, - int rootSignatureParameterIndex, - int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot) : base(unmodifiedType) + internal ModifiedType(Type unmodifiedType, TypeSignature typeSignature) + : base(unmodifiedType) { - _signatureProvider = signatureProvider; - _rootSignatureParameterIndex = rootSignatureParameterIndex; - _nestedSignatureIndex = nestedSignatureIndex; - _nestedSignatureParameterIndex = nestedSignatureParameterIndex; - _isRoot = isRoot; + _typeSignature = typeSignature; } /// @@ -41,89 +24,28 @@ protected ModifiedType( /// A type tree is formed due to arrays and pointers having an element type, function pointers /// having a return type and parameter types, and generic types having argument types. /// - protected static ModifiedType Create( - Type unmodifiedType, - object? signatureProvider, - int rootSignatureParameterIndex, - ref int nestedSignatureIndex, - int nestedSignatureParameterIndex, - bool isRoot = false) + protected static Type Create(Type unmodifiedType, TypeSignature typeSignature) { - ModifiedType modifiedType; - + Type modifiedType; if (unmodifiedType.IsFunctionPointer) { - modifiedType = new ModifiedFunctionPointerType( - unmodifiedType, - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot); + modifiedType = new ModifiedFunctionPointerType(unmodifiedType, typeSignature); } else if (unmodifiedType.HasElementType) { - modifiedType = new ModifiedHasElementType( - unmodifiedType, - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot); + modifiedType = new ModifiedHasElementType(unmodifiedType, typeSignature); } else if (unmodifiedType.IsGenericType) { - modifiedType = new ModifiedGenericType( - unmodifiedType, - signatureProvider, - rootSignatureParameterIndex, - ref nestedSignatureIndex, - nestedSignatureParameterIndex, - isRoot); + modifiedType = new ModifiedGenericType(unmodifiedType, typeSignature); } else { - modifiedType = new ModifiedStandaloneType( - unmodifiedType, - signatureProvider, - rootSignatureParameterIndex, - nestedSignatureIndex, // Passing byref is not necessary; no more recursion. - nestedSignatureParameterIndex, - isRoot); + modifiedType = new ModifiedType(unmodifiedType, typeSignature); } - return modifiedType; } - - /// - /// The runtime-specific information to look up a signature, such as 'Signature' class or a type handle. - /// - protected object? SignatureProvider => _signatureProvider; - - /// - /// Part 1 of 3 to determine the lookup hierarchy for custom modifiers. - /// Specifies the root signature's parameter index (0 for properties, 1 for fields, 0..n for methods). - /// - protected int RootSignatureParameterIndex => _rootSignatureParameterIndex; - - /// - /// Part 2 of 3 to determine the lookup hierarchy for custom modifiers. - /// Specifies the nested signature's index into the recursive type tree which was the running count - /// for each signature node as it was created. - /// A value of -1 means the node is not nested under any signature. - /// - protected int NestedSignatureIndex => _nestedSignatureIndex; - - /// - /// Part 3 of 3 to determine the lookup hierarchy for custom modifiers. - /// Specifies the parameter index from a given signature node. 0 for return; 1..n for parameters. - /// A value of -1 means the node is not a signature parameter. - /// - protected int NestedSignatureParameterIndex => _nestedSignatureParameterIndex; - - protected virtual bool IsRoot => _isRoot; - public override Type[] GetRequiredCustomModifiers() { // No caching is performed; as is the case with FieldInfo.GetCustomModifiers and friends. @@ -152,17 +74,5 @@ public override bool Equals(Type? other) // Not forwarded. public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. - - public static T[] CloneArray(T[] original, int start = 0) - { - if (original.Length == 0) - { - return original; - } - - T[] copy = new T[original.Length - start]; - Array.Copy(sourceArray: original, sourceIndex: start, destinationArray: copy, destinationIndex: 0, length: original.Length - start); - return copy; - } } } diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 0f6807814e84ea..141184b9b0e5cd 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -207,7 +207,6 @@ - diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs deleted file mode 100644 index 2c143398e1f593..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.Mono.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Reflection -{ - internal partial class ModifiedFunctionPointerType - { - private SignatureCallingConvention GetCallingConvention() => throw new NotSupportedException(); - } -} 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 4eeb6acb7bf2e8..7cf1313aed901e 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,7 +5,15 @@ namespace System.Reflection { internal partial class ModifiedType { + internal struct TypeSignature + { + } + #pragma warning disable IDE0060 + internal Type GetTypeParameter(Type unmodifiedType, int index) => throw new NotSupportedException(); + + internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() => throw new NotSupportedException(); + private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException(); #pragma warning restore IDE0060 } From f40e506fb194cb9ea5d6d3c3c810a637f1558397 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 13 Feb 2023 14:24:04 -0600 Subject: [PATCH 15/20] Move tests into separate classes; other misc non-functional --- .../System/Reflection/ModifiedType.CoreCLR.cs | 2 +- .../src/System/RuntimeHandles.cs | 2 +- src/coreclr/vm/ecalllist.h | 2 +- src/coreclr/vm/runtimehandles.cpp | 2 +- src/coreclr/vm/runtimehandles.h | 2 +- ... FunctionPointerCallingConventionTests.cs} | 33 +- ...ity.cs => FunctionPointerEqualityTests.cs} | 41 ++- .../tests/System/FunctionPointerTests.cs | 13 +- .../Common/tests/System/ModifiedTypeTests.cs | 283 +++++++++--------- .../TestILAssembly.il} | 4 +- .../TestILAssembly.ilproj} | 2 +- .../System.Reflection.MetadataLoadContext.sln | 2 +- ...eflection.MetadataLoadContext.Tests.csproj | 6 +- .../System.Runtime/System.Runtime.sln | 2 +- .../tests/System.Runtime.Tests.csproj | 6 +- 15 files changed, 223 insertions(+), 179 deletions(-) rename src/libraries/Common/tests/System/{FunctionPointerTests.CallingConventions.cs => FunctionPointerCallingConventionTests.cs} (87%) rename src/libraries/Common/tests/System/{FunctionPointerTests.Identity.cs => FunctionPointerEqualityTests.cs} (77%) rename src/libraries/Common/tests/System/{TestReflectionILAssembly/GenericWithModifiers.il => TestILAssembly/TestILAssembly.il} (93%) rename src/libraries/Common/tests/System/{TestReflectionILAssembly/TestReflectionILAssembly.ilproj => TestILAssembly/TestILAssembly.ilproj} (84%) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs index 71bedbb52caf19..60ab5dd00d102d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/ModifiedType.CoreCLR.cs @@ -15,7 +15,7 @@ internal Type GetTypeParameter(Type unmodifiedType, int index) => Create(unmodifiedType, new TypeSignature() { _signature = _typeSignature._signature, - _offset = _typeSignature._signature?.GetTypeParameterFromOffset(_typeSignature._offset, index) ?? 0 + _offset = _typeSignature._signature?.GetTypeParameterOffset(_typeSignature._offset, index) ?? 0 }); internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() => diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 5ecca78f07172f..70252bff3e7c0a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -1641,7 +1641,7 @@ internal Type[] GetCustomModifiers(int parameterIndex, bool required) => internal extern int GetParameterOffset(int parameterIndex); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern int GetTypeParameterFromOffset(int offset, int index); + internal extern int GetTypeParameterOffset(int offset, int index); [MethodImpl(MethodImplOptions.InternalCall)] internal extern SignatureCallingConvention GetCallingConventionFromFunctionPointerAtOffset(int offset); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index dbe466bbec7efe..fe98a58ef37d40 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -206,7 +206,7 @@ FCFuncStart(gSignatureNative) FCFuncElement("GetSignature", SignatureNative::GetSignature) FCFuncElement("CompareSig", SignatureNative::CompareSig) FCFuncElement("GetParameterOffset", SignatureNative::GetParameterOffset) - FCFuncElement("GetTypeParameterFromOffset", SignatureNative::GetTypeParameterFromOffset) + FCFuncElement("GetTypeParameterOffset", SignatureNative::GetTypeParameterOffset) FCFuncElement("GetCustomModifiersAtOffset", SignatureNative::GetCustomModifiersAtOffset) FCFuncElement("GetCallingConventionFromFunctionPointerAtOffset", SignatureNative::GetCallingConventionFromFunctionPointerAtOffset) FCFuncEnd() diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 000ee98c086068..f5a696ed701ed4 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1867,7 +1867,7 @@ FCIMPL2(INT32, SignatureNative::GetParameterOffset, SignatureNative* pSignatureU } FCIMPLEND -FCIMPL3(INT32, SignatureNative::GetTypeParameterFromOffset, SignatureNative* pSignatureUNSAFE, INT32 offset, INT32 index) +FCIMPL3(INT32, SignatureNative::GetTypeParameterOffset, SignatureNative* pSignatureUNSAFE, INT32 offset, INT32 index) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 195f5a6379ef47..f9275671a9f44c 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -379,7 +379,7 @@ class SignatureNative : public Object static FCDECL2(INT32, GetParameterOffset, SignatureNative* pSig, INT32 parameterIndex); - static FCDECL3(INT32, GetTypeParameterFromOffset, SignatureNative* pSig, INT32 offset, INT32 index); + static FCDECL3(INT32, GetTypeParameterOffset, SignatureNative* pSig, INT32 offset, INT32 index); static FCDECL2(FC_INT8_RET, GetCallingConventionFromFunctionPointerAtOffset, SignatureNative* pSig, INT32 offset); diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs b/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs similarity index 87% rename from src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs rename to src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs index 4271d42e1ae4cb..1024ab823c5950 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.CallingConventions.cs +++ b/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs @@ -8,8 +8,10 @@ namespace System.Tests.Types { - public partial class FunctionPointerTests + public partial class FunctionPointerCallingConventionTests { + private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + [Theory] [InlineData(true)] [InlineData(false)] @@ -166,11 +168,31 @@ public static unsafe void UnmanagedCallConv_PhysicalModifiers_Modified(string me Assert.Equal(0, returnType.GetRequiredCustomModifiers().Length); } - public unsafe partial class FunctionPointerHolder + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void GenericTypeParameter() + { + Type holder = typeof(FunctionPointerHolder).Project(); + FieldInfo f = holder.GetField(nameof(FunctionPointerHolder._genericType), Bindings); + Type propType = f.FieldType.GetProperty("MyProp").GetModifiedPropertyType(); + + // Requires skipping past the return parameter metadata in order to get to the metadata for the first parameter. + Type paramType = propType.GetFunctionPointerParameterTypes()[1]; + Type[] cc = paramType.GetFunctionPointerCallingConventions(); + Assert.Equal(1, cc.Length); + Assert.Equal(typeof(CallConvCdecl).Project(), cc[0]); + } + + private unsafe partial class FunctionPointerHolder { public delegate* unmanaged[Cdecl, MemberFunction] MethodUnmanagedReturnValue_DifferentCallingConventions1() => default; public delegate* unmanaged[Stdcall, MemberFunction] MethodUnmanagedReturnValue_DifferentCallingConventions2() => default; +#pragma warning disable 0649 + public MyGenericClass[]> _genericType; +#pragma warning restore 0649 + // Methods to verify calling conventions and synthesized modopts. // The non-SuppressGCTransition variants are encoded with the CallKind byte. // The SuppressGCTransition variants are encoded as modopts (CallKind is "Unmananged"). @@ -183,6 +205,13 @@ public void MethodCallConv_Thiscall(delegate* unmanaged[Thiscall] f) { } public void MethodCallConv_Thiscall_SuppressGCTransition(delegate* unmanaged[Thiscall, SuppressGCTransition] f) { } public void MethodCallConv_Fastcall(delegate* unmanaged[Fastcall] f) { } public void MethodCallConv_Fastcall_SuppressGCTransition(delegate* unmanaged[Fastcall, SuppressGCTransition] f) { } + + public class MyClass { } + + public unsafe class MyGenericClass + { + public delegate*, void> MyProp { get; } + } } } } diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs similarity index 77% rename from src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs rename to src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs index 1be48aa79da203..8080c32e382afe 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.Identity.cs +++ b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs @@ -10,12 +10,14 @@ namespace System.Tests.Types // Also see ModifiedTypeTests which tests custom modifiers. // Unmodified Type instances are cached and keyed by the runtime. // Modified Type instances are created for each member. - public partial class FunctionPointerTests + public partial class FunctionPointerEqualityTests { + 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)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void FunctionUnmanagedPointerReturn_DifferentReturnValue() + public static unsafe void DifferentReturnValue() { Type t = typeof(FunctionPointerHolder).Project(); @@ -34,7 +36,7 @@ public static unsafe void FunctionUnmanagedPointerReturn_DifferentReturnValue() [InlineData(nameof(FunctionPointerHolder.Field_DateOnly), nameof(FunctionPointerHolder.Field_Int))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void SigEqualityInDifferentModule_Field(string name, string otherName) + public static unsafe void SigInDifferentModule_Field(string name, string otherName) { Type fph1 = typeof(FunctionPointerHolder).Project(); Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); @@ -54,7 +56,7 @@ public static unsafe void SigEqualityInDifferentModule_Field(string name, string [InlineData(nameof(FunctionPointerHolder.Prop_DateOnly), nameof(FunctionPointerHolder.Prop_Int))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void SigEqualityInDifferentModule_Property(string name, string otherName) + public static unsafe void SigInDifferentModule_Property(string name, string otherName) { Type fph1 = typeof(FunctionPointerHolder).Project(); Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); @@ -74,7 +76,7 @@ public static unsafe void SigEqualityInDifferentModule_Property(string name, str [InlineData(nameof(FunctionPointerHolder.MethodReturnValue_DateOnly), nameof(FunctionPointerHolder.MethodReturnValue_Int))] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void SigEqualityInDifferentModule_MethodReturn(string name, string otherName) + public static unsafe void SigInDifferentModule_MethodReturn(string name, string otherName) { Type fph1 = typeof(FunctionPointerHolder).Project(); Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); @@ -96,7 +98,7 @@ public static unsafe void SigEqualityInDifferentModule_MethodReturn(string name, [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/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void CallingConventionIdentity_Unmodified(string methodName1, string methodName2) + public static unsafe void CallingConvention_Unmodified(string methodName1, string methodName2) { Type t = typeof(FunctionPointerHolder).Project(); MethodInfo m1 = t.GetMethod(methodName1, Bindings); @@ -115,7 +117,7 @@ public static unsafe void CallingConventionIdentity_Unmodified(string methodName [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/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void CallingConventionIdentity_Modified(string methodName1, string methodName2) + public static unsafe void CallingConvention_Modified(string methodName1, string methodName2) { Type t = typeof(FunctionPointerHolder).Project(); MethodInfo m1 = t.GetMethod(methodName1, Bindings); @@ -126,5 +128,30 @@ public static unsafe void CallingConventionIdentity_Modified(string methodName1, Assert.True(fnPtrType1.IsFunctionPointerNotEqual(fnPtrType2)); } + + private unsafe class FunctionPointerHolder + { +#pragma warning disable 0649 + public delegate* managed Field_Int; + public delegate* managed Field_DateOnly; // Verify non-primitive +#pragma warning restore 0649 + + public delegate* managed Prop_Int { get; } + public delegate* managed Prop_DateOnly { get; } + public delegate* managed MethodReturnValue_Int() => default; + public delegate* managed MethodReturnValue_DateOnly() => default; + + public delegate* unmanaged MethodUnmanagedReturnValue1() => default; + public delegate* unmanaged MethodUnmanagedReturnValue2() => default; + + // Methods to verify calling conventions and synthesized modopts. + // The non-SuppressGCTransition variants are encoded with the CallKind byte. + // The SuppressGCTransition variants are encoded as modopts (CallKind is "Unmananged"). + public void MethodCallConv_Cdecl(delegate* unmanaged[Cdecl] f) { } + public void MethodCallConv_Cdecl_SuppressGCTransition(delegate* unmanaged[Cdecl, SuppressGCTransition] f) { } + public void MethodCallConv_Stdcall(delegate* unmanaged[Stdcall] f) { } + public void MethodCallConv_Thiscall(delegate* unmanaged[Thiscall] f) { } + public void MethodCallConv_Fastcall(delegate* unmanaged[Fastcall] f) { } + } } } diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index f793415dc938c6..abb853c4e90d62 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -279,8 +279,9 @@ private static void VerifyFieldOrProperty(Type fnPtrType, bool isModified) Assert.Equal(Type.EmptyTypes, fnPtrType.GetFunctionPointerReturnType().GetRequiredCustomModifiers()); } - public unsafe partial class FunctionPointerHolder + private unsafe class FunctionPointerHolder { +#pragma warning disable 0649 public delegate* ToString_1; public delegate*unmanaged ToString_2; public delegate* ToString_3; @@ -292,20 +293,14 @@ public unsafe partial class FunctionPointerHolder public delegate*, bool> ToString_9; public delegate* managed Field_Int; - public delegate* managed Field_DateOnly; // Verify non-primitive public delegate* managed Field_MyClass; +#pragma warning restore 0649 + public delegate* managed Prop_Int { get; } - public delegate* managed Prop_DateOnly { get; } public delegate* managed Prop_MyClass { get; } - public delegate* managed MethodReturnValue_Int() => default; - public delegate* managed MethodReturnValue_DateOnly() => default; - public delegate* unmanaged MethodUnmanagedReturnValue_Int() => default; - public delegate* unmanaged MethodUnmanagedReturnValue_DateOnly() => default; public delegate* managed MethodReturnValue1() => default; public delegate* managed MethodReturnValue2() => default; - public delegate* unmanaged MethodUnmanagedReturnValue1() => default; - public delegate* unmanaged MethodUnmanagedReturnValue2() => default; public delegate* unmanaged[Stdcall, MemberFunction] SeveralArguments() => default; public delegate* RequiredModifiers() => default; diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index cc3537b8ca2755..62917e7f688231 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -55,103 +55,101 @@ void Verify(Type type) } } - // NOTE: the below tests commented out due to compiler issue on NativeAOT: #81117 - - //[Fact] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - //public static unsafe void Fields_Generic_Unmodified() - //{ - // Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; - // Assert.True(arrayGenericFcnPtr.IsGenericType); - // Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); - // Assert.False(IsModifiedType(arrayGenericFcnPtr)); - - // Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; - // Assert.False(IsModifiedType(genericParam)); - - // Type fcnPtr = genericParam.GetElementType(); - // Assert.True(fcnPtr.IsFunctionPointer); - // Assert.False(IsModifiedType(fcnPtr)); - - // Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); - // Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; - // Assert.False(IsModifiedType(paramType)); - //} - - //[Fact] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - //public static unsafe void Fields_Generic_Modified() - //{ - // Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); - // Assert.True(IsModifiedType(arrayGenericFcnPtr)); - // Assert.True(arrayGenericFcnPtr.IsGenericType); - // Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); - - // Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; - // Assert.True(IsModifiedType(genericParam)); - - // Type fcnPtr = genericParam.GetElementType(); - // Assert.True(fcnPtr.IsFunctionPointer); - // Assert.True(IsModifiedType(fcnPtr)); - - // Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); - // Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; - // Assert.True(IsModifiedType(paramType)); - // Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); - // Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); - //} - - //[Fact] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - //public static unsafe void Methods_OpenGeneric_Unmodified() - //{ - // MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); - // Assert.Equal(1, mi.GetGenericArguments().Length); - // Type p0 = mi.GetGenericArguments()[0]; - // Assert.True(p0.IsGenericMethodParameter); - // Assert.False(IsModifiedType(p0)); - - // Type arr = mi.GetParameters()[1].ParameterType; - // Assert.False(IsModifiedType(arr)); - - // Type p1 = arr.GetElementType(); - // Assert.True(p1.IsFunctionPointer); - // Assert.False(p1.IsGenericTypeParameter); - // Assert.False(IsModifiedType(p1)); - // Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); - // Type paramType = p1.GetFunctionPointerParameterTypes()[0]; - // Assert.Equal(0, paramType.GetRequiredCustomModifiers().Length); - // Assert.False(IsModifiedType(paramType)); - //} - - //[Fact] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095",TestRuntimes.Mono)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - //public static unsafe void Methods_OpenGeneric_Modified() - //{ - // MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); - // Assert.Equal(1, mi.GetGenericArguments().Length); - // Type p0 = mi.GetGenericArguments()[0]; - // Assert.True(p0.IsGenericMethodParameter); - // Assert.False(IsModifiedType(p0)); - - // Type arr = mi.GetParameters()[1].GetModifiedParameterType(); - // Assert.True(IsModifiedType(arr)); - - // Type p1 = arr.GetElementType(); - // Assert.True(p1.IsFunctionPointer); - // Assert.False(p1.IsGenericTypeParameter); - // Assert.True(IsModifiedType(p1)); - - // Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); - // Type paramType = p1.GetFunctionPointerParameterTypes()[0]; - // Assert.True(IsModifiedType(paramType)); - // Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); - // Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); - //} + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Fields_Generic_Unmodified() + { + Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).FieldType; + Assert.True(arrayGenericFcnPtr.IsGenericType); + Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); + Assert.False(IsModifiedType(arrayGenericFcnPtr)); + + Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; + Assert.False(IsModifiedType(genericParam)); + + Type fcnPtr = genericParam.GetElementType(); + Assert.True(fcnPtr.IsFunctionPointer); + Assert.False(IsModifiedType(fcnPtr)); + + Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); + Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.False(IsModifiedType(paramType)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Fields_Generic_Modified() + { + Type arrayGenericFcnPtr = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._arrayGenericFcnPtr), Bindings).GetModifiedFieldType(); + Assert.True(IsModifiedType(arrayGenericFcnPtr)); + Assert.True(arrayGenericFcnPtr.IsGenericType); + Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); + + Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; + Assert.True(IsModifiedType(genericParam)); + + Type fcnPtr = genericParam.GetElementType(); + Assert.True(fcnPtr.IsFunctionPointer); + Assert.True(IsModifiedType(fcnPtr)); + + Assert.Equal(1, fcnPtr.GetFunctionPointerParameterTypes().Length); + Type paramType = fcnPtr.GetFunctionPointerParameterTypes()[0]; + Assert.True(IsModifiedType(paramType)); + Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Methods_OpenGeneric_Unmodified() + { + MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); + Assert.Equal(1, mi.GetGenericArguments().Length); + Type p0 = mi.GetGenericArguments()[0]; + Assert.True(p0.IsGenericMethodParameter); + Assert.False(IsModifiedType(p0)); + + Type arr = mi.GetParameters()[1].ParameterType; + Assert.False(IsModifiedType(arr)); + + Type p1 = arr.GetElementType(); + Assert.True(p1.IsFunctionPointer); + Assert.False(p1.IsGenericTypeParameter); + Assert.False(IsModifiedType(p1)); + Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); + Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + Assert.Equal(0, paramType.GetRequiredCustomModifiers().Length); + Assert.False(IsModifiedType(paramType)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Methods_OpenGeneric_Modified() + { + MethodInfo mi = typeof(ModifiedTypeHolder).Project().GetMethod(nameof(ModifiedTypeHolder.M_ArrayOpenGenericFcnPtr), Bindings); + Assert.Equal(1, mi.GetGenericArguments().Length); + Type p0 = mi.GetGenericArguments()[0]; + Assert.True(p0.IsGenericMethodParameter); + Assert.False(IsModifiedType(p0)); + + Type arr = mi.GetParameters()[1].GetModifiedParameterType(); + Assert.True(IsModifiedType(arr)); + + Type p1 = arr.GetElementType(); + Assert.True(p1.IsFunctionPointer); + Assert.False(p1.IsGenericTypeParameter); + Assert.True(IsModifiedType(p1)); + + Assert.Equal(1, p1.GetFunctionPointerParameterTypes().Length); + Type paramType = p1.GetFunctionPointerParameterTypes()[0]; + Assert.True(IsModifiedType(paramType)); + Assert.Equal(1, paramType.GetRequiredCustomModifiers().Length); + Assert.Equal(typeof(OutAttribute).Project(), paramType.GetRequiredCustomModifiers()[0]); + } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -466,43 +464,42 @@ public static unsafe void FunctionPointerParameters_fcnPtr_complex_Modified() Assert.Equal(typeof(OutAttribute).Project(), target.GetRequiredCustomModifiers()[0]); } - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - //[Fact] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - //public static unsafe void Property_FcnPtr_Complex_Unmodified() - //{ - // Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).PropertyType; - // Type f1 = mt.GetElementType(); - // Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Property_FcnPtr_Complex_Unmodified() + { + Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).PropertyType; + Type f1 = mt.GetElementType(); + Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); - // Type f2 = f1.GetFunctionPointerParameterTypes()[1]; - // Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); + Type f2 = f1.GetFunctionPointerParameterTypes()[1]; + Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); - // Type target = f2.GetFunctionPointerParameterTypes()[2]; - // Assert.Equal("System.Int64()", target.ToString()); + Type target = f2.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Int64()", target.ToString()); - // Assert.Equal(0, target.GetFunctionPointerCallingConventions().Length); - //} + Assert.Equal(0, target.GetFunctionPointerCallingConventions().Length); + } - //[Fact] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - //public static unsafe void Property_FcnPtr_Complex_Modified() - //{ - // Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).GetModifiedPropertyType(); + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void Property_FcnPtr_Complex_Modified() + { + Type mt = typeof(ModifiedTypeHolder).Project().GetProperty(nameof(ModifiedTypeHolder.Property_FcnPtr_Complex), Bindings).GetModifiedPropertyType(); - // Type f1 = mt.GetElementType(); - // Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); + Type f1 = mt.GetElementType(); + Assert.Equal("System.Boolean(System.Int32(), System.Void(System.Byte(), System.Int32(), System.Int64()))", f1.ToString()); - // Type f2 = f1.GetFunctionPointerParameterTypes()[1]; - // Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); + Type f2 = f1.GetFunctionPointerParameterTypes()[1]; + Assert.Equal("System.Void(System.Byte(), System.Int32(), System.Int64())", f2.ToString()); - // Type target = f2.GetFunctionPointerParameterTypes()[2]; - // Assert.Equal("System.Int64()", target.ToString()); - // Assert.Equal(1, target.GetFunctionPointerCallingConventions().Length); - // Assert.Equal(typeof(CallConvCdecl).Project(), target.GetFunctionPointerCallingConventions()[0]); - //} + Type target = f2.GetFunctionPointerParameterTypes()[2]; + Assert.Equal("System.Int64()", target.ToString()); + Assert.Equal(1, target.GetFunctionPointerCallingConventions().Length); + Assert.Equal(typeof(CallConvCdecl).Project(), target.GetFunctionPointerCallingConventions()[0]); + } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] @@ -594,8 +591,7 @@ public ModifiedTypeHolder(delegate* d) { } // Although function pointer types can't be used as generic parameters, they can be used indirectly // as an array element type. - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - //public static volatile Tuple[]> _arrayGenericFcnPtr; + public static volatile Tuple[]> _arrayGenericFcnPtr; public static int** _ptr_ptr_int; public static int*[] _array_ptr_int; @@ -605,26 +601,23 @@ public ModifiedTypeHolder(delegate* d) { } public static void M_P0IntOut(out int i) { i = 42; } public static void M_P0FcnPtrOut(delegate* fp) { } - - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - //public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } + public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] fp) { } public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } - // NOTE: commented out due to compiler issue on NativeAOT: #81117 - //public delegate* - //< - // delegate*, // p0 - // delegate* // p1 - // < - // delegate*, // p0 - // delegate*, // p1 - // delegate* unmanaged[Cdecl], // p2 - // void // ret - // >, - // bool // ret - //>[] Property_FcnPtr_Complex { get; } + public delegate* + < + delegate*, // p0 + delegate* // p1 + < + delegate*, // p0 + delegate*, // p1 + delegate* unmanaged[Cdecl], // p2 + void // ret + >, + bool // ret + >[] Property_FcnPtr_Complex { get; } public static delegate* FcnPtrP0Out { get; set; } public static delegate* _fcnPtrP0Out; diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il b/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il similarity index 93% rename from src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il rename to src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il index b54ccae300ea30..ca2582be13414b 100644 --- a/src/libraries/Common/tests/System/TestReflectionILAssembly/GenericWithModifiers.il +++ b/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.il @@ -7,12 +7,12 @@ .ver 4:0:0:0 } -.assembly TestReflectionILAssembly +.assembly TestILAssembly { .ver 1:0:0:0 } -.module TestReflectionILAssembly.dll +.module TestILAssembly.dll .namespace System.Tests { diff --git a/src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj b/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.ilproj similarity index 84% rename from src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj rename to src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.ilproj index 15ff9670cfb8a4..770a84293ac276 100644 --- a/src/libraries/Common/tests/System/TestReflectionILAssembly/TestReflectionILAssembly.ilproj +++ b/src/libraries/Common/tests/System/TestILAssembly/TestILAssembly.ilproj @@ -5,6 +5,6 @@ Microsoft - + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln index d97438e639aade..f10bd6caa6ceb2 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln +++ b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln @@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.MetadataL EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{F85BDD51-AC29-4D8D-8257-C509BED9A448}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestReflectionILAssembly", "..\Common\tests\System\TestReflectionILAssembly\TestReflectionILAssembly.ilproj", "{6DA9926C-8763-42A2-A51A-EDF8684C80A8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestILAssembly", "..\Common\tests\System\TestILAssembly\TestILAssembly.ilproj", "{6DA9926C-8763-42A2-A51A-EDF8684C80A8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{4361CEFA-8238-4247-9CC5-D99DF794843C}" EndProject diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index 82be945597ab5c..9f7b66f0cc1fda 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -75,11 +75,11 @@ - + - - + + diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index b539b4e3108b9e..1d11b33776dcaf 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -41,7 +41,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.ReflectionIn EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCollectibleAssembly", "tests\TestCollectibleAssembly\TestCollectibleAssembly.csproj", "{C230AC88-A377-4BEB-824F-AB174C14DC86}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestReflectionILAssembly", "..\Common\tests\System\TestReflectionILAssembly\TestReflectionILAssembly.ilproj", "{AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestILAssembly", "..\Common\tests\System\TestILAssembly\TestILAssembly.ilproj", "{AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{B7975A39-2E87-4C6C-A7EC-1F5926676800}" EndProject diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 1a3ccd5e2853d2..cd7bb699bb0016 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -23,8 +23,8 @@ - - + + @@ -338,7 +338,7 @@ - + From 4610e93318f5f9e11d98de2e2fa0e0a2f960c91a Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Tue, 14 Feb 2023 15:55:46 -0600 Subject: [PATCH 16/20] Throw NSE for modified type members than may return an unmodified type --- src/coreclr/vm/runtimehandles.cpp | 12 +- .../System/FunctionPointerEqualityTests.cs | 43 +++++ .../tests/System/FunctionPointerTests.cs | 16 +- .../Common/tests/System/ModifiedTypeTests.cs | 157 +++++++++++++++-- .../src/Resources/Strings.resx | 4 +- .../Reflection/ModifiedFunctionPointerType.cs | 4 +- .../System/Reflection/ModifiedGenericType.cs | 2 +- .../Reflection/ModifiedHasElementType.cs | 2 +- .../src/System/Reflection/ModifiedType.cs | 161 ++++++++++++++++-- .../src/System/Reflection/TypeDelegator.cs | 4 + .../src/Resources/Strings.resx | 12 +- ...stem.Reflection.MetadataLoadContext.csproj | 1 - .../Types/RoFunctionPointerType.cs | 2 +- .../TypeLoading/Types/RoModifiedType.cs | 114 ++++++++++++- .../Types/RoType.TypeClassification.cs | 2 +- .../Reflection/TypeLoading/Types/RoType.cs | 24 +-- .../TypeLoading/Types/RoTypeDelegator.cs | 98 ----------- .../FunctionPointerTestsExtensions.cs | 4 +- .../tests/src/TestUtils/TestUtils.cs | 1 - 19 files changed, 475 insertions(+), 188 deletions(-) delete mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index f5a696ed701ed4..df847b0f900179 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -926,12 +926,14 @@ FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsUnmanagedFunctionPointer, ReflectClass CONTRACTL_END; REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); + BOOL unmanaged = FALSE; TypeHandle typeHandle = refType->GetType(); - if (!typeHandle.IsFnPtrType()) - FCThrowRes(kArgumentException, W("Arg_InvalidHandle")); - - FnPtrTypeDesc* fnPtr = typeHandle.AsFnPtrType(); - BOOL unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_UNMANAGED) == IMAGE_CEE_CS_CALLCONV_UNMANAGED; + if (typeHandle.IsFnPtrType()) + { + FnPtrTypeDesc* fnPtr = typeHandle.AsFnPtrType(); + unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_UNMANAGED) == IMAGE_CEE_CS_CALLCONV_UNMANAGED; + } + FC_RETURN_BOOL(unmanaged); } FCIMPLEND diff --git a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs index 8080c32e382afe..d6f199c86af013 100644 --- a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs @@ -31,6 +31,46 @@ public static unsafe void DifferentReturnValue() Assert.False(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void ObjectEquals_ModifiedTypes() + { + Type holder = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue1), Bindings); + Type t1 = m1.ReturnParameter.GetModifiedParameterType(); + + MethodInfo m2 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue2), Bindings); + Type t2 = m2.ReturnParameter.GetModifiedParameterType(); + + Assert.False(ReferenceEquals(t1, t1.UnderlyingSystemType)); + + // Modified types do not support Equals other than when references are equal. + Assert.True(t1.Equals(t1)); + Assert.False(t1.Equals(t2)); + Assert.False(((object)t1).Equals(t2)); + Assert.False(t1.Equals((object)t2)); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void ObjectEquals_OneSideModifiedType() + { + Type holder = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue1), Bindings); + Type modifiedType = m1.ReturnParameter.GetModifiedParameterType(); + Type t = typeof(int).Project(); + + Assert.False(ReferenceEquals(modifiedType, modifiedType.UnderlyingSystemType)); + Assert.False(ReferenceEquals(modifiedType, t)); + Assert.False(modifiedType.Equals(t)); + Assert.False(((object)modifiedType).Equals(t)); + Assert.False(modifiedType.Equals((object)t)); + } + [Theory] [InlineData(nameof(FunctionPointerHolder.Field_Int), nameof(FunctionPointerHolder.Field_DateOnly))] [InlineData(nameof(FunctionPointerHolder.Field_DateOnly), nameof(FunctionPointerHolder.Field_Int))] @@ -144,6 +184,9 @@ private unsafe class FunctionPointerHolder public delegate* unmanaged MethodUnmanagedReturnValue1() => default; public delegate* unmanaged MethodUnmanagedReturnValue2() => default; + public int MethodIntReturnValue1() => default; + public int MethodIntReturnValue2() => default; + // Methods to verify calling conventions and synthesized modopts. // The non-SuppressGCTransition variants are encoded with the CallKind byte. // The SuppressGCTransition variants are encoded as modopts (CallKind is "Unmananged"). diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index abb853c4e90d62..df39bab6730643 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -28,7 +28,7 @@ public static unsafe void TypeMembers() Assert.Equal(string.Empty, t.Name); Assert.Null(t.Namespace); Assert.True(t.IsFunctionPointer); - Assert.False(t.IsPointer); // A function pointer is not compatible with IsPointer semantics. + Assert.False(t.IsPointer); Assert.False(t.IsUnmanagedFunctionPointer); // Common for all function pointers: @@ -113,8 +113,6 @@ public static unsafe void TypeMembers() Assert.NotNull(t.Module); Assert.Null(t.ReflectedType); Assert.Null(t.TypeInitializer); - - // Select methods Assert.Throws(() => t.GetArrayRank()); Assert.Null(t.GetElementType()); } @@ -214,17 +212,11 @@ public static unsafe void MethodInfo( Assert.Null(fnPtrType.AssemblyQualifiedName); Assert.Equal("", fnPtrType.Name); - VerifyArg(fnPtrType.GetFunctionPointerReturnType(), expectedFcnPtrReturnName); + Assert.Equal(fnPtrType.GetFunctionPointerReturnType().Name, expectedFcnPtrReturnName); for (int i = 0; i < expectedArgNames.Length; i++) { - VerifyArg(fnPtrType.GetFunctionPointerParameterTypes()[i], expectedArgNames[i]); - } - - static void VerifyArg(Type paramType, string expected) - { - Assert.Equal(expected, paramType.Name); - Assert.Null(paramType.DeclaringType); + Assert.Equal(fnPtrType.GetFunctionPointerParameterTypes()[i].Name, expectedArgNames[i]); } } @@ -273,8 +265,6 @@ private static void VerifyFieldOrProperty(Type fnPtrType, bool isModified) Assert.Null(fnPtrType.FullName); Assert.Null(fnPtrType.AssemblyQualifiedName); Assert.Equal("", fnPtrType.Name); - Assert.Null(fnPtrType.DeclaringType); - Assert.Null(fnPtrType.BaseType); Assert.Equal(Type.EmptyTypes, fnPtrType.GetFunctionPointerCallingConventions()); Assert.Equal(Type.EmptyTypes, fnPtrType.GetFunctionPointerReturnType().GetRequiredCustomModifiers()); } diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index 62917e7f688231..b0a7599ab2cc78 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Tests; using System.Runtime.CompilerServices; @@ -16,6 +16,134 @@ public partial class ModifiedTypeTests { 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)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] + public static unsafe void TypeMembers() + { + FieldInfo fi = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings); + + Type unmodifiedType = fi.FieldType; + CommonMembers(unmodifiedType); + UnmodifiedTypeMembers(unmodifiedType); + + Type modifiedType = fi.GetModifiedFieldType(); + CommonMembers(modifiedType); + ModifiedTypeMembers(modifiedType); + + void CommonMembers(Type t) + { + Assert.Equal("System.Int32", t.ToString()); + Assert.NotNull(t.AssemblyQualifiedName); + Assert.Equal("Int32", t.Name); + Assert.Equal("System", t.Namespace); + Assert.False(t.IsFunctionPointer); + Assert.False(t.IsPointer); + Assert.False(t.IsUnmanagedFunctionPointer); + Assert.NotNull(t.Assembly); + Assert.True(t.Attributes != default); + Assert.False(t.ContainsGenericParameters); + Assert.False(t.ContainsGenericParameters); + var _ = t.GUID; // Just ensure it doesn't throw. + Assert.Throws(() => t.GenericParameterAttributes); + Assert.Throws(() => t.GenericParameterPosition); + Assert.Throws(() => t.GetFunctionPointerCallingConventions()); + Assert.Throws(() => t.GetFunctionPointerParameterTypes()); + Assert.Throws(() => t.GetFunctionPointerReturnType()); + Assert.False(t.HasElementType); + Assert.False(t.IsAbstract); + Assert.True(t.IsAnsiClass); + Assert.False(t.IsArray); + Assert.False(t.IsAutoClass); + Assert.False(t.IsAutoLayout); + Assert.False(t.IsByRef); + Assert.False(t.IsByRefLike); + Assert.False(t.IsCOMObject); + Assert.False(t.IsClass); + Assert.False(t.IsAbstract); + Assert.False(t.IsConstructedGenericType); + Assert.False(t.IsContextful); + Assert.False(t.IsEnum); + Assert.False(t.IsExplicitLayout); + Assert.False(t.IsGenericMethodParameter); + Assert.False(t.IsGenericParameter); + Assert.False(t.IsGenericType); + Assert.False(t.IsGenericTypeDefinition); + Assert.False(t.IsGenericTypeParameter); + Assert.False(t.IsImport); + Assert.False(t.IsInterface); + Assert.True(t.IsLayoutSequential); + Assert.False(t.IsMarshalByRef); + Assert.False(t.IsNotPublic); + Assert.True(t.IsPublic); + Assert.False(t.IsSZArray); + Assert.True(t.IsSealed); + + if (FunctionPointerTestsExtensions.IsMetadataLoadContext) + { + Assert.Throws(() => t.IsSecurityCritical); + Assert.Throws(() => t.IsSecuritySafeCritical); + Assert.Throws(() => t.IsSecurityTransparent); + } + else + { + Assert.True(t.IsSecurityCritical); + Assert.False(t.IsSecuritySafeCritical); + Assert.False(t.IsSecurityTransparent); + } + + Assert.True(t.IsSerializable); + Assert.False(t.IsSignatureType); + Assert.False(t.IsSpecialName); + Assert.True(t.IsTypeDefinition); + Assert.False(t.IsUnicodeClass); + Assert.True(t.IsValueType); + Assert.False(t.IsVariableBoundArray); + Assert.Equal(MemberTypes.TypeInfo, t.MemberType); + Assert.NotNull(t.Module); + + Assert.False(t.IsNestedAssembly); + Assert.False(t.IsNestedFamANDAssem); + Assert.False(t.IsNestedFamORAssem); + Assert.False(t.IsNestedFamily); + Assert.False(t.IsNestedPrivate); + Assert.False(t.IsNestedPublic); + Assert.Throws(() => t.GetArrayRank()); + Assert.Null(t.GetElementType()); + Assert.False(t.GenericTypeArguments.Any()); + } + + void UnmodifiedTypeMembers(Type t) + { + Assert.False(t.GetOptionalCustomModifiers().Any()); + Assert.False(t.GetRequiredCustomModifiers().Any()); + Assert.True(t.IsPrimitive); + Assert.NotNull(t.BaseType); + Assert.Null(t.DeclaringType); + Assert.Null(t.ReflectedType); + Assert.Null(t.TypeInitializer); + Assert.True(t.MetadataToken != 0); + Assert.False(t.IsNested); + Assert.True(t.IsVisible); + } + + void ModifiedTypeMembers(Type t) + { + Assert.False(t.GetOptionalCustomModifiers().Any()); + Assert.True(t.GetRequiredCustomModifiers().Any()); // The volatile modifier. + Assert.True(t.IsPrimitive); + Assert.Throws(() => t.BaseType); + Assert.Throws(() => t.DeclaringType); + Assert.Throws(() => t.ReflectedType); + Assert.Throws(() => t.TypeInitializer); + Assert.Throws(() => t.MetadataToken); + + // These can call DeclaringType which is not supported. + Assert.Throws(() => t.IsNested); + Assert.Throws(() => t.IsVisible); + } + } + [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -65,10 +193,10 @@ public static unsafe void Fields_Generic_Unmodified() Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); Assert.False(IsModifiedType(arrayGenericFcnPtr)); - Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; - Assert.False(IsModifiedType(genericParam)); + Type genericArg = arrayGenericFcnPtr.GetGenericArguments()[0]; + Assert.False(IsModifiedType(genericArg)); - Type fcnPtr = genericParam.GetElementType(); + Type fcnPtr = genericArg.GetElementType(); Assert.True(fcnPtr.IsFunctionPointer); Assert.False(IsModifiedType(fcnPtr)); @@ -87,10 +215,10 @@ public static unsafe void Fields_Generic_Modified() Assert.True(arrayGenericFcnPtr.IsGenericType); Assert.False(arrayGenericFcnPtr.IsGenericTypeDefinition); - Type genericParam = arrayGenericFcnPtr.GetGenericArguments()[0]; - Assert.True(IsModifiedType(genericParam)); + Type genericArg = arrayGenericFcnPtr.GetGenericArguments()[0]; + Assert.True(IsModifiedType(genericArg)); - Type fcnPtr = genericParam.GetElementType(); + Type fcnPtr = genericArg.GetElementType(); Assert.True(fcnPtr.IsFunctionPointer); Assert.True(IsModifiedType(fcnPtr)); @@ -511,7 +639,7 @@ public static unsafe void MethodWithGenericParameter_Unmodified() Type a1 = mi.GetParameters()[0].ParameterType; Assert.False(IsModifiedType(a1)); - Assert.Equal(typeof(Tuple).Project(), a1); + Assert.Equal(typeof(Tuple).Project(), a1.Project()); Type ga1 = a1.GetGenericArguments()[0]; Assert.False(IsModifiedType(ga1)); @@ -533,7 +661,7 @@ public static unsafe void MethodWithGenericParameter_Modified() Type a1 = mi.GetParameters()[0].GetModifiedParameterType(); Assert.True(IsModifiedType(a1)); - Assert.Equal(typeof(Tuple).Project(), a1.UnderlyingSystemType); + Assert.Equal(typeof(Tuple).Project(), a1.UnderlyingSystemType.Project()); Type ga1 = a1.GetGenericArguments()[0]; Assert.True(IsModifiedType(ga1)); @@ -606,6 +734,11 @@ public static void M_ArrayOpenGenericFcnPtr(T t, delegate*[] public int InitProperty_Int { get; init; } public static delegate* Property_FcnPtr { get; set; } + public static delegate* _fcnPtrP0Out; + public static delegate*, void> _fcnPtr_fcnPtrP0Out; + public static delegate*, void> _fcnPtr_fcnPtrP0Ref; + public static delegate*> _fcnPtr_fcnPtrRetP0Out; + public delegate* < delegate*, // p0 @@ -619,12 +752,6 @@ public delegate* bool // ret >[] Property_FcnPtr_Complex { get; } - public static delegate* FcnPtrP0Out { get; set; } - public static delegate* _fcnPtrP0Out; - public static delegate*, void> _fcnPtr_fcnPtrP0Out; - public static delegate*, void> _fcnPtr_fcnPtrP0Ref; - public static delegate*> _fcnPtr_fcnPtrRetP0Out; - public static delegate* < delegate*, // p0 diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 46f26a3108144a..6347ca9b1d1652 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3995,5 +3995,7 @@ Method may only be called on a Type for which Type.IsFunctionPointer is true. + + Modified types do not support this member. Use the UnderlyingSystemType property to call this member. + - diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs index 18d967bbb466dc..6971e1642d0683 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedFunctionPointerType.cs @@ -27,7 +27,7 @@ public override Type GetFunctionPointerReturnType() Type Initialize() { - Interlocked.CompareExchange(ref _returnType, GetTypeParameter(typeImpl.GetFunctionPointerReturnType(), 0), null); + Interlocked.CompareExchange(ref _returnType, GetTypeParameter(UnmodifiedType.GetFunctionPointerReturnType(), 0), null); return _returnType!; } } @@ -38,7 +38,7 @@ public override Type[] GetFunctionPointerParameterTypes() Type[] Initialize() { - Type[] parameterTypes = typeImpl.GetFunctionPointerParameterTypes(); + Type[] parameterTypes = UnmodifiedType.GetFunctionPointerParameterTypes(); for (int i = 0; i < parameterTypes.Length; i++) { parameterTypes[i] = GetTypeParameter(parameterTypes[i], i + 1); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs index 1dbd90c56751d0..c93caad06d9c33 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedGenericType.cs @@ -22,7 +22,7 @@ public override Type[] GetGenericArguments() Type[] Initialize() { - Type[] genericArguments = typeImpl.GetGenericArguments(); + Type[] genericArguments = UnmodifiedType.GetGenericArguments(); for (int i = 0; i < genericArguments.Length; i++) { genericArguments[i] = GetTypeParameter(genericArguments[i], i); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs index cc8e180883263a..19df3af6f7944c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedHasElementType.cs @@ -25,7 +25,7 @@ internal ModifiedHasElementType(Type unmodifiedType, TypeSignature typeSignature Type Initialize() { - Interlocked.CompareExchange(ref _elementType, GetTypeParameter(typeImpl.GetElementType()!, 0), null); + Interlocked.CompareExchange(ref _elementType, GetTypeParameter(UnmodifiedType.GetElementType()!, 0), null); return _elementType!; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index 5f34b86a254812..b58ffc5579d868 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -1,21 +1,23 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; +using CultureInfo = System.Globalization.CultureInfo; + namespace System.Reflection { /// /// Base class for modified types and standalone modified type. /// Design supports code sharing between different runtimes and lazy loading of custom modifiers. /// - // TODO (PR REVIEW COMMENT): no longer derive from TypeDelegator and throw NSE for members - // that can directly or indirectly return an unmodified Type. - internal partial class ModifiedType : TypeDelegator + internal partial class ModifiedType : Type { private readonly TypeSignature _typeSignature; + private readonly Type _unmodifiedType; internal ModifiedType(Type unmodifiedType, TypeSignature typeSignature) - : base(unmodifiedType) { + _unmodifiedType = unmodifiedType; _typeSignature = typeSignature; } @@ -46,6 +48,11 @@ protected static Type Create(Type unmodifiedType, TypeSignature typeSignature) return modifiedType; } + protected Type UnmodifiedType => _unmodifiedType; + + // Below are the multitude of Type overloads. We throw NSE for members that would return an unmodified Type + // directly or indirectly. We do this in case we want to support returning modified types instead. + public override Type[] GetRequiredCustomModifiers() { // No caching is performed; as is the case with FieldInfo.GetCustomModifiers and friends. @@ -58,9 +65,18 @@ public override Type[] GetOptionalCustomModifiers() return GetCustomModifiers(required: false); } - // TypeDelegator doesn't forward these the way we want: - public override bool ContainsGenericParameters => typeImpl.ContainsGenericParameters; // not forwarded. - public override bool Equals(Type? other) // Not forwarded. + // Modified types do not support Equals other than when references are equal. + // UnderlyingSystemType.Equals() should should be used if basic equality is necessary. + // Supporting Equals on a modified type would need to include custom modifiers and any parameterized types recursively. + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (!(obj is ModifiedType)) + return false; + + return ReferenceEquals(this, obj); + } + + public override bool Equals(Type? other) { if (other is ModifiedType otherModifiedType) { @@ -69,10 +85,131 @@ public override bool Equals(Type? other) // Not forwarded. return false; } - public override int GetHashCode() => UnderlyingSystemType.GetHashCode(); // Not forwarded. - public override Type GetGenericTypeDefinition() => typeImpl.GetGenericTypeDefinition(); // not forwarded. - public override bool IsGenericType => typeImpl.IsGenericType; // Not forwarded. - public override string ToString() => UnderlyingSystemType.ToString(); // Not forwarded. - public override Type UnderlyingSystemType => typeImpl; // We don't want to forward to typeImpl.UnderlyingSystemType. + public override int GetHashCode() => _unmodifiedType.GetHashCode(); + public override string ToString() => _unmodifiedType.ToString(); + public override Type UnderlyingSystemType => _unmodifiedType; + + public override GenericParameterAttributes GenericParameterAttributes => _unmodifiedType.GenericParameterAttributes; + public override bool ContainsGenericParameters => _unmodifiedType.ContainsGenericParameters; + public override Type GetGenericTypeDefinition() => _unmodifiedType.GetGenericTypeDefinition(); + public override bool IsGenericType => _unmodifiedType.IsGenericType; + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + public override object? InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target, + object?[]? args, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParameters) + => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + public override Guid GUID => _unmodifiedType.GUID; + public override int MetadataToken => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override Module Module => _unmodifiedType.Module; + public override Assembly Assembly => _unmodifiedType.Assembly; + public override RuntimeTypeHandle TypeHandle => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override string Name => _unmodifiedType.Name; + public override string? FullName => _unmodifiedType.FullName; + public override string? Namespace => _unmodifiedType.Namespace; + public override string? AssemblyQualifiedName => _unmodifiedType.AssemblyQualifiedName; + public override Type? BaseType => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override Type? DeclaringType => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override Type? ReflectedType => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder, + CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] + protected override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder, + CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers) + => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] + public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] + public override FieldInfo? GetField(string name, BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] + public override FieldInfo[] GetFields(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + public override Type[] GetFunctionPointerCallingConventions() => _unmodifiedType.GetFunctionPointerCallingConventions(); + public override Type[] GetFunctionPointerParameterTypes() => _unmodifiedType.GetFunctionPointerParameterTypes(); + public override Type GetFunctionPointerReturnType() => _unmodifiedType.GetFunctionPointerReturnType(); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] + public override Type? GetInterface(string name, bool ignoreCase) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] + public override Type[] GetInterfaces() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type interfaceType) => _unmodifiedType.GetInterfaceMap(interfaceType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] + public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents)] + public override EventInfo[] GetEvents() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] + protected override PropertyInfo? GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder, + Type? returnType, Type[]? types, ParameterModifier[]? modifiers) + => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] + public override EventInfo[] GetEvents(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] + public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] + public override Type? GetNestedType(string name, BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(GetAllMembers)] + public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + [DynamicallyAccessedMembers(GetAllMembers)] + public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + public override MemberInfo GetMemberWithSameMetadataDefinitionAs(MemberInfo member) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + protected override TypeAttributes GetAttributeFlagsImpl() => _unmodifiedType.Attributes; + public override int GetArrayRank() => _unmodifiedType.GetArrayRank(); + + public override bool IsTypeDefinition => _unmodifiedType.IsTypeDefinition; + public override bool IsSZArray => _unmodifiedType.IsSZArray; + public override bool IsVariableBoundArray => _unmodifiedType.IsVariableBoundArray; + + protected override bool IsArrayImpl() => _unmodifiedType.IsArray; + public override bool IsEnum => _unmodifiedType.IsEnum; + protected override bool IsPrimitiveImpl() => _unmodifiedType.IsPrimitive; + protected override bool IsByRefImpl() => _unmodifiedType.IsByRef; + public override bool IsGenericTypeParameter => _unmodifiedType.IsGenericTypeParameter; + public override bool IsGenericMethodParameter => _unmodifiedType.IsGenericMethodParameter; + protected override bool IsPointerImpl() => _unmodifiedType.IsPointer; + protected override bool IsValueTypeImpl() => _unmodifiedType.IsValueType; + protected override bool IsCOMObjectImpl() => _unmodifiedType.IsCOMObject; + public override bool IsByRefLike => _unmodifiedType.IsByRefLike; + public override bool IsConstructedGenericType => _unmodifiedType.IsConstructedGenericType; + + public override bool IsCollectible => _unmodifiedType.IsCollectible; + + public override bool IsFunctionPointer => _unmodifiedType.IsFunctionPointer; + public override bool IsUnmanagedFunctionPointer => _unmodifiedType.IsUnmanagedFunctionPointer; + + public override bool IsSecurityCritical => _unmodifiedType.IsSecurityCritical; + public override bool IsSecuritySafeCritical => _unmodifiedType.IsSecuritySafeCritical; + public override bool IsSecurityTransparent => _unmodifiedType.IsSecurityTransparent; + + public override Type? GetElementType() => _unmodifiedType.GetElementType(); // Supported + protected override bool HasElementTypeImpl() => _unmodifiedType.HasElementType; + + // ICustomAttributeProvider + public override object[] GetCustomAttributes(bool inherit) => _unmodifiedType.GetCustomAttributes(inherit); + public override object[] GetCustomAttributes(Type attributeType, bool inherit) => _unmodifiedType.GetCustomAttributes(attributeType, inherit); + public override bool IsDefined(Type attributeType, bool inherit) => _unmodifiedType.IsDefined(attributeType, inherit); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs index 99d560db28ded4..6711d1430484b7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/TypeDelegator.cs @@ -4,6 +4,10 @@ // TypeDelegator // // This class wraps a Type object and delegates all methods to that Type. +// +// When changes are made here, also consider changing the ModifiedType class +// in both the runtime and in MetadataLoadContext since those classes also +// wrap Type. using System.Diagnostics.CodeAnalysis; using CultureInfo = System.Globalization.CultureInfo; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx b/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx index f0ca801c005d15..4412920b3cdf8d 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/Resources/Strings.resx @@ -192,6 +192,9 @@ This property is not supported on assemblies loaded by a MetadataLoadContext as there is no trust level to evaluate these against. + + Method may only be called on a Type for which Type.IsFunctionPointer is true. + This operation is only valid on generic types. @@ -228,9 +231,6 @@ Passing true for ignoreCase is not supported on assemblies loaded by a MetadataLoadContext. - - Parsing function pointer types in signatures is not supported. - GetBaseDefinition() is not supported on assemblies loaded by a MetadataLoadContext. @@ -243,6 +243,9 @@ MDStreamVersion is not supported on assemblies loaded by a MetadataLoadContext. + + Modified types do not support this member. Use the UnderlyingSystemType property to call this member. + Resolving tokens is not supported on assemblies loaded by a MetadataLoadContext. @@ -267,7 +270,4 @@ The path '{0}' is not valid. - - Method may only be called on a Type for which Type.IsFunctionPointer is true. - \ No newline at end of file diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index d3cff8244b2ca3..24b13652f03bd6 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -144,7 +144,6 @@ - diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs index 40847efb0b1cd6..73cd87437551f6 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs @@ -128,7 +128,7 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj) for (int i = 0; i < args.Length; i++) { - if (!args[i].Equals(otherArgs[i])) + if (args[i] != otherArgs[i]) return false; } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs index 3e733a060147d3..9b9ce3d8f95e56 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection.TypeLoading; +using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute; namespace System.Reflection { @@ -12,14 +13,18 @@ namespace System.Reflection /// Base type for modified types obtained through FieldInfo.GetModifiedFieldInfo(), PropertyInfo.GetModifiedPropertyInfo() /// and ParameterInfo.GetModifiedParameterInfo(). /// - internal abstract class RoModifiedType : RoTypeDelegator + internal abstract class RoModifiedType : RoType { private List? _requiredModifiersBuilder; private List? _optionalModifiersBuilder; private Type[]? _requiredModifiers; private Type[]? _optionalModifiers; + private readonly RoType _unmodifiedType; - protected RoModifiedType(RoType unmodifiedType) : base(unmodifiedType) { } + protected RoModifiedType(RoType unmodifiedType) + { + _unmodifiedType = unmodifiedType; + } public static RoModifiedType Create(RoType unmodifiedType) { @@ -64,6 +69,9 @@ public void AddOptionalModifier(Type type) _optionalModifiersBuilder.Add(type); } + // Below are the multitude of Type overloads. We throw NSE for members that would return an unmodified Type + // directly or indirectly. We do this in case we want to support returning modified types instead. + public override Type[] GetRequiredCustomModifiers() { if (_requiredModifiers == null) @@ -100,18 +108,106 @@ public override Type[] GetOptionalCustomModifiers() return Helpers.CloneArray(_optionalModifiers); } - public sealed override bool Equals([NotNullWhen(true)] object? obj) + public override Type UnderlyingSystemType => _unmodifiedType; + + // Modified types do not support Equals other than when references are equal. + // UnderlyingSystemType.Equals() should should be used if basic equality is necessary. + // Supporting Equals on a modified type would need to include custom modifiers and any parameterized types recursively. + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (!(obj is RoModifiedType)) + return false; + + return ReferenceEquals(this, obj); + } + + public override bool Equals(Type? t) { - if (!(obj is RoFunctionPointerType otherModifiedType)) + if (!(t is RoModifiedType)) return false; - return ReferenceEquals(this, otherModifiedType); + return ReferenceEquals(this, t); } - public override int GetHashCode() => base.GetHashCode(); + public override int GetHashCode() => _unmodifiedType.GetHashCode(); + public override string ToString() => _unmodifiedType.ToString(); + public sealed override bool IsEnum => _unmodifiedType.IsEnum; + protected sealed override bool IsPrimitiveImpl() => _unmodifiedType.IsPrimitive; + protected sealed override bool IsValueTypeImpl() => _unmodifiedType.IsValueType; + public override bool IsTypeDefinition => _unmodifiedType.IsTypeDefinition; + public override bool IsGenericTypeDefinition => _unmodifiedType.IsGenericTypeDefinition; + protected override bool HasElementTypeImpl() => _unmodifiedType.Call_HasElementTypeImpl(); + protected override bool IsArrayImpl() => _unmodifiedType.Call_IsArrayImpl(); + public override bool IsSZArray => _unmodifiedType.IsSZArray(); + public override bool IsVariableBoundArray => _unmodifiedType.IsVariableBoundArray; + protected override bool IsByRefImpl() => _unmodifiedType.Call_IsByRefImpl(); + protected override bool IsPointerImpl() => _unmodifiedType.Call_IsPointerImpl(); + public override bool IsFunctionPointer => _unmodifiedType.IsFunctionPointer; + public override bool IsUnmanagedFunctionPointer => _unmodifiedType.IsUnmanagedFunctionPointer; + public override bool IsConstructedGenericType => _unmodifiedType.IsConstructedGenericType; + public override bool IsGenericParameter => _unmodifiedType.IsGenericParameter; + public override bool IsGenericTypeParameter => _unmodifiedType.IsGenericTypeParameter; + public override bool IsGenericMethodParameter => _unmodifiedType.IsGenericMethodParameter; + public override bool ContainsGenericParameters => _unmodifiedType.ContainsGenericParameters; + + internal override RoModule GetRoModule() => _unmodifiedType.GetRoModule(); + + public override int GetArrayRank() => _unmodifiedType.GetArrayRank(); + + protected override string ComputeName() => _unmodifiedType.Call_ComputeName(); + protected override string? ComputeNamespace() => _unmodifiedType.Call_ComputeNamespace(); + protected override string? ComputeFullName() => _unmodifiedType.Call_ComputeFullName(); + + protected override TypeAttributes ComputeAttributeFlags() => _unmodifiedType.Call_ComputeAttributeFlags(); + protected override TypeCode GetTypeCodeImpl() => _unmodifiedType.Call_GetTypeCodeImpl(); + + public override MethodBase? DeclaringMethod => throw new NotSupportedException(SR.NotSupported_ModifiedType); + protected override RoType? ComputeDeclaringType() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + public override IEnumerable DeclaredNestedTypes + { +#if NETCOREAPP + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicNestedTypes | DynamicallyAccessedMemberTypes.PublicNestedTypes)] +#endif + get { throw new NotSupportedException(SR.NotSupported_ModifiedType); } + } + + public override IEnumerable CustomAttributes => _unmodifiedType.CustomAttributes; + internal override bool IsCustomAttributeDefined(ReadOnlySpan ns, ReadOnlySpan name) => _unmodifiedType.IsCustomAttributeDefined(ns, name); + internal override CustomAttributeData? TryFindCustomAttribute(ReadOnlySpan ns, ReadOnlySpan name) => _unmodifiedType.TryFindCustomAttribute(ns, name); + + public override int MetadataToken => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + internal override RoType? GetRoElementType() => null; + + public override Type GetGenericTypeDefinition() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + // Generic parameters are supported. + internal override RoType[] GetGenericTypeParametersNoCopy() => _unmodifiedType.GetGenericTypeParametersNoCopy(); + internal override RoType[] GetGenericTypeArgumentsNoCopy() => _unmodifiedType.GetGenericTypeArgumentsNoCopy(); + protected internal override RoType[] GetGenericArgumentsNoCopy() => _unmodifiedType.GetGenericArgumentsNoCopy(); + [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] + public override Type MakeGenericType(params Type[] typeArguments) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + public override Type GetFunctionPointerReturnType() => throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + public override Type[] GetFunctionPointerParameterTypes() => throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer); + + public override GenericParameterAttributes GenericParameterAttributes => _unmodifiedType.GenericParameterAttributes; + public override int GenericParameterPosition => _unmodifiedType.GenericParameterPosition; + public override Type[] GetGenericParameterConstraints() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override Guid GUID => _unmodifiedType.GUID; + public override StructLayoutAttribute? StructLayoutAttribute => _unmodifiedType.StructLayoutAttribute; + protected internal override RoType ComputeEnumUnderlyingType() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + + internal override RoType? ComputeBaseTypeWithoutDesktopQuirk() => throw new NotSupportedException(SR.NotSupported_ModifiedType); + internal override IEnumerable ComputeDirectlyImplementedInterfaces() => throw new NotSupportedException(SR.NotSupported_ModifiedType); - // TypeDelegator doesn't forward the way we want. - public override Type UnderlyingSystemType => TypeImpl; - protected sealed override RoType? ComputeDeclaringType() => null; + // Low level support for the BindingFlag-driven enumerator apis. + internal override IEnumerable GetConstructorsCore(NameFilter? filter) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + internal override IEnumerable GetMethodsCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + internal override IEnumerable GetEventsCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + internal override IEnumerable GetFieldsCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + internal override IEnumerable GetPropertiesCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + internal override IEnumerable GetNestedTypesCore(NameFilter? filter) => throw new NotSupportedException(SR.NotSupported_ModifiedType); } } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.TypeClassification.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.TypeClassification.cs index 6f04239e7c99f8..9ed005fc39ef4c 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.TypeClassification.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.TypeClassification.cs @@ -68,7 +68,7 @@ private BaseTypeClassification ComputeBaseTypeClassification() private volatile BaseTypeClassification _lazyBaseTypeClassification; // Keep this separate from the other TypeClassification computations as it locks in the core assembly name. - protected sealed override bool IsPrimitiveImpl() + protected override bool IsPrimitiveImpl() { CoreTypes coreTypes = Loader.GetAllFoundCoreTypes(); foreach (CoreType primitiveType in s_primitiveTypes) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 0e5b30db95ad19..50ab6b7f307a08 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -24,28 +24,16 @@ public override bool Equals([NotNullWhen(true)] object? obj) { if (obj is RoType objType) { - if (objType is RoTypeDelegator ftObj) + if (obj is not RoModifiedType) { - objType = ftObj.TypeImpl; + return base.Equals(objType); } - - if (this is RoTypeDelegator ftThis) - { - // Call this Equals() again, but with actual type. - return ftThis.TypeImpl.Equals(objType); - } - - return base.Equals(objType); - } - else - { - return false; } + + return false; } public override int GetHashCode() => base.GetHashCode(); - - // Type classifiers public abstract override bool IsTypeDefinition { get; } public abstract override bool IsGenericTypeDefinition { get; } protected abstract override bool HasElementTypeImpl(); @@ -278,8 +266,8 @@ public sealed override bool IsAssignableFrom(Type? c) // Identify interesting subgroups of Types protected sealed override bool IsCOMObjectImpl() => false; // RCW's are irrelevant in a MetadataLoadContext without object creation. - public sealed override bool IsEnum => (GetBaseTypeClassification() & BaseTypeClassification.IsEnum) != 0; - protected sealed override bool IsValueTypeImpl() => (GetBaseTypeClassification() & BaseTypeClassification.IsValueType) != 0; + public override bool IsEnum => (GetBaseTypeClassification() & BaseTypeClassification.IsEnum) != 0; + protected override bool IsValueTypeImpl() => (GetBaseTypeClassification() & BaseTypeClassification.IsValueType) != 0; // Metadata public abstract override int MetadataToken { get; } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs deleted file mode 100644 index f4b1708316bd9e..00000000000000 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoTypeDelegator.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// TODO (PR REVIEW COMMENT): remove this file and throw NSE from RoModifiedType for members -// that can directly or indirectly return an unmodified Type. - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute; - -namespace System.Reflection.TypeLoading -{ - // Similar to TypeDelegator, wraps an instance of a Type (in this case, RoType) and delegates calls to it. - // TypeDelegator cannot be used since it does not derive from RoType, and RoType is required to be used - // with MetadataReader interfaces. - internal abstract class RoTypeDelegator : RoType - { - private RoType _typeImpl; - - protected RoTypeDelegator(RoType actualType) - { - _typeImpl = actualType; - } - - public RoType TypeImpl => _typeImpl; - - // RoType also overrides Equals to ensure both l- and r-value are checked for actualType. - public override bool Equals([NotNullWhen(true)] object? obj) => _typeImpl.Equals(obj); - - public override int GetHashCode() => _typeImpl.GetHashCode(); - public override string ToString() => _typeImpl.ToString(); - - public override bool IsTypeDefinition => _typeImpl.IsTypeDefinition; - public override bool IsGenericTypeDefinition => _typeImpl.IsGenericTypeDefinition; - protected override bool HasElementTypeImpl() => _typeImpl.Call_HasElementTypeImpl(); - protected override bool IsArrayImpl() => _typeImpl.Call_IsArrayImpl(); - public override bool IsSZArray => _typeImpl.IsSZArray(); - public override bool IsVariableBoundArray => _typeImpl.IsVariableBoundArray; - protected override bool IsByRefImpl() => _typeImpl.Call_IsByRefImpl(); - protected override bool IsPointerImpl() => _typeImpl.Call_IsPointerImpl(); - public override bool IsFunctionPointer => _typeImpl.IsFunctionPointer; - public override bool IsUnmanagedFunctionPointer => _typeImpl.IsUnmanagedFunctionPointer; - public override bool IsConstructedGenericType => _typeImpl.IsConstructedGenericType; - public override bool IsGenericParameter => _typeImpl.IsGenericParameter; - public override bool IsGenericTypeParameter => _typeImpl.IsGenericTypeParameter; - public override bool IsGenericMethodParameter => _typeImpl.IsGenericMethodParameter; - public override bool ContainsGenericParameters => _typeImpl.ContainsGenericParameters; - - internal override RoModule GetRoModule() => _typeImpl.GetRoModule(); - - public override int GetArrayRank() => _typeImpl.GetArrayRank(); - - protected override string ComputeName() => _typeImpl.Call_ComputeName(); - protected override string? ComputeNamespace() => _typeImpl.Call_ComputeNamespace(); - protected override string? ComputeFullName() => _typeImpl.Call_ComputeFullName(); - - protected override TypeAttributes ComputeAttributeFlags() => _typeImpl.Call_ComputeAttributeFlags(); - protected override TypeCode GetTypeCodeImpl() => _typeImpl.Call_GetTypeCodeImpl(); - - public override MethodBase? DeclaringMethod => _typeImpl.DeclaringMethod; - protected override RoType? ComputeDeclaringType() => _typeImpl.Call_ComputeDeclaringType(); - - public override IEnumerable CustomAttributes => _typeImpl.CustomAttributes; - internal override bool IsCustomAttributeDefined(ReadOnlySpan ns, ReadOnlySpan name) => _typeImpl.IsCustomAttributeDefined(ns, name); - internal override CustomAttributeData? TryFindCustomAttribute(ReadOnlySpan ns, ReadOnlySpan name) => _typeImpl.TryFindCustomAttribute(ns, name); - - public override int MetadataToken => _typeImpl.MetadataToken; - - internal override RoType? GetRoElementType() => _typeImpl.GetRoElementType(); - - public override Type GetGenericTypeDefinition() => _typeImpl.GetGenericTypeDefinition(); - internal override RoType[] GetGenericTypeParametersNoCopy() => _typeImpl.GetGenericTypeParametersNoCopy(); - internal override RoType[] GetGenericTypeArgumentsNoCopy() => _typeImpl.GetGenericTypeArgumentsNoCopy(); - protected internal override RoType[] GetGenericArgumentsNoCopy() => _typeImpl.GetGenericArgumentsNoCopy(); - [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] - public override Type MakeGenericType(params Type[] typeArguments) => _typeImpl.MakeGenericType(typeArguments); - - public override GenericParameterAttributes GenericParameterAttributes => _typeImpl.GenericParameterAttributes; - public override int GenericParameterPosition => _typeImpl.GenericParameterPosition; - public override Type[] GetGenericParameterConstraints() => _typeImpl.GetGenericParameterConstraints(); - public override Type GetFunctionPointerReturnType() => _typeImpl.GetFunctionPointerReturnType(); - public override Type[] GetFunctionPointerParameterTypes() => _typeImpl.GetFunctionPointerParameterTypes(); - public override Guid GUID => _typeImpl.GUID; - public override StructLayoutAttribute? StructLayoutAttribute => _typeImpl.StructLayoutAttribute; - protected internal override RoType ComputeEnumUnderlyingType() => _typeImpl.ComputeEnumUnderlyingType(); - - internal override RoType? ComputeBaseTypeWithoutDesktopQuirk() => _typeImpl.ComputeBaseTypeWithoutDesktopQuirk(); - internal override IEnumerable ComputeDirectlyImplementedInterfaces() => _typeImpl.ComputeDirectlyImplementedInterfaces(); - - // Low level support for the BindingFlag-driven enumerator apis. - internal override IEnumerable GetConstructorsCore(NameFilter? filter) => _typeImpl.GetConstructorsCore(filter); - internal override IEnumerable GetMethodsCore(NameFilter? filter, Type reflectedType) => _typeImpl.GetMethodsCore(filter, reflectedType); - internal override IEnumerable GetEventsCore(NameFilter? filter, Type reflectedType) => _typeImpl.GetEventsCore(filter, reflectedType); - internal override IEnumerable GetFieldsCore(NameFilter? filter, Type reflectedType) => _typeImpl.GetFieldsCore(filter, reflectedType); - internal override IEnumerable GetPropertiesCore(NameFilter? filter, Type reflectedType) => _typeImpl.GetPropertiesCore(filter, reflectedType); - internal override IEnumerable GetNestedTypesCore(NameFilter? filter) => _typeImpl.GetNestedTypesCore(filter); - } -} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs index 2c650327d8c029..e111e1a18cbd5d 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/FunctionPointerTestsExtensions.cs @@ -2,12 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // The runtime tests have the name spacespace and methods to facilitate sharing. -namespace System.Tests.Types +namespace System.Reflection.Tests { internal static class FunctionPointerTestsExtensions { - public static Type Project(this Type type) => Reflection.Tests.TestUtils.Project(type); - public static bool IsMetadataLoadContext => true; /// diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.cs index 5b6635cabfafc7..c29e785ef65852 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestUtils.cs @@ -146,7 +146,6 @@ internal static byte[] ToArray(this Stream s) // to spread GetGenericArguments() calls all over so we do it once in this helper. public static Type[] GetGenericTypeParameters(this Type t) { - Debug.Assert(t.IsGenericTypeDefinition); return t.GetGenericArguments(); } From 70529f0e3ef3ee98b95a9a75be9572c485d6ada5 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Wed, 15 Feb 2023 11:53:56 -0600 Subject: [PATCH 17/20] Throw NSE on modified type Equals() and GetHashCode() --- src/coreclr/vm/runtimehandles.cpp | 2 +- .../FunctionPointerCallingConventionTests.cs | 1 - .../System/FunctionPointerEqualityTests.cs | 19 +++++---------- .../tests/System/FunctionPointerTests.cs | 11 ++++----- .../Common/tests/System/ModifiedTypeTests.cs | 6 +++++ .../src/System/Reflection/ModifiedType.cs | 23 ++++--------------- .../TypeLoading/Modules/RoModule.Unifier.cs | 20 ++++++++++++---- .../Types/RoConstructedGenericType.Key.cs | 17 ++++++++++++-- .../TypeLoading/Types/RoModifiedType.cs | 22 ++++-------------- 9 files changed, 57 insertions(+), 64 deletions(-) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index df847b0f900179..037c9e91402e5b 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -931,7 +931,7 @@ FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsUnmanagedFunctionPointer, ReflectClass if (typeHandle.IsFnPtrType()) { FnPtrTypeDesc* fnPtr = typeHandle.AsFnPtrType(); - unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_UNMANAGED) == IMAGE_CEE_CS_CALLCONV_UNMANAGED; + unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_UNMANAGED; } FC_RETURN_BOOL(unmanaged); diff --git a/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs b/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs index 1024ab823c5950..6150907e43d813 100644 --- a/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerCallingConventionTests.cs @@ -110,7 +110,6 @@ public static unsafe void UnmanagedCallConvs_Return_Modified() Assert.True(fcnPtr2.IsUnmanagedFunctionPointer); Assert.NotSame(fcnPtr1, fcnPtr2); - Assert.False(fcnPtr1.IsFunctionPointerEqual(fcnPtr2)); Type retType = fcnPtr1.GetFunctionPointerReturnType(); Assert.True(typeof(int).Project().IsFunctionPointerEqual(retType.UnderlyingSystemType)); diff --git a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs index d6f199c86af013..43c524ac0546f6 100644 --- a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs @@ -40,17 +40,12 @@ public static unsafe void ObjectEquals_ModifiedTypes() MethodInfo m1 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue1), Bindings); Type t1 = m1.ReturnParameter.GetModifiedParameterType(); + Assert.NotSame(t1, t1.UnderlyingSystemType); MethodInfo m2 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue2), Bindings); Type t2 = m2.ReturnParameter.GetModifiedParameterType(); - Assert.False(ReferenceEquals(t1, t1.UnderlyingSystemType)); - - // Modified types do not support Equals other than when references are equal. - Assert.True(t1.Equals(t1)); - Assert.False(t1.Equals(t2)); - Assert.False(((object)t1).Equals(t2)); - Assert.False(t1.Equals((object)t2)); + Assert.NotSame(t1, t2); } [Fact] @@ -64,11 +59,8 @@ public static unsafe void ObjectEquals_OneSideModifiedType() Type modifiedType = m1.ReturnParameter.GetModifiedParameterType(); Type t = typeof(int).Project(); - Assert.False(ReferenceEquals(modifiedType, modifiedType.UnderlyingSystemType)); - Assert.False(ReferenceEquals(modifiedType, t)); - Assert.False(modifiedType.Equals(t)); - Assert.False(((object)modifiedType).Equals(t)); - Assert.False(modifiedType.Equals((object)t)); + Assert.NotSame(modifiedType, modifiedType.UnderlyingSystemType); + Assert.NotSame(modifiedType, t); } [Theory] @@ -166,7 +158,8 @@ public static unsafe void CallingConvention_Modified(string methodName1, string Type fnPtrType1 = m1.GetParameters()[0].GetModifiedParameterType(); Type fnPtrType2 = m2.GetParameters()[0].GetModifiedParameterType(); - Assert.True(fnPtrType1.IsFunctionPointerNotEqual(fnPtrType2)); + // Modified types don't support Equals, so just verify instance. + Assert.NotSame(fnPtrType1, fnPtrType2); } private unsafe class FunctionPointerHolder diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index df39bab6730643..e80a1528d27a7c 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -36,7 +36,6 @@ public static unsafe void TypeMembers() Assert.Equal(TypeAttributes.Public, t.Attributes); Assert.Null(t.BaseType); Assert.False(t.ContainsGenericParameters); - Assert.False(t.ContainsGenericParameters); Assert.False(t.DeclaredConstructors.Any()); Assert.False(t.DeclaredEvents.Any()); Assert.False(t.DeclaredFields.Any()); @@ -233,11 +232,11 @@ public static unsafe void Property(string name, string expectedToString) Type fnPtrType = p.PropertyType; Assert.Equal(expectedToString, fnPtrType.ToString()); - VerifyFieldOrProperty(fnPtrType, isModified: false); + VerifyFieldOrProperty(fnPtrType); fnPtrType = p.GetModifiedPropertyType(); Assert.Equal(expectedToString, fnPtrType.ToString()); - VerifyFieldOrProperty(fnPtrType, isModified: true); + VerifyFieldOrProperty(fnPtrType); } [Theory] @@ -253,14 +252,14 @@ public static unsafe void Field(string name, string expectedToString) Type fnPtrType = f.FieldType; Assert.Equal(expectedToString, fnPtrType.ToString()); - VerifyFieldOrProperty(fnPtrType, isModified: false); + VerifyFieldOrProperty(fnPtrType); fnPtrType = f.GetModifiedFieldType(); Assert.Equal(expectedToString, fnPtrType.ToString()); - VerifyFieldOrProperty(fnPtrType, isModified: true); + VerifyFieldOrProperty(fnPtrType); } - private static void VerifyFieldOrProperty(Type fnPtrType, bool isModified) + private static void VerifyFieldOrProperty(Type fnPtrType) { Assert.Null(fnPtrType.FullName); Assert.Null(fnPtrType.AssemblyQualifiedName); diff --git a/src/libraries/Common/tests/System/ModifiedTypeTests.cs b/src/libraries/Common/tests/System/ModifiedTypeTests.cs index b0a7599ab2cc78..ba973b17bb25cc 100644 --- a/src/libraries/Common/tests/System/ModifiedTypeTests.cs +++ b/src/libraries/Common/tests/System/ModifiedTypeTests.cs @@ -118,6 +118,9 @@ void UnmodifiedTypeMembers(Type t) Assert.False(t.GetOptionalCustomModifiers().Any()); Assert.False(t.GetRequiredCustomModifiers().Any()); Assert.True(t.IsPrimitive); + Assert.True(((object)t).Equals(t)); + Assert.True(t.Equals(t)); + Assert.Equal(t.GetHashCode(), t.GetHashCode()); Assert.NotNull(t.BaseType); Assert.Null(t.DeclaringType); Assert.Null(t.ReflectedType); @@ -132,6 +135,9 @@ void ModifiedTypeMembers(Type t) Assert.False(t.GetOptionalCustomModifiers().Any()); Assert.True(t.GetRequiredCustomModifiers().Any()); // The volatile modifier. Assert.True(t.IsPrimitive); + Assert.Throws(() => ((object)t).Equals(t)); + Assert.Throws(() => t.Equals(t)); + Assert.Throws(() => t.GetHashCode()); Assert.Throws(() => t.BaseType); Assert.Throws(() => t.DeclaringType); Assert.Throws(() => t.ReflectedType); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs index b58ffc5579d868..9ab42fdc11d251 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs @@ -65,27 +65,12 @@ public override Type[] GetOptionalCustomModifiers() return GetCustomModifiers(required: false); } - // Modified types do not support Equals other than when references are equal. + // Modified types do not support Equals. That would need to include custom modifiers and any parameterized types recursively. // UnderlyingSystemType.Equals() should should be used if basic equality is necessary. - // Supporting Equals on a modified type would need to include custom modifiers and any parameterized types recursively. - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (!(obj is ModifiedType)) - return false; - - return ReferenceEquals(this, obj); - } - - public override bool Equals(Type? other) - { - if (other is ModifiedType otherModifiedType) - { - return ReferenceEquals(this, otherModifiedType); - } + public override bool Equals([NotNullWhen(true)] object? obj) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override bool Equals(Type? other) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override int GetHashCode() => throw new NotSupportedException(SR.NotSupported_ModifiedType); - return false; - } - public override int GetHashCode() => _unmodifiedType.GetHashCode(); public override string ToString() => _unmodifiedType.ToString(); public override Type UnderlyingSystemType => _unmodifiedType; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoModule.Unifier.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoModule.Unifier.cs index 9bc2edc59949e9..7c19636bcde1ef 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoModule.Unifier.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoModule.Unifier.cs @@ -12,7 +12,10 @@ internal abstract partial class RoModule // internal RoArrayType GetUniqueArrayType(RoType elementType) { - return _szArrayDict.GetOrAdd(elementType, s_szArrayTypeFactory); + // Modified types do not support Equals\GetHashCode. + return elementType is RoModifiedType ? + s_szArrayTypeFactory(elementType) : + _szArrayDict.GetOrAdd(elementType, s_szArrayTypeFactory); } private static readonly Func s_szArrayTypeFactory = (e) => new RoArrayType(e, multiDim: false, rank: 1); private readonly ConcurrentDictionary _szArrayDict = new ConcurrentDictionary(); @@ -22,7 +25,11 @@ internal RoArrayType GetUniqueArrayType(RoType elementType) // internal RoArrayType GetUniqueArrayType(RoType elementType, int rank) { - return _mdArrayDict.GetOrAdd(new RoArrayType.Key(elementType, rank: rank), s_mdArrayTypeFactory); + // Modified types do not support Equals\GetHashCode. + RoArrayType.Key key = new(elementType, rank: rank); + return elementType is RoModifiedType ? + s_mdArrayTypeFactory(key) : + _mdArrayDict.GetOrAdd(key, s_mdArrayTypeFactory); } private static readonly Func s_mdArrayTypeFactory = (k) => new RoArrayType(k.ElementType, multiDim: true, rank: k.Rank); private readonly ConcurrentDictionary _mdArrayDict = new ConcurrentDictionary(); @@ -32,7 +39,10 @@ internal RoArrayType GetUniqueArrayType(RoType elementType, int rank) // internal RoByRefType GetUniqueByRefType(RoType elementType) { - return _byRefDict.GetOrAdd(elementType, s_byrefTypeFactory); + // Modified types do not support Equals\GetHashCode. + return elementType is RoModifiedType ? + s_byrefTypeFactory(elementType) : + _byRefDict.GetOrAdd(elementType, s_byrefTypeFactory); } private static readonly Func s_byrefTypeFactory = (e) => new RoByRefType(e); private readonly ConcurrentDictionary _byRefDict = new ConcurrentDictionary(); @@ -42,7 +52,9 @@ internal RoByRefType GetUniqueByRefType(RoType elementType) // internal RoPointerType GetUniquePointerType(RoType elementType) { - return _pointerDict.GetOrAdd(elementType, (e) => new RoPointerType(e)); + return elementType is RoModifiedType ? + new RoPointerType(elementType) : + _pointerDict.GetOrAdd(elementType, (e) => new RoPointerType(e)); } private readonly ConcurrentDictionary _pointerDict = new ConcurrentDictionary(); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.Key.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.Key.cs index 92121c08dee22e..1c9c177ddb10e6 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.Key.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoConstructedGenericType.Key.cs @@ -30,8 +30,18 @@ public bool Equals(Key other) return false; for (int i = 0; i < GenericTypeArguments.Length; i++) { - if (GenericTypeArguments[i] != other.GenericTypeArguments[i]) + Type t1 = GenericTypeArguments[i]; + Type t2 = other.GenericTypeArguments[i]; + + // Modified types do not support Equals\GetHashCode. + if (t1 is RoModifiedType || t2 is RoModifiedType) + { + return ReferenceEquals(t1, t2); + } + else if (t1 != t2) + { return false; + } } return true; } @@ -43,7 +53,10 @@ public override int GetHashCode() int hashCode = GenericTypeDefinition.GetHashCode(); for (int i = 0; i < GenericTypeArguments.Length; i++) { - hashCode ^= GenericTypeArguments[i].GetHashCode(); + RoType argType = GenericTypeArguments[i]; + hashCode ^= argType is RoModifiedType ? + argType.UnderlyingSystemType.GetHashCode() : + argType.GetHashCode(); } return hashCode; } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs index 9b9ce3d8f95e56..afb9c79952ccfe 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoModifiedType.cs @@ -110,26 +110,12 @@ public override Type[] GetOptionalCustomModifiers() public override Type UnderlyingSystemType => _unmodifiedType; - // Modified types do not support Equals other than when references are equal. + // Modified types do not support Equals. That would need to include custom modifiers and any parameterized types recursively. // UnderlyingSystemType.Equals() should should be used if basic equality is necessary. - // Supporting Equals on a modified type would need to include custom modifiers and any parameterized types recursively. - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (!(obj is RoModifiedType)) - return false; - - return ReferenceEquals(this, obj); - } - - public override bool Equals(Type? t) - { - if (!(t is RoModifiedType)) - return false; - - return ReferenceEquals(this, t); - } + public override bool Equals([NotNullWhen(true)] object? obj) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override bool Equals(Type? other) => throw new NotSupportedException(SR.NotSupported_ModifiedType); + public override int GetHashCode() => throw new NotSupportedException(SR.NotSupported_ModifiedType); - public override int GetHashCode() => _unmodifiedType.GetHashCode(); public override string ToString() => _unmodifiedType.ToString(); public sealed override bool IsEnum => _unmodifiedType.IsEnum; protected sealed override bool IsPrimitiveImpl() => _unmodifiedType.IsPrimitive; From 9770a2d97b6ff93242f24104268c0d476c72f101 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Wed, 15 Feb 2023 12:58:20 -0600 Subject: [PATCH 18/20] Fix tests for WASI --- src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index a380353bae0911..b85c93bb4b9faa 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -338,7 +338,7 @@ - + From 14a9007ca23f70cdac5ecb432e0c6ff0338a6824 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 16 Feb 2023 09:33:55 -0600 Subject: [PATCH 19/20] Remove unnecessary high overhead tests --- .../System/FunctionPointerEqualityTests.cs | 60 ------------------- .../FunctionPointerHolder.cs | 18 ------ .../TestFunctionPointerAssembly.csproj | 11 ---- .../System.Reflection.MetadataLoadContext.sln | 7 --- ...eflection.MetadataLoadContext.Tests.csproj | 1 - .../System.Runtime/System.Runtime.sln | 21 ------- .../tests/System.Runtime.Tests.csproj | 1 - 7 files changed, 119 deletions(-) delete mode 100644 src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs delete mode 100644 src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj diff --git a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs index 43c524ac0546f6..ad392c7e4042fe 100644 --- a/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs @@ -63,66 +63,6 @@ public static unsafe void ObjectEquals_OneSideModifiedType() Assert.NotSame(modifiedType, t); } - [Theory] - [InlineData(nameof(FunctionPointerHolder.Field_Int), nameof(FunctionPointerHolder.Field_DateOnly))] - [InlineData(nameof(FunctionPointerHolder.Field_DateOnly), nameof(FunctionPointerHolder.Field_Int))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void SigInDifferentModule_Field(string name, string otherName) - { - Type fph1 = typeof(FunctionPointerHolder).Project(); - Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); - Assert.True(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph2, name))); - - // Verify other combinations fail - Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); - Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); - Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); - Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); - - static Type GetFuncPtr(Type owner, string name) => owner.GetField(name, Bindings).FieldType; - } - - [Theory] - [InlineData(nameof(FunctionPointerHolder.Prop_Int), nameof(FunctionPointerHolder.Prop_DateOnly))] - [InlineData(nameof(FunctionPointerHolder.Prop_DateOnly), nameof(FunctionPointerHolder.Prop_Int))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void SigInDifferentModule_Property(string name, string otherName) - { - Type fph1 = typeof(FunctionPointerHolder).Project(); - Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); - Assert.True(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph2, name))); - - // Verify other combinations fail - Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); - Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); - Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); - Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); - - static Type GetFuncPtr(Type owner, string name) => owner.GetProperty(name, Bindings).PropertyType; - } - - [Theory] - [InlineData(nameof(FunctionPointerHolder.MethodReturnValue_Int), nameof(FunctionPointerHolder.MethodReturnValue_DateOnly))] - [InlineData(nameof(FunctionPointerHolder.MethodReturnValue_DateOnly), nameof(FunctionPointerHolder.MethodReturnValue_Int))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] - public static unsafe void SigInDifferentModule_MethodReturn(string name, string otherName) - { - Type fph1 = typeof(FunctionPointerHolder).Project(); - Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project(); - Assert.True(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph2, name))); - - // Verify other combinations fail - Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); - Assert.False(GetFuncPtr(fph1, name).IsFunctionPointerEqual(GetFuncPtr(fph1, otherName))); - Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); - Assert.False(GetFuncPtr(fph2, name).IsFunctionPointerEqual(GetFuncPtr(fph2, otherName))); - - static Type GetFuncPtr(Type owner, string name) => owner.GetMethod(name, Bindings).ReturnParameter.ParameterType; - } - [Theory] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Cdecl_SuppressGCTransition))] [InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Stdcall))] diff --git a/src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs b/src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs deleted file mode 100644 index 0013f93e0f9abf..00000000000000 --- a/src/libraries/Common/tests/System/TestFunctionPointerAssembly/FunctionPointerHolder.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Reflection; -using System.Threading; - -public unsafe class FunctionPointerHolderSeparateModule -{ - public delegate* managed Field_Int; - public delegate* managed Field_DateOnly; // Verify non-primitive which will have its own Rid - public delegate* managed Prop_Int { get; } - public delegate* managed Prop_DateOnly { get; } - public delegate* managed MethodReturnValue_Int() => default; - public delegate* managed MethodReturnValue_DateOnly() => default; - public delegate* unmanaged MethodUnmanagedReturnValue_Int() => default; - public delegate* unmanaged MethodUnmanagedReturnValue_DateOnly() => default; -} diff --git a/src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj b/src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj deleted file mode 100644 index 0a8720fa6bbdae..00000000000000 --- a/src/libraries/Common/tests/System/TestFunctionPointerAssembly/TestFunctionPointerAssembly.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - true - 1.0.0.0 - $(NetCoreAppCurrent) - True - - - - - diff --git a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln index f10bd6caa6ceb2..d9375ddfe65190 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln +++ b/src/libraries/System.Reflection.MetadataLoadContext/System.Reflection.MetadataLoadContext.sln @@ -17,8 +17,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.MetadataL EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.MetadataLoadContext.Tests", "tests\System.Reflection.MetadataLoadContext.Tests.csproj", "{D28B6414-C82C-4BDE-B8BB-A4E3297A0651}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{F85BDD51-AC29-4D8D-8257-C509BED9A448}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestILAssembly", "..\Common\tests\System\TestILAssembly\TestILAssembly.ilproj", "{6DA9926C-8763-42A2-A51A-EDF8684C80A8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{4361CEFA-8238-4247-9CC5-D99DF794843C}" @@ -81,10 +79,6 @@ Global {D28B6414-C82C-4BDE-B8BB-A4E3297A0651}.Debug|Any CPU.Build.0 = Debug|Any CPU {D28B6414-C82C-4BDE-B8BB-A4E3297A0651}.Release|Any CPU.ActiveCfg = Release|Any CPU {D28B6414-C82C-4BDE-B8BB-A4E3297A0651}.Release|Any CPU.Build.0 = Release|Any CPU - {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F85BDD51-AC29-4D8D-8257-C509BED9A448}.Release|Any CPU.Build.0 = Release|Any CPU {4361CEFA-8238-4247-9CC5-D99DF794843C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4361CEFA-8238-4247-9CC5-D99DF794843C}.Debug|Any CPU.Build.0 = Debug|Any CPU {4361CEFA-8238-4247-9CC5-D99DF794843C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -104,7 +98,6 @@ Global GlobalSection(NestedProjects) = preSolution {6A69770F-4F95-411F-ACAE-2B902EB62161} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {D28B6414-C82C-4BDE-B8BB-A4E3297A0651} = {F45DECCA-03D3-4087-AB01-F099C027DC33} - {F85BDD51-AC29-4D8D-8257-C509BED9A448} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {6DA9926C-8763-42A2-A51A-EDF8684C80A8} = {F45DECCA-03D3-4087-AB01-F099C027DC33} {22BDB23C-24DE-4C3C-9A18-A048C445EDC1} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} {E524DAF8-3F2C-4EC5-833D-E7D182055A66} = {B3731232-B2FE-401B-A9F1-5DFB1A90D687} diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index 9f7b66f0cc1fda..e1e1e937f20b33 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -74,7 +74,6 @@ - diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index 1d11b33776dcaf..01b1044d52de52 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -43,8 +43,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCollectibleAssembly", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestILAssembly", "..\Common\tests\System\TestILAssembly\TestILAssembly.ilproj", "{AF7BA66D-EA0E-4755-8DA8-4CFE9B935F83}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionPointerAssembly", "..\Common\tests\System\TestFunctionPointerAssembly\TestFunctionPointerAssembly.csproj", "{B7975A39-2E87-4C6C-A7EC-1F5926676800}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLoadAssembly", "tests\TestLoadAssembly\TestLoadAssembly.csproj", "{1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.TestModule", "tests\TestModule\System.Reflection.TestModule.ilproj", "{0F83B07B-2E3F-4708-BE6D-7A8DA8168803}" @@ -392,24 +390,6 @@ Global {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x64.Build.0 = Release|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x86.ActiveCfg = Release|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x86.Build.0 = Release|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|Any CPU.Build.0 = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x64.ActiveCfg = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x64.Build.0 = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x86.ActiveCfg = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Checked|x86.Build.0 = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x64.ActiveCfg = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x64.Build.0 = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x86.ActiveCfg = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Debug|x86.Build.0 = Debug|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|Any CPU.Build.0 = Release|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x64.ActiveCfg = Release|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x64.Build.0 = Release|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x86.ActiveCfg = Release|Any CPU - {B7975A39-2E87-4C6C-A7EC-1F5926676800}.Release|x86.Build.0 = Release|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x64.ActiveCfg = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x86.ActiveCfg = Debug|Any CPU @@ -584,7 +564,6 @@ Global {C3F25EEF-04B4-407A-960B-0C1CE9C04430} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {47E26787-7C27-4572-AD8B-868DE44E2C48} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {C230AC88-A377-4BEB-824F-AB174C14DC86} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} - {B7975A39-2E87-4C6C-A7EC-1F5926676800} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {0F83B07B-2E3F-4708-BE6D-7A8DA8168803} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index b85c93bb4b9faa..8be0ce5839a3c8 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -339,7 +339,6 @@ - From f76331c7d9efd785b8f70178c7cb820538155369 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 16 Feb 2023 09:53:20 -0600 Subject: [PATCH 20/20] Fix merge error --- src/libraries/System.Private.CoreLib/src/Resources/Strings.resx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index f907afc4ab6d66..3d9d7ae1ca364d 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3997,6 +3997,7 @@ Modified types do not support this member. Use the UnderlyingSystemType property to call this member. + An unexpected state object was encountered. This is usually a sign of a bug in async method custom infrastructure, such as a custom awaiter or IValueTaskSource implementation.