Skip to content

Conversation

@hez2010
Copy link
Contributor

@hez2010 hez2010 commented Nov 27, 2025

Enable devirtualization support for generic virtual methods.

When we see a base method having a method instantiation, we use FindOrCreateAssociatedMethodDesc to obtain the devirted method. Then we need insert the lookup node to the inst param.

Also introduced a jit knob so that it can be turned off at any time.

AOT support is not included in this PR, which needs additional work in managed type system.

Example:

public class IntProcessor : VirtualGenericClass, IVritualGenericInterface
{
    public override void Process<T>(T item)
    {
        Console.WriteLine(item.ToString());
    }
}

public interface IVritualGenericInterface
{
    void Process<T>(T item) where T : notnull;
}

public static void Test<T>(IVritualGenericInterface ifce, T item) where T : notnull
{
    ifce.Process(item);
}

public static void Test<T>(VirtualGenericClass baseClass, T item) where T : notnull
{
    baseClass.Process(item);
}

static void Test()
{
    IVritualGenericInterface i = new IntProcessor();
    Test(i, 42);
    Test(i, "test");

    VirtualGenericClass c = new IntProcessor();
    Test(c, 42);
    Test(c, "test");
}

Codegen diff:

  G_M24707_IG01:  ;; offset=0x0000
-        push     rdi
-        push     rsi
-        push     rbp
         push     rbx
-        sub      rsp, 40
-                                                 ;; size=8 bbWeight=1 PerfScore 4.25
- G_M24707_IG02:  ;; offset=0x0008
-        mov      rbx, 0x7FFC21E046E0      ; Program+IntProcessor
-        mov      rcx, rbx
-        call     CORINFO_HELP_NEWSFAST
-        mov      rsi, rax
-        mov      rcx, rsi
-        mov      rdi, 0x7FFC21E044C8      ; Program+IVritualGenericInterface
-        mov      rdx, rdi
-        mov      r8, 0x7FFC21E04EA0      ; token handle
-        call     CORINFO_HELP_VIRTUAL_FUNC_PTR
-        mov      rcx, rsi
-        mov      edx, 42
-        call     rax
-        mov      rbp, 0x1AC49ACE518      ; 'test'
-        mov      rcx, rsi
-        mov      rdx, rdi
-        mov      r8, 0x7FFC21E051C0      ; token handle
-        call     CORINFO_HELP_VIRTUAL_FUNC_PTR
-        mov      rcx, rsi
-        mov      rdx, rbp
-        call     rax
-        mov      rcx, rbx
-        call     CORINFO_HELP_NEWSFAST
-        mov      rbx, rax
-        mov      rcx, rbx
-        mov      rsi, 0x7FFC21E042F8      ; Program+VirtualGenericClass
-        mov      rdx, rsi
-        mov      r8, 0x7FFC21E052B8      ; token handle
-        call     CORINFO_HELP_VIRTUAL_FUNC_PTR
-        mov      rcx, rbx
-        mov      edx, 42
-        call     rax
+        sub      rsp, 32
+                                                 ;; size=5 bbWeight=1 PerfScore 1.25
+ G_M24707_IG02:  ;; offset=0x0005
+        mov      ecx, 42
+        call     [System.Number:Int32ToDecStr(int):System.String]
+        mov      rcx, rax
+        call     [System.Console:WriteLine(System.String)]
+        mov      rbx, 0x1E66CB8E518      ; 'test'
         mov      rcx, rbx
-        mov      rdx, rsi
-        mov      r8, 0x7FFC21E055D8      ; token handle
-        call     CORINFO_HELP_VIRTUAL_FUNC_PTR
+        call     [System.Console:WriteLine(System.String)]
+        mov      ecx, 42
+        call     [System.Number:Int32ToDecStr(int):System.String]
+        mov      rcx, rax
+        call     [System.Console:WriteLine(System.String)]
         mov      rcx, rbx
-        mov      rdx, rbp
-        call     rax
+        call     [System.Console:WriteLine(System.String)]
         nop
-                                                 ;; size=183 bbWeight=1 PerfScore 25.25
- G_M24707_IG03:  ;; offset=0x00BF
-        add      rsp, 40
+                                                 ;; size=69 bbWeight=1 PerfScore 20.00
+ G_M24707_IG03:  ;; offset=0x004A
+        add      rsp, 32
         pop      rbx
-        pop      rbp
-        pop      rsi
-        pop      rdi
         ret
-                                                 ;; size=9 bbWeight=1 PerfScore 3.25
+                                                 ;; size=6 bbWeight=1 PerfScore 1.75

Contributes to #112596

cc: @dotnet/jit-contrib

Copilot AI review requested due to automatic review settings November 27, 2025 17:12
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Nov 27, 2025
@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 27, 2025
@dotnet-policy-service
Copy link
Contributor

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

Copilot finished reviewing on behalf of hez2010 November 27, 2025 17:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enables devirtualization support for generic virtual methods in the JIT compiler, allowing calls to generic virtual methods to be devirtualized when the exact type is known at JIT time. This optimization eliminates virtual dispatch overhead and enables further optimizations like inlining.

Key changes:

  • Removes the assertion that previously blocked generic method devirtualization
  • Generalizes array interface devirtualization to support generic virtual methods by renaming wasArrayInterfaceDevirt to needsMethodContext
  • Adds runtime lookup support for generic method instantiation parameters

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/coreclr/vm/jitinterface.cpp Removes assertion blocking generic method devirtualization and adds logic to handle generic virtual methods using FindOrCreateAssociatedMethodDesc
src/coreclr/inc/corinfo.h Renames wasArrayInterfaceDevirt to needsMethodContext to generalize the field meaning
src/coreclr/jit/jitconfigvalues.h Adds JitEnableGenericVirtualDevirtualization configuration flag to control the feature
src/coreclr/jit/gentree.h Adds IsGenericVirtual() helper method to identify generic virtual method calls
src/coreclr/jit/gentree.cpp Updates IsDevirtualizationCandidate() to include generic virtual methods (non-AOT only)
src/coreclr/jit/importercalls.cpp Implements devirtualization logic for generic virtual methods including runtime lookup handling, updates comments and variable names, and introduces DEVIRT label for control flow
src/coreclr/jit/inline.h Renames arrayInterface field to needsMethodContext in InlineCandidateInfo struct
src/coreclr/jit/indirectcalltransformer.cpp Updates to use renamed needsMethodContext field
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Updates managed struct definition to match renamed field
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Updates to use renamed field in managed implementation
src/coreclr/tools/superpmi/superpmi-shared/agnostic.h Updates SuperPMI data structure with renamed field
src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp Updates SuperPMI recording/replay to use renamed field

@hez2010
Copy link
Contributor Author

hez2010 commented Nov 28, 2025

@MihuBot

@hez2010
Copy link
Contributor Author

hez2010 commented Nov 29, 2025

@MihuBot
Just check again to make sure we properly preserved the runtime lookup calls for shared generics.

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.

2 participants