From: Dmitry Stogov Date: Tue, 26 Apr 2016 21:24:20 +0000 (+0300) Subject: Optimize property guards for the most usual case with only one acive guard. X-Git-Tag: php-7.1.0alpha1~266 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e88c71d3560d06a3d5a330b8572dd2aa83ecc5b6;p=php Optimize property guards for the most usual case with only one acive guard. --- diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 9abe3875ef..d0c5106342 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -486,31 +486,58 @@ ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_inf /* }}} */ static void zend_property_guard_dtor(zval *el) /* {{{ */ { - efree_size(Z_PTR_P(el), sizeof(zend_ulong)); + uint32_t *ptr = (uint32_t*)Z_PTR_P(el); + if (EXPECTED(!(((zend_uintptr_t)ptr) & 1))) { + efree_size(ptr, sizeof(uint32_t)); + } } /* }}} */ -static zend_long *zend_get_property_guard(zend_object *zobj, zend_string *member) /* {{{ */ +static uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member) /* {{{ */ { HashTable *guards; - zend_long stub, *guard; + zval *zv; + uint32_t *ptr; ZEND_ASSERT(GC_FLAGS(zobj) & IS_OBJ_USE_GUARDS); - if (GC_FLAGS(zobj) & IS_OBJ_HAS_GUARDS) { - guards = Z_PTR(zobj->properties_table[zobj->ce->default_properties_count]); + zv = zobj->properties_table + zobj->ce->default_properties_count; + if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) { + zend_string *str = Z_STR_P(zv); + if (EXPECTED(str == member) || + /* hash values are always pred-calculated here */ + (EXPECTED(ZSTR_H(str) == ZSTR_H(member)) && + EXPECTED(ZSTR_LEN(str) == ZSTR_LEN(member)) && + EXPECTED(memcmp(ZSTR_VAL(str), ZSTR_VAL(member), ZSTR_LEN(member)) == 0))) { + return &zv->u2.property_guard; + } else if (EXPECTED(zv->u2.property_guard == 0)) { + zend_string_release(Z_STR_P(zv)); + ZVAL_STR_COPY(zv, member); + return &zv->u2.property_guard; + } else { + ALLOC_HASHTABLE(guards); + zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0); + /* mark pointer as "special" using low bit */ + zend_hash_add_new_ptr(guards, member, (void*)(((zend_uintptr_t)&zv->u2.property_guard) | 1)); + ZVAL_ARR(zv, guards); + } + } else if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) { + guards = Z_ARRVAL_P(zv); ZEND_ASSERT(guards != NULL); - if ((guard = (zend_long *)zend_hash_find_ptr(guards, member)) != NULL) { - return guard; + zv = zend_hash_find(guards, member); + if (zv != NULL) { + return (uint32_t*)(((zend_uintptr_t)Z_PTR_P(zv)) & ~1); } } else { - ALLOC_HASHTABLE(guards); - zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0); - Z_PTR(zobj->properties_table[zobj->ce->default_properties_count]) = guards; + ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF); GC_FLAGS(zobj) |= IS_OBJ_HAS_GUARDS; - } - - stub = 0; - return (zend_long *)zend_hash_add_mem(guards, member, &stub, sizeof(zend_ulong)); + ZVAL_STR_COPY(zv, member); + zv->u2.property_guard = 0; + return &zv->u2.property_guard; + } + /* we have to allocate uint32_t separately because ht->arData may be reallocated */ + ptr = (uint32_t*)emalloc(sizeof(uint32_t)); + *ptr = 0; + return (uint32_t*)zend_hash_add_new_ptr(guards, member, ptr); } /* }}} */ @@ -555,7 +582,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_ /* magic isset */ if ((type == BP_VAR_IS) && zobj->ce->__isset) { zval tmp_object, tmp_result; - zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member)); + uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member)); if (!((*guard) & IN_ISSET)) { ZVAL_COPY(&tmp_object, object); @@ -579,7 +606,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_ /* magic get */ if (zobj->ce->__get) { - zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member)); + uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member)); if (!((*guard) & IN_GET)) { zval tmp_object; @@ -674,7 +701,7 @@ found: /* magic set */ if (zobj->ce->__set) { - zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member)); + uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member)); if (!((*guard) & IN_SET)) { zval tmp_object; @@ -944,7 +971,7 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo /* magic unset */ if (zobj->ce->__unset) { - zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member)); + uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member)); if (!((*guard) & IN_UNSET)) { zval tmp_object; @@ -1507,7 +1534,7 @@ found: result = 0; if ((has_set_exists != 2) && zobj->ce->__isset) { - zend_long *guard = zend_get_property_guard(zobj, Z_STR_P(member)); + uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member)); if (!((*guard) & IN_ISSET)) { zval rv; diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 793d1ac4c3..0f052335db 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -46,7 +46,6 @@ ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce) } if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) { GC_FLAGS(object) |= IS_OBJ_USE_GUARDS; - Z_PTR_P(p) = NULL; ZVAL_UNDEF(p); } } @@ -71,11 +70,17 @@ ZEND_API void zend_object_std_dtor(zend_object *object) } while (p != end); } if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_HAS_GUARDS)) { - HashTable *guards = Z_PTR_P(p); + if (EXPECTED(Z_TYPE_P(p) == IS_STRING)) { + zend_string_release(Z_STR_P(p)); + } else { + HashTable *guards; - ZEND_ASSERT(guards != NULL); - zend_hash_destroy(guards); - FREE_HASHTABLE(guards); + ZEND_ASSERT(Z_TYPE_P(p) == IS_ARRAY); + guards = Z_ARRVAL_P(p); + ZEND_ASSERT(guards != NULL); + zend_hash_destroy(guards); + FREE_HASHTABLE(guards); + } } } diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 9545b53e33..b775bd7e53 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -138,6 +138,7 @@ struct _zval_struct { uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ uint32_t access_flags; /* class constant access flags */ + uint32_t property_guard; /* single property guard */ } u2; };