[clr-interp] Fix jmp instruction to tolerate the call.tail opcode failing to actually tail call#123513
Merged
davidwrighton merged 1 commit intodotnet:mainfrom Jan 23, 2026
Merged
Conversation
…ling to actually tail call call.tail in the interpreter isn't guaranteed to tail-call in some cases, so we need to put in a ret instruction after the tail-call to ensure that the runtime doesn't execute invalid code
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts the CLR interpreter’s handling of CEE_RET and CEE_JMP to ensure correct behavior when call.tail does not actually result in a tail call, particularly fixing Windows Arm64 P/Invoke jump/tailcall tests.
Changes:
- Refactors return emission logic into a shared
InterpCompiler::EmitRethelper used by bothCEE_RETandCEE_JMPhandling. - Updates the
CEE_RETopcode handling to delegate all return-related code generation toEmitRet, keeping IP and block-linking logic in one place. - Tightens
CEE_JMPsemantics by disallowing its use in synchronized/async methods and by emitting aretafter the tailcall to guard against non-tail-call behavior in the interpreter.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/coreclr/interpreter/compiler.h | Declares the new EmitRet(CORINFO_METHOD_INFO* methodInfo) helper to centralize return emission logic. |
| src/coreclr/interpreter/compiler.cpp | Implements EmitRet, refactors CEE_RET to use it, and updates CEE_JMP to forbid use in synchronized/async methods and to emit a post-call return to ensure valid control flow even if the tailcall is not honored. |
Copilot AI
pushed a commit
that referenced
this pull request
Jan 23, 2026
…ling to actually tail call (#123513) call.tail in the interpreter isn't guaranteed to tail-call in some cases, so we need to put in a ret instruction after the tail-call to ensure that the runtime doesn't execute invalid code. The code for doing a ret is extracted into a helper routine, and now called from both the CEE_JMP and CEE_RET pathways. The only change made to the code was to unify where the ip adjustment was to not happen in the EmitRet logic and instead keep it all in the same place in CEE_RET handling case. This fixes these test cases on Windows Arm64 JIT/Directed/pinvoke/jump JIT/Directed/pinvoke/tail_pinvoke
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
call.tail in the interpreter isn't guaranteed to tail-call in some cases, so we need to put in a ret instruction after the tail-call to ensure that the runtime doesn't execute invalid code. The code for doing a ret is extracted into a helper routine, and now called from both the CEE_JMP and CEE_RET pathways. The only change made to the code was to unify where the ip adjustment was to not happen in the EmitRet logic and instead keep it all in the same place in CEE_RET handling case.
This fixes these test cases on Windows Arm64
JIT/Directed/pinvoke/jump
JIT/Directed/pinvoke/tail_pinvoke