[PHP-CVS] [php-src] master: Zend: use zend_object* for this_ptr

[email protected] (Gina Peter Banyard)
Newsgroups php.cvs
Message-ID <[email protected]>
Author: Gina Peter Banyard (Girgias)
Date: 2026-08-14T14:38:56+01:00

Commit: https://github.com/php/php-src/commit/7a5e452f14ce2e4719d6e86586652a2fad8c3697
Raw diff: https://github.com/php/php-src/commit/7a5e452f14ce2e4719d6e86586652a2fad8c3697.diff

Zend: use zend_object* for this_ptr

Instead of a zval

Changed paths:
  M  Zend/zend_closures.c
  M  Zend/zend_closures.h
  M  ext/opcache/jit/zend_jit_ir.c
  M  ext/reflection/php_reflection.c


Diff:

diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index d421bdbc8eb5..4aa467315907 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -35,7 +35,7 @@
 typedef struct _zend_closure {
 	zend_object       std;
 	zend_function     func;
-	zval              this_ptr;
+	zend_object      *this_ptr;
 	zend_class_entry *called_scope;
 	zif_handler       orig_internal_handler;
 } zend_closure;
@@ -115,7 +115,7 @@ static bool zend_valid_closure_binding(
 			&& !(func->common.fn_flags & ZEND_ACC_STATIC)) {
 		zend_error(E_WARNING, "Cannot unbind $this of method, this will be an error in PHP 9");
 		return false;
-	} else if (!is_fake_closure && !Z_ISUNDEF(closure->this_ptr)
+	} else if (!is_fake_closure && closure->this_ptr
 			&& (func->common.fn_flags & ZEND_ACC_USES_THIS)) {
 		zend_error(E_WARNING, "Cannot unbind $this of closure using $this, this will be an error in PHP 9");
 		return false;
@@ -197,7 +197,7 @@ ZEND_METHOD(Closure, call)
 		fake_closure->std.gc.refcount = 1;
 		fake_closure->std.gc.u.type_info = GC_NULL;
 		fake_closure->std.extra_flags = zend_closure_flags(closure);
-		ZVAL_UNDEF(&fake_closure->this_ptr);
+		fake_closure->this_ptr = NULL;
 		fake_closure->called_scope = NULL;
 		my_function = &fake_closure->func;
 		if (ZEND_USER_CODE(closure->func.type)) {
@@ -510,11 +510,7 @@ static int zend_closure_compare(zval *o1, zval *o2) /* {{{ */
 		return ZEND_UNCOMPARABLE;
 	}
 
-	if (Z_TYPE(lhs->this_ptr) != Z_TYPE(rhs->this_ptr)) {
-		return ZEND_UNCOMPARABLE;
-	}
-
-	if (Z_TYPE(lhs->this_ptr) == IS_OBJECT && Z_OBJ(lhs->this_ptr) != Z_OBJ(rhs->this_ptr)) {
+	if (lhs->this_ptr != rhs->this_ptr) {
 		return ZEND_UNCOMPARABLE;
 	}
 
@@ -574,10 +570,10 @@ ZEND_API const zend_function *zend_get_closure_method_def(zend_object *obj) /* {
 }
 /* }}} */
 
-ZEND_API zval* zend_get_closure_this_ptr(zval *obj) /* {{{ */
+ZEND_API zend_object* zend_get_closure_this_ptr(zval *obj) /* {{{ */
 {
 	zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
-	return &closure->this_ptr;
+	return closure->this_ptr;
 }
 /* }}} */
 
@@ -607,8 +603,8 @@ static void zend_closure_free_storage(zend_object *object) /* {{{ */
 		zend_string_release(closure->func.common.function_name);
 	}
 
-	if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
-		zval_ptr_dtor(&closure->this_ptr);
+	if (closure->this_ptr) {
+		OBJ_RELEASE(closure->this_ptr);
 	}
 }
 /* }}} */
@@ -633,7 +629,7 @@ static zend_object *zend_closure_clone(zend_object *zobject) /* {{{ */
 
 	zend_create_closure_ex(&result, &closure->func,
 		closure->func.common.scope, closure->called_scope,
-		Z_ISUNDEF(closure->this_ptr) ? NULL : Z_OBJ(closure->this_ptr),
+		closure->this_ptr,
 		zend_closure_is_fake(closure), zend_closure_flags(closure));
 	return Z_OBJ(result);
 }
@@ -645,12 +641,7 @@ static zend_result zend_closure_get_closure(zend_object *obj, zend_class_entry *
 
 	*fptr_ptr = &closure->func;
 	*ce_ptr = closure->called_scope;
-
-	if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
-		*obj_ptr = Z_OBJ(closure->this_ptr);
-	} else {
-		*obj_ptr = NULL;
-	}
+	*obj_ptr = closure->this_ptr;
 
 	return SUCCESS;
 }
@@ -718,9 +709,10 @@ static HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp)
 		}
 	}
 
-	if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
-		Z_ADDREF(closure->this_ptr);
-		zend_hash_update(debug_info, ZSTR_KNOWN(ZEND_STR_THIS), &closure->this_ptr);
+	if (closure->this_ptr) {
+		zval tmp;
+		ZVAL_OBJ_COPY(&tmp, closure->this_ptr);
+		zend_hash_update(debug_info, ZSTR_KNOWN(ZEND_STR_THIS), &tmp);
 	}
 
 	if (arg_info &&
@@ -757,8 +749,15 @@ static HashTable *zend_closure_get_gc(zend_object *obj, zval **table, int *n) /*
 {
 	zend_closure *closure = (zend_closure *)obj;
 
-	*table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL;
-	*n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0;
+	if (closure->this_ptr) {
+		zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
+		zend_get_gc_buffer_add_obj(gc_buffer, closure->this_ptr);
+		zend_get_gc_buffer_use(gc_buffer, table, n);
+	} else {
+		*table = NULL;
+		*n = 0;
+	}
+
 	/* Fake closures don't own the static variables they reference. */
 	return (closure->func.type == ZEND_USER_FUNCTION
 			&& !(closure->func.op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) ?
@@ -894,7 +893,7 @@ static void zend_create_closure_ex(
 		}
 	}
 
-	ZVAL_UNDEF(&closure->this_ptr);
+	closure->this_ptr = NULL;
 	/* Invariant:
 	 * If the closure is unscoped or static, it has no bound object. */
 	closure->func.common.scope = scope;
@@ -902,7 +901,8 @@ static void zend_create_closure_ex(
 	if (scope) {
 		closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
 		if (this_ptr && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
-			ZVAL_OBJ_COPY(&closure->this_ptr, this_ptr);
+			closure->this_ptr = this_ptr;
+			GC_ADDREF(this_ptr);
 		}
 	}
 }
@@ -924,7 +924,7 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas
 
 	closure = (zend_closure *)Z_OBJ_P(res);
 	closure->func.common.fn_flags |= ZEND_ACC_FAKE_CLOSURE;
-	if (Z_TYPE(closure->this_ptr) != IS_OBJECT) {
+	if (!closure->this_ptr) {
 		GC_ADD_FLAGS(&closure->std, GC_NOT_COLLECTABLE);
 	}
 }
diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h
index 969594e900e8..c421c100833a 100644
--- a/Zend/zend_closures.h
+++ b/Zend/zend_closures.h
@@ -39,7 +39,7 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *op_array, zend_
 ZEND_API void zend_create_partial_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zend_object *this_ptr, bool partial_of_closure);
 ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *obj);
 ZEND_API const zend_function *zend_get_closure_method_def(zend_object *obj);
-ZEND_API zval* zend_get_closure_this_ptr(zval *obj);
+ZEND_API zend_object* zend_get_closure_this_ptr(zval *obj);
 
 END_EXTERN_C()
 
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index 2bbd7b0e3f4d..9849bda4cd2f 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -8453,7 +8453,7 @@ static int zend_jit_isset_isempty_cv(zend_jit_ctx *jit, const zend_op *opline, u
 typedef struct _zend_closure {
 	zend_object       std;
 	zend_function     func;
-	zval              this_ptr;
+	zend_object      *this_ptr;
 	zend_class_entry *called_scope;
 	zif_handler       orig_internal_handler;
 } zend_closure;
@@ -8708,17 +8708,17 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
 			ir_AND_U32(
 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
 				ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
-			ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
-		// JIT: if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
-		if_cond = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.u1.v.type))));
+				ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
+
+		// JIT: object_or_called_scope = closure->this_ptr;
+		object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr)));
+		// JIT: if (closure->this_ptr != NULL) {
+		if_cond = ir_IF(object);
 		ir_IF_TRUE(if_cond);
 
 		// JIT: call_info |= ZEND_CALL_HAS_THIS;
 		call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
 
-		// JIT: object_or_called_scope = Z_OBJ(closure->this_ptr);
-		object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.value.ptr)));
-
 		ir_MERGE_WITH_EMPTY_FALSE(if_cond);
 		call_info = ir_PHI_2(IR_U32, call_info2, call_info);
 		object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 3f65acb68c10..1accd39e2578 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -1772,9 +1772,9 @@ ZEND_METHOD(ReflectionFunctionAbstract, getClosureThis)
 
 	GET_REFLECTION_OBJECT();
 	if (!Z_ISUNDEF(intern->obj)) {
-		zval *closure_this = zend_get_closure_this_ptr(&intern->obj);
-		if (!Z_ISUNDEF_P(closure_this)) {
-			RETURN_OBJ_COPY(Z_OBJ_P(closure_this));
+		zend_object *closure_this = zend_get_closure_this_ptr(&intern->obj);
+		if (closure_this) {
+			RETURN_OBJ_COPY(closure_this);
 		}
 	}
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.