Skip to content

Fix transition from monomorphic to polymorphic VSD - #132544

Merged
AndyAyersMS merged 2 commits into
dotnet:mainfrom
AndyAyersMS:fix-arm64-vsd-backpatch
Aug 21, 2026
Merged

Fix transition from monomorphic to polymorphic VSD#132544
AndyAyersMS merged 2 commits into
dotnet:mainfrom
AndyAyersMS:fix-arm64-vsd-backpatch

Conversation

@AndyAyersMS

@AndyAyersMSAndyAyersMS commented Aug 20, 2026

Copy link
Copy Markdown
Member

An interface call site initially uses a dispatch stub specialized for one receiver type. After enough misses, the site should be backpatched to a resolve stub to handle polymorphic receivers.

On ARM, ARM64, LoongArch64, and RISC-V64, the expired-counter path set SDF_ResolveBackPatch but then probed the inline resolve cache. A cache hit there branched directly to the target without processing the flag, leaving the site monomorphic and causing subsequent receiver-type misses to continue through the dispatch stub.

Enter the slow resolve path after setting SDF_ResolveBackPatch so the call site is backpatched as intended. Also correct the inverted miss-counter handling on LoongArch64 and RISC-V64. This matches the existing x64 behavior.

An interface call site initially uses a dispatch stub specialized for one
receiver type. After enough misses, the site should be backpatched to a
resolve stub to handle polymorphic receivers.
On ARM64, the expired-counter path set SDF_ResolveBackPatch but then probed
the inline resolve cache. A cache hit there branched directly to the target
without processing the flag, leaving the site monomorphic and causing
subsequent receiver-type misses to continue through the dispatch stub.
Enter the slow resolve path after setting SDF_ResolveBackPatch so the call
site is backpatched as intended. This matches the existing x64 behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_arm64 -windows_arm64 --envvars DOTNET_TieredCompilation:0 DOTNET_TieredPGO:0 DOTNET_JitEnableGuardedDevirtualization:0 DOTNET_ReadyToRun:0

usingSystem.Runtime.CompilerServices;usingBenchmarkDotNet.Attributes;publicinterfaceITarget{intInvoke(intvalue);}publicsealedclassA:ITarget{[MethodImpl(MethodImplOptions.NoInlining)]publicintInvoke(intvalue)=>value+1;}publicsealedclassB:ITarget{[MethodImpl(MethodImplOptions.NoInlining)]publicintInvoke(intvalue)=>value+2;}[SimpleJob(launchCount:1,warmupCount:3,iterationCount:10,invocationCount:1)]publicclassVsdBackpatchBench{privateITarget_target=null!;privatelong_checksum;[Params(false,true)]publicboolSwitchType{get;set;}[Params(16)]publicintThreads{get;set;}[GlobalSetup]publicvoidSetup(){vara=newA();_checksum=Run(a,100_000);_target=SwitchType?newB():a;}[Benchmark]publiclongInterfaceCalls(){vargate=newManualResetEventSlim();varworkers=newThread[Threads];varresults=newlong[Threads];for(intthread=0;thread<Threads;thread++){intindex=thread;workers[thread]=newThread(()=>{gate.Wait();results[index]=Run(_target,20_000_000);});workers[thread].Start();}gate.Set();foreach(Threadworkerinworkers){worker.Join();}longchecksum=_checksum;foreach(longresultinresults){checksum^=result;}returnchecksum;}[MethodImpl(MethodImplOptions.NoInlining)]privatestaticlongRun(ITargettarget,intiterations){longsum=0;for(inti=0;i<iterations;i++){sum+=target.Invoke(i);}returnsum;}}

Note

This benchmark request was created with GitHub Copilot.

CopilotAI 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

Updates the ARM64 virtual call resolve stub’s fail path so that when the dispatch-miss counter expires, the stub routes through the slow resolve path with SDF_ResolveBackPatch observed, enabling a monomorphic interface call site to transition to a polymorphic resolve stub (matching the established x64 behavior).

Changes:

  • ARM64: On counter expiration, set SDF_ResolveBackPatch and branch to _slowEntryPoint (instead of _resolveEntryPoint) so backpatching can occur.
  • ARM64: Add/adjust explanatory comments around why the slow path is required for backpatch flag processing.

Comment threadsrc/coreclr/vm/arm64/virtualcallstubcpu.hpp Outdated
@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

@davidwrighton@VSadov PTAL
fyi @EgorBo

Distilled from a real-world case I've been working on.

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

Also Arm32/RiscV/LoongArch also ave this issue (and the latter two seem to also have some inverted logic).

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

Also fyi @jkotas -- from what I can tell arm64 behavior has been like this (different than x64) for a long time.

@EgorBo

Copy link
Copy Markdown
Member

@EgorBot orchard -aws_arm

@jkotas

Copy link
Copy Markdown
Member

Good catch!

Also Arm32/RiscV/LoongArch also ave this issu

Do you plan to apply the fix there as part of this PR?

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

Good catch!

Also Arm32/RiscV/LoongArch also ave this issu

Do you plan to apply the fix there as part of this PR?

Yeah, I can fix those as well.

Route expired dispatch misses through the slow resolve path on ARM, ARM64, LoongArch64, and RISC-V64 so the backpatch flag is processed. Correct the inverted miss-counter handling on LoongArch64 and RISC-V64.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6bd43e03-841f-47ee-80f4-4da985b32a67
CopilotAI review requested due to automatic review settings August 21, 2026 01:25
@AndyAyersMSAndyAyersMS changed the title Fix ARM64 transition from monomorphic to polymorphic VSDFix transition from monomorphic to polymorphic VSDAug 21, 2026

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

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

@AndyAyersMS
AndyAyersMS merged commit 16f3d6c into dotnet:mainAug 21, 2026
102 checks passed
@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-rc1

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-rc1 (link to workflow run)

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

@github-actions

Copy link
Copy Markdown
Contributor

@AndyAyersMS backporting to release/10.0 failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git cherry-pick 16f3d6c9031cb4c76abedd8a12f78bd86b0b9337Auto-merging src/coreclr/vm/arm/stubs.cppCONFLICT (content): Merge conflict in src/coreclr/vm/arm/stubs.cppAuto-merging src/coreclr/vm/arm64/virtualcallstubcpu.hppAuto-merging src/coreclr/vm/loongarch64/virtualcallstubcpu.hppAuto-merging src/coreclr/vm/riscv64/virtualcallstubcpu.hppCONFLICT (content): Merge conflict in src/coreclr/vm/riscv64/virtualcallstubcpu.hpperror: could not apply 16f3d6c9031... Fix transition from monomorphic to polymorphic VSD (#132544)hint: After resolving the conflicts, mark them withhint: "git add/rm <pathspec>", then runhint: "git cherry-pick --continue".hint: You can instead skip this commit with "git cherry-pick --skip".hint: To abort and get back to the state before "git cherry-pick",hint: run "git cherry-pick --abort".hint: Disable this message with "git config set advice.mergeConflict false"
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patchApplying: Fix ARM64 transition from monomorphic to polymorphic VSDApplying: Fix VSD backpatch on non-x64 architecturesUsing index info to reconstruct a base tree...M	src/coreclr/vm/arm/stubs.cppM	src/coreclr/vm/arm64/virtualcallstubcpu.hppM	src/coreclr/vm/loongarch64/virtualcallstubcpu.hppM	src/coreclr/vm/riscv64/virtualcallstubcpu.hppFalling back to patching base and 3-way merge...Auto-merging src/coreclr/vm/arm/stubs.cppCONFLICT (content): Merge conflict in src/coreclr/vm/arm/stubs.cppAuto-merging src/coreclr/vm/arm64/virtualcallstubcpu.hppAuto-merging src/coreclr/vm/loongarch64/virtualcallstubcpu.hppAuto-merging src/coreclr/vm/riscv64/virtualcallstubcpu.hppCONFLICT (content): Merge conflict in src/coreclr/vm/riscv64/virtualcallstubcpu.hpperror: Failed to merge in the changes.hint: Use 'git am --show-current-patch=diff' to see the failed patchhint: When you have resolved this problem, run "git am --continue".hint: If you prefer to skip this patch, run "git am --skip" instead.hint: To restore the original branch and stop patching, run "git am --abort".hint: Disable this message with "git config set advice.mergeConflict false"Patch failed at 0002 Fix VSD backpatch on non-x64 architecturesError: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

Sign up for freeto 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.

4 participants

@AndyAyersMS@EgorBo@jkotas