diff options
Diffstat (limited to 'Zend/zend_inheritance.c')
| -rw-r--r-- | Zend/zend_inheritance.c | 190 |
1 files changed, 120 insertions, 70 deletions
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 8d11513090..46a674ba90 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -79,7 +79,7 @@ static zend_function *zend_duplicate_function(zend_function *func, zend_class_en return func; } if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(func->op_array.static_variables)++; + GC_ADDREF(func->op_array.static_variables); } new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_function, func, sizeof(zend_op_array)); @@ -410,14 +410,8 @@ static ZEND_COLD void zend_append_type_hint(smart_str *str, const zend_function smart_str_appendc(str, ' '); } } else if (ZEND_TYPE_IS_CODE(arg_info->type)) { - if (ZEND_TYPE_CODE(arg_info->type) == IS_LONG) { - smart_str_appendl(str, "int", 3); - } else if (ZEND_TYPE_CODE(arg_info->type) == _IS_BOOL) { - smart_str_appendl(str, "bool", 4); - } else { - const char *type_name = zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)); - smart_str_appends(str, type_name); - } + const char *type_name = zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)); + smart_str_appends(str, type_name); if (!return_hint) { smart_str_appendc(str, ' '); } @@ -495,11 +489,9 @@ static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function } } if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { - zval *zv = RT_CONSTANT(&fptr->op_array, precv->op2); + zval *zv = RT_CONSTANT(precv, precv->op2); - if (Z_TYPE_P(zv) == IS_CONSTANT) { - smart_str_append(&str, Z_STR_P(zv)); - } else if (Z_TYPE_P(zv) == IS_FALSE) { + if (Z_TYPE_P(zv) == IS_FALSE) { smart_str_appends(&str, "false"); } else if (Z_TYPE_P(zv) == IS_TRUE) { smart_str_appends(&str, "true"); @@ -515,11 +507,17 @@ static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function } else if (Z_TYPE_P(zv) == IS_ARRAY) { smart_str_appends(&str, "Array"); } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) { - smart_str_appends(&str, "<expression>"); + zend_ast *ast = Z_ASTVAL_P(zv); + if (ast->kind == ZEND_AST_CONSTANT) { + smart_str_append(&str, zend_ast_get_constant_name(ast)); + } else { + smart_str_appends(&str, "<expression>"); + } } else { - zend_string *zv_str = zval_get_string(zv); + zend_string *tmp_zv_str; + zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str); smart_str_append(&str, zv_str); - zend_string_release(zv_str); + zend_tmp_string_release(tmp_zv_str); } } } else { @@ -629,7 +627,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function * static zend_function *do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce) /* {{{ */ { - zval *child = zend_hash_find(&ce->function_table, key); + zval *child = zend_hash_find_ex(&ce->function_table, key, 1); if (child) { zend_function *func = (zend_function*)Z_PTR_P(child); @@ -659,7 +657,7 @@ static zend_function *do_inherit_method(zend_string *key, zend_function *parent, static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */ { - zval *child = zend_hash_find(&ce->properties_info, key); + zval *child = zend_hash_find_ex(&ce->properties_info, key, 1); zend_property_info *child_info; if (UNEXPECTED(child)) { @@ -761,27 +759,25 @@ ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_ static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */ { - zend_class_constant *c = zend_hash_find_ptr(&ce->constants_table, name); + zval *zv = zend_hash_find_ex(&ce->constants_table, name, 1); + zend_class_constant *c; - if (c != NULL) { + if (zv != NULL) { + c = (zend_class_constant*)Z_PTR_P(zv); if (UNEXPECTED((Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PPP_MASK) > (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PPP_MASK))) { zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s", ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(Z_ACCESS_FLAGS(parent_const->value)), ZSTR_VAL(ce->parent->name), (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PUBLIC) ? "" : " or weaker"); } } else if (!(Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PRIVATE)) { - if (Z_CONSTANT(parent_const->value)) { + if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) { ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } if (ce->type & ZEND_INTERNAL_CLASS) { - if (Z_REFCOUNTED(parent_const->value)) { - Z_ADDREF(parent_const->value); - } c = pemalloc(sizeof(zend_class_constant), 1); memcpy(c, parent_const, sizeof(zend_class_constant)); - } else { - c = parent_const; + parent_const = c; } - _zend_hash_append_ptr(&ce->constants_table, name, c); + _zend_hash_append_ptr(&ce->constants_table, name, parent_const); } } /* }}} */ @@ -839,24 +835,28 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent ce->default_properties_table = end; } src = parent_ce->default_properties_table + parent_ce->default_properties_count; - do { - dst--; - src--; -#ifdef ZTS - if (parent_ce->type != ce->type) { - ZVAL_DUP(dst, src); - if (Z_OPT_CONSTANT_P(dst)) { + if (UNEXPECTED(parent_ce->type != ce->type)) { + /* User class extends internal */ + do { + dst--; + src--; + ZVAL_COPY_OR_DUP(dst, src); + if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) { ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } continue; - } -#endif - - ZVAL_COPY(dst, src); - if (Z_OPT_CONSTANT_P(dst)) { - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; - } - } while (dst != end); + } while (dst != end); + } else { + do { + dst--; + src--; + ZVAL_COPY(dst, src); + if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) { + ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; + } + continue; + } while (dst != end); + } ce->default_properties_count += parent_ce->default_properties_count; } @@ -881,23 +881,49 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent dst = end + parent_ce->default_static_members_count; ce->default_static_members_table = end; } - src = parent_ce->default_static_members_table + parent_ce->default_static_members_count; - do { - dst--; - src--; - if (parent_ce->type == ZEND_INTERNAL_CLASS) { + if (UNEXPECTED(parent_ce->type != ce->type)) { + /* User class extends internal */ + if (UNEXPECTED(zend_update_class_constants(parent_ce) != SUCCESS)) { + ZEND_ASSERT(0); + } + src = CE_STATIC_MEMBERS(parent_ce) + parent_ce->default_static_members_count; + do { + dst--; + src--; + if (Z_ISREF_P(src)) { + Z_ADDREF_P(src); + } else { + ZVAL_MAKE_REF_EX(src, 2); + } + ZVAL_REF(dst, Z_REF_P(src)); + } while (dst != end); + } else if (ce->type == ZEND_USER_CLASS) { + src = parent_ce->default_static_members_table + parent_ce->default_static_members_count; + do { + dst--; + src--; + if (Z_ISREF_P(src)) { + Z_ADDREF_P(src); + } else { + ZVAL_MAKE_REF_EX(src, 2); + } + ZVAL_REF(dst, Z_REF_P(src)); + if (Z_TYPE_P(Z_REFVAL_P(dst)) == IS_CONSTANT_AST) { + ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; + } + } while (dst != end); + } else { + src = parent_ce->default_static_members_table + parent_ce->default_static_members_count; + do { + dst--; + src--; if (!Z_ISREF_P(src)) { ZVAL_NEW_PERSISTENT_REF(src, src); } - } else { - ZVAL_MAKE_REF(src); - } - ZVAL_COPY_VALUE(dst, src); - Z_ADDREF_P(dst); - if (Z_CONSTANT_P(Z_REFVAL_P(dst))) { - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; - } - } while (dst != end); + ZVAL_COPY_VALUE(dst, src); + Z_ADDREF_P(dst); + } while (dst != end); + } ce->default_static_members_count += parent_ce->default_static_members_count; if (ce->type == ZEND_USER_CLASS) { ce->static_members_table = ce->default_static_members_table; @@ -966,9 +992,11 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zend_class_constant *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */ { + zval *zv = zend_hash_find_ex(child_constants_table, name, 1); zend_class_constant *old_constant; - if ((old_constant = zend_hash_find_ptr(child_constants_table, name)) != NULL) { + if (zv != NULL) { + old_constant = (zend_class_constant*)Z_PTR_P(zv); if (old_constant->ce != parent_constant->ce) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", ZSTR_VAL(name), ZSTR_VAL(iface->name)); } @@ -982,19 +1010,15 @@ static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, { if (do_inherit_constant_check(&ce->constants_table, c, name, iface)) { zend_class_constant *ct; - if (Z_CONSTANT(c->value)) { + if (Z_TYPE(c->value) == IS_CONSTANT_AST) { ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } if (ce->type & ZEND_INTERNAL_CLASS) { - if (Z_REFCOUNTED(c->value)) { - Z_ADDREF(c->value); - } ct = pemalloc(sizeof(zend_class_constant), 1); memcpy(ct, c, sizeof(zend_class_constant)); - } else { - ct = c; + c = ct; } - zend_hash_update_ptr(&ce->constants_table, name, ct); + zend_hash_update_ptr(&ce->constants_table, name, c); } } /* }}} */ @@ -1145,6 +1169,11 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s zend_function *new_fn; if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) { + /* if it is the same function regardless of where it is coming from, there is no conflict and we do not need to add it again */ + if (existing_fn->op_array.opcodes == fn->op_array.opcodes) { + return; + } + if (existing_fn->common.scope == ce) { /* members from the current class override trait methods */ /* use temporary *overriden HashTable to detect hidden conflict */ @@ -1565,10 +1594,14 @@ static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */ zend_hash_del(&ce->properties_info, prop_name); flags |= ZEND_ACC_CHANGED; } else { + not_compatible = 1; + if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC)) == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) { - /* flags are identical, now the value needs to be checked */ + /* the flags are identical, thus, the properties may be compatible */ zval *op1, *op2; + zval op1_tmp, op2_tmp; + if (flags & ZEND_ACC_STATIC) { op1 = &ce->default_static_members_table[coliding_prop->offset]; op2 = &ce->traits[i]->default_static_members_table[property_info->offset]; @@ -1578,10 +1611,27 @@ static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */ op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(coliding_prop->offset)]; op2 = &ce->traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]; } + + /* if any of the values is a constant, we try to resolve it */ + if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) { + ZVAL_COPY_OR_DUP(&op1_tmp, op1); + zval_update_constant_ex(&op1_tmp, ce); + op1 = &op1_tmp; + } + if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) { + ZVAL_COPY_OR_DUP(&op2_tmp, op2); + zval_update_constant_ex(&op2_tmp, ce); + op2 = &op2_tmp; + } + not_compatible = fast_is_not_identical_function(op1, op2); - } else { - /* the flags are not identical, thus, we assume properties are not compatible */ - not_compatible = 1; + + if (op1 == &op1_tmp) { + zval_ptr_dtor_nogc(&op1_tmp); + } + if (op2 == &op2_tmp) { + zval_ptr_dtor_nogc(&op2_tmp); + } } if (not_compatible) { @@ -1604,8 +1654,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */ } else { prop_value = &ce->traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]; } - if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value); + Z_TRY_ADDREF_P(prop_value); doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL; zend_declare_property_ex(ce, prop_name, prop_value, flags, @@ -1669,7 +1719,7 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce) ZEND_API void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */ { - if (ce->num_traits <= 0) { + if (ce->num_traits == 0) { return; } |
