From 61a278fdb44c5796dff07531cd585f4474c0e0ff Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 21:32:01 +0900
Subject: [PATCH 01/33] Devirtualize virtual methods that require an
 instantiating stub

---
 src/coreclr/vm/jitinterface.cpp | 41 ++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index c0ec22f3e75a8f..4d167fb4a33624 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8762,15 +8762,6 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP;
             return false;
         }
-
-        // If we devirtualized into a default interface method on a generic type, we should actually return an
-        // instantiating stub but this is not happening.
-        // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588
-        if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation())
-        {
-            info->detail = CORINFO_DEVIRTUALIZATION_FAILED_DIM;
-            return false;
-        }
     }
     else
     {
@@ -8833,12 +8824,13 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     bool isArray = false;
     bool isGenericVirtual = false;
 
-    if (pApproxMT->IsInterface())
+    if (pExactMT->IsInterface())
     {
-        // As noted above, we can't yet handle generic interfaces
-        // with default methods.
-        _ASSERTE(!pDevirtMD->HasClassInstantiation());
-
+        if (pDevirtMD->HasClassInstantiation())
+        {
+            info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE)pExactMT;
+            info->instParamLookup.constLookup.accessType = IAT_VALUE;
+        }
     }
     else if (pBaseMT->IsInterface() && pObjMT->IsArray())
     {
@@ -8855,10 +8847,27 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
         MethodDesc* pPrimaryMD = pDevirtMD;
         pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
             pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), true);
+
         if (pDevirtMD->IsSharedByGenericMethodInstantiations())
         {
-            info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-            return false;
+            pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
+                pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), false);
+
+            if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetClassInstantiation()))
+            {
+                // If we end up with a shared MethodTable that is not exact,
+                // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
+                info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+            }
+
+            const bool requiresRuntimeLookup = TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetMethodInstantiation());
+            if (requiresRuntimeLookup)
+            {
+                // TODO: Support for runtime lookup
+                info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+            }
         }
 
         isGenericVirtual = true;

From f01f4f478d436f287bae4cb753ddcccb8bc4b4f7 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 21:43:40 +0900
Subject: [PATCH 02/33] R2R support

---
 .../Compiler/DevirtualizationManager.cs       | 16 ++++---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 43 ++++++++++++++++++-
 .../ReadyToRun/DevirtualizationManager.cs     |  4 +-
 3 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
index ac544ed02e3fea..1fb376fcb91274 100644
--- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
+++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
@@ -148,6 +148,14 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
                                 return null;
 
                             case DefaultInterfaceMethodResolution.DefaultImplementation:
+#if READYTORUN
+                                if (declMethod != defaultInterfaceDispatchDeclMethod)
+                                {
+                                    // Fail for variant default interface dispatch
+                                    devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
+                                    return null;
+                                }
+#else
                                 if (dimMethod.OwningType.HasInstantiation || (declMethod != defaultInterfaceDispatchDeclMethod))
                                 {
                                     // If we devirtualized into a default interface method on a generic type, we should actually return an
@@ -158,6 +166,7 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
                                     devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
                                     return null;
                                 }
+#endif
                                 else
                                 {
                                     impl = dimMethod;
@@ -219,13 +228,6 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
                 }
             }
 
-            if (impl != null && impl.HasInstantiation && impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific))
-            {
-                // We don't support devirtualization of shared generic virtual methods yet.
-                devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-                impl = null;
-            }
-
             return impl;
         }
 
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 5fc46db5a8978b..9ceed25708ae2e 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1482,6 +1482,47 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN);
             }
 
+
+            bool isArrayInterfaceDevirtualization = objType.IsArray && decl.OwningType.IsInterface;
+            bool isGenericVirtual = decl.HasInstantiation;
+            bool isGenericDim = impl.OwningType.IsInterface && !impl.IsAbstract && impl.RequiresInstMethodTableArg();
+
+            if ((isGenericVirtual || isGenericDim) && originalImpl.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
+            {
+                // If we end up with a shared MethodTable that is not exact,
+                // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
+                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+            }
+
+            if (isGenericDim)
+            {
+#if READYTORUN
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
+#else
+                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+#endif
+            }
+            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsCanonicalMethod(CanonicalFormKind.Any))
+            {
+                bool requiresRuntimeLookup = originalImpl.IsSharedByGenericInstantiations;
+                if (requiresRuntimeLookup)
+                {
+                    // TODO: Support for runtime lookup
+                    info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                    return false;
+                }
+#if READYTORUN
+                MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodHandle, originalImplWithToken));
+#else
+                // TODO: Implement array interface and generic virtual method devirtualization constant lookup for NativeAOT
+                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+#endif
+            }
+
 #if READYTORUN
             // Testing has not shown that concerns about virtual matching are significant
             // Only generate verification for builds with the stress mode enabled
@@ -1496,7 +1537,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 #endif
             info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS;
             info->devirtualizedMethod = ObjectToHandle(impl);
-            info->tokenLookupContext = contextFromType(owningType);
+            info->tokenLookupContext = (isArrayInterfaceDevirtualization || isGenericVirtual) ? contextFromMethod(originalImpl) : contextFromType(owningType);
 
             return true;
 
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs
index 7d0275ff2eaaee..e6e329e5b32663 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs
@@ -45,9 +45,7 @@ protected override MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefTyp
             //
             // Result method checking
             // 1. Ensure that the resolved result versions with the code, or is the decl method
-            // 2. Devirtualizing to a default interface method is not currently considered to be useful, and how to check for version
-            //    resilience has not yet been analyzed.
-            // 3. When checking that the resolved result versions with the code, validate that all of the types
+            // 2. When checking that the resolved result versions with the code, validate that all of the types
             //    From implType to the owning type of resolved result method also version with the code.
 
             bool declMethodCheckFailed;

From b42c29153a94e34f1886e406e3ce396139a203f4 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 22:30:16 +0900
Subject: [PATCH 03/33] Bail shared MT for generic DIM as well

---
 src/coreclr/vm/jitinterface.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 4d167fb4a33624..5e7d79fefc700b 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8828,6 +8828,14 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     {
         if (pDevirtMD->HasClassInstantiation())
         {
+            if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetClassInstantiation()))
+            {
+                // If we end up with a shared MethodTable that is not exact,
+                // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
+                info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+            }
+
             info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE)pExactMT;
             info->instParamLookup.constLookup.accessType = IAT_VALUE;
         }

From b96fc2e697f9f5f577707251d2b5ec6b7c0b5db5 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 22:48:30 +0900
Subject: [PATCH 04/33] Stop returning an instantiating stub

---
 src/coreclr/vm/jitinterface.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 5e7d79fefc700b..beb317e730e876 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8890,12 +8890,13 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
         }
 
         info->tokenLookupContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD);
-        pDevirtMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
     }
     else
     {
         info->tokenLookupContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
     }
+    
+    pDevirtMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
 
     // Success! Pass back the results.
     //

From de840c22fceb7c99f134a3b2739e93619704f77f Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:15:16 +0900
Subject: [PATCH 05/33] Nit

---
 src/coreclr/vm/jitinterface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index beb317e730e876..a2f0e472bcc7b6 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8824,7 +8824,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     bool isArray = false;
     bool isGenericVirtual = false;
 
-    if (pExactMT->IsInterface())
+    if (pApproxMT->IsInterface())
     {
         if (pDevirtMD->HasClassInstantiation())
         {

From 181e88ee4a73bc99ae31b7497191f4c559a92a16 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:17:46 +0900
Subject: [PATCH 06/33] Nit 2

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 9ceed25708ae2e..30ba55c7869a07 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1500,7 +1500,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 #if READYTORUN
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
 #else
-                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
                 return false;
 #endif
             }

From 9331cc106570d5071f7a265ce8c8fee7697d54af Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:18:31 +0900
Subject: [PATCH 07/33] Remove redundant empty line

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 30ba55c7869a07..a80328f469daae 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1482,7 +1482,6 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN);
             }
 
-
             bool isArrayInterfaceDevirtualization = objType.IsArray && decl.OwningType.IsInterface;
             bool isGenericVirtual = decl.HasInstantiation;
             bool isGenericDim = impl.OwningType.IsInterface && !impl.IsAbstract && impl.RequiresInstMethodTableArg();

From f6356869b188d30dfd72eda84f3f1f57984c43ae Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:28:35 +0900
Subject: [PATCH 08/33] Generic DIM devirt for NativeAOT

---
 .../Common/Compiler/DevirtualizationManager.cs      | 13 -------------
 .../tools/Common/JitInterface/CorInfoImpl.cs        |  2 +-
 2 files changed, 1 insertion(+), 14 deletions(-)

diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
index 1fb376fcb91274..a8a83cedec3bb5 100644
--- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
+++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
@@ -148,25 +148,12 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
                                 return null;
 
                             case DefaultInterfaceMethodResolution.DefaultImplementation:
-#if READYTORUN
                                 if (declMethod != defaultInterfaceDispatchDeclMethod)
                                 {
                                     // Fail for variant default interface dispatch
                                     devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
                                     return null;
                                 }
-#else
-                                if (dimMethod.OwningType.HasInstantiation || (declMethod != defaultInterfaceDispatchDeclMethod))
-                                {
-                                    // If we devirtualized into a default interface method on a generic type, we should actually return an
-                                    // instantiating stub but this is not happening.
-                                    // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588
-
-                                    // In addition, we fail here for variant default interface dispatch
-                                    devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
-                                    return null;
-                                }
-#endif
                                 else
                                 {
                                     impl = dimMethod;
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index a80328f469daae..4cb789c2e59af1 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1499,7 +1499,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 #if READYTORUN
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
 #else
-                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM;
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
                 return false;
 #endif
             }

From 5da42c52152ebd6b2bd1d6309f84581d06199a2b Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:29:05 +0900
Subject: [PATCH 09/33] Meh

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 4cb789c2e59af1..2adffdc85918c9 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1500,7 +1500,6 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
 #else
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
-                return false;
 #endif
             }
             else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsCanonicalMethod(CanonicalFormKind.Any))

From 66c8d6a5bff3a34958d1b8edcc2fb4370260ec49 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:39:53 +0900
Subject: [PATCH 10/33] More NativeAOT support

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 4 +---
 src/coreclr/vm/jitinterface.cpp                      | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 2adffdc85918c9..baa36c4f0e56e5 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1515,9 +1515,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodHandle, originalImplWithToken));
 #else
-                // TODO: Implement array interface and generic virtual method devirtualization constant lookup for NativeAOT
-                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-                return false;
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
 #endif
             }
 
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index a2f0e472bcc7b6..b104699e6c7600 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8895,7 +8895,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     {
         info->tokenLookupContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
     }
-    
+
     pDevirtMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
 
     // Success! Pass back the results.

From 152c44a903f4cab79f15c5ec4c1088c6cc3012d6 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:49:54 +0900
Subject: [PATCH 11/33] Address an assertion

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  4 ++--
 .../MethodDesc.RuntimeDetermined.cs           | 20 +++++++++++++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index baa36c4f0e56e5..21c978b9de52c5 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1502,9 +1502,9 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
 #endif
             }
-            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsCanonicalMethod(CanonicalFormKind.Any))
+            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsMethodSharedByGenericInstantiations)
             {
-                bool requiresRuntimeLookup = originalImpl.IsSharedByGenericInstantiations;
+                bool requiresRuntimeLookup = originalImpl.IsMethodSharedByGenericInstantiations;
                 if (requiresRuntimeLookup)
                 {
                     // TODO: Support for runtime lookup
diff --git a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
index 2a66359448f0a4..624e7e44b35a5b 100644
--- a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
+++ b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
@@ -69,6 +69,26 @@ public bool IsSharedByGenericInstantiations
             }
         }
 
+        /// <summary>
+        /// Gets a value indicating whether this is a shared method body.
+        /// Similar to <see cref="IsSharedByGenericInstantiations"/> but this doesn't consider the owning type's generic instantiation.
+        /// </summary>
+        public bool IsMethodSharedByGenericInstantiations
+        {
+            get
+            {
+                foreach (TypeDesc type in Instantiation)
+                {
+                    if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
+                    {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+        }
+
         /// <summary>
         /// Gets a value indicating whether this is a canonical method that will only become concrete
         /// at runtime (after supplying the generic context).

From 466ba2c16d9511eeaa051cf8ca0f8018c12c0f76 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 28 May 2026 23:50:36 +0900
Subject: [PATCH 12/33] Use IsSharedByGenericMethodInstantiations

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs          | 4 ++--
 .../RuntimeDetermined/MethodDesc.RuntimeDetermined.cs         | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 21c978b9de52c5..45174412090d75 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1502,9 +1502,9 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
 #endif
             }
-            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsMethodSharedByGenericInstantiations)
+            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsSharedByGenericMethodInstantiations)
             {
-                bool requiresRuntimeLookup = originalImpl.IsMethodSharedByGenericInstantiations;
+                bool requiresRuntimeLookup = originalImpl.IsSharedByGenericMethodInstantiations;
                 if (requiresRuntimeLookup)
                 {
                     // TODO: Support for runtime lookup
diff --git a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
index 624e7e44b35a5b..528dac156da9a9 100644
--- a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
+++ b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
@@ -73,7 +73,7 @@ public bool IsSharedByGenericInstantiations
         /// Gets a value indicating whether this is a shared method body.
         /// Similar to <see cref="IsSharedByGenericInstantiations"/> but this doesn't consider the owning type's generic instantiation.
         /// </summary>
-        public bool IsMethodSharedByGenericInstantiations
+        public bool IsSharedByGenericMethodInstantiations
         {
             get
             {

From dca1834326efd3835f3e6ff998ce4c2125bd3728 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Fri, 29 May 2026 01:06:36 +0900
Subject: [PATCH 13/33] Add a couple of tests

---
 .../devirtualization/github39419.cs           | 36 +++++++++++++++++++
 .../devirtualization/github39419.csproj       | 11 ++++++
 .../devirtualization/inline.cs                | 26 ++++++++++++++
 .../devirtualization/inline.csproj            | 11 ++++++
 .../devirtualization/simple.cs                | 31 ++++++++++++++++
 .../devirtualization/simple.csproj            | 11 ++++++
 .../devirtualization/singlenongeneric.cs      | 24 +++++++++++++
 .../devirtualization/singlenongeneric.csproj  | 11 ++++++
 .../devirtualization/singleoverriding.cs      | 25 +++++++++++++
 .../devirtualization/singleoverriding.csproj  | 11 ++++++
 .../singleoverridinggeneric.cs                | 25 +++++++++++++
 .../singleoverridinggeneric.csproj            | 11 ++++++
 .../devirtualization/singleoverstruct.cs      | 24 +++++++++++++
 .../devirtualization/singleoverstruct.csproj  | 11 ++++++
 .../devirtualization/singlevaluetypenondim.cs | 25 +++++++++++++
 .../singlevaluetypenondim.csproj              | 11 ++++++
 .../devirtualization/singlevariance.cs        | 24 +++++++++++++
 .../devirtualization/singlevariance.csproj    | 11 ++++++
 .../devirtualization/snondimstruct.cs         | 22 ++++++++++++
 .../devirtualization/snondimstruct.csproj     | 11 ++++++
 .../devirtualization/staticshared.cs          | 19 ++++++++++
 .../devirtualization/staticshared.csproj      | 11 ++++++
 .../devirtualization/structs.cs               | 31 ++++++++++++++++
 .../devirtualization/structs.csproj           | 11 ++++++
 24 files changed, 444 insertions(+)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.cs
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj

diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.cs
new file mode 100644
index 00000000000000..8a611b3fbef284
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface IM<T>
+{
+    bool UseDefaultM { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; }
+    ValueTask M(T instance) => throw new NotImplementedException("M must be implemented if UseDefaultM is false");
+    static ValueTask DefaultM(T instance)
+    {
+        return default;
+    }
+}
+
+struct M : IM<int> { }
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var m = new M();
+        if (((IM<int>)m).UseDefaultM)
+        {
+            IM<int>.DefaultM(42);
+            return;
+        }
+        else
+        {
+            ((IM<int>)m).M(42);
+        }
+        throw new UnreachableException();
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj
new file mode 100644
index 00000000000000..6eeef117cf6b22
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="github39419.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.cs
new file mode 100644
index 00000000000000..c43a13315f0bac
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T> where T : IComparable<T>
+{
+    T GetAt(int i, T[] tx) => tx[i];
+}
+
+class C : I<string>
+{
+}
+
+public static class Program
+{
+    private static string[] tx = new string[] { "test" };
+
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        I<string> c = new C();
+        var dcs = c.GetAt(0, tx);
+        Assert.Equal("test", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj
new file mode 100644
index 00000000000000..b8a4a14ab89dab
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="inline.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.cs
new file mode 100644
index 00000000000000..0d96d46bd09252
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T>
+{
+    string DefaultTypeOf() => typeof(T).Name;
+}
+
+class Dummy { }
+
+class C : I<string>, I<object>, I<Dummy>
+{
+    string I<Dummy>.DefaultTypeOf() => "C.Dummy";
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("String", dcs);
+        var dos = ((I<object>)c).DefaultTypeOf();
+        Assert.Equal("Object", dos);
+        var dds = ((I<Dummy>)c).DefaultTypeOf();
+        Assert.Equal("C.Dummy", dds);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj
new file mode 100644
index 00000000000000..c0b27ba716c988
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="simple.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.cs
new file mode 100644
index 00000000000000..4deff94ccc5e94
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I
+{
+    string DefaultTypeOf() => typeof(string).Name;
+}
+
+class C : I
+{
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C();
+        var dcs = ((I)c).DefaultTypeOf();
+        Assert.Equal("String", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj
new file mode 100644
index 00000000000000..e2b70bcd7df723
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="singlenongeneric.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.cs
new file mode 100644
index 00000000000000..b2bb95f36434e1
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T>
+{
+    string DefaultTypeOf() => typeof(T).Name;
+}
+
+class C : I<string>
+{
+    public string DefaultTypeOf() => "C.String";
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("C.String", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj
new file mode 100644
index 00000000000000..f4f4302b148d01
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="singleoverriding.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.cs
new file mode 100644
index 00000000000000..31d8ec3549d629
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T>
+{
+    string DefaultTypeOf() => typeof(T).Name;
+}
+
+class C<T> : I<T>
+{
+    public string DefaultTypeOf() => "C." + typeof(T).Name;
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C<string>();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("C.String", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj
new file mode 100644
index 00000000000000..43285ec1c5afc7
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="singleoverridinggeneric.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.cs
new file mode 100644
index 00000000000000..91560c952ed6fd
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T>
+{
+    string DefaultTypeOf() => typeof(T).Name;
+}
+
+class C : I<int>
+{
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C();
+        var dcs = ((I<int>)c).DefaultTypeOf();
+        Assert.Equal("Int32", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj
new file mode 100644
index 00000000000000..e7d13cf00c25f6
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="singleoverstruct.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.cs
new file mode 100644
index 00000000000000..d401949fc5f577
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T>
+{
+    string DefaultTypeOf();
+}
+
+struct C<T> : I<T>
+{
+    public string DefaultTypeOf() => "C." + typeof(T).Name;
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C<string>();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("C.String", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj
new file mode 100644
index 00000000000000..8b76d9a4f2e880
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="singlevaluetypenondim.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.cs
new file mode 100644
index 00000000000000..114fcbcf8933d1
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<in T>
+{
+    string DefaultTypeOf() => typeof(T).Name;
+}
+
+class C : I<object>
+{
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("Object", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj
new file mode 100644
index 00000000000000..2bd3f7a79a671c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="singlevariance.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.cs
new file mode 100644
index 00000000000000..f384f31c02d756
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+
+struct C<T>
+{
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    public string DefaultTypeOf() => typeof(T).Name;
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C<string>();
+        var dcs = c.DefaultTypeOf();
+        Assert.Equal("String", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj
new file mode 100644
index 00000000000000..c7f805adcc4b03
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="snondimstruct.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.cs
new file mode 100644
index 00000000000000..f33c8b8aaf0fcd
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+class C<T>
+{
+    public static string DefaultTypeOf() => typeof(T).Name;
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var dcs = C<string>.DefaultTypeOf();
+        Assert.Equal("String", dcs);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj
new file mode 100644
index 00000000000000..1620cacc449e07
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="staticshared.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.cs
new file mode 100644
index 00000000000000..bbb79c7c3f0313
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+interface I<T>
+{
+    string DefaultTypeOf() => typeof(T).Name;
+}
+
+class Dummy { }
+
+struct C : I<string>, I<object>, I<Dummy>
+{
+    string I<Dummy>.DefaultTypeOf() => "C.Dummy";
+}
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        var c = new C();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("String", dcs);
+        var dos = ((I<object>)c).DefaultTypeOf();
+        Assert.Equal("Object", dos);
+        var dds = ((I<Dummy>)c).DefaultTypeOf();
+        Assert.Equal("C.Dummy", dds);
+    }
+}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj
new file mode 100644
index 00000000000000..79889f0c9b5077
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="structs.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>

From 2582ba6065e7b4c5056ed05c39d9329476e65c1e Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 00:07:51 +0900
Subject: [PATCH 14/33] Address test name collisions

---
 .../{github39419.cs => dim_devirt_github39419.cs}     |  0
 ...thub39419.csproj => dim_devirt_github39419.csproj} |  2 +-
 .../{inline.cs => dim_devirt_inline.cs}               |  0
 .../{inline.csproj => dim_devirt_inline.csproj}       |  2 +-
 .../{simple.cs => dim_devirt_simple.cs}               |  0
 .../{simple.csproj => dim_devirt_simple.csproj}       |  2 +-
 ...lenongeneric.cs => dim_devirt_singlenongeneric.cs} |  0
 ...eric.csproj => dim_devirt_singlenongeneric.csproj} |  2 +-
 ...leoverriding.cs => dim_devirt_singleoverriding.cs} |  0
 .../dim_devirt_singleoverriding.csproj                | 11 +++++++++++
 ...neric.cs => dim_devirt_singleoverridinggeneric.cs} |  0
 .../dim_devirt_singleoverridinggeneric.csproj         | 11 +++++++++++
 ...leoverstruct.cs => dim_devirt_singleoverstruct.cs} |  0
 .../dim_devirt_singleoverstruct.csproj                | 11 +++++++++++
 ...enondim.cs => dim_devirt_singlevaluetypenondim.cs} |  0
 .../dim_devirt_singlevaluetypenondim.csproj           | 11 +++++++++++
 ...singlevariance.cs => dim_devirt_singlevariance.cs} |  0
 .../devirtualization/dim_devirt_singlevariance.csproj | 11 +++++++++++
 .../{snondimstruct.cs => dim_devirt_snondimstruct.cs} |  0
 .../devirtualization/dim_devirt_snondimstruct.csproj  | 11 +++++++++++
 .../{staticshared.cs => dim_devirt_staticshared.cs}   |  0
 .../devirtualization/dim_devirt_staticshared.csproj   | 11 +++++++++++
 .../{structs.cs => dim_devirt_structs.cs}             |  0
 .../devirtualization/dim_devirt_structs.csproj        | 11 +++++++++++
 .../devirtualization/singleoverriding.csproj          | 11 -----------
 .../devirtualization/singleoverridinggeneric.csproj   | 11 -----------
 .../devirtualization/singleoverstruct.csproj          | 11 -----------
 .../devirtualization/singlevaluetypenondim.csproj     | 11 -----------
 .../devirtualization/singlevariance.csproj            | 11 -----------
 .../devirtualization/snondimstruct.csproj             | 11 -----------
 .../devirtualization/staticshared.csproj              | 11 -----------
 .../devirtualization/structs.csproj                   | 11 -----------
 32 files changed, 92 insertions(+), 92 deletions(-)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{github39419.cs => dim_devirt_github39419.cs} (100%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{github39419.csproj => dim_devirt_github39419.csproj} (82%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{inline.cs => dim_devirt_inline.cs} (100%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{inline.csproj => dim_devirt_inline.csproj} (82%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{simple.cs => dim_devirt_simple.cs} (100%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{simple.csproj => dim_devirt_simple.csproj} (82%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singlenongeneric.cs => dim_devirt_singlenongeneric.cs} (100%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singlenongeneric.csproj => dim_devirt_singlenongeneric.csproj} (82%)
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singleoverriding.cs => dim_devirt_singleoverriding.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singleoverridinggeneric.cs => dim_devirt_singleoverridinggeneric.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singleoverstruct.cs => dim_devirt_singleoverstruct.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singlevaluetypenondim.cs => dim_devirt_singlevaluetypenondim.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{singlevariance.cs => dim_devirt_singlevariance.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{snondimstruct.cs => dim_devirt_snondimstruct.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{staticshared.cs => dim_devirt_staticshared.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{structs.cs => dim_devirt_structs.cs} (100%)
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj

diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj
similarity index 82%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj
index 6eeef117cf6b22..30d4804022360c 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/github39419.csproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj
@@ -3,7 +3,7 @@
     <CLRTestPriority>1</CLRTestPriority>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="github39419.cs" />
+    <Compile Include="$(MSBuildProjectName).cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(TestLibraryProjectPath)" />
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj
similarity index 82%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj
index b8a4a14ab89dab..30d4804022360c 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/inline.csproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj
@@ -3,7 +3,7 @@
     <CLRTestPriority>1</CLRTestPriority>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="inline.cs" />
+    <Compile Include="$(MSBuildProjectName).cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(TestLibraryProjectPath)" />
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj
similarity index 82%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj
index c0b27ba716c988..30d4804022360c 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/simple.csproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj
@@ -3,7 +3,7 @@
     <CLRTestPriority>1</CLRTestPriority>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="simple.cs" />
+    <Compile Include="$(MSBuildProjectName).cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(TestLibraryProjectPath)" />
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj
similarity index 82%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj
index e2b70bcd7df723..30d4804022360c 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlenongeneric.csproj
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj
@@ -3,7 +3,7 @@
     <CLRTestPriority>1</CLRTestPriority>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="singlenongeneric.cs" />
+    <Compile Include="$(MSBuildProjectName).cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(TestLibraryProjectPath)" />
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.cs
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj
new file mode 100644
index 00000000000000..30d4804022360c
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <CLRTestPriority>1</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestLibraryProjectPath)" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj
deleted file mode 100644
index f4f4302b148d01..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverriding.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="singleoverriding.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj
deleted file mode 100644
index 43285ec1c5afc7..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverridinggeneric.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="singleoverridinggeneric.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj
deleted file mode 100644
index e7d13cf00c25f6..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singleoverstruct.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="singleoverstruct.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj
deleted file mode 100644
index 8b76d9a4f2e880..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevaluetypenondim.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="singlevaluetypenondim.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj
deleted file mode 100644
index 2bd3f7a79a671c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/singlevariance.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="singlevariance.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj
deleted file mode 100644
index c7f805adcc4b03..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/snondimstruct.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="snondimstruct.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj
deleted file mode 100644
index 1620cacc449e07..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/staticshared.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="staticshared.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj
deleted file mode 100644
index 79889f0c9b5077..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/structs.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="structs.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>

From 800aa20f25514f2ba0abb72d8c9bc9f06ac5371f Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 10:45:17 +0900
Subject: [PATCH 15/33] Fix crossgen2 not producing a const lookup

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  6 ++++--
 .../MethodDesc.RuntimeDetermined.cs           | 20 -------------------
 src/coreclr/vm/jitinterface.cpp               |  2 ++
 3 files changed, 6 insertions(+), 22 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 45174412090d75..56aee7a65ce7d0 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1502,9 +1502,11 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
 #endif
             }
-            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsSharedByGenericMethodInstantiations)
+            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsSharedByGenericInstantiations)
             {
-                bool requiresRuntimeLookup = originalImpl.IsSharedByGenericMethodInstantiations;
+                // We are dealing with a generic virtual method whose owning type is exact.
+                // If the method is not exact, a runtime lookup would be required.
+                bool requiresRuntimeLookup = originalImpl.IsSharedByGenericInstantiations;
                 if (requiresRuntimeLookup)
                 {
                     // TODO: Support for runtime lookup
diff --git a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
index 528dac156da9a9..2a66359448f0a4 100644
--- a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
+++ b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
@@ -69,26 +69,6 @@ public bool IsSharedByGenericInstantiations
             }
         }
 
-        /// <summary>
-        /// Gets a value indicating whether this is a shared method body.
-        /// Similar to <see cref="IsSharedByGenericInstantiations"/> but this doesn't consider the owning type's generic instantiation.
-        /// </summary>
-        public bool IsSharedByGenericMethodInstantiations
-        {
-            get
-            {
-                foreach (TypeDesc type in Instantiation)
-                {
-                    if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
-                    {
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-        }
-
         /// <summary>
         /// Gets a value indicating whether this is a canonical method that will only become concrete
         /// at runtime (after supplying the generic context).
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index b104699e6c7600..7c629b79b28ec7 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8869,6 +8869,8 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
                 return false;
             }
 
+            // We are dealing with a generic virtual method whose owning type is exact.
+            // If the method is not exact, a runtime lookup would be required.
             const bool requiresRuntimeLookup = TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetMethodInstantiation());
             if (requiresRuntimeLookup)
             {

From 31ff0062a401a9b8ad938337550e4390c3cae10e Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 11:47:14 +0900
Subject: [PATCH 16/33] Fix NativeAOT build

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 56aee7a65ce7d0..ffc98c161a4958 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1517,7 +1517,14 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodHandle, originalImplWithToken));
 #else
-                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
+                if (originalImpl.HasInstantiation)
+                {
+                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
+                }
+                else
+                {
+                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
+                }
 #endif
             }
 

From 645e5dd18bd75f48b1d663de389789f33e9545f8 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 12:05:19 +0900
Subject: [PATCH 17/33] Pass a type dictionary fixup when the method doesn't
 have an instantiation

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 23 ++++++++++++-------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index ffc98c161a4958..8a80145504b039 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1513,25 +1513,32 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                     info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
                     return false;
                 }
-#if READYTORUN
-                MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
-                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodHandle, originalImplWithToken));
-#else
+
                 if (originalImpl.HasInstantiation)
                 {
+#if READYTORUN
+                    MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
+                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodDictionary, originalImplWithToken));
+
+#else
                     info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
+#endif
                 }
                 else
                 {
+#if READYTORUN
+                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
+
+#else
                     info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
-                }
 #endif
+                }
             }
 
 #if READYTORUN
-            // Testing has not shown that concerns about virtual matching are significant
-            // Only generate verification for builds with the stress mode enabled
-            if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+                // Testing has not shown that concerns about virtual matching are significant
+                // Only generate verification for builds with the stress mode enabled
+                if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
             {
                 if (!methodWithTokenDecl.Method.OwningType.IsValueType || !methodWithTokenImpl.Method.OwningType.IsValueType)
                 {

From 1f2aacc4b06b4540fdceecd6687d4d15addb1e2e Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 12:08:05 +0900
Subject: [PATCH 18/33] Nit

---
 src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 8a80145504b039..d6e25bf62d4b65 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1536,9 +1536,9 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
             }
 
 #if READYTORUN
-                // Testing has not shown that concerns about virtual matching are significant
-                // Only generate verification for builds with the stress mode enabled
-                if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+            // Testing has not shown that concerns about virtual matching are significant
+            // Only generate verification for builds with the stress mode enabled
+            if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
             {
                 if (!methodWithTokenDecl.Method.OwningType.IsValueType || !methodWithTokenImpl.Method.OwningType.IsValueType)
                 {

From cad1140934ecc10f5fe95323214795745a5c79a4 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 14:04:53 +0900
Subject: [PATCH 19/33] More fixes to AOT

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  2 +-
 .../MethodDesc.RuntimeDetermined.cs           | 20 +++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index d6e25bf62d4b65..7108e3a791e76b 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1514,7 +1514,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                     return false;
                 }
 
-                if (originalImpl.HasInstantiation)
+                if (impl.IsSharedByGenericMethodInstantiations)
                 {
 #if READYTORUN
                     MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
diff --git a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
index 2a66359448f0a4..528dac156da9a9 100644
--- a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
+++ b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
@@ -69,6 +69,26 @@ public bool IsSharedByGenericInstantiations
             }
         }
 
+        /// <summary>
+        /// Gets a value indicating whether this is a shared method body.
+        /// Similar to <see cref="IsSharedByGenericInstantiations"/> but this doesn't consider the owning type's generic instantiation.
+        /// </summary>
+        public bool IsSharedByGenericMethodInstantiations
+        {
+            get
+            {
+                foreach (TypeDesc type in Instantiation)
+                {
+                    if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
+                    {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+        }
+
         /// <summary>
         /// Gets a value indicating whether this is a canonical method that will only become concrete
         /// at runtime (after supplying the generic context).

From 0c7102a6ee686d628c6d1a52471ebb60b40fa881 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 14:15:40 +0900
Subject: [PATCH 20/33] Use a better helper

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  2 +-
 .../MethodDesc.RuntimeDetermined.cs           | 20 -------------------
 2 files changed, 1 insertion(+), 21 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 7108e3a791e76b..e72d3ff5996d8c 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1514,7 +1514,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                     return false;
                 }
 
-                if (impl.IsSharedByGenericMethodInstantiations)
+                if (impl.RequiresInstMethodDescArg())
                 {
 #if READYTORUN
                     MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
diff --git a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
index 528dac156da9a9..2a66359448f0a4 100644
--- a/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
+++ b/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs
@@ -69,26 +69,6 @@ public bool IsSharedByGenericInstantiations
             }
         }
 
-        /// <summary>
-        /// Gets a value indicating whether this is a shared method body.
-        /// Similar to <see cref="IsSharedByGenericInstantiations"/> but this doesn't consider the owning type's generic instantiation.
-        /// </summary>
-        public bool IsSharedByGenericMethodInstantiations
-        {
-            get
-            {
-                foreach (TypeDesc type in Instantiation)
-                {
-                    if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
-                    {
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-        }
-
         /// <summary>
         /// Gets a value indicating whether this is a canonical method that will only become concrete
         /// at runtime (after supplying the generic context).

From 8f0275089389d21a66355b46b8417f1cba3303ac Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 14:27:37 +0900
Subject: [PATCH 21/33] Minor refactor

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 57 +++++++------------
 1 file changed, 21 insertions(+), 36 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index e72d3ff5996d8c..1b9b130b489e24 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1482,57 +1482,42 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN);
             }
 
-            bool isArrayInterfaceDevirtualization = objType.IsArray && decl.OwningType.IsInterface;
-            bool isGenericVirtual = decl.HasInstantiation;
-            bool isGenericDim = impl.OwningType.IsInterface && !impl.IsAbstract && impl.RequiresInstMethodTableArg();
-
-            if ((isGenericVirtual || isGenericDim) && originalImpl.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
+            if (!impl.AcquiresInstMethodTableFromThis())
             {
-                // If we end up with a shared MethodTable that is not exact,
-                // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
-                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-                return false;
-            }
+                if (originalImpl.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
+                {
+                    // If we end up with a shared MethodTable that is not exact,
+                    // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
+                    info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                    return false;
+                }
 
-            if (isGenericDim)
-            {
-#if READYTORUN
-                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
-#else
-                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
-#endif
-            }
-            else if ((isArrayInterfaceDevirtualization || isGenericVirtual) && impl.IsSharedByGenericInstantiations)
-            {
-                // We are dealing with a generic virtual method whose owning type is exact.
-                // If the method is not exact, a runtime lookup would be required.
-                bool requiresRuntimeLookup = originalImpl.IsSharedByGenericInstantiations;
-                if (requiresRuntimeLookup)
+                if (originalImpl.IsSharedByGenericInstantiations)
                 {
                     // TODO: Support for runtime lookup
                     info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
                     return false;
                 }
+            }
 
-                if (impl.RequiresInstMethodDescArg())
-                {
+            if (impl.RequiresInstMethodDescArg())
+            {
 #if READYTORUN
-                    MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
-                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodDictionary, originalImplWithToken));
+                MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodDictionary, originalImplWithToken));
 
 #else
-                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
 #endif
-                }
-                else
-                {
+            }
+            else if (impl.RequiresInstMethodTableArg())
+            {
 #if READYTORUN
-                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
 
 #else
-                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
+                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
 #endif
-                }
             }
 
 #if READYTORUN
@@ -1549,7 +1534,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 #endif
             info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS;
             info->devirtualizedMethod = ObjectToHandle(impl);
-            info->tokenLookupContext = (isArrayInterfaceDevirtualization || isGenericVirtual) ? contextFromMethod(originalImpl) : contextFromType(owningType);
+            info->tokenLookupContext = impl.RequiresInstMethodDescArg() ? contextFromMethod(originalImpl) : contextFromType(owningType);
 
             return true;
 

From e27aba9a9e19987c958e40d58380f818afab21a7 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 16:10:18 +0900
Subject: [PATCH 22/33] Handle unboxing stub

---
 src/coreclr/jit/importercalls.cpp | 28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index f4ce0bd388072f..2fb882205ce189 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -9414,26 +9414,24 @@ void Compiler::impTransformDevirtualizedCall(GenTreeCall*            call,
             }
         }
     }
-    else
+
+    if (instParam == nullptr && dcInfo->pMethSig->hasTypeArg())
     {
-        if (dcInfo->pMethSig->hasTypeArg())
+        if (((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
         {
-            if (((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
-            {
-                CORINFO_METHOD_HANDLE exactMethodHandle =
-                    (CORINFO_METHOD_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
+            CORINFO_METHOD_HANDLE exactMethodHandle =
+                (CORINFO_METHOD_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
 
-                instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle);
-            }
-            else
-            {
-                assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
+            instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle);
+        }
+        else
+        {
+            assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
 
-                CORINFO_CLASS_HANDLE exactClassHandle =
-                    (CORINFO_CLASS_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
+            CORINFO_CLASS_HANDLE exactClassHandle =
+                (CORINFO_CLASS_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
 
-                instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle);
-            }
+            instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle);
         }
     }
 

From b77ad2d77e152682eeff5f8b2ef703ca368cd98b Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sat, 30 May 2026 16:17:21 +0900
Subject: [PATCH 23/33] Bail out unboxing stub in R2R for now

---
 src/coreclr/jit/importercalls.cpp             | 28 ++++++++++---------
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  6 ++++
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index 2fb882205ce189..f4ce0bd388072f 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -9414,24 +9414,26 @@ void Compiler::impTransformDevirtualizedCall(GenTreeCall*            call,
             }
         }
     }
-
-    if (instParam == nullptr && dcInfo->pMethSig->hasTypeArg())
+    else
     {
-        if (((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
+        if (dcInfo->pMethSig->hasTypeArg())
         {
-            CORINFO_METHOD_HANDLE exactMethodHandle =
-                (CORINFO_METHOD_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
+            if (((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
+            {
+                CORINFO_METHOD_HANDLE exactMethodHandle =
+                    (CORINFO_METHOD_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
 
-            instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle);
-        }
-        else
-        {
-            assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
+                instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle);
+            }
+            else
+            {
+                assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
 
-            CORINFO_CLASS_HANDLE exactClassHandle =
-                (CORINFO_CLASS_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
+                CORINFO_CLASS_HANDLE exactClassHandle =
+                    (CORINFO_CLASS_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
 
-            instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle);
+                instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle);
+            }
         }
     }
 
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 1b9b130b489e24..b4281b43e2da9b 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1502,6 +1502,12 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 
             if (impl.RequiresInstMethodDescArg())
             {
+                if (unboxingStub)
+                {
+                    // Bail out for now. We need an unboxing stub that points to an instantiated method.
+                    info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                    return false;
+                }
 #if READYTORUN
                 MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null);
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodDictionary, originalImplWithToken));

From de3bd27e3de8bc7413265f2c1c30b8f1051d9cd0 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sun, 31 May 2026 17:31:37 +0900
Subject: [PATCH 24/33] Clean up tests

---
 .../dim_devirt_github39419.cs                 |  36 ---
 .../devirtualization/dim_devirt_inline.cs     |  26 --
 .../devirtualization/dim_devirt_inline.csproj |  11 -
 .../devirtualization/dim_devirt_simple.cs     |  31 --
 .../devirtualization/dim_devirt_simple.csproj |  11 -
 .../dim_devirt_singlenongeneric.cs            |  24 --
 .../dim_devirt_singlenongeneric.csproj        |  11 -
 .../dim_devirt_singleoverriding.cs            |  25 --
 .../dim_devirt_singleoverriding.csproj        |  11 -
 .../dim_devirt_singleoverridinggeneric.cs     |  25 --
 .../dim_devirt_singleoverridinggeneric.csproj |  11 -
 .../dim_devirt_singleoverstruct.cs            |  24 --
 .../dim_devirt_singleoverstruct.csproj        |  11 -
 .../dim_devirt_singlevaluetypenondim.cs       |  25 --
 .../dim_devirt_singlevaluetypenondim.csproj   |  11 -
 .../dim_devirt_singlevariance.cs              |  24 --
 .../dim_devirt_singlevariance.csproj          |  11 -
 .../dim_devirt_snondimstruct.cs               |  22 --
 .../dim_devirt_snondimstruct.csproj           |  11 -
 .../dim_devirt_staticshared.cs                |  19 --
 .../dim_devirt_staticshared.csproj            |  11 -
 .../devirtualization/dim_devirt_structs.cs    |  31 --
 .../dim_devirt_structs.csproj                 |  11 -
 .../devirtualization/dim_devirtualization.cs  | 275 ++++++++++++++++++
 ...419.csproj => dim_devirtualization.csproj} |   0
 25 files changed, 275 insertions(+), 433 deletions(-)
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs
 delete mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj
 create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
 rename src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/{dim_devirt_github39419.csproj => dim_devirtualization.csproj} (100%)

diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs
deleted file mode 100644
index 8a611b3fbef284..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface IM<T>
-{
-    bool UseDefaultM { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; }
-    ValueTask M(T instance) => throw new NotImplementedException("M must be implemented if UseDefaultM is false");
-    static ValueTask DefaultM(T instance)
-    {
-        return default;
-    }
-}
-
-struct M : IM<int> { }
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var m = new M();
-        if (((IM<int>)m).UseDefaultM)
-        {
-            IM<int>.DefaultM(42);
-            return;
-        }
-        else
-        {
-            ((IM<int>)m).M(42);
-        }
-        throw new UnreachableException();
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs
deleted file mode 100644
index c43a13315f0bac..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T> where T : IComparable<T>
-{
-    T GetAt(int i, T[] tx) => tx[i];
-}
-
-class C : I<string>
-{
-}
-
-public static class Program
-{
-    private static string[] tx = new string[] { "test" };
-
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        I<string> c = new C();
-        var dcs = c.GetAt(0, tx);
-        Assert.Equal("test", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs
deleted file mode 100644
index 0d96d46bd09252..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T>
-{
-    string DefaultTypeOf() => typeof(T).Name;
-}
-
-class Dummy { }
-
-class C : I<string>, I<object>, I<Dummy>
-{
-    string I<Dummy>.DefaultTypeOf() => "C.Dummy";
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C();
-        var dcs = ((I<string>)c).DefaultTypeOf();
-        Assert.Equal("String", dcs);
-        var dos = ((I<object>)c).DefaultTypeOf();
-        Assert.Equal("Object", dos);
-        var dds = ((I<Dummy>)c).DefaultTypeOf();
-        Assert.Equal("C.Dummy", dds);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs
deleted file mode 100644
index 4deff94ccc5e94..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I
-{
-    string DefaultTypeOf() => typeof(string).Name;
-}
-
-class C : I
-{
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C();
-        var dcs = ((I)c).DefaultTypeOf();
-        Assert.Equal("String", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs
deleted file mode 100644
index b2bb95f36434e1..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T>
-{
-    string DefaultTypeOf() => typeof(T).Name;
-}
-
-class C : I<string>
-{
-    public string DefaultTypeOf() => "C.String";
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C();
-        var dcs = ((I<string>)c).DefaultTypeOf();
-        Assert.Equal("C.String", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs
deleted file mode 100644
index 31d8ec3549d629..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T>
-{
-    string DefaultTypeOf() => typeof(T).Name;
-}
-
-class C<T> : I<T>
-{
-    public string DefaultTypeOf() => "C." + typeof(T).Name;
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C<string>();
-        var dcs = ((I<string>)c).DefaultTypeOf();
-        Assert.Equal("C.String", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs
deleted file mode 100644
index 91560c952ed6fd..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T>
-{
-    string DefaultTypeOf() => typeof(T).Name;
-}
-
-class C : I<int>
-{
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C();
-        var dcs = ((I<int>)c).DefaultTypeOf();
-        Assert.Equal("Int32", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs
deleted file mode 100644
index d401949fc5f577..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T>
-{
-    string DefaultTypeOf();
-}
-
-struct C<T> : I<T>
-{
-    public string DefaultTypeOf() => "C." + typeof(T).Name;
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C<string>();
-        var dcs = ((I<string>)c).DefaultTypeOf();
-        Assert.Equal("C.String", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs
deleted file mode 100644
index 114fcbcf8933d1..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<in T>
-{
-    string DefaultTypeOf() => typeof(T).Name;
-}
-
-class C : I<object>
-{
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C();
-        var dcs = ((I<string>)c).DefaultTypeOf();
-        Assert.Equal("Object", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs
deleted file mode 100644
index f384f31c02d756..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-
-struct C<T>
-{
-    [MethodImpl(MethodImplOptions.NoInlining)]
-    public string DefaultTypeOf() => typeof(T).Name;
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C<string>();
-        var dcs = c.DefaultTypeOf();
-        Assert.Equal("String", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs
deleted file mode 100644
index f33c8b8aaf0fcd..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-class C<T>
-{
-    public static string DefaultTypeOf() => typeof(T).Name;
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var dcs = C<string>.DefaultTypeOf();
-        Assert.Equal("String", dcs);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs
deleted file mode 100644
index bbb79c7c3f0313..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-using Xunit;
-
-interface I<T>
-{
-    string DefaultTypeOf() => typeof(T).Name;
-}
-
-class Dummy { }
-
-struct C : I<string>, I<object>, I<Dummy>
-{
-    string I<Dummy>.DefaultTypeOf() => "C.Dummy";
-}
-
-public static class Program
-{
-    [Fact]
-    public static void TestEntryPoint()
-    {
-        var c = new C();
-        var dcs = ((I<string>)c).DefaultTypeOf();
-        Assert.Equal("String", dcs);
-        var dos = ((I<object>)c).DefaultTypeOf();
-        Assert.Equal("Object", dos);
-        var dds = ((I<Dummy>)c).DefaultTypeOf();
-        Assert.Equal("C.Dummy", dds);
-    }
-}
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj
deleted file mode 100644
index 30d4804022360c..00000000000000
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <CLRTestPriority>1</CLRTestPriority>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildProjectName).cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(TestLibraryProjectPath)" />
-  </ItemGroup>
-</Project>
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
new file mode 100644
index 00000000000000..5a0b517304adb8
--- /dev/null
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
@@ -0,0 +1,275 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+public static class Program
+{
+    [Fact]
+    public static void TestEntryPoint()
+    {
+        GitHubIssue39419RegressionCase.Run();
+        ConstrainedGenericInlineCase.Run();
+        MultiInterfaceDefaultMethodCases.Run();
+        NonGenericDefaultMethodCase.Run();
+        OverriddenDefaultMethodCases.Run();
+        ValueTypeArgumentDefaultMethodCase.Run();
+        StructNonDefaultImplementationCase.Run();
+        ContravariantDefaultMethodCase.Run();
+        DirectStructMethodCase.Run();
+        StaticGenericMethodCase.Run();
+    }
+}
+
+static class GitHubIssue39419RegressionCase
+{
+    interface IM<T>
+    {
+        bool UseDefaultM
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => true;
+        }
+
+        ValueTask M(T instance) => throw new NotImplementedException("M must be implemented if UseDefaultM is false");
+
+        static ValueTask DefaultM(T instance)
+        {
+            return default;
+        }
+    }
+
+    struct M : IM<int>
+    {
+    }
+
+    public static void Run()
+    {
+        var m = new M();
+        if (((IM<int>)m).UseDefaultM)
+        {
+            IM<int>.DefaultM(42);
+            return;
+        }
+
+        ((IM<int>)m).M(42);
+        throw new UnreachableException();
+    }
+}
+
+static class ConstrainedGenericInlineCase
+{
+    interface I<T> where T : IComparable<T>
+    {
+        T GetAt(int i, T[] tx) => tx[i];
+    }
+
+    class C : I<string>
+    {
+    }
+
+    private static readonly string[] s_values = new string[] { "test" };
+
+    public static void Run()
+    {
+        I<string> c = new C();
+        var dcs = c.GetAt(0, s_values);
+        Assert.Equal("test", dcs);
+    }
+}
+
+static class MultiInterfaceDefaultMethodCases
+{
+    interface I<T>
+    {
+        string DefaultTypeOf() => typeof(T).Name;
+    }
+
+    class Dummy
+    {
+    }
+
+    class ClassImplementation : I<string>, I<object>, I<Dummy>
+    {
+        string I<Dummy>.DefaultTypeOf() => "C.Dummy";
+    }
+
+    struct StructImplementation : I<string>, I<object>, I<Dummy>
+    {
+        string I<Dummy>.DefaultTypeOf() => "C.Dummy";
+    }
+
+    public static void Run()
+    {
+        RunClassImplementation();
+        RunStructImplementation();
+    }
+
+    static void RunClassImplementation()
+    {
+        var c = new ClassImplementation();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("String", dcs);
+        var dos = ((I<object>)c).DefaultTypeOf();
+        Assert.Equal("Object", dos);
+        var dds = ((I<Dummy>)c).DefaultTypeOf();
+        Assert.Equal("C.Dummy", dds);
+    }
+
+    static void RunStructImplementation()
+    {
+        var c = new StructImplementation();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("String", dcs);
+        var dos = ((I<object>)c).DefaultTypeOf();
+        Assert.Equal("Object", dos);
+        var dds = ((I<Dummy>)c).DefaultTypeOf();
+        Assert.Equal("C.Dummy", dds);
+    }
+}
+
+static class NonGenericDefaultMethodCase
+{
+    interface I
+    {
+        string DefaultTypeOf() => typeof(string).Name;
+    }
+
+    class C : I
+    {
+    }
+
+    public static void Run()
+    {
+        var c = new C();
+        var dcs = ((I)c).DefaultTypeOf();
+        Assert.Equal("String", dcs);
+    }
+}
+
+static class OverriddenDefaultMethodCases
+{
+    interface I<T>
+    {
+        string DefaultTypeOf() => typeof(T).Name;
+    }
+    class C : I<string>
+    {
+        public string DefaultTypeOf() => "C.String";
+    }
+
+    class GenericC<T> : I<T>
+    {
+        public string DefaultTypeOf() => "C." + typeof(T).Name;
+    }
+
+    public static void Run()
+    {
+        RunNonGenericOverride();
+        RunGenericOverride();
+    }
+
+    static void RunNonGenericOverride()
+    {
+        var c = new C();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("C.String", dcs);
+    }
+
+    static void RunGenericOverride()
+    {
+        var c = new GenericC<string>();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("C.String", dcs);
+    }
+}
+
+static class ValueTypeArgumentDefaultMethodCase
+{
+    interface I<T>
+    {
+        string DefaultTypeOf() => typeof(T).Name;
+    }
+
+    class C : I<int>
+    {
+    }
+
+    public static void Run()
+    {
+        var c = new C();
+        var dcs = ((I<int>)c).DefaultTypeOf();
+        Assert.Equal("Int32", dcs);
+    }
+}
+
+static class StructNonDefaultImplementationCase
+{
+    interface I<T>
+    {
+        string DefaultTypeOf();
+    }
+
+    struct C<T> : I<T>
+    {
+        public string DefaultTypeOf() => "C." + typeof(T).Name;
+    }
+
+    public static void Run()
+    {
+        var c = new C<string>();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("C.String", dcs);
+    }
+}
+
+static class ContravariantDefaultMethodCase
+{
+    interface I<in T>
+    {
+        string DefaultTypeOf() => typeof(T).Name;
+    }
+
+    class C : I<object>
+    {
+    }
+
+    public static void Run()
+    {
+        var c = new C();
+        var dcs = ((I<string>)c).DefaultTypeOf();
+        Assert.Equal("Object", dcs);
+    }
+}
+
+static class DirectStructMethodCase
+{
+    struct C<T>
+    {
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        public string DefaultTypeOf() => typeof(T).Name;
+    }
+
+    public static void Run()
+    {
+        var c = new C<string>();
+        var dcs = c.DefaultTypeOf();
+        Assert.Equal("String", dcs);
+    }
+}
+
+static class StaticGenericMethodCase
+{
+    class C<T>
+    {
+        public static string DefaultTypeOf() => typeof(T).Name;
+    }
+
+    public static void Run()
+    {
+        var dcs = C<string>.DefaultTypeOf();
+        Assert.Equal("String", dcs);
+    }
+}
+
diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.csproj
similarity index 100%
rename from src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj
rename to src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.csproj

From 41e0827642769378d6e08b8cc4d36611ec8aed1a Mon Sep 17 00:00:00 2001
From: Steve <hez2010@outlook.com>
Date: Mon, 1 Jun 2026 21:36:50 +0900
Subject: [PATCH 25/33] Nit

---
 .../devirtualization/dim_devirtualization.cs                    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
index 5a0b517304adb8..cb67af966d11cd 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
@@ -4,7 +4,7 @@
 using System.Threading.Tasks;
 using Xunit;
 
-public static class Program
+public class Program
 {
     [Fact]
     public static void TestEntryPoint()

From b55d5c1fc7627d8834d86fd2283d1899cb7a48d8 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Mon, 1 Jun 2026 23:35:58 +0900
Subject: [PATCH 26/33] Take canonical subtype into account as well

---
 src/coreclr/vm/jitinterface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 7c629b79b28ec7..ec39958752c9bc 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8856,7 +8856,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
         pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
             pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), true);
 
-        if (pDevirtMD->IsSharedByGenericMethodInstantiations())
+        if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetMethodInstantiation()))
         {
             pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
                 pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), false);

From 0820190ac5b4428ba664c08212dfb8620b63f0d9 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Mon, 1 Jun 2026 23:40:40 +0900
Subject: [PATCH 27/33] Add a test case

---
 .../VirtualMethods/generic_virtual_methods.cs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/tests/JIT/Generics/VirtualMethods/generic_virtual_methods.cs b/src/tests/JIT/Generics/VirtualMethods/generic_virtual_methods.cs
index 7aba5abe26bab3..cab401999094bb 100644
--- a/src/tests/JIT/Generics/VirtualMethods/generic_virtual_methods.cs
+++ b/src/tests/JIT/Generics/VirtualMethods/generic_virtual_methods.cs
@@ -4,6 +4,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Reflection;
 using System.Runtime.CompilerServices;
 using Xunit;
 
@@ -219,6 +220,11 @@ internal static void Test<T>()
         Delegate m1 = test2.Foo<List<T>>();
         Delegate m2 = test2.Foo<List<List<T>>>;
         Assert.Equal(m1, m2);
+        
+        IBase foo = new DerivedStruct();
+        Delegate d = foo.Foo<List<T>>();
+        MethodInfo expected = typeof(DerivedStruct).GetMethod(nameof(DerivedStruct.Foo))!.MakeGenericMethod(typeof(List<T>));
+        Assert.Equal(expected, d.Method);
     }
 }
 
@@ -245,6 +251,19 @@ public override Delegate Foo<U1>()
     }
 }
 
+internal interface IBase
+{
+    Delegate Foo<U>();
+}
+
+internal struct DerivedStruct : IBase
+{
+    public Delegate Foo<U>()
+    {
+        return Foo<U>;
+    }
+}
+
 internal static class IconContextBridgeNonShared<TMethod>
 {
     public static TMethod SameMethodSameClass(IBaseMethodCaller caller, TMethod value)

From d47b38275c89a0fb0642c73dc2b1f759a6b7fefb Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Tue, 2 Jun 2026 21:25:57 +0900
Subject: [PATCH 28/33] Refactor and properly handle unboxing stubs

---
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 16 +++-
 src/coreclr/vm/jitinterface.cpp               | 85 ++++++++-----------
 2 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index b4281b43e2da9b..907eb19889a0c2 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1482,6 +1482,9 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN);
             }
 
+            bool isArray = decl.OwningType.IsInterface && objType.IsArray;
+            bool isGenericVirtual = !isArray && decl.HasInstantiation;
+
             if (!impl.AcquiresInstMethodTableFromThis())
             {
                 if (originalImpl.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
@@ -1500,6 +1503,17 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 }
             }
 
+            if (isArray)
+            {
+#if READYTORUN
+                // Array interface devirt is not yet supported by R2R.
+                info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+                return false;
+#else
+                // NativeAOT handles arrays in a different way that doesn't require an instantiating stub.
+#endif
+            }
+
             if (impl.RequiresInstMethodDescArg())
             {
                 if (unboxingStub)
@@ -1540,7 +1554,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 #endif
             info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS;
             info->devirtualizedMethod = ObjectToHandle(impl);
-            info->tokenLookupContext = impl.RequiresInstMethodDescArg() ? contextFromMethod(originalImpl) : contextFromType(owningType);
+            info->tokenLookupContext = (isArray || isGenericVirtual) ? contextFromMethod(originalImpl) : contextFromType(owningType);
 
             return true;
 
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index ec39958752c9bc..e4e59c1ed21ad7 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8823,82 +8823,67 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     MethodTable* pExactMT = pApproxMT;
     bool isArray = false;
     bool isGenericVirtual = false;
-
-    if (pApproxMT->IsInterface())
-    {
-        if (pDevirtMD->HasClassInstantiation())
-        {
-            if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetClassInstantiation()))
-            {
-                // If we end up with a shared MethodTable that is not exact,
-                // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
-                info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-                return false;
-            }
-
-            info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE)pExactMT;
-            info->instParamLookup.constLookup.accessType = IAT_VALUE;
-        }
-    }
-    else if (pBaseMT->IsInterface() && pObjMT->IsArray())
+    
+    if (pBaseMT->IsInterface() && pObjMT->IsArray())
     {
         isArray = true;
     }
-    else
+    else if (!pApproxMT->IsInterface())
     {
         pExactMT = pDevirtMD->GetExactDeclaringType(pObjMT);
     }
 
+    MethodDesc* pInstantiatedMD = pDevirtMD;
+
     // This is generic virtual method devirtualization.
     if (!isArray && pBaseMD->HasMethodInstantiation())
     {
         MethodDesc* pPrimaryMD = pDevirtMD;
+
         pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
             pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), true);
-
-        if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetMethodInstantiation()))
-        {
-            pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
-                pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), false);
-
-            if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetClassInstantiation()))
-            {
-                // If we end up with a shared MethodTable that is not exact,
-                // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
-                info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-                return false;
-            }
-
-            // We are dealing with a generic virtual method whose owning type is exact.
-            // If the method is not exact, a runtime lookup would be required.
-            const bool requiresRuntimeLookup = TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetMethodInstantiation());
-            if (requiresRuntimeLookup)
-            {
-                // TODO: Support for runtime lookup
-                info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
-                return false;
-            }
-        }
+        
+        pInstantiatedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
+            pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), false);
 
         isGenericVirtual = true;
     }
 
-    if (isArray || isGenericVirtual)
+    MethodDesc* pUnboxedDevirtMD = pDevirtMD->IsUnboxingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
+
+    if (!pUnboxedDevirtMD->AcquiresInstMethodTableFromThis())
     {
-        if (pDevirtMD->IsInstantiatingStub())
+        if (TypeHandle::IsCanonicalSubtypeInstantiation(pInstantiatedMD->GetClassInstantiation()))
         {
-            info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE)pDevirtMD;
-            info->instParamLookup.constLookup.accessType = IAT_VALUE;
+            // If we end up with a shared MethodTable that is not exact,
+            // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
+            info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+            return false;
+        }
+
+        if (TypeHandle::IsCanonicalSubtypeInstantiation(pInstantiatedMD->GetMethodInstantiation()))
+        {
+            // TODO: Support for runtime lookup
+            info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+            return false;
         }
+    }
 
-        info->tokenLookupContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD);
+    if (pUnboxedDevirtMD->RequiresInstMethodDescArg())
+    {
+        info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE) pInstantiatedMD;
+        info->instParamLookup.constLookup.accessType = IAT_VALUE;
     }
-    else
+    else if (pUnboxedDevirtMD->RequiresInstMethodTableArg())
     {
-        info->tokenLookupContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
+        info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE) pExactMT;
+        info->instParamLookup.constLookup.accessType = IAT_VALUE;
     }
 
     pDevirtMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
+    info->tokenLookupContext = (isArray || isGenericVirtual)
+        ? MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pInstantiatedMD)
+        : MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
 
     // Success! Pass back the results.
     //

From fe252112fe4a1200447e3c4680af18ac6b7822da Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 11 Jun 2026 21:31:17 +0900
Subject: [PATCH 29/33] Cleanup getUnboxedEntry and getInstantiatedEntry

---
 src/coreclr/inc/corinfo.h                     |  25 ++--
 src/coreclr/inc/icorjitinfoimpl_generated.h   |   9 --
 src/coreclr/inc/jiteeversionguid.h            |  10 +-
 src/coreclr/jit/ICorJitInfo_names_generated.h |   2 -
 .../jit/ICorJitInfo_wrapper_generated.hpp     |  21 ----
 src/coreclr/jit/compiler.h                    |   2 +-
 src/coreclr/jit/importercalls.cpp             | 111 ++++++++----------
 src/coreclr/jit/indirectcalltransformer.cpp   |   2 +-
 src/coreclr/jit/inline.h                      |   3 +-
 .../tools/Common/JitInterface/CorInfoImpl.cs  |  22 ----
 .../JitInterface/CorInfoImpl_generated.cs     |  34 ------
 .../tools/Common/JitInterface/CorInfoTypes.cs |   9 +-
 .../ThunkGenerator/ThunkInput.txt             |   2 -
 .../aot/jitinterface/jitinterface_generated.h |  23 ----
 .../tools/superpmi/superpmi-shared/agnostic.h |   7 --
 .../tools/superpmi/superpmi-shared/lwmlist.h  |   2 -
 .../superpmi-shared/methodcontext.cpp         |  84 -------------
 .../superpmi/superpmi-shared/methodcontext.h  |  17 +--
 .../superpmi-shim-collector/icorjitinfo.cpp   |  22 ----
 .../icorjitinfo_generated.cpp                 |  17 ---
 .../icorjitinfo_generated.cpp                 |  15 ---
 .../tools/superpmi/superpmi/icorjitinfo.cpp   |  15 ---
 src/coreclr/vm/jitinterface.cpp               |  84 ++-----------
 23 files changed, 85 insertions(+), 453 deletions(-)

diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 5ac1524d19c6f1..98a03384d8b26d 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -1583,12 +1583,15 @@ struct CORINFO_DEVIRTUALIZATION_INFO
     // [Out] results of resolveVirtualMethod.
     // - devirtualizedMethod is set to MethodDesc of devirt'ed method iff we were able to devirtualize.
     //      invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`.
-    // - tokenLookupContext is set to the wrapped context handle to use for token lookups after devirtualization.
+    // - tokenLookupContext is set to the wrapped context handle to use for token lookups and the instantiation
+    //   parameter after devirtualization.
     // - details on the computation done by the jit host
-    // - If pResolvedTokenDevirtualizedMethod is not set to NULL and targeting an R2R image
-    //   use it as the parameter to getCallInfo
+    // - resolvedTokenDevirtualizedMethod is used as the parameter to getCallInfo when targeting an R2R image.
+    // - resolvedTokenDevirtualizedUnboxedMethod is set when devirtualizedMethod is an unboxing stub. Its hMethod
+    //   is the unboxed entry point, and the resolved token is used as the parameter to getCallInfo when targeting
+    //   an R2R image.
     // - instParamLookup contains all the information necessary to pass the instantiation parameter for
-    //   the devirtualized method.
+    //   the devirtualized method or its unboxed entry point.
     //
     CORINFO_METHOD_HANDLE           devirtualizedMethod;
     CORINFO_CONTEXT_HANDLE          tokenLookupContext;
@@ -2265,20 +2268,6 @@ class ICorStaticInfo
     // Returns false if devirtualization is not possible.
     virtual bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info) = 0;
 
-    // Get the unboxed entry point for a method, if possible.
-    virtual CORINFO_METHOD_HANDLE getUnboxedEntry(
-        CORINFO_METHOD_HANDLE ftn,
-        bool*                 requiresInstMethodTableArg
-        ) = 0;
-
-    // Get the wrapped entry point for an instantiating stub, if possible.
-    // Sets methodArg for method instantiations, classArg for class instantiations.
-    virtual CORINFO_METHOD_HANDLE getInstantiatedEntry(
-        CORINFO_METHOD_HANDLE ftn,
-        CORINFO_METHOD_HANDLE* methodArg,
-        CORINFO_CLASS_HANDLE* classArg
-        ) = 0;
-
     // Get the other variant of an async method, if possible.
     // If this is a method with async calling convention: returns the corresponding task-returning method.
     // If this is a task-returning method: returns the corresponding method with async calling convention.
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 8fc80cda20018c..09d1608bfa134f 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -95,15 +95,6 @@ void getMethodVTableOffset(
 bool resolveVirtualMethod(
           CORINFO_DEVIRTUALIZATION_INFO* info) override;
 
-CORINFO_METHOD_HANDLE getUnboxedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          bool* requiresInstMethodTableArg) override;
-
-CORINFO_METHOD_HANDLE getInstantiatedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          CORINFO_METHOD_HANDLE* methodArg,
-          CORINFO_CLASS_HANDLE* classArg) override;
-
 CORINFO_METHOD_HANDLE getAsyncOtherVariant(
           CORINFO_METHOD_HANDLE ftn,
           bool* variantIsThunk) override;
diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h
index 85d8a8682bf489..bc9e29979e6989 100644
--- a/src/coreclr/inc/jiteeversionguid.h
+++ b/src/coreclr/inc/jiteeversionguid.h
@@ -37,11 +37,11 @@
 
 #include <minipal/guid.h>
 
-constexpr GUID JITEEVersionIdentifier = { /* 59df85b8-c0fd-4e40-aea1-68cb2cd916cc */
-    0x59df85b8,
-    0xc0fd,
-    0x4e40,
-    {0xae, 0xa1, 0x68, 0xcb, 0x2c, 0xd9, 0x16, 0xcc}
+constexpr GUID JITEEVersionIdentifier = { /* 14ca1721-a3ba-40a0-b8a6-92a939719e66 */
+    0x14ca1721,
+    0xa3ba,
+    0x40a0,
+    {0xb8, 0xa6, 0x92, 0xa9, 0x39, 0x71, 0x9e, 0x66}
   };
 
 #endif // JIT_EE_VERSIONING_GUID_H
diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h
index 57781f560ce0d5..32abc2cd9596d2 100644
--- a/src/coreclr/jit/ICorJitInfo_names_generated.h
+++ b/src/coreclr/jit/ICorJitInfo_names_generated.h
@@ -21,8 +21,6 @@ DEF_CLR_API(getEHinfo)
 DEF_CLR_API(getMethodClass)
 DEF_CLR_API(getMethodVTableOffset)
 DEF_CLR_API(resolveVirtualMethod)
-DEF_CLR_API(getUnboxedEntry)
-DEF_CLR_API(getInstantiatedEntry)
 DEF_CLR_API(getAsyncOtherVariant)
 DEF_CLR_API(getDefaultComparerClass)
 DEF_CLR_API(getDefaultEqualityComparerClass)
diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
index 87e541b608f155..c775460f0c1bbc 100644
--- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
+++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
@@ -181,27 +181,6 @@ bool WrapICorJitInfo::resolveVirtualMethod(
     return temp;
 }
 
-CORINFO_METHOD_HANDLE WrapICorJitInfo::getUnboxedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          bool* requiresInstMethodTableArg)
-{
-    API_ENTER(getUnboxedEntry);
-    CORINFO_METHOD_HANDLE temp = wrapHnd->getUnboxedEntry(ftn, requiresInstMethodTableArg);
-    API_LEAVE(getUnboxedEntry);
-    return temp;
-}
-
-CORINFO_METHOD_HANDLE WrapICorJitInfo::getInstantiatedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          CORINFO_METHOD_HANDLE* methodArg,
-          CORINFO_CLASS_HANDLE* classArg)
-{
-    API_ENTER(getInstantiatedEntry);
-    CORINFO_METHOD_HANDLE temp = wrapHnd->getInstantiatedEntry(ftn, methodArg, classArg);
-    API_LEAVE(getInstantiatedEntry);
-    return temp;
-}
-
 CORINFO_METHOD_HANDLE WrapICorJitInfo::getAsyncOtherVariant(
           CORINFO_METHOD_HANDLE ftn,
           bool* variantIsThunk)
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index de116a31f9ebb1..9c834818a54890 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -4977,7 +4977,7 @@ class Compiler
     {
         CORINFO_CONTEXT_HANDLE  tokenLookupContext;      // The class context or method context
         CORINFO_RESOLVED_TOKEN* pResolvedToken;          // Resolved token for the target method, used by R2R.
-        CORINFO_RESOLVED_TOKEN* pUnboxedResolvedToken;   // Resolved token for the unboxed entry, used by R2R.
+        CORINFO_RESOLVED_TOKEN* pUnboxedResolvedToken;   // Resolved token and method handle for the unboxed entry.
         CORINFO_LOOKUP*         pInstParamLookup;        // All the information needed for the instantiation parameter lookup.
         CORINFO_SIG_INFO*       pMethSig;                // The devirted method signature.
         bool                    objIsNonNull;            // True if the receiver is known non-null.
diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index 851e08288b3d35..258067957e2091 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -8161,7 +8161,6 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall*            call,
     InlineCandidateInfo* pInfo = new (this, CMK_Inlining) InlineCandidateInfo;
 
     pInfo->guardedMethodHandle               = methodHandle;
-    pInfo->guardedMethodUnboxedEntryHandle   = nullptr;
     pInfo->guardedMethodInstParamLookup      = {};
     pInfo->guardedMethodResolvedToken        = {};
     pInfo->guardedMethodUnboxedResolvedToken = {};
@@ -8181,22 +8180,6 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall*            call,
         pInfo->guardedMethodUnboxedResolvedToken = *pUnboxedResolvedToken;
     }
 
-    // If the guarded class is a value class, look for an unboxed entry point.
-    //
-    if ((classAttr & CORINFO_FLG_VALUECLASS) != 0)
-    {
-        JITDUMP("    ... class is a value class, looking for unboxed entry\n");
-        bool                  requiresInstMethodTableArg = false;
-        CORINFO_METHOD_HANDLE unboxedEntryMethodHandle =
-            info.compCompHnd->getUnboxedEntry(methodHandle, &requiresInstMethodTableArg);
-
-        if (unboxedEntryMethodHandle != nullptr)
-        {
-            JITDUMP("    ... updating GDV candidate with unboxed entry info\n");
-            pInfo->guardedMethodUnboxedEntryHandle = unboxedEntryMethodHandle;
-        }
-    }
-
     call->AddGDVCandidateInfo(this, pInfo);
 }
 
@@ -8472,9 +8455,9 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall*           call,
     if (call->IsGuardedDevirtualizationCandidate())
     {
         InlineCandidateInfo* gdvCandidate = call->GetGDVCandidateInfo(candidateIndex);
-        if (gdvCandidate->guardedMethodUnboxedEntryHandle != nullptr)
+        if (gdvCandidate->guardedMethodUnboxedResolvedToken.hMethod != nullptr)
         {
-            fncHandle = gdvCandidate->guardedMethodUnboxedEntryHandle;
+            fncHandle = gdvCandidate->guardedMethodUnboxedResolvedToken.hMethod;
         }
         else
         {
@@ -9411,61 +9394,61 @@ void Compiler::impTransformDevirtualizedCall(GenTreeCall*            call,
         {
             JITDUMP("Have a direct call to boxed entry point. Trying to optimize to call an unboxed entry point\n");
 
-            // Note for some shared methods the unboxed entry point requires an extra parameter.
-            bool                  requiresInstMethodTableArg = false;
-            CORINFO_METHOD_HANDLE unboxedEntryMethod =
-                info.compCompHnd->getUnboxedEntry(derivedMethod, &requiresInstMethodTableArg);
+            CORINFO_METHOD_HANDLE const unboxedEntryMethod =
+                (dcInfo->pUnboxedResolvedToken == nullptr) ? nullptr : dcInfo->pUnboxedResolvedToken->hMethod;
 
             if (unboxedEntryMethod != nullptr)
             {
-                // Rewrite the call to target the unboxed entry on the box payload. Keep the heap box,
-                // since the callee may return an interior managed pointer into it; object stack allocation
-                // can later promote the box to the stack when escape analysis proves the receiver does not
-                // escape.
-                //
-                if (requiresInstMethodTableArg)
-                {
-                    // Get the method table from the boxed object.
-                    //
-                    // TODO-CallArgs-REVIEW: Use thisObj here? Differs by gtEffectiveVal.
-                    GenTree* const clonedThisArg = gtClone(thisArg->GetEarlyNode());
+                CORINFO_SIG_INFO unboxedEntrySig;
+                info.compCompHnd->getMethodSig(unboxedEntryMethod, &unboxedEntrySig);
+
+                bool canUseUnboxedEntry = true;
 
-                    if (clonedThisArg == nullptr)
+                if (unboxedEntrySig.hasTypeArg())
+                {
+                    if (unboxedEntrySig.sigInst.methInstCount != 0)
                     {
-                        JITDUMP("unboxed entry needs MT arg, but `this` was too complex to clone. Deferring update.\n");
+                        assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) ==
+                               CORINFO_CONTEXTFLAGS_METHOD);
+                        CORINFO_METHOD_HANDLE exactMethodHandle =
+                            (CORINFO_METHOD_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
+
+                        instParam = getLookupTree(dcInfo->pInstParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle);
+                        JITDUMP("revising call to invoke unboxed entry with additional method desc arg\n");
                     }
                     else
                     {
-                        JITDUMP("revising call to invoke unboxed entry with additional method table arg\n");
-
-                        instParam = gtNewMethodTableLookup(clonedThisArg);
-
-                        // Update the 'this' pointer to refer to the box payload
+                        // Get the method table from the boxed object.
                         //
-                        GenTree* const payloadOffset = gtNewIconNode(TARGET_POINTER_SIZE, TYP_I_IMPL);
-                        GenTree* const boxPayload =
-                            gtNewOperNode(GT_ADD, TYP_BYREF, thisArg->GetEarlyNode(), payloadOffset);
-
-                        assert(thisObj == thisArg->GetEarlyNode());
-                        thisArg->SetEarlyNode(boxPayload);
-                        call->gtCallMethHnd = unboxedEntryMethod;
-                        INDEBUG(call->gtCallDebugFlags |= GTF_CALL_MD_UNBOXED);
+                        // TODO-CallArgs-REVIEW: Use thisObj here? Differs by gtEffectiveVal.
+                        GenTree* const clonedThisArg = gtClone(thisArg->GetEarlyNode());
 
-                        // Method attributes will differ because unboxed entry point is shared
-                        //
-                        const DWORD unboxedMethodAttribs = info.compCompHnd->getMethodAttribs(unboxedEntryMethod);
-                        JITDUMP("Updating method attribs from 0x%08x to 0x%08x\n", derivedMethodAttribs,
-                                unboxedMethodAttribs);
-                        derivedMethod         = unboxedEntryMethod;
-                        pDerivedResolvedToken = dcInfo->pUnboxedResolvedToken;
-                        derivedMethodAttribs  = unboxedMethodAttribs;
-                        Metrics.DevirtualizedCallUnboxedEntry++;
+                        if (clonedThisArg == nullptr)
+                        {
+                            JITDUMP(
+                                "unboxed entry needs MT arg, but `this` was too complex to clone. Deferring update.\n");
+                            canUseUnboxedEntry = false;
+                        }
+                        else
+                        {
+                            instParam = gtNewMethodTableLookup(clonedThisArg);
+                            assert(thisObj == thisArg->GetEarlyNode());
+                            JITDUMP("revising call to invoke unboxed entry with additional method table arg\n");
+                        }
                     }
                 }
                 else
                 {
                     JITDUMP("revising call to invoke unboxed entry\n");
+                }
 
+                if (canUseUnboxedEntry)
+                {
+                    // Rewrite the call to target the unboxed entry on the box payload. Keep the heap box,
+                    // since the callee may return an interior managed pointer into it; object stack allocation
+                    // can later promote the box to the stack when escape analysis proves the receiver does not
+                    // escape.
+                    //
                     GenTree* const payloadOffset = gtNewIconNode(TARGET_POINTER_SIZE, TYP_I_IMPL);
                     GenTree* const boxPayload =
                         gtNewOperNode(GT_ADD, TYP_BYREF, thisArg->GetEarlyNode(), payloadOffset);
@@ -9473,6 +9456,17 @@ void Compiler::impTransformDevirtualizedCall(GenTreeCall*            call,
                     thisArg->SetEarlyNode(boxPayload);
                     call->gtCallMethHnd = unboxedEntryMethod;
                     INDEBUG(call->gtCallDebugFlags |= GTF_CALL_MD_UNBOXED);
+
+                    if (unboxedEntrySig.hasTypeArg())
+                    {
+                        // Method attributes will differ because unboxed entry point is shared.
+                        //
+                        const DWORD unboxedMethodAttribs = info.compCompHnd->getMethodAttribs(unboxedEntryMethod);
+                        JITDUMP("Updating method attribs from 0x%08x to 0x%08x\n", derivedMethodAttribs,
+                                unboxedMethodAttribs);
+                        derivedMethodAttribs = unboxedMethodAttribs;
+                    }
+
                     derivedMethod         = unboxedEntryMethod;
                     pDerivedResolvedToken = dcInfo->pUnboxedResolvedToken;
                     Metrics.DevirtualizedCallUnboxedEntry++;
@@ -10068,7 +10062,6 @@ void Compiler::impCheckCanInline(GenTreeCall*           call,
             //
             pInfo->guardedClassHandle                = nullptr;
             pInfo->guardedMethodHandle               = nullptr;
-            pInfo->guardedMethodUnboxedEntryHandle   = nullptr;
             pInfo->guardedMethodInstParamLookup      = {};
             pInfo->guardedMethodResolvedToken        = {};
             pInfo->guardedMethodUnboxedResolvedToken = {};
diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp
index 892a2c5b430586..195c3ad5dc877c 100644
--- a/src/coreclr/jit/indirectcalltransformer.cpp
+++ b/src/coreclr/jit/indirectcalltransformer.cpp
@@ -1007,7 +1007,7 @@ class IndirectCallTransformer
             // If the devirtualizer was unable to transform the call to invoke the unboxed entry, the inline info
             // we set up may be invalid. We won't be able to inline anyways. So demote the call as an inline candidate.
             //
-            CORINFO_METHOD_HANDLE unboxedMethodHnd = inlineInfo->guardedMethodUnboxedEntryHandle;
+            CORINFO_METHOD_HANDLE unboxedMethodHnd = inlineInfo->guardedMethodUnboxedResolvedToken.hMethod;
             if ((unboxedMethodHnd != nullptr) && (methodHnd != unboxedMethodHnd))
             {
                 // Demote this call to a non-inline candidate
diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h
index 595acc9ecb174f..065f7de3eaaa20 100644
--- a/src/coreclr/jit/inline.h
+++ b/src/coreclr/jit/inline.h
@@ -595,10 +595,9 @@ struct InlineCandidateInfo : public HandleHistogramProfileCandidateInfo
 {
     CORINFO_CLASS_HANDLE   guardedClassHandle;
     CORINFO_METHOD_HANDLE  guardedMethodHandle;
-    CORINFO_METHOD_HANDLE  guardedMethodUnboxedEntryHandle;
     CORINFO_LOOKUP         guardedMethodInstParamLookup;
     CORINFO_RESOLVED_TOKEN guardedMethodResolvedToken;        // Only used by R2R
-    CORINFO_RESOLVED_TOKEN guardedMethodUnboxedResolvedToken; // Only used by R2R
+    CORINFO_RESOLVED_TOKEN guardedMethodUnboxedResolvedToken; // hMethod is the unboxed entry; token data is used by R2R
     unsigned               likelihood;
 
     CORINFO_METHOD_INFO methInfo;
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 5638e885771ee5..80250efc4e5b39 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1540,28 +1540,6 @@ static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInter
             }
         }
 
-        private CORINFO_METHOD_STRUCT_* getUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, ref bool requiresInstMethodTableArg)
-        {
-            MethodDesc result = null;
-            requiresInstMethodTableArg = false;
-
-            MethodDesc method = HandleToObject(ftn);
-            if (method.IsUnboxingThunk())
-            {
-                result = method.GetUnboxedMethod();
-                requiresInstMethodTableArg = method.RequiresInstMethodTableArg();
-            }
-
-            return result != null ? ObjectToHandle(result) : null;
-        }
-
-        private CORINFO_METHOD_STRUCT_* getInstantiatedEntry(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_STRUCT_** methodArg, CORINFO_CLASS_STRUCT_** classArg)
-        {
-            *methodArg = null;
-            *classArg = null;
-            return null;
-        }
-
         private CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk)
         {
             MethodDesc method = HandleToObject(ftn);
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
index 2ec1fc175a8d91..74da04da013a53 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
@@ -37,8 +37,6 @@ static ICorJitInfoCallbacks()
                 s_callbacks.getMethodClass = &_getMethodClass;
                 s_callbacks.getMethodVTableOffset = &_getMethodVTableOffset;
                 s_callbacks.resolveVirtualMethod = &_resolveVirtualMethod;
-                s_callbacks.getUnboxedEntry = &_getUnboxedEntry;
-                s_callbacks.getInstantiatedEntry = &_getInstantiatedEntry;
                 s_callbacks.getAsyncOtherVariant = &_getAsyncOtherVariant;
                 s_callbacks.getDefaultComparerClass = &_getDefaultComparerClass;
                 s_callbacks.getDefaultEqualityComparerClass = &_getDefaultEqualityComparerClass;
@@ -220,8 +218,6 @@ static ICorJitInfoCallbacks()
             public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*> getMethodClass;
             public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint*, bool*, void> getMethodVTableOffset;
             public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_DEVIRTUALIZATION_INFO*, byte> resolveVirtualMethod;
-            public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, bool*, CORINFO_METHOD_STRUCT_*> getUnboxedEntry;
-            public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_METHOD_STRUCT_**, CORINFO_CLASS_STRUCT_**, CORINFO_METHOD_STRUCT_*> getInstantiatedEntry;
             public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, bool*, CORINFO_METHOD_STRUCT_*> getAsyncOtherVariant;
             public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*> getDefaultComparerClass;
             public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*> getDefaultEqualityComparerClass;
@@ -639,36 +635,6 @@ private static byte _resolveVirtualMethod(IntPtr thisHandle, IntPtr* ppException
             }
         }
 
-        [UnmanagedCallersOnly]
-        private static CORINFO_METHOD_STRUCT_* _getUnboxedEntry(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, bool* requiresInstMethodTableArg)
-        {
-            var _this = GetThis(thisHandle);
-            try
-            {
-                return _this.getUnboxedEntry(ftn, ref *requiresInstMethodTableArg);
-            }
-            catch (Exception ex)
-            {
-                *ppException = _this.AllocException(ex);
-                return default;
-            }
-        }
-
-        [UnmanagedCallersOnly]
-        private static CORINFO_METHOD_STRUCT_* _getInstantiatedEntry(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_STRUCT_** methodArg, CORINFO_CLASS_STRUCT_** classArg)
-        {
-            var _this = GetThis(thisHandle);
-            try
-            {
-                return _this.getInstantiatedEntry(ftn, methodArg, classArg);
-            }
-            catch (Exception ex)
-            {
-                *ppException = _this.AllocException(ex);
-                return default;
-            }
-        }
-
         [UnmanagedCallersOnly]
         private static CORINFO_METHOD_STRUCT_* _getAsyncOtherVariant(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, bool* variantIsThunk)
         {
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
index f173125897d053..14284d26860edc 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
@@ -1176,10 +1176,15 @@ public unsafe struct CORINFO_DEVIRTUALIZATION_INFO
         // [Out] results of resolveVirtualMethod.
         // - devirtualizedMethod is set to MethodDesc of devirt'ed method iff we were able to devirtualize.
         //      invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`.
-        // - tokenLookupContext is set to the wrapped context handle to use for token lookups after devirtualization.
+        // - tokenLookupContext is set to the wrapped context handle to use for token lookups and the instantiation
+        //   parameter after devirtualization.
         // - detail describes the computation done by the jit host
+        // - resolvedTokenDevirtualizedMethod is used as the parameter to getCallInfo when targeting an R2R image.
+        // - resolvedTokenDevirtualizedUnboxedMethod is set when devirtualizedMethod is an unboxing stub. Its hMethod
+        //   is the unboxed entry point, and the resolved token is used as the parameter to getCallInfo when targeting
+        //   an R2R image.
         // - instParamLookup contains all the information necessary to pass the instantiation parameter for
-        //   the devirtualized method.
+        //   the devirtualized method or its unboxed entry point.
         //
         public CORINFO_METHOD_STRUCT_* devirtualizedMethod;
         public CORINFO_CONTEXT_STRUCT* tokenLookupContext;
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index 384ca10f881504..fe14f4d9bc0e5c 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -190,8 +190,6 @@ FUNCTIONS
     CORINFO_CLASS_HANDLE getMethodClass(        CORINFO_METHOD_HANDLE       method        );
     void getMethodVTableOffset(        CORINFO_METHOD_HANDLE       method,        unsigned*                   offsetOfIndirection,        unsigned*                   offsetAfterIndirection, bool*                       isRelative);
     bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info);
-    CORINFO_METHOD_HANDLE getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg);
-    CORINFO_METHOD_HANDLE getInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodArg, CORINFO_CLASS_HANDLE* classArg);
     CORINFO_METHOD_HANDLE getAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk);
     CORINFO_CLASS_HANDLE getDefaultComparerClass(CORINFO_CLASS_HANDLE elemType);
     CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType);
diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h
index 90ec07a3b446bc..0049a99f1e1dd8 100644
--- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h
+++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h
@@ -28,8 +28,6 @@ struct JitInterfaceCallbacks
     CORINFO_CLASS_HANDLE (* getMethodClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method);
     void (* getMethodVTableOffset)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection, bool* isRelative);
     bool (* resolveVirtualMethod)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_DEVIRTUALIZATION_INFO* info);
-    CORINFO_METHOD_HANDLE (* getUnboxedEntry)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg);
-    CORINFO_METHOD_HANDLE (* getInstantiatedEntry)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodArg, CORINFO_CLASS_HANDLE* classArg);
     CORINFO_METHOD_HANDLE (* getAsyncOtherVariant)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk);
     CORINFO_CLASS_HANDLE (* getDefaultComparerClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE elemType);
     CORINFO_CLASS_HANDLE (* getDefaultEqualityComparerClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE elemType);
@@ -376,27 +374,6 @@ class JitInterfaceWrapper : public ICorJitInfo
     return temp;
 }
 
-    virtual CORINFO_METHOD_HANDLE getUnboxedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          bool* requiresInstMethodTableArg)
-{
-    CorInfoExceptionClass* pException = nullptr;
-    CORINFO_METHOD_HANDLE temp = _callbacks->getUnboxedEntry(_thisHandle, &pException, ftn, requiresInstMethodTableArg);
-    if (pException != nullptr) throw pException;
-    return temp;
-}
-
-    virtual CORINFO_METHOD_HANDLE getInstantiatedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          CORINFO_METHOD_HANDLE* methodArg,
-          CORINFO_CLASS_HANDLE* classArg)
-{
-    CorInfoExceptionClass* pException = nullptr;
-    CORINFO_METHOD_HANDLE temp = _callbacks->getInstantiatedEntry(_thisHandle, &pException, ftn, methodArg, classArg);
-    if (pException != nullptr) throw pException;
-    return temp;
-}
-
     virtual CORINFO_METHOD_HANDLE getAsyncOtherVariant(
           CORINFO_METHOD_HANDLE ftn,
           bool* variantIsThunk)
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h
index 85a7a8bf540eed..82bbc093be6f70 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h
@@ -694,13 +694,6 @@ struct Agnostic_ResolveVirtualMethodResult
     Agnostic_CORINFO_LOOKUP         instParamLookup;
 };
 
-struct Agnostic_GetInstantiatedEntryResult
-{
-    DWORDLONG                       methodHandle;
-    DWORDLONG                       classHandle;
-    DWORDLONG                       result;
-};
-
 struct ResolveTokenValue
 {
     Agnostic_CORINFO_RESOLVED_TOKENout tokenOut;
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
index b464feef60b3f6..957c92a4aa30f7 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h
@@ -138,8 +138,6 @@ LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG)
 LWM(GetTypeForBox, DWORDLONG, DWORDLONG)
 LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD)
 LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD)
-LWM(GetUnboxedEntry, DWORDLONG, DLD);
-LWM(GetInstantiatedEntry, DWORDLONG, Agnostic_GetInstantiatedEntryResult);
 LWM(GetAsyncOtherVariant, DWORDLONG, DLD);
 LWM(GetUnBoxHelper, DWORDLONG, DWORD)
 LWM(GetRuntimeTypePointer, DWORDLONG, DWORDLONG)
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
index ec6b3b9e1ef4ac..85dec9a6b527ca 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
@@ -3318,90 +3318,6 @@ bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info
     return result.returnValue;
 }
 
-void MethodContext::recGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn,
-                                       bool*                 requiresInstMethodTableArg,
-                                       CORINFO_METHOD_HANDLE result)
-{
-    if (GetUnboxedEntry == nullptr)
-    {
-        GetUnboxedEntry = new LightWeightMap<DWORDLONG, DLD>();
-    }
-
-    DWORDLONG key = CastHandle(ftn);
-    DLD       value;
-    value.A = CastHandle(result);
-    if (requiresInstMethodTableArg != nullptr)
-    {
-        value.B = (DWORD)*requiresInstMethodTableArg ? 1 : 0;
-    }
-    else
-    {
-        value.B = 0;
-    }
-    GetUnboxedEntry->Add(key, value);
-    DEBUG_REC(dmpGetUnboxedEntry(key, value));
-}
-
-void MethodContext::dmpGetUnboxedEntry(DWORDLONG key, DLD value)
-{
-    printf("GetUnboxedEntry ftn-%016" PRIX64 ", result-%016" PRIX64 ", requires-inst-%u", key, value.A, value.B);
-}
-
-CORINFO_METHOD_HANDLE MethodContext::repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
-{
-    DWORDLONG key = CastHandle(ftn);
-
-    DLD value = LookupByKeyOrMiss(GetUnboxedEntry, key, ": key %016" PRIX64 "", key);
-
-    DEBUG_REP(dmpGetUnboxedEntry(key, value));
-
-    if (requiresInstMethodTableArg != nullptr)
-    {
-        *requiresInstMethodTableArg = (value.B == 1);
-    }
-    return (CORINFO_METHOD_HANDLE)(value.A);
-}
-
-void MethodContext::recGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn,
-    CORINFO_METHOD_HANDLE methodHandle,
-    CORINFO_CLASS_HANDLE classHandle,
-    CORINFO_METHOD_HANDLE result)
-{
-    if (GetInstantiatedEntry == nullptr)
-    {
-        GetInstantiatedEntry = new LightWeightMap<DWORDLONG, Agnostic_GetInstantiatedEntryResult>();
-    }
-
-    DWORDLONG key = CastHandle(ftn);
-    Agnostic_GetInstantiatedEntryResult value;
-    value.methodHandle = CastHandle(methodHandle);
-    value.classHandle = CastHandle(classHandle);
-    value.result = CastHandle(result);
-
-    GetInstantiatedEntry->Add(key, value);
-    DEBUG_REC(dmpGetUnboxedEntry(key, value));
-}
-
-void MethodContext::dmpGetInstantiatedEntry(DWORDLONG key, const Agnostic_GetInstantiatedEntryResult& value)
-{
-    printf("GetUnboxedEntry ftn-%016" PRIX64 ", methodHnd-%016" PRIX64 ", classHnd-%016" PRIX64 ", result-%016" PRIX64 "\n",
-        key, value.methodHandle, value.classHandle, value.result);
-}
-
-CORINFO_METHOD_HANDLE MethodContext::repGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodHandle, CORINFO_CLASS_HANDLE* classHandle)
-{
-    DWORDLONG key = CastHandle(ftn);
-
-    Agnostic_GetInstantiatedEntryResult value = LookupByKeyOrMiss(GetInstantiatedEntry, key, ": key %016" PRIX64 "", key);
-
-    DEBUG_REP(dmpGetInstantiatedEntryEntry(key, value));
-
-    *methodHandle = (CORINFO_METHOD_HANDLE)value.methodHandle;
-    *classHandle = (CORINFO_CLASS_HANDLE)value.classHandle;
-
-    return (CORINFO_METHOD_HANDLE)(value.result);
-}
-
 void MethodContext::recGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn,
                                             bool                  variantIsThunk,
                                             CORINFO_METHOD_HANDLE result)
diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
index 449a18a91caeb5..e4cef62c08791a 100644
--- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h
@@ -446,19 +446,6 @@ class MethodContext
     void dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethodKey& key, const Agnostic_ResolveVirtualMethodResult& value);
     bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info);
 
-    void recGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg, CORINFO_METHOD_HANDLE result);
-    void dmpGetUnboxedEntry(DWORDLONG key, DLD value);
-    CORINFO_METHOD_HANDLE repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg);
-
-    void recGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn,
-                                 CORINFO_METHOD_HANDLE methodHandle,
-                                 CORINFO_CLASS_HANDLE classHandle,
-                                 CORINFO_METHOD_HANDLE result);
-    void dmpGetInstantiatedEntry(DWORDLONG key, const Agnostic_GetInstantiatedEntryResult& value);
-    CORINFO_METHOD_HANDLE repGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn,
-                                                  CORINFO_METHOD_HANDLE* methodHandle,
-                                                  CORINFO_CLASS_HANDLE* classHandle);
-
     void recGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool variantIsThunk, CORINFO_METHOD_HANDLE result);
     void dmpGetAsyncOtherVariant(DWORDLONG key, DLD value);
     CORINFO_METHOD_HANDLE repGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk);
@@ -1149,7 +1136,7 @@ enum mcPackets
     Packet_GetDefaultEqualityComparerClass = 162,
     Packet_CompareTypesForCast = 163,
     Packet_CompareTypesForEquality = 164,
-    Packet_GetUnboxedEntry = 165,
+    //Packet_GetUnboxedEntry = 165,
     Packet_GetClassNameFromMetadata = 166,
     Packet_GetTypeInstantiationArgument = 167,
     Packet_GetTypeForPrimitiveNumericClass = 168,
@@ -1212,7 +1199,7 @@ enum mcPackets
     Packet_GetClassAssemblyName = 225,
     Packet_GetSZArrayHelperEnumeratorClass = 226,
     Packet_GetMethodInstantiationArgument = 227,
-    Packet_GetInstantiatedEntry = 228,
+    //Packet_GetInstantiatedEntry = 228,
     Packet_NotifyInstructionSetUsage = 229,
     Packet_GetAsyncInfo = 230,
     Packet_GetAsyncResumptionStub = 231,
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 6d0cadcd5616ae..04082c6ac0c406 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -241,28 +241,6 @@ bool interceptor_ICJI::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info
     return result;
 }
 
-// Get the unboxed entry point for a method, if possible.
-CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
-{
-    mc->cr->AddCall("getUnboxedEntry");
-    bool                  localRequiresInstMethodTableArg = false;
-    CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getUnboxedEntry(ftn, &localRequiresInstMethodTableArg);
-    mc->recGetUnboxedEntry(ftn, &localRequiresInstMethodTableArg, result);
-    if (requiresInstMethodTableArg != nullptr)
-    {
-        *requiresInstMethodTableArg = localRequiresInstMethodTableArg;
-    }
-    return result;
-}
-
-CORINFO_METHOD_HANDLE interceptor_ICJI::getInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodHandle, CORINFO_CLASS_HANDLE* classHandle)
-{
-    mc->cr->AddCall("getInstantaitedEntry");
-    CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getInstantiatedEntry(ftn, methodHandle, classHandle);
-    mc->recGetInstantiatedEntry(ftn, *methodHandle, *classHandle, result);
-    return result;
-}
-
 CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk)
 {
     mc->cr->AddCall("getAsyncOtherVariant");
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp
index 874083bd15b940..3b3ad4933853be 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp
@@ -154,23 +154,6 @@ bool interceptor_ICJI::resolveVirtualMethod(
     return original_ICorJitInfo->resolveVirtualMethod(info);
 }
 
-CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          bool* requiresInstMethodTableArg)
-{
-    mcs->AddCall("getUnboxedEntry");
-    return original_ICorJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg);
-}
-
-CORINFO_METHOD_HANDLE interceptor_ICJI::getInstantiatedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          CORINFO_METHOD_HANDLE* methodArg,
-          CORINFO_CLASS_HANDLE* classArg)
-{
-    mcs->AddCall("getInstantiatedEntry");
-    return original_ICorJitInfo->getInstantiatedEntry(ftn, methodArg, classArg);
-}
-
 CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncOtherVariant(
           CORINFO_METHOD_HANDLE ftn,
           bool* variantIsThunk)
diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp
index b870f0f947f2f6..5e9dbe609bde3b 100644
--- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp
+++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp
@@ -137,21 +137,6 @@ bool interceptor_ICJI::resolveVirtualMethod(
     return original_ICorJitInfo->resolveVirtualMethod(info);
 }
 
-CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          bool* requiresInstMethodTableArg)
-{
-    return original_ICorJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg);
-}
-
-CORINFO_METHOD_HANDLE interceptor_ICJI::getInstantiatedEntry(
-          CORINFO_METHOD_HANDLE ftn,
-          CORINFO_METHOD_HANDLE* methodArg,
-          CORINFO_CLASS_HANDLE* classArg)
-{
-    return original_ICorJitInfo->getInstantiatedEntry(ftn, methodArg, classArg);
-}
-
 CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncOtherVariant(
           CORINFO_METHOD_HANDLE ftn,
           bool* variantIsThunk)
diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
index 93262fd2279b01..c2743ff9524bb4 100644
--- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp
@@ -203,21 +203,6 @@ bool MyICJI::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info)
     return result;
 }
 
-// Get the unboxed entry point for a method, if possible.
-CORINFO_METHOD_HANDLE MyICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
-{
-    jitInstance->mc->cr->AddCall("getUnboxedEntry");
-    CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetUnboxedEntry(ftn, requiresInstMethodTableArg);
-    return result;
-}
-
-CORINFO_METHOD_HANDLE MyICJI::getInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodHandle, CORINFO_CLASS_HANDLE* classHandle)
-{
-    jitInstance->mc->cr->AddCall("getInstantiatedEntry");
-    CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetInstantiatedEntry(ftn, methodHandle, classHandle);
-    return result;
-}
-
 CORINFO_METHOD_HANDLE MyICJI::getAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk)
 {
     jitInstance->mc->cr->AddCall("getAsyncOtherVariant");
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index c0ec22f3e75a8f..b6bce399a68a56 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8880,6 +8880,15 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
         info->tokenLookupContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
     }
 
+    // If we devirtualized into an unboxing stub, also hand back the unboxed entry
+    // so the jit can perform the unboxing transformation.
+    //
+    if (pDevirtMD->IsUnboxingStub())
+    {
+        MethodDesc* pUnboxedMD = pDevirtMD->GetMethodTable()->GetUnboxedEntryPointMD(pDevirtMD);
+        info->resolvedTokenDevirtualizedUnboxedMethod.hMethod = (CORINFO_METHOD_HANDLE) pUnboxedMD;
+    }
+
     // Success! Pass back the results.
     //
     info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD;
@@ -8907,81 +8916,6 @@ bool CEEInfo::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info)
     return result;
 }
 
-/*********************************************************************/
-CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
-    CORINFO_METHOD_HANDLE ftn,
-    bool* requiresInstMethodTableArg)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_PREEMPTIVE;
-    } CONTRACTL_END;
-
-    CORINFO_METHOD_HANDLE result = NULL;
-
-    JIT_TO_EE_TRANSITION();
-
-    MethodDesc* pMD = GetMethod(ftn);
-    bool requiresInstMTArg = false;
-
-    if (pMD->IsUnboxingStub())
-    {
-        MethodTable* pMT = pMD->GetMethodTable();
-        MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
-
-        result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
-        requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
-    }
-
-    *requiresInstMethodTableArg = requiresInstMTArg;
-
-    EE_TO_JIT_TRANSITION();
-
-    return result;
-}
-
-/*********************************************************************/
-CORINFO_METHOD_HANDLE CEEInfo::getInstantiatedEntry(
-    CORINFO_METHOD_HANDLE ftn,
-    CORINFO_METHOD_HANDLE* methodArg,
-    CORINFO_CLASS_HANDLE* classArg)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_PREEMPTIVE;
-    } CONTRACTL_END;
-
-    CORINFO_METHOD_HANDLE result = NULL;
-
-    JIT_TO_EE_TRANSITION();
-
-    *methodArg = NULL;
-    *classArg = NULL;
-
-    MethodDesc* pMD = GetMethod(ftn);
-    bool requiresInstMTArg = false;
-
-    if (pMD->IsInstantiatingStub())
-    {
-        result = (CORINFO_METHOD_HANDLE) pMD->GetWrappedMethodDesc();
-
-        if (pMD->HasMethodInstantiation())
-        {
-            *methodArg = ftn;
-        }
-        else
-        {
-            *classArg = (CORINFO_CLASS_HANDLE)pMD->GetMethodTable();
-        }
-    }
-
-    EE_TO_JIT_TRANSITION();
-
-    return result;
-}
-
 CORINFO_METHOD_HANDLE CEEInfo::getAsyncOtherVariant(
     CORINFO_METHOD_HANDLE ftn,
     bool* variantIsThunk)

From 852a5724f42f0783e464e6bae9a6d3a1a4abde5e Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Thu, 11 Jun 2026 21:50:42 +0900
Subject: [PATCH 30/33] Check the context directly

---
 src/coreclr/jit/importercalls.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index 258067957e2091..7c9242370b7bd6 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -9406,10 +9406,8 @@ void Compiler::impTransformDevirtualizedCall(GenTreeCall*            call,
 
                 if (unboxedEntrySig.hasTypeArg())
                 {
-                    if (unboxedEntrySig.sigInst.methInstCount != 0)
+                    if (((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
                     {
-                        assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) ==
-                               CORINFO_CONTEXTFLAGS_METHOD);
                         CORINFO_METHOD_HANDLE exactMethodHandle =
                             (CORINFO_METHOD_HANDLE)((SIZE_T)dcInfo->tokenLookupContext & ~CORINFO_CONTEXTFLAGS_MASK);
 
@@ -9418,6 +9416,9 @@ void Compiler::impTransformDevirtualizedCall(GenTreeCall*            call,
                     }
                     else
                     {
+                        assert(((SIZE_T)dcInfo->tokenLookupContext & CORINFO_CONTEXTFLAGS_MASK) ==
+                               CORINFO_CONTEXTFLAGS_CLASS);
+
                         // Get the method table from the boxed object.
                         //
                         // TODO-CallArgs-REVIEW: Use thisObj here? Differs by gtEffectiveVal.

From 176d6b9b9cd590823e91e8f484b02ae3ef8aec45 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sun, 21 Jun 2026 00:17:29 +0900
Subject: [PATCH 31/33] Rework unboxing stub and instantiating stub

---
 .../Compiler/DevirtualizationManager.cs       |  4 ++
 .../tools/Common/JitInterface/CorInfoImpl.cs  | 18 +++++---
 .../ReadyToRun/DevirtualizationManager.cs     | 14 +++++-
 src/coreclr/vm/jitinterface.cpp               | 43 +++++++++++++++----
 4 files changed, 63 insertions(+), 16 deletions(-)

diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
index a8a83cedec3bb5..9e23da8fb606b3 100644
--- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
+++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
@@ -157,6 +157,10 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
                                 else
                                 {
                                     impl = dimMethod;
+                                    if (originalDeclMethod.HasInstantiation)
+                                    {
+                                        impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation);
+                                    }
                                 }
                                 break;
                         }
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 013ffcffa692ae..1212919f9a6533 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -1476,8 +1476,11 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 
             bool isArray = decl.OwningType.IsInterface && objType.IsArray;
             bool isGenericVirtual = !isArray && decl.HasInstantiation;
+            MethodDesc instArgTarget = unboxingStub ? nonUnboxingImpl : impl;
+            bool requiresInstMethodDescArg = instArgTarget.RequiresInstMethodDescArg();
+            bool requiresInstMethodTableArg = instArgTarget.RequiresInstMethodTableArg();
 
-            if (!impl.AcquiresInstMethodTableFromThis())
+            if (requiresInstMethodDescArg || (requiresInstMethodTableArg && !unboxingStub))
             {
                 if (originalImpl.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                 {
@@ -1487,7 +1490,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                     return false;
                 }
 
-                if (originalImpl.IsSharedByGenericInstantiations)
+                if (originalImpl.IsRuntimeDeterminedExactMethod || originalImpl.IsSharedByGenericInstantiations)
                 {
                     // TODO: Support for runtime lookup
                     info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
@@ -1506,7 +1509,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
 #endif
             }
 
-            if (impl.RequiresInstMethodDescArg())
+            if (requiresInstMethodDescArg)
             {
                 if (unboxingStub)
                 {
@@ -1522,14 +1525,17 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info)
                 info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl));
 #endif
             }
-            else if (impl.RequiresInstMethodTableArg())
+            else if (requiresInstMethodTableArg)
             {
+                if (!unboxingStub)
+                {
 #if READYTORUN
-                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
+                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType));
 
 #else
-                info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
+                    info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType));
 #endif
+                }
             }
 
 #if READYTORUN
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs
index e6e329e5b32663..d6ebb33f99db18 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs
@@ -45,7 +45,8 @@ protected override MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefTyp
             //
             // Result method checking
             // 1. Ensure that the resolved result versions with the code, or is the decl method
-            // 2. When checking that the resolved result versions with the code, validate that all of the types
+            // 2. When devirtualizing to a default interface method, the resolved result method must version with the code.
+            // 3. When checking that the resolved result versions with the code, validate that all of the types
             //    From implType to the owning type of resolved result method also version with the code.
 
             bool declMethodCheckFailed;
@@ -161,6 +162,17 @@ protected override MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefTyp
 
             if (resolvedVirtualMethod != null)
             {
+                if (resolvedVirtualMethod.OwningType.IsInterface)
+                {
+                    if (_compilationModuleGroup.VersionsWithMethodBody(resolvedVirtualMethod))
+                    {
+                        return resolvedVirtualMethod;
+                    }
+
+                    devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_BUBBLE;
+                    return null;
+                }
+
                 // Validate that the inheritance chain for resolution is within version bubble
                 // The rule is somewhat tricky here.
                 // If the resolved method is the declMethod, then only types which derive from the
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index d047a0766f49dd..77535a69a7702b 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -8812,7 +8812,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     MethodTable* pExactMT = pApproxMT;
     bool isArray = false;
     bool isGenericVirtual = false;
-    
+
     if (pBaseMT->IsInterface() && pObjMT->IsArray())
     {
         isArray = true;
@@ -8827,20 +8827,40 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
     // This is generic virtual method devirtualization.
     if (!isArray && pBaseMD->HasMethodInstantiation())
     {
-        MethodDesc* pPrimaryMD = pDevirtMD;
+        MethodDesc* pPrimaryMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
 
         pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
             pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), true);
-        
+
         pInstantiatedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
             pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), false);
 
         isGenericVirtual = true;
     }
 
-    MethodDesc* pUnboxedDevirtMD = pDevirtMD->IsUnboxingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD;
+    MethodDesc* pInstArgMD = pDevirtMD;
+    bool isUnboxingStub = pDevirtMD->IsUnboxingStub();
+    bool instArgIsInstantiatingStub = pDevirtMD->IsInstantiatingStub();
 
-    if (!pUnboxedDevirtMD->AcquiresInstMethodTableFromThis())
+    if (isUnboxingStub || instArgIsInstantiatingStub)
+    {
+        pInstArgMD = pDevirtMD->GetWrappedMethodDesc();
+        if (pInstArgMD->IsInstantiatingStub())
+        {
+            instArgIsInstantiatingStub = true;
+        }
+    }
+
+    if (instArgIsInstantiatingStub &&
+        (TypeHandle::IsCanonicalSubtypeInstantiation(pInstantiatedMD->GetClassInstantiation()) ||
+         TypeHandle::IsCanonicalSubtypeInstantiation(pInstantiatedMD->GetMethodInstantiation())))
+    {
+        // TODO: Support for runtime lookup
+        info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+        return false;
+    }
+
+    if (pInstArgMD->RequiresInstMethodDescArg())
     {
         if (TypeHandle::IsCanonicalSubtypeInstantiation(pInstantiatedMD->GetClassInstantiation()))
         {
@@ -8856,15 +8876,20 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
             return false;
         }
-    }
 
-    if (pUnboxedDevirtMD->RequiresInstMethodDescArg())
-    {
         info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE) pInstantiatedMD;
         info->instParamLookup.constLookup.accessType = IAT_VALUE;
     }
-    else if (pUnboxedDevirtMD->RequiresInstMethodTableArg())
+    else if (pInstArgMD->RequiresInstMethodTableArg())
     {
+        if (!isUnboxingStub && TypeHandle::IsCanonicalSubtypeInstantiation(pExactMT->GetInstantiation()))
+        {
+            // If we end up with a shared MethodTable that is not exact,
+            // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup.
+            info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
+            return false;
+        }
+
         info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE) pExactMT;
         info->instParamLookup.constLookup.accessType = IAT_VALUE;
     }

From 5dec3737bfc73b76c9c8fd900fc90b91451a06b6 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sun, 21 Jun 2026 15:32:55 +0900
Subject: [PATCH 32/33] Address some verification issues

---
 .../Compiler/GenericCycleDetection/GraphBuilder.ForEach.cs  | 6 +++++-
 src/coreclr/vm/jitinterface.cpp                             | 4 ++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/coreclr/tools/Common/Compiler/GenericCycleDetection/GraphBuilder.ForEach.cs b/src/coreclr/tools/Common/Compiler/GenericCycleDetection/GraphBuilder.ForEach.cs
index 6224974cd05155..e0b946b9341249 100644
--- a/src/coreclr/tools/Common/Compiler/GenericCycleDetection/GraphBuilder.ForEach.cs
+++ b/src/coreclr/tools/Common/Compiler/GenericCycleDetection/GraphBuilder.ForEach.cs
@@ -59,7 +59,11 @@ private static void ForEachEmbeddedGenericFormalWorker(TypeDesc type, Instantiat
                         TypeDesc genericTypeDefinition = type.GetTypeDefinition();
                         Instantiation genericTypeParameters = genericTypeDefinition.Instantiation;
                         Instantiation genericTypeArguments = type.Instantiation;
-                        for (int i = 0; i < genericTypeArguments.Length; i++)
+
+                        // We have some negative IL tests that reference a generic type with more type arguments
+                        // than the type definition has type parameters.
+                        // Tolerate them as such a type can never load and therefore cannot form a cycle.
+                        for (int i = 0; i < genericTypeArguments.Length && i < genericTypeParameters.Length; i++)
                         {
                             var genericTypeParameter = (EcmaGenericParameter)genericTypeParameters[i];
                             TypeDesc genericTypeArgument = genericTypeArguments[i];
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 77535a69a7702b..69924540109242 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -14509,8 +14509,8 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
                 }
             }
 
-            // Strip off method instantiation for comparison if the method is generic virtual.
-            if (pDeclMethod->HasMethodInstantiation())
+            // Strip off method instantiation for comparison if the method is generic virtual or generic DIM.
+            if (pDeclMethod->HasMethodInstantiation() || pDeclMethod->IsInterface())
             {
                 if (pImplMethodRuntime != NULL)
                 {

From d0b8e364b80db67c893c33b3dc9d461652e80685 Mon Sep 17 00:00:00 2001
From: Steven He <hez2010@outlook.com>
Date: Sun, 21 Jun 2026 15:50:32 +0900
Subject: [PATCH 33/33] Add file header

---
 .../devirtualization/dim_devirtualization.cs                   | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
index cb67af966d11cd..b71856d12b2df5 100644
--- a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
+++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirtualization.cs
@@ -1,3 +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;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
