From dc99efdd90995f97eb765b93f81439e74dc8cdbe Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:27:30 +0800 Subject: [PATCH 1/8] Zend: Use lowercase hash lookup for duplicate function checks --- Zend/zend_API.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 6b52080643f1..a03ceb8cd28b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3238,12 +3238,9 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend if (unload) { /* before unloading, display all remaining bad function in the module */ while (ptr->fname) { fname_len = strlen(ptr->fname); - lowercase_name = zend_string_alloc(fname_len, 0); - zend_str_tolower_copy(ZSTR_VAL(lowercase_name), ptr->fname, fname_len); - if (zend_hash_exists(target_function_table, lowercase_name)) { + if (zend_hash_str_find_ptr_lc(target_function_table, ptr->fname, fname_len) != NULL) { zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); } - zend_string_efree(lowercase_name); ptr++; } zend_unregister_functions(functions, count, target_function_table); From c6d8a2de6f33edf90dc8e5b5760d7d3f0806d9c2 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:27:37 +0800 Subject: [PATCH 2/8] Zend: Reuse zend_fetch_function() for dynamic calls --- Zend/zend_execute.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6f3572840d4c..14a340ffee37 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -5103,7 +5103,6 @@ static void zend_swap_operands(zend_op *op) /* {{{ */ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */ { zend_function *fbc; - zval *func; zend_class_entry *called_scope; zend_string *lcname; const char *colon; @@ -5155,23 +5154,11 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s init_func_run_time_cache(&fbc->op_array); } } else { - if (ZSTR_VAL(function)[0] == '\\') { - lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0); - zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1); - } else { - lcname = zend_string_tolower(function); - } - if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { + fbc = zend_fetch_function(function); + if (UNEXPECTED(fbc == NULL)) { zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function)); - zend_string_release_ex(lcname, 0); return NULL; } - zend_string_release_ex(lcname, 0); - - fbc = Z_FUNC_P(func); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { - init_func_run_time_cache(&fbc->op_array); - } called_scope = NULL; } From 6106ba88348f160d90b39bea154ca550cf597da1 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:31:02 +0800 Subject: [PATCH 3/8] Zend: Use pointer hash lookups for methods --- Zend/zend_API.c | 10 +++------- Zend/zend_object_handlers.c | 14 ++++---------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index a03ceb8cd28b..b5bea957106b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3802,7 +3802,6 @@ static zend_always_inline bool zend_is_method_callable(zend_string *callable, co HashTable *ftable; bool call_via_handler = false; zend_class_entry *scope; - zval *zv; fcc->calling_scope = NULL; @@ -3888,8 +3887,7 @@ static zend_always_inline bool zend_is_method_callable(zend_string *callable, co if (fcc->function_handler) { retval = true; } - } else if ((zv = zend_hash_find(ftable, lmname)) != NULL) { - fcc->function_handler = Z_PTR_P(zv); + } else if ((fcc->function_handler = zend_hash_find_ptr(ftable, lmname)) != NULL) { retval = true; if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) && !strict_class) { @@ -3897,10 +3895,8 @@ static zend_always_inline bool zend_is_method_callable(zend_string *callable, co if (scope && instanceof_function(fcc->function_handler->common.scope, scope)) { - zv = zend_hash_find(&scope->function_table, lmname); - if (zv != NULL) { - zend_function *priv_fbc = Z_PTR_P(zv); - + zend_function *priv_fbc = zend_hash_find_ptr(&scope->function_table, lmname); + if (priv_fbc != NULL) { if ((priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE) && priv_fbc->common.scope == scope) { fcc->function_handler = priv_fbc; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e06287895d15..f3b925cdeb31 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1756,13 +1756,9 @@ ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset) /* {{{ static zend_never_inline zend_function *zend_get_parent_private_method(const zend_class_entry *scope, const zend_class_entry *ce, zend_string *function_name) /* {{{ */ { - zval *func; - zend_function *fbc; - if (scope != ce && scope && is_derived_class(ce, scope)) { - func = zend_hash_find(&scope->function_table, function_name); - if (func != NULL) { - fbc = Z_FUNC_P(func); + zend_function *fbc = zend_hash_find_ptr(&scope->function_table, function_name); + if (fbc != NULL) { if ((fbc->common.fn_flags & ZEND_ACC_PRIVATE) && fbc->common.scope == scope) { return fbc; @@ -1979,7 +1975,6 @@ ZEND_API ZEND_COLD zend_never_inline void zend_abstract_method_call(const zend_f ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */ { zend_object *zobj = *obj_ptr; - zval *func; zend_function *fbc; zend_string *lc_method_name; ALLOCA_FLAG(use_heap); @@ -1994,7 +1989,8 @@ ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string * zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name)); } - if (UNEXPECTED((func = zend_hash_find(&zobj->ce->function_table, lc_method_name)) == NULL)) { + fbc = zend_hash_find_ptr(&zobj->ce->function_table, lc_method_name); + if (UNEXPECTED(fbc == NULL)) { if (UNEXPECTED(!key)) { ZSTR_ALLOCA_FREE(lc_method_name, use_heap); } @@ -2005,8 +2001,6 @@ ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string * } } - fbc = Z_FUNC_P(func); - /* Check access level */ if (fbc->op_array.fn_flags & (ZEND_ACC_CHANGED|ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) { const zend_class_entry *scope = zend_get_executed_scope(); From 7e15a1d851b34cbbf5fe23c3f4287533b54f2449 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:31:02 +0800 Subject: [PATCH 4/8] Zend: Avoid temporary lowercase static method names --- Zend/zend_object_handlers.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index f3b925cdeb31..45b6be2cc9eb 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -2061,17 +2061,14 @@ static zend_always_inline zend_function *get_static_method_fallback( ZEND_API zend_function *zend_std_get_static_method(const zend_class_entry *ce, zend_string *function_name, const zval *key) /* {{{ */ { - zend_string *lc_function_name; + zend_function *fbc; if (EXPECTED(key != NULL)) { - lc_function_name = Z_STR_P(key); + fbc = zend_hash_find_ptr(&ce->function_table, Z_STR_P(key)); } else { - lc_function_name = zend_string_tolower(function_name); + fbc = zend_hash_find_ptr_lc(&ce->function_table, function_name); } - zend_function *fbc; - zval *func = zend_hash_find(&ce->function_table, lc_function_name); - if (EXPECTED(func)) { - fbc = Z_FUNC_P(func); + if (EXPECTED(fbc)) { if (!(fbc->common.fn_flags & ZEND_ACC_PUBLIC)) { const zend_class_entry *scope = zend_get_executed_scope(); ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_PUBLIC)); @@ -2087,10 +2084,6 @@ ZEND_API zend_function *zend_std_get_static_method(const zend_class_entry *ce, z fbc = get_static_method_fallback(ce, function_name); } - if (UNEXPECTED(!key)) { - zend_string_release_ex(lc_function_name, 0); - } - if (EXPECTED(fbc)) { if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) { zend_abstract_method_call(fbc); From eee522cff00cd70a0b3ff3429ce96ffac5a8fb53 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:29:07 +0800 Subject: [PATCH 5/8] Zend: Use pointer hash lookup for classes --- Zend/zend_execute_API.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index cc99a75a6ab9..b48352a5aaf3 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1201,7 +1201,6 @@ ZEND_API bool zend_is_valid_class_name(const zend_string *name) { ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */ { zend_class_entry *ce = NULL; - zval *zv; zend_string *lc_name; zend_string *autoload_name; uint32_t ce_cache = 0; @@ -1229,12 +1228,11 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * } } - zv = zend_hash_find(EG(class_table), lc_name); - if (zv) { + ce = zend_hash_find_ptr(EG(class_table), lc_name); + if (ce) { if (!key) { zend_string_release_ex(lc_name, 0); } - ce = (zend_class_entry*)Z_PTR_P(zv); if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) { if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) || ((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) && From a602221cd4f6adf7a2a6993a7c77d3571e66be58 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:31:43 +0800 Subject: [PATCH 6/8] Zend: Use pointer hash lookups for property metadata --- Zend/zend_object_handlers.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 45b6be2cc9eb..95046d1589d4 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -294,13 +294,9 @@ static zend_never_inline int is_protected_compatible_scope(const zend_class_entr static zend_never_inline zend_property_info *zend_get_parent_private_property(const zend_class_entry *scope, const zend_class_entry *ce, zend_string *member) /* {{{ */ { - zval *zv; - zend_property_info *prop_info; - if (scope != ce && scope && is_derived_class(ce, scope)) { - zv = zend_hash_find(&scope->properties_info, member); - if (zv != NULL) { - prop_info = (zend_property_info*)Z_PTR_P(zv); + zend_property_info *prop_info = zend_hash_find_ptr(&scope->properties_info, member); + if (prop_info != NULL) { if ((prop_info->flags & ZEND_ACC_PRIVATE) && prop_info->ce == scope) { return prop_info; @@ -364,7 +360,6 @@ static zend_always_inline const zend_class_entry *get_fake_or_executed_scope(voi static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot, const zend_property_info **info_ptr) /* {{{ */ { - zval *zv; zend_property_info *property_info; uint32_t flags; uintptr_t offset; @@ -375,7 +370,7 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c } if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0) - || UNEXPECTED((zv = zend_hash_find(&ce->properties_info, member)) == NULL)) { + || UNEXPECTED((property_info = zend_hash_find_ptr(&ce->properties_info, member)) == NULL)) { if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0') && ZSTR_LEN(member) != 0) { if (!silent) { zend_bad_property_name(); @@ -390,7 +385,6 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c return ZEND_DYNAMIC_PROPERTY_OFFSET; } - property_info = (zend_property_info*)Z_PTR_P(zv); flags = property_info->flags; if (flags & (ZEND_ACC_CHANGED|ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) { @@ -474,12 +468,11 @@ static ZEND_COLD void zend_wrong_offset(zend_class_entry *ce, zend_string *membe ZEND_API zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent) /* {{{ */ { - zval *zv; zend_property_info *property_info; uint32_t flags; if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0) - || EXPECTED((zv = zend_hash_find(&ce->properties_info, member)) == NULL)) { + || EXPECTED((property_info = zend_hash_find_ptr(&ce->properties_info, member)) == NULL)) { if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0') && ZSTR_LEN(member) != 0) { if (!silent) { zend_bad_property_name(); @@ -490,7 +483,6 @@ ZEND_API zend_property_info *zend_get_property_info(const zend_class_entry *ce, return NULL; } - property_info = (zend_property_info*)Z_PTR_P(zv); flags = property_info->flags; if (flags & (ZEND_ACC_CHANGED|ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) { From 2046048f9bc8c2aedfccd4dd2f82b741254dc5e7 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:31:43 +0800 Subject: [PATCH 7/8] Zend: Use pointer hash lookup for property guards --- Zend/zend_object_handlers.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 95046d1589d4..c5ec6fe5515b 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -635,9 +635,9 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe } else if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) { guards = Z_ARRVAL_P(zv); ZEND_ASSERT(guards != NULL); - zv = zend_hash_find(guards, member); - if (zv != NULL) { - return (uint32_t*)(((uintptr_t)Z_PTR_P(zv)) & ~1); + void *guard = zend_hash_find_ptr(guards, member); + if (guard != NULL) { + return (uint32_t*)(((uintptr_t)guard) & ~1); } } else { ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF); From 41d24395e5bcc2640f39e39103a7d00a24d43be9 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 16 Aug 2026 02:44:52 +0800 Subject: [PATCH 8/8] Zend: Use zend_hash_find_ex_ptr() for __invoke --- Zend/zend_object_handlers.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index c5ec6fe5515b..8ca6d212fd72 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -2615,12 +2615,13 @@ ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *w ZEND_API zend_result zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) /* {{{ */ { zend_class_entry *ce = obj->ce; - const zval *func = zend_hash_find_known_hash(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE)); + zend_function *func = zend_hash_find_ex_ptr( + &ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE), /* known_hash */ true); if (func == NULL) { return FAILURE; } - *fptr_ptr = Z_FUNC_P(func); + *fptr_ptr = func; *ce_ptr = ce; *obj_ptr = obj;