From: Dmitry Stogov Date: Wed, 10 Feb 2021 12:22:09 +0000 (+0300) Subject: Reuse single map_ptr slot for indentical class names X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6aea64c44455b78b2ca773b9e082f11fd2734eae;p=php Reuse single map_ptr slot for indentical class names --- diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 9819e7acdd..49efc3a431 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -505,7 +505,7 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str) hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h); STRTAB_COLLISION(s) = *hash_slot; *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s); - GC_SET_REFCOUNT(s, 1); + GC_SET_REFCOUNT(s, 2); GC_TYPE_INFO(s) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT); ZSTR_H(s) = h; ZSTR_LEN(s) = ZSTR_LEN(str); diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index d8cf261ed2..663cffca14 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -329,6 +329,8 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type); zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str); +uint32_t zend_accel_get_type_map_ptr(zend_string *type_name, zend_class_entry *scope); + /* memory write protection */ #define SHM_PROTECT() \ do { \ diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 56a26eec5d..d62fabb8d5 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -1190,7 +1190,7 @@ static void zend_file_cache_unserialize_attribute(zval *zv, zend_persistent_scri } static void zend_file_cache_unserialize_type( - zend_type *type, zend_persistent_script *script, void *buf) + zend_type *type, zend_class_entry *scope, zend_persistent_script *script, void *buf) { if (ZEND_TYPE_HAS_LIST(*type)) { zend_type_list *list = ZEND_TYPE_LIST(*type); @@ -1199,16 +1199,21 @@ static void zend_file_cache_unserialize_type( zend_type *list_type; ZEND_TYPE_LIST_FOREACH(list, list_type) { - zend_file_cache_unserialize_type(list_type, script, buf); + zend_file_cache_unserialize_type(list_type, scope, script, buf); } ZEND_TYPE_LIST_FOREACH_END(); } else if (ZEND_TYPE_HAS_NAME(*type)) { zend_string *type_name = ZEND_TYPE_NAME(*type); UNSERIALIZE_STR(type_name); ZEND_TYPE_SET_PTR(*type, type_name); if (!(script->corrupted)) { - // TODO: we may use single map_ptr slot for each class name ??? - type->type_mask |= _ZEND_TYPE_CACHE_BIT; - type->ce_cache__ptr = (uint32_t)(uintptr_t)zend_map_ptr_new(); + uint32_t ptr = zend_accel_get_type_map_ptr(type_name, scope); + + if (ptr) { + type->type_mask |= _ZEND_TYPE_CACHE_BIT; + type->ce_cache__ptr = ptr; + } else { + type->type_mask &= ~_ZEND_TYPE_CACHE_BIT; + } } else { type->type_mask &= ~_ZEND_TYPE_CACHE_BIT; } @@ -1362,7 +1367,7 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr if (!IS_UNSERIALIZED(p->name)) { UNSERIALIZE_STR(p->name); } - zend_file_cache_unserialize_type(&p->type, script, buf); + zend_file_cache_unserialize_type(&p->type, op_array->scope, script, buf); p++; } } @@ -1421,7 +1426,7 @@ static void zend_file_cache_unserialize_prop_info(zval *zv, UNSERIALIZE_STR(prop->doc_comment); } UNSERIALIZE_ATTRIBUTES(prop->attributes); - zend_file_cache_unserialize_type(&prop->type, script, buf); + zend_file_cache_unserialize_type(&prop->type, prop->ce, script, buf); } } } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index a95c614f2a..f1a7ee2ef5 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -36,6 +36,7 @@ #endif #define zend_set_str_gc_flags(str) do { \ + GC_SET_REFCOUNT(str, 2); \ if (file_cache_only) { \ GC_TYPE_INFO(str) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT); \ } else { \ @@ -290,7 +291,40 @@ static HashTable *zend_persist_attributes(HashTable *attributes) return ptr; } -static void zend_persist_type(zend_type *type) { +uint32_t zend_accel_get_type_map_ptr(zend_string *type_name, zend_class_entry *scope) +{ + uint32_t ret; + + if (zend_string_equals_literal_ci(type_name, "self")) { + if (!scope) { + return 0; + } + type_name = scope->name; + } else if (zend_string_equals_literal_ci(type_name, "parent")) { + if (!scope || !scope->parent) { + return 0; + } + if (scope->ce_flags & ZEND_ACC_RESOLVED_PARENT) { + type_name = scope->parent->name; + } else { + type_name = scope->parent_name; + } + } + + ZEND_ASSERT(GC_FLAGS(type_name) & GC_IMMUTABLE); + ZEND_ASSERT(GC_FLAGS(type_name) & IS_STR_PERMANENT); + ret = GC_REFCOUNT(type_name); + + /* We use type.name.gc.refcount to keep map_ptr of corresponding type */ + if (ret <= 2) { + ret = (uint32_t)(uintptr_t)zend_map_ptr_new(); + ZEND_ASSERT(ret > 2); + GC_SET_REFCOUNT(type_name, ret); + } + return ret; +} + +static void zend_persist_type(zend_type *type, zend_class_entry *scope) { if (ZEND_TYPE_HAS_LIST(*type)) { zend_type_list *list = ZEND_TYPE_LIST(*type); if (ZEND_TYPE_USES_ARENA(*type)) { @@ -309,9 +343,12 @@ static void zend_persist_type(zend_type *type) { zend_accel_store_interned_string(type_name); ZEND_TYPE_SET_PTR(*single_type, type_name); if (!ZCG(current_persistent_script)->corrupted) { - // TODO: we may use single map_ptr slot for each class name ??? - single_type->type_mask |= _ZEND_TYPE_CACHE_BIT; - single_type->ce_cache__ptr = (uint32_t)(uintptr_t)zend_map_ptr_new(); + uint32_t ptr = zend_accel_get_type_map_ptr(type_name, scope); + + if (ptr) { + single_type->type_mask |= _ZEND_TYPE_CACHE_BIT; + single_type->ce_cache__ptr = ptr; + } } } } ZEND_TYPE_FOREACH_END(); @@ -584,7 +621,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc if (arg_info[i].name) { zend_accel_store_interned_string(arg_info[i].name); } - zend_persist_type(&arg_info[i].type); + zend_persist_type(&arg_info[i].type, op_array->scope); } if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { arg_info++; @@ -743,7 +780,7 @@ static zend_property_info *zend_persist_property_info(zend_property_info *prop) if (prop->attributes) { prop->attributes = zend_persist_attributes(prop->attributes); } - zend_persist_type(&prop->type); + zend_persist_type(&prop->type, ce); return prop; }