Skip to content

Support devirtualization for virtual methods that require runtime lookups#129806

Open
hez2010 wants to merge 16 commits into
dotnet:mainfrom
hez2010:devirt-runtime-lookups
Open

Support devirtualization for virtual methods that require runtime lookups#129806
hez2010 wants to merge 16 commits into
dotnet:mainfrom
hez2010:devirt-runtime-lookups

Conversation

@hez2010

@hez2010 hez2010 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Add support for devirtualizing virtual methods that require a runtime lookup. In this case we can't avoid the expensive runtime lookup, but at least the callee now can be devirtualized and inlined, so that they can benefit from the downstream optimizations like escape analysis, struct promotion and etc.

When we see an inexact instantiating stub on an exact class, we compute a runtime lookup against the shared generic token of the virtual method.

public interface IProcessor
{
    object? Process<T>(T value);
}

public class PrintProcessor : IProcessor
{
    public object? Process<T>(T value)
    {
        return value;
    }
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine(Call("hello"));
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static object? Call<T>(T value) where T : class
    {
        IProcessor processor = new PrintProcessor();
        return processor.Process(value);
    }
}

Codegen for Call:

Before:

G_M47477_IG01:  ;; offset=0x0000
       push     rdi
       push     rsi
       push     rbx
       sub      rsp, 48
       mov      qword ptr [rsp+0x28], rcx
       mov      rbx, rcx
       mov      rsi, rdx
                                                ;; size=18 bbWeight=1 PerfScore 4.75
G_M47477_IG02:  ;; offset=0x0012
       mov      rcx, 0x7FF9258BB130      ; PrintProcessor
       call     CORINFO_HELP_NEWSFAST
       mov      rdi, rax
       mov      rcx, qword ptr [rbx+0x48]
       mov      r8, qword ptr [rcx+0x10]
       test     r8, r8
       je       SHORT G_M47477_IG05
                                                ;; size=31 bbWeight=1 PerfScore 6.75
G_M47477_IG03:  ;; offset=0x0031
       mov      rcx, rdi
       mov      rdx, 0x7FF9258BAF08      ; IProcessor
       call     CORINFO_HELP_VIRTUAL_FUNC_PTR
       mov      rcx, rdi
       mov      rdx, rsi
       call     rax
       nop
                                                ;; size=27 bbWeight=1 PerfScore 5.25
G_M47477_IG04:  ;; offset=0x004C
       add      rsp, 48
       pop      rbx
       pop      rsi
       pop      rdi
       ret
                                                ;; size=8 bbWeight=1 PerfScore 2.75
G_M47477_IG05:  ;; offset=0x0054
       mov      rcx, rbx
       mov      rdx, 0x7FF9258E0DE8      ; global ptr
       call     CORINFO_HELP_RUNTIMEHANDLE_METHOD
       mov      r8, rax
       jmp      SHORT G_M47477_IG03
                                                ;; size=23 bbWeight=0.20 PerfScore 0.75

After:

G_M47477_IG01:  ;; offset=0x0000
       sub      rsp, 40
       mov      qword ptr [rsp+0x20], rcx
                                                ;; size=9 bbWeight=1 PerfScore 1.25
G_M47477_IG02:  ;; offset=0x0009
       mov      rax, qword ptr [rcx+0x48]
       cmp      qword ptr [rax+0x08], 24
       jle      SHORT G_M47477_IG03
                                                ;; size=11 bbWeight=1 PerfScore 5.00
G_M47477_IG03:  ;; offset=0x0014
       mov      rax, rdx
                                                ;; size=3 bbWeight=1 PerfScore 0.25
G_M47477_IG04:  ;; offset=0x0017
       add      rsp, 40
       ret
                                                ;; size=5 bbWeight=1 PerfScore 1.25

Contributes to #112596

Copilot AI review requested due to automatic review settings June 24, 2026 16:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the area-crossgen2-coreclr only use for closed issues label Jun 24, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jun 24, 2026
@hez2010

hez2010 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

@MihuBot -nuget

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@hez2010

hez2010 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@MihuBot -nuget -dependsOn 128702

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings July 1, 2026 11:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/importercalls.cpp
Copilot AI review requested due to automatic review settings July 1, 2026 11:42
@hez2010 hez2010 requested a review from MichalStrehovsky as a code owner July 1, 2026 11:46
@hez2010

hez2010 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

This is now ready for review. It's the last piece of the whole story (at least for coreclr).

cc: @jakobbotsch @davidwrighton @MichalStrehovsky

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Comment thread src/coreclr/vm/jitinterface.cpp
Copilot AI review requested due to automatic review settings July 1, 2026 11:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment on lines +2774 to 2787
object helperArg;
if (entryKind == DictionaryEntryKind.DevirtualizedMethodDescSlot)
{
var methodIL = HandleToObject(pResolvedToken.tokenScope);
MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget();
// We shouldn't be needing shared generics in resumption stubs - generics info should all be stored in the continuation
Debug.Assert(MethodBeingCompiled is not AsyncResumptionStub);
_compilation.NodeFactory.DetectGenericCycles(MethodBeingCompiled, sharedMethod);
helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken, out bool strippedInstantiation), constrainedType, unboxing: false, genericContextObject: sharedMethod, forceOwningTypeFromMethodDesc: strippedInstantiation);
Debug.Assert(templateMethod != null);
MethodDesc tokenMethod = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken);
if (tokenMethod.HasInstantiation)
{
templateMethod = _compilation.TypeSystemContext.GetInstantiatedMethod(templateMethod.GetMethodDefinition(), tokenMethod.Instantiation);
}
_compilation.NodeFactory.DetectGenericCycles(MethodBeingCompiled, templateMethod);
ModuleToken templateMethodToken =
_compilation.NodeFactory.Resolver.GetModuleTokenForMethod(templateMethod.GetTypicalMethodDefinition(), allowDynamicallyCreatedReference: false, throwIfNotFound: true);
helperArg = new MethodWithToken(templateMethod, templateMethodToken, constrainedType: null, unboxing: false, genericContextObject: null);
}
Comment thread src/coreclr/jit/importercalls.cpp
@hez2010

hez2010 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@MihuBot -nuget

Copilot AI review requested due to automatic review settings July 1, 2026 14:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Comment thread src/coreclr/jit/importercalls.cpp
Comment thread src/coreclr/vm/jitinterface.cpp
Comment thread src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@jakobbotsch jakobbotsch added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI and removed area-crossgen2-coreclr only use for closed issues labels Jul 1, 2026
@jakobbotsch

Copy link
Copy Markdown
Member

/azp run runtime-coreclr outerloop, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Copilot AI review requested due to automatic review settings July 2, 2026 16:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/importercalls.cpp
Comment thread src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants