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: 1080 1210 89.3 %
Date: 2016-05-03 Functions: 72 80 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2016 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             :    |          Dmitry Stogov <dmitry@zend.com>                             |
      18             :    +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : #include "zend.h"
      24             : #include "zend_globals.h"
      25             : #include "zend_variables.h"
      26             : 
      27             : #define HT_DEBUG 0
      28             : #if HT_DEBUG
      29             : # define HT_ASSERT(c) ZEND_ASSERT(c)
      30             : #else
      31             : # define HT_ASSERT(c)
      32             : #endif
      33             : 
      34             : #define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
      35             : 
      36             : #if ZEND_DEBUG
      37             : /*
      38             : #define HASH_MASK_CONSISTENCY   0xc0
      39             : */
      40             : #define HT_OK                                   0x00
      41             : #define HT_IS_DESTROYING                0x40
      42             : #define HT_DESTROYED                    0x80
      43             : #define HT_CLEANING                             0xc0
      44             : 
      45             : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
      46             : {
      47             :         if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) {
      48             :                 return;
      49             :         }
      50             :         switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) {
      51             :                 case HT_IS_DESTROYING:
      52             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
      53             :                         break;
      54             :                 case HT_DESTROYED:
      55             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
      56             :                         break;
      57             :                 case HT_CLEANING:
      58             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
      59             :                         break;
      60             :                 default:
      61             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
      62             :                         break;
      63             :         }
      64             :         zend_bailout();
      65             : }
      66             : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
      67             : #define SET_INCONSISTENT(n) do { \
      68             :                 (ht)->u.flags |= n; \
      69             :         } while (0)
      70             : #else
      71             : #define IS_CONSISTENT(a)
      72             : #define SET_INCONSISTENT(n)
      73             : #endif
      74             : 
      75             : #define HASH_PROTECT_RECURSION(ht)                                                                                                              \
      76             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      77             :                 if (((ht)->u.flags & ZEND_HASH_APPLY_COUNT_MASK) >= (3 << 8)) {                                                                                         \
      78             :                         zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");\
      79             :                 }                                                                                                                                                               \
      80             :                 ZEND_HASH_INC_APPLY_COUNT(ht);                                                                                                  \
      81             :         }
      82             : 
      83             : #define HASH_UNPROTECT_RECURSION(ht)                                                                                                    \
      84             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      85             :                 ZEND_HASH_DEC_APPLY_COUNT(ht);                                                                                                  \
      86             :         }
      87             : 
      88             : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht)                         \
      89             :         if ((ht)->nNumUsed >= (ht)->nTableSize) {              \
      90             :                 zend_hash_do_resize(ht);                                        \
      91             :         }
      92             : 
      93             : static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht);
      94             : 
      95             : static uint32_t zend_always_inline zend_hash_check_size(uint32_t nSize)
      96             : {
      97             : #if defined(ZEND_WIN32)
      98             :         unsigned long index;
      99             : #endif
     100             : 
     101             :         /* Use big enough power of 2 */
     102             :         /* size should be between HT_MIN_SIZE and HT_MAX_SIZE */
     103    21857533 :         if (nSize < HT_MIN_SIZE) {
     104     6279131 :                 nSize = HT_MIN_SIZE;
     105    15578402 :         } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) {
     106           0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket));
     107             :         }
     108             : 
     109             : #if defined(ZEND_WIN32)
     110             :         if (BitScanReverse(&index, nSize - 1)) {
     111             :                 return 0x2 << ((31 - index) ^ 0x1f);
     112             :         } else {
     113             :                 /* nSize is ensured to be in the valid range, fall back to it
     114             :                    rather than using an undefined bis scan result. */
     115             :                 return nSize;
     116             :         }
     117             : #elif (defined(__GNUC__) || __has_builtin(__builtin_clz))  && defined(PHP_HAVE_BUILTIN_CLZ)
     118    21857533 :         return 0x2 << (__builtin_clz(nSize - 1) ^ 0x1f);
     119             : #else
     120             :         nSize -= 1;
     121             :         nSize |= (nSize >> 1);
     122             :         nSize |= (nSize >> 2);
     123             :         nSize |= (nSize >> 4);
     124             :         nSize |= (nSize >> 8);
     125             :         nSize |= (nSize >> 16);
     126             :         return nSize + 1;
     127             : #endif
     128             : }
     129             : 
     130             : static void zend_always_inline zend_hash_real_init_ex(HashTable *ht, int packed)
     131             : {
     132             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     133             :         ZEND_ASSERT(!((ht)->u.flags & HASH_FLAG_INITIALIZED));
     134    10788043 :         if (packed) {
     135     2097157 :                 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
     136     2097157 :                 (ht)->u.flags |= HASH_FLAG_INITIALIZED | HASH_FLAG_PACKED;
     137     2097157 :                 HT_HASH_RESET_PACKED(ht);
     138             :         } else {
     139     8690886 :                 (ht)->nTableMask = -(ht)->nTableSize;
     140     8690886 :                 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
     141     8690886 :                 (ht)->u.flags |= HASH_FLAG_INITIALIZED;
     142     8690886 :                 if (EXPECTED(ht->nTableMask == -8)) {
     143     7598709 :                         Bucket *arData = ht->arData;
     144             : 
     145     7598709 :                         HT_HASH_EX(arData, -8) = -1;
     146     7598709 :                         HT_HASH_EX(arData, -7) = -1;
     147     7598709 :                         HT_HASH_EX(arData, -6) = -1;
     148     7598709 :                         HT_HASH_EX(arData, -5) = -1;
     149     7598709 :                         HT_HASH_EX(arData, -4) = -1;
     150     7598709 :                         HT_HASH_EX(arData, -3) = -1;
     151     7598709 :                         HT_HASH_EX(arData, -2) = -1;
     152     7598709 :                         HT_HASH_EX(arData, -1) = -1;
     153             :                 } else {
     154     1092177 :                         HT_HASH_RESET(ht);
     155             :                 }
     156             :         }
     157             : }
     158             : 
     159             : static void zend_always_inline zend_hash_check_init(HashTable *ht, int packed)
     160             : {
     161             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     162    10600725 :         if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
     163             :                 zend_hash_real_init_ex(ht, packed);
     164             :         }
     165             : }
     166             : 
     167             : #define CHECK_INIT(ht, packed) \
     168             :         zend_hash_check_init(ht, packed)
     169             : 
     170             : static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
     171             :         {HT_INVALID_IDX, HT_INVALID_IDX};
     172             : 
     173    20092858 : ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     174             : {
     175    20092858 :         GC_REFCOUNT(ht) = 1;
     176    20092858 :         GC_TYPE_INFO(ht) = IS_ARRAY;
     177    20092858 :         ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
     178    20092858 :         ht->nTableSize = zend_hash_check_size(nSize);
     179    20092858 :         ht->nTableMask = HT_MIN_MASK;
     180    20092858 :         HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
     181    20092858 :         ht->nNumUsed = 0;
     182    20092858 :         ht->nNumOfElements = 0;
     183    20092858 :         ht->nInternalPointer = HT_INVALID_IDX;
     184    20092858 :         ht->nNextFreeElement = 0;
     185    20092858 :         ht->pDestructor = pDestructor;
     186    20092858 : }
     187             : 
     188       38657 : static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
     189             : {
     190             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     191       38657 :         if (ht->nTableSize >= HT_MAX_SIZE) {
     192           0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
     193             :         }
     194             :         HANDLE_BLOCK_INTERRUPTIONS();
     195       38657 :         ht->nTableSize += ht->nTableSize;
     196       38657 :         HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE(ht), HT_USED_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
     197             :         HANDLE_UNBLOCK_INTERRUPTIONS();
     198       38657 : }
     199             : 
     200      187318 : ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed)
     201             : {
     202             :         IS_CONSISTENT(ht);
     203             : 
     204             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     205      187318 :         zend_hash_real_init_ex(ht, packed);
     206      187318 : }
     207             : 
     208       26817 : ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
     209             : {
     210       26817 :         void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
     211       26817 :         Bucket *old_buckets = ht->arData;
     212             : 
     213             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     214             :         HANDLE_BLOCK_INTERRUPTIONS();
     215       26817 :         ht->u.flags &= ~HASH_FLAG_PACKED;
     216       26817 :         new_data = pemalloc(HT_SIZE_EX(ht->nTableSize, -ht->nTableSize), (ht)->u.flags & HASH_FLAG_PERSISTENT);
     217       26817 :         ht->nTableMask = -ht->nTableSize;
     218       26817 :         HT_SET_DATA_ADDR(ht, new_data);
     219       26817 :         memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     220       26817 :         pefree(old_data, (ht)->u.flags & HASH_FLAG_PERSISTENT);
     221       26817 :         zend_hash_rehash(ht);
     222             :         HANDLE_UNBLOCK_INTERRUPTIONS();
     223       26817 : }
     224             : 
     225          15 : ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
     226             : {
     227          15 :         void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
     228          15 :         Bucket *old_buckets = ht->arData;
     229             : 
     230             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     231             :         HANDLE_BLOCK_INTERRUPTIONS();
     232          15 :         new_data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), (ht)->u.flags & HASH_FLAG_PERSISTENT);
     233          15 :         ht->u.flags |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
     234          15 :         ht->nTableMask = HT_MIN_MASK;
     235          15 :         HT_SET_DATA_ADDR(ht, new_data);
     236          15 :         HT_HASH_RESET_PACKED(ht);
     237          15 :         memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     238          15 :         pefree(old_data, (ht)->u.flags & HASH_FLAG_PERSISTENT);
     239             :         HANDLE_UNBLOCK_INTERRUPTIONS();
     240          15 : }
     241             : 
     242    13304882 : ZEND_API void ZEND_FASTCALL _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC)
     243             : {
     244    13304882 :         _zend_hash_init(ht, nSize, pDestructor, persistent ZEND_FILE_LINE_RELAY_CC);
     245    13304882 :         if (!bApplyProtection) {
     246    13304882 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     247             :         }
     248    13304882 : }
     249             : 
     250     2989975 : ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, zend_bool packed)
     251             : {
     252             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     253     2989975 :         if (nSize == 0) return;
     254     2847810 :         if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
     255     1696346 :                 if (nSize > ht->nTableSize) {
     256      814676 :                         ht->nTableSize = zend_hash_check_size(nSize);
     257             :                 }
     258     1696346 :                 zend_hash_check_init(ht, packed);
     259             :         } else {
     260     1151464 :                 if (packed) {
     261             :                         ZEND_ASSERT(ht->u.flags & HASH_FLAG_PACKED);
     262           0 :                         if (nSize > ht->nTableSize) {
     263             :                                 HANDLE_BLOCK_INTERRUPTIONS();
     264           0 :                                 ht->nTableSize = zend_hash_check_size(nSize);
     265           0 :                                 HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE(ht), HT_USED_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
     266             :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     267             :                         }
     268             :                 } else {
     269             :                         ZEND_ASSERT(!(ht->u.flags & HASH_FLAG_PACKED));
     270     1151464 :                         if (nSize > ht->nTableSize) {
     271      949999 :                                 void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
     272      949999 :                                 Bucket *old_buckets = ht->arData;
     273      949999 :                                 nSize = zend_hash_check_size(nSize);
     274             :                                 HANDLE_BLOCK_INTERRUPTIONS();
     275      949999 :                                 new_data = pemalloc(HT_SIZE_EX(nSize, -nSize), ht->u.flags & HASH_FLAG_PERSISTENT);
     276      949999 :                                 ht->nTableSize = nSize;
     277      949999 :                                 ht->nTableMask = -ht->nTableSize;
     278      949999 :                                 HT_SET_DATA_ADDR(ht, new_data);
     279      949999 :                                 memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     280      949999 :                                 pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT);
     281      949999 :                                 zend_hash_rehash(ht);
     282             :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     283             :                         }
     284             :                 }
     285             :         }
     286             : }
     287             : 
     288          43 : static uint32_t zend_array_recalc_elements(HashTable *ht)
     289             : {
     290             :        zval *val;
     291          43 :        uint32_t num = ht->nNumOfElements;
     292             : 
     293         357 :            ZEND_HASH_FOREACH_VAL(ht, val) {
     294         157 :                    if (Z_TYPE_P(val) == IS_UNDEF) continue;
     295         157 :                    if (Z_TYPE_P(val) == IS_INDIRECT) {
     296         228 :                            if (UNEXPECTED(Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF)) {
     297          53 :                                    num--;
     298             :                            }
     299             :                    }
     300             :        } ZEND_HASH_FOREACH_END();
     301          43 :        return num;
     302             : }
     303             : /* }}} */
     304             : 
     305      264006 : ZEND_API uint32_t zend_array_count(HashTable *ht)
     306             : {
     307             :         uint32_t num;
     308      264006 :         if (UNEXPECTED(ht->u.v.flags & HASH_FLAG_HAS_EMPTY_IND)) {
     309          40 :                 num = zend_array_recalc_elements(ht);
     310          40 :                 if (UNEXPECTED(ht->nNumOfElements == num)) {
     311           0 :                         ht->u.v.flags &= ~HASH_FLAG_HAS_EMPTY_IND;
     312             :                 }
     313      263966 :         } else if (UNEXPECTED(ht == &EG(symbol_table))) {
     314           3 :                 num = zend_array_recalc_elements(ht);
     315             :         } else {
     316      263963 :                 num = zend_hash_num_elements(ht);
     317             :         }
     318      264006 :         return num;
     319             : }
     320             : /* }}} */
     321             : 
     322           0 : ZEND_API void ZEND_FASTCALL zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
     323             : {
     324           0 :         if (bApplyProtection) {
     325           0 :                 ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
     326             :         } else {
     327           0 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     328             :         }
     329           0 : }
     330             : 
     331      200711 : ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
     332             : {
     333      200711 :         HashTableIterator *iter = EG(ht_iterators);
     334      200711 :         HashTableIterator *end  = iter + EG(ht_iterators_count);
     335             :         uint32_t idx;
     336             : 
     337      200711 :         if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     338      200711 :                 ht->u.v.nIteratorsCount++;
     339             :         }
     340      401841 :         while (iter != end) {
     341      201130 :                 if (iter->ht == NULL) {
     342      200711 :                         iter->ht = ht;
     343      200711 :                         iter->pos = pos;
     344      200711 :                         idx = iter - EG(ht_iterators);
     345      200711 :                         if (idx + 1 > EG(ht_iterators_used)) {
     346      200708 :                                 EG(ht_iterators_used) = idx + 1;
     347             :                         }
     348      200711 :                         return idx;
     349             :                 }
     350         419 :                 iter++;
     351             :         }
     352           0 :         if (EG(ht_iterators) == EG(ht_iterators_slots)) {
     353           0 :                 EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
     354           0 :                 memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
     355             :         } else {
     356           0 :                 EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
     357             :         }
     358           0 :         iter = EG(ht_iterators) + EG(ht_iterators_count);
     359           0 :         EG(ht_iterators_count) += 8;
     360           0 :         iter->ht = ht;
     361           0 :         iter->pos = pos;
     362           0 :         memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
     363           0 :         idx = iter - EG(ht_iterators);
     364           0 :         EG(ht_iterators_used) = idx + 1;
     365           0 :         return idx;
     366             : }
     367             : 
     368         382 : ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
     369             : {
     370         382 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     371             : 
     372             :         ZEND_ASSERT(idx != (uint32_t)-1);
     373         382 :         if (iter->pos == HT_INVALID_IDX) {
     374          69 :                 return HT_INVALID_IDX;
     375         313 :         } else if (UNEXPECTED(iter->ht != ht)) {
     376           0 :                 if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
     377           0 :                                 && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     378           0 :                         iter->ht->u.v.nIteratorsCount--;
     379             :                 }
     380           0 :                 if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     381           0 :                         ht->u.v.nIteratorsCount++;
     382             :                 }
     383           0 :                 iter->ht = ht;
     384           0 :                 iter->pos = ht->nInternalPointer;
     385             :         }
     386         313 :         return iter->pos;
     387             : }
     388             : 
     389        1036 : ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array)
     390             : {
     391        1036 :         HashTable *ht = Z_ARRVAL_P(array);
     392        1036 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     393             : 
     394             :         ZEND_ASSERT(idx != (uint32_t)-1);
     395        1036 :         if (iter->pos == HT_INVALID_IDX) {
     396         109 :                 return HT_INVALID_IDX;
     397         927 :         } else if (UNEXPECTED(iter->ht != ht)) {
     398           2 :                 if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
     399           1 :                                 && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     400           0 :                         iter->ht->u.v.nIteratorsCount--;
     401             :                 }
     402           1 :                 SEPARATE_ARRAY(array);
     403           1 :                 ht = Z_ARRVAL_P(array);
     404           1 :                 if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     405           1 :                         ht->u.v.nIteratorsCount++;
     406             :                 }
     407           1 :                 iter->ht = ht;
     408           1 :                 iter->pos = ht->nInternalPointer;
     409             :         }
     410         927 :         return iter->pos;
     411             : }
     412             : 
     413      200711 : ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
     414             : {
     415      200711 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     416             : 
     417             :         ZEND_ASSERT(idx != (uint32_t)-1);
     418             : 
     419      602128 :         if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
     420      401417 :                         && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     421      200706 :                 iter->ht->u.v.nIteratorsCount--;
     422             :         }
     423      200711 :         iter->ht = NULL;
     424             : 
     425      200711 :         if (idx == EG(ht_iterators_used) - 1) {
     426      401388 :                 while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
     427          28 :                         idx--;
     428             :                 }
     429      200680 :                 EG(ht_iterators_used) = idx;
     430             :         }
     431      200711 : }
     432             : 
     433          25 : static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(HashTable *ht)
     434             : {
     435          25 :         HashTableIterator *iter = EG(ht_iterators);
     436          25 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     437             : 
     438          63 :         while (iter != end) {
     439          13 :                 if (iter->ht == ht) {
     440           6 :                         iter->ht = HT_POISONED_PTR;
     441             :                 }
     442          13 :                 iter++;
     443             :         }
     444          25 : }
     445             : 
     446             : static zend_always_inline void zend_hash_iterators_remove(HashTable *ht)
     447             : {
     448    11826067 :         if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
     449          25 :                 _zend_hash_iterators_remove(ht);
     450             :         }
     451             : }
     452             : 
     453         200 : ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start)
     454             : {
     455         200 :         HashTableIterator *iter = EG(ht_iterators);
     456         200 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     457         200 :         HashPosition res = HT_INVALID_IDX;
     458             : 
     459         490 :         while (iter != end) {
     460          90 :                 if (iter->ht == ht) {
     461          90 :                         if (iter->pos >= start && iter->pos < res) {
     462          48 :                                 res = iter->pos;
     463             :                         }
     464             :                 }
     465          90 :                 iter++;
     466             :         }
     467         200 :         return res;
     468             : }
     469             : 
     470         233 : ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
     471             : {
     472         233 :         HashTableIterator *iter = EG(ht_iterators);
     473         233 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     474             : 
     475         725 :         while (iter != end) {
     476         259 :                 if (iter->ht == ht && iter->pos == from) {
     477          73 :                         iter->pos = to;
     478             :                 }
     479         259 :                 iter++;
     480             :         }
     481         233 : }
     482             : 
     483             : static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
     484             : {
     485             :         zend_ulong h;
     486             :         uint32_t nIndex;
     487             :         uint32_t idx;
     488             :         Bucket *p, *arData;
     489             : 
     490   262133209 :         h = zend_string_hash_val(key);
     491   262133209 :         arData = ht->arData;
     492   262133209 :         nIndex = h | ht->nTableMask;
     493   262133209 :         idx = HT_HASH_EX(arData, nIndex);
     494   413554923 :         while (EXPECTED(idx != HT_INVALID_IDX)) {
     495   166256487 :                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
     496   166256487 :                 if (EXPECTED(p->key == key)) { /* check for the same interned string */
     497     9676190 :                         return p;
     498   172062520 :                 } else if (EXPECTED(p->h == h) &&
     499     5160741 :                      EXPECTED(p->key) &&
     500     5160741 :                      EXPECTED(ZSTR_LEN(p->key) == ZSTR_LEN(key)) &&
     501     5160741 :                      EXPECTED(memcmp(ZSTR_VAL(p->key), ZSTR_VAL(key), ZSTR_LEN(key)) == 0)) {
     502     5158583 :                         return p;
     503             :                 }
     504   151421714 :                 idx = Z_NEXT(p->val);
     505             :         }
     506   247298436 :         return NULL;
     507             : }
     508             : 
     509             : static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
     510             : {
     511             :         uint32_t nIndex;
     512             :         uint32_t idx;
     513             :         Bucket *p, *arData;
     514             : 
     515     3301318 :         arData = ht->arData;
     516     3301318 :         nIndex = h | ht->nTableMask;
     517     3301318 :         idx = HT_HASH_EX(arData, nIndex);
     518     3956917 :         while (idx != HT_INVALID_IDX) {
     519             :                 ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
     520     3158892 :                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
     521    10668822 :                 if ((p->h == h)
     522             :                          && p->key
     523     5006620 :                          && (ZSTR_LEN(p->key) == len)
     524     2503310 :                          && !memcmp(ZSTR_VAL(p->key), str, len)) {
     525     2503293 :                         return p;
     526             :                 }
     527      655599 :                 idx = Z_NEXT(p->val);
     528             :         }
     529      798025 :         return NULL;
     530             : }
     531             : 
     532             : static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
     533             : {
     534             :         uint32_t nIndex;
     535             :         uint32_t idx;
     536             :         Bucket *p, *arData;
     537             : 
     538     4477017 :         arData = ht->arData;
     539     4477017 :         nIndex = h | ht->nTableMask;
     540     4477017 :         idx = HT_HASH_EX(arData, nIndex);
     541     6000712 :         while (idx != HT_INVALID_IDX) {
     542             :                 ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
     543     2557208 :                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
     544     2557208 :                 if (p->h == h && !p->key) {
     545     1033513 :                         return p;
     546             :                 }
     547     1523695 :                 idx = Z_NEXT(p->val);
     548             :         }
     549     3443504 :         return NULL;
     550             : }
     551             : 
     552             : 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)
     553             : {
     554             :         zend_ulong h;
     555             :         uint32_t nIndex;
     556             :         uint32_t idx;
     557             :         Bucket *p;
     558             : 
     559             :         IS_CONSISTENT(ht);
     560             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     561             : 
     562   209416662 :         if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
     563             :                 CHECK_INIT(ht, 0);
     564             :                 goto add_to_hash;
     565   202608441 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     566       24987 :                 zend_hash_packed_to_hash(ht);
     567   202583454 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     568   200088872 :                 p = zend_hash_find_bucket(ht, key);
     569             : 
     570   200088872 :                 if (p) {
     571             :                         zval *data;
     572             : 
     573      561401 :                         if (flag & HASH_ADD) {
     574      283043 :                                 return NULL;
     575             :                         }
     576             :                         ZEND_ASSERT(&p->val != pData);
     577      278358 :                         data = &p->val;
     578      334994 :                         if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
     579         286 :                                 data = Z_INDIRECT_P(data);
     580             :                         }
     581             :                         HANDLE_BLOCK_INTERRUPTIONS();
     582      278358 :                         if (ht->pDestructor) {
     583      232810 :                                 ht->pDestructor(data);
     584             :                         }
     585      278358 :                         ZVAL_COPY_VALUE(data, pData);
     586             :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     587      278358 :                         return data;
     588             :                 }
     589             :         }
     590             : 
     591   202047040 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     592             : 
     593             : add_to_hash:
     594             :         HANDLE_BLOCK_INTERRUPTIONS();
     595   208855261 :         idx = ht->nNumUsed++;
     596   208855261 :         ht->nNumOfElements++;
     597   208855261 :         if (ht->nInternalPointer == HT_INVALID_IDX) {
     598     6997246 :                 ht->nInternalPointer = idx;
     599             :         }
     600             :         zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
     601   208855261 :         p = ht->arData + idx;
     602   208855261 :         p->key = key;
     603   208855261 :         if (!ZSTR_IS_INTERNED(key)) {
     604             :                 zend_string_addref(key);
     605   113217183 :                 ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
     606             :                 zend_string_hash_val(key);
     607             :         }
     608   208855261 :         p->h = h = ZSTR_H(key);
     609   208855261 :         ZVAL_COPY_VALUE(&p->val, pData);
     610   208855261 :         nIndex = h | ht->nTableMask;
     611   208855261 :         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     612   208855261 :         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
     613             :         HANDLE_UNBLOCK_INTERRUPTIONS();
     614             : 
     615   208855261 :         return &p->val;
     616             : }
     617             : 
     618     3299198 : ZEND_API zval* ZEND_FASTCALL _zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     619             : {
     620     3299198 :         return _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_RELAY_CC);
     621             : }
     622             : 
     623   177488447 : ZEND_API zval* ZEND_FASTCALL _zend_hash_add(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     624             : {
     625   177488447 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     626             : }
     627             : 
     628     8495622 : ZEND_API zval* ZEND_FASTCALL _zend_hash_update(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     629             : {
     630     8495622 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     631             : }
     632             : 
     633         944 : ZEND_API zval* ZEND_FASTCALL _zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     634             : {
     635         944 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC);
     636             : }
     637             : 
     638     2945028 : ZEND_API zval* ZEND_FASTCALL _zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     639             : {
     640     2945028 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     641             : }
     642             : 
     643           0 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     644             : {
     645           0 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     646           0 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_RELAY_CC);
     647             :         zend_string_release(key);
     648           0 :         return ret;
     649             : }
     650             : 
     651     1477267 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     652             : {
     653     2954534 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     654     1477267 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     655             :         zend_string_release(key);
     656     1477267 :         return ret;
     657             : }
     658             : 
     659     1385802 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     660             : {
     661     2771604 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     662     1385802 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC);
     663             :         zend_string_release(key);
     664     1385802 :         return ret;
     665             : }
     666             : 
     667    14321525 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     668             : {
     669    28643050 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     670    14321525 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     671             :         zend_string_release(key);
     672    14321525 :         return ret;
     673             : }
     674             : 
     675        2829 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     676             : {
     677        5658 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     678        2829 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     679             :         zend_string_delref(key);
     680        2829 :         return ret;
     681             : }
     682             : 
     683           0 : ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
     684             : {
     685             :         zval dummy;
     686             : 
     687           0 :         ZVAL_NULL(&dummy);
     688           0 :         return zend_hash_index_add(ht, h, &dummy);
     689             : }
     690             : 
     691       54012 : ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
     692             : {
     693             :         zval dummy;
     694             : 
     695       54012 :         ZVAL_NULL(&dummy);
     696       54012 :         return zend_hash_add(ht, key, &dummy);
     697             : }
     698             : 
     699      554890 : ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
     700             : {
     701             :         zval dummy;
     702             : 
     703      554890 :         ZVAL_NULL(&dummy);
     704      554890 :         return zend_hash_str_add(ht, str, len, &dummy);
     705             : }
     706             : 
     707             : 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)
     708             : {
     709             :         uint32_t nIndex;
     710             :         uint32_t idx;
     711             :         Bucket *p;
     712             : 
     713             :         IS_CONSISTENT(ht);
     714             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     715             : 
     716     8598279 :         if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
     717     2096158 :                 CHECK_INIT(ht, h < ht->nTableSize);
     718     2096158 :                 if (h < ht->nTableSize) {
     719     1993110 :                         p = ht->arData + h;
     720             :                         goto add_to_packed;
     721             :                 }
     722             :                 goto add_to_hash;
     723     6502121 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     724     3801687 :                 if (h < ht->nNumUsed) {
     725        3777 :                         p = ht->arData + h;
     726        7554 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     727        3620 :                                 if (flag & HASH_ADD) {
     728           0 :                                         return NULL;
     729             :                                 }
     730        3620 :                                 if (ht->pDestructor) {
     731        3620 :                                         ht->pDestructor(&p->val);
     732             :                                 }
     733        3620 :                                 ZVAL_COPY_VALUE(&p->val, pData);
     734        3620 :                                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     735           0 :                                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     736             :                                 }
     737        3620 :                                 return &p->val;
     738             :                         } else { /* we have to keep the order :( */
     739             :                                 goto convert_to_hash;
     740             :                         }
     741     3797910 :                 } else if (EXPECTED(h < ht->nTableSize)) {
     742     3757825 :                         p = ht->arData + h;
     743       80094 :                 } else if ((h >> 1) < ht->nTableSize &&
     744       40009 :                            (ht->nTableSize >> 1) < ht->nNumOfElements) {
     745       38657 :                         zend_hash_packed_grow(ht);
     746       38657 :                         p = ht->arData + h;
     747             :                 } else {
     748             :                         goto convert_to_hash;
     749             :                 }
     750             : 
     751             : add_to_packed:
     752             :                 HANDLE_BLOCK_INTERRUPTIONS();
     753             :                 /* incremental initialization of empty Buckets */
     754     5789592 :                 if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) == (HASH_ADD_NEW|HASH_ADD_NEXT)) {
     755     1218375 :                         ht->nNumUsed = h + 1;
     756     4571217 :                 } else if (h >= ht->nNumUsed) {
     757     4571217 :                         if (h > ht->nNumUsed) {
     758      973475 :                                 Bucket *q = ht->arData + ht->nNumUsed;
     759     1955513 :                                 while (q != p) {
     760      982038 :                                         ZVAL_UNDEF(&q->val);
     761      982038 :                                         q++;
     762             :                                 }
     763             :                         }
     764     4571217 :                         ht->nNumUsed = h + 1;
     765             :                 }
     766     5789592 :                 ht->nNumOfElements++;
     767     5789592 :                 if (ht->nInternalPointer == HT_INVALID_IDX) {
     768     2045394 :                         ht->nInternalPointer = h;
     769             :                 }
     770     5789592 :                 zend_hash_iterators_update(ht, HT_INVALID_IDX, h);
     771     5789592 :                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     772     5737410 :                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     773             :                 }
     774     5789592 :                 p->h = h;
     775     5789592 :                 p->key = NULL;
     776     5789592 :                 ZVAL_COPY_VALUE(&p->val, pData);
     777             : 
     778             :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     779             : 
     780     5789592 :                 return &p->val;
     781             : 
     782             : convert_to_hash:
     783        1585 :                 zend_hash_packed_to_hash(ht);
     784     2700434 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     785     1610141 :                 p = zend_hash_index_find_bucket(ht, h);
     786     1610141 :                 if (p) {
     787       10408 :                         if (flag & HASH_ADD) {
     788         158 :                                 return NULL;
     789             :                         }
     790             :                         ZEND_ASSERT(&p->val != pData);
     791             :                         HANDLE_BLOCK_INTERRUPTIONS();
     792       10250 :                         if (ht->pDestructor) {
     793       10205 :                                 ht->pDestructor(&p->val);
     794             :                         }
     795       10250 :                         ZVAL_COPY_VALUE(&p->val, pData);
     796             :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     797       10250 :                         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     798           1 :                                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     799             :                         }
     800       10250 :                         return &p->val;
     801             :                 }
     802             :         }
     803             : 
     804     2691611 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     805             : 
     806             : add_to_hash:
     807             :         HANDLE_BLOCK_INTERRUPTIONS();
     808     2794659 :         idx = ht->nNumUsed++;
     809     2794659 :         ht->nNumOfElements++;
     810     2794659 :         if (ht->nInternalPointer == HT_INVALID_IDX) {
     811      261585 :                 ht->nInternalPointer = idx;
     812             :         }
     813             :         zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
     814     2794659 :         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     815     1214148 :                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     816             :         }
     817     2794659 :         p = ht->arData + idx;
     818     2794659 :         p->h = h;
     819     2794659 :         p->key = NULL;
     820     2794659 :         nIndex = h | ht->nTableMask;
     821     2794659 :         ZVAL_COPY_VALUE(&p->val, pData);
     822     2794659 :         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     823     2794659 :         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
     824             :         HANDLE_UNBLOCK_INTERRUPTIONS();
     825             : 
     826     2794659 :         return &p->val;
     827             : }
     828             : 
     829           0 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     830             : {
     831           0 :         return _zend_hash_index_add_or_update_i(ht, h, pData, flag ZEND_FILE_LINE_RELAY_CC);
     832             : }
     833             : 
     834         522 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     835             : {
     836         522 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     837             : }
     838             : 
     839     1533838 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     840             : {
     841     1533838 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     842             : }
     843             : 
     844     2838330 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     845             : {
     846     2838330 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     847             : }
     848             : 
     849     3006685 : ZEND_API zval* ZEND_FASTCALL _zend_hash_next_index_insert(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     850             : {
     851     6013370 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     852             : }
     853             : 
     854     1218904 : ZEND_API zval* ZEND_FASTCALL _zend_hash_next_index_insert_new(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     855             : {
     856     2437808 :         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);
     857             : }
     858             : 
     859     5071780 : static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
     860             : {
     861             : 
     862             :         IS_CONSISTENT(ht);
     863             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     864             : 
     865     5071780 :         if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */
     866             :                 HANDLE_BLOCK_INTERRUPTIONS();
     867      125569 :                 zend_hash_rehash(ht);
     868             :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     869     4946211 :         } else if (ht->nTableSize < HT_MAX_SIZE) {        /* Let's double the table size */
     870     4946211 :                 void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
     871     4946211 :                 uint32_t nSize = ht->nTableSize + ht->nTableSize;
     872     4946211 :                 Bucket *old_buckets = ht->arData;
     873             : 
     874             :                 HANDLE_BLOCK_INTERRUPTIONS();
     875     4946211 :                 new_data = pemalloc(HT_SIZE_EX(nSize, -nSize), ht->u.flags & HASH_FLAG_PERSISTENT);
     876     4946211 :                 ht->nTableSize = nSize;
     877     4946211 :                 ht->nTableMask = -ht->nTableSize;
     878     4946211 :                 HT_SET_DATA_ADDR(ht, new_data);
     879     4946211 :                 memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     880     4946211 :                 pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT);
     881     4946211 :                 zend_hash_rehash(ht);
     882             :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     883             :         } else {
     884           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));
     885             :         }
     886     5071780 : }
     887             : 
     888     6139887 : ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
     889             : {
     890             :         Bucket *p;
     891             :         uint32_t nIndex, i;
     892             : 
     893             :         IS_CONSISTENT(ht);
     894             : 
     895     6139887 :         if (UNEXPECTED(ht->nNumOfElements == 0)) {
     896           5 :                 if (ht->u.flags & HASH_FLAG_INITIALIZED) {
     897           2 :                         ht->nNumUsed = 0;
     898           2 :                         HT_HASH_RESET(ht);
     899             :                 }
     900           5 :                 return SUCCESS;
     901             :         }
     902             : 
     903     6139882 :         HT_HASH_RESET(ht);
     904     6139882 :         i = 0;
     905     6139882 :         p = ht->arData;
     906     6139882 :         if (ht->nNumUsed == ht->nNumOfElements) {
     907             :                 do {
     908   431564687 :                         nIndex = p->h | ht->nTableMask;
     909   431564687 :                         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     910   431564687 :                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
     911   431564687 :                         p++;
     912   431564687 :                 } while (++i < ht->nNumUsed);
     913             :         } else {
     914             :                 do {
     915     1542792 :                         if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) {
     916      127632 :                                 uint32_t j = i;
     917      127632 :                                 Bucket *q = p;
     918             : 
     919      127632 :                                 if (EXPECTED(ht->u.v.nIteratorsCount == 0)) {
     920      958548 :                                         while (++i < ht->nNumUsed) {
     921      703290 :                                                 p++;
     922      703290 :                                                 if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
     923      520790 :                                                         ZVAL_COPY_VALUE(&q->val, &p->val);
     924      520790 :                                                         q->h = p->h;
     925      520790 :                                                         nIndex = q->h | ht->nTableMask;
     926      520790 :                                                         q->key = p->key;
     927      520790 :                                                         Z_NEXT(q->val) = HT_HASH(ht, nIndex);
     928      520790 :                                                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
     929      520790 :                                                         if (UNEXPECTED(ht->nInternalPointer == i)) {
     930       24762 :                                                                 ht->nInternalPointer = j;
     931             :                                                         }
     932      520790 :                                                         q++;
     933      520790 :                                                         j++;
     934             :                                                 }
     935             :                                         }
     936             :                                 } else {
     937           3 :                                         uint32_t iter_pos = zend_hash_iterators_lower_pos(ht, 0);
     938             : 
     939          27 :                                         while (++i < ht->nNumUsed) {
     940          21 :                                                 p++;
     941          21 :                                                 if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
     942          12 :                                                         ZVAL_COPY_VALUE(&q->val, &p->val);
     943          12 :                                                         q->h = p->h;
     944          12 :                                                         nIndex = q->h | ht->nTableMask;
     945          12 :                                                         q->key = p->key;
     946          12 :                                                         Z_NEXT(q->val) = HT_HASH(ht, nIndex);
     947          12 :                                                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
     948          12 :                                                         if (UNEXPECTED(ht->nInternalPointer == i)) {
     949           3 :                                                                 ht->nInternalPointer = j;
     950             :                                                         }
     951          12 :                                                         if (UNEXPECTED(i == iter_pos)) {
     952             :                                                                 zend_hash_iterators_update(ht, i, j);
     953           5 :                                                                 iter_pos = zend_hash_iterators_lower_pos(ht, iter_pos + 1);
     954             :                                                         }
     955          12 :                                                         q++;
     956          12 :                                                         j++;
     957             :                                                 }
     958             :                                         }
     959             :                                 }
     960      127632 :                                 ht->nNumUsed = j;
     961      127632 :                                 break;
     962             :                         }
     963      643764 :                         nIndex = p->h | ht->nTableMask;
     964      643764 :                         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     965      643764 :                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
     966      643764 :                         p++;
     967      643764 :                 } while (++i < ht->nNumUsed);
     968             :         }
     969     6139882 :         return SUCCESS;
     970             : }
     971             : 
     972             : static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
     973             : {
     974             :         HANDLE_BLOCK_INTERRUPTIONS();
     975    58679124 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     976    58465431 :                 if (prev) {
     977     3527738 :                         Z_NEXT(prev->val) = Z_NEXT(p->val);
     978             :                 } else {
     979    54937693 :                         HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
     980             :                 }
     981             :         }
     982    58679124 :         if (HT_IDX_TO_HASH(ht->nNumUsed - 1) == idx) {
     983             :                 do {
     984     4720708 :                         ht->nNumUsed--;
     985     9112385 :                 } while (ht->nNumUsed > 0 && (UNEXPECTED(Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF)));
     986             :         }
     987    58679124 :         ht->nNumOfElements--;
     988    58679124 :         if (HT_IDX_TO_HASH(ht->nInternalPointer) == idx || UNEXPECTED(ht->u.v.nIteratorsCount)) {
     989             :                 uint32_t new_idx;
     990             : 
     991     3783677 :                 new_idx = idx = HT_HASH_TO_IDX(idx);
     992             :                 while (1) {
     993    51690213 :                         new_idx++;
     994    51690213 :                         if (new_idx >= ht->nNumUsed) {
     995      283876 :                                 new_idx = HT_INVALID_IDX;
     996             :                                 break;
     997   102812674 :                         } else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
     998             :                                 break;
     999             :                         }
    1000             :                 }
    1001     3783677 :                 if (ht->nInternalPointer == idx) {
    1002     3783640 :                         ht->nInternalPointer = new_idx;
    1003             :                 }
    1004             :                 zend_hash_iterators_update(ht, idx, new_idx);
    1005             :         }
    1006    58679124 :         if (p->key) {
    1007    57672873 :                 zend_string_release(p->key);
    1008             :         }
    1009    58679124 :         if (ht->pDestructor) {
    1010             :                 zval tmp;
    1011    57789169 :                 ZVAL_COPY_VALUE(&tmp, &p->val);
    1012    57789169 :                 ZVAL_UNDEF(&p->val);
    1013    57789169 :                 ht->pDestructor(&tmp);
    1014             :         } else {
    1015      889955 :                 ZVAL_UNDEF(&p->val);
    1016             :         }
    1017             :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1018             : }
    1019             : 
    1020             : static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
    1021             : {
    1022     7959914 :         Bucket *prev = NULL;
    1023             : 
    1024     7959914 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1025     7955887 :                 uint32_t nIndex = p->h | ht->nTableMask;
    1026     7955887 :                 uint32_t i = HT_HASH(ht, nIndex);
    1027             : 
    1028     7955887 :                 if (i != idx) {
    1029      367503 :                         prev = HT_HASH_TO_BUCKET(ht, i);
    1030      436492 :                         while (Z_NEXT(prev->val) != idx) {
    1031       68989 :                                 i = Z_NEXT(prev->val);
    1032       68989 :                                 prev = HT_HASH_TO_BUCKET(ht, i);
    1033             :                         }
    1034             :                 }
    1035             :         }
    1036             : 
    1037             :         _zend_hash_del_el_ex(ht, idx, p, prev);
    1038             : }
    1039             : 
    1040          24 : ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p)
    1041             : {
    1042             :         IS_CONSISTENT(ht);
    1043             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1044          24 :         _zend_hash_del_el(ht, HT_IDX_TO_HASH(p - ht->arData), p);
    1045          24 : }
    1046             : 
    1047    49757632 : ZEND_API int ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
    1048             : {
    1049             :         zend_ulong h;
    1050             :         uint32_t nIndex;
    1051             :         uint32_t idx;
    1052             :         Bucket *p;
    1053    49757632 :         Bucket *prev = NULL;
    1054             : 
    1055             :         IS_CONSISTENT(ht);
    1056             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1057             : 
    1058    49757632 :         h = zend_string_hash_val(key);
    1059    49757632 :         nIndex = h | ht->nTableMask;
    1060             : 
    1061    49757632 :         idx = HT_HASH(ht, nIndex);
    1062   102830061 :         while (idx != HT_INVALID_IDX) {
    1063    52241583 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1064   251142186 :                 if ((p->key == key) ||
    1065    52211214 :                         (p->h == h &&
    1066    48896463 :                      p->key &&
    1067    48896463 :                      ZSTR_LEN(p->key) == ZSTR_LEN(key) &&
    1068    48896463 :                      memcmp(ZSTR_VAL(p->key), ZSTR_VAL(key), ZSTR_LEN(key)) == 0)) {
    1069             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1070    48926786 :                         return SUCCESS;
    1071             :                 }
    1072     3314797 :                 prev = p;
    1073     3314797 :                 idx = Z_NEXT(p->val);
    1074             :         }
    1075      830846 :         return FAILURE;
    1076             : }
    1077             : 
    1078         482 : ZEND_API int ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key)
    1079             : {
    1080             :         zend_ulong h;
    1081             :         uint32_t nIndex;
    1082             :         uint32_t idx;
    1083             :         Bucket *p;
    1084         482 :         Bucket *prev = NULL;
    1085             : 
    1086             :         IS_CONSISTENT(ht);
    1087             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1088             : 
    1089         482 :         h = zend_string_hash_val(key);
    1090         482 :         nIndex = h | ht->nTableMask;
    1091             : 
    1092         482 :         idx = HT_HASH(ht, nIndex);
    1093         972 :         while (idx != HT_INVALID_IDX) {
    1094         291 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1095        1275 :                 if ((p->key == key) ||
    1096         252 :                         (p->h == h &&
    1097         244 :                      p->key &&
    1098         244 :                      ZSTR_LEN(p->key) == ZSTR_LEN(key) &&
    1099         244 :                      memcmp(ZSTR_VAL(p->key), ZSTR_VAL(key), ZSTR_LEN(key)) == 0)) {
    1100         566 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
    1101          15 :                                 zval *data = Z_INDIRECT(p->val);
    1102             : 
    1103          15 :                                 if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
    1104           0 :                                         return FAILURE;
    1105             :                                 } else {
    1106          15 :                                         if (ht->pDestructor) {
    1107             :                                                 zval tmp;
    1108          15 :                                                 ZVAL_COPY_VALUE(&tmp, data);
    1109          15 :                                                 ZVAL_UNDEF(data);
    1110          15 :                                                 ht->pDestructor(&tmp);
    1111             :                                         } else {
    1112           0 :                                                 ZVAL_UNDEF(data);
    1113             :                                         }
    1114          15 :                                         ht->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND;
    1115             :                                 }
    1116             :                         } else {
    1117             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
    1118             :                         }
    1119         283 :                         return SUCCESS;
    1120             :                 }
    1121           8 :                 prev = p;
    1122           8 :                 idx = Z_NEXT(p->val);
    1123             :         }
    1124         199 :         return FAILURE;
    1125             : }
    1126             : 
    1127           0 : ZEND_API int ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
    1128             : {
    1129             :         zend_ulong h;
    1130             :         uint32_t nIndex;
    1131             :         uint32_t idx;
    1132             :         Bucket *p;
    1133           0 :         Bucket *prev = NULL;
    1134             : 
    1135             :         IS_CONSISTENT(ht);
    1136             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1137             : 
    1138           0 :         h = zend_inline_hash_func(str, len);
    1139           0 :         nIndex = h | ht->nTableMask;
    1140             : 
    1141           0 :         idx = HT_HASH(ht, nIndex);
    1142           0 :         while (idx != HT_INVALID_IDX) {
    1143           0 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1144           0 :                 if ((p->h == h)
    1145             :                          && p->key
    1146           0 :                          && (ZSTR_LEN(p->key) == len)
    1147           0 :                          && !memcmp(ZSTR_VAL(p->key), str, len)) {
    1148           0 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
    1149           0 :                                 zval *data = Z_INDIRECT(p->val);
    1150             : 
    1151           0 :                                 if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
    1152           0 :                                         return FAILURE;
    1153             :                                 } else {
    1154           0 :                                         if (ht->pDestructor) {
    1155           0 :                                                 ht->pDestructor(data);
    1156             :                                         }
    1157           0 :                                         ZVAL_UNDEF(data);
    1158           0 :                                         ht->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND;
    1159             :                                 }
    1160             :                         } else {
    1161             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
    1162             :                         }
    1163           0 :                         return SUCCESS;
    1164             :                 }
    1165           0 :                 prev = p;
    1166           0 :                 idx = Z_NEXT(p->val);
    1167             :         }
    1168           0 :         return FAILURE;
    1169             : }
    1170             : 
    1171      818232 : ZEND_API int ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
    1172             : {
    1173             :         zend_ulong h;
    1174             :         uint32_t nIndex;
    1175             :         uint32_t idx;
    1176             :         Bucket *p;
    1177      818232 :         Bucket *prev = NULL;
    1178             : 
    1179             :         IS_CONSISTENT(ht);
    1180             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1181             : 
    1182      818232 :         h = zend_inline_hash_func(str, len);
    1183      818232 :         nIndex = h | ht->nTableMask;
    1184             : 
    1185      818232 :         idx = HT_HASH(ht, nIndex);
    1186     1682233 :         while (idx != HT_INVALID_IDX) {
    1187      838397 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1188     3216281 :                 if ((p->h == h)
    1189             :                          && p->key
    1190     1585256 :                          && (ZSTR_LEN(p->key) == len)
    1191      792628 :                          && !memcmp(ZSTR_VAL(p->key), str, len)) {
    1192             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1193      792628 :                         return SUCCESS;
    1194             :                 }
    1195       45769 :                 prev = p;
    1196       45769 :                 idx = Z_NEXT(p->val);
    1197             :         }
    1198       25604 :         return FAILURE;
    1199             : }
    1200             : 
    1201     1010987 : ZEND_API int ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
    1202             : {
    1203             :         uint32_t nIndex;
    1204             :         uint32_t idx;
    1205             :         Bucket *p;
    1206     1010987 :         Bucket *prev = NULL;
    1207             : 
    1208             :         IS_CONSISTENT(ht);
    1209             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1210             : 
    1211     1010987 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1212      215840 :                 if (h < ht->nNumUsed) {
    1213      209675 :                         p = ht->arData + h;
    1214      419350 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1215      209666 :                                 _zend_hash_del_el_ex(ht, HT_IDX_TO_HASH(h), p, NULL);
    1216      209666 :                                 return SUCCESS;
    1217             :                         }
    1218             :                 }
    1219        6174 :                 return FAILURE;
    1220             :         }
    1221      795147 :         nIndex = h | ht->nTableMask;
    1222             : 
    1223      795147 :         idx = HT_HASH(ht, nIndex);
    1224     1591421 :         while (idx != HT_INVALID_IDX) {
    1225      790989 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1226      790989 :                 if ((p->h == h) && (p->key == NULL)) {
    1227             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1228      789862 :                         return SUCCESS;
    1229             :                 }
    1230        1127 :                 prev = p;
    1231        1127 :                 idx = Z_NEXT(p->val);
    1232             :         }
    1233        5285 :         return FAILURE;
    1234             : }
    1235             : 
    1236    11674215 : ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
    1237             : {
    1238             :         Bucket *p, *end;
    1239             : 
    1240             :         IS_CONSISTENT(ht);
    1241             :         HT_ASSERT(GC_REFCOUNT(ht) <= 1);
    1242             : 
    1243    11674215 :         if (ht->nNumUsed) {
    1244     7966588 :                 p = ht->arData;
    1245     7966588 :                 end = p + ht->nNumUsed;
    1246     7966588 :                 if (ht->pDestructor) {
    1247             :                         SET_INCONSISTENT(HT_IS_DESTROYING);
    1248             : 
    1249     7640748 :                         if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
    1250     4699126 :                                 if (ht->nNumUsed == ht->nNumOfElements) {
    1251             :                                         do {
    1252   170458869 :                                                 ht->pDestructor(&p->val);
    1253   170458868 :                                         } while (++p != end);
    1254             :                                 } else {
    1255             :                                         do {
    1256   100604192 :                                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1257     1634790 :                                                         ht->pDestructor(&p->val);
    1258             :                                                 }
    1259    50302096 :                                         } while (++p != end);
    1260             :                                 }
    1261     2941622 :                         } else if (ht->nNumUsed == ht->nNumOfElements) {
    1262             :                                 do {
    1263    98305879 :                                         ht->pDestructor(&p->val);
    1264    98305879 :                                         if (EXPECTED(p->key)) {
    1265    98299511 :                                                 zend_string_release(p->key);
    1266             :                                         }
    1267    98305879 :                                 } while (++p != end);
    1268             :                         } else {
    1269             :                                 do {
    1270    10514344 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1271      294458 :                                                 ht->pDestructor(&p->val);
    1272      294458 :                                                 if (EXPECTED(p->key)) {
    1273      294458 :                                                         zend_string_release(p->key);
    1274             :                                                 }
    1275             :                                         }
    1276     5257172 :                                 } while (++p != end);
    1277             :                         }
    1278             : 
    1279             :                         SET_INCONSISTENT(HT_DESTROYED);
    1280             :                 } else {
    1281      325840 :                         if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) {
    1282             :                                 do {
    1283    20208788 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1284    10013899 :                                                 if (EXPECTED(p->key)) {
    1285    10013265 :                                                         zend_string_release(p->key);
    1286             :                                                 }
    1287             :                                         }
    1288    10104394 :                                 } while (++p != end);
    1289             :                         }
    1290             :                 }
    1291             :                 zend_hash_iterators_remove(ht);
    1292     3707627 :         } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    1293     3633312 :                 return;
    1294             :         }
    1295     8040902 :         pefree(HT_GET_DATA_ADDR(ht), ht->u.flags & HASH_FLAG_PERSISTENT);
    1296             : }
    1297             : 
    1298     6835340 : ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
    1299             : {
    1300             :         Bucket *p, *end;
    1301             : 
    1302             :         IS_CONSISTENT(ht);
    1303             :         HT_ASSERT(GC_REFCOUNT(ht) <= 1);
    1304             : 
    1305             :         /* break possible cycles */
    1306     6835340 :         GC_REMOVE_FROM_BUFFER(ht);
    1307     6835340 :         GC_TYPE_INFO(ht) = IS_NULL | (GC_WHITE << 16);
    1308             : 
    1309     6835340 :         if (ht->nNumUsed) {
    1310             :                 /* In some rare cases destructors of regular arrays may be changed */
    1311     3859555 :                 if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) {
    1312          73 :                         zend_hash_destroy(ht);
    1313          73 :                         goto free_ht;
    1314             :                 }
    1315             : 
    1316     3859482 :                 p = ht->arData;
    1317     3859482 :                 end = p + ht->nNumUsed;
    1318             :                 SET_INCONSISTENT(HT_IS_DESTROYING);
    1319             : 
    1320     3859482 :                 if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
    1321             :                         do {
    1322     9571324 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1323     9571322 :                         } while (++p != end);
    1324      862722 :                 } else if (ht->nNumUsed == ht->nNumOfElements) {
    1325             :                         do {
    1326     5533455 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1327     5533455 :                                 if (EXPECTED(p->key)) {
    1328     5457064 :                                         zend_string_release(p->key);
    1329             :                                 }
    1330     5533455 :                         } while (++p != end);
    1331             :                 } else {
    1332             :                         do {
    1333        4518 :                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1334        1959 :                                         i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1335        1959 :                                         if (EXPECTED(p->key)) {
    1336        1900 :                                                 zend_string_release(p->key);
    1337             :                                         }
    1338             :                                 }
    1339        2259 :                         } while (++p != end);
    1340             :                 }
    1341             :                 zend_hash_iterators_remove(ht);
    1342             :                 SET_INCONSISTENT(HT_DESTROYED);
    1343     2975785 :         } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    1344     2973336 :                 goto free_ht;
    1345             :         }
    1346     3861929 :         efree(HT_GET_DATA_ADDR(ht));
    1347             : free_ht:
    1348     6835338 :         FREE_HASHTABLE(ht);
    1349     6835338 : }
    1350             : 
    1351       54452 : ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
    1352             : {
    1353             :         Bucket *p, *end;
    1354             : 
    1355             :         IS_CONSISTENT(ht);
    1356             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1357             : 
    1358       54452 :         if (ht->nNumUsed) {
    1359        8851 :                 p = ht->arData;
    1360        8851 :                 end = p + ht->nNumUsed;
    1361        8851 :                 if (ht->pDestructor) {
    1362        3827 :                         if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
    1363        1006 :                                 if (ht->nNumUsed == ht->nNumOfElements) {
    1364             :                                         do {
    1365      555365 :                                                 ht->pDestructor(&p->val);
    1366      555365 :                                         } while (++p != end);
    1367             :                                 } else {
    1368             :                                         do {
    1369          78 :                                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1370           9 :                                                         ht->pDestructor(&p->val);
    1371             :                                                 }
    1372          39 :                                         } while (++p != end);
    1373             :                                 }
    1374        2821 :                         } else if (ht->nNumUsed == ht->nNumOfElements) {
    1375             :                                 do {
    1376     1313471 :                                         ht->pDestructor(&p->val);
    1377     1313471 :                                         if (EXPECTED(p->key)) {
    1378     1313471 :                                                 zend_string_release(p->key);
    1379             :                                         }
    1380     1313471 :                                 } while (++p != end);
    1381             :                         } else {
    1382             :                                 do {
    1383           0 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1384           0 :                                                 ht->pDestructor(&p->val);
    1385           0 :                                                 if (EXPECTED(p->key)) {
    1386           0 :                                                         zend_string_release(p->key);
    1387             :                                                 }
    1388             :                                         }
    1389           0 :                                 } while (++p != end);
    1390             :                         }
    1391             :                 } else {
    1392        5024 :                         if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) {
    1393        4590 :                                 if (ht->nNumUsed == ht->nNumOfElements) {
    1394             :                                         do {
    1395       27555 :                                                 if (EXPECTED(p->key)) {
    1396       27555 :                                                         zend_string_release(p->key);
    1397             :                                                 }
    1398       27555 :                                         } while (++p != end);
    1399             :                                 } else {
    1400             :                                         do {
    1401           0 :                                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1402           0 :                                                         if (EXPECTED(p->key)) {
    1403           0 :                                                                 zend_string_release(p->key);
    1404             :                                                         }
    1405             :                                                 }
    1406           0 :                                         } while (++p != end);
    1407             :                                 }
    1408             :                         }
    1409             :                 }
    1410        8851 :                 if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1411        8835 :                         HT_HASH_RESET(ht);
    1412             :                 }
    1413             :         }
    1414       54452 :         ht->nNumUsed = 0;
    1415       54452 :         ht->nNumOfElements = 0;
    1416       54452 :         ht->nNextFreeElement = 0;
    1417       54452 :         ht->nInternalPointer = HT_INVALID_IDX;
    1418       54452 : }
    1419             : 
    1420       87798 : ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
    1421             : {
    1422             :         Bucket *p, *end;
    1423             : 
    1424             :         IS_CONSISTENT(ht);
    1425             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1426             : 
    1427       87798 :         if (ht->nNumUsed) {
    1428       87790 :                 p = ht->arData;
    1429       87790 :                 end = p + ht->nNumUsed;
    1430       87790 :                 if (ht->u.flags & HASH_FLAG_STATIC_KEYS) {
    1431             :                         do {
    1432      176755 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1433      176755 :                         } while (++p != end);
    1434          79 :                 } else if (ht->nNumUsed == ht->nNumOfElements) {
    1435             :                         do {
    1436         563 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1437         563 :                                 zend_string_release(p->key);
    1438         563 :                         } while (++p != end);
    1439             :                 } else {
    1440             :                         do {
    1441           0 :                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1442           0 :                                         i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1443           0 :                                         zend_string_release(p->key);
    1444             :                                 }
    1445           0 :                         } while (++p != end);
    1446             :                 }
    1447       87790 :                 HT_HASH_RESET(ht);
    1448             :         }
    1449       87798 :         ht->nNumUsed = 0;
    1450       87798 :         ht->nNumOfElements = 0;
    1451       87798 :         ht->nNextFreeElement = 0;
    1452       87798 :         ht->nInternalPointer = HT_INVALID_IDX;
    1453       87798 : }
    1454             : 
    1455           0 : ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht)
    1456             : {
    1457             :         uint32_t idx;
    1458             :         Bucket *p;
    1459             : 
    1460             :         IS_CONSISTENT(ht);
    1461             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1462             : 
    1463           0 :         p = ht->arData;
    1464           0 :         for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
    1465           0 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1466             :                 _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1467             :         }
    1468           0 :         if (ht->u.flags & HASH_FLAG_INITIALIZED) {
    1469           0 :                 pefree(HT_GET_DATA_ADDR(ht), ht->u.flags & HASH_FLAG_PERSISTENT);
    1470             :         }
    1471             : 
    1472             :         SET_INCONSISTENT(HT_DESTROYED);
    1473           0 : }
    1474             : 
    1475       90526 : ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht)
    1476             : {
    1477             :         uint32_t idx;
    1478             :         Bucket *p;
    1479             : 
    1480             :         IS_CONSISTENT(ht);
    1481             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1482             : 
    1483       90526 :         idx = ht->nNumUsed;
    1484       90526 :         p = ht->arData + ht->nNumUsed;
    1485     2023945 :         while (idx > 0) {
    1486     1842893 :                 idx--;
    1487     1842893 :                 p--;
    1488     3685786 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1489             :                 _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1490             :         }
    1491             : 
    1492       90526 :         if (ht->u.flags & HASH_FLAG_INITIALIZED) {
    1493       68438 :                 pefree(HT_GET_DATA_ADDR(ht), ht->u.flags & HASH_FLAG_PERSISTENT);
    1494             :         }
    1495             : 
    1496             :         SET_INCONSISTENT(HT_DESTROYED);
    1497       90526 : }
    1498             : 
    1499             : /* This is used to recurse elements and selectively delete certain entries
    1500             :  * from a hashtable. apply_func() receives the data and decides if the entry
    1501             :  * should be deleted or recursion should be stopped. The following three
    1502             :  * return codes are possible:
    1503             :  * ZEND_HASH_APPLY_KEEP   - continue
    1504             :  * ZEND_HASH_APPLY_STOP   - stop iteration
    1505             :  * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
    1506             :  */
    1507             : 
    1508      351204 : ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func)
    1509             : {
    1510             :         uint32_t idx;
    1511             :         Bucket *p;
    1512             :         int result;
    1513             : 
    1514             :         IS_CONSISTENT(ht);
    1515             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1516             : 
    1517      351204 :         HASH_PROTECT_RECURSION(ht);
    1518     2753399 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1519     2402200 :                 p = ht->arData + idx;
    1520     4804400 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1521     2177707 :                 result = apply_func(&p->val);
    1522             : 
    1523     2177702 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1524             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1525             :                 }
    1526     2177702 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1527           0 :                         break;
    1528             :                 }
    1529             :         }
    1530      351199 :         HASH_UNPROTECT_RECURSION(ht);
    1531      351199 : }
    1532             : 
    1533             : 
    1534      647658 : ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
    1535             : {
    1536             :     uint32_t idx;
    1537             :         Bucket *p;
    1538             :         int result;
    1539             : 
    1540             :         IS_CONSISTENT(ht);
    1541             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1542             : 
    1543      647658 :         HASH_PROTECT_RECURSION(ht);
    1544   143559070 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1545   142915591 :                 p = ht->arData + idx;
    1546   285831182 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1547   103152861 :                 result = apply_func(&p->val, argument);
    1548             : 
    1549   103152861 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1550             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1551             :                 }
    1552   103152861 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1553        4179 :                         break;
    1554             :                 }
    1555             :         }
    1556      647658 :         HASH_UNPROTECT_RECURSION(ht);
    1557      647658 : }
    1558             : 
    1559             : 
    1560         176 : ZEND_API void ZEND_FASTCALL zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int num_args, ...)
    1561             : {
    1562             :         uint32_t idx;
    1563             :         Bucket *p;
    1564             :         va_list args;
    1565             :         zend_hash_key hash_key;
    1566             :         int result;
    1567             : 
    1568             :         IS_CONSISTENT(ht);
    1569             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1570             : 
    1571         176 :         HASH_PROTECT_RECURSION(ht);
    1572             : 
    1573      162122 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1574      161946 :                 p = ht->arData + idx;
    1575      323892 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1576      161880 :                 va_start(args, num_args);
    1577      161880 :                 hash_key.h = p->h;
    1578      161880 :                 hash_key.key = p->key;
    1579             : 
    1580      161880 :                 result = apply_func(&p->val, num_args, args, &hash_key);
    1581             : 
    1582      161880 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1583             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1584             :                 }
    1585      161880 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1586           0 :                         va_end(args);
    1587           0 :                         break;
    1588             :                 }
    1589      161880 :                 va_end(args);
    1590             :         }
    1591             : 
    1592         176 :         HASH_UNPROTECT_RECURSION(ht);
    1593         176 : }
    1594             : 
    1595             : 
    1596      118168 : ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func)
    1597             : {
    1598             :         uint32_t idx;
    1599             :         Bucket *p;
    1600             :         int result;
    1601             : 
    1602             :         IS_CONSISTENT(ht);
    1603             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1604             : 
    1605      118168 :         HASH_PROTECT_RECURSION(ht);
    1606      118168 :         idx = ht->nNumUsed;
    1607      758021 :         while (idx > 0) {
    1608      589422 :                 idx--;
    1609      589422 :                 p = ht->arData + idx;
    1610     1178844 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1611             : 
    1612      537318 :                 result = apply_func(&p->val);
    1613             : 
    1614      537318 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1615             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1616             :                 }
    1617      537318 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1618       67737 :                         break;
    1619             :                 }
    1620             :         }
    1621      118168 :         HASH_UNPROTECT_RECURSION(ht);
    1622      118168 : }
    1623             : 
    1624             : 
    1625         471 : ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
    1626             : {
    1627             :     uint32_t idx;
    1628             :         Bucket *p;
    1629             :         zval *new_entry, *data;
    1630             :         zend_bool setTargetPointer;
    1631             : 
    1632             :         IS_CONSISTENT(source);
    1633             :         IS_CONSISTENT(target);
    1634             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1635             : 
    1636         471 :         setTargetPointer = (target->nInternalPointer == HT_INVALID_IDX);
    1637       11977 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1638       11506 :                 p = source->arData + idx;
    1639       23012 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1640             : 
    1641       11506 :                 if (setTargetPointer && source->nInternalPointer == idx) {
    1642         327 :                         target->nInternalPointer = HT_INVALID_IDX;
    1643             :                 }
    1644             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1645       11506 :                 data = &p->val;
    1646       11506 :                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1647         103 :                         data = Z_INDIRECT_P(data);
    1648         103 :                         if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
    1649           4 :                                 continue;
    1650             :                         }
    1651             :                 }
    1652       11502 :                 if (p->key) {
    1653       11411 :                         new_entry = zend_hash_update(target, p->key, data);
    1654             :                 } else {
    1655          91 :                         new_entry = zend_hash_index_update(target, p->h, data);
    1656             :                 }
    1657       11502 :                 if (pCopyConstructor) {
    1658         282 :                         pCopyConstructor(new_entry);
    1659             :                 }
    1660             :         }
    1661         471 :         if (target->nInternalPointer == HT_INVALID_IDX && target->nNumOfElements > 0) {
    1662           0 :                 idx = 0;
    1663           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1664           0 :                         idx++;
    1665             :                 }
    1666           0 :                 target->nInternalPointer = idx;
    1667             :         }
    1668         471 : }
    1669             : 
    1670             : 
    1671             : static zend_always_inline int zend_array_dup_element(HashTable *source, HashTable *target, uint32_t idx, Bucket *p, Bucket *q, int packed, int static_keys, int with_holes)
    1672             : {
    1673     3718586 :         zval *data = &p->val;
    1674             : 
    1675     3718586 :         if (with_holes) {
    1676     2653135 :                 if (!packed && Z_TYPE_INFO_P(data) == IS_INDIRECT) {
    1677           0 :                         data = Z_INDIRECT_P(data);
    1678             :                 }
    1679     2653135 :                 if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
    1680      883548 :                         return 0;
    1681             :                 }
    1682     1065451 :         } else if (!packed) {
    1683             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1684      746780 :                 if (Z_TYPE_INFO_P(data) == IS_INDIRECT) {
    1685       18169 :                         data = Z_INDIRECT_P(data);
    1686       18169 :                         if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
    1687        2893 :                                 return 0;
    1688             :                         }
    1689             :                 }
    1690             :         }
    1691             : 
    1692             :         do {
    1693     2832145 :                 if (Z_OPT_REFCOUNTED_P(data)) {
    1694     2643795 :                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1 &&
    1695          61 :                             (Z_TYPE_P(Z_REFVAL_P(data)) != IS_ARRAY ||
    1696          18 :                               Z_ARRVAL_P(Z_REFVAL_P(data)) != source)) {
    1697          58 :                                 data = Z_REFVAL_P(data);
    1698          58 :                                 if (!Z_OPT_REFCOUNTED_P(data)) {
    1699             :                                         break;
    1700             :                                 }
    1701             :                         }
    1702             :                         Z_ADDREF_P(data);
    1703             :                 }
    1704             :         } while (0);
    1705     2832145 :         ZVAL_COPY_VALUE(&q->val, data);
    1706             : 
    1707     2832145 :         q->h = p->h;
    1708     2832145 :         if (packed) {
    1709     2088238 :                 q->key = NULL;
    1710             :         } else {
    1711             :                 uint32_t nIndex;
    1712             : 
    1713      743907 :                 q->key = p->key;
    1714      743907 :                 if (!static_keys && q->key) {
    1715      738002 :                         zend_string_addref(q->key);
    1716             :                 }
    1717             : 
    1718      743907 :                 nIndex = q->h | target->nTableMask;
    1719      743907 :                 Z_NEXT(q->val) = HT_HASH(target, nIndex);
    1720      743907 :                 HT_HASH(target, nIndex) = HT_IDX_TO_HASH(idx);
    1721             :         }
    1722     2832145 :         return 1;
    1723             : }
    1724             : 
    1725             : static zend_always_inline void zend_array_dup_packed_elements(HashTable *source, HashTable *target, int with_holes)
    1726             : {
    1727     1088659 :         Bucket *p = source->arData;
    1728     1088659 :         Bucket *q = target->arData;
    1729     1088659 :         Bucket *end = p + source->nNumUsed;
    1730             : 
    1731             :         do {
    1732     2971782 :                 if (!zend_array_dup_element(source, target, 0, p, q, 1, 1, with_holes)) {
    1733      883544 :                         if (with_holes) {
    1734      883544 :                                 ZVAL_UNDEF(&q->val);
    1735             :                         }
    1736             :                 }
    1737     2971782 :                 p++; q++;
    1738     2971782 :         } while (p != end);
    1739             : }
    1740             : 
    1741             : static zend_always_inline uint32_t zend_array_dup_elements(HashTable *source, HashTable *target, int static_keys, int with_holes)
    1742             : {
    1743       60426 :     uint32_t idx = 0;
    1744       60426 :         Bucket *p = source->arData;
    1745       60426 :         Bucket *q = target->arData;
    1746       60426 :         Bucket *end = p + source->nNumUsed;
    1747             : 
    1748             :         do {
    1749      735812 :                 if (!zend_array_dup_element(source, target, idx, p, q, 0, static_keys, with_holes)) {
    1750        1916 :                         uint32_t target_idx = idx;
    1751             : 
    1752        1916 :                         idx++; p++;
    1753       12908 :                         while (p != end) {
    1754       10992 :                                 if (zend_array_dup_element(source, target, target_idx, p, q, 0, static_keys, with_holes)) {
    1755       10011 :                                         if (source->nInternalPointer == idx) {
    1756           0 :                                                 target->nInternalPointer = target_idx;
    1757             :                                         }
    1758       10011 :                                         target_idx++; q++;
    1759             :                                 }
    1760       10992 :                                 idx++; p++;
    1761             :                         }
    1762        1916 :                         return target_idx;
    1763             :                 }
    1764      733896 :                 idx++; p++; q++;
    1765      733896 :         } while (p != end);
    1766       58510 :         return idx;
    1767             : }
    1768             : 
    1769     1773221 : ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
    1770             : {
    1771             :     uint32_t idx;
    1772             :         HashTable *target;
    1773             : 
    1774             :         IS_CONSISTENT(source);
    1775             : 
    1776     1773221 :         ALLOC_HASHTABLE(target);
    1777     1773221 :         GC_REFCOUNT(target) = 1;
    1778     1773221 :         GC_TYPE_INFO(target) = IS_ARRAY;
    1779             : 
    1780     1773221 :         target->nTableSize = source->nTableSize;
    1781     1773221 :         target->pDestructor = source->pDestructor;
    1782             : 
    1783     1773221 :         if (source->nNumUsed == 0) {
    1784      624121 :                 target->u.flags = (source->u.flags & ~(HASH_FLAG_INITIALIZED|HASH_FLAG_PACKED|HASH_FLAG_PERSISTENT)) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
    1785      624121 :                 target->nTableMask = HT_MIN_MASK;
    1786      624121 :                 target->nNumUsed = 0;
    1787      624121 :                 target->nNumOfElements = 0;
    1788      624121 :                 target->nNextFreeElement = 0;
    1789      624121 :                 target->nInternalPointer = HT_INVALID_IDX;
    1790      624121 :                 HT_SET_DATA_ADDR(target, &uninitialized_bucket);
    1791     1149100 :         } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
    1792          15 :                 target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1793          15 :                 target->nTableMask = source->nTableMask;
    1794          15 :                 target->nNumUsed = source->nNumUsed;
    1795          15 :                 target->nNumOfElements = source->nNumOfElements;
    1796          15 :                 target->nNextFreeElement = source->nNextFreeElement;
    1797          15 :                 HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
    1798          15 :                 target->nInternalPointer = source->nInternalPointer;
    1799          15 :                 memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source));
    1800          30 :                 if (target->nNumOfElements > 0 &&
    1801          15 :                     target->nInternalPointer == HT_INVALID_IDX) {
    1802           0 :                         idx = 0;
    1803           0 :                         while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1804           0 :                                 idx++;
    1805             :                         }
    1806           0 :                         target->nInternalPointer = idx;
    1807             :                 }
    1808     1149085 :         } else if (source->u.flags & HASH_FLAG_PACKED) {
    1809     1088659 :                 target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1810     1088659 :                 target->nTableMask = source->nTableMask;
    1811     1088659 :                 target->nNumUsed = source->nNumUsed;
    1812     1088659 :                 target->nNumOfElements = source->nNumOfElements;
    1813     1088659 :                 target->nNextFreeElement = source->nNextFreeElement;
    1814     1088659 :                 HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
    1815     1088659 :                 target->nInternalPointer = source->nInternalPointer;
    1816     1088659 :                 HT_HASH_RESET_PACKED(target);
    1817             : 
    1818     1088659 :                 if (target->nNumUsed == target->nNumOfElements) {
    1819             :                         zend_array_dup_packed_elements(source, target, 0);
    1820             :                 } else {
    1821             :                         zend_array_dup_packed_elements(source, target, 1);
    1822             :                 }
    1823     2177318 :                 if (target->nNumOfElements > 0 &&
    1824     1088659 :                     target->nInternalPointer == HT_INVALID_IDX) {
    1825           8 :                         idx = 0;
    1826          26 :                         while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1827           1 :                                 idx++;
    1828             :                         }
    1829           8 :                         target->nInternalPointer = idx;
    1830             :                 }
    1831             :         } else {
    1832       60426 :                 target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1833       60426 :                 target->nTableMask = source->nTableMask;
    1834       60426 :                 target->nNextFreeElement = source->nNextFreeElement;
    1835       60426 :                 target->nInternalPointer = HT_INVALID_IDX;
    1836       60426 :                 HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
    1837       60426 :                 HT_HASH_RESET(target);
    1838             : 
    1839       60426 :                 if (target->u.flags & HASH_FLAG_STATIC_KEYS) {
    1840         927 :                         if (source->nNumUsed == source->nNumOfElements) {
    1841         927 :                                 idx = zend_array_dup_elements(source, target, 1, 0);
    1842             :                         } else {
    1843           0 :                                 idx = zend_array_dup_elements(source, target, 1, 1);
    1844             :                         }
    1845             :                 } else {
    1846       59499 :                         if (source->nNumUsed == source->nNumOfElements) {
    1847       59496 :                                 idx = zend_array_dup_elements(source, target, 0, 0);
    1848             :                         } else {
    1849           3 :                                 idx = zend_array_dup_elements(source, target, 0, 1);
    1850             :                         }
    1851             :                 }
    1852       60426 :                 target->nNumUsed = idx;
    1853       60426 :                 target->nNumOfElements = idx;
    1854       60426 :                 if (idx > 0 && target->nInternalPointer == HT_INVALID_IDX) {
    1855       60415 :                         target->nInternalPointer = 0;
    1856             :                 }
    1857             :         }
    1858     1773221 :         return target;
    1859             : }
    1860             : 
    1861             : 
    1862      203376 : ZEND_API void ZEND_FASTCALL _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite ZEND_FILE_LINE_DC)
    1863             : {
    1864             :     uint32_t idx;
    1865             :         Bucket *p;
    1866             :         zval *t;
    1867      203376 :         uint32_t mode = (overwrite?HASH_UPDATE:HASH_ADD);
    1868             : 
    1869             :         IS_CONSISTENT(source);
    1870             :         IS_CONSISTENT(target);
    1871             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1872             : 
    1873     3502628 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1874     3299252 :                 p = source->arData + idx;
    1875     6598504 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1876     3299252 :                 if (p->key) {
    1877     3299198 :                         t = _zend_hash_add_or_update(target, p->key, &p->val, mode ZEND_FILE_LINE_RELAY_CC);
    1878     3299198 :                         if (t && pCopyConstructor) {
    1879     3298616 :                                 pCopyConstructor(t);
    1880             :                         }
    1881             :                 } else {
    1882          54 :                         if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h))) {
    1883          26 :                                 t = zend_hash_index_update(target, p->h, &p->val);
    1884          26 :                                 if (t && pCopyConstructor) {
    1885          26 :                                         pCopyConstructor(t);
    1886             :                                 }
    1887             :                         }
    1888             :                 }
    1889             :         }
    1890      203376 :         if (target->nNumOfElements > 0) {
    1891      203373 :                 idx = 0;
    1892      610119 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1893           0 :                         idx++;
    1894             :                 }
    1895      203373 :                 target->nInternalPointer = idx;
    1896             :         }
    1897      203376 : }
    1898             : 
    1899             : 
    1900           0 : static zend_bool ZEND_FASTCALL zend_hash_replace_checker_wrapper(HashTable *target, zval *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
    1901             : {
    1902             :         zend_hash_key hash_key;
    1903             : 
    1904           0 :         hash_key.h = p->h;
    1905           0 :         hash_key.key = p->key;
    1906           0 :         return merge_checker_func(target, source_data, &hash_key, pParam);
    1907             : }
    1908             : 
    1909             : 
    1910           0 : ZEND_API void ZEND_FASTCALL zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam)
    1911             : {
    1912             :         uint32_t idx;
    1913             :         Bucket *p;
    1914             :         zval *t;
    1915             : 
    1916             :         IS_CONSISTENT(source);
    1917             :         IS_CONSISTENT(target);
    1918             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1919             : 
    1920           0 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1921           0 :                 p = source->arData + idx;
    1922           0 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1923           0 :                 if (zend_hash_replace_checker_wrapper(target, &p->val, p, pParam, pMergeSource)) {
    1924           0 :                         t = zend_hash_update(target, p->key, &p->val);
    1925           0 :                         if (t && pCopyConstructor) {
    1926           0 :                                 pCopyConstructor(t);
    1927             :                         }
    1928             :                 }
    1929             :         }
    1930           0 :         if (target->nNumOfElements > 0) {
    1931           0 :                 idx = 0;
    1932           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1933           0 :                         idx++;
    1934             :                 }
    1935           0 :                 target->nInternalPointer = idx;
    1936             :         }
    1937           0 : }
    1938             : 
    1939             : 
    1940             : /* Returns the hash table data if found and NULL if not. */
    1941    61817065 : ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
    1942             : {
    1943             :         Bucket *p;
    1944             : 
    1945             :         IS_CONSISTENT(ht);
    1946             : 
    1947    61817065 :         p = zend_hash_find_bucket(ht, key);
    1948    61817065 :         return p ? &p->val : NULL;
    1949             : }
    1950             : 
    1951     2294245 : ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
    1952             : {
    1953             :         zend_ulong h;
    1954             :         Bucket *p;
    1955             : 
    1956             :         IS_CONSISTENT(ht);
    1957             : 
    1958     2294245 :         h = zend_inline_hash_func(str, len);
    1959     2294245 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1960     2294245 :         return p ? &p->val : NULL;
    1961             : }
    1962             : 
    1963      227272 : ZEND_API zend_bool ZEND_FASTCALL zend_hash_exists(const HashTable *ht, zend_string *key)
    1964             : {
    1965             :         Bucket *p;
    1966             : 
    1967             :         IS_CONSISTENT(ht);
    1968             : 
    1969      227272 :         p = zend_hash_find_bucket(ht, key);
    1970      227272 :         return p ? 1 : 0;
    1971             : }
    1972             : 
    1973     1007073 : ZEND_API zend_bool ZEND_FASTCALL zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
    1974             : {
    1975             :         zend_ulong h;
    1976             :         Bucket *p;
    1977             : 
    1978             :         IS_CONSISTENT(ht);
    1979             : 
    1980     1007073 :         h = zend_inline_hash_func(str, len);
    1981     1007073 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1982     1007073 :         return p ? 1 : 0;
    1983             : }
    1984             : 
    1985     7525876 : ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
    1986             : {
    1987             :         Bucket *p;
    1988             : 
    1989             :         IS_CONSISTENT(ht);
    1990             : 
    1991     7525876 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1992     6330782 :                 if (h < ht->nNumUsed) {
    1993     6067890 :                         p = ht->arData + h;
    1994    12135780 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1995     6067540 :                                 return &p->val;
    1996             :                         }
    1997             :                 }
    1998      263242 :                 return NULL;
    1999             :         }
    2000             : 
    2001     1195094 :         p = zend_hash_index_find_bucket(ht, h);
    2002     1195094 :         return p ? &p->val : NULL;
    2003             : }
    2004             : 
    2005             : 
    2006     1672892 : ZEND_API zend_bool ZEND_FASTCALL zend_hash_index_exists(const HashTable *ht, zend_ulong h)
    2007             : {
    2008             :         Bucket *p;
    2009             : 
    2010             :         IS_CONSISTENT(ht);
    2011             : 
    2012     1672892 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    2013        1110 :                 if (h < ht->nNumUsed) {
    2014         158 :                         if (Z_TYPE(ht->arData[h].val) != IS_UNDEF) {
    2015          72 :                                 return 1;
    2016             :                         }
    2017             :                 }
    2018        1038 :                 return 0;
    2019             :         }
    2020             : 
    2021     1671782 :         p = zend_hash_index_find_bucket(ht, h);
    2022     1671782 :         return p ? 1 : 0;
    2023             : }
    2024             : 
    2025             : 
    2026      219380 : ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
    2027             : {
    2028             :     uint32_t idx;
    2029             : 
    2030             :         IS_CONSISTENT(ht);
    2031             :         HT_ASSERT(&ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
    2032             : 
    2033      220021 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    2034       39698 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    2035       19208 :                         *pos = idx;
    2036       19208 :                         return;
    2037             :                 }
    2038             :         }
    2039      200172 :         *pos = HT_INVALID_IDX;
    2040             : }
    2041             : 
    2042             : 
    2043             : /* This function will be extremely optimized by remembering
    2044             :  * the end of the list
    2045             :  */
    2046          47 : ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
    2047             : {
    2048             :         uint32_t idx;
    2049             : 
    2050             :         IS_CONSISTENT(ht);
    2051             :         HT_ASSERT(&ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
    2052             : 
    2053          47 :         idx = ht->nNumUsed;
    2054          94 :         while (idx > 0) {
    2055          45 :                 idx--;
    2056          90 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    2057          45 :                         *pos = idx;
    2058          45 :                         return;
    2059             :                 }
    2060             :         }
    2061           2 :         *pos = HT_INVALID_IDX;
    2062             : }
    2063             : 
    2064             : 
    2065       68679 : ZEND_API int ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
    2066             : {
    2067       68679 :         uint32_t idx = *pos;
    2068             : 
    2069             :         IS_CONSISTENT(ht);
    2070             :         HT_ASSERT(&ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
    2071             : 
    2072       68679 :         if (idx != HT_INVALID_IDX) {
    2073             :                 while (1) {
    2074       68713 :                         idx++;
    2075       68713 :                         if (idx >= ht->nNumUsed) {
    2076       16330 :                                 *pos = HT_INVALID_IDX;
    2077       16330 :                                 return SUCCESS;
    2078             :                         }
    2079      104766 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    2080       52314 :                                 *pos = idx;
    2081       52314 :                                 return SUCCESS;
    2082             :                         }
    2083          69 :                 }
    2084             :         } else {
    2085          35 :                 return FAILURE;
    2086             :         }
    2087             : }
    2088             : 
    2089          21 : ZEND_API int ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
    2090             : {
    2091          21 :         uint32_t idx = *pos;
    2092             : 
    2093             :         IS_CONSISTENT(ht);
    2094             :         HT_ASSERT(&ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
    2095             : 
    2096          21 :         if (idx != HT_INVALID_IDX) {
    2097          38 :                 while (idx > 0) {
    2098          14 :                         idx--;
    2099          28 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    2100          14 :                                 *pos = idx;
    2101          14 :                                 return SUCCESS;
    2102             :                         }
    2103             :                 }
    2104           5 :                 *pos = HT_INVALID_IDX;
    2105           5 :                 return SUCCESS;
    2106             :         } else {
    2107           2 :                 return FAILURE;
    2108             :         }
    2109             : }
    2110             : 
    2111             : 
    2112             : /* This function should be made binary safe  */
    2113       13146 : ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, HashPosition *pos)
    2114             : {
    2115       13146 :         uint32_t idx = *pos;
    2116             :         Bucket *p;
    2117             : 
    2118             :         IS_CONSISTENT(ht);
    2119       13146 :         if (idx != HT_INVALID_IDX) {
    2120       12690 :                 p = ht->arData + idx;
    2121       12690 :                 if (p->key) {
    2122       11358 :                         *str_index = p->key;
    2123       11358 :                         return HASH_KEY_IS_STRING;
    2124             :                 } else {
    2125        1332 :                         *num_index = p->h;
    2126        1332 :                         return HASH_KEY_IS_LONG;
    2127             :                 }
    2128             :         }
    2129         456 :         return HASH_KEY_NON_EXISTENT;
    2130             : }
    2131             : 
    2132        3417 : ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
    2133             : {
    2134        3417 :         uint32_t idx = *pos;
    2135             :         Bucket *p;
    2136             : 
    2137             :         IS_CONSISTENT(ht);
    2138        3417 :         if (idx == HT_INVALID_IDX) {
    2139          53 :                 ZVAL_NULL(key);
    2140             :         } else {
    2141        3364 :                 p = ht->arData + idx;
    2142        3364 :                 if (p->key) {
    2143         679 :                         ZVAL_STR_COPY(key, p->key);
    2144             :                 } else {
    2145        2685 :                         ZVAL_LONG(key, p->h);
    2146             :                 }
    2147             :         }
    2148        3417 : }
    2149             : 
    2150      279018 : ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
    2151             : {
    2152      279018 :     uint32_t idx = *pos;
    2153             :         Bucket *p;
    2154             : 
    2155             :         IS_CONSISTENT(ht);
    2156      279018 :         if (idx != HT_INVALID_IDX) {
    2157       63753 :                 p = ht->arData + idx;
    2158       63753 :                 if (p->key) {
    2159       50987 :                         return HASH_KEY_IS_STRING;
    2160             :                 } else {
    2161       12766 :                         return HASH_KEY_IS_LONG;
    2162             :                 }
    2163             :         }
    2164      215265 :         return HASH_KEY_NON_EXISTENT;
    2165             : }
    2166             : 
    2167             : 
    2168       66122 : ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
    2169             : {
    2170       66122 :         uint32_t idx = *pos;
    2171             :         Bucket *p;
    2172             : 
    2173             :         IS_CONSISTENT(ht);
    2174       66122 :         if (idx != HT_INVALID_IDX) {
    2175       65259 :                 p = ht->arData + idx;
    2176       65259 :                 return &p->val;
    2177             :         } else {
    2178         863 :                 return NULL;
    2179             :         }
    2180             : }
    2181             : 
    2182       98877 : ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q)
    2183             : {
    2184             :         zval val;
    2185             :         zend_ulong h;
    2186             :         zend_string *key;
    2187             : 
    2188       98877 :         ZVAL_COPY_VALUE(&val, &p->val);
    2189       98877 :         h = p->h;
    2190       98877 :         key = p->key;
    2191             : 
    2192       98877 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    2193       98877 :         p->h = q->h;
    2194       98877 :         p->key = q->key;
    2195             : 
    2196       98877 :         ZVAL_COPY_VALUE(&q->val, &val);
    2197       98877 :         q->h = h;
    2198       98877 :         q->key = key;
    2199       98877 : }
    2200             : 
    2201       72950 : ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q)
    2202             : {
    2203             :         zval val;
    2204             : 
    2205       72950 :         ZVAL_COPY_VALUE(&val, &p->val);
    2206       72950 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    2207       72950 :         ZVAL_COPY_VALUE(&q->val, &val);
    2208       72950 : }
    2209             : 
    2210        1083 : ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q)
    2211             : {
    2212             :         zval val;
    2213             :         zend_ulong h;
    2214             : 
    2215        1083 :         ZVAL_COPY_VALUE(&val, &p->val);
    2216        1083 :         h = p->h;
    2217             : 
    2218        1083 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    2219        1083 :         p->h = q->h;
    2220             : 
    2221        1083 :         ZVAL_COPY_VALUE(&q->val, &val);
    2222        1083 :         q->h = h;
    2223        1083 : }
    2224             : 
    2225       24311 : ZEND_API int ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, compare_func_t compar, zend_bool renumber)
    2226             : {
    2227             :         Bucket *p;
    2228             :         uint32_t i, j;
    2229             : 
    2230             :         IS_CONSISTENT(ht);
    2231             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    2232             : 
    2233       24311 :         if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
    2234         299 :                 return SUCCESS;
    2235             :         }
    2236             : 
    2237       24012 :         if (ht->nNumUsed == ht->nNumOfElements) {
    2238       23919 :                 i = ht->nNumUsed;
    2239             :         } else {
    2240         679 :                 for (j = 0, i = 0; j < ht->nNumUsed; j++) {
    2241         586 :                         p = ht->arData + j;
    2242        1172 :                         if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    2243         475 :                         if (i != j) {
    2244         459 :                                 ht->arData[i] = *p;
    2245             :                         }
    2246         475 :                         i++;
    2247             :                 }
    2248             :         }
    2249             : 
    2250       47725 :         sort((void *)ht->arData, i, sizeof(Bucket), compar,
    2251             :                         (swap_func_t)(renumber? zend_hash_bucket_renum_swap :
    2252       23713 :                                 ((ht->u.flags & HASH_FLAG_PACKED) ? zend_hash_bucket_packed_swap : zend_hash_bucket_swap)));
    2253             : 
    2254             :         HANDLE_BLOCK_INTERRUPTIONS();
    2255       24011 :         ht->nNumUsed = i;
    2256       24011 :         ht->nInternalPointer = 0;
    2257             : 
    2258       24011 :         if (renumber) {
    2259       16866 :                 for (j = 0; j < i; j++) {
    2260       16568 :                         p = ht->arData + j;
    2261       16568 :                         p->h = j;
    2262       16568 :                         if (p->key) {
    2263         232 :                                 zend_string_release(p->key);
    2264         232 :                                 p->key = NULL;
    2265             :                         }
    2266             :                 }
    2267             : 
    2268         298 :                 ht->nNextFreeElement = i;
    2269             :         }
    2270       24011 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    2271         497 :                 if (!renumber) {
    2272         245 :                         zend_hash_packed_to_hash(ht);
    2273             :                 }
    2274             :         } else {
    2275       23514 :                 if (renumber) {
    2276          46 :                         void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
    2277          46 :                         Bucket *old_buckets = ht->arData;
    2278             : 
    2279          46 :                         new_data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), (ht->u.flags & HASH_FLAG_PERSISTENT));
    2280          46 :                         ht->u.flags |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
    2281          46 :                         ht->nTableMask = HT_MIN_MASK;
    2282          46 :                         HT_SET_DATA_ADDR(ht, new_data);
    2283          46 :                         memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
    2284          46 :                         pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT & HASH_FLAG_PERSISTENT);
    2285          46 :                         HT_HASH_RESET_PACKED(ht);
    2286             :                 } else {
    2287       23468 :                         zend_hash_rehash(ht);
    2288             :                 }
    2289             :         }
    2290             : 
    2291             :         HANDLE_UNBLOCK_INTERRUPTIONS();
    2292             : 
    2293       24011 :         return SUCCESS;
    2294             : }
    2295             : 
    2296             : static zend_always_inline int zend_hash_compare_impl(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered) {
    2297             :         uint32_t idx1, idx2;
    2298             : 
    2299         918 :         if (ht1->nNumOfElements != ht2->nNumOfElements) {
    2300         307 :                 return ht1->nNumOfElements > ht2->nNumOfElements ? 1 : -1;
    2301             :         }
    2302             : 
    2303        4637 :         for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
    2304        4206 :                 Bucket *p1 = ht1->arData + idx1, *p2;
    2305             :                 zval *pData1, *pData2;
    2306             :                 int result;
    2307             : 
    2308        8412 :                 if (Z_TYPE(p1->val) == IS_UNDEF) continue;
    2309        4189 :                 if (ordered) {
    2310             :                         while (1) {
    2311             :                                 ZEND_ASSERT(idx2 != ht2->nNumUsed);
    2312        1145 :                                 p2 = ht2->arData + idx2;
    2313        2290 :                                 if (Z_TYPE(p2->val) != IS_UNDEF) break;
    2314           1 :                                 idx2++;
    2315             :                         }
    2316        1144 :                         if (p1->key == NULL && p2->key == NULL) { /* numeric indices */
    2317         364 :                                 if (p1->h != p2->h) {
    2318           2 :                                         return p1->h > p2->h ? 1 : -1;
    2319             :                                 }
    2320         780 :                         } else if (p1->key != NULL && p2->key != NULL) { /* string indices */
    2321         779 :                                 if (ZSTR_LEN(p1->key) != ZSTR_LEN(p2->key)) {
    2322           0 :                                         return ZSTR_LEN(p1->key) > ZSTR_LEN(p2->key) ? 1 : -1;
    2323             :                                 }
    2324             : 
    2325         779 :                                 result = memcmp(ZSTR_VAL(p1->key), ZSTR_VAL(p2->key), ZSTR_LEN(p1->key));
    2326         779 :                                 if (result != 0) {
    2327           0 :                                         return result;
    2328             :                                 }
    2329             :                         } else {
    2330             :                                 /* Mixed key types: A string key is considered as larger */
    2331           1 :                                 return p1->key != NULL ? 1 : -1;
    2332             :                         }
    2333        1141 :                         pData2 = &p2->val;
    2334        1141 :                         idx2++;
    2335             :                 } else {
    2336        3045 :                         if (p1->key == NULL) { /* numeric index */
    2337         488 :                                 pData2 = zend_hash_index_find(ht2, p1->h);
    2338         488 :                                 if (pData2 == NULL) {
    2339           2 :                                         return 1;
    2340             :                                 }
    2341             :                         } else { /* string index */
    2342        2557 :                                 pData2 = zend_hash_find(ht2, p1->key);
    2343        2557 :                                 if (pData2 == NULL) {
    2344          11 :                                         return 1;
    2345             :                                 }
    2346             :                         }
    2347             :                 }
    2348             : 
    2349        4173 :                 pData1 = &p1->val;
    2350        4173 :                 if (Z_TYPE_P(pData1) == IS_INDIRECT) {
    2351         129 :                         pData1 = Z_INDIRECT_P(pData1);
    2352             :                 }
    2353        4173 :                 if (Z_TYPE_P(pData2) == IS_INDIRECT) {
    2354         129 :                         pData2 = Z_INDIRECT_P(pData2);
    2355             :                 }
    2356             : 
    2357        4173 :                 if (Z_TYPE_P(pData1) == IS_UNDEF) {
    2358           0 :                         if (Z_TYPE_P(pData2) != IS_UNDEF) {
    2359           0 :                                 return -1;
    2360             :                         }
    2361        4173 :                 } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
    2362           0 :                         return 1;
    2363             :                 } else {
    2364        4173 :                         result = compar(pData1, pData2);
    2365        4173 :                         if (result != 0) {
    2366         164 :                                 return result;
    2367             :                         }
    2368             :                 }
    2369             :         }
    2370             : 
    2371         431 :         return 0;
    2372             : }
    2373             : 
    2374         918 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered)
    2375             : {
    2376             :         int result;
    2377             :         IS_CONSISTENT(ht1);
    2378             :         IS_CONSISTENT(ht2);
    2379             : 
    2380         918 :         HASH_PROTECT_RECURSION(ht1);
    2381         918 :         HASH_PROTECT_RECURSION(ht2);
    2382        1836 :         result = zend_hash_compare_impl(ht1, ht2, compar, ordered);
    2383         918 :         HASH_UNPROTECT_RECURSION(ht1);
    2384         918 :         HASH_UNPROTECT_RECURSION(ht2);
    2385             : 
    2386         918 :         return result;
    2387             : }
    2388             : 
    2389             : 
    2390          82 : ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag)
    2391             : {
    2392             :         uint32_t idx;
    2393             :         Bucket *p, *res;
    2394             : 
    2395             :         IS_CONSISTENT(ht);
    2396             : 
    2397          82 :         if (ht->nNumOfElements == 0 ) {
    2398           4 :                 return NULL;
    2399             :         }
    2400             : 
    2401          78 :         idx = 0;
    2402             :         while (1) {
    2403          78 :                 if (idx == ht->nNumUsed) {
    2404           0 :                         return NULL;
    2405             :                 }
    2406         156 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
    2407           0 :                 idx++;
    2408           0 :         }
    2409          78 :         res = ht->arData + idx;
    2410         376 :         for (; idx < ht->nNumUsed; idx++) {
    2411         298 :                 p = ht->arData + idx;
    2412         596 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    2413             : 
    2414         298 :                 if (flag) {
    2415         229 :                         if (compar(res, p) < 0) { /* max */
    2416          20 :                                 res = p;
    2417             :                         }
    2418             :                 } else {
    2419          69 :                         if (compar(res, p) > 0) { /* min */
    2420           6 :                                 res = p;
    2421             :                         }
    2422             :                 }
    2423             :         }
    2424          78 :         return &res->val;
    2425             : }
    2426             : 
    2427      384077 : ZEND_API int ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
    2428             : {
    2429      384077 :         register const char *tmp = key;
    2430             : 
    2431      384077 :         const char *end = key + length;
    2432             :         ZEND_ASSERT(*end == '\0');
    2433             : 
    2434      384077 :         if (*tmp == '-') {
    2435          59 :                 tmp++;
    2436             :         }
    2437             : 
    2438      748003 :         if ((*tmp == '0' && length > 1) /* numbers with leading zeros */
    2439      363926 :          || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
    2440             :          || (SIZEOF_ZEND_LONG == 4 &&
    2441             :              end - tmp == MAX_LENGTH_OF_LONG - 1 &&
    2442             :              *tmp > '2')) { /* overflow */
    2443       20178 :                 return 0;
    2444             :         }
    2445      363899 :         *idx = (*tmp - '0');
    2446             :         while (1) {
    2447     1447113 :                 ++tmp;
    2448     1447113 :                 if (tmp == end) {
    2449      363532 :                         if (*key == '-') {
    2450          28 :                                 if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
    2451           0 :                                         return 0;
    2452             :                                 }
    2453          28 :                                 *idx = 0 - *idx;
    2454      363504 :                         } else if (*idx > ZEND_LONG_MAX) { /* overflow */
    2455           0 :                                 return 0;
    2456             :                         }
    2457      363532 :                         return 1;
    2458             :                 }
    2459     2166795 :                 if (*tmp <= '9' && *tmp >= '0') {
    2460     1083214 :                         *idx = (*idx * 10) + (*tmp - '0');
    2461             :                 } else {
    2462         367 :                         return 0;
    2463             :                 }
    2464     1083214 :         }
    2465             : }
    2466             : 
    2467             : /*
    2468             :  * Local variables:
    2469             :  * tab-width: 4
    2470             :  * c-basic-offset: 4
    2471             :  * indent-tabs-mode: t
    2472             :  * End:
    2473             :  */

Generated by: LCOV version 1.10

Generated at Wed, 04 May 2016 01:00:46 +0000 (27 hours ago)

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