Commit 8326ad029d5 for php.net
commit 8326ad029d5220d8d413d8e59a15b8a44f39bec0
Author: Gina Peter Banyard <girgias@php.net>
Date: Mon Jan 5 18:39:30 2026 +0100
ext/spl: refactor autoloading to use newer FCC APIs
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 834058a993f..bfe8e6f2901 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -340,67 +340,11 @@ PHP_FUNCTION(spl_autoload_extensions)
}
} /* }}} */
-typedef struct {
- zend_function *func_ptr;
- zend_object *obj;
- zend_object *closure;
- zend_class_entry *ce;
-} autoload_func_info;
-
-static void autoload_func_info_destroy(autoload_func_info *alfi) {
- if (alfi->obj) {
- zend_object_release(alfi->obj);
- }
- if (alfi->func_ptr &&
- UNEXPECTED(alfi->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
- zend_string_release_ex(alfi->func_ptr->common.function_name, 0);
- zend_free_trampoline(alfi->func_ptr);
- }
- if (alfi->closure) {
- zend_object_release(alfi->closure);
- }
- efree(alfi);
-}
-
static void autoload_func_info_zval_dtor(zval *element)
{
- autoload_func_info_destroy(Z_PTR_P(element));
-}
-
-static autoload_func_info *autoload_func_info_from_fci(
- zend_fcall_info *fci, zend_fcall_info_cache *fcc) {
- autoload_func_info *alfi = emalloc(sizeof(autoload_func_info));
- alfi->ce = fcc->calling_scope;
- alfi->func_ptr = fcc->function_handler;
- alfi->obj = fcc->object;
- if (alfi->obj) {
- GC_ADDREF(alfi->obj);
- }
- if (Z_TYPE(fci->function_name) == IS_OBJECT) {
- alfi->closure = Z_OBJ(fci->function_name);
- GC_ADDREF(alfi->closure);
- } else {
- alfi->closure = NULL;
- }
- return alfi;
-}
-
-static bool autoload_func_info_equals(
- const autoload_func_info *alfi1, const autoload_func_info *alfi2) {
- if (UNEXPECTED(
- (alfi1->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) &&
- (alfi2->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)
- )) {
- return alfi1->obj == alfi2->obj
- && alfi1->ce == alfi2->ce
- && alfi1->closure == alfi2->closure
- && zend_string_equals(alfi1->func_ptr->common.function_name, alfi2->func_ptr->common.function_name)
- ;
- }
- return alfi1->func_ptr == alfi2->func_ptr
- && alfi1->obj == alfi2->obj
- && alfi1->ce == alfi2->ce
- && alfi1->closure == alfi2->closure;
+ zend_fcall_info_cache *fcc = Z_PTR_P(element);
+ zend_fcc_dtor(fcc);
+ efree(fcc);
}
static zend_class_entry *spl_perform_autoload(zend_string *class_name, zend_string *lc_name) {
@@ -412,34 +356,27 @@ static zend_class_entry *spl_perform_autoload(zend_string *class_name, zend_stri
* because autoloaders may be added/removed during autoloading. */
HashPosition pos;
zend_hash_internal_pointer_reset_ex(spl_autoload_functions, &pos);
- while (1) {
- autoload_func_info *alfi =
+
+ zval zname;
+ ZVAL_STR(&zname, class_name);
+ while (true) {
+ zend_fcall_info_cache *fcc =
zend_hash_get_current_data_ptr_ex(spl_autoload_functions, &pos);
- if (!alfi) {
+ if (!fcc) {
break;
}
- zend_function *func = alfi->func_ptr;
- if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
- func = emalloc(sizeof(zend_op_array));
- memcpy(func, alfi->func_ptr, sizeof(zend_op_array));
- zend_string_addref(func->op_array.function_name);
- }
-
- zval param;
- ZVAL_STR(¶m, class_name);
- zend_call_known_function(func, alfi->obj, alfi->ce, NULL, 1, ¶m, NULL);
- if (EG(exception)) {
+ zend_call_known_fcc(fcc, NULL, 1, &zname, NULL);
+ if (UNEXPECTED(EG(exception))) {
break;
}
- if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) {
+ if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) {
return (zend_class_entry*)ZSTR_GET_CE_CACHE(class_name);
- } else {
- zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name);
- if (ce) {
- return ce;
- }
+ }
+ zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name);
+ if (ce != NULL) {
+ return ce;
}
zend_hash_move_forward_ex(spl_autoload_functions, &pos);
@@ -471,14 +408,14 @@ PHP_FUNCTION(spl_autoload_call)
zend_hash_rehash(ht); \
} while (0)
-static Bucket *spl_find_registered_function(autoload_func_info *find_alfi) {
+static Bucket *spl_find_registered_function(const zend_fcall_info_cache *find_fcc) {
if (!spl_autoload_functions) {
return NULL;
}
- autoload_func_info *alfi;
- ZEND_HASH_MAP_FOREACH_PTR(spl_autoload_functions, alfi) {
- if (autoload_func_info_equals(alfi, find_alfi)) {
+ zend_fcall_info_cache *fcc;
+ ZEND_HASH_MAP_FOREACH_PTR(spl_autoload_functions, fcc) {
+ if (zend_fcc_equals(fcc, find_fcc)) {
return _p;
}
} ZEND_HASH_FOREACH_END();
@@ -492,7 +429,6 @@ PHP_FUNCTION(spl_autoload_register)
bool prepend = 0;
zend_fcall_info fci = {0};
zend_fcall_info_cache fcc;
- autoload_func_info *alfi;
ZEND_PARSE_PARAMETERS_START(0, 3)
Z_PARAM_OPTIONAL
@@ -508,14 +444,14 @@ PHP_FUNCTION(spl_autoload_register)
if (!spl_autoload_functions) {
ALLOC_HASHTABLE(spl_autoload_functions);
- zend_hash_init(spl_autoload_functions, 1, NULL, autoload_func_info_zval_dtor, 0);
+ zend_hash_init(spl_autoload_functions, 1, NULL, autoload_func_info_zval_dtor, false);
/* Initialize as non-packed hash table for prepend functionality. */
zend_hash_real_init_mixed(spl_autoload_functions);
}
/* If first arg is not null */
if (ZEND_FCI_INITIALIZED(fci)) {
- if (!fcc.function_handler) {
+ if (!ZEND_FCC_INITIALIZED(fcc)) {
/* Call trampoline has been cleared by zpp. Refetch it, because we want to deal
* with it ourselves. It is important that it is not refetched on every call,
* because calls may occur from different scopes. */
@@ -527,30 +463,19 @@ PHP_FUNCTION(spl_autoload_register)
zend_argument_value_error(1, "must not be the spl_autoload_call() function");
RETURN_THROWS();
}
-
- alfi = autoload_func_info_from_fci(&fci, &fcc);
- if (UNEXPECTED(alfi->func_ptr == &EG(trampoline))) {
- zend_function *copy = emalloc(sizeof(zend_op_array));
-
- memcpy(copy, alfi->func_ptr, sizeof(zend_op_array));
- alfi->func_ptr->common.function_name = NULL;
- alfi->func_ptr = copy;
- }
} else {
- alfi = emalloc(sizeof(autoload_func_info));
- alfi->func_ptr = zend_hash_str_find_ptr(
- CG(function_table), "spl_autoload", sizeof("spl_autoload") - 1);
- alfi->obj = NULL;
- alfi->ce = NULL;
- alfi->closure = NULL;
+ memset(&fcc, 0, sizeof(fcc));
+ fcc.function_handler = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("spl_autoload"));
}
- if (spl_find_registered_function(alfi)) {
- autoload_func_info_destroy(alfi);
+ if (spl_find_registered_function(&fcc)) {
+ /* Release call trampoline */
+ zend_release_fcall_info_cache(&fcc);
RETURN_TRUE;
}
- zend_hash_next_index_insert_ptr(spl_autoload_functions, alfi);
+ zend_fcc_addref(&fcc);
+ zend_hash_next_index_insert_mem(spl_autoload_functions, &fcc, sizeof(zend_fcall_info_cache));
if (prepend && spl_autoload_functions->nNumOfElements > 1) {
/* Move the newly created element to the head of the hashtable */
HT_MOVE_TAIL_TO_HEAD(spl_autoload_functions);
@@ -592,9 +517,9 @@ PHP_FUNCTION(spl_autoload_unregister)
zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL);
}
- autoload_func_info *alfi = autoload_func_info_from_fci(&fci, &fcc);
- Bucket *p = spl_find_registered_function(alfi);
- autoload_func_info_destroy(alfi);
+ Bucket *p = spl_find_registered_function(&fcc);
+ /* Release trampoline */
+ zend_release_fcall_info_cache(&fcc);
if (p) {
zend_hash_del_bucket(spl_autoload_functions, p);
RETURN_TRUE;
@@ -606,32 +531,19 @@ PHP_FUNCTION(spl_autoload_unregister)
/* {{{ Return all registered autoloader functions */
PHP_FUNCTION(spl_autoload_functions)
{
- autoload_func_info *alfi;
-
ZEND_PARSE_PARAMETERS_NONE();
- array_init(return_value);
if (spl_autoload_functions) {
- ZEND_HASH_MAP_FOREACH_PTR(spl_autoload_functions, alfi) {
- if (alfi->closure) {
- GC_ADDREF(alfi->closure);
- add_next_index_object(return_value, alfi->closure);
- } else if (alfi->func_ptr->common.scope) {
- zval tmp;
-
- array_init(&tmp);
- if (alfi->obj) {
- GC_ADDREF(alfi->obj);
- add_next_index_object(&tmp, alfi->obj);
- } else {
- add_next_index_str(&tmp, zend_string_copy(alfi->ce->name));
- }
- add_next_index_str(&tmp, zend_string_copy(alfi->func_ptr->common.function_name));
- add_next_index_zval(return_value, &tmp);
- } else {
- add_next_index_str(return_value, zend_string_copy(alfi->func_ptr->common.function_name));
- }
+ zend_fcall_info_cache *fcc;
+
+ array_init_size(return_value, zend_hash_num_elements(spl_autoload_functions));
+ ZEND_HASH_MAP_FOREACH_PTR(spl_autoload_functions, fcc) {
+ zval tmp;
+ zend_get_callable_zval_from_fcc(fcc, &tmp);
+ add_next_index_zval(return_value, &tmp);
} ZEND_HASH_FOREACH_END();
+ } else {
+ RETURN_EMPTY_ARRAY();
}
} /* }}} */