From a110b75e146e3751dd8628f1d4d35f10bbe8123e Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 11 Sep 2026 21:55:50 +0100 Subject: [PATCH] Zend: have zend_call_known_function_ex create an FCC And call zend_call_known_fcc_ex, rather than zend_call_known_fcc_ex call zend_call_known_function_ex which re-creates an FCC in the end when we already have one. We prevent trampolines from zend_call_known_function as those would be duplicates, but this seems unlikely to break anything --- Zend/zend_API.h | 43 ++++++++++++++++++++--------------------- Zend/zend_execute_API.c | 19 +++++++++--------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index da871e1eb390..89fe53423ecf 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -856,13 +856,32 @@ static zend_always_inline zend_result zend_call_function_with_return_value( return zend_call_function(fci, fci_cache); } +ZEND_API void zend_call_known_fcc_ex( + zend_fcall_info_cache *fcc, zval *retval_ptr, + uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args); + +static zend_always_inline void zend_call_known_fcc( + zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params) +{ + zend_call_known_fcc_ex(fcc, retval_ptr, param_count, params, named_params, 0); +} + /* Call the provided zend_function with the given params. * If retval_ptr is NULL, the return value is discarded. * If object is NULL, this must be a free function or static call. * called_scope must be provided for instance and static method calls. */ -ZEND_API void zend_call_known_function_ex( +static zend_always_inline void zend_call_known_function_ex( zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, - uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args); + uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args) { + ZEND_ASSERT(fn && "zend_function must be passed!"); + ZEND_ASSERT((fn->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0 && "fn cannot be a trampoline"); + + zend_fcall_info_cache fcc; + fcc.function_handler = fn; + fcc.object = object; + fcc.called_scope = called_scope; + zend_call_known_fcc_ex(&fcc, retval_ptr, param_count, params, named_params, consumed_args); +} static zend_always_inline void zend_call_known_function( zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, @@ -870,26 +889,6 @@ static zend_always_inline void zend_call_known_function( zend_call_known_function_ex(fn, object, called_scope, retval_ptr, param_count, params, named_params, 0); } -static zend_always_inline void zend_call_known_fcc_ex( - const zend_fcall_info_cache *fcc, zval *retval_ptr, - uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args) -{ - zend_function *func = fcc->function_handler; - /* Need to copy trampolines as they get released after they are called */ - if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - func = (zend_function*) emalloc(sizeof(zend_function)); - memcpy(func, fcc->function_handler, sizeof(zend_function)); - zend_string_addref(func->op_array.function_name); - } - zend_call_known_function_ex(func, fcc->object, fcc->called_scope, retval_ptr, param_count, params, named_params, consumed_args); -} - -static zend_always_inline void zend_call_known_fcc( - const zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params) -{ - zend_call_known_fcc_ex(fcc, retval_ptr, param_count, params, named_params, 0); -} - /* Call the provided zend_function instance method on an object. */ static zend_always_inline void zend_call_known_instance_method( zend_function *fn, zend_object *object, zval *retval_ptr, diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index c67a31fd8de2..a0a9d309626b 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1110,18 +1110,22 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_ } /* }}} */ -ZEND_API void zend_call_known_function_ex( - zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, +ZEND_API void zend_call_known_fcc_ex( + zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params, uint32_t consumed_args) { zval retval; zend_fcall_info fci; - zend_fcall_info_cache fcic; - ZEND_ASSERT(fn && "zend_function must be passed!"); + zend_function *fn = fcc->function_handler; + /* Need to copy trampolines as they get released after they are called */ + if (UNEXPECTED(fn->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + fn = (zend_function*) emalloc(sizeof(zend_function)); + memcpy(fn, fcc->function_handler, sizeof(zend_function)); + zend_string_addref(fn->op_array.function_name); + } fci.size = sizeof(fci); - fci.object = object; fci.retval = retval_ptr ? retval_ptr : &retval; fci.param_count = param_count; fci.params = params; @@ -1129,11 +1133,8 @@ ZEND_API void zend_call_known_function_ex( fci.consumed_args = consumed_args; ZVAL_UNDEF(&fci.function_name); /* Unused */ - fcic.function_handler = fn; - fcic.object = object; - fcic.called_scope = called_scope; - zend_result result = zend_call_function(&fci, &fcic); + zend_result result = zend_call_function(&fci, fcc); if (UNEXPECTED(result == FAILURE)) { if (!EG(exception)) { zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s",