Uh oh!
There was an error while loading. Please reload this page.
Fix transition from monomorphic to polymorphic VSD - #132544
Conversation
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: 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. |
Tagging subscribers to this area: @agocke |
AndyAyersMS
commented
Aug 20, 2026
@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. |
There was a problem hiding this comment.
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_ResolveBackPatchand 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.
Uh oh!
There was an error while loading. Please reload this page.
AndyAyersMS
commented
Aug 20, 2026
@davidwrighton@VSadov PTAL Distilled from a real-world case I've been working on. |
AndyAyersMS
commented
Aug 20, 2026
Also Arm32/RiscV/LoongArch also ave this issue (and the latter two seem to also have some inverted logic). |
AndyAyersMS
commented
Aug 20, 2026
Also fyi @jkotas -- from what I can tell arm64 behavior has been like this (different than x64) for a long time. |
EgorBo
commented
Aug 20, 2026
@EgorBot orchard -aws_arm |
jkotas
commented
Aug 21, 2026
Good catch!
Do you plan to apply the fix there as part of this PR? |
AndyAyersMS
commented
Aug 21, 2026
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
Uh oh!
There was an error while loading. Please reload this page.
AndyAyersMS
commented
Aug 21, 2026
/backport to release/11.0-rc1 |
Started backporting to |
AndyAyersMS
commented
Aug 21, 2026
/backport to release/10.0 |
Started backporting to |
@AndyAyersMS backporting to 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 |
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_ResolveBackPatchbut 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_ResolveBackPatchso 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.