]> granicus.if.org Git - php/commitdiff
Added HashTable flag HASH_FLAG_STATIC_KEYS that is maintaned to be set if all hash...
authorDmitry Stogov <dmitry@zend.com>
Fri, 24 Apr 2015 06:34:50 +0000 (09:34 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 24 Apr 2015 06:34:50 +0000 (09:34 +0300)
Take this flag into account when copy or destroy HashTable to avoud useless checks for each key.

Zend/zend_hash.c
Zend/zend_hash.h
ext/opcache/zend_persist.c

index 5aa8620683d44a7ab0c5fbf726127419c374b7f4..c187aef2002da7369745354a368fadc86722dffd 100644 (file)
@@ -147,7 +147,7 @@ ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_
 {
        GC_REFCOUNT(ht) = 1;
        GC_TYPE_INFO(ht) = IS_ARRAY;
-       ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION;
+       ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
        ht->nTableSize = zend_hash_check_size(nSize);
        ht->nTableMask = HT_MIN_MASK;
        HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
@@ -201,7 +201,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
 
        HT_ASSERT(GC_REFCOUNT(ht) == 1);
        HANDLE_BLOCK_INTERRUPTIONS();
-       ht->u.flags |= HASH_FLAG_PACKED;
+       ht->u.flags |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
        ht->nTableMask = HT_MIN_MASK;
        HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
        HT_HASH_RESET_PACKED(ht);
@@ -518,7 +518,10 @@ add_to_hash:
        p = ht->arData + idx;
        p->h = h = zend_string_hash_val(key);
        p->key = key;
-       zend_string_addref(key);
+       if (!IS_INTERNED(key)) {
+               zend_string_addref(key);
+               ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
+       }
        ZVAL_COPY_VALUE(&p->val, pData);
        nIndex = h | ht->nTableMask;
        Z_NEXT(p->val) = HT_HASH(ht, nIndex);
@@ -1127,7 +1130,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
                if (ht->pDestructor) {
                        SET_INCONSISTENT(HT_IS_DESTROYING);
 
-                       if (ht->u.flags & HASH_FLAG_PACKED) {
+                       if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
                                do {
                                        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
                                                ht->pDestructor(&p->val);
@@ -1146,7 +1149,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
 
                        SET_INCONSISTENT(HT_DESTROYED);
                } else {
-                       if (!(ht->u.flags & HASH_FLAG_PACKED)) {
+                       if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) {
                                do {
                                        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
                                                if (EXPECTED(p->key)) {
@@ -1182,7 +1185,7 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
                end = p + ht->nNumUsed;
                SET_INCONSISTENT(HT_IS_DESTROYING);
 
-               if (ht->u.flags & HASH_FLAG_PACKED) {
+               if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
                        do {
                                i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
                        } while (++p != end);
@@ -1217,7 +1220,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
                p = ht->arData;
                end = p + ht->nNumUsed;
                if (ht->pDestructor) {
-                       if (ht->u.flags & HASH_FLAG_PACKED) {
+                       if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
                                do {
                                        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
                                                ht->pDestructor(&p->val);
@@ -1234,7 +1237,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
                                } while (++p != end);
                        }
                } else {
-                       if (!(ht->u.flags & HASH_FLAG_PACKED)) {
+                       if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) {
                                do {
                                        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
                                                if (EXPECTED(p->key)) {
@@ -1264,17 +1267,23 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
        if (ht->nNumUsed) {
                p = ht->arData;
                end = p + ht->nNumUsed;
-               do {
-                       if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
-                               i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
-                               if (EXPECTED(p->key)) {
-                                       zend_string_release(p->key);
+               if (ht->u.flags & HASH_FLAG_STATIC_KEYS) {
+                       do {
+                               if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
+                                       ht->pDestructor(&p->val);
                                }
-                       }
-               } while (++p != end);
-               if (!(ht->u.flags & HASH_FLAG_PACKED)) {
-                       HT_HASH_RESET(ht);
+                       } while (++p != end);
+               } else {
+                       do {
+                               if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
+                                       i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
+                                       if (EXPECTED(p->key)) {
+                                               zend_string_release(p->key);
+                                       }
+                               }
+                       } while (++p != end);
                }
+               HT_HASH_RESET(ht);
        }
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
@@ -1521,7 +1530,22 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
 
        target_idx = 0;
        if (target->u.flags & HASH_FLAG_INITIALIZED) {
-               if (target->u.flags & HASH_FLAG_PACKED) {
+               if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
+                       target->nNumUsed = source->nNumUsed;
+                       target->nNumOfElements = source->nNumOfElements;
+                       target->nNextFreeElement = source->nNextFreeElement;
+                       HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
+                       target->nInternalPointer = source->nInternalPointer;
+                       memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source));
+                       if (target->nNumOfElements > 0 &&
+                           target->nInternalPointer == HT_INVALID_IDX) {
+                               idx = 0;
+                               while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
+                                       idx++;
+                               }
+                               target->nInternalPointer = idx;
+                       }
+               } else if (target->u.flags & HASH_FLAG_PACKED) {
                        target->nNumUsed = source->nNumUsed;
                        target->nNumOfElements = source->nNumOfElements;
                        target->nNextFreeElement = source->nNextFreeElement;
@@ -1568,6 +1592,50 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
                                }
                                target->nInternalPointer = idx;
                        }
+               } else if (target->u.flags & HASH_FLAG_STATIC_KEYS) {
+                       target->nNextFreeElement = source->nNextFreeElement;
+                       HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
+                       HT_HASH_RESET(target);
+
+                       for (idx = 0; idx < source->nNumUsed; idx++) {
+                               p = source->arData + idx;
+                               if (Z_TYPE(p->val) == IS_UNDEF) continue;
+                               /* INDIRECT element may point to UNDEF-ined slots */
+                               data = &p->val;
+                               if (Z_TYPE_P(data) == IS_INDIRECT) {
+                                       data = Z_INDIRECT_P(data);
+                                       if (Z_TYPE_P(data) == IS_UNDEF) {
+                                               continue;
+                                       }
+                               }
+
+                               if (source->nInternalPointer == idx) {
+                                       target->nInternalPointer = target_idx;
+                               }
+
+                               q = target->arData + target_idx;
+                               q->h = p->h;
+                               q->key = p->key;
+                               nIndex = q->h | target->nTableMask;
+                               Z_NEXT(q->val) = HT_HASH(target, nIndex);
+                               HT_HASH(target, nIndex) = HT_IDX_TO_HASH(target_idx);
+                               if (Z_OPT_REFCOUNTED_P(data)) {
+                                       if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
+                                               ZVAL_COPY(&q->val, Z_REFVAL_P(data));
+                                       } else {
+                                               ZVAL_COPY(&q->val, data);
+                                       }
+                               } else {
+                                       ZVAL_COPY_VALUE(&q->val, data);
+                               }
+                               target_idx++;
+                       }
+                       target->nNumUsed = target_idx;
+                       target->nNumOfElements = target_idx;
+                       if (target->nNumOfElements > 0 &&
+                           target->nInternalPointer == HT_INVALID_IDX) {
+                               target->nInternalPointer = 0;
+                       }
                } else {
                        target->nNextFreeElement = source->nNextFreeElement;
                        HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
@@ -2043,7 +2111,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, co
                        void *old_data = HT_GET_DATA_ADDR(ht);
                        Bucket *old_buckets = ht->arData;
 
-                       ht->u.flags |= HASH_FLAG_PACKED;
+                       ht->u.flags |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
                        ht->nTableMask = HT_MIN_MASK;
                        HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT & HASH_FLAG_PERSISTENT));
                        memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
index 7ef9242ad2883451f0f7173197f255d991489e76..419b26149e7893af4b616bb2b77bbd5215e878cd 100644 (file)
@@ -38,6 +38,7 @@
 #define HASH_FLAG_APPLY_PROTECTION (1<<1)
 #define HASH_FLAG_PACKED           (1<<2)
 #define HASH_FLAG_INITIALIZED      (1<<3)
+#define HASH_FLAG_STATIC_KEYS      (1<<4)
 
 #define HASH_MASK_CONSISTENCY      0x60
 
@@ -879,8 +880,13 @@ static zend_always_inline void _zend_hash_append(HashTable *ht, zend_string *key
        Bucket *p = ht->arData + idx;
 
        ZVAL_COPY_VALUE(&p->val, zv);
-       p->key = zend_string_copy(key);
-       p->h = zend_string_hash_val(key);
+       if (!IS_INTERNED(key)) {
+               ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
+               zend_string_addref(key);
+               zend_string_hash_val(key);              
+       }
+       p->key = key;
+       p->h = key->h;
        nIndex = (uint32_t)p->h | ht->nTableMask;
        Z_NEXT(p->val) = HT_HASH(ht, nIndex);
        HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
@@ -895,8 +901,13 @@ static zend_always_inline void _zend_hash_append_ptr(HashTable *ht, zend_string
        Bucket *p = ht->arData + idx;
 
        ZVAL_PTR(&p->val, ptr);
-       p->key = zend_string_copy(key);
-       p->h = zend_string_hash_val(key);
+       if (!IS_INTERNED(key)) {
+               ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
+               zend_string_addref(key);
+               zend_string_hash_val(key);              
+       }
+       p->key = key;
+       p->h = key->h;
        nIndex = (uint32_t)p->h | ht->nTableMask;
        Z_NEXT(p->val) = HT_HASH(ht, nIndex);
        HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
@@ -911,8 +922,13 @@ static zend_always_inline void _zend_hash_append_ind(HashTable *ht, zend_string
        Bucket *p = ht->arData + idx;
 
        ZVAL_INDIRECT(&p->val, ptr);
-       p->key = zend_string_copy(key);
-       p->h = zend_string_hash_val(key);
+       if (!IS_INTERNED(key)) {
+               ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
+               zend_string_addref(key);
+               zend_string_hash_val(key);              
+       }
+       p->key = key;
+       p->h = key->h;
        nIndex = (uint32_t)p->h | ht->nTableMask;
        Z_NEXT(p->val) = HT_HASH(ht, nIndex);
        HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
index 2b94e3da7baac6a1b72ff705b47767aac4d4fcf8..b8a8694b84ea60247c58b1b2d36b5cc20b8c5165 100644 (file)
@@ -268,6 +268,7 @@ static void zend_persist_zval(zval *z)
                                        Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
                                        GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
                                        GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
+                                       Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS;
                                        Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
                                }
                        }
@@ -323,6 +324,7 @@ static void zend_persist_zval_static(zval *z)
                                        Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
                                        GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
                                        GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
+                                       Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS;
                                        Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
                                }
                        }
@@ -380,6 +382,7 @@ static void zend_persist_zval_const(zval *z)
                                        Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
                                        GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
                                        GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
+                                       Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS;
                                        Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
                                }
                        }
@@ -445,6 +448,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                        /* make immutable array */
                        GC_REFCOUNT(op_array->static_variables) = 2;
                        GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
+                       op_array->static_variables->u.flags |= HASH_FLAG_STATIC_KEYS;
                        op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
                }
        }