Skip to content

Conversation

@hez2010
Copy link
Contributor

@hez2010 hez2010 commented Jan 14, 2026

Implement the support for GVM devirtualization in managed type system.

It shares the same issue in #122023 where we are still not able to devirt shared GVMs due to lacking a proper generic context, so let's do the non-shared case first.

NativeAOT still not supported yet as it requires some work in the JIT to stop spilling the helper call for fat pointers.

Contributes to #112596

/cc: @MichalStrehovsky @jakobbotsch

Copilot AI review requested due to automatic review settings January 14, 2026 17:22
@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 Jan 14, 2026
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jan 14, 2026
@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.

@hez2010 hez2010 changed the title Devirtualize non-shared GVMs in R2R JIT: Devirtualize non-shared GVMs in R2R Jan 14, 2026
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 of non-shared Generic Virtual Methods (GVMs) in ReadyToRun (R2R) compilation by recording the compile-time method handle before embedding it into a lookup, allowing it to be used for devirtualization later. Shared GVMs remain unsupported due to lacking a proper generic context.

Changes:

  • Added IsConstructed property to Instantiation to determine if all type parameters are concrete types
  • Removed the early rejection of GVM devirtualization in R2R compilation
  • Enhanced devirtualization logic to properly handle generic method instantiations
  • Extended JIT's devirtualization candidate detection to support R2R virtual function pointers
  • Updated JIT-EE interface version GUID to reflect the API change

Reviewed changes

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

Show a summary per file
File Description
src/coreclr/tools/Common/TypeSystem/Common/Instantiation.cs Adds IsConstructed property to check if instantiation contains only concrete types (no generic parameters)
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Removes CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL enum value as GVM devirtualization is now supported
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Removes early rejection check for generic virtual method devirtualization
src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs Enhances logic to instantiate generic methods and adds check to block shared GVMs
src/coreclr/jit/importer.cpp Records compile-time method handle for R2R virtual function pointer helper calls
src/coreclr/jit/gentree.h Adds compileTimeMethodHandle union field and extends IsGenericVirtual to include R2R helper
src/coreclr/jit/gentree.cpp Adds R2R-specific logic to extract method handle for devirtualization candidates
src/coreclr/jit/compiler.cpp Removes error message case for the deleted enum value
src/coreclr/inc/jiteeversionguid.h Updates JIT-EE version identifier GUID for interface change
src/coreclr/inc/corinfo.h Removes CORINFO_DEVIRTUALIZATION_FAILED_GENERIC_VIRTUAL enum value

@hez2010
Copy link
Contributor Author

hez2010 commented Jan 16, 2026

It hit a weird assertion:

Assert failure(PID 4616 [0x00001208], Thread: 3532 [0x0dcc]): Verify_VirtualFunctionOverride Decl Method 'instance int32 [crossgen2smoke] Program+BaseClass::MyGvm()' on type 'BaseClass' is 'instance int32 [crossgen2smoke] Program+BaseClass::MyGvm()'(actual) instead of expected 'instance int32 [crossgen2smoke] Program+BaseClass::MyGvm()'(from compiler)

CORECLR! LoadDynamicInfoEntry + 0x15EC (0x00007ff9`b8340c6c)
CORECLR! Module::FixupNativeEntry + 0x2A3 (0x00007ff9`b8221383)
CORECLR! Module::FixupDelayListAux<Module *,int (__cdecl Module::*)(READYTORUN_IMPORT_SECTION *,unsigned __int64,unsigned __int64 *,int)> + 0x674 (0x00007ff9`b84dcf04)
CORECLR! ReadyToRunInfo::GetEntryPoint + 0x4BE (0x00007ff9`b84e08ce)
CORECLR! MethodDesc::GetPrecompiledR2RCode + 0x11A (0x00007ff9`b842f20a)
CORECLR! MethodDesc::GetPrecompiledCode + 0xFA (0x00007ff9`b842ee3a)
CORECLR! MethodDesc::PrepareILBasedCode + 0x32F (0x00007ff9`b843252f)
CORECLR! MethodDesc::PrepareCode + 0x129 (0x00007ff9`b8432199)
CORECLR! CodeVersionManager::PublishVersionableCodeIfNecessary + 0x4F6 (0x00007ff9`b82812b6)
CORECLR! MethodDesc::DoPrestub + 0xD03 (0x00007ff9`b842b3b3)
    File: D:\a\_work\1\s\src\coreclr\vm\jitinterface.cpp:14372
    Image: C:\h\w\AA800A0D\p\corerun.exe

aren't the two instance int32 [crossgen2smoke] Program+BaseClass::MyGvm() identical?

@hez2010
Copy link
Contributor Author

hez2010 commented Jan 16, 2026

It seems that the failure only happens when specifying --verify-type-and-field-layout in crossgen2.

@hez2010
Copy link
Contributor Author

hez2010 commented Jan 16, 2026

It turns out to be a verification-only issue. We need to use the method definition for comparison during verification instead.

@hez2010
Copy link
Contributor Author

hez2010 commented Jan 17, 2026

Tests are passing. Please take a look. @MichalStrehovsky

Copy link
Member

@MichalStrehovsky MichalStrehovsky left a comment

Choose a reason for hiding this comment

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

Cc @davidwrighton for the JitInterface.cpp change, Cc @jakobbotsch for the RyuJIT change

MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);
// We need to bring the original instantiation back so that we can still try devirtualizing
// when the method is a generic virtual method
if (originalDeclMethod.HasInstantiation)
Copy link
Member

Choose a reason for hiding this comment

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

Could you move this right under the impl = implType.FindVirtualFunctionTargetMethodOnObjectType(declMethod); line as if (impl != null && originalDeclMethod.HasInstantiation) to reduce the diff in this PR and nesting?

The fact that FindVirtualFunctionTargetMethodOnObjectType will strip the method instantiation is a nuisance. I'd like to fix these (there's a couple more resolution APIs that annoying do this) at some point. But let's not perturb the git history for this wart.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

FindVirtualFunctionTargetMethodOnObjectType doesn't strip method instantiation. ResolveInterfaceMethodTargetWithVariance and FindMethodOnTypeWithMatchingTypicalMethod do.

@hez2010
Copy link
Contributor Author

hez2010 commented Jan 23, 2026

@MichalStrehovsky
Addressed feedback comments. Please take another look.

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