Commit b9761d5b51a for php

commit b9761d5b51ae4f5c5ed74dc55337a38c7c6e40bd
Author: Nora Dossche <7771979+ndossche@users.noreply.github.com>
Date:   Wed Nov 4 10:57:41 2026 +0100

    JIT: Avoid exception check on function leave when possible (#24261)

diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c
index 01a5f50a32f..d47b28d819c 100644
--- a/ext/opcache/jit/zend_jit.c
+++ b/ext/opcache/jit/zend_jit.c
@@ -1437,6 +1437,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
 	int call_level = 0;
 	void *checkpoint = NULL;
 	bool recv_emitted = false;   /* emitted at least one RECV opcode */
+	bool leave_may_throw = false; /* a destructor may run on the common return path */
 	uint8_t smart_branch_opcode;
 	uint32_t target_label, target_label2;
 	uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_mem_info;
@@ -2302,6 +2303,12 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
 									op1_info, OP1_REG_ADDR())) {
 								goto jit_failure;
 							}
+							/* An unused return value is destroyed by zend_jit_return() */
+							if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
+							 && (op1_info & MAY_BE_RC1)
+							 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
+								leave_may_throw = true;
+							}
 						}
 						goto done;
 					case ZEND_BOOL:
@@ -2952,6 +2959,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
 				goto jit_failure;
 			}
 			left_frame = true;
+			leave_may_throw = true;
 		}
 		if (!left_frame) {
 			int j;
@@ -2969,11 +2977,21 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
 					if (!zend_jit_free_cv(&ctx, info, j)) {
 						goto jit_failure;
 					}
+					if ((info & MAY_BE_REF)
+					 || ((info & MAY_BE_RC1)
+					  && (info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE)))) {
+						leave_may_throw = true;
+					}
 				}
 			}
 		}
+		if (ZEND_OBSERVER_ENABLED
+		 /* releasing the closure may destroy its bound $this or used variables */
+		 || (op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
+			leave_may_throw = true;
+		}
 		if (!zend_jit_leave_func(&ctx, op_array, NULL, MAY_BE_ANY, left_frame,
-				NULL, NULL, (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, 1)) {
+				NULL, NULL, (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, leave_may_throw)) {
 			goto jit_failure;
 		}
 	}
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index b8f83813432..1cee1025c60 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -11425,8 +11425,10 @@ static int zend_jit_leave_func(zend_jit_ctx         *jit,

 		return 1;
 	} else {
-		// JIT: if (EG(exception))
-		ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
+		if (may_throw) {
+			// JIT: if (EG(exception))
+			ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
+		}
 		// JIT: opline = EX(opline) + 1
 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
 		jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));