]> granicus.if.org Git - php/commitdiff
Keep information about unresolved parent class in zend_class_entry->parent_name
authorDmitry Stogov <dmitry@zend.com>
Thu, 23 Aug 2018 21:20:57 +0000 (00:20 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 23 Aug 2018 21:20:57 +0000 (00:20 +0300)
Zend/zend.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_inheritance.c
Zend/zend_opcode.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/zend_accelerator_util_funcs.c
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c

index ee47d0b1403670f684c6391b74fa7817f6bbc120..ba577274d9a196bbeb0f72b4ce0dbd0d2a12e3d5 100644 (file)
@@ -115,7 +115,10 @@ typedef struct _zend_trait_alias {
 struct _zend_class_entry {
        char type;
        zend_string *name;
-       zend_class_entry *parent;
+       union {
+               zend_class_entry *parent;
+               zend_string *parent_name;
+       };
        int refcount;
        uint32_t ce_flags;
 
index b1ac89cb5acbea696b0ab7ae2bd90a90cce7e8b0..5482bf6ec53e72e0fd6bd6b67ab207a1948922ff 100644 (file)
@@ -6403,7 +6403,7 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
 
        if (extends_ast) {
                znode extends_node;
-               zend_string *extends_name;
+               zend_string *extends_name, *parent_name;
 
                if (!zend_is_const_default_class_ref(extends_ast)) {
                        extends_name = zend_ast_get_str(extends_ast);
@@ -6416,11 +6416,12 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
                        zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
                }
                extends_name = Z_STR(extends_node.u.constant);
-               extends_const = zend_add_class_name_literal(CG(active_op_array),
-                               zend_resolve_class_name(extends_name,
-                                       extends_ast->kind == ZEND_AST_ZVAL ? extends_ast->attr : ZEND_NAME_FQ));
+               parent_name = zend_resolve_class_name(extends_name,
+                                       extends_ast->kind == ZEND_AST_ZVAL ? extends_ast->attr : ZEND_NAME_FQ);
+               extends_const = zend_add_class_name_literal(CG(active_op_array), parent_name);
+               ce->parent_name = zend_string_copy(parent_name);
                zend_string_release_ex(extends_name, 0);
-               ce->ce_flags |= ZEND_ACC_INHERITED;
+               ce->ce_flags |= ZEND_ACC_INHERITED | ZEND_ACC_UNRESOLVED_PARENT;
        }
 
        opline = get_next_op(CG(active_op_array));
index 9132ee25379d84b3c26de4dfffb37be5593da9ac..6c969d99613e69d2e8e0dbecb7cd0c4684581a40 100644 (file)
@@ -244,6 +244,9 @@ typedef struct _zend_oparray_context {
 /* Class extends another class                            |     |     |     */
 #define ZEND_ACC_INHERITED               (1 << 10) /*  X  |     |     |     */
 /*                                                        |     |     |     */
+/* Class extends another class                            |     |     |     */
+#define ZEND_ACC_UNRESOLVED_PARENT       (1 << 11) /*  X  |     |     |     */
+/*                                                        |     |     |     */
 /* Class implements interface(s)                          |     |     |     */
 #define ZEND_ACC_IMPLEMENT_INTERFACES    (1 << 19) /*  X  |     |     |     */
 /*                                                        |     |     |     */
index 59bb5c4f1839f0889657701e48654012cfba52dc..d36d3040cb303923ddff344a8a9a95f7b4def104 100644 (file)
@@ -816,6 +816,10 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
                }
        }
 
+       if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+               zend_string_release_ex(ce->parent_name, 0);
+               ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_PARENT;
+       }
        ce->parent = parent_ce;
 
        /* Inherit interfaces */
index 451104aaf0257568b9896f9b7a8b0ae5ff824e58..28c85edb8aa23c387350c59f52ec3c086676a171 100644 (file)
@@ -218,6 +218,9 @@ ZEND_API void destroy_zend_class(zval *zv)
        }
        switch (ce->type) {
                case ZEND_USER_CLASS:
+                       if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+                               zend_string_release_ex(ce->parent_name, 0);
+                       }
                        if (ce->default_properties_table) {
                                zval *p = ce->default_properties_table;
                                zval *end = p + ce->default_properties_count;
index 46749b64c6d54a4e4bb362713748553c2792e71c..b3976dd11527b3c766bdf053e04ab5bfb18261be 100644 (file)
@@ -2981,7 +2981,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
                                                }
                                                break;
                                        case ZEND_FETCH_CLASS_PARENT:
-                                               if (op_array->scope && op_array->scope->parent) {
+                                               if (op_array->scope && op_array->scope->parent && !(op_array->scope->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
                                                        UPDATE_SSA_OBJ_TYPE(op_array->scope->parent, 0, ssa_ops[i].result_def);
                                                } else {
                                                        UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def);
@@ -3464,9 +3464,11 @@ unknown_opcode:
 
 static uint32_t get_class_entry_rank(zend_class_entry *ce) {
        uint32_t rank = 0;
-       while (ce->parent) {
-               rank++;
-               ce = ce->parent;
+       if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
+               while (ce->parent) {
+                       rank++;
+                       ce = ce->parent;
+               }
        }
        return rank;
 }
@@ -3487,17 +3489,17 @@ static zend_class_entry *join_class_entries(
 
        while (rank1 != rank2) {
                if (rank1 > rank2) {
-                       ce1 = ce1->parent;
+                       ce1 = (ce1->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce1->parent;
                        rank1--;
                } else {
-                       ce2 = ce2->parent;
+                       ce2 = (ce2->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce2->parent;
                        rank2--;
                }
        }
 
        while (ce1 != ce2) {
-               ce1 = ce1->parent;
-               ce2 = ce2->parent;
+               ce1 = (ce1->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce1->parent;
+               ce2 = (ce2->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce2->parent;
        }
 
        if (ce1) {
index 7fb4c7bfb95b926ea2861cf0f0ff7c82b6b55358..58409ee0634ce9739cc6f372b61da267355b8fe6 100644 (file)
@@ -292,7 +292,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
        *pce = ce = ARENA_REALLOC(old_ce);
        ce->refcount = 1;
 
-       if (ce->parent) {
+       if (ce->parent && !(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
                ce->parent = ARENA_REALLOC(ce->parent);
        }
 
@@ -312,7 +312,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
        /* static members */
        if (old_ce->default_static_members_table) {
                int i, end;
-               zend_class_entry *parent = ce->parent;
+               zend_class_entry *parent = (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) ? NULL : ce->parent;
 
                ce->default_static_members_table = emalloc(sizeof(zval) * old_ce->default_static_members_count);
                i = ce->default_static_members_count - 1;
index 4f46c4899452b96067d0b6eb135853690dc1d76f..ca284b7c852c4141277908f97e23d87d479ad788 100644 (file)
@@ -604,12 +604,19 @@ static void zend_file_cache_serialize_class(zval                     *zv,
                                             void                     *buf)
 {
        zend_class_entry *ce;
+       zend_class_entry *parent = NULL;
 
        SERIALIZE_PTR(Z_PTR_P(zv));
        ce = Z_PTR_P(zv);
        UNSERIALIZE_PTR(ce);
 
        SERIALIZE_STR(ce->name);
+       if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+               SERIALIZE_STR(ce->parent_name);
+       } else {
+               parent = ce->parent;
+               SERIALIZE_PTR(ce->parent);
+       }
        zend_file_cache_serialize_hash(&ce->function_table, script, info, buf, zend_file_cache_serialize_func);
        if (ce->default_properties_table) {
                zval *p, *end;
@@ -632,7 +639,7 @@ static void zend_file_cache_serialize_class(zval                     *zv,
 
                /* Serialize only static properties in this class.
                 * Static properties from parent classes will be handled in class_copy_ctor */
-               p = table + (ce->parent ? ce->parent->default_static_members_count : 0);
+               p = table + (parent ? parent->default_static_members_count : 0);
                end = table + ce->default_static_members_count;
                while (p < end) {
                        zend_file_cache_serialize_zval(p, script, info, buf);
@@ -727,7 +734,6 @@ static void zend_file_cache_serialize_class(zval                     *zv,
                }
        }
 
-       SERIALIZE_PTR(ce->parent);
        SERIALIZE_PTR(ce->constructor);
        SERIALIZE_PTR(ce->destructor);
        SERIALIZE_PTR(ce->clone);
@@ -1238,12 +1244,18 @@ static void zend_file_cache_unserialize_class(zval                    *zv,
                                               void                    *buf)
 {
        zend_class_entry *ce;
+       zend_class_entry *parent = NULL;
 
        UNSERIALIZE_PTR(Z_PTR_P(zv));
        ce = Z_PTR_P(zv);
 
        UNSERIALIZE_STR(ce->name);
-       UNSERIALIZE_PTR(ce->parent);
+       if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+               UNSERIALIZE_STR(ce->parent_name);
+       } else {
+               UNSERIALIZE_PTR(ce->parent);
+               parent = ce->parent;
+       }
        zend_file_cache_unserialize_hash(&ce->function_table,
                        script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
        if (ce->default_properties_table) {
@@ -1264,7 +1276,7 @@ static void zend_file_cache_unserialize_class(zval                    *zv,
                 * Static properties from parent classes will be handled in class_copy_ctor */
                UNSERIALIZE_PTR(ce->default_static_members_table);
                table = ce->default_static_members_table;
-               p = table + (ce->parent ? ce->parent->default_static_members_count : 0);
+               p = table + (parent ? parent->default_static_members_count : 0);
                end = table + ce->default_static_members_count;
                while (p < end) {
                        zend_file_cache_unserialize_zval(p, script, buf);
index 89e9f46fc6f3c8986f2b90038e94568cfbe180c2..f023782d3d6f1714fa73acd94235127612d1fa34 100644 (file)
@@ -722,6 +722,9 @@ static void zend_persist_class_entry(zval *zv)
                ce = Z_PTR_P(zv) = ZCG(arena_mem);
                ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_class_entry)));
                zend_accel_store_interned_string(ce->name);
+               if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+                       zend_accel_store_interned_string(ce->parent_name);
+               }
                zend_hash_persist(&ce->function_table, zend_persist_class_method);
                if (ce->default_properties_table) {
                    int i;
@@ -737,7 +740,7 @@ static void zend_persist_class_entry(zval *zv)
 
                        /* Persist only static properties in this class.
                         * Static properties from parent classes will be handled in class_copy_ctor */
-                       i = ce->parent ? ce->parent->default_static_members_count : 0;
+                       i = (ce->parent && !(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) ? ce->parent->default_static_members_count : 0;
                        for (; i < ce->default_static_members_count; i++) {
                                zend_persist_zval(&ce->default_static_members_table[i]);
                        }
@@ -838,7 +841,7 @@ static int zend_update_parent_ce(zval *zv)
 {
        zend_class_entry *ce = Z_PTR_P(zv);
 
-       if (ce->parent) {
+       if (ce->parent && !(ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT)) {
                ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
        }
 
index 1ce039641c902331fca75e13813eb2b6f0fbee07..4032032e8a4bfe8fe9b7d8f6a1e2606118089e6d 100644 (file)
@@ -312,6 +312,9 @@ static void zend_persist_class_entry_calc(zval *zv)
        if (ce->type == ZEND_USER_CLASS) {
                ADD_ARENA_SIZE(sizeof(zend_class_entry));
                ADD_INTERNED_STRING(ce->name, 0);
+               if (ce->ce_flags & ZEND_ACC_UNRESOLVED_PARENT) {
+                       ADD_INTERNED_STRING(ce->parent_name, 0);
+               }
                zend_hash_persist_calc(&ce->function_table, zend_persist_class_method_calc);
                if (ce->default_properties_table) {
                    int i;