]> granicus.if.org Git - php/commitdiff
Improve HashTable iterators handling:
authorDmitry Stogov <dmitry@zend.com>
Wed, 21 Mar 2018 23:41:49 +0000 (02:41 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 21 Mar 2018 23:41:49 +0000 (02:41 +0300)
- Avoid iterators check/update on each HashTable update opration
- Keep position equal (or above) nNumUsed instead of HT_INVALID_IDX
- Fixed iterators handling in array_unshift()

Zend/zend_hash.c
Zend/zend_hash.h
Zend/zend_object_handlers.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/zend_accelerator_util_funcs.c
ext/spl/spl_array.c
ext/spl/spl_observer.c
ext/standard/array.c
tests/lang/foreachLoop.013.phpt
tests/lang/foreachLoop.015.phpt

index b209cbb70ee8e36ab9256de247498bead4059b8c..d5de72e95a0989b53addcbaa4a9693ad479c3fe7 100644 (file)
@@ -166,7 +166,7 @@ ZEND_API const HashTable zend_empty_array = {
        .nNumUsed = 0,
        .nNumOfElements = 0,
        .nTableSize = HT_MIN_SIZE,
-       .nInternalPointer = HT_INVALID_IDX,
+       .nInternalPointer = 0,
        .nNextFreeElement = 0,
        .pDestructor = ZVAL_PTR_DTOR
 };
@@ -180,7 +180,7 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize
        HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
-       ht->nInternalPointer = HT_INVALID_IDX;
+       ht->nInternalPointer = 0;
        ht->nNextFreeElement = 0;
        ht->pDestructor = pDestructor;
        ht->nTableSize = zend_hash_check_size(nSize);
@@ -313,6 +313,31 @@ ZEND_API uint32_t zend_array_count(HashTable *ht)
 }
 /* }}} */
 
+static zend_always_inline HashPosition _zend_hash_get_first_pos(const HashTable *ht)
+{
+       HashPosition pos = 0;
+
+       while (pos < ht->nNumUsed && Z_ISUNDEF(ht->arData[pos].val)) {
+               pos++;
+       }
+       return pos;
+}
+
+static zend_always_inline HashPosition _zend_hash_get_current_pos(const HashTable *ht)
+{
+       HashPosition pos = ht->nInternalPointer;
+
+       if (pos == 0) {
+               pos = _zend_hash_get_first_pos(ht);
+       }
+       return pos;
+}
+
+ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht)
+{
+       return _zend_hash_get_current_pos(ht);
+}
+
 ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
 {
        HashTableIterator *iter = EG(ht_iterators);
@@ -355,9 +380,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTab
        HashTableIterator *iter = EG(ht_iterators) + idx;
 
        ZEND_ASSERT(idx != (uint32_t)-1);
-       if (iter->pos == HT_INVALID_IDX) {
-               return HT_INVALID_IDX;
-       } else if (UNEXPECTED(iter->ht != ht)) {
+       if (UNEXPECTED(iter->ht != ht)) {
                if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
                                && EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
                        HT_DEC_ITERATORS_COUNT(iter->ht);
@@ -366,7 +389,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTab
                        HT_INC_ITERATORS_COUNT(ht);
                }
                iter->ht = ht;
-               iter->pos = ht->nInternalPointer;
+               iter->pos = _zend_hash_get_current_pos(ht);
        }
        return iter->pos;
 }
@@ -377,9 +400,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval
        HashTableIterator *iter = EG(ht_iterators) + idx;
 
        ZEND_ASSERT(idx != (uint32_t)-1);
-       if (iter->pos == HT_INVALID_IDX) {
-               return HT_INVALID_IDX;
-       } else if (UNEXPECTED(iter->ht != ht)) {
+       if (UNEXPECTED(iter->ht != ht)) {
                if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
                                && EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
                        HT_DEC_ITERATORS_COUNT(iter->ht);
@@ -390,7 +411,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval
                        HT_INC_ITERATORS_COUNT(ht);
                }
                iter->ht = ht;
-               iter->pos = ht->nInternalPointer;
+               iter->pos = _zend_hash_get_current_pos(ht);
        }
        return iter->pos;
 }
@@ -439,7 +460,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht,
 {
        HashTableIterator *iter = EG(ht_iterators);
        HashTableIterator *end  = iter + EG(ht_iterators_used);
-       HashPosition res = HT_INVALID_IDX;
+       HashPosition res = ht->nNumUsed;
 
        while (iter != end) {
                if (iter->ht == ht) {
@@ -465,6 +486,19 @@ ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosit
        }
 }
 
+ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step)
+{
+       HashTableIterator *iter = EG(ht_iterators);
+       HashTableIterator *end  = iter + EG(ht_iterators_used);
+
+       while (iter != end) {
+               if (iter->ht == ht) {
+                       iter->pos += step;
+               }
+               iter++;
+       }
+}
+
 static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key, zend_bool known_hash)
 {
        zend_ulong h;
@@ -610,10 +644,6 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s
 add_to_hash:
        idx = ht->nNumUsed++;
        ht->nNumOfElements++;
-       if (ht->nInternalPointer == HT_INVALID_IDX) {
-               ht->nInternalPointer = idx;
-       }
-       zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
        arData = ht->arData;
        p = arData + idx;
        p->key = key;
@@ -681,10 +711,6 @@ static zend_always_inline zval *_zend_hash_str_add_or_update_i(HashTable *ht, co
 add_to_hash:
        idx = ht->nNumUsed++;
        ht->nNumOfElements++;
-       if (ht->nInternalPointer == HT_INVALID_IDX) {
-               ht->nInternalPointer = idx;
-       }
-       zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
        p = ht->arData + idx;
        p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
        p->h = ZSTR_H(key) = h;
@@ -837,10 +863,6 @@ add_to_packed:
                        ht->nNumUsed = h + 1;
                }
                ht->nNumOfElements++;
-               if (ht->nInternalPointer == HT_INVALID_IDX) {
-                       ht->nInternalPointer = h;
-               }
-               zend_hash_iterators_update(ht, HT_INVALID_IDX, h);
                if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
                        ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
                }
@@ -875,10 +897,6 @@ convert_to_hash:
 add_to_hash:
        idx = ht->nNumUsed++;
        ht->nNumOfElements++;
-       if (ht->nInternalPointer == HT_INVALID_IDX) {
-               ht->nInternalPointer = idx;
-       }
-       zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
        if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
                ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
        }
@@ -1055,7 +1073,6 @@ static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx,
                while (1) {
                        new_idx++;
                        if (new_idx >= ht->nNumUsed) {
-                               new_idx = HT_INVALID_IDX;
                                break;
                        } else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
                                break;
@@ -1474,7 +1491,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
        ht->nNextFreeElement = 0;
-       ht->nInternalPointer = HT_INVALID_IDX;
+       ht->nInternalPointer = 0;
 }
 
 ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
@@ -1513,7 +1530,7 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
        ht->nNumUsed = 0;
        ht->nNumOfElements = 0;
        ht->nNextFreeElement = 0;
-       ht->nInternalPointer = HT_INVALID_IDX;
+       ht->nInternalPointer = 0;
 }
 
 ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht)
@@ -1681,20 +1698,15 @@ ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source,
     uint32_t idx;
        Bucket *p;
        zval *new_entry, *data;
-       zend_bool setTargetPointer;
 
        IS_CONSISTENT(source);
        IS_CONSISTENT(target);
        HT_ASSERT_RC1(target);
 
-       setTargetPointer = (target->nInternalPointer == HT_INVALID_IDX);
        for (idx = 0; idx < source->nNumUsed; idx++) {
                p = source->arData + idx;
                if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
 
-               if (setTargetPointer && source->nInternalPointer == idx) {
-                       target->nInternalPointer = HT_INVALID_IDX;
-               }
                /* INDIRECT element may point to UNDEF-ined slots */
                data = &p->val;
                if (Z_TYPE_P(data) == IS_INDIRECT) {
@@ -1712,13 +1724,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source,
                        pCopyConstructor(new_entry);
                }
        }
-       if (target->nInternalPointer == HT_INVALID_IDX && target->nNumOfElements > 0) {
-               idx = 0;
-               while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
-                       idx++;
-               }
-               target->nInternalPointer = idx;
-       }
 }
 
 
@@ -1840,7 +1845,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
                target->nNumUsed = 0;
                target->nNumOfElements = 0;
                target->nNextFreeElement = 0;
-               target->nInternalPointer = HT_INVALID_IDX;
+               target->nInternalPointer = 0;
                HT_SET_DATA_ADDR(target, &uninitialized_bucket);
        } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
                HT_FLAGS(target) = HT_FLAGS(source);
@@ -1851,13 +1856,6 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
                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->nInternalPointer == HT_INVALID_IDX) {
-                       idx = 0;
-                       while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
-                               idx++;
-                       }
-                       target->nInternalPointer = idx;
-               }
        } else if (HT_FLAGS(source) & HASH_FLAG_PACKED) {
                HT_FLAGS(target) = HT_FLAGS(source);
                target->nTableMask = HT_MIN_MASK;
@@ -1865,7 +1863,10 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
                target->nNumOfElements = source->nNumOfElements;
                target->nNextFreeElement = source->nNextFreeElement;
                HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
-               target->nInternalPointer = source->nInternalPointer;
+               target->nInternalPointer =
+                       (source->nInternalPointer < source->nNumUsed) ?
+                               source->nInternalPointer : 0;
+
                HT_HASH_RESET_PACKED(target);
 
                if (HT_IS_WITHOUT_HOLES(target)) {
@@ -1873,18 +1874,13 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
                } else {
                        zend_array_dup_packed_elements(source, target, 1);
                }
-               if (target->nInternalPointer == HT_INVALID_IDX) {
-                       idx = 0;
-                       while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
-                               idx++;
-                       }
-                       target->nInternalPointer = idx;
-               }
        } else {
                HT_FLAGS(target) = HT_FLAGS(source);
                target->nTableMask = source->nTableMask;
                target->nNextFreeElement = source->nNextFreeElement;
-               target->nInternalPointer = source->nInternalPointer;
+               target->nInternalPointer =
+                       (source->nInternalPointer < source->nNumUsed) ?
+                               source->nInternalPointer : 0;
 
                HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
                HT_HASH_RESET(target);
@@ -1904,9 +1900,6 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
                }
                target->nNumUsed = idx;
                target->nNumOfElements = idx;
-               if (target->nInternalPointer == HT_INVALID_IDX) {
-                       target->nInternalPointer = 0;
-               }
        }
        return target;
 }
@@ -1963,13 +1956,6 @@ ZEND_API void ZEND_FASTCALL _zend_hash_merge(HashTable *target, HashTable *sourc
                        }
                }
        }
-       if (target->nNumOfElements > 0) {
-               idx = 0;
-               while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
-                       idx++;
-               }
-               target->nInternalPointer = idx;
-       }
 }
 
 
@@ -2003,13 +1989,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge_ex(HashTable *target, HashTable *sou
                        }
                }
        }
-       if (target->nNumOfElements > 0) {
-               idx = 0;
-               while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
-                       idx++;
-               }
-               target->nInternalPointer = idx;
-       }
 }
 
 
@@ -2120,18 +2099,9 @@ ZEND_API zend_bool ZEND_FASTCALL zend_hash_index_exists(const HashTable *ht, zen
 
 ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
 {
-    uint32_t idx;
-
        IS_CONSISTENT(ht);
        HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
-
-       for (idx = 0; idx < ht->nNumUsed; idx++) {
-               if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
-                       *pos = idx;
-                       return;
-               }
-       }
-       *pos = HT_INVALID_IDX;
+       *pos = _zend_hash_get_first_pos(ht);
 }
 
 
@@ -2153,7 +2123,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, Has
                        return;
                }
        }
-       *pos = HT_INVALID_IDX;
+       *pos = ht->nNumUsed;
 }
 
 
@@ -2164,11 +2134,18 @@ ZEND_API int ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition
        IS_CONSISTENT(ht);
        HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
 
-       if (idx != HT_INVALID_IDX) {
+       if (idx < ht->nNumUsed) {
+               if (idx == 0) {
+                       idx = _zend_hash_get_first_pos(ht);
+                       if (idx >= ht->nNumUsed) {
+                               *pos = idx;
+                               return SUCCESS;
+                       }
+               }
                while (1) {
                        idx++;
                        if (idx >= ht->nNumUsed) {
-                               *pos = HT_INVALID_IDX;
+                               *pos = ht->nNumUsed;
                                return SUCCESS;
                        }
                        if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
@@ -2177,7 +2154,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition
                        }
                }
        } else {
-               return FAILURE;
+               return FAILURE;
        }
 }
 
@@ -2188,7 +2165,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPositi
        IS_CONSISTENT(ht);
        HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
 
-       if (idx != HT_INVALID_IDX) {
+       if (idx < ht->nNumUsed) {
                while (idx > 0) {
                        idx--;
                        if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
@@ -2196,7 +2173,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPositi
                                return SUCCESS;
                        }
                }
-               *pos = HT_INVALID_IDX;
+               *pos = ht->nNumUsed;
                return SUCCESS;
        } else {
                return FAILURE;
@@ -2211,7 +2188,13 @@ ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zen
        Bucket *p;
 
        IS_CONSISTENT(ht);
-       if (idx != HT_INVALID_IDX) {
+       if (idx < ht->nNumUsed) {
+               if (idx == 0) {
+                       idx = _zend_hash_get_first_pos(ht);
+                       if (idx >= ht->nNumUsed) {
+                               return HASH_KEY_NON_EXISTENT;
+                       }
+               }
                p = ht->arData + idx;
                if (p->key) {
                        *str_index = p->key;
@@ -2230,9 +2213,16 @@ ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *h
        Bucket *p;
 
        IS_CONSISTENT(ht);
-       if (idx == HT_INVALID_IDX) {
+       if (idx >= ht->nNumUsed) {
                ZVAL_NULL(key);
        } else {
+               if (idx == 0) {
+                       idx = _zend_hash_get_first_pos(ht);
+                       if (idx >= ht->nNumUsed) {
+                               ZVAL_NULL(key);
+                               return;
+                       }
+               }
                p = ht->arData + idx;
                if (p->key) {
                        ZVAL_STR_COPY(key, p->key);
@@ -2248,7 +2238,13 @@ ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, Hash
        Bucket *p;
 
        IS_CONSISTENT(ht);
-       if (idx != HT_INVALID_IDX) {
+       if (idx < ht->nNumUsed) {
+               if (idx == 0) {
+                       idx = _zend_hash_get_first_pos(ht);
+                       if (idx >= ht->nNumUsed) {
+                               return HASH_KEY_NON_EXISTENT;
+                       }
+               }
                p = ht->arData + idx;
                if (p->key) {
                        return HASH_KEY_IS_STRING;
@@ -2266,7 +2262,13 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPo
        Bucket *p;
 
        IS_CONSISTENT(ht);
-       if (idx != HT_INVALID_IDX) {
+       if (idx < ht->nNumUsed) {
+               if (idx == 0) {
+                       idx = _zend_hash_get_first_pos(ht);
+                       if (idx >= ht->nNumUsed) {
+                               return NULL;
+                       }
+               }
                p = ht->arData + idx;
                return &p->val;
        } else {
index 1cdf6a82d3453edf6e31fcdd04ba6b772d42949c..5b14f51f2d6abac4ad4d1f6b1e58174c3d41384e 100644 (file)
@@ -230,6 +230,8 @@ ZEND_API zend_bool ZEND_FASTCALL zend_hash_str_exists(const HashTable *ht, const
 ZEND_API zend_bool ZEND_FASTCALL zend_hash_index_exists(const HashTable *ht, zend_ulong h);
 
 /* traversing */
+ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht);
+
 #define zend_hash_has_more_elements_ex(ht, pos) \
        (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS)
 ZEND_API int   ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos);
@@ -304,6 +306,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval
 ZEND_API void         ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx);
 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start);
 ZEND_API void         ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to);
+ZEND_API void         ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step);
 
 static zend_always_inline void zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
 {
@@ -1091,7 +1094,7 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
                __fill_ht->nNumUsed = __fill_idx; \
                __fill_ht->nNumOfElements = __fill_idx; \
                __fill_ht->nNextFreeElement = __fill_idx; \
-               __fill_ht->nInternalPointer = __fill_idx ? 0 : HT_INVALID_IDX; \
+               __fill_ht->nInternalPointer = 0; \
        } while (0)
 
 static zend_always_inline zval *_zend_hash_append(HashTable *ht, zend_string *key, zval *zv)
index 09792063267887d0b4a2a37b23ed086f6e7fabe0..93cfc88fbf461eecd42499691f0f5201bd04d06d 100644 (file)
@@ -69,7 +69,6 @@ ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
                zobj->properties = zend_new_array(ce->default_properties_count);
                if (ce->default_properties_count) {
                        zend_hash_real_init(zobj->properties, 0);
-                       zobj->properties->nInternalPointer = 0;
                        ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
                                if (/*prop_info->ce == ce &&*/
                                    (prop_info->flags & ZEND_ACC_STATIC) == 0) {
index f967ba8595a0095eb37e34fd644c744b35461c9c..a411bc42b96e9fde2006a6f608bcb59a935cb7cf 100644 (file)
@@ -5963,10 +5963,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY, JMP_ADDR)
                                        ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
-                       if (++pos >= fe_ht->nNumUsed) {
-                               pos = HT_INVALID_IDX;
-                       }
-                       EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos;
+                       EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos + 1;
                } else {
                        if (EXPECTED(++iter->index > 0)) {
                                /* This could cause an endless loop if index becomes zero again.
@@ -6079,10 +6076,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR)
                                ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
                        }
                }
-               if (++pos >= fe_ht->nNumUsed) {
-                       pos = HT_INVALID_IDX;
-               }
-               EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
+               EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos + 1;
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
                zend_object_iterator *iter;
 
@@ -6128,10 +6122,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR)
                                        ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
-                       if (++pos >= fe_ht->nNumUsed) {
-                               pos = HT_INVALID_IDX;
-                       }
-                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
+                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos + 1;
                } else {
                        if (++iter->index > 0) {
                                /* This could cause an endless loop if index becomes zero again.
index d7c94e514e7701729a0152904bc130f47a8df1d4..34fdcbd6bb428a0ceb9e52d7ebb8c4aae33a3365 100644 (file)
@@ -21657,10 +21657,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZE
                                        ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
-                       if (++pos >= fe_ht->nNumUsed) {
-                               pos = HT_INVALID_IDX;
-                       }
-                       EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos;
+                       EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos + 1;
                } else {
                        if (EXPECTED(++iter->index > 0)) {
                                /* This could cause an endless loop if index becomes zero again.
@@ -21773,10 +21770,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                                ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
                        }
                }
-               if (++pos >= fe_ht->nNumUsed) {
-                       pos = HT_INVALID_IDX;
-               }
-               EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
+               EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos + 1;
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
                zend_object_iterator *iter;
 
@@ -21822,10 +21816,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z
                                        ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
                                }
                        }
-                       if (++pos >= fe_ht->nNumUsed) {
-                               pos = HT_INVALID_IDX;
-                       }
-                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
+                       EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos + 1;
                } else {
                        if (++iter->index > 0) {
                                /* This could cause an endless loop if index becomes zero again.
index f63609417e18325002075c2754da0f306c978299..fe98d77d3b86b0250224b0c7ae397293d6f753dc 100644 (file)
@@ -181,7 +181,7 @@ static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
        ht->nNextFreeElement = source->nNextFreeElement;
        ht->pDestructor = NULL;
        HT_FLAGS(ht) = (HT_FLAGS(source) & (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS));
-       ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
+       ht->nInternalPointer = 0;
 
        if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
                ht->arData = source->arData;
@@ -232,7 +232,7 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class
        ht->nNextFreeElement = source->nNextFreeElement;
        ht->pDestructor = ZEND_FUNCTION_DTOR;
        HT_FLAGS(ht) = (HT_FLAGS(source) & (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS));
-       ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
+       ht->nInternalPointer = 0;
 
        if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
                ht->arData = source->arData;
@@ -290,7 +290,7 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla
        ht->nNextFreeElement = source->nNextFreeElement;
        ht->pDestructor = NULL;
        HT_FLAGS(ht) = (HT_FLAGS(source) & (HASH_FLAG_INITIALIZED | HASH_FLAG_STATIC_KEYS));
-       ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
+       ht->nInternalPointer = 0;
 
        if (!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED)) {
                ht->arData = source->arData;
@@ -492,7 +492,7 @@ static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
                        _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
                }
        }
-       target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
+       target->nInternalPointer = 0;
        return;
 
 failure:
@@ -536,7 +536,7 @@ static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable
                        _zend_hash_append_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
                }
        }
-       target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
+       target->nInternalPointer = 0;
        return;
 
 failure:
@@ -592,7 +592,7 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, uni
                        }
                }
        }
-       target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
+       target->nInternalPointer = 0;
        return;
 }
 
index d0a1f68215f751fafcd345380b1738aa95686334..3135f82f81b9707f8e4029898fc76afacdc6aacf 100644 (file)
@@ -134,7 +134,7 @@ static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht);
 
 static zend_never_inline void spl_array_create_ht_iter(HashTable *ht, spl_array_object* intern) /* {{{ */
 {
-       intern->ht_iter = zend_hash_iterator_add(ht, ht->nInternalPointer);
+       intern->ht_iter = zend_hash_iterator_add(ht, zend_hash_get_current_pos(ht));
        zend_hash_internal_pointer_reset_ex(ht, &EG(ht_iterators)[intern->ht_iter].pos);
        spl_array_skip_protected(intern, ht);
 }
@@ -1419,7 +1419,7 @@ static int spl_array_object_count_elements_helper(spl_array_object *intern, zend
                pos = *pos_ptr;
                *count = 0;
                spl_array_rewind(intern);
-               while (*pos_ptr != HT_INVALID_IDX && spl_array_next(intern) == SUCCESS) {
+               while (*pos_ptr < aht->nNumUsed && spl_array_next(intern) == SUCCESS) {
                        (*count)++;
                }
                *pos_ptr = pos;
index 295f7765d28a3b72f319a19da5128115a25f60ac..1c3911a25e5e0fc64b5481a8f25f814ef13c17bd 100644 (file)
@@ -234,7 +234,7 @@ static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zval
 
        intern = emalloc(sizeof(spl_SplObjectStorage) + zend_object_properties_size(parent));
        memset(intern, 0, sizeof(spl_SplObjectStorage) - sizeof(zval));
-       intern->pos = HT_INVALID_IDX;
+       intern->pos = 0;
 
        zend_object_std_init(&intern->std, class_type);
        object_properties_init(&intern->std, class_type);
index 68061b83ce09fe9b36db329466cc6c122389f321..062070d947597e478d75019492ab2e9345882feb 100644 (file)
@@ -2684,7 +2684,6 @@ PHP_FUNCTION(array_fill)
                        zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
                        Z_ARRVAL_P(return_value)->nNumUsed = (uint32_t)(start_key + num);
                        Z_ARRVAL_P(return_value)->nNumOfElements = (uint32_t)num;
-                       Z_ARRVAL_P(return_value)->nInternalPointer = (uint32_t)start_key;
                        Z_ARRVAL_P(return_value)->nNextFreeElement = (zend_long)(start_key + num);
 
                        if (Z_REFCOUNTED_P(val)) {
@@ -3428,36 +3427,22 @@ PHP_FUNCTION(array_unshift)
                Z_TRY_ADDREF(args[i]);
                zend_hash_next_index_insert_new(&new_hash, &args[i]);
        }
-       if (EXPECTED(!HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
-               ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
-                       if (key) {
-                               zend_hash_add_new(&new_hash, key, value);
-                       } else {
-                               zend_hash_next_index_insert_new(&new_hash, value);
-                       }
-               } ZEND_HASH_FOREACH_END();
-       } else {
-               uint32_t old_idx;
-               uint32_t new_idx = i;
-               uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
 
-               ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
-                       if (key) {
-                               zend_hash_add_new(&new_hash, key, value);
-                       } else {
-                               zend_hash_next_index_insert_new(&new_hash, value);
-                       }
-                       old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
-                       if (old_idx == iter_pos) {
-                               zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
-                               iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
-                       }
-                       new_idx++;
-               } ZEND_HASH_FOREACH_END();
+       ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
+               if (key) {
+                       zend_hash_add_new(&new_hash, key, value);
+               } else {
+                       zend_hash_next_index_insert_new(&new_hash, value);
+               }
+       } ZEND_HASH_FOREACH_END();
+
+       if (EXPECTED(HT_HAS_ITERATORS(Z_ARRVAL_P(stack)))) {
+               zend_hash_iterators_advance(Z_ARRVAL_P(stack), argc);
+               HT_SET_ITERATORS_COUNT(&new_hash, HT_ITERATORS_COUNT(Z_ARRVAL_P(stack)));
+               HT_SET_ITERATORS_COUNT(Z_ARRVAL_P(stack), 0);
        }
 
        /* replace HashTable data */
-       HT_SET_ITERATORS_COUNT(Z_ARRVAL_P(stack), 0);
        Z_ARRVAL_P(stack)->pDestructor = NULL;
        zend_hash_destroy(Z_ARRVAL_P(stack));
 
index ba1bc89628da6204f766a5d4815ebe91d9e0b57d..cd1e0af96e95f93de1ca954483d9d7c6e8b7dd48 100644 (file)
@@ -488,18 +488,21 @@ array(3) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=3; $v=v.2
+     iteration 1:  $k=2; $v=v.1
+     iteration 2:  $k=4; $v=v.2
 --> State of array after loop:
-array(5) {
+array(6) {
   [0]=>
-  string(5) "new.1"
+  string(5) "new.2"
   [1]=>
-  string(5) "new.0"
+  string(5) "new.1"
   [2]=>
-  string(3) "v.0"
+  string(5) "new.0"
   [3]=>
-  string(3) "v.1"
+  string(3) "v.0"
   [4]=>
+  string(3) "v.1"
+  [5]=>
   &string(3) "v.2"
 }
 
@@ -517,19 +520,25 @@ array(4) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=4; $v=v.3
+     iteration 1:  $k=2; $v=v.1
+     iteration 2:  $k=4; $v=v.2
+     iteration 3:  $k=6; $v=v.3
 --> State of array after loop:
-array(6) {
+array(8) {
   [0]=>
-  string(5) "new.1"
+  string(5) "new.3"
   [1]=>
-  string(5) "new.0"
+  string(5) "new.2"
   [2]=>
-  string(3) "v.0"
+  string(5) "new.1"
   [3]=>
-  string(3) "v.1"
+  string(5) "new.0"
   [4]=>
-  string(3) "v.2"
+  string(3) "v.0"
   [5]=>
+  string(3) "v.1"
+  [6]=>
+  string(3) "v.2"
+  [7]=>
   &string(3) "v.3"
 }
index f7f5389395725a0b705697d90cc4765ae7e1a8ec..13333ccf4df46227dff9aacc5adb40898db8d8e6 100644 (file)
@@ -490,18 +490,21 @@ array(3) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=3; $v=v.2
+     iteration 1:  $k=2; $v=v.1
+     iteration 2:  $k=4; $v=v.2
 --> State of array after loop:
-array(5) {
+array(6) {
   [0]=>
-  string(5) "new.1"
+  string(5) "new.2"
   [1]=>
-  string(5) "new.0"
+  string(5) "new.1"
   [2]=>
-  string(3) "v.0"
+  string(5) "new.0"
   [3]=>
-  string(3) "v.1"
+  string(3) "v.0"
   [4]=>
+  string(3) "v.1"
+  [5]=>
   &string(3) "v.2"
 }
 
@@ -519,19 +522,25 @@ array(4) {
 }
 --> Do loop:
      iteration 0:  $k=0; $v=v.0
-     iteration 1:  $k=4; $v=v.3
+     iteration 1:  $k=2; $v=v.1
+     iteration 2:  $k=4; $v=v.2
+     iteration 3:  $k=6; $v=v.3
 --> State of array after loop:
-array(6) {
+array(8) {
   [0]=>
-  string(5) "new.1"
+  string(5) "new.3"
   [1]=>
-  string(5) "new.0"
+  string(5) "new.2"
   [2]=>
-  string(3) "v.0"
+  string(5) "new.1"
   [3]=>
-  string(3) "v.1"
+  string(5) "new.0"
   [4]=>
-  string(3) "v.2"
+  string(3) "v.0"
   [5]=>
+  string(3) "v.1"
+  [6]=>
+  string(3) "v.2"
+  [7]=>
   &string(3) "v.3"
 }