From 32cb7345df7ca3c9cbf15270ae585b09f8fcbaa7 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sun, 6 Sep 2026 17:10:18 +0200 Subject: [PATCH] fix tailcall VM for gcc --- Zend/zend_vm_gen.php | 2 +- Zend/zend_vm_opcodes.h | 2 +- ext/opcache/jit/zend_jit.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 6e6349bee0ad..1ffa80f718dc 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -2523,7 +2523,7 @@ function gen_vm_opcodes_header( $str .= "# define ZEND_VM_KIND\t\tZEND_VM_KIND_HYBRID\n"; } if ($GLOBALS["vm_kind_name"][ZEND_VM_GEN_KIND] === "ZEND_VM_KIND_HYBRID" || $GLOBALS["vm_kind_name"][ZEND_VM_GEN_KIND] === "ZEND_VM_KIND_CALL") { - $str .= "#elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(__aarch64__)) && defined(__clang__)\n"; + $str .= "#elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(__aarch64__))\n"; $str .= "# define ZEND_VM_KIND\t\tZEND_VM_KIND_TAILCALL\n"; $str .= "#else\n"; $str .= "# define ZEND_VM_KIND\t\tZEND_VM_KIND_CALL\n"; diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 34e24ec14b1e..dae282705d53 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -42,7 +42,7 @@ static const char *const zend_vm_kind_name[] = { /* HYBRID requires support for computed GOTO and global register variables*/ #elif (defined(__GNUC__) && defined(HAVE_GCC_GLOBAL_REGS)) # define ZEND_VM_KIND ZEND_VM_KIND_HYBRID -#elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(__aarch64__)) && defined(__clang__) +#elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(__aarch64__)) # define ZEND_VM_KIND ZEND_VM_KIND_TAILCALL #else # define ZEND_VM_KIND ZEND_VM_KIND_CALL diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 76510743d333..0905bb96a7a9 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -3099,6 +3099,12 @@ static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, cons return FAILURE; } +#if defined(__GNUC__) && !defined(__clang__) && ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL +/* GCC cannot tail-call from a function that uses setjmp. */ +static zend_never_inline void zend_runtime_jit_compile(zend_op_array *op_array) +{ + const zend_op *opline = op_array->opcodes; +#else /* Run-time JIT handler */ #if ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS) @@ -3116,6 +3122,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_runtime_jit(Z execute_data = EG(current_execute_data); zend_op_array *op_array = &EX(func)->op_array; opline = op_array->opcodes; +#endif zend_jit_op_array_extension *jit_extension; bool do_bailout = 0; @@ -3154,6 +3161,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_runtime_jit(Z zend_bailout(); } +#if defined(__GNUC__) && !defined(__clang__) && ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL +} + +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS) +{ + const zend_op *orig_opline = opline; + execute_data = EG(current_execute_data); + zend_runtime_jit_compile(&EX(func)->op_array); +#endif + /* JIT-ed code is going to be called by VM */ #if GCC_GLOBAL_REGS return; // ZEND_VM_CONTINUE