diff options
author | Alan Wu <[email protected]> | 2024-01-29 12:21:17 -0500 |
---|---|---|
committer | <[email protected]> | 2024-01-29 12:21:17 -0500 |
commit | b0711b1cf152afad0a480ee2f9bedd142a0d24ac () | |
tree | 68b67cf497e01fd59944900338131b7d0b459883 /vm_exec.h | |
parent | 9a5a11f3d0e5d9b595d51aafe8fdadfe384568ad (diff) |
YJIT: Fix tailcall and JIT entry eating up FINISH frames (#9729)
Suppose YJIT runs a rb_vm_opt_send_without_block() fallback and the control frame stack looks like: ``` will_tailcall_bar [FINISH] caller_that_used_fallback ``` will_tailcall_bar() runs in the interpreter and sets up a tailcall. Right before JIT_EXEC() in the `send` instruction, the stack will look like: ``` bar [FINISH] caller_that_used_fallback ``` Previously, JIT_EXEC() ran bar() in JIT code, which caused the `FINISH` flag to return to the interpreter instead of to the JIT code running caller_that_used_fallback(), causing code to run twice and probably crash. Recent flaky failures on CI about "each stub expects a particular iseq" are probably due to leaving methods twice in `test_optimizations.rb`. Only run JIT code from the interpreter if a new frame is pushed.
-rw-r--r-- | vm_exec.h | 3 |
1 files changed, 2 insertions, 1 deletions
@@ -176,7 +176,8 @@ default: \ // Run the JIT from the interpreter #define JIT_EXEC(ec, val) do { \ rb_jit_func_t func; \ - if (val == Qundef && (func = jit_compile(ec))) { \ val = func(ec, ec->cfp); \ RESTORE_REGS(); /* fix cfp for tailcall */ \ if (ec->tag->state) THROW_EXCEPTION(val); \ |