You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CreateILDelegateShuffleThunk (src/coreclr/vm/comdelegate.cpp) generates an IL stub that loads Delegate._methodPtrAux and invokes it with a plain calli:
For an open virtual delegate, _methodPtrAux holds a virtual dispatch stub from GetVirtualCallStub (comdelegate.cpp:990). The stub is:
CID_VirtualOpenDelegateDispatch under FEATURE_CACHED_INTERFACE_DISPATCH, or
a virtual stub dispatch stub under FEATURE_VIRTUAL_STUB_DISPATCH.
Both kinds of stub expect the address of _methodPtrAux (the indirection cell) in a hidden argument register, for example r11 on amd64 or x11 on arm64. calli cannot express that argument, so the stub reads whatever happens to be in that register.
The hand-written shuffle thunks do set up the hidden argument, for example:
No dynamic code (FEATURE_DYNAMIC_CODE_COMPILED off; iOS, tvOS, maccatalyst, browser-wasm):FEATURE_PORTABLE_SHUFFLE_THUNKS is not defined, so the IL shuffle thunk is always used and it runs in the interpreter.
On maccatalyst-arm64 CoreCLR this crashed in CID_VirtualOpenDelegateDispatchWorker.
riscv64 / loongarch64 (JIT):GenerateShuffleArray returns false when a shuffle would move arguments between the integer and floating-point calling conventions (comdelegate.cpp:~340). SetupShuffleThunk then falls back to CreateILDelegateShuffleThunk, and the JIT-compiled calli does not set the hidden argument.
amd64 / arm64 (JIT): the portable stub-linker thunk is used today, so this configuration isn't hit in regular testing. It can be reproduced for investigation by forcing the CreateILDelegateShuffleThunk fallback in SetupShuffleThunk.
Reproduction (sketch)
Create and invoke an open virtual delegate through a path that uses the IL shuffle thunk, for example:
Use either riscv64/loongarch64 with a signature that forces the FP/integer fallback, or x64 with the fallback forced.
Expected behavior
Open virtual delegates invoked through the IL shuffle thunk dispatch to the correct override.
Notes
A general fix needs the IL shuffle thunk to supply the hidden argument, or to avoid calli to the dispatch stub for open virtual delegates, rather than each consumer special-casing it. The interpreter change in #134699 is a workaround limited to the interpreter's calli.
Note
This issue was generated with GitHub Copilot, based on review feedback from @jkotas on #134699.
Description
CreateILDelegateShuffleThunk(src/coreclr/vm/comdelegate.cpp) generates an IL stub that loadsDelegate._methodPtrAuxand invokes it with a plaincalli:runtime/src/coreclr/vm/comdelegate.cpp
Lines 816 to 818 in e2234ae
For an open virtual delegate,
_methodPtrAuxholds a virtual dispatch stub fromGetVirtualCallStub(comdelegate.cpp:990). The stub is:CID_VirtualOpenDelegateDispatchunderFEATURE_CACHED_INTERFACE_DISPATCH, orFEATURE_VIRTUAL_STUB_DISPATCH.Both kinds of stub expect the address of
_methodPtrAux(the indirection cell) in a hidden argument register, for exampler11on amd64 orx11on arm64.callicannot express that argument, so the stub reads whatever happens to be in that register.The hand-written shuffle thunks do set up the hidden argument, for example:
runtime/src/coreclr/vm/i386/stublinkerx86.cpp
Lines 1196 to 1199 in e2234ae
Where the IL shuffle thunk is used
FEATURE_DYNAMIC_CODE_COMPILEDoff; iOS, tvOS, maccatalyst, browser-wasm):FEATURE_PORTABLE_SHUFFLE_THUNKSis not defined, so the IL shuffle thunk is always used and it runs in the interpreter.CID_VirtualOpenDelegateDispatchWorker.PrepareInterpreterCode([browser][CoreCLR][R2R] System.Linq.Expressions tests trap in PrepareInterpreterCode #134261).INTOP_CALLIrecognizes the stub and resolves the target itself, asINTOP_CALLDELEGATEalready does.GenerateShuffleArrayreturns false when a shuffle would move arguments between the integer and floating-point calling conventions (comdelegate.cpp:~340).SetupShuffleThunkthen falls back toCreateILDelegateShuffleThunk, and the JIT-compiledcallidoes not set the hidden argument.CreateILDelegateShuffleThunkfallback inSetupShuffleThunk.Reproduction (sketch)
Create and invoke an open virtual delegate through a path that uses the IL shuffle thunk, for example:
Use either riscv64/loongarch64 with a signature that forces the FP/integer fallback, or x64 with the fallback forced.
Expected behavior
Open virtual delegates invoked through the IL shuffle thunk dispatch to the correct override.
Notes
A general fix needs the IL shuffle thunk to supply the hidden argument, or to avoid
callito the dispatch stub for open virtual delegates, rather than each consumer special-casing it. The interpreter change in #134699 is a workaround limited to the interpreter'scalli.Note
This issue was generated with GitHub Copilot, based on review feedback from @jkotas on #134699.