From: Dmitry Stogov Date: Thu, 23 Aug 2018 21:20:57 +0000 (+0300) Subject: Keep information about unresolved parent class in zend_class_entry->parent_name X-Git-Tag: php-7.4.0alpha1~2064 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8050f4a334ca43cc95a977413252fa45d3f3bdc3;p=php Keep information about unresolved parent class in zend_class_entry->parent_name --- diff --git a/Zend/zend.h b/Zend/zend.h index ee47d0b140..ba577274d9 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -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; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b1ac89cb5a..5482bf6ec5 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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)); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 9132ee2537..6c969d9961 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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 | | | */ /* | | | */ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 59bb5c4f18..d36d3040cb 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -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 */ diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 451104aaf0..28c85edb8a 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -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; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 46749b64c6..b3976dd115 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -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) { diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 7fb4c7bfb9..58409ee063 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -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; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 4f46c48994..ca284b7c85 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -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); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 89e9f46fc6..f023782d3d 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -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); } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 1ce039641c..4032032e8a 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -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;