diff --git a/NEWS b/NEWS
index 6c54aa4c998ce..f73cbf7b5c351 100644
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,7 @@ PHP NEWS
- Opcache:
. Fixed bug GH-15981 (Segfault with frameless jumps and minimal JIT).
(nielsdos)
+ . Fixed bug GH-17307 (Internal closure causes JIT failure). (nielsdos)
- PHPDBG:
. Fix crashes in function registration + test. (nielsdos, Girgias)
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index e14345215f6f4..0aea4eab2bff7 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -8503,18 +8503,16 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
} else {
ir_ref num_args_ref;
ir_ref if_internal_func = IR_UNUSED;
+ const size_t func_type_offset = is_closure ? offsetof(zend_closure, func.type) : offsetof(zend_function, type);
used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
used_stack_ref = ir_CONST_ADDR(used_stack);
+ used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
- if (!is_closure) {
- used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
-
- // JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
- ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
- if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
- ir_IF_FALSE(if_internal_func);
- }
+ // JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
+ ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, func_type_offset));
+ if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
+ ir_IF_FALSE(if_internal_func);
// JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
num_args_ref = ir_CONST_U32(opline->extended_value);
@@ -8541,12 +8539,8 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
}
ref = ir_SUB_A(used_stack_ref, ref);
- if (is_closure) {
- used_stack_ref = ref;
- } else {
- ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
- used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
- }
+ ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
+ used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
}
zend_jit_start_reuse_ip(jit);
diff --git a/ext/opcache/tests/jit/gh17307.phpt b/ext/opcache/tests/jit/gh17307.phpt
new file mode 100644
index 0000000000000..292d695963c2e
--- /dev/null
+++ b/ext/opcache/tests/jit/gh17307.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-17307 (Internal closure causes JIT failure)
+--EXTENSIONS--
+opcache
+simplexml
+bcmath
+--INI--
+opcache.jit=1254
+opcache.jit_hot_func=1
+opcache.jit_buffer_size=32M
+--FILE--
+");
+
+function run_loop($firstTerms, $closure) {
+ foreach ($firstTerms as $firstTerm) {
+ \debug_zval_dump($firstTerm);
+ $closure($firstTerm, "10");
+ }
+}
+
+run_loop($simple, bcadd(...));
+echo "Done\n";
+
+?>
+--EXPECTF--
+object(SimpleXMLElement)#%d (0) refcount(3){
+}
+object(SimpleXMLElement)#%d (0) refcount(3){
+}
+Done