summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-03-04 17:41:01 +0300
committerDmitry Stogov <dmitry@zend.com>2015-03-04 17:41:01 +0300
commit8ec8648c911d848c86316b8dce2b9d8ce23098ff (patch)
tree71a4dc447acefa24a4a228936c9ddd39ba38e774
parentfefbddf22b2a4cd4edbff0e0945b68b563530b2b (diff)
downloadphp-git-8ec8648c911d848c86316b8dce2b9d8ce23098ff.tar.gz
Improved code for class property inheritance
-rw-r--r--Zend/zend_compile.c13
-rw-r--r--Zend/zend_hash.c32
-rw-r--r--Zend/zend_hash.h17
-rw-r--r--Zend/zend_inheritance.c87
-rw-r--r--Zend/zend_opcode.c9
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.c43
-rw-r--r--ext/opcache/zend_persist.c23
-rw-r--r--ext/opcache/zend_persist_calc.c11
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);
+ }
}
}