summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Ayers <andya@microsoft.com>2019-02-15 14:39:33 -0800
committerGitHub <noreply@github.com>2019-02-15 14:39:33 -0800
commitbb62718325435a1ad5761c84c06b8b653856e296 (patch)
tree8627cb86b978ea9c4252ef405dd822852aafbe84
parent6f1bdfffb77ba1c95f46e16a7eeff3cfaf2f2f1f (diff)
downloadcoreclr-bb62718325435a1ad5761c84c06b8b653856e296.tar.gz
coreclr-bb62718325435a1ad5761c84c06b8b653856e296.tar.bz2
coreclr-bb62718325435a1ad5761c84c06b8b653856e296.zip
JIT: modify how jit determines when to update a type (#22618)
For single-def locals, the type of a reference seen at the assignment to the local may be a more specific type than the local's declared type. If so the jit would prefer to use the assignment type to describe the local's value, as this will lead to better optimization. For instance in ``` object x = "a string"; // only assignment to x ``` the jit can optimize better if it models the type of `x` as `string`. Instead of relying on `mergeClasses` plus some jit-side screening to decide if the assignment type is a more specific type, implement a new jit interface method `isMoreSpecificType` that tries to answer this question more directly. Added a test case with type equivalence that hit asserts. Closes #22583.
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h5
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/lwmlist.h1
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp35
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.h7
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp11
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp7
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp6
-rw-r--r--src/ToolBox/superpmi/superpmi/icorjitinfo.cpp9
-rw-r--r--src/inc/corinfo.h22
-rw-r--r--src/jit/lclvars.cpp26
-rw-r--r--src/vm/jitinterface.cpp64
-rw-r--r--src/vm/jitinterface.h7
-rw-r--r--src/zap/zapinfo.cpp7
-rw-r--r--src/zap/zapinfo.h3
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.cs21
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.csproj43
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_22583/base.cs11
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_22583/base.csproj35
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.cs12
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.csproj41
20 files changed, 339 insertions, 34 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
index 223e1d89c7..fe4ed6a5ff 100644
--- a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
+++ b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
@@ -461,9 +461,12 @@ TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLA
// equal, or the comparison needs to be resolved at runtime.
TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
index d034bdcd8f..4fe06d2fd7 100644
--- a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
+++ b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
@@ -151,6 +151,7 @@ LWM(IsValidToken, DLD, DWORD)
LWM(IsValueClass, DWORDLONG, DWORD)
LWM(IsWriteBarrierHelperRequired, DWORDLONG, DWORD)
LWM(MergeClasses, DLDL, DWORDLONG)
+LWM(IsMoreSpecificType, DLDL, DWORD)
LWM(PInvokeMarshalingRequired, PInvokeMarshalingRequiredValue, DWORD)
LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue)
LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethod, DWORDLONG)
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index 5f4861d544..96ecb8d5f1 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -5318,6 +5318,41 @@ CORINFO_CLASS_HANDLE MethodContext::repMergeClasses(CORINFO_CLASS_HANDLE cls1, C
return (CORINFO_CLASS_HANDLE)value;
}
+void MethodContext::recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, BOOL result)
+{
+ if (IsMoreSpecificType == nullptr)
+ IsMoreSpecificType = new LightWeightMap<DLDL, DWORD>();
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ IsMoreSpecificType->Add(key, (DWORD)result);
+}
+void MethodContext::dmpIsMoreSpecificType(DLDL key, DWORD value)
+{
+ printf("IsMoreSpecificType key cls1-%016llX cls2-%016llX, value %u", key.A, key.B, value);
+}
+BOOL MethodContext::repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+ DWORD value;
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ AssertCodeMsg(IsMoreSpecificType->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX", (DWORDLONG)cls1,
+ (DWORDLONG)cls2);
+
+ value = IsMoreSpecificType->Get(key);
+
+ return (BOOL)value;
+}
+
void MethodContext::recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result)
{
if (GetCookieForPInvokeCalliSig == nullptr)
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
index 7e20c2bc1a..8de6a070f0 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
@@ -1204,6 +1204,10 @@ public:
void dmpMergeClasses(DLDL key, DWORDLONG value);
CORINFO_CLASS_HANDLE repMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+ void recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, BOOL result);
+ void dmpIsMoreSpecificType(DLDL key, DWORD value);
+ BOOL repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
void recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result);
void dmpGetCookieForPInvokeCalliSig(const GetCookieForPInvokeCalliSigValue& key, DLDL value);
LPVOID repGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection);
@@ -1348,7 +1352,7 @@ private:
};
// ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 173
+// Highest packet number: 174
// *************************************************************************************
enum mcPackets
{
@@ -1494,6 +1498,7 @@ enum mcPackets
Packet_IsValueClass = 105,
Packet_IsWriteBarrierHelperRequired = 106,
Packet_MergeClasses = 107,
+ Packet_IsMoreSpecificType = 174, // Added 2/14/2019
Packet_PInvokeMarshalingRequired = 108,
Packet_ResolveToken = 109,
Packet_ResolveVirtualMethod = 160, // Added 2/13/17
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 44b08dfe71..79071488a7 100644
--- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -987,7 +987,7 @@ TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE
return temp;
}
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
mc->cr->AddCall("mergeClasses");
@@ -996,6 +996,15 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, C
return temp;
}
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mc->cr->AddCall("isMoreSpecificType");
+ BOOL temp = original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
+ mc->recIsMoreSpecificType(cls1, cls2, temp);
+ return temp;
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 5fe6bc367b..044f1f2c4a 100644
--- a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -776,6 +776,13 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, C
return original_ICorJitInfo->mergeClasses(cls1, cls2);
}
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mcs->AddCall("isMoreSpecificType");
+ return original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 0455503658..49dd2423e1 100644
--- a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -692,6 +692,12 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, C
return original_ICorJitInfo->mergeClasses(cls1, cls2);
}
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ return original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
index bca4cb04fa..377ad1d054 100644
--- a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
@@ -826,13 +826,20 @@ TypeCompareState MyICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORI
return jitInstance->mc->repCompareTypesForEquality(cls1, cls2);
}
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE MyICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
jitInstance->mc->cr->AddCall("mergeClasses");
return jitInstance->mc->repMergeClasses(cls1, cls2);
}
+// Returns true if cls2 is known to be a more specific type than cls1
+BOOL MyICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ jitInstance->mc->cr->AddCall("isMoreSpecificType");
+ return jitInstance->mc->repIsMoreSpecificType(cls1, cls2);
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index 852bf3168b..412a6cee78 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use
#define SELECTANY extern __declspec(selectany)
#endif
-SELECTANY const GUID JITEEVersionIdentifier = { /* 8903fe7b-a82a-4e2e-b691-f58430b485d1 */
- 0x8903fe7b,
- 0xa82a,
- 0x4e2e,
- {0xb6, 0x91, 0xf5, 0x84, 0x30, 0xb4, 0x85, 0xd1}
+SELECTANY const GUID JITEEVersionIdentifier = { /* d609bed1-7831-49fc-bd49-b6f054dd4d46 */
+ 0xd609bed1,
+ 0x7831,
+ 0x49fc,
+ {0xbd, 0x49, 0xb6, 0xf0, 0x54, 0xdd, 0x4d, 0x46}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2592,12 +2592,22 @@ public:
CORINFO_CLASS_HANDLE cls2
) = 0;
- // returns is the intersection of cls1 and cls2.
+ // Returns the intersection of cls1 and cls2.
virtual CORINFO_CLASS_HANDLE mergeClasses(
CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2
) = 0;
+ // Returns true if cls2 is known to be a more specific type
+ // than cls1 (a subtype or more restrictive shared type)
+ // for purposes of jit type tracking. This is a hint to the
+ // jit for optimization; it does not have correctness
+ // implications.
+ virtual BOOL isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ ) = 0;
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index 473ade919d..c691480827 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -2704,27 +2704,7 @@ void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool
// updating exact classes.
if (!varDsc->lvClassIsExact && isNewClass)
{
- // Todo: improve this analysis by adding a new jit interface method
- DWORD newAttrs = info.compCompHnd->getClassAttribs(clsHnd);
- DWORD oldAttrs = info.compCompHnd->getClassAttribs(varDsc->lvClassHnd);
-
- // Avoid funny things with __Canon by only merging if both shared or both unshared
- if ((newAttrs & CORINFO_FLG_SHAREDINST) == (oldAttrs & CORINFO_FLG_SHAREDINST))
- {
- // If we merge types and we get back the old class, the new class is more
- // specific and we should update to it.
- CORINFO_CLASS_HANDLE mergeClass = info.compCompHnd->mergeClasses(clsHnd, varDsc->lvClassHnd);
-
- if (mergeClass == varDsc->lvClassHnd)
- {
- shouldUpdate = true;
- }
- }
- else if ((newAttrs & CORINFO_FLG_SHAREDINST) == 0)
- {
- // Update if we go from shared to unshared
- shouldUpdate = true;
- }
+ shouldUpdate = info.compCompHnd->isMoreSpecificType(varDsc->lvClassHnd, clsHnd);
}
// Else are we attempting to update exactness?
else if (isExact && !varDsc->lvClassIsExact && !isNewClass)
@@ -2736,9 +2716,9 @@ void Compiler::lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool
if (isNewClass || (isExact != varDsc->lvClassIsExact))
{
JITDUMP("\nlvaUpdateClass:%s Updating class for V%02u", shouldUpdate ? "" : " NOT", varNum);
- JITDUMP(" from(%p) %s%s", dspPtr(varDsc->lvClassHnd), info.compCompHnd->getClassName(varDsc->lvClassHnd),
+ JITDUMP(" from (%p) %s%s", dspPtr(varDsc->lvClassHnd), info.compCompHnd->getClassName(varDsc->lvClassHnd),
varDsc->lvClassIsExact ? " [exact]" : "");
- JITDUMP(" to(%p) %s%s\n", dspPtr(clsHnd), info.compCompHnd->getClassName(clsHnd), isExact ? " [exact]" : "");
+ JITDUMP(" to (%p) %s%s\n", dspPtr(clsHnd), info.compCompHnd->getClassName(clsHnd), isExact ? " [exact]" : "");
}
#endif // DEBUG
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index def08c629f..4df43fe86f 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -4706,7 +4706,7 @@ TypeCompareState CEEInfo::compareTypesForEquality(
}
/*********************************************************************/
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2)
@@ -4776,6 +4776,68 @@ CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
}
/*********************************************************************/
+static BOOL isMoreSpecificTypeHelper(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ TypeHandle hnd1 = TypeHandle(cls1);
+ TypeHandle hnd2 = TypeHandle(cls2);
+
+ // We can't really reason about equivalent types. Just
+ // assume the new type is not more specific.
+ if (hnd1.HasTypeEquivalence() || hnd2.HasTypeEquivalence())
+ {
+ return FALSE;
+ }
+
+ // If we have a mixture of shared and unshared types,
+ // consider the unshared type as more specific.
+ BOOL isHnd1CanonSubtype = hnd1.IsCanonicalSubtype();
+ BOOL isHnd2CanonSubtype = hnd2.IsCanonicalSubtype();
+ if (isHnd1CanonSubtype != isHnd2CanonSubtype)
+ {
+ // Only one of hnd1 and hnd2 is shared.
+ // hdn2 is more specific if hnd1 is the shared type.
+ return isHnd1CanonSubtype;
+ }
+
+ // Otherwise both types are either shared or not shared.
+ // Look for a common parent type.
+ TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(hnd1, hnd2);
+
+ // If the common parent is hnd1, then hnd2 is more specific.
+ return merged == hnd1;
+}
+
+// Returns true if cls2 is known to be a more specific type
+// than cls1 (a subtype or more restrictive shared type).
+BOOL CEEInfo::isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ BOOL result = FALSE;
+
+ JIT_TO_EE_TRANSITION();
+
+ result = isMoreSpecificTypeHelper(cls1, cls2);
+
+ EE_TO_JIT_TRANSITION();
+ return result;
+}
+
+/*********************************************************************/
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h
index c47123d324..fe7dd4a922 100644
--- a/src/vm/jitinterface.h
+++ b/src/vm/jitinterface.h
@@ -601,6 +601,13 @@ public:
CORINFO_CLASS_HANDLE cls2
);
+ // Returns true if cls2 is known to be a more specific type
+ // than cls1 (a subtype or more restrictive shared type).
+ BOOL isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ );
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp
index a56004a6b4..8a372828f0 100644
--- a/src/zap/zapinfo.cpp
+++ b/src/zap/zapinfo.cpp
@@ -3199,6 +3199,13 @@ CORINFO_CLASS_HANDLE ZapInfo::mergeClasses(
return m_pEEJitInfo->mergeClasses(cls1, cls2);
}
+BOOL ZapInfo::isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ return m_pEEJitInfo->isMoreSpecificType(cls1, cls2);
+}
+
BOOL ZapInfo::shouldEnforceCallvirtRestriction(
CORINFO_MODULE_HANDLE scopeHnd)
{
diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h
index eadefe8555..962bbdacd4 100644
--- a/src/zap/zapinfo.h
+++ b/src/zap/zapinfo.h
@@ -591,6 +591,9 @@ public:
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2);
+ BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2);
+
BOOL shouldEnforceCallvirtRestriction(CORINFO_MODULE_HANDLE scope);
CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls);
CorInfoType getChildType (CORINFO_CLASS_HANDLE clsHnd,
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.cs b/tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.cs
new file mode 100644
index 0000000000..dbd4c2b365
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+// Test case where a type-equvalent delegate is assigned
+
+class X
+{
+ static int F() => 3;
+
+ public static int Main()
+ {
+ XD x = F;
+ XD y = Lib.GetDelegate();
+ return x() + y() + 64;
+ }
+
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.csproj
new file mode 100644
index 0000000000..b65453fbe4
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_22583/GitHub_22583.csproj
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <!-- Test unsupported outside of windows (type equivalence) -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="GitHub_22583.cs" />
+ <ProjectReference Include="lib.csproj" />
+ <ProjectReference Include="base.csproj">
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_22583/base.cs b/tests/src/JIT/Regression/JitBlue/GitHub_22583/base.cs
new file mode 100644
index 0000000000..36d20e370f
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_22583/base.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.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+[assembly:Guid("a95d54f0-5e7c-46e0-a15f-59ab08d41c38")]
+[assembly:ImportedFromTypeLib("test")]
+
+public delegate int XD();
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_22583/base.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_22583/base.csproj
new file mode 100644
index 0000000000..d6055b3e16
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_22583/base.csproj
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <GenerateRunScript>false</GenerateRunScript>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="base.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.cs b/tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.cs
new file mode 100644
index 0000000000..ef9f734dea
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.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.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+public class Lib
+{
+ public static int F() => 33;
+
+ public static XD GetDelegate() => F;
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.csproj
new file mode 100644
index 0000000000..ac7f8f6b84
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_22583/lib.csproj
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <GenerateRunScript>false</GenerateRunScript>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="lib.cs" />
+ <ProjectReference Include="base.csproj">
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project> \ No newline at end of file