]> granicus.if.org Git - php/commitdiff
Reuse single map_ptr slot for indentical class names
authorDmitry Stogov <dmitry@zend.com>
Wed, 10 Feb 2021 12:22:09 +0000 (15:22 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 10 Feb 2021 12:22:09 +0000 (15:22 +0300)
ext/opcache/ZendAccelerator.c
ext/opcache/ZendAccelerator.h
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c

index 9819e7acdd26f56b14826c7463bc2b63f5fd0cfb..49efc3a431a434a0043d617ec8d167b7ee9cfab9 100644 (file)
@@ -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);
index d8cf261ed2bd7457c4dffe025d231f3765dae407..663cffca14a55cb0462095a0ae2d9ac30c07cc58 100644 (file)
@@ -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 { \
index 56a26eec5d8c8d9616f740d7c2d7abd19401c1fa..d62fabb8d5b50cdee884ed1954d16422c4943871 100644 (file)
@@ -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);
                }
        }
 }
index a95c614f2a273dffb666837faf18d17db3f87ae8..f1a7ee2ef54cda35a47b06f69a59fea205453092 100644 (file)
@@ -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;
 }