From 61a278fdb44c5796dff07531cd585f4474c0e0ff Mon Sep 17 00:00:00 2001 From: Steven He Date: Thu, 28 May 2026 21:32:01 +0900 Subject: [PATCH 01/23] 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 Date: Thu, 28 May 2026 21:43:40 +0900 Subject: [PATCH 02/23] 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 Date: Thu, 28 May 2026 22:30:16 +0900 Subject: [PATCH 03/23] 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 Date: Thu, 28 May 2026 22:48:30 +0900 Subject: [PATCH 04/23] 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 Date: Thu, 28 May 2026 23:15:16 +0900 Subject: [PATCH 05/23] 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 Date: Thu, 28 May 2026 23:17:46 +0900 Subject: [PATCH 06/23] 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 Date: Thu, 28 May 2026 23:18:31 +0900 Subject: [PATCH 07/23] 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 Date: Thu, 28 May 2026 23:28:35 +0900 Subject: [PATCH 08/23] 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 Date: Thu, 28 May 2026 23:29:05 +0900 Subject: [PATCH 09/23] 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 Date: Thu, 28 May 2026 23:39:53 +0900 Subject: [PATCH 10/23] 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 Date: Thu, 28 May 2026 23:49:54 +0900 Subject: [PATCH 11/23] 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 } } + /// + /// Gets a value indicating whether this is a shared method body. + /// Similar to but this doesn't consider the owning type's generic instantiation. + /// + public bool IsMethodSharedByGenericInstantiations + { + get + { + foreach (TypeDesc type in Instantiation) + { + if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + return true; + } + } + + return false; + } + } + /// /// 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 Date: Thu, 28 May 2026 23:50:36 +0900 Subject: [PATCH 12/23] 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 but this doesn't consider the owning type's generic instantiation. /// - public bool IsMethodSharedByGenericInstantiations + public bool IsSharedByGenericMethodInstantiations { get { From dca1834326efd3835f3e6ff998ce4c2125bd3728 Mon Sep 17 00:00:00 2001 From: Steven He Date: Fri, 29 May 2026 01:06:36 +0900 Subject: [PATCH 13/23] 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 +{ + 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 { } + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var m = new M(); + if (((IM)m).UseDefaultM) + { + IM.DefaultM(42); + return; + } + else + { + ((IM)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 @@ + + + 1 + + + + + + + + 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 where T : IComparable +{ + T GetAt(int i, T[] tx) => tx[i]; +} + +class C : I +{ +} + +public static class Program +{ + private static string[] tx = new string[] { "test" }; + + [Fact] + public static void TestEntryPoint() + { + I 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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class Dummy { } + +class C : I, I, I +{ + string I.DefaultTypeOf() => "C.Dummy"; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("String", dcs); + var dos = ((I)c).DefaultTypeOf(); + Assert.Equal("Object", dos); + var dds = ((I)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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ + public string DefaultTypeOf() => "C.String"; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ + public string DefaultTypeOf() => "C." + typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf(); +} + +struct C : I +{ + public string DefaultTypeOf() => "C." + typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)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 @@ + + + 1 + + + + + + + + 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 +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public string DefaultTypeOf() => typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + 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 @@ + + + 1 + + + + + + + + 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 +{ + public static string DefaultTypeOf() => typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var dcs = C.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 @@ + + + 1 + + + + + + + + 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 +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class Dummy { } + +struct C : I, I, I +{ + string I.DefaultTypeOf() => "C.Dummy"; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("String", dcs); + var dos = ((I)c).DefaultTypeOf(); + Assert.Equal("Object", dos); + var dds = ((I)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 @@ + + + 1 + + + + + + + + From 2582ba6065e7b4c5056ed05c39d9329476e65c1e Mon Sep 17 00:00:00 2001 From: Steven He Date: Sat, 30 May 2026 00:07:51 +0900 Subject: [PATCH 14/23] 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 @@ 1 - + 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 @@ 1 - + 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 @@ 1 - + 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 @@ 1 - + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ + + + 1 + + + + + + + + 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - 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 @@ - - - 1 - - - - - - - - From 800aa20f25514f2ba0abb72d8c9bc9f06ac5371f Mon Sep 17 00:00:00 2001 From: Steven He Date: Sat, 30 May 2026 10:45:17 +0900 Subject: [PATCH 15/23] 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 } } - /// - /// Gets a value indicating whether this is a shared method body. - /// Similar to but this doesn't consider the owning type's generic instantiation. - /// - public bool IsSharedByGenericMethodInstantiations - { - get - { - foreach (TypeDesc type in Instantiation) - { - if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - return true; - } - } - - return false; - } - } - /// /// 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 Date: Sat, 30 May 2026 11:47:14 +0900 Subject: [PATCH 16/23] 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 Date: Sat, 30 May 2026 12:05:19 +0900 Subject: [PATCH 17/23] 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 Date: Sat, 30 May 2026 12:08:05 +0900 Subject: [PATCH 18/23] 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 Date: Sat, 30 May 2026 14:04:53 +0900 Subject: [PATCH 19/23] 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 } } + /// + /// Gets a value indicating whether this is a shared method body. + /// Similar to but this doesn't consider the owning type's generic instantiation. + /// + public bool IsSharedByGenericMethodInstantiations + { + get + { + foreach (TypeDesc type in Instantiation) + { + if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + return true; + } + } + + return false; + } + } + /// /// 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 Date: Sat, 30 May 2026 14:15:40 +0900 Subject: [PATCH 20/23] 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 } } - /// - /// Gets a value indicating whether this is a shared method body. - /// Similar to but this doesn't consider the owning type's generic instantiation. - /// - public bool IsSharedByGenericMethodInstantiations - { - get - { - foreach (TypeDesc type in Instantiation) - { - if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - return true; - } - } - - return false; - } - } - /// /// 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 Date: Sat, 30 May 2026 14:27:37 +0900 Subject: [PATCH 21/23] 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 Date: Sat, 30 May 2026 16:10:18 +0900 Subject: [PATCH 22/23] 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 Date: Sat, 30 May 2026 16:17:21 +0900 Subject: [PATCH 23/23] 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));