From 65859fe17e2d0b39a7376704e46b9d240d4d2ef7 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 11 Mar 2021 13:42:35 +0300 Subject: Inheritance cache optimization --- Zend/zend_inheritance.c | 62 +++++++++++++++++-------------- ext/opcache/ZendAccelerator.c | 6 ++- ext/opcache/zend_accelerator_util_funcs.c | 4 +- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 75f5536eaa..676ab0368c 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1797,6 +1797,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e zend_trait_precedence **precedences; zend_trait_precedence *cur_precedence; zend_trait_method_reference *cur_method_ref; + zend_string *lc_trait_name; zend_string *lcname; HashTable **exclude_tables = NULL; zend_class_entry **aliases = NULL; @@ -1811,9 +1812,10 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e while ((cur_precedence = precedences[i])) { /** Resolve classes for all precedence operations. */ cur_method_ref = &cur_precedence->trait_method; - trait = zend_fetch_class(cur_method_ref->class_name, - ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD); - if (!trait) { + lc_trait_name = zend_string_tolower(cur_method_ref->class_name); + trait = zend_hash_find_ptr(EG(class_table), lc_trait_name); + zend_string_release_ex(lc_trait_name, 0); + if (!trait && !(trait->ce_flags & ZEND_ACC_LINKED)) { zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name)); } zend_check_trait_usage(ce, trait, traits); @@ -1836,10 +1838,13 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e for (j = 0; j < cur_precedence->num_excludes; j++) { zend_string* class_name = cur_precedence->exclude_class_names[j]; - zend_class_entry *exclude_ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD); + zend_class_entry *exclude_ce; uint32_t trait_num; - if (!exclude_ce) { + lc_trait_name = zend_string_tolower(class_name); + exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name); + zend_string_release_ex(lc_trait_name, 0); + if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) { zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name)); } trait_num = zend_check_trait_usage(ce, exclude_ce, traits); @@ -1881,8 +1886,10 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e lcname = zend_string_tolower(cur_method_ref->method_name); if (cur_method_ref->class_name) { /* For all aliases with an explicit class name, resolve the class now. */ - trait = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD); - if (!trait) { + lc_trait_name = zend_string_tolower(cur_method_ref->class_name); + trait = zend_hash_find_ptr(EG(class_table), lc_trait_name); + zend_string_release_ex(lc_trait_name, 0); + if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) { zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name)); } zend_check_trait_usage(ce, trait, traits); @@ -2608,13 +2615,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string * with an exception and remove the class from the class table. This is only possible * if no variance obligations on the current class have been added during autoloading. */ zend_class_entry *parent = NULL; - zend_class_entry **interfaces = NULL; zend_class_entry **traits_and_interfaces = NULL; zend_class_entry *proto = NULL; zend_class_entry *orig_linking_class; uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE; uint32_t i, j; zval *zv; + ALLOCA_FLAG(use_heap) ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED)); @@ -2630,18 +2637,18 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } if (ce->num_traits || ce->num_interfaces) { - traits_and_interfaces = emalloc(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces)); + traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap); for (i = 0; i < ce->num_traits; i++) { zend_class_entry *trait = zend_fetch_class_by_name(ce->trait_names[i].name, ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT); if (UNEXPECTED(trait == NULL)) { - efree(traits_and_interfaces); + free_alloca(traits_and_interfaces, use_heap); return NULL; } if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) { zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name)); - efree(traits_and_interfaces); + free_alloca(traits_and_interfaces, use_heap); return NULL; } for (j = 0; j < i; j++) { @@ -2659,14 +2666,6 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } if (ce->num_interfaces) { - /* Also copy the parent interfaces here, so we don't need to reallocate later. */ - uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0; - interfaces = emalloc( - sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces)); - if (num_parent_interfaces) { - memcpy(interfaces, parent->interfaces, - sizeof(zend_class_entry *) * num_parent_interfaces); - } for (i = 0; i < ce->num_interfaces; i++) { zend_class_entry *iface = zend_fetch_class_by_name( ce->interface_names[i].name, ce->interface_names[i].lc_name, @@ -2674,11 +2673,9 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION); if (!iface) { check_unrecoverable_load_failure(ce); - efree(interfaces); - efree(traits_and_interfaces); + free_alloca(traits_and_interfaces, use_heap); return NULL; } - interfaces[num_parent_interfaces + i] = iface; traits_and_interfaces[ce->num_traits + i] = iface; if (iface) { UPDATE_IS_CACHEABLE(iface); @@ -2693,10 +2690,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces); if (ret) { if (traits_and_interfaces) { - efree(traits_and_interfaces); - } - if (traits_and_interfaces) { - efree(interfaces); + free_alloca(traits_and_interfaces, use_heap); } zv = zend_hash_find_ex(CG(class_table), key, 1); Z_CE_P(zv) = ret; @@ -2739,7 +2733,19 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string if (ce->num_traits) { zend_do_bind_traits(ce, traits_and_interfaces); } - if (interfaces) { + if (ce->num_interfaces) { + /* Also copy the parent interfaces here, so we don't need to reallocate later. */ + uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0; + zend_class_entry **interfaces = emalloc( + sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces)); + + if (num_parent_interfaces) { + memcpy(interfaces, parent->interfaces, + sizeof(zend_class_entry *) * num_parent_interfaces); + } + memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits, + sizeof(zend_class_entry *) * ce->num_interfaces); + zend_do_implement_interfaces(ce, interfaces); } else if (parent && parent->num_interfaces) { zend_do_inherit_interfaces(ce, parent); @@ -2797,7 +2803,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } if (traits_and_interfaces) { - efree(traits_and_interfaces); + free_alloca(traits_and_interfaces, use_heap); } return ce; diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index c2e5690273..d2349b90bd 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2251,7 +2251,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type) return zend_accel_load_script(persistent_script, from_shared_memory); } -static zend_inheritance_cache_entry* zend_accel_inheritance_cache_find(zend_inheritance_cache_entry *entry, zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, bool *needs_autoload_ptr) +static zend_always_inline zend_inheritance_cache_entry* zend_accel_inheritance_cache_find(zend_inheritance_cache_entry *entry, zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, bool *needs_autoload_ptr) { uint32_t i; @@ -2306,7 +2306,9 @@ static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce, entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload); if (entry) { if (!needs_autoload) { - zend_map_ptr_extend(ZCSG(map_ptr_last)); + if (ZCSG(map_ptr_last) > CG(map_ptr_last)) { + zend_map_ptr_extend(ZCSG(map_ptr_last)); + } return entry->ce; } diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index ad456c1bcb..6f101b0915 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -236,7 +236,9 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, zend_string_release_ex(name, 0); } - zend_map_ptr_extend(ZCSG(map_ptr_last)); + if (ZCSG(map_ptr_last) > CG(map_ptr_last)) { + zend_map_ptr_extend(ZCSG(map_ptr_last)); + } } if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) { -- cgit v1.2.1