PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_hash.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 956 1069 89.4 %
Date: 2015-04-14 Functions: 67 75 89.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #include "zend.h"
      23             : #include "zend_globals.h"
      24             : #include "zend_variables.h"
      25             : 
      26             : #define HT_DEBUG 0
      27             : #if HT_DEBUG
      28             : # define HT_ASSERT(c) ZEND_ASSERT(c)
      29             : #else
      30             : # define HT_ASSERT(c)
      31             : #endif 
      32             : 
      33             : #if ZEND_DEBUG
      34             : /*
      35             : #define HASH_MASK_CONSISTENCY   0x60
      36             : */
      37             : #define HT_OK                                   0x00
      38             : #define HT_IS_DESTROYING                0x20
      39             : #define HT_DESTROYED                    0x40
      40             : #define HT_CLEANING                             0x60
      41             : 
      42             : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
      43             : {
      44             :         if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) {
      45             :                 return;
      46             :         }
      47             :         switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) {
      48             :                 case HT_IS_DESTROYING:
      49             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
      50             :                         break;
      51             :                 case HT_DESTROYED:
      52             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
      53             :                         break;
      54             :                 case HT_CLEANING:
      55             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
      56             :                         break;
      57             :                 default:
      58             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
      59             :                         break;
      60             :         }
      61             :         zend_bailout();
      62             : }
      63             : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
      64             : #define SET_INCONSISTENT(n) do { \
      65             :                 (ht)->u.flags |= n; \
      66             :         } while (0)
      67             : #else
      68             : #define IS_CONSISTENT(a)
      69             : #define SET_INCONSISTENT(n)
      70             : #endif
      71             : 
      72             : #define HASH_PROTECT_RECURSION(ht)                                                                                                              \
      73             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      74             :                 if ((ht)->u.flags >= (3 << 8)) {                                                                                            \
      75             :                         zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");\
      76             :                 }                                                                                                                                                               \
      77             :                 ZEND_HASH_INC_APPLY_COUNT(ht);                                                                                                  \
      78             :         }
      79             : 
      80             : #define HASH_UNPROTECT_RECURSION(ht)                                                                                                    \
      81             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      82             :                 ZEND_HASH_DEC_APPLY_COUNT(ht);                                                                                                  \
      83             :         }
      84             : 
      85             : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht)                         \
      86             :         if ((ht)->nNumUsed >= (ht)->nTableSize) {              \
      87             :                 zend_hash_do_resize(ht);                                        \
      88             :         }
      89             : 
      90             : static void zend_hash_do_resize(HashTable *ht);
      91             : 
      92             : static uint32_t zend_always_inline zend_hash_check_size(uint32_t nSize)
      93             : {
      94             : #if defined(ZEND_WIN32)
      95             :         unsigned long index;
      96             : #endif
      97             : 
      98             :         /* Use big enough power of 2 */
      99             :         /* size should be between HT_MIN_SIZE and HT_MAX_SIZE */
     100    17118258 :         nSize = (nSize <= HT_MIN_SIZE ? HT_MIN_SIZE : (nSize >= HT_MAX_SIZE ? HT_MAX_SIZE : nSize));
     101             : 
     102             : #if defined(ZEND_WIN32)
     103             :         if (BitScanReverse(&index, nSize - 1)) {
     104             :                 return 0x2 << ((31 - index) ^ 0x1f);
     105             :         } else {
     106             :                 /* nSize is ensured to be in the valid range, fall back to it
     107             :                    rather than using an undefined bis scan result. */
     108             :                 return nSize;
     109             :         }
     110             : #elif defined(__GNUC__)
     111    17118258 :         return 0x2 << (__builtin_clz(nSize - 1) ^ 0x1f);
     112             : #else
     113             :         nSize -= 1;
     114             :         nSize |= (nSize >> 1);
     115             :         nSize |= (nSize >> 2);
     116             :         nSize |= (nSize >> 4);
     117             :         nSize |= (nSize >> 8);
     118             :         nSize |= (nSize >> 16);
     119             :         return nSize + 1;
     120             : #endif
     121             : }
     122             : 
     123             : static void zend_always_inline zend_hash_check_init(HashTable *ht, int packed)
     124             : {
     125             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     126     8985566 :         if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
     127     8985566 :                 if (packed) {
     128     1935992 :                         (ht)->u.flags |= HASH_FLAG_INITIALIZED | HASH_FLAG_PACKED;
     129     3871984 :                         (ht)->arData = (Bucket *) pemalloc((ht)->nTableSize * sizeof(Bucket), (ht)->u.flags & HASH_FLAG_PERSISTENT);
     130             :                 } else {
     131     7049574 :                         (ht)->u.flags |= HASH_FLAG_INITIALIZED;
     132     7049574 :                         (ht)->nTableMask = (ht)->nTableSize - 1;
     133    14099148 :                         (ht)->arData = (Bucket *) pemalloc((ht)->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)), (ht)->u.flags & HASH_FLAG_PERSISTENT);
     134     7049574 :                         (ht)->arHash = (uint32_t*)((ht)->arData + (ht)->nTableSize);
     135     7049574 :                         memset((ht)->arHash, INVALID_IDX, (ht)->nTableSize * sizeof(uint32_t));
     136             :                 }
     137             :         }
     138             : }
     139             : 
     140             : #define CHECK_INIT(ht, packed) \
     141             :         zend_hash_check_init(ht, packed)
     142             : 
     143             : static const uint32_t uninitialized_bucket = {INVALID_IDX};
     144             : 
     145    17118258 : ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     146             : {
     147    17118258 :         GC_REFCOUNT(ht) = 1;
     148    17118258 :         GC_TYPE_INFO(ht) = IS_ARRAY;
     149    17118258 :         ht->nTableSize = zend_hash_check_size(nSize);
     150    17118258 :         ht->nTableMask = 0;
     151    17118258 :         ht->nNumUsed = 0;
     152    17118258 :         ht->nNumOfElements = 0;
     153    17118258 :         ht->nNextFreeElement = 0;
     154    17118258 :         ht->arData = NULL;
     155    17118258 :         ht->arHash = (uint32_t*)&uninitialized_bucket;
     156    17118258 :         ht->pDestructor = pDestructor;
     157    17118258 :         ht->nInternalPointer = INVALID_IDX;
     158    17118258 :         ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION;
     159    17118258 : }
     160             : 
     161       16263 : static void zend_hash_packed_grow(HashTable *ht)
     162             : {
     163             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     164       16263 :         if (ht->nTableSize >= HT_MAX_SIZE) {
     165           0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
     166             :         }
     167       16263 :         HANDLE_BLOCK_INTERRUPTIONS();
     168       16263 :         ht->nTableSize += ht->nTableSize;
     169       32526 :         ht->arData = (Bucket *) perealloc(ht->arData, ht->nTableSize * sizeof(Bucket), ht->u.flags & HASH_FLAG_PERSISTENT);
     170       16263 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     171       16263 : }
     172             : 
     173      172994 : ZEND_API void zend_hash_real_init(HashTable *ht, zend_bool packed)
     174             : {
     175             :         IS_CONSISTENT(ht);
     176             : 
     177             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     178      172994 :         CHECK_INIT(ht, packed);
     179      172994 : }
     180             : 
     181       28832 : ZEND_API void zend_hash_packed_to_hash(HashTable *ht)
     182             : {
     183             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     184       28832 :         HANDLE_BLOCK_INTERRUPTIONS();
     185       28832 :         ht->u.flags &= ~HASH_FLAG_PACKED;
     186       28832 :         ht->nTableMask = ht->nTableSize - 1;
     187       57664 :         ht->arData = (Bucket *) perealloc(ht->arData, ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)), ht->u.flags & HASH_FLAG_PERSISTENT);
     188       28832 :         ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize);
     189       28832 :         zend_hash_rehash(ht);
     190       28832 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     191       28832 : }
     192             : 
     193          15 : ZEND_API void zend_hash_to_packed(HashTable *ht)
     194             : {
     195             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     196          15 :         HANDLE_BLOCK_INTERRUPTIONS();
     197          15 :         ht->u.flags |= HASH_FLAG_PACKED;
     198          15 :         ht->nTableMask = 0;
     199          30 :         ht->arData = (Bucket *) perealloc(ht->arData, ht->nTableSize * sizeof(Bucket), ht->u.flags & HASH_FLAG_PERSISTENT);
     200          15 :         ht->arHash = (uint32_t*)&uninitialized_bucket;
     201          15 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     202          15 : }
     203             : 
     204    11480242 : ZEND_API void _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC)
     205             : {
     206    11480242 :         _zend_hash_init(ht, nSize, pDestructor, persistent ZEND_FILE_LINE_CC);
     207    11480242 :         if (!bApplyProtection) {
     208    11480242 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     209             :         }
     210    11480242 : }
     211             : 
     212             : 
     213           0 : ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
     214             : {
     215           0 :         if (bApplyProtection) {
     216           0 :                 ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
     217             :         } else {
     218           0 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     219             :         }
     220           0 : }
     221             : 
     222         187 : ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht, HashPosition pos)
     223             : {
     224         187 :         HashTableIterator *iter = EG(ht_iterators);
     225         187 :         HashTableIterator *end  = iter + EG(ht_iterators_count);
     226             :         uint32_t idx;
     227             : 
     228         187 :         if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     229         187 :                 ht->u.v.nIteratorsCount++;
     230             :         }
     231         389 :         while (iter != end) {
     232         202 :                 if (iter->ht == NULL) {
     233         187 :                         iter->ht = ht;
     234         187 :                         iter->pos = pos;
     235         187 :                         idx = iter - EG(ht_iterators);
     236         187 :                         if (idx + 1 > EG(ht_iterators_used)) {
     237         187 :                                 EG(ht_iterators_used) = idx + 1;
     238             :                         }
     239         187 :                         return idx;
     240             :                 }
     241          15 :                 iter++;
     242             :         }
     243           0 :         if (EG(ht_iterators) == EG(ht_iterators_slots)) {
     244           0 :                 EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
     245           0 :                 memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
     246             :         } else {
     247           0 :                 EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
     248             :         }
     249           0 :         iter = EG(ht_iterators) + EG(ht_iterators_count);
     250           0 :         EG(ht_iterators_count) += 8;
     251           0 :         iter->ht = ht;
     252           0 :         iter->pos = pos;
     253           0 :         memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
     254           0 :         idx = iter - EG(ht_iterators);
     255           0 :         EG(ht_iterators_used) = idx + 1;
     256           0 :         return idx;
     257             : }
     258             : 
     259        1380 : ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
     260             : {
     261        1380 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     262             : 
     263             :         ZEND_ASSERT(idx != (uint32_t)-1);
     264        1380 :         if (iter->pos == INVALID_IDX) {
     265         173 :                 return INVALID_IDX;
     266        1207 :         } else if (UNEXPECTED(iter->ht != ht)) {
     267           0 :                 if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     268           0 :                         iter->ht->u.v.nIteratorsCount--;
     269             :                 }
     270           0 :                 if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     271           0 :                         ht->u.v.nIteratorsCount++;
     272             :                 }
     273           0 :                 iter->ht = ht;
     274           0 :                 iter->pos = ht->nInternalPointer;
     275             :         }
     276        1207 :         return iter->pos;
     277             : }
     278             : 
     279         183 : ZEND_API void zend_hash_iterator_del(uint32_t idx)
     280             : {
     281         183 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     282             : 
     283             :         ZEND_ASSERT(idx != (uint32_t)-1);
     284             : 
     285         183 :         if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     286         183 :                 iter->ht->u.v.nIteratorsCount--;
     287             :         }
     288         183 :         iter->ht = NULL;
     289             : 
     290         183 :         if (idx == EG(ht_iterators_used) - 1) {
     291         366 :                 while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
     292           0 :                         idx--;
     293             :                 }
     294         183 :                 EG(ht_iterators_used) = idx;
     295             :         }
     296         183 : }
     297             : 
     298          18 : static zend_never_inline void _zend_hash_iterators_remove(HashTable *ht)
     299             : {
     300          18 :         HashTableIterator *iter = EG(ht_iterators);
     301          18 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     302             :         uint32_t idx;
     303             : 
     304          40 :         while (iter != end) {
     305           4 :                 if (iter->ht == ht) {
     306           4 :                         iter->ht = NULL;
     307             :                 }
     308           4 :                 iter++;
     309             :         }
     310             : 
     311          18 :         idx = EG(ht_iterators_used);
     312          40 :         while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
     313           4 :                 idx--;
     314             :         }
     315          18 :         EG(ht_iterators_used) = idx;
     316          18 : }
     317             : 
     318             : static zend_always_inline void zend_hash_iterators_remove(HashTable *ht)
     319             : {
     320     9979850 :         if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
     321          18 :                 _zend_hash_iterators_remove(ht);
     322             :         }
     323             : }
     324             : 
     325         202 : ZEND_API HashPosition zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start)
     326             : {
     327         202 :         HashTableIterator *iter = EG(ht_iterators);
     328         202 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     329         202 :         HashPosition res = INVALID_IDX;
     330             : 
     331         496 :         while (iter != end) {
     332          92 :                 if (iter->ht == ht) {
     333          92 :                         if (iter->pos >= start && iter->pos < res) {
     334          51 :                                 res = iter->pos;
     335             :                         }
     336             :                 }
     337          92 :                 iter++;
     338             :         }
     339         202 :         return res;
     340             : }
     341             : 
     342         204 : ZEND_API void _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
     343             : {
     344         204 :         HashTableIterator *iter = EG(ht_iterators);
     345         204 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     346             : 
     347         620 :         while (iter != end) {
     348         212 :                 if (iter->ht == ht && iter->pos == from) {
     349          57 :                         iter->pos = to;
     350             :                 }
     351         212 :                 iter++;
     352             :         }
     353         204 : }
     354             : 
     355             : static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
     356             : {
     357             :         zend_ulong h;
     358             :         uint32_t nIndex;
     359             :         uint32_t idx;
     360             :         Bucket *p;
     361             : 
     362   278077998 :         h = zend_string_hash_val(key);
     363   278077998 :         nIndex = h & ht->nTableMask;
     364   278077998 :         idx = ht->arHash[nIndex];
     365   432966890 :         while (idx != INVALID_IDX) {
     366   168811633 :                 p = ht->arData + idx;
     367   344353383 :                 if ((p->key == key) || /* check for the the same interned string */
     368   160050488 :                         (p->h == h &&
     369     5163754 :                          p->key &&
     370     5163754 :                          p->key->len == key->len &&
     371     5163754 :                          memcmp(p->key->val, key->val, key->len) == 0)) {
     372    13922741 :                         return p;
     373             :                 }
     374   154888892 :                 idx = Z_NEXT(p->val);
     375             :         }
     376   264155257 :         return NULL;
     377             : }
     378             : 
     379             : static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
     380             : {
     381             :         uint32_t nIndex;
     382             :         uint32_t idx;
     383             :         Bucket *p;
     384             : 
     385     3494770 :         nIndex = h & ht->nTableMask;
     386     3494770 :         idx = ht->arHash[nIndex];
     387     4337849 :         while (idx != INVALID_IDX) {
     388             :                 ZEND_ASSERT(idx < ht->nTableSize);
     389     3434705 :                 p = ht->arData + idx;
     390    11209634 :                 if ((p->h == h)
     391             :                          && p->key
     392     5183286 :                          && (p->key->len == len)
     393     2591643 :                          && !memcmp(p->key->val, str, len)) {
     394     2591626 :                         return p;
     395             :                 }
     396      843079 :                 idx = Z_NEXT(p->val);
     397             :         }
     398      903144 :         return NULL;
     399             : }
     400             : 
     401             : static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
     402             : {
     403             :         uint32_t nIndex;
     404             :         uint32_t idx;
     405             :         Bucket *p;
     406             : 
     407     4002460 :         nIndex = h & ht->nTableMask;
     408     4002460 :         idx = ht->arHash[nIndex];
     409     5352036 :         while (idx != INVALID_IDX) {
     410             :                 ZEND_ASSERT(idx < ht->nTableSize);
     411     2358200 :                 p = ht->arData + idx;
     412     2358200 :                 if (p->h == h && !p->key) {
     413     1008624 :                         return p;
     414             :                 }
     415     1349576 :                 idx = Z_NEXT(p->val);
     416             :         }
     417     2993836 :         return NULL;
     418             : }
     419             : 
     420             : static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     421             : {
     422             :         zend_ulong h;
     423             :         uint32_t nIndex;
     424             :         uint32_t idx;
     425             :         Bucket *p;
     426             : 
     427             :         IS_CONSISTENT(ht);
     428             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     429             : 
     430   261790666 :         if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
     431             :                 CHECK_INIT(ht, 0);
     432             :                 goto add_to_hash;
     433   254912759 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     434       27804 :                 zend_hash_packed_to_hash(ht);
     435   254884955 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     436   226107377 :                 p = zend_hash_find_bucket(ht, key);
     437             : 
     438   226107377 :                 if (p) {
     439             :                         zval *data;
     440             : 
     441     1045115 :                         if (flag & HASH_ADD) {
     442      262444 :                                 return NULL;
     443             :                         }
     444             :                         ZEND_ASSERT(&p->val != pData);
     445      782671 :                         data = &p->val;
     446      838024 :                         if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
     447         258 :                                 data = Z_INDIRECT_P(data);
     448             :                         }
     449      782671 :                         HANDLE_BLOCK_INTERRUPTIONS();
     450      782671 :                         if (ht->pDestructor) {
     451      740557 :                                 ht->pDestructor(data);
     452             :                         }
     453      782671 :                         ZVAL_COPY_VALUE(data, pData);
     454      782671 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     455      782671 :                         return data;
     456             :                 }
     457             :         }
     458             : 
     459   253867644 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     460             : 
     461             : add_to_hash:
     462   260745551 :         HANDLE_BLOCK_INTERRUPTIONS();
     463   260745551 :         idx = ht->nNumUsed++;
     464   260745551 :         ht->nNumOfElements++;
     465   260745551 :         if (ht->nInternalPointer == INVALID_IDX) {
     466     7014312 :                 ht->nInternalPointer = idx;
     467             :         }
     468             :         zend_hash_iterators_update(ht, INVALID_IDX, idx);
     469   260745551 :         p = ht->arData + idx;
     470   260745551 :         p->h = h = zend_string_hash_val(key);
     471   260745551 :         p->key = key;
     472             :         zend_string_addref(key);
     473   260745551 :         ZVAL_COPY_VALUE(&p->val, pData);
     474   260745551 :         nIndex = h & ht->nTableMask;
     475   260745551 :         Z_NEXT(p->val) = ht->arHash[nIndex];
     476   260745551 :         ht->arHash[nIndex] = idx;
     477   260745551 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     478             : 
     479   260745551 :         return &p->val;
     480             : }
     481             : 
     482     3048661 : ZEND_API zval *_zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     483             : {
     484     3048661 :         return _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_RELAY_CC);
     485             : }
     486             : 
     487   139085200 : ZEND_API zval *_zend_hash_add(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     488             : {
     489   139085200 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     490             : }
     491             : 
     492    51980567 : ZEND_API zval *_zend_hash_update(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     493             : {
     494    51980567 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     495             : }
     496             : 
     497        1106 : ZEND_API zval *_zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     498             : {
     499        1106 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC);
     500             : }
     501             : 
     502    29874913 : ZEND_API zval *_zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     503             : {
     504    29874913 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     505             : }
     506             : 
     507           0 : ZEND_API zval *_zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     508             : {
     509           0 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     510           0 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_CC);
     511             :         zend_string_release(key);
     512           0 :         return ret;
     513             : }
     514             : 
     515    23645397 : ZEND_API zval *_zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     516             : {
     517    47290794 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     518    23645397 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_CC);
     519             :         zend_string_release(key);
     520    23645397 :         return ret;
     521             : }
     522             : 
     523     1296808 : ZEND_API zval *_zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     524             : {
     525     2593616 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     526     1296808 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_CC);
     527             :         zend_string_release(key);
     528     1296808 :         return ret;
     529             : }
     530             : 
     531    12855144 : ZEND_API zval *_zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     532             : {
     533    25710288 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     534    12855144 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_CC);
     535             :         zend_string_release(key);
     536    12855144 :         return ret;
     537             : }
     538             : 
     539        2870 : ZEND_API zval *_zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     540             : {
     541        5740 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     542        2870 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_CC);
     543             :         zend_string_release(key);
     544        2870 :         return ret;
     545             : }
     546             : 
     547           0 : ZEND_API zval *zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
     548             : {
     549             : 
     550             :         zval dummy;
     551             : 
     552           0 :         ZVAL_NULL(&dummy);
     553           0 :         return zend_hash_index_add(ht, h, &dummy);
     554             : }
     555             : 
     556         226 : ZEND_API zval *zend_hash_add_empty_element(HashTable *ht, zend_string *key)
     557             : {
     558             : 
     559             :         zval dummy;
     560             : 
     561         226 :         ZVAL_NULL(&dummy);
     562         226 :         return zend_hash_add(ht, key, &dummy);
     563             : }
     564             : 
     565      522828 : ZEND_API zval *zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
     566             : {
     567             : 
     568             :         zval dummy;
     569             : 
     570      522828 :         ZVAL_NULL(&dummy);
     571      522828 :         return zend_hash_str_add(ht, str, len, &dummy);
     572             : }
     573             : 
     574             : static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     575             : {
     576             :         uint32_t nIndex;
     577             :         uint32_t idx;
     578             :         Bucket *p;
     579             : 
     580             :         IS_CONSISTENT(ht);
     581             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     582             : 
     583     7091272 :         if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
     584     1934665 :                 CHECK_INIT(ht, h < ht->nTableSize);
     585     1934665 :                 if (h < ht->nTableSize) {
     586     1832714 :                         p = ht->arData + h;
     587             :                         goto add_to_packed;
     588             :                 }
     589             :                 goto add_to_hash;
     590     5156607 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     591     3236268 :                 if (h < ht->nNumUsed) {
     592        3800 :                         p = ht->arData + h;
     593        7600 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     594        3644 :                                 if (flag & HASH_ADD) {
     595          24 :                                         return NULL;
     596             :                                 }
     597        3620 :                                 if (ht->pDestructor) {
     598        3620 :                                         ht->pDestructor(&p->val);
     599             :                                 }
     600        3620 :                                 ZVAL_COPY_VALUE(&p->val, pData);
     601        3620 :                                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     602           0 :                                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     603             :                                 }
     604        3620 :                                 return &p->val;
     605             :                         } else { /* we have to keep the order :( */
     606             :                                 goto convert_to_hash;
     607             :                         }
     608     3232468 :                 } else if (EXPECTED(h < ht->nTableSize)) {
     609     3215594 :                         p = ht->arData + h;
     610       33670 :                 } else if ((h >> 1) < ht->nTableSize &&
     611       16796 :                            (ht->nTableSize >> 1) < ht->nNumOfElements) {
     612       16263 :                         zend_hash_packed_grow(ht);
     613       16263 :                         p = ht->arData + h;
     614             :                 } else {
     615             :                         goto convert_to_hash;
     616             :                 }
     617             : 
     618             : add_to_packed:
     619     5064571 :                 HANDLE_BLOCK_INTERRUPTIONS();
     620             :                 /* incremental initialization of empty Buckets */
     621     5064571 :                 if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) == (HASH_ADD_NEW|HASH_ADD_NEXT)) {
     622       34849 :                         ht->nNumUsed = h + 1;
     623     5029722 :                 } else if (h >= ht->nNumUsed) {
     624     5029722 :                         if (h > ht->nNumUsed) {
     625      896856 :                                 Bucket *q = ht->arData + ht->nNumUsed;
     626     1798511 :                                 while (q != p) {
     627      901655 :                                         ZVAL_UNDEF(&q->val);
     628      901655 :                                         q++;
     629             :                                 }
     630             :                         }
     631     5029722 :                         ht->nNumUsed = h + 1;
     632             :                 }
     633     5064571 :                 ht->nNumOfElements++;
     634     5064571 :                 if (ht->nInternalPointer == INVALID_IDX) {
     635     1832754 :                         ht->nInternalPointer = h;
     636             :                 }
     637     5064571 :                 zend_hash_iterators_update(ht, INVALID_IDX, h);
     638     5064571 :                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     639     5064559 :                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     640             :                 }
     641     5064571 :                 p->h = h;
     642     5064571 :                 p->key = NULL;
     643     5064571 :                 ZVAL_COPY_VALUE(&p->val, pData);
     644             : 
     645     5064571 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     646             : 
     647     5064571 :                 return &p->val;
     648             : 
     649             : convert_to_hash:
     650         767 :                 zend_hash_packed_to_hash(ht);
     651     1920339 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     652     1303841 :                 p = zend_hash_index_find_bucket(ht, h);
     653     1303841 :                 if (p) {
     654       10253 :                         if (flag & HASH_ADD) {
     655           6 :                                 return NULL;
     656             :                         }
     657             :                         ZEND_ASSERT(&p->val != pData);
     658       10247 :                         HANDLE_BLOCK_INTERRUPTIONS();
     659       10247 :                         if (ht->pDestructor) {
     660       10202 :                                 ht->pDestructor(&p->val);
     661             :                         }
     662       10247 :                         ZVAL_COPY_VALUE(&p->val, pData);
     663       10247 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     664       10247 :                         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     665           1 :                                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     666             :                         }
     667       10247 :                         return &p->val;
     668             :                 }
     669             :         }
     670             : 
     671     1910853 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     672             : 
     673             : add_to_hash:
     674     2012804 :         HANDLE_BLOCK_INTERRUPTIONS();
     675     2012804 :         idx = ht->nNumUsed++;
     676     2012804 :         ht->nNumOfElements++;
     677     2012804 :         if (ht->nInternalPointer == INVALID_IDX) {
     678      170453 :                 ht->nInternalPointer = idx;
     679             :         }
     680             :         zend_hash_iterators_update(ht, INVALID_IDX, idx);
     681     2012804 :         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     682      628990 :                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     683             :         }
     684     2012804 :         p = ht->arData + idx;
     685     2012804 :         p->h = h;
     686     2012804 :         p->key = NULL;
     687     2012804 :         nIndex = h & ht->nTableMask;
     688     2012804 :         ZVAL_COPY_VALUE(&p->val, pData);
     689     2012804 :         Z_NEXT(p->val) = ht->arHash[nIndex];
     690     2012804 :         ht->arHash[nIndex] = idx;
     691     2012804 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     692             : 
     693     2012804 :         return &p->val;
     694             : }
     695             : 
     696           0 : ZEND_API zval *_zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     697             : {
     698           0 :         return _zend_hash_index_add_or_update_i(ht, h, pData, flag ZEND_FILE_LINE_RELAY_CC);
     699             : }
     700             : 
     701          94 : ZEND_API zval *_zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     702             : {
     703          94 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     704             : }
     705             : 
     706     1053673 : ZEND_API zval *_zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     707             : {
     708     1053673 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     709             : }
     710             : 
     711     2314362 : ZEND_API zval *_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     712             : {
     713     2314362 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     714             : }
     715             : 
     716     3687765 : ZEND_API zval *_zend_hash_next_index_insert(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     717             : {
     718     7375530 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     719             : }
     720             : 
     721       35378 : ZEND_API zval *_zend_hash_next_index_insert_new(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     722             : {
     723       70756 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     724             : }
     725             : 
     726     6605078 : static void zend_hash_do_resize(HashTable *ht)
     727             : {
     728             : 
     729             :         IS_CONSISTENT(ht);
     730             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     731             : 
     732     6605078 :         if (ht->nNumUsed > ht->nNumOfElements) {
     733       23759 :                 HANDLE_BLOCK_INTERRUPTIONS();
     734       23759 :                 zend_hash_rehash(ht);
     735       23759 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     736     6581319 :         } else if (ht->nTableSize < HT_MAX_SIZE) {        /* Let's double the table size */
     737     6581319 :                 HANDLE_BLOCK_INTERRUPTIONS();
     738     6581319 :                 ht->nTableSize += ht->nTableSize;
     739    13162638 :                 ht->arData = (Bucket *) perealloc(ht->arData, ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)), ht->u.flags & HASH_FLAG_PERSISTENT);
     740     6581319 :                 ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize);
     741     6581319 :                 ht->nTableMask = ht->nTableSize - 1;
     742     6581319 :                 zend_hash_rehash(ht);
     743     6581319 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     744             :         } else {
     745           0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket));
     746             :         }
     747     6605078 : }
     748             : 
     749     6718289 : ZEND_API int zend_hash_rehash(HashTable *ht)
     750             : {
     751             :         Bucket *p;
     752             :         uint32_t nIndex, i, j;
     753             : 
     754             :         IS_CONSISTENT(ht);
     755             : 
     756     6718289 :         if (UNEXPECTED(ht->nNumOfElements == 0)) {
     757           3 :                 if (ht->u.flags & HASH_FLAG_INITIALIZED) {
     758           0 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
     759             :                 }
     760           3 :                 return SUCCESS;
     761             :         }
     762             : 
     763     6718286 :         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
     764     6718286 :         if (EXPECTED(ht->u.v.nIteratorsCount == 0)) {
     765   427775710 :                 for (i = 0, j = 0; i < ht->nNumUsed; i++) {
     766   421057430 :                         p = ht->arData + i;
     767   842114860 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
     768   420993294 :                         if (i != j) {
     769      165225 :                                 ht->arData[j] = ht->arData[i];
     770      165225 :                                 if (ht->nInternalPointer == i) {
     771        1075 :                                         ht->nInternalPointer = j;
     772             :                                 }
     773             :                         }
     774   420993294 :                         nIndex = ht->arData[j].h & ht->nTableMask;
     775   420993294 :                         Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
     776   420993294 :                         ht->arHash[nIndex] = j;
     777   420993294 :                         j++;
     778             :                 }
     779             :         } else {
     780           6 :                 uint32_t iter_pos = zend_hash_iterators_lower_pos(ht, 0);
     781             : 
     782          70 :                 for (i = 0, j = 0; i < ht->nNumUsed; i++) {
     783          64 :                         p = ht->arData + i;
     784         128 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
     785          56 :                         if (i != j) {
     786           8 :                                 ht->arData[j] = ht->arData[i];
     787           8 :                                 if (ht->nInternalPointer == i) {
     788           2 :                                         ht->nInternalPointer = j;
     789             :                                 }
     790           8 :                                 if (i == iter_pos) {
     791             :                                         zend_hash_iterators_update(ht, i, j);
     792           4 :                                         iter_pos = zend_hash_iterators_lower_pos(ht, iter_pos + 1);
     793             :                                 }
     794             :                         }
     795          56 :                         nIndex = ht->arData[j].h & ht->nTableMask;
     796          56 :                         Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
     797          56 :                         ht->arHash[nIndex] = j;
     798          56 :                         j++;
     799             :                 }
     800             :         }
     801     6718286 :         ht->nNumUsed = j;
     802     6718286 :         return SUCCESS;
     803             : }
     804             : 
     805             : static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
     806             : {
     807    52194542 :         HANDLE_BLOCK_INTERRUPTIONS();
     808    52194542 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     809    52088235 :                 if (prev) {
     810     2928510 :                         Z_NEXT(prev->val) = Z_NEXT(p->val);
     811             :                 } else {
     812    49159725 :                         ht->arHash[p->h & ht->nTableMask] = Z_NEXT(p->val);
     813             :                 }
     814             :         }
     815    52194542 :         if (ht->nNumUsed - 1 == idx) {
     816             :                 do {
     817     3723064 :                         ht->nNumUsed--;
     818     7273266 :                 } while (ht->nNumUsed > 0 && (Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF));
     819             :         }
     820    52194542 :         ht->nNumOfElements--;
     821    52194542 :         if (ht->nInternalPointer == idx || UNEXPECTED(ht->u.v.nIteratorsCount)) {
     822     3237870 :                 uint32_t new_idx = idx;
     823             : 
     824             :                 while (1) {
     825    46357777 :                         new_idx++;
     826    46357777 :                         if (new_idx >= ht->nNumUsed) {
     827      172883 :                                 new_idx = INVALID_IDX;
     828             :                                 break;
     829    92369788 :                         } else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
     830             :                                 break;
     831             :                         }
     832             :                 }
     833     3237870 :                 if (ht->nInternalPointer == idx) {
     834     3237841 :                         ht->nInternalPointer = new_idx;
     835             :                 }
     836             :                 zend_hash_iterators_update(ht, idx, new_idx);
     837             :         }
     838    52194542 :         if (p->key) {
     839    51919638 :                 zend_string_release(p->key);
     840             :         }
     841    52194542 :         if (ht->pDestructor) {
     842             :                 zval tmp;
     843    51391763 :                 ZVAL_COPY_VALUE(&tmp, &p->val);
     844    51391763 :                 ZVAL_UNDEF(&p->val);
     845    51391763 :                 ht->pDestructor(&tmp);
     846             :         } else {
     847      802779 :                 ZVAL_UNDEF(&p->val);
     848             :         }
     849    52194542 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     850             : }
     851             : 
     852             : static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
     853             : {
     854     7312829 :         Bucket *prev = NULL;
     855             : 
     856     7312829 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     857     7300767 :                 uint32_t nIndex = p->h & ht->nTableMask;
     858     7300767 :                 uint32_t i = ht->arHash[nIndex];
     859             : 
     860     7300767 :                 if (i != idx) {
     861      319499 :                         prev = ht->arData + i;
     862      362749 :                         while (Z_NEXT(prev->val) != idx) {
     863       43250 :                                 i = Z_NEXT(prev->val);
     864       43250 :                                 prev = ht->arData + i;
     865             :                         }
     866             :                 }
     867             :         }
     868             : 
     869             :         _zend_hash_del_el_ex(ht, idx, p, prev);
     870             : }
     871             : 
     872    44723832 : ZEND_API int zend_hash_del(HashTable *ht, zend_string *key)
     873             : {
     874             :         zend_ulong h;
     875             :         uint32_t nIndex;
     876             :         uint32_t idx;
     877             :         Bucket *p;
     878    44723832 :         Bucket *prev = NULL;
     879             : 
     880             :         IS_CONSISTENT(ht);
     881             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     882             : 
     883    44723832 :         h = zend_string_hash_val(key);
     884    44723832 :         nIndex = h & ht->nTableMask;
     885             : 
     886    44723832 :         idx = ht->arHash[nIndex];
     887    92199425 :         while (idx != INVALID_IDX) {
     888    46680252 :                 p = ht->arData + idx;
     889   225035955 :                 if ((p->key == key) ||
     890    46652712 :                         (p->h == h &&
     891    43900997 :                      p->key &&
     892    43900997 :                      p->key->len == key->len &&
     893    43900997 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     894             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     895    43928491 :                         return SUCCESS;
     896             :                 }
     897     2751761 :                 prev = p;
     898     2751761 :                 idx = Z_NEXT(p->val);
     899             :         }
     900      795341 :         return FAILURE;
     901             : }
     902             : 
     903         399 : ZEND_API int zend_hash_del_ind(HashTable *ht, zend_string *key)
     904             : {
     905             :         zend_ulong h;
     906             :         uint32_t nIndex;
     907             :         uint32_t idx;
     908             :         Bucket *p;
     909         399 :         Bucket *prev = NULL;
     910             : 
     911             :         IS_CONSISTENT(ht);
     912             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     913             : 
     914         399 :         h = zend_string_hash_val(key);
     915         399 :         nIndex = h & ht->nTableMask;
     916             : 
     917         399 :         idx = ht->arHash[nIndex];
     918         806 :         while (idx != INVALID_IDX) {
     919         218 :                 p = ht->arData + idx;
     920         914 :                 if ((p->key == key) ||
     921         180 :                         (p->h == h &&
     922         172 :                      p->key &&
     923         172 :                      p->key->len == key->len &&
     924         172 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     925         420 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
     926          14 :                                 zval *data = Z_INDIRECT(p->val);
     927             : 
     928          14 :                                 if (Z_TYPE_P(data) == IS_UNDEF) {
     929           0 :                                         return FAILURE;
     930             :                                 } else {
     931          14 :                                         if (ht->pDestructor) {
     932          14 :                                                 ht->pDestructor(data);
     933             :                                         }
     934          14 :                                         ZVAL_UNDEF(data);
     935             :                                 }
     936             :                         } else {
     937             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
     938             :                         }
     939         210 :                         return SUCCESS;
     940             :                 }
     941           8 :                 prev = p;
     942           8 :                 idx = Z_NEXT(p->val);
     943             :         }
     944         189 :         return FAILURE;
     945             : }
     946             : 
     947      736176 : ZEND_API int zend_hash_str_del(HashTable *ht, const char *str, size_t len)
     948             : {
     949             :         zend_ulong h;
     950             :         uint32_t nIndex;
     951             :         uint32_t idx;
     952             :         Bucket *p;
     953      736176 :         Bucket *prev = NULL;
     954             : 
     955             :         IS_CONSISTENT(ht);
     956             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     957             : 
     958      736176 :         h = zend_inline_hash_func(str, len);
     959      736176 :         nIndex = h & ht->nTableMask;
     960             : 
     961      736176 :         idx = ht->arHash[nIndex];
     962     1514604 :         while (idx != INVALID_IDX) {
     963      754785 :                 p = ht->arData + idx;
     964     2892384 :                 if ((p->h == h)
     965             :                          && p->key
     966     1425066 :                          && (p->key->len == len)
     967      712533 :                          && !memcmp(p->key->val, str, len)) {
     968     1425066 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
     969           0 :                                 zval *data = Z_INDIRECT(p->val);
     970             : 
     971           0 :                                 if (Z_TYPE_P(data) == IS_UNDEF) {
     972           0 :                                         return FAILURE;
     973             :                                 } else {
     974           0 :                                         if (ht->pDestructor) {
     975           0 :                                                 ht->pDestructor(data);
     976             :                                         }
     977           0 :                                         ZVAL_UNDEF(data);
     978             :                                 }
     979             :                         } else {
     980             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
     981             :                         }
     982      712533 :                         return SUCCESS;
     983             :                 }
     984       42252 :                 prev = p;
     985       42252 :                 idx = Z_NEXT(p->val);
     986             :         }
     987       23643 :         return FAILURE;
     988             : }
     989             : 
     990           0 : ZEND_API int zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
     991             : {
     992             :         zend_ulong h;
     993             :         uint32_t nIndex;
     994             :         uint32_t idx;
     995             :         Bucket *p;
     996           0 :         Bucket *prev = NULL;
     997             : 
     998             :         IS_CONSISTENT(ht);
     999             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1000             : 
    1001           0 :         h = zend_inline_hash_func(str, len);
    1002           0 :         nIndex = h & ht->nTableMask;
    1003             : 
    1004           0 :         idx = ht->arHash[nIndex];
    1005           0 :         while (idx != INVALID_IDX) {
    1006           0 :                 p = ht->arData + idx;
    1007           0 :                 if ((p->h == h)
    1008             :                          && p->key
    1009           0 :                          && (p->key->len == len)
    1010           0 :                          && !memcmp(p->key->val, str, len)) {
    1011             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1012           0 :                         return SUCCESS;
    1013             :                 }
    1014           0 :                 prev = p;
    1015           0 :                 idx = Z_NEXT(p->val);
    1016             :         }
    1017           0 :         return FAILURE;
    1018             : }
    1019             : 
    1020      247861 : ZEND_API int zend_hash_index_del(HashTable *ht, zend_ulong h)
    1021             : {
    1022             :         uint32_t nIndex;
    1023             :         uint32_t idx;
    1024             :         Bucket *p;
    1025      247861 :         Bucket *prev = NULL;
    1026             : 
    1027             :         IS_CONSISTENT(ht);
    1028             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1029             : 
    1030      247861 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1031      100410 :                 if (h < ht->nNumUsed) {
    1032       94251 :                         p = ht->arData + h;
    1033      188502 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1034       94245 :                                 _zend_hash_del_el_ex(ht, h, p, NULL);
    1035       94245 :                                 return SUCCESS;
    1036             :                         }
    1037             :                 }
    1038        6165 :                 return FAILURE;
    1039             :         }
    1040      147451 :         nIndex = h & ht->nTableMask;
    1041             : 
    1042      147451 :         idx = ht->arHash[nIndex];
    1043      295166 :         while (idx != INVALID_IDX) {
    1044      146512 :                 p = ht->arData + idx;
    1045      146512 :                 if ((p->h == h) && (p->key == NULL)) {
    1046             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1047      146248 :                         return SUCCESS;
    1048             :                 }
    1049         264 :                 prev = p;
    1050         264 :                 idx = Z_NEXT(p->val);
    1051             :         }
    1052        1203 :         return FAILURE;
    1053             : }
    1054             : 
    1055    14597568 : ZEND_API void zend_hash_destroy(HashTable *ht)
    1056             : {
    1057             :         Bucket *p, *end;
    1058             : 
    1059             :         IS_CONSISTENT(ht);
    1060             :         HT_ASSERT(GC_REFCOUNT(ht) <= 1);
    1061             : 
    1062    14597568 :         if (ht->nNumUsed) {
    1063     7637137 :                 p = ht->arData;
    1064     7637137 :                 end = p + ht->nNumUsed;
    1065     7637137 :                 if (ht->pDestructor) {
    1066             :                         SET_INCONSISTENT(HT_IS_DESTROYING);
    1067             : 
    1068     7338727 :                         if (ht->u.flags & HASH_FLAG_PACKED) {
    1069             :                                 do {
    1070     7867488 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1071     3064053 :                                                 ht->pDestructor(&p->val);
    1072             :                                         }
    1073     3933743 :                                 } while (++p != end);
    1074             :                         } else {
    1075             :                                 do {
    1076   660195702 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1077   281767137 :                                                 ht->pDestructor(&p->val);
    1078   281767137 :                                                 if (EXPECTED(p->key)) {
    1079   281494451 :                                                         zend_string_release(p->key);
    1080             :                                                 }
    1081             :                                         }
    1082   330097851 :                                 } while (++p != end);
    1083             :                         }
    1084             : 
    1085             :                         SET_INCONSISTENT(HT_DESTROYED);
    1086             :                 } else {
    1087      298410 :                         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1088             :                                 do {
    1089    21580146 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1090    10706446 :                                                 if (EXPECTED(p->key)) {
    1091     9426714 :                                                         zend_string_release(p->key);
    1092             :                                                 }
    1093             :                                         }
    1094    10790073 :                                 } while (++p != end);
    1095             :                         }
    1096             :                 }
    1097             :                 zend_hash_iterators_remove(ht);
    1098     6960431 :         } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    1099     6889830 :                 return;
    1100             :         }
    1101     7707737 :         pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1102             : }
    1103             : 
    1104     3716314 : ZEND_API void zend_array_destroy(HashTable *ht)
    1105             : {
    1106             :         Bucket *p, *end;
    1107             : 
    1108             :         IS_CONSISTENT(ht);
    1109             :         HT_ASSERT(GC_REFCOUNT(ht) <= 1);
    1110             : 
    1111     3716314 :         if (ht->nNumUsed) {
    1112             : 
    1113             :                 /* In some rare cases destructors of regular arrays may be changed */
    1114     2342787 :                 if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) {
    1115          71 :                         zend_hash_destroy(ht);
    1116          71 :                         return;
    1117             :                 }
    1118             : 
    1119     2342716 :                 p = ht->arData;
    1120     2342716 :                 end = p + ht->nNumUsed;
    1121             :                 SET_INCONSISTENT(HT_IS_DESTROYING);
    1122             : 
    1123     2342716 :                 if (ht->u.flags & HASH_FLAG_PACKED) {
    1124             :                         do {
    1125    10290756 :                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1126     4272266 :                                         i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1127             :                                 }
    1128     5145376 :                         } while (++p != end);
    1129             :                 } else {
    1130             :                         do {
    1131     9507178 :                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1132     4752859 :                                         i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1133     4752859 :                                         if (EXPECTED(p->key)) {
    1134     4420388 :                                                 zend_string_release(p->key);
    1135             :                                         }
    1136             :                                 }
    1137     4753589 :                         } while (++p != end);
    1138             :                 }
    1139             :                 zend_hash_iterators_remove(ht);
    1140             :                 SET_INCONSISTENT(HT_DESTROYED);
    1141     1373527 :         } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    1142     1373273 :                 return;
    1143             :         }
    1144     2342968 :         pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1145             : }
    1146             : 
    1147       50889 : ZEND_API void zend_hash_clean(HashTable *ht)
    1148             : {
    1149             :         Bucket *p, *end;
    1150             : 
    1151             :         IS_CONSISTENT(ht);
    1152             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1153             : 
    1154       50889 :         if (ht->nNumUsed) {
    1155        8654 :                 p = ht->arData;
    1156        8654 :                 end = p + ht->nNumUsed;
    1157        8654 :                 if (ht->pDestructor) {
    1158        3639 :                         if (ht->u.flags & HASH_FLAG_PACKED) {
    1159             :                                 do {
    1160         100 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1161          21 :                                                 ht->pDestructor(&p->val);
    1162             :                                         }
    1163          50 :                                 } while (++p != end);
    1164             :                         } else {
    1165             :                                 do {
    1166     3545722 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1167     1772860 :                                                 ht->pDestructor(&p->val);
    1168     1772860 :                                                 if (EXPECTED(p->key)) {
    1169     1772858 :                                                         zend_string_release(p->key);
    1170             :                                                 }
    1171             :                                         }
    1172     1772861 :                                 } while (++p != end);
    1173             :                         }
    1174             :                 } else {
    1175        5015 :                         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1176             :                                 do {
    1177       60836 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1178       30418 :                                                 if (EXPECTED(p->key)) {
    1179       27553 :                                                         zend_string_release(p->key);
    1180             :                                                 }
    1181             :                                         }
    1182       30418 :                                 } while (++p != end);
    1183             :                         }
    1184             :                 }
    1185        8654 :                 if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1186        8639 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
    1187             :                 }
    1188             :         }
    1189       50889 :         ht->nNumUsed = 0;
    1190       50889 :         ht->nNumOfElements = 0;
    1191       50889 :         ht->nNextFreeElement = 0;
    1192       50889 :         ht->nInternalPointer = INVALID_IDX;
    1193       50889 : }
    1194             : 
    1195       87833 : ZEND_API void zend_symtable_clean(HashTable *ht)
    1196             : {
    1197             :         Bucket *p, *end;
    1198             : 
    1199             :         IS_CONSISTENT(ht);
    1200             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1201             : 
    1202       87833 :         if (ht->nNumUsed) {
    1203       87827 :                 p = ht->arData;
    1204       87827 :                 end = p + ht->nNumUsed;
    1205             :                 do {
    1206      354994 :                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1207      177496 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1208      177496 :                                 if (EXPECTED(p->key)) {
    1209      177496 :                                         zend_string_release(p->key);
    1210             :                                 }
    1211             :                         }
    1212      177497 :                 } while (++p != end);
    1213       87827 :                 if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1214       87827 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
    1215             :                 }
    1216             :         }
    1217       87833 :         ht->nNumUsed = 0;
    1218       87833 :         ht->nNumOfElements = 0;
    1219       87833 :         ht->nNextFreeElement = 0;
    1220       87833 :         ht->nInternalPointer = INVALID_IDX;
    1221       87833 : }
    1222             : 
    1223           0 : ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
    1224             : {
    1225             :         uint32_t idx;
    1226             :         Bucket *p;
    1227             : 
    1228             :         IS_CONSISTENT(ht);
    1229             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1230             : 
    1231           0 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1232           0 :                 p = ht->arData + idx;
    1233           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1234             :                 _zend_hash_del_el(ht, idx, p);
    1235             :         }
    1236           0 :         if (ht->u.flags & HASH_FLAG_INITIALIZED) {
    1237           0 :                 pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1238             :         }
    1239             : 
    1240             :         SET_INCONSISTENT(HT_DESTROYED);
    1241           0 : }
    1242             : 
    1243       83660 : ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht)
    1244             : {
    1245             :         uint32_t idx;
    1246             :         Bucket *p;
    1247             : 
    1248             :         IS_CONSISTENT(ht);
    1249             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1250             : 
    1251       83660 :         idx = ht->nNumUsed;
    1252     1933711 :         while (idx > 0) {
    1253     1766391 :                 idx--;
    1254     1766391 :                 p = ht->arData + idx;
    1255     3532782 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1256             :                 _zend_hash_del_el(ht, idx, p);
    1257             :         }
    1258             : 
    1259       83660 :         if (ht->u.flags & HASH_FLAG_INITIALIZED) {
    1260       63582 :                 pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1261             :         }
    1262             : 
    1263             :         SET_INCONSISTENT(HT_DESTROYED);
    1264       83660 : }
    1265             : 
    1266             : /* This is used to recurse elements and selectively delete certain entries
    1267             :  * from a hashtable. apply_func() receives the data and decides if the entry
    1268             :  * should be deleted or recursion should be stopped. The following three
    1269             :  * return codes are possible:
    1270             :  * ZEND_HASH_APPLY_KEEP   - continue
    1271             :  * ZEND_HASH_APPLY_STOP   - stop iteration
    1272             :  * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
    1273             :  */
    1274             : 
    1275       93184 : ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func)
    1276             : {
    1277             :         uint32_t idx;
    1278             :         Bucket *p;
    1279             :         int result;
    1280             : 
    1281             :         IS_CONSISTENT(ht);
    1282             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1283             : 
    1284       93184 :         HASH_PROTECT_RECURSION(ht);
    1285     1710728 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1286     1617546 :                 p = ht->arData + idx;
    1287     3235092 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1288             : 
    1289     1617525 :                 result = apply_func(&p->val);
    1290             : 
    1291     1617523 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1292             :                         _zend_hash_del_el(ht, idx, p);
    1293             :                 }
    1294     1617523 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1295           0 :                         break;
    1296             :                 }
    1297             :         }
    1298       93182 :         HASH_UNPROTECT_RECURSION(ht);
    1299       93182 : }
    1300             : 
    1301             : 
    1302      637614 : ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
    1303             : {
    1304             :     uint32_t idx;
    1305             :         Bucket *p;
    1306             :         int result;
    1307             : 
    1308             :         IS_CONSISTENT(ht);
    1309             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1310             : 
    1311      637614 :         HASH_PROTECT_RECURSION(ht);
    1312   180578970 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1313   179945421 :                 p = ht->arData + idx;
    1314   359890842 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1315             : 
    1316   142808195 :                 result = apply_func(&p->val, argument);
    1317             : 
    1318   142808195 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1319             :                         _zend_hash_del_el(ht, idx, p);
    1320             :                 }
    1321   142808195 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1322        4065 :                         break;
    1323             :                 }
    1324             :         }
    1325      637614 :         HASH_UNPROTECT_RECURSION(ht);
    1326      637614 : }
    1327             : 
    1328             : 
    1329         724 : ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int num_args, ...)
    1330             : {
    1331             :         uint32_t idx;
    1332             :         Bucket *p;
    1333             :         va_list args;
    1334             :         zend_hash_key hash_key;
    1335             :         int result;
    1336             : 
    1337             :         IS_CONSISTENT(ht);
    1338             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1339             : 
    1340         724 :         HASH_PROTECT_RECURSION(ht);
    1341             : 
    1342     1064231 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1343     1063507 :                 p = ht->arData + idx;
    1344     2127014 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1345     1063418 :                 va_start(args, num_args);
    1346     1063418 :                 hash_key.h = p->h;
    1347     1063418 :                 hash_key.key = p->key;
    1348             : 
    1349     1063418 :                 result = apply_func(&p->val, num_args, args, &hash_key);
    1350             : 
    1351     1063418 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1352             :                         _zend_hash_del_el(ht, idx, p);
    1353             :                 }
    1354     1063418 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1355           0 :                         va_end(args);
    1356           0 :                         break;
    1357             :                 }
    1358     1063418 :                 va_end(args);
    1359             :         }
    1360             : 
    1361         724 :         HASH_UNPROTECT_RECURSION(ht);
    1362         724 : }
    1363             : 
    1364             : 
    1365      109131 : ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func)
    1366             : {
    1367             :         uint32_t idx;
    1368             :         Bucket *p;
    1369             :         int result;
    1370             : 
    1371             :         IS_CONSISTENT(ht);
    1372             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1373             : 
    1374      109131 :         HASH_PROTECT_RECURSION(ht);
    1375      109131 :         idx = ht->nNumUsed;
    1376      729971 :         while (idx > 0) {
    1377      574301 :                 idx--;
    1378      574301 :                 p = ht->arData + idx;
    1379     1148602 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1380             : 
    1381      522401 :                 result = apply_func(&p->val);
    1382             : 
    1383      522401 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1384             :                         _zend_hash_del_el(ht, idx, p);
    1385             :                 }
    1386      522401 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1387       62592 :                         break;
    1388             :                 }
    1389             :         }
    1390      109131 :         HASH_UNPROTECT_RECURSION(ht);
    1391      109131 : }
    1392             : 
    1393             : 
    1394         468 : ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
    1395             : {
    1396             :     uint32_t idx;
    1397             :         Bucket *p;
    1398             :         zval *new_entry, *data;
    1399             :         zend_bool setTargetPointer;
    1400             : 
    1401             :         IS_CONSISTENT(source);
    1402             :         IS_CONSISTENT(target);
    1403             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1404             : 
    1405         468 :         setTargetPointer = (target->nInternalPointer == INVALID_IDX);
    1406       11870 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1407       11402 :                 p = source->arData + idx;
    1408       22804 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1409             : 
    1410       11402 :                 if (setTargetPointer && source->nInternalPointer == idx) {
    1411         315 :                         target->nInternalPointer = INVALID_IDX;
    1412             :                 }
    1413             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1414       11402 :                 data = &p->val;
    1415       11402 :                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1416          96 :                         data = Z_INDIRECT_P(data);
    1417          96 :                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1418           0 :                                 continue;
    1419             :                         }
    1420             :                 }
    1421       11402 :                 if (p->key) {
    1422       11313 :                         new_entry = zend_hash_update(target, p->key, data);
    1423             :                 } else {
    1424          89 :                         new_entry = zend_hash_index_update(target, p->h, data);
    1425             :                 }
    1426       11402 :                 if (pCopyConstructor) {
    1427         412 :                         pCopyConstructor(new_entry);
    1428             :                 }
    1429             :         }
    1430         468 :         if (target->nInternalPointer == INVALID_IDX && target->nNumOfElements > 0) {
    1431           0 :                 idx = 0;
    1432           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1433           0 :                         idx++;
    1434             :                 }
    1435           0 :                 target->nInternalPointer = idx;
    1436             :         }
    1437         468 : }
    1438             : 
    1439             : 
    1440     1269937 : ZEND_API HashTable *zend_array_dup(HashTable *source)
    1441             : {
    1442             :     uint32_t idx, target_idx;
    1443             :         uint32_t nIndex;
    1444             :         Bucket *p, *q;
    1445             :         zval *data;
    1446             :         HashTable *target;
    1447             : 
    1448             :         IS_CONSISTENT(source);
    1449             : 
    1450     1269937 :         ALLOC_HASHTABLE(target);
    1451     1269937 :         GC_REFCOUNT(target) = 1;
    1452     1269937 :         GC_TYPE_INFO(target) = IS_ARRAY;
    1453             : 
    1454     1269937 :         target->nTableMask = source->nTableMask;
    1455     1269937 :         target->nTableSize = source->nTableSize;
    1456     1269937 :         target->pDestructor = source->pDestructor;
    1457     1269937 :         target->nInternalPointer = INVALID_IDX;
    1458     1269937 :         target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1459             : 
    1460     1269937 :         target_idx = 0;
    1461     1269937 :         if (target->u.flags & HASH_FLAG_INITIALIZED) {
    1462     1107185 :                 if (target->u.flags & HASH_FLAG_PACKED) {
    1463     1049432 :                         target->nNumUsed = source->nNumUsed;
    1464     1049432 :                         target->nNumOfElements = source->nNumOfElements;
    1465     1049432 :                         target->nNextFreeElement = source->nNextFreeElement;
    1466     1049432 :                         target->arData = (Bucket *) pemalloc(target->nTableSize * sizeof(Bucket), 0);
    1467     1049432 :                         target->arHash = (uint32_t*)&uninitialized_bucket;
    1468     1049432 :                         target->nInternalPointer = source->nInternalPointer;
    1469             : 
    1470     3906081 :                         for (idx = 0; idx < source->nNumUsed; idx++) {
    1471     2856649 :                                 p = source->arData + idx;
    1472     2856649 :                                 q = target->arData + idx;
    1473     5713298 :                                 if (Z_TYPE(p->val) == IS_UNDEF) {
    1474      849222 :                                         ZVAL_UNDEF(&q->val);
    1475      849222 :                                         continue;
    1476             :                                 }
    1477             :                                 /* INDIRECT element may point to UNDEF-ined slots */
    1478     2007427 :                                 data = &p->val;
    1479     2007427 :                                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1480           0 :                                         data = Z_INDIRECT_P(data);
    1481           0 :                                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1482           0 :                                                 ZVAL_UNDEF(&q->val);
    1483           0 :                                                 continue;
    1484             :                                         }
    1485             :                                 }
    1486             : 
    1487     2007427 :                                 q->h = p->h;
    1488     2007427 :                                 q->key = NULL;
    1489     2007427 :                                 if (Z_OPT_REFCOUNTED_P(data)) {
    1490     1884351 :                                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
    1491           1 :                                                 ZVAL_COPY(&q->val, Z_REFVAL_P(data));
    1492             :                                         } else {
    1493     1884328 :                                                 ZVAL_COPY(&q->val, data);
    1494             :                                         }
    1495             :                                 } else {
    1496      123098 :                                         ZVAL_COPY_VALUE(&q->val, data);
    1497             :                                 }
    1498             :                         }
    1499     2098864 :                         if (target->nNumOfElements > 0 &&
    1500     1049432 :                             target->nInternalPointer == INVALID_IDX) {
    1501           8 :                                 idx = 0;
    1502          26 :                                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1503           1 :                                         idx++;
    1504             :                                 }
    1505           8 :                                 target->nInternalPointer = idx;
    1506             :                         }
    1507             :                 } else {
    1508       57753 :                         target->nNextFreeElement = source->nNextFreeElement;
    1509       57753 :                         target->arData = (Bucket *) pemalloc(target->nTableSize * (sizeof(Bucket) + sizeof(uint32_t)), 0);
    1510       57753 :                         target->arHash = (uint32_t*)(target->arData + target->nTableSize);
    1511       57753 :                         memset(target->arHash, INVALID_IDX, target->nTableSize * sizeof(uint32_t));
    1512             : 
    1513      772196 :                         for (idx = 0; idx < source->nNumUsed; idx++) {
    1514      714443 :                                 p = source->arData + idx;
    1515     1428886 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1516             :                                 /* INDIRECT element may point to UNDEF-ined slots */
    1517      714439 :                                 data = &p->val;
    1518      714439 :                                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1519       29408 :                                         data = Z_INDIRECT_P(data);
    1520       29408 :                                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1521        5159 :                                                 continue;
    1522             :                                         }
    1523             :                                 }
    1524             : 
    1525      709280 :                                 if (source->nInternalPointer == idx) {
    1526       57721 :                                         target->nInternalPointer = target_idx;
    1527             :                                 }
    1528             : 
    1529      709280 :                                 q = target->arData + target_idx;
    1530      709280 :                                 q->h = p->h;
    1531      709280 :                                 q->key = p->key;
    1532      709280 :                                 if (q->key) {
    1533      704225 :                                         zend_string_addref(q->key);
    1534             :                                 }
    1535      709280 :                                 nIndex = q->h & target->nTableMask;
    1536      709280 :                                 Z_NEXT(q->val) = target->arHash[nIndex];
    1537      709280 :                                 target->arHash[nIndex] = target_idx;
    1538      709280 :                                 if (Z_OPT_REFCOUNTED_P(data)) {
    1539      641850 :                                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
    1540          97 :                                                 ZVAL_COPY(&q->val, Z_REFVAL_P(data));
    1541             :                                         } else {
    1542      641116 :                                                 ZVAL_COPY(&q->val, data);
    1543             :                                         }
    1544             :                                 } else {
    1545       68067 :                                         ZVAL_COPY_VALUE(&q->val, data);
    1546             :                                 }
    1547      709280 :                                 target_idx++;
    1548             :                         }
    1549       57753 :                         target->nNumUsed = target_idx;
    1550       57753 :                         target->nNumOfElements = target_idx;
    1551      115486 :                         if (target->nNumOfElements > 0 &&
    1552       57733 :                             target->nInternalPointer == INVALID_IDX) {
    1553          12 :                                 target->nInternalPointer = 0;
    1554             :                         }
    1555             :                 }
    1556             :         } else {
    1557      162752 :                 target->nNumUsed = 0;
    1558      162752 :                 target->nNumOfElements = 0;
    1559      162752 :                 target->nNextFreeElement = 0;
    1560      162752 :                 target->arData = NULL;
    1561      162752 :                 target->arHash = (uint32_t*)&uninitialized_bucket;
    1562             :         }
    1563     1269937 :         return target;
    1564             : }
    1565             : 
    1566             : 
    1567      187913 : ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite ZEND_FILE_LINE_DC)
    1568             : {
    1569             :     uint32_t idx;
    1570             :         Bucket *p;
    1571             :         zval *t;
    1572      187913 :         uint32_t mode = (overwrite?HASH_UPDATE:HASH_ADD);
    1573             : 
    1574             :         IS_CONSISTENT(source);
    1575             :         IS_CONSISTENT(target);
    1576             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1577             : 
    1578     3236585 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1579     3048672 :                 p = source->arData + idx;
    1580     6097344 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1581     3048672 :                 if (p->key) {
    1582     3048661 :                         t = _zend_hash_add_or_update(target, p->key, &p->val, mode ZEND_FILE_LINE_RELAY_CC);
    1583     3048661 :                         if (t && pCopyConstructor) {
    1584     3048079 :                                 pCopyConstructor(t);
    1585             :                         }
    1586             :                 } else {
    1587          11 :                         if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h))) {
    1588           1 :                                 t = zend_hash_index_update(target, p->h, &p->val);
    1589           1 :                                 if (t && pCopyConstructor) {
    1590           1 :                                         pCopyConstructor(t);
    1591             :                                 }
    1592             :                         }
    1593             :                 }
    1594             :         }
    1595      187913 :         if (target->nNumOfElements > 0) {
    1596      187911 :                 idx = 0;
    1597      563733 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1598           0 :                         idx++;
    1599             :                 }
    1600      187911 :                 target->nInternalPointer = idx;
    1601             :         }
    1602      187913 : }
    1603             : 
    1604             : 
    1605           0 : static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, zval *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
    1606             : {
    1607             :         zend_hash_key hash_key;
    1608             : 
    1609           0 :         hash_key.h = p->h;
    1610           0 :         hash_key.key = p->key;
    1611           0 :         return merge_checker_func(target, source_data, &hash_key, pParam);
    1612             : }
    1613             : 
    1614             : 
    1615           0 : ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam)
    1616             : {
    1617             :         uint32_t idx;
    1618             :         Bucket *p;
    1619             :         zval *t;
    1620             : 
    1621             :         IS_CONSISTENT(source);
    1622             :         IS_CONSISTENT(target);
    1623             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1624             : 
    1625           0 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1626           0 :                 p = source->arData + idx;
    1627           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1628           0 :                 if (zend_hash_replace_checker_wrapper(target, &p->val, p, pParam, pMergeSource)) {
    1629           0 :                         t = zend_hash_update(target, p->key, &p->val);
    1630           0 :                         if (t && pCopyConstructor) {
    1631           0 :                                 pCopyConstructor(t);
    1632             :                         }
    1633             :                 }
    1634             :         }
    1635           0 :         if (target->nNumOfElements > 0) {
    1636           0 :                 idx = 0;
    1637           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1638           0 :                         idx++;
    1639             :                 }
    1640           0 :                 target->nInternalPointer = idx;
    1641             :         }
    1642           0 : }
    1643             : 
    1644             : 
    1645             : /* Returns SUCCESS if found and FAILURE if not. The pointer to the
    1646             :  * data is returned in pData. The reason is that there's no reason
    1647             :  * someone using the hash table might not want to have NULL data
    1648             :  */
    1649    51403876 : ZEND_API zval *zend_hash_find(const HashTable *ht, zend_string *key)
    1650             : {
    1651             :         Bucket *p;
    1652             : 
    1653             :         IS_CONSISTENT(ht);
    1654             : 
    1655    51403876 :         p = zend_hash_find_bucket(ht, key);
    1656    51403876 :         return p ? &p->val : NULL;
    1657             : }
    1658             : 
    1659     2632520 : ZEND_API zval *zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
    1660             : {
    1661             :         zend_ulong h;
    1662             :         Bucket *p;
    1663             : 
    1664             :         IS_CONSISTENT(ht);
    1665             : 
    1666     2632520 :         h = zend_inline_hash_func(str, len);
    1667     2632520 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1668     2632520 :         return p ? &p->val : NULL;
    1669             : }
    1670             : 
    1671      566745 : ZEND_API zend_bool zend_hash_exists(const HashTable *ht, zend_string *key)
    1672             : {
    1673             :         Bucket *p;
    1674             : 
    1675             :         IS_CONSISTENT(ht);
    1676             : 
    1677      566745 :         p = zend_hash_find_bucket(ht, key);
    1678      566745 :         return p ? 1 : 0;
    1679             : }
    1680             : 
    1681      862250 : ZEND_API zend_bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
    1682             : {
    1683             :         zend_ulong h;
    1684             :         Bucket *p;
    1685             : 
    1686             :         IS_CONSISTENT(ht);
    1687             : 
    1688      862250 :         h = zend_inline_hash_func(str, len);
    1689      862250 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1690      862250 :         return p ? 1 : 0;
    1691             : }
    1692             : 
    1693     5777983 : ZEND_API zval *zend_hash_index_find(const HashTable *ht, zend_ulong h)
    1694             : {
    1695             :         Bucket *p;
    1696             : 
    1697             :         IS_CONSISTENT(ht);
    1698             : 
    1699     5777983 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1700     4624130 :                 if (h < ht->nNumUsed) {
    1701     4372738 :                         p = ht->arData + h;
    1702     8745476 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1703     4372246 :                                 return &p->val;
    1704             :                         }
    1705             :                 }
    1706      251884 :                 return NULL;
    1707             :         }
    1708             : 
    1709     1153853 :         p = zend_hash_index_find_bucket(ht, h);
    1710     1153853 :         return p ? &p->val : NULL;
    1711             : }
    1712             : 
    1713             : 
    1714     1544822 : ZEND_API zend_bool zend_hash_index_exists(const HashTable *ht, zend_ulong h)
    1715             : {
    1716             :         Bucket *p;
    1717             : 
    1718             :         IS_CONSISTENT(ht);
    1719             : 
    1720     1544822 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1721          56 :                 if (h < ht->nNumUsed) {
    1722         102 :                         if (Z_TYPE(ht->arData[h].val) != IS_UNDEF) {
    1723          50 :                                 return 1;
    1724             :                         }
    1725             :                 }
    1726           6 :                 return 0;
    1727             :         }
    1728             : 
    1729     1544766 :         p = zend_hash_index_find_bucket(ht, h);
    1730     1544766 :         return p ? 1 : 0;
    1731             : }
    1732             : 
    1733             : 
    1734       20586 : ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
    1735             : {
    1736             :     uint32_t idx;
    1737             : 
    1738             :         IS_CONSISTENT(ht);
    1739             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1740             : 
    1741       21061 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1742       40354 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1743       19702 :                         *pos = idx;
    1744       19702 :                         return;
    1745             :                 }
    1746             :         }
    1747         884 :         *pos = INVALID_IDX;
    1748             : }
    1749             : 
    1750             : 
    1751             : /* This function will be extremely optimized by remembering
    1752             :  * the end of the list
    1753             :  */
    1754          47 : ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
    1755             : {
    1756             :         uint32_t idx;
    1757             : 
    1758             :         IS_CONSISTENT(ht);
    1759             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1760             : 
    1761          47 :         idx = ht->nNumUsed;
    1762          94 :         while (idx > 0) {
    1763          45 :                 idx--;
    1764          90 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1765          45 :                         *pos = idx;
    1766          45 :                         return;
    1767             :                 }
    1768             :         }
    1769           2 :         *pos = INVALID_IDX;
    1770             : }
    1771             : 
    1772             : 
    1773       58065 : ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
    1774             : {
    1775       58065 :         uint32_t idx = *pos;
    1776             : 
    1777             :         IS_CONSISTENT(ht);
    1778             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1779             : 
    1780       58065 :         if (idx != INVALID_IDX) {
    1781             :                 while (1) {
    1782       58109 :                         idx++;
    1783       58109 :                         if (idx >= ht->nNumUsed) {
    1784       16215 :                                 *pos = INVALID_IDX;
    1785       16215 :                                 return SUCCESS;
    1786             :                         }
    1787       83788 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1788       41826 :                                 *pos = idx;
    1789       41826 :                                 return SUCCESS;
    1790             :                         }
    1791          68 :                 }
    1792             :         } else {
    1793          24 :                 return FAILURE;
    1794             :         }
    1795             : }
    1796             : 
    1797          21 : ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
    1798             : {
    1799          21 :         uint32_t idx = *pos;
    1800             : 
    1801             :         IS_CONSISTENT(ht);
    1802             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1803             : 
    1804          21 :         if (idx != INVALID_IDX) {
    1805          38 :                 while (idx > 0) {
    1806          14 :                         idx--;
    1807          28 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1808          14 :                                 *pos = idx;
    1809          14 :                                 return SUCCESS;
    1810             :                         }
    1811             :                 }
    1812           5 :                 *pos = INVALID_IDX;
    1813           5 :                 return SUCCESS;
    1814             :         } else {
    1815           2 :                 return FAILURE;
    1816             :         }
    1817             : }
    1818             : 
    1819             : 
    1820             : /* This function should be made binary safe  */
    1821       13261 : ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, HashPosition *pos)
    1822             : {
    1823       13261 :         uint32_t idx = *pos;
    1824             :         Bucket *p;
    1825             : 
    1826             :         IS_CONSISTENT(ht);
    1827       13261 :         if (idx != INVALID_IDX) {
    1828       12754 :                 p = ht->arData + idx;
    1829       12754 :                 if (p->key) {
    1830       11246 :                         *str_index = p->key;
    1831       11246 :                         return HASH_KEY_IS_STRING;
    1832             :                 } else {
    1833        1508 :                         *num_index = p->h;
    1834        1508 :                         return HASH_KEY_IS_LONG;
    1835             :                 }
    1836             :         }
    1837         507 :         return HASH_KEY_NON_EXISTENT;
    1838             : }
    1839             : 
    1840        3222 : ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
    1841             : {
    1842        3222 :         uint32_t idx = *pos;
    1843             :         Bucket *p;
    1844             : 
    1845             :         IS_CONSISTENT(ht);
    1846        3222 :         if (idx == INVALID_IDX) {
    1847          50 :                 ZVAL_NULL(key);
    1848             :         } else {
    1849        3172 :                 p = ht->arData + idx;
    1850        3172 :                 if (p->key) {
    1851         669 :                         ZVAL_STR_COPY(key, p->key);
    1852             :                 } else {
    1853        2503 :                         ZVAL_LONG(key, p->h);
    1854             :                 }
    1855             :         }
    1856        3222 : }
    1857             : 
    1858       68539 : ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
    1859             : {
    1860       68539 :     uint32_t idx = *pos;
    1861             :         Bucket *p;
    1862             : 
    1863             :         IS_CONSISTENT(ht);
    1864       68539 :         if (idx != INVALID_IDX) {
    1865       53374 :                 p = ht->arData + idx;
    1866       53374 :                 if (p->key) {
    1867       50841 :                         return HASH_KEY_IS_STRING;
    1868             :                 } else {
    1869        2533 :                         return HASH_KEY_IS_LONG;
    1870             :                 }
    1871             :         }
    1872       15165 :         return HASH_KEY_NON_EXISTENT;
    1873             : }
    1874             : 
    1875             : 
    1876       55729 : ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
    1877             : {
    1878       55729 :         uint32_t idx = *pos;
    1879             :         Bucket *p;
    1880             : 
    1881             :         IS_CONSISTENT(ht);
    1882       55729 :         if (idx != INVALID_IDX) {
    1883       54899 :                 p = ht->arData + idx;
    1884       54899 :                 return &p->val;
    1885             :         } else {
    1886         830 :                 return NULL;
    1887             :         }
    1888             : }
    1889             : 
    1890       92926 : ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q) {
    1891             :         zval val;
    1892             :         zend_ulong h;
    1893             :         zend_string *key;
    1894             : 
    1895       92926 :         ZVAL_COPY_VALUE(&val, &p->val);
    1896       92926 :         h = p->h;
    1897       92926 :         key = p->key;
    1898             : 
    1899       92926 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    1900       92926 :         p->h = q->h;
    1901       92926 :         p->key = q->key;
    1902             : 
    1903       92926 :         ZVAL_COPY_VALUE(&q->val, &val);
    1904       92926 :         q->h = h;
    1905       92926 :         q->key = key;
    1906       92926 : }
    1907             : 
    1908       68825 : ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q) {
    1909             :         zval val;
    1910             : 
    1911       68825 :         ZVAL_COPY_VALUE(&val, &p->val);
    1912       68825 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    1913       68825 :         ZVAL_COPY_VALUE(&q->val, &val);
    1914       68825 : }
    1915             : 
    1916        1099 : ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q) {
    1917             :         zval val;
    1918             :         zend_ulong h;
    1919             : 
    1920        1099 :         ZVAL_COPY_VALUE(&val, &p->val);
    1921        1099 :         h = p->h;
    1922             : 
    1923        1099 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    1924        1099 :         p->h = q->h;
    1925             : 
    1926        1099 :         ZVAL_COPY_VALUE(&q->val, &val);
    1927        1099 :         q->h = h;
    1928        1099 : }
    1929             : 
    1930       22592 : ZEND_API int zend_hash_sort_ex(HashTable *ht, sort_func_t sort, compare_func_t compar, zend_bool renumber)
    1931             : {
    1932             :         Bucket *p;
    1933             :         uint32_t i, j;
    1934             : 
    1935             :         IS_CONSISTENT(ht);
    1936             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1937             : 
    1938       22592 :         if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
    1939         288 :                 return SUCCESS;
    1940             :         }
    1941             : 
    1942       22304 :         if (ht->nNumUsed == ht->nNumOfElements) {
    1943       22194 :                 i = ht->nNumUsed;
    1944             :         } else {
    1945         787 :                 for (j = 0, i = 0; j < ht->nNumUsed; j++) {
    1946         677 :                         p = ht->arData + j;
    1947        1354 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1948         520 :                         if (i != j) {
    1949         504 :                                 ht->arData[i] = *p;
    1950             :                         }
    1951         520 :                         i++;
    1952             :                 }
    1953             :         }
    1954             : 
    1955       44309 :         sort((void *)ht->arData, i, sizeof(Bucket), compar,
    1956             :                         (swap_func_t)(renumber? zend_hash_bucket_renum_swap :
    1957       22005 :                                 ((ht->u.flags & HASH_FLAG_PACKED) ? zend_hash_bucket_packed_swap : zend_hash_bucket_swap)));
    1958             : 
    1959       22303 :         HANDLE_BLOCK_INTERRUPTIONS();
    1960       22303 :         ht->nNumUsed = i;
    1961       22303 :         ht->nInternalPointer = 0;
    1962             : 
    1963       22303 :         if (renumber) {
    1964       15772 :                 for (j = 0; j < i; j++) {
    1965       15474 :                         p = ht->arData + j;
    1966       15474 :                         p->h = j;
    1967       15474 :                         if (p->key) {
    1968         286 :                                 zend_string_release(p->key);
    1969         286 :                                 p->key = NULL;
    1970             :                         }
    1971             :                 }
    1972             : 
    1973         298 :                 ht->nNextFreeElement = i;
    1974             :         }
    1975       22303 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1976         511 :                 if (!renumber) {
    1977         261 :                         zend_hash_packed_to_hash(ht);
    1978             :                 }
    1979             :         } else {
    1980       21792 :                 if (renumber) {
    1981          48 :                         ht->u.flags |= HASH_FLAG_PACKED;
    1982          48 :                         ht->nTableMask = 0;
    1983          96 :                         ht->arData = perealloc(ht->arData, ht->nTableSize * sizeof(Bucket), ht->u.flags & HASH_FLAG_PERSISTENT);
    1984          48 :                         ht->arHash = (uint32_t*)&uninitialized_bucket;
    1985             :                 } else {
    1986       21744 :                         zend_hash_rehash(ht);
    1987             :                 }
    1988             :         }
    1989             : 
    1990       22303 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1991             : 
    1992       22303 :         return SUCCESS;
    1993             : }
    1994             : 
    1995             : 
    1996        1117 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered)
    1997             : {
    1998             :         uint32_t idx1, idx2;
    1999        1117 :         Bucket *p1, *p2 = NULL;
    2000             :         int result;
    2001             :         zval *pData1, *pData2;
    2002             : 
    2003             :         IS_CONSISTENT(ht1);
    2004             :         IS_CONSISTENT(ht2);
    2005             : 
    2006        1117 :         HASH_PROTECT_RECURSION(ht1);
    2007        1117 :         HASH_PROTECT_RECURSION(ht2);
    2008             : 
    2009        1117 :         result = ht1->nNumOfElements - ht2->nNumOfElements;
    2010        1117 :         if (result!=0) {
    2011         509 :                 HASH_UNPROTECT_RECURSION(ht1);
    2012         509 :                 HASH_UNPROTECT_RECURSION(ht2);
    2013         509 :                 return result;
    2014             :         }
    2015             : 
    2016        4419 :         for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
    2017        4000 :                 p1 = ht1->arData + idx1;
    2018        8000 :                 if (Z_TYPE(p1->val) == IS_UNDEF) continue;
    2019             : 
    2020        3987 :                 if (ordered) {
    2021             :                         while (1) {
    2022        1140 :                                 p2 = ht2->arData + idx2;
    2023        1140 :                                 if (idx2 == ht2->nNumUsed) {
    2024           0 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2025           0 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2026           0 :                                         return 1; /* That's not supposed to happen */
    2027             :                                 }
    2028        2280 :                                 if (Z_TYPE(p2->val) != IS_UNDEF) break;
    2029           1 :                                 idx2++;
    2030           1 :                         }
    2031        1506 :                         if (p1->key == NULL && p2->key == NULL) { /* numeric indices */
    2032         368 :                                 result = p1->h - p2->h;
    2033         368 :                                 if (result != 0) {
    2034           1 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2035           1 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2036           1 :                                         return result;
    2037             :                                 }
    2038             :                         } else { /* string indices */
    2039         771 :                                 size_t len0 = (p1->key ? p1->key->len : 0);
    2040         771 :                                 size_t len1 = (p2->key ? p2->key->len : 0);
    2041         771 :                                 if (len0 != len1) {
    2042           0 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2043           0 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2044           0 :                                         return len0 > len1 ? 1 : -1;
    2045             :                                 }
    2046         771 :                                 result = memcmp(p1->key->val, p2->key->val, p1->key->len);
    2047         771 :                                 if (result != 0) {
    2048           0 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2049           0 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2050           0 :                                         return result;
    2051             :                                 }
    2052             :                         }
    2053        1138 :                         pData2 = &p2->val;
    2054             :                 } else {
    2055        2848 :                         if (p1->key == NULL) { /* numeric index */
    2056         486 :                                 pData2 = zend_hash_index_find(ht2, p1->h);
    2057         486 :                                 if (pData2 == NULL) {
    2058           2 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2059           2 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2060           2 :                                         return 1;
    2061             :                                 }
    2062             :                         } else { /* string index */
    2063        2362 :                                 pData2 = zend_hash_find(ht2, p1->key);
    2064        2362 :                                 if (pData2 == NULL) {
    2065          22 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2066          22 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2067          22 :                                         return 1;
    2068             :                                 }
    2069             :                         }
    2070             :                 }
    2071        3962 :                 pData1 = &p1->val;
    2072        3962 :                 if (Z_TYPE_P(pData1) == IS_INDIRECT) {
    2073         129 :                         pData1 = Z_INDIRECT_P(pData1);
    2074             :                 }
    2075        3962 :                 if (Z_TYPE_P(pData2) == IS_INDIRECT) {
    2076         129 :                         pData2 = Z_INDIRECT_P(pData2);
    2077             :                 }
    2078        3962 :                 if (Z_TYPE_P(pData1) == IS_UNDEF) {
    2079           0 :                         if (Z_TYPE_P(pData2) != IS_UNDEF) {
    2080           0 :                                 return -1;
    2081             :                         }
    2082        3962 :                 } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
    2083           0 :                         return 1;
    2084             :                 } else {
    2085        3962 :                         result = compar(pData1, pData2);
    2086             :                 }
    2087        3962 :                 if (result != 0) {
    2088         164 :                         HASH_UNPROTECT_RECURSION(ht1);
    2089         164 :                         HASH_UNPROTECT_RECURSION(ht2);
    2090         164 :                         return result;
    2091             :                 }
    2092        3798 :                 if (ordered) {
    2093        1134 :                         idx2++;
    2094             :                 }
    2095             :         }
    2096             : 
    2097         419 :         HASH_UNPROTECT_RECURSION(ht1);
    2098         419 :         HASH_UNPROTECT_RECURSION(ht2);
    2099         419 :         return 0;
    2100             : }
    2101             : 
    2102             : 
    2103          82 : ZEND_API zval *zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag)
    2104             : {
    2105             :         uint32_t idx;
    2106             :         Bucket *p, *res;
    2107             : 
    2108             :         IS_CONSISTENT(ht);
    2109             : 
    2110          82 :         if (ht->nNumOfElements == 0 ) {
    2111           4 :                 return NULL;
    2112             :         }
    2113             : 
    2114          78 :         idx = 0;
    2115             :         while (1) {
    2116          78 :                 if (idx == ht->nNumUsed) {
    2117           0 :                         return NULL;
    2118             :                 }
    2119         156 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
    2120           0 :                 idx++;
    2121           0 :         }
    2122          78 :         res = ht->arData + idx;
    2123         376 :         for (; idx < ht->nNumUsed; idx++) {
    2124         298 :                 p = ht->arData + idx;
    2125         596 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2126             : 
    2127         298 :                 if (flag) {
    2128         229 :                         if (compar(res, p) < 0) { /* max */
    2129          20 :                                 res = p;
    2130             :                         }
    2131             :                 } else {
    2132          69 :                         if (compar(res, p) > 0) { /* min */
    2133           6 :                                 res = p;
    2134             :                         }
    2135             :                 }
    2136             :         }
    2137          78 :         return &res->val;
    2138             : }
    2139             : 
    2140      383125 : ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
    2141             : {
    2142      383125 :         register const char *tmp = key;
    2143             : 
    2144      383125 :         const char *end = key + length;
    2145             :         ZEND_ASSERT(*end == '\0');
    2146             : 
    2147      383125 :         if (*tmp == '-') {
    2148          59 :                 tmp++;
    2149             :         }
    2150             : 
    2151      746109 :         if ((*tmp == '0' && length > 1) /* numbers with leading zeros */
    2152      362984 :          || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
    2153             :          || (SIZEOF_ZEND_LONG == 4 &&
    2154             :              end - tmp == MAX_LENGTH_OF_LONG - 1 &&
    2155             :              *tmp > '2')) { /* overflow */
    2156       20168 :                 return 0;
    2157             :         }
    2158      362957 :         *idx = (*tmp - '0');
    2159             :         while (1) {
    2160     1444670 :                 ++tmp;
    2161     1444670 :                 if (tmp == end) {
    2162      362694 :                         if (*key == '-') {
    2163          28 :                                 if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
    2164           0 :                                         return 0;
    2165             :                                 }
    2166          28 :                                 *idx = 0 - *idx;
    2167      362666 :                         } else if (*idx > ZEND_LONG_MAX) { /* overflow */
    2168           0 :                                 return 0;
    2169             :                         }
    2170      362694 :                         return 1;
    2171             :                 }
    2172     2163689 :                 if (*tmp <= '9' && *tmp >= '0') {
    2173     1081713 :                         *idx = (*idx * 10) + (*tmp - '0');
    2174             :                 } else {
    2175         263 :                         return 0;
    2176             :                 }
    2177     1081713 :         }
    2178             : }
    2179             : 
    2180             : /*
    2181             :  * Local variables:
    2182             :  * tab-width: 4
    2183             :  * c-basic-offset: 4
    2184             :  * indent-tabs-mode: t
    2185             :  * End:
    2186             :  */

Generated by: LCOV version 1.10

Generated at Tue, 14 Apr 2015 11:48:39 +0000 (3 days ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.