Fix GH-22206: avoid musttail in zend_runtime_jit() in the tail-call VM - #23054
Fix GH-22206: avoid musttail in zend_runtime_jit() in the tail-call VM#23054lazerg wants to merge 1 commit into
Conversation
arnaud-lb
left a comment
There was a problem hiding this comment.
This is not really a supported configuration, and even with this fix the build fails on my machine with errors related to musttail:
Zend/zend_vm_execute.h: In function 'ZEND_RETURN_BY_REF_SPEC_OBSERVER_TAILCALL_HANDLER':
Zend/zend_vm_execute.h:53688:66: error: address of automatic variable 'observer_retval' can escape to 'musttail' call [-Werror=maybe-musttail-local-addr]
53688 | # define ZEND_VM_CONTINUE() ZEND_VM_TAIL_CALL(opline->handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Zend/zend_vm_execute.h:53687:69: note: in definition of macro 'ZEND_VM_TAIL_CALL'
53687 | # define ZEND_VM_TAIL_CALL(call) ZEND_MUSTTAIL return call
| ^~~~
Zend/zend_vm_execute.h:53695:91: note: in expansion of macro 'ZEND_VM_CONTINUE'
53695 | # define ZEND_VM_DISPATCH_TO_LEAVE_HELPER(helper) opline = &call_leave_op; SAVE_OPLINE(); ZEND_VM_CONTINUE()
| ^~~~~~~~~~~~~~~~
Zend/zend_vm_execute.h:57867:9: note: in expansion of macro 'ZEND_VM_DISPATCH_TO_LEAVE_HELPER'
57867 | ZEND_VM_DISPATCH_TO_LEAVE_HELPER(zend_leave_helper_SPEC_TAILCALL);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GCC's musttail is stricter than Clang, so we can not support the TAILCALL VM on GCC yet.
Normally the TAILCALL VM is not selected on GCC due to global regs supports, but --disable-gcc-global-regs breaks this. Maybe we should explicitly enable the TAILCALL VM only on Clang.
|
I reproduced this. On macOS/aarch64 with GCC 16.1 and
Your build stopped on So Two more things I checked:
void sink(int *p);
int next(void);
int f(void) {
int local = 42;
sink(&local);
[[gnu::musttail]] return next();
}compiles to I agree with your conclusion. Fixing #elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(__aarch64__))
# define ZEND_VM_KIND ZEND_VM_KIND_TAILCALLemitted by I did not do it here for two reasons. It is a support decision that is yours to make. And it makes this PR unnecessary: the One side note. GCC 16.1 on darwin/aarch64 also ICEs on the TAILCALL build, a segfault in the vartrack RTL pass, in both |
With
--disable-gcc-global-regsand a compiler that supportspreserve_none, opcache is built withZEND_VM_KIND_TAILCALL, whereZEND_OPCODE_RETURN()expands to a guaranteed tail call.zend_runtime_jit()does its work insidezend_try(), which usessetjmp(), and GCC 16 rejects that combination with "cannot tail-call: caller uses setjmp".GH-22320 fixed the
--enable-gcc-global-regsside of the same report. Here the tail call isn't needed:zend_runtime_jit()is a cold one-shot JIT trigger rather than a hot VM handler, so a plain call works and the returned opline still goes back to the VM loop as before.Checked with GCC 16.1.0: a
--disable-gcc-global-regsbuild fails onext/opcache/jit/zend_jit.lobefore the change and compiles after it. ext/opcache and Zend tests pass on a tail-call VM build.Fixes GH-22206