Skip to content

Use dispatch cells for generic virtual method dispatch#129609

Open
MichalStrehovsky wants to merge 5 commits into
dotnet:mainfrom
MichalStrehovsky:gvmdispatch
Open

Use dispatch cells for generic virtual method dispatch#129609
MichalStrehovsky wants to merge 5 commits into
dotnet:mainfrom
MichalStrehovsky:gvmdispatch

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

This puts generic virtual method dispatch on the same plan as interface method dispatch.

Benefits:

  • The cost of generic virtual methods went down (still not quite same as interface calls due to fat pointers, but closer)
    • Monomorpic GVM callsite: Before: ~2.45 ns/call. After: 1.74 ns/call
    • Polymorphic GVM callsite: Before: ~2.45 ns/call. After: 2.10 ns/call.
  • GVM methods no longer implicitly considered targets of reflection due to LDTOKEN used as implementation detail.
  • The weird RuntimeMethodHandle for async method variants that reflection should never see is gone

This is three commits:

  • First just deletes some dead code I noticed.
  • Second moves some of the dispatch resolution to CoreLib. We've been breaking the "interface dispatch lives in Runtime.Base" boundary for a while. This puts us closer to it living in CoreLib. We can move rest of the interface resolution later, didn't want to perturb this too much. The cache itself stays in Runtime.Base because the assembly helper can only handle one. (We can decide the assembly helper is also owned by CoreLib I guess, but we don't currently have such layer.) I think copilot could easily undo this if this is not the split we want.
  • Third commit switches the GVM calls to use the dispatch cell. We need a resolve helper variant because GVM dispatch is a resolver due to fat calls, not a dispatcher.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

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

This PR reworks NativeAOT generic virtual method (GVM) dispatch to use dispatch cells (aligning it more closely with interface dispatch), adds new ReadyToRun sections/nodes to emit GVM dispatch-cell metadata, and updates the JIT/AOT toolchain to consume the new helper + lookup shapes.

Changes:

  • Introduces GVM dispatch-cell sections/metadata in the compiler output and routes GVM lookups through a dispatch-cell-based helper.
  • Refactors “interface dispatch cell” infrastructure into a generalized “dispatch cell” concept used for both interface dispatch and GVM dispatch.
  • Moves parts of dispatch resolution into CoreLib (classlib function table) and adds new per-architecture “resolve” helper entrypoints.

Reviewed changes

Copilot reviewed 70 out of 70 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/coreclr/tools/Common/Internal/Runtime/RuntimeConstants.cs Introduces GvmDispatchCellFlags for encoding async-variant bit in GVM dispatch-cell metadata.
src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs Adds new ReadyToRun section types for GVM dispatch-cell regions.
src/coreclr/tools/Common/Internal/Runtime/InterfaceDispatchCellCachePointerFlags.cs Removes unused interface-dispatch cache-pointer flags enum.
src/coreclr/tools/Common/Internal/Runtime/DispatchCell.cs Adds shared dispatch-cell structs (including dynamic dispatch-cell layouts).
src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs Allocates FixupSignatureKind.GvmDispatchCell.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs Adds ordered node kinds for GVM dispatch-cell sections.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/GVMDependenciesNode.cs Marks compilation with an analysis characteristic when GVMs are present.
src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Switches call-info emission to use dispatch-cell helpers/const lookups for interface+GVM cases.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs Uses dispatch-cell symbol node instead of interface-only dispatch cell.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs Consolidates cell cache from interface-only to general dispatch cells.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj Adds new dispatch-cell nodes/sections; removes old interface-dispatch-cell node source.
src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs Updates dependency scanning for dispatch-cell-based GVM/interface lookups.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs Tracks generalized dispatch cells; emits new GVM dispatch-cell sections into the R2R header.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs Maps GVMLookupForSlot to the new RhpDispatchResolve entrypoint.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunHelperNode.cs Emits dispatch-cell references for interface dispatch helper.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunGenericHelperNode.cs Routes generic helper ID from VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs Emits dispatch-cell references for interface dispatch helper.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs Routes generic helper ID from VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64ReadyToRunHelperNode.cs Emits dispatch-cell references for interface dispatch helper.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_RiscV64/RiscV64ReadyToRunGenericHelperNode.cs Routes generic helper ID from VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64ReadyToRunHelperNode.cs Emits dispatch-cell references for interface dispatch helper.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64ReadyToRunGenericHelperNode.cs Routes generic helper ID from VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_ARM64/ARM64ReadyToRunHelperNode.cs Emits dispatch-cell references for interface dispatch helper.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_ARM64/ARM64ReadyToRunGenericHelperNode.cs Routes generic helper ID from VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs Emits dispatch-cell references for interface dispatch helper.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs Routes generic helper ID from VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/RuntimeMethodHandleNode.cs Removes async-variant encoding from runtime method handle node emission.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs Renames helper ID VirtualDispatchCell to DispatchCell.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs Updates generic-lookup signatures/comparisons to use dispatch-cell lookup kind.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.NativeLayout.cs Adds native-layout dictionary slot node for GVM dispatch-cell fixup signatures.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs Generalizes “virtual dispatch cell” generic lookup result into “dispatch cell”.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs Generalizes dispatch-cell node cache/factory API.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs Adds NativeLayoutGvmDispatchGenericDictionarySlotNode implementation.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchCellInfoSectionNode.cs Updates section emission to operate on generalized dispatch cells (filters out GVM instantiations).
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GvmDispatchCellInfoSectionNode.cs Adds new section emitting GVM dispatch-cell info (token+flags+instantiation).
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs Renames/expands dispatch-cell lookup result to support interface and GVM.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DispatchCellSectionNode.cs Splits dispatch-cell BSS into interface vs GVM sections via filtering.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DispatchCellNode.cs Generalizes interface dispatch cell node into a dispatch cell node.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DelegateCreationInfo.cs Switches delegate creation for GVM/interface targets to dispatch-cell-based lookup.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs Updates runtime-lookup decision for the new dispatch-cell helper ID.
src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Links in shared dispatch-cell type(s) and adds a ResolveDispatch export stub.
src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/Dispatch.cs Adds Test.CoreLib ResolveDispatch export (currently stubbed).
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj Adds AnalysisCharacteristicAttribute compilation input.
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.Metadata.cs Updates GVM token handle construction call signature.
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs Removes async-variant handling from runtime-method-handle ldtoken cache machinery.
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs Reworks GVM resolution input shape (declaring type + handle + instantiation list + async flag).
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs Adds GenericVirtualMethodsPresent analysis characteristic gate and new callback signature.
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs Allocates dynamic dispatch-cell layouts for interface cells and new GVM dispatch cells.
src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs Removes async-variant flag from handle layout; adds helper to resolve GVM targets via callbacks.
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/TypeLoaderExports.cs Removes old GVMLookupForSlot cache-based implementation.
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs Updates GVM delegate initialization to go through dispatch-cell-based resolution.
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj Links dispatch-cell types and adds CoreLib ResolveDispatch implementation source.
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Dispatch.cs Implements ResolveDispatch and static/dynamic dispatch-cell resolution.
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs Updates open-method resolver to resolve GVM targets via the new handle helper.
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/TypeLoaderCallbacks.cs Changes callback signature for resolving GVM targets (more explicit components).
src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml Adds compat suppressions for new public dispatch-cell types.
src/coreclr/nativeaot/Runtime/riscv64/DispatchResolve.S Adds RhpDispatchResolve entrypoint (returns target rather than dispatching).
src/coreclr/nativeaot/Runtime/loongarch64/DispatchResolve.S Adds RhpDispatchResolve entrypoint (returns target rather than dispatching).
src/coreclr/nativeaot/Runtime/i386/DispatchResolve.asm Adds x86 RhpDispatchResolve (cache probe + fallback to worker).
src/coreclr/nativeaot/Runtime/EHHelpers.cpp Teaches EH helper classification about RhpDispatchResolve AV locations/addresses.
src/coreclr/nativeaot/Runtime/arm64/DispatchResolve.S Factors common macro + adds RhpDispatchResolve variant (returning target).
src/coreclr/nativeaot/Runtime/arm64/DispatchResolve.asm Adds RhpDispatchResolve variant and calls RhpCidResolve_Worker for return-only slow path.
src/coreclr/nativeaot/Runtime/arm/DispatchResolve.S Adds ARM32 RhpDispatchResolve with a barrier before reading cached code.
src/coreclr/nativeaot/Runtime/amd64/DispatchResolve.S Adds RhpDispatchResolve macro variant (returning target).
src/coreclr/nativeaot/Runtime/amd64/DispatchResolve.asm Adds RhpDispatchResolve macro variant and optimized slow path.
src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs Adds ClassLibFunctionId.ResolveDispatch entry.
src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs Routes cache misses to classlib ResolveDispatch and exports RhpCidResolve_Worker.
src/coreclr/nativeaot/Bootstrap/main.cpp Exposes ResolveDispatch in the classlib function table.
src/coreclr/jit/importer.cpp Switches NativeAOT GVM ldvirtftn import to pass dispatch cell instead of runtime method handle.
src/coreclr/inc/corinfo.h Updates helper comment to document dispatch-cell argument for GVM lookup helper.

Comment on lines +15 to +22
internal static class Dispatch
{
[RuntimeExport("ResolveDispatch")]
internal static unsafe MethodTable* ResolveDispatch(object pObject, DispatchCell* pCell)
{
// Assume this is a static dispatch cell first
foreach (TypeManagerHandle typeManager in StartupCodeHelpers.GetLoadedModules())
{
Comment on lines +23 to +33
var pDispatchCellRegion = (DispatchCell*)RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.InterfaceDispatchCellRegion, out int length);
if (pCell >= pDispatchCellRegion && pCell < (byte*)pDispatchCellRegion + length)
{
return ResolveStaticInterfaceDispatch(typeManager, pObject, (nint)(pCell - pDispatchCellRegion));
}

pDispatchCellRegion = (DispatchCell*)RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.GvmDispatchCellRegion, out length);
if (pCell >= pDispatchCellRegion && pCell < (byte*)pDispatchCellRegion + length)
{
return ResolveGvmDispatch(typeManager, pObject, (nint)(pCell - pDispatchCellRegion));
}
Comment thread src/coreclr/tools/Common/Internal/Runtime/DispatchCell.cs
Comment thread src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/Dispatch.cs
Comment on lines +32 to +38
ld t0, 0(a0)

ld t1, 0(a1) // load cached MethodTable
bne t0, t1, LOCAL_LABEL(ResolveInterfaceMethod)

ld a0, 8(a1) // return cached monomorphic resolved code address
ret
Comment on lines +31 to +37
ld.d $t0, $a0, 0

ld.d $t1, $a1, 0 // load cached MethodTable
bne $t0, $t1, LOCAL_LABEL(ResolveInterfaceMethod)

ld.d $a0, $a1, 8 // return cached monomorphic resolved code address
jirl $r0, $ra, 0
@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines

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

Copilot AI review requested due to automatic review settings June 24, 2026 04:29

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 70 out of 70 changed files in this pull request and generated 4 comments.

Comment thread src/coreclr/tools/Common/Internal/Runtime/DispatchCell.cs
Comment on lines +44 to +46
private static nint GVMLookupForSlot(object o, RuntimeMethodHandle method)
=> method.ResolveGenericVirtualMethodTarget(o);

@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants