diff options
| author | Dmitry Stogov <dmitry@zend.com> | 2015-03-04 17:41:01 +0300 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@zend.com> | 2015-03-04 17:41:01 +0300 |
| commit | 8ec8648c911d848c86316b8dce2b9d8ce23098ff (patch) | |
| tree | 71a4dc447acefa24a4a228936c9ddd39ba38e774 | |
| parent | fefbddf22b2a4cd4edbff0e0945b68b563530b2b (diff) | |
| download | php-git-8ec8648c911d848c86316b8dce2b9d8ce23098ff.tar.gz | |
Improved code for class property inheritance
| -rw-r--r-- | Zend/zend_compile.c | 13 | ||||
| -rw-r--r-- | Zend/zend_hash.c | 32 | ||||
| -rw-r--r-- | Zend/zend_hash.h | 17 | ||||
| -rw-r--r-- | Zend/zend_inheritance.c | 87 | ||||
| -rw-r--r-- | Zend/zend_opcode.c | 9 | ||||
| -rw-r--r-- | ext/opcache/zend_accelerator_util_funcs.c | 43 | ||||
| -rw-r--r-- | ext/opcache/zend_persist.c | 23 | ||||
| -rw-r--r-- | ext/opcache/zend_persist_calc.c | 11 |
8 files changed, 144 insertions, 91 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bb0ab25b59..1c4ecf7119 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -72,17 +72,6 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif -static void zend_destroy_property_info(zval *zv) /* {{{ */ -{ - zend_property_info *property_info = Z_PTR_P(zv); - - zend_string_release(property_info->name); - if (property_info->doc_comment) { - zend_string_release(property_info->doc_comment); - } -} -/* }}} */ - static void zend_destroy_property_info_internal(zval *zv) /* {{{ */ { zend_property_info *property_info = Z_PTR_P(zv); @@ -1415,7 +1404,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->default_properties_table = NULL; ce->default_static_members_table = NULL; - zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); + zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : NULL), persistent_hashes, 0); zend_hash_init_ex(&ce->constants_table, 8, NULL, zval_ptr_dtor_func, persistent_hashes, 0); zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index e4df989e56..f44129cbb0 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -209,6 +209,38 @@ ZEND_API void _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDes } } +ZEND_API void zend_hash_extend(HashTable *ht, uint32_t nSize, zend_bool packed) +{ + HT_ASSERT(GC_REFCOUNT(ht) == 1); + if (nSize == 0) return; + if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) { + if (nSize > ht->nTableSize) { + ht->nTableSize = zend_hash_check_size(nSize); + } + zend_hash_check_init(ht, packed); + } else { + if (packed) { + ZEND_ASSERT(ht->u.flags & HASH_FLAG_PACKED); + if (nSize > ht->nTableSize) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->nTableSize = zend_hash_check_size(nSize); + ht->arData = (Bucket *) perealloc(ht->arData, ht->nTableSize * sizeof(Bucket), ht->u.flags & HASH_FLAG_PERSISTENT); + HANDLE_UNBLOCK_INTERRUPTIONS(); + } + } else { + ZEND_ASSERT(!(ht->u.flags & HASH_FLAG_PACKED)); + if (nSize > ht->nTableSize) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->nTableSize = zend_hash_check_size(nSize); + ht->arData = (Bucket *) perealloc(ht->arData, ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)), ht->u.flags & HASH_FLAG_PERSISTENT); + ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize); + ht->nTableMask = ht->nTableSize - 1; + zend_hash_rehash(ht); + HANDLE_UNBLOCK_INTERRUPTIONS(); + } + } + } +} ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection) { diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 4583d34e99..5e285f40c4 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -63,6 +63,7 @@ ZEND_API void zend_hash_clean(HashTable *ht); ZEND_API void zend_hash_real_init(HashTable *ht, zend_bool packed); ZEND_API void zend_hash_packed_to_hash(HashTable *ht); ZEND_API void zend_hash_to_packed(HashTable *ht); +ZEND_API void zend_hash_extend(HashTable *ht, uint32_t nSize, zend_bool packed); /* additions/updates/changes */ ZEND_API zval *_zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC); @@ -799,6 +800,22 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, __fill_ht->nInternalPointer = 0; \ } while (0) +static zend_always_inline void _zend_hash_append_ptr(HashTable *ht, zend_string *key, void *ptr) +{ + uint32_t idx = ht->nNumUsed++; + uint32_t nIndex; + Bucket *p = ht->arData + idx; + + ZVAL_PTR(&p->val, ptr); + p->key = key; + p->h = key->h; + nIndex = p->h & ht->nTableMask; + Z_NEXT(p->val) = ht->arHash[nIndex]; + ht->arHash[nIndex] = idx; + ht->nNumUsed = idx + 1; + ht->nNumOfElements++; +} + #endif /* ZEND_HASH_H */ /* diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 10633d73a7..cc92569a99 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -635,53 +635,55 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f } /* }}} */ -static zend_bool do_inherit_property_access_check(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */ +static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */ { - zend_property_info *child_info; + zend_property_info *child_info = zend_hash_find_ptr(&ce->properties_info, key); zend_class_entry *parent_ce = ce->parent; - if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) { - if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) { + if (UNEXPECTED(child_info)) { + if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) { child_info->flags |= ZEND_ACC_CHANGED; } else { + if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s", + (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val, + (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val); + } + + if (parent_info->flags & ZEND_ACC_CHANGED) { + child_info->flags |= ZEND_ACC_CHANGED; + } + + if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) { + zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name->val, key->val, zend_visibility_string(parent_info->flags), parent_ce->name->val, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); + } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) { + int parent_num = OBJ_PROP_TO_NUM(parent_info->offset); + int child_num = OBJ_PROP_TO_NUM(child_info->offset); + + zval_ptr_dtor(&(ce->default_properties_table[parent_num])); + ce->default_properties_table[parent_num] = ce->default_properties_table[child_num]; + ZVAL_UNDEF(&ce->default_properties_table[child_num]); + child_info->offset = parent_info->offset; + } + } + } else { + if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) { if(ce->type & ZEND_INTERNAL_CLASS) { child_info = zend_duplicate_property_info_internal(parent_info); } else { child_info = zend_duplicate_property_info(parent_info); } - zend_hash_update_ptr(&ce->properties_info, key, child_info); child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */ child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */ + } else { + if (ce->type & ZEND_INTERNAL_CLASS) { + child_info = zend_duplicate_property_info_internal(parent_info); + } else { + child_info = parent_info; + } } - return 0; /* don't copy access information to child */ - } - - if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) { - if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s", - (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val, - (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val); - - } - - if(parent_info->flags & ZEND_ACC_CHANGED) { - child_info->flags |= ZEND_ACC_CHANGED; - } - - if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) { - zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name->val, key->val, zend_visibility_string(parent_info->flags), parent_ce->name->val, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); - } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) { - int parent_num = OBJ_PROP_TO_NUM(parent_info->offset); - int child_num = OBJ_PROP_TO_NUM(child_info->offset); - - zval_ptr_dtor(&(ce->default_properties_table[parent_num])); - ce->default_properties_table[parent_num] = ce->default_properties_table[child_num]; - ZVAL_UNDEF(&ce->default_properties_table[child_num]); - child_info->offset = parent_info->offset; - } - return 0; /* Don't copy from parent */ - } else { - return 1; /* Copy from parent */ + zend_string_addref(key); + _zend_hash_append_ptr(&ce->properties_info, key, child_info); } } /* }}} */ @@ -886,15 +888,12 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent } } ZEND_HASH_FOREACH_END(); + zend_hash_extend(&ce->properties_info, + zend_hash_num_elements(&ce->properties_info) + + zend_hash_num_elements(&parent_ce->properties_info), 0); + ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) { - if (do_inherit_property_access_check(property_info, key, ce)) { - if (ce->type & ZEND_INTERNAL_CLASS) { - property_info = zend_duplicate_property_info_internal(property_info); - } else { - property_info = zend_duplicate_property_info(property_info); - } - zend_hash_add_new_ptr(&ce->properties_info, key, property_info); - } + do_inherit_property(property_info, key, ce); } ZEND_HASH_FOREACH_END(); ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) { @@ -1485,6 +1484,10 @@ static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */ /* next: check for conflicts with current class */ if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) { if (coliding_prop->flags & ZEND_ACC_SHADOW) { + zend_string_release(coliding_prop->name); + if (coliding_prop->doc_comment) { + zend_string_release(coliding_prop->doc_comment); + } zend_hash_del(&ce->properties_info, prop_name); flags |= ZEND_ACC_CHANGED; } else { diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 0473fc9f26..e76cfe9498 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -233,6 +233,7 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) ZEND_API void destroy_zend_class(zval *zv) { + zend_property_info *prop_info; zend_class_entry *ce = Z_PTR_P(zv); if (--ce->refcount > 0) { @@ -260,6 +261,14 @@ ZEND_API void destroy_zend_class(zval *zv) } efree(ce->default_static_members_table); } + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { + if (prop_info->ce == ce || (prop_info->flags & ZEND_ACC_SHADOW)) { + zend_string_release(prop_info->name); + if (prop_info->doc_comment) { + zend_string_release(prop_info->doc_comment); + } + } + } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&ce->properties_info); zend_string_release(ce->name); zend_hash_destroy(&ce->function_table); diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index ae6e8c8555..e4430bf0a2 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -158,16 +158,6 @@ void zend_accel_copy_internal_functions(void) ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table)); } -static void zend_destroy_property_info(zval *zv) -{ - zend_property_info *property_info = Z_PTR_P(zv); - - zend_string_release(property_info->name); - if (property_info->doc_comment) { - zend_string_release(property_info->doc_comment); - } -} - static zend_always_inline zend_string *zend_clone_str(zend_string *str) { zend_string *ret; @@ -420,7 +410,7 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class } } -static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce) +static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce) { uint idx; Bucket *p, *q; @@ -432,7 +422,7 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla ht->nNumUsed = 0; ht->nNumOfElements = source->nNumOfElements; ht->nNextFreeElement = source->nNextFreeElement; - ht->pDestructor = zend_destroy_property_info; + ht->pDestructor = NULL; ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED); ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX; @@ -463,19 +453,24 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla q->key = zend_clone_str(p->key); /* Copy data */ - ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val))); - prop_info = Z_PTR(q->val); - - /* Copy constructor */ - prop_info->name = zend_clone_str(prop_info->name); - if (prop_info->doc_comment) { - if (ZCG(accel_directives).load_comments) { - prop_info->doc_comment = zend_string_dup(prop_info->doc_comment, 0); - } else { - prop_info->doc_comment = NULL; + prop_info = ARENA_REALLOC(Z_PTR(p->val)); + ZVAL_PTR(&q->val, prop_info); + + if (prop_info->ce == old_ce || (prop_info->flags & ZEND_ACC_SHADOW)) { + /* Copy constructor */ + prop_info->name = zend_clone_str(prop_info->name); + if (prop_info->doc_comment) { + if (ZCG(accel_directives).load_comments) { + prop_info->doc_comment = zend_string_dup(prop_info->doc_comment, 0); + } else { + prop_info->doc_comment = NULL; + } } + prop_info->ce = ARENA_REALLOC(prop_info->ce); + } else if ((void*)prop_info->ce >= ZCG(current_persistent_script)->arena_mem && + (void*)prop_info->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) { + prop_info->ce = ARENA_REALLOC(prop_info->ce); } - prop_info->ce = ARENA_REALLOC(prop_info->ce); } } @@ -520,7 +515,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce) ce->static_members_table = ce->default_static_members_table; /* properties_info */ - zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce, ce); + zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce); /* constants table */ zend_hash_clone_zval(&ce->constants_table, &old_ce->constants_table, 1); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index c0cd5b270b..fdba5069f4 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -581,12 +581,17 @@ static void zend_persist_op_array(zval *zv) static void zend_persist_property_info(zval *zv) { - zend_property_info *prop; + zend_property_info *prop = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv)); + if (prop) { + Z_PTR_P(zv) = prop; + return; + } memcpy(ZCG(arena_mem), Z_PTR_P(zv), sizeof(zend_property_info)); zend_shared_alloc_register_xlat_entry(Z_PTR_P(zv), ZCG(arena_mem)); prop = Z_PTR_P(zv) = ZCG(arena_mem); ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(sizeof(zend_property_info))); + prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce); zend_accel_store_interned_string(prop->name); if (prop->doc_comment) { if (ZCG(accel_directives).save_comments) { @@ -714,13 +719,13 @@ static void zend_persist_class_entry(zval *zv) } } -static int zend_update_property_info_ce(zval *zv) -{ - zend_property_info *prop = Z_PTR_P(zv); - - prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce); - return 0; -} +//static int zend_update_property_info_ce(zval *zv) +//{ +// zend_property_info *prop = Z_PTR_P(zv); +// +// prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce); +// return 0; +//} static int zend_update_parent_ce(zval *zv) { @@ -770,7 +775,7 @@ static int zend_update_parent_ce(zval *zv) if (ce->__debugInfo) { ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo); } - zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce); +// zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce); return 0; } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 7d77d62b8d..d7fbaa272a 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -255,10 +255,13 @@ static void zend_persist_property_info_calc(zval *zv) { zend_property_info *prop = Z_PTR_P(zv); - ADD_ARENA_SIZE(sizeof(zend_property_info)); - ADD_INTERNED_STRING(prop->name, 0); - if (ZCG(accel_directives).save_comments && prop->doc_comment) { - ADD_STRING(prop->doc_comment); + if (!zend_shared_alloc_get_xlat_entry(prop)) { + zend_shared_alloc_register_xlat_entry(prop, prop); + ADD_ARENA_SIZE(sizeof(zend_property_info)); + ADD_INTERNED_STRING(prop->name, 0); + if (ZCG(accel_directives).save_comments && prop->doc_comment) { + ADD_STRING(prop->doc_comment); + } } } |
