From 1dd5a8c767a3828cbb4ff669d282c72dcead832e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 26 Apr 2023 12:51:27 -0700 Subject: [PATCH] Fix generic dictionary lookups for param types and function pointers (#85369) * Fix generic dictionary lookups for param types and function pointers Fixes #85240 * AllowUnsafeBlocks * Disable test on Mono --- src/coreclr/vm/typedesc.cpp | 44 +++++++++++++++++----- src/coreclr/vm/typedesc.h | 4 ++ src/coreclr/vm/typehandle.cpp | 9 +++-- .../Regressions/coreclr/GitHub_85240/test85240.cs | 33 ++++++++++++++++ .../coreclr/GitHub_85240/test85240.csproj | 9 +++++ src/tests/issues.targets | 3 ++ 6 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 src/tests/Regressions/coreclr/GitHub_85240/test85240.cs create mode 100644 src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index db04506..0650f58 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -87,6 +87,23 @@ PTR_Module TypeDesc::GetLoaderModule() } } +BOOL TypeDesc::IsSharedByGenericInstantiations() +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (HasTypeParam()) + { + return GetRootTypeParam().IsCanonicalSubtype(); + } + + if (IsFnPtr()) + { + return dac_cast(this)->IsSharedByGenericInstantiations(); + } + + return FALSE; +} + PTR_BaseDomain TypeDesc::GetDomain() { CONTRACTL @@ -1634,18 +1651,26 @@ OBJECTREF TypeVarTypeDesc::GetManagedClassObject() TypeHandle * FnPtrTypeDesc::GetRetAndArgTypes() { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - + LIMITED_METHOD_CONTRACT; return m_RetAndArgTypes; } // FnPtrTypeDesc::GetRetAndArgTypes +BOOL +FnPtrTypeDesc::IsSharedByGenericInstantiations() +{ + LIMITED_METHOD_DAC_CONTRACT; + + for (DWORD i = 0; i <= m_NumArgs; i++) + { + if (m_RetAndArgTypes[i].IsCanonicalSubtype()) + { + return TRUE; + } + } + return FALSE; +} // FnPtrTypeDesc::IsSharedByGenericInstantiations + #ifndef DACCESS_COMPILE // Returns TRUE if all return and argument types are externally visible. @@ -1660,10 +1685,9 @@ FnPtrTypeDesc::IsExternallyVisible() const } CONTRACTL_END; - const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes(); for (DWORD i = 0; i <= m_NumArgs; i++) { - if (!rgRetAndArgTypes[i].IsExternallyVisible()) + if (!m_RetAndArgTypes[i].IsExternallyVisible()) { return FALSE; } diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index 7134195..a306930 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -181,6 +181,8 @@ public: return GetLoaderModule()->GetLoaderAllocator(); } + BOOL IsSharedByGenericInstantiations(); + protected: // See methodtable.h for details of the flags with the same name there enum @@ -524,6 +526,8 @@ public: return PTR_TypeHandle(m_RetAndArgTypes); } + BOOL IsSharedByGenericInstantiations(); + #ifndef DACCESS_COMPILE // Returns TRUE if all return and argument types are externally visible. BOOL IsExternallyVisible() const; diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 292d14f..647e14e 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -325,12 +325,15 @@ BOOL TypeHandle::IsSharedByGenericInstantiations() const { LIMITED_METHOD_DAC_CONTRACT; - if (IsArray()) + if (IsTypeDesc()) { - return GetArrayElementTypeHandle().IsCanonicalSubtype(); + return AsTypeDesc()->IsSharedByGenericInstantiations(); } - else if (!IsTypeDesc()) + else { + if (IsArray()) + return GetArrayElementTypeHandle().IsCanonicalSubtype(); + return AsMethodTable()->IsSharedByGenericInstantiations(); } diff --git a/src/tests/Regressions/coreclr/GitHub_85240/test85240.cs b/src/tests/Regressions/coreclr/GitHub_85240/test85240.cs new file mode 100644 index 0000000..e56c7d4 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_85240/test85240.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +#pragma warning disable 8500 + +public unsafe class Program +{ + static void AssertEqual(T actual, T expected) + { + if (!actual.Equals(expected)) + throw new Exception($"Failed Scenario. Actual = {actual}. Expected = {expected}"); + } + + public static Type GrabArray() => typeof(T[]); + public static Type GrabPtr() => typeof(T*); + public static Type GrabFnptr() => typeof(delegate*); + + public static int Main() + { + AssertEqual(GrabArray().GetElementType(), typeof(int)); + AssertEqual(GrabArray().GetElementType(), typeof(string)); + + AssertEqual(GrabPtr().GetElementType(), typeof(uint)); + AssertEqual(GrabPtr().GetElementType(), typeof(object)); + + AssertEqual(GrabFnptr().GetFunctionPointerReturnType(), typeof(DateTime)); + AssertEqual(GrabFnptr().GetFunctionPointerReturnType(), typeof(Action)); + + return 100; + } +} diff --git a/src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj b/src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj new file mode 100644 index 0000000..2dc4ce7 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj @@ -0,0 +1,9 @@ + + + Exe + true + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index f0d8e1b..c32e9c4 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1420,6 +1420,9 @@ + + https://github.com/dotnet/runtime/issues/71095 + https://github.com/dotnet/runtime/issues/79022 -- 2.7.4