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: 1068 1203 88.8 %
Date: 2015-05-21 Functions: 69 77 89.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #include "zend.h"
      23             : #include "zend_globals.h"
      24             : #include "zend_variables.h"
      25             : 
      26             : #define HT_DEBUG 0
      27             : #if HT_DEBUG
      28             : # define HT_ASSERT(c) ZEND_ASSERT(c)
      29             : #else
      30             : # define HT_ASSERT(c)
      31             : #endif 
      32             : 
      33             : #if ZEND_DEBUG
      34             : /*
      35             : #define HASH_MASK_CONSISTENCY   0x60
      36             : */
      37             : #define HT_OK                                   0x00
      38             : #define HT_IS_DESTROYING                0x20
      39             : #define HT_DESTROYED                    0x40
      40             : #define HT_CLEANING                             0x60
      41             : 
      42             : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
      43             : {
      44             :         if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) {
      45             :                 return;
      46             :         }
      47             :         switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) {
      48             :                 case HT_IS_DESTROYING:
      49             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
      50             :                         break;
      51             :                 case HT_DESTROYED:
      52             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
      53             :                         break;
      54             :                 case HT_CLEANING:
      55             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
      56             :                         break;
      57             :                 default:
      58             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
      59             :                         break;
      60             :         }
      61             :         zend_bailout();
      62             : }
      63             : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
      64             : #define SET_INCONSISTENT(n) do { \
      65             :                 (ht)->u.flags |= n; \
      66             :         } while (0)
      67             : #else
      68             : #define IS_CONSISTENT(a)
      69             : #define SET_INCONSISTENT(n)
      70             : #endif
      71             : 
      72             : #define HASH_PROTECT_RECURSION(ht)                                                                                                              \
      73             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      74             :                 if ((ht)->u.flags >= (3 << 8)) {                                                                                            \
      75             :                         zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");\
      76             :                 }                                                                                                                                                               \
      77             :                 ZEND_HASH_INC_APPLY_COUNT(ht);                                                                                                  \
      78             :         }
      79             : 
      80             : #define HASH_UNPROTECT_RECURSION(ht)                                                                                                    \
      81             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      82             :                 ZEND_HASH_DEC_APPLY_COUNT(ht);                                                                                                  \
      83             :         }
      84             : 
      85             : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht)                         \
      86             :         if ((ht)->nNumUsed >= (ht)->nTableSize) {              \
      87             :                 zend_hash_do_resize(ht);                                        \
      88             :         }
      89             : 
      90             : static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht);
      91             : 
      92             : static uint32_t zend_always_inline zend_hash_check_size(uint32_t nSize)
      93             : {
      94             : #if defined(ZEND_WIN32)
      95             :         unsigned long index;
      96             : #endif
      97             : 
      98             :         /* Use big enough power of 2 */
      99             :         /* size should be between HT_MIN_SIZE and HT_MAX_SIZE */
     100    19179561 :         nSize = (nSize <= HT_MIN_SIZE ? HT_MIN_SIZE : (nSize >= HT_MAX_SIZE ? HT_MAX_SIZE : nSize));
     101             : 
     102             : #if defined(ZEND_WIN32)
     103             :         if (BitScanReverse(&index, nSize - 1)) {
     104             :                 return 0x2 << ((31 - index) ^ 0x1f);
     105             :         } else {
     106             :                 /* nSize is ensured to be in the valid range, fall back to it
     107             :                    rather than using an undefined bis scan result. */
     108             :                 return nSize;
     109             :         }
     110             : #elif defined(__GNUC__)
     111    19179561 :         return 0x2 << (__builtin_clz(nSize - 1) ^ 0x1f);
     112             : #else
     113             :         nSize -= 1;
     114             :         nSize |= (nSize >> 1);
     115             :         nSize |= (nSize >> 2);
     116             :         nSize |= (nSize >> 4);
     117             :         nSize |= (nSize >> 8);
     118             :         nSize |= (nSize >> 16);
     119             :         return nSize + 1;
     120             : #endif
     121             : }
     122             : 
     123             : static void zend_always_inline zend_hash_real_init_ex(HashTable *ht, int packed)
     124             : {
     125             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     126             :         ZEND_ASSERT(!((ht)->u.flags & HASH_FLAG_INITIALIZED));
     127     9247796 :         if (packed) {
     128     1931330 :                 (ht)->u.flags |= HASH_FLAG_INITIALIZED | HASH_FLAG_PACKED;
     129     3862660 :                 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
     130     1931330 :                 HT_HASH_RESET_PACKED(ht);
     131             :         } else {
     132     7316466 :                 (ht)->u.flags |= HASH_FLAG_INITIALIZED;
     133     7316466 :                 (ht)->nTableMask = -(ht)->nTableSize;
     134    14632932 :                 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
     135     7316466 :                 HT_HASH_RESET(ht);
     136             :         }
     137             : }
     138             : 
     139             : static void zend_always_inline zend_hash_check_init(HashTable *ht, int packed)
     140             : {
     141             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     142     9061661 :         if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
     143             :                 zend_hash_real_init_ex(ht, packed);
     144             :         }
     145             : }
     146             : 
     147             : #define CHECK_INIT(ht, packed) \
     148             :         zend_hash_check_init(ht, packed)
     149             : 
     150             : static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
     151             :         {HT_INVALID_IDX, HT_INVALID_IDX};
     152             : 
     153    17545295 : ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     154             : {
     155    17545295 :         GC_REFCOUNT(ht) = 1;
     156    17545295 :         GC_TYPE_INFO(ht) = IS_ARRAY;
     157    17545295 :         ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
     158    17545295 :         ht->nTableSize = zend_hash_check_size(nSize);
     159    17545295 :         ht->nTableMask = HT_MIN_MASK;
     160    17545295 :         HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
     161    17545295 :         ht->nNumUsed = 0;
     162    17545295 :         ht->nNumOfElements = 0;
     163    17545295 :         ht->nInternalPointer = HT_INVALID_IDX;
     164    17545295 :         ht->nNextFreeElement = 0;
     165    17545295 :         ht->pDestructor = pDestructor;
     166    17545295 : }
     167             : 
     168       15537 : static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
     169             : {
     170             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     171       15537 :         if (ht->nTableSize >= HT_MAX_SIZE) {
     172           0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
     173             :         }
     174       15537 :         HANDLE_BLOCK_INTERRUPTIONS();
     175       15537 :         ht->nTableSize += ht->nTableSize;
     176       31074 :         HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE(ht), HT_USED_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
     177       15537 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     178       15537 : }
     179             : 
     180      186135 : ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed)
     181             : {
     182             :         IS_CONSISTENT(ht);
     183             : 
     184             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     185      186135 :         zend_hash_real_init_ex(ht, packed);
     186      186135 : }
     187             : 
     188       29627 : ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
     189             : {
     190       29627 :         void *old_data = HT_GET_DATA_ADDR(ht);
     191       29627 :         Bucket *old_buckets = ht->arData;
     192             : 
     193             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     194       29627 :         HANDLE_BLOCK_INTERRUPTIONS();
     195       29627 :         ht->u.flags &= ~HASH_FLAG_PACKED;
     196       29627 :         ht->nTableMask = -ht->nTableSize;
     197       59254 :         HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
     198       29627 :         memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     199       29627 :         pefree(old_data, (ht)->u.flags & HASH_FLAG_PERSISTENT);
     200       29627 :         zend_hash_rehash(ht);
     201       29627 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     202       29627 : }
     203             : 
     204          15 : ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
     205             : {
     206          15 :         void *old_data = HT_GET_DATA_ADDR(ht);
     207          15 :         Bucket *old_buckets = ht->arData;
     208             : 
     209             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     210          15 :         HANDLE_BLOCK_INTERRUPTIONS();
     211          15 :         ht->u.flags |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
     212          15 :         ht->nTableMask = HT_MIN_MASK;
     213          30 :         HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
     214          15 :         HT_HASH_RESET_PACKED(ht);
     215          15 :         memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     216          15 :         pefree(old_data, (ht)->u.flags & HASH_FLAG_PERSISTENT);
     217          15 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     218          15 : }
     219             : 
     220    11944504 : 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)
     221             : {
     222    11944504 :         _zend_hash_init(ht, nSize, pDestructor, persistent ZEND_FILE_LINE_CC);
     223    11944504 :         if (!bApplyProtection) {
     224    11944504 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     225             :         }
     226    11944504 : }
     227             : 
     228     2643485 : ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, zend_bool packed)
     229             : {
     230             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     231     2643485 :         if (nSize == 0) return;
     232     2643485 :         if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
     233     1570721 :                 if (nSize > ht->nTableSize) {
     234      754492 :                         ht->nTableSize = zend_hash_check_size(nSize);
     235             :                 }
     236     1570721 :                 zend_hash_check_init(ht, packed);
     237             :         } else {
     238     1072764 :                 if (packed) {
     239             :                         ZEND_ASSERT(ht->u.flags & HASH_FLAG_PACKED);
     240           0 :                         if (nSize > ht->nTableSize) {
     241           0 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     242           0 :                                 ht->nTableSize = zend_hash_check_size(nSize);
     243           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));
     244           0 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     245             :                         }
     246             :                 } else {
     247             :                         ZEND_ASSERT(!(ht->u.flags & HASH_FLAG_PACKED));
     248     1072764 :                         if (nSize > ht->nTableSize) {
     249      879774 :                                 void *old_data = HT_GET_DATA_ADDR(ht);
     250      879774 :                                 Bucket *old_buckets = ht->arData;
     251             : 
     252      879774 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     253      879774 :                                 ht->nTableSize = zend_hash_check_size(nSize);
     254      879774 :                                 ht->nTableMask = -ht->nTableSize;
     255     1759548 :                                 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
     256      879774 :                                 memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     257      879774 :                                 pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT);
     258      879774 :                                 zend_hash_rehash(ht);
     259      879774 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     260             :                         }
     261             :                 }
     262             :         }
     263             : }
     264             : 
     265           0 : ZEND_API void ZEND_FASTCALL zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
     266             : {
     267           0 :         if (bApplyProtection) {
     268           0 :                 ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
     269             :         } else {
     270           0 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     271             :         }
     272           0 : }
     273             : 
     274         684 : ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
     275             : {
     276         684 :         HashTableIterator *iter = EG(ht_iterators);
     277         684 :         HashTableIterator *end  = iter + EG(ht_iterators_count);
     278             :         uint32_t idx;
     279             : 
     280         684 :         if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     281         684 :                 ht->u.v.nIteratorsCount++;
     282             :         }
     283        1814 :         while (iter != end) {
     284        1130 :                 if (iter->ht == NULL) {
     285         684 :                         iter->ht = ht;
     286         684 :                         iter->pos = pos;
     287         684 :                         idx = iter - EG(ht_iterators);
     288         684 :                         if (idx + 1 > EG(ht_iterators_used)) {
     289         670 :                                 EG(ht_iterators_used) = idx + 1;
     290             :                         }
     291         684 :                         return idx;
     292             :                 }
     293         446 :                 iter++;
     294             :         }
     295           0 :         if (EG(ht_iterators) == EG(ht_iterators_slots)) {
     296           0 :                 EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
     297           0 :                 memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
     298             :         } else {
     299           0 :                 EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
     300             :         }
     301           0 :         iter = EG(ht_iterators) + EG(ht_iterators_count);
     302           0 :         EG(ht_iterators_count) += 8;
     303           0 :         iter->ht = ht;
     304           0 :         iter->pos = pos;
     305           0 :         memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
     306           0 :         idx = iter - EG(ht_iterators);
     307           0 :         EG(ht_iterators_used) = idx + 1;
     308           0 :         return idx;
     309             : }
     310             : 
     311        1380 : ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
     312             : {
     313        1380 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     314             : 
     315             :         ZEND_ASSERT(idx != (uint32_t)-1);
     316        1380 :         if (iter->pos == HT_INVALID_IDX) {
     317         173 :                 return HT_INVALID_IDX;
     318        1207 :         } else if (UNEXPECTED(iter->ht != ht)) {
     319           0 :                 if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     320           0 :                         iter->ht->u.v.nIteratorsCount--;
     321             :                 }
     322           0 :                 if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
     323           0 :                         ht->u.v.nIteratorsCount++;
     324             :                 }
     325           0 :                 iter->ht = ht;
     326           0 :                 iter->pos = ht->nInternalPointer;
     327             :         }
     328        1207 :         return iter->pos;
     329             : }
     330             : 
     331         183 : ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
     332             : {
     333         183 :         HashTableIterator *iter = EG(ht_iterators) + idx;
     334             : 
     335             :         ZEND_ASSERT(idx != (uint32_t)-1);
     336             : 
     337         183 :         if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
     338         183 :                 iter->ht->u.v.nIteratorsCount--;
     339             :         }
     340         183 :         iter->ht = NULL;
     341             : 
     342         183 :         if (idx == EG(ht_iterators_used) - 1) {
     343         366 :                 while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
     344           0 :                         idx--;
     345             :                 }
     346         183 :                 EG(ht_iterators_used) = idx;
     347             :         }
     348         183 : }
     349             : 
     350         483 : static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(HashTable *ht)
     351             : {
     352         483 :         HashTableIterator *iter = EG(ht_iterators);
     353         483 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     354             :         uint32_t idx;
     355             : 
     356        1919 :         while (iter != end) {
     357         953 :                 if (iter->ht == ht) {
     358         493 :                         iter->ht = NULL;
     359             :                 }
     360         953 :                 iter++;
     361             :         }
     362             : 
     363         483 :         idx = EG(ht_iterators_used);
     364        1442 :         while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
     365         476 :                 idx--;
     366             :         }
     367         483 :         EG(ht_iterators_used) = idx;
     368         483 : }
     369             : 
     370             : static zend_always_inline void zend_hash_iterators_remove(HashTable *ht)
     371             : {
     372    10243147 :         if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
     373         483 :                 _zend_hash_iterators_remove(ht);
     374             :         }
     375             : }
     376             : 
     377         200 : ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start)
     378             : {
     379         200 :         HashTableIterator *iter = EG(ht_iterators);
     380         200 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     381         200 :         HashPosition res = HT_INVALID_IDX;
     382             : 
     383         490 :         while (iter != end) {
     384          90 :                 if (iter->ht == ht) {
     385          90 :                         if (iter->pos >= start && iter->pos < res) {
     386          48 :                                 res = iter->pos;
     387             :                         }
     388             :                 }
     389          90 :                 iter++;
     390             :         }
     391         200 :         return res;
     392             : }
     393             : 
     394         237 : ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
     395             : {
     396         237 :         HashTableIterator *iter = EG(ht_iterators);
     397         237 :         HashTableIterator *end  = iter + EG(ht_iterators_used);
     398             : 
     399         739 :         while (iter != end) {
     400         265 :                 if (iter->ht == ht && iter->pos == from) {
     401          77 :                         iter->pos = to;
     402             :                 }
     403         265 :                 iter++;
     404             :         }
     405         237 : }
     406             : 
     407             : static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
     408             : {
     409             :         zend_ulong h;
     410             :         uint32_t nIndex;
     411             :         uint32_t idx;
     412             :         Bucket *p, *arData;
     413             : 
     414   234088636 :         h = zend_string_hash_val(key);
     415   234088636 :         arData = ht->arData;
     416   234088636 :         nIndex = h | ht->nTableMask;
     417   234088636 :         idx = HT_HASH_EX(arData, nIndex);
     418   369824151 :         while (EXPECTED(idx != HT_INVALID_IDX)) {
     419   149142839 :                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
     420   149142839 :                 if (EXPECTED(p->key == key)) { /* check for the same interned string */
     421     8780477 :                         return p;
     422   154249494 :                 } else if (EXPECTED(p->h == h) &&
     423     4629044 :                      EXPECTED(p->key) &&
     424     4629044 :                      EXPECTED(p->key->len == key->len) &&
     425     4629044 :                      EXPECTED(memcmp(p->key->val, key->val, key->len) == 0)) {
     426     4626847 :                         return p;
     427             :                 }
     428   135735515 :                 idx = Z_NEXT(p->val);
     429             :         }
     430   220681312 :         return NULL;
     431             : }
     432             : 
     433             : static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
     434             : {
     435             :         uint32_t nIndex;
     436             :         uint32_t idx;
     437             :         Bucket *p, *arData;
     438             : 
     439     2863872 :         arData = ht->arData;
     440     2863872 :         nIndex = h | ht->nTableMask;
     441     2863872 :         idx = HT_HASH_EX(arData, nIndex);
     442     3537699 :         while (idx != HT_INVALID_IDX) {
     443             :                 ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
     444     2807838 :                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
     445     9209922 :                 if ((p->h == h)
     446             :                          && p->key
     447     4268056 :                          && (p->key->len == len)
     448     2134028 :                          && !memcmp(p->key->val, str, len)) {
     449     2134011 :                         return p;
     450             :                 }
     451      673827 :                 idx = Z_NEXT(p->val);
     452             :         }
     453      729861 :         return NULL;
     454             : }
     455             : 
     456             : static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
     457             : {
     458             :         uint32_t nIndex;
     459             :         uint32_t idx;
     460             :         Bucket *p, *arData;
     461             : 
     462     4041214 :         arData = ht->arData;
     463     4041214 :         nIndex = h | ht->nTableMask;
     464     4041214 :         idx = HT_HASH_EX(arData, nIndex);
     465     5479034 :         while (idx != HT_INVALID_IDX) {
     466             :                 ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
     467     2459747 :                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
     468     2459747 :                 if (p->h == h && !p->key) {
     469     1021927 :                         return p;
     470             :                 }
     471     1437820 :                 idx = Z_NEXT(p->val);
     472             :         }
     473     3019287 :         return NULL;
     474             : }
     475             : 
     476             : 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)
     477             : {
     478             :         zend_ulong h;
     479             :         uint32_t nIndex;
     480             :         uint32_t idx;
     481             :         Bucket *p;
     482             : 
     483             :         IS_CONSISTENT(ht);
     484             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     485             : 
     486   186100944 :         if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
     487             :                 CHECK_INIT(ht, 0);
     488             :                 goto add_to_hash;
     489   180539653 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     490       28062 :                 zend_hash_packed_to_hash(ht);
     491   180511591 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     492   178194086 :                 p = zend_hash_find_bucket(ht, key);
     493             : 
     494   178194086 :                 if (p) {
     495             :                         zval *data;
     496             : 
     497      562550 :                         if (flag & HASH_ADD) {
     498      264521 :                                 return NULL;
     499             :                         }
     500             :                         ZEND_ASSERT(&p->val != pData);
     501      298029 :                         data = &p->val;
     502      351961 :                         if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
     503         263 :                                 data = Z_INDIRECT_P(data);
     504             :                         }
     505      298029 :                         HANDLE_BLOCK_INTERRUPTIONS();
     506      298029 :                         if (ht->pDestructor) {
     507      255823 :                                 ht->pDestructor(data);
     508             :                         }
     509      298029 :                         ZVAL_COPY_VALUE(data, pData);
     510      298029 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     511      298029 :                         return data;
     512             :                 }
     513             :         }
     514             : 
     515   179977103 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     516             : 
     517             : add_to_hash:
     518   185538394 :         HANDLE_BLOCK_INTERRUPTIONS();
     519   185538394 :         idx = ht->nNumUsed++;
     520   185538394 :         ht->nNumOfElements++;
     521   185538394 :         if (ht->nInternalPointer == HT_INVALID_IDX) {
     522     5735791 :                 ht->nInternalPointer = idx;
     523             :         }
     524             :         zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
     525   185538394 :         p = ht->arData + idx;
     526   185538394 :         p->key = key;
     527   185538394 :         if (!IS_INTERNED(key)) {
     528             :                 zend_string_addref(key);
     529   101200574 :                 ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
     530             :                 zend_string_hash_val(key);
     531             :         }
     532   185538394 :         p->h = h = key->h;
     533   185538394 :         ZVAL_COPY_VALUE(&p->val, pData);
     534   185538394 :         nIndex = h | ht->nTableMask;
     535   185538394 :         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     536   185538394 :         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
     537   185538394 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     538             : 
     539   185538394 :         return &p->val;
     540             : }
     541             : 
     542     3055231 : ZEND_API zval* ZEND_FASTCALL _zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     543             : {
     544     3055231 :         return _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_RELAY_CC);
     545             : }
     546             : 
     547   135852570 : ZEND_API zval* ZEND_FASTCALL _zend_hash_add(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     548             : {
     549   135852570 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     550             : }
     551             : 
     552     7521005 : ZEND_API zval* ZEND_FASTCALL _zend_hash_update(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     553             : {
     554     7521005 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     555             : }
     556             : 
     557        1116 : ZEND_API zval* ZEND_FASTCALL _zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     558             : {
     559        1116 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC);
     560             : }
     561             : 
     562     2357671 : ZEND_API zval* ZEND_FASTCALL _zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     563             : {
     564     2357671 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     565             : }
     566             : 
     567           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)
     568             : {
     569           0 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     570           0 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_CC);
     571             :         zend_string_release(key);
     572           0 :         return ret;
     573             : }
     574             : 
     575    23187362 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     576             : {
     577    46374724 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     578    23187362 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_CC);
     579             :         zend_string_release(key);
     580    23187362 :         return ret;
     581             : }
     582             : 
     583     1289890 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     584             : {
     585     2579780 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     586     1289890 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_CC);
     587             :         zend_string_release(key);
     588     1289890 :         return ret;
     589             : }
     590             : 
     591    12833269 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     592             : {
     593    25666538 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     594    12833269 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_CC);
     595             :         zend_string_release(key);
     596    12833269 :         return ret;
     597             : }
     598             : 
     599        2830 : ZEND_API zval* ZEND_FASTCALL _zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     600             : {
     601        5660 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     602        2830 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_CC);
     603             :         zend_string_release(key);
     604        2830 :         return ret;
     605             : }
     606             : 
     607           0 : ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
     608             : {
     609             : 
     610             :         zval dummy;
     611             : 
     612           0 :         ZVAL_NULL(&dummy);
     613           0 :         return zend_hash_index_add(ht, h, &dummy);
     614             : }
     615             : 
     616       49132 : ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
     617             : {
     618             : 
     619             :         zval dummy;
     620             : 
     621       49132 :         ZVAL_NULL(&dummy);
     622       49132 :         return zend_hash_add(ht, key, &dummy);
     623             : }
     624             : 
     625      495526 : ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
     626             : {
     627             : 
     628             :         zval dummy;
     629             : 
     630      495526 :         ZVAL_NULL(&dummy);
     631      495526 :         return zend_hash_str_add(ht, str, len, &dummy);
     632             : }
     633             : 
     634             : 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)
     635             : {
     636             :         uint32_t nIndex;
     637             :         uint32_t idx;
     638             :         Bucket *p;
     639             : 
     640             :         IS_CONSISTENT(ht);
     641             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     642             : 
     643     7106481 :         if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
     644     1929649 :                 CHECK_INIT(ht, h < ht->nTableSize);
     645     1929649 :                 if (h < ht->nTableSize) {
     646     1827380 :                         p = ht->arData + h;
     647             :                         goto add_to_packed;
     648             :                 }
     649             :                 goto add_to_hash;
     650     5176832 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     651     3222616 :                 if (h < ht->nNumUsed) {
     652        3773 :                         p = ht->arData + h;
     653        7546 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     654        3620 :                                 if (flag & HASH_ADD) {
     655           0 :                                         return NULL;
     656             :                                 }
     657        3620 :                                 if (ht->pDestructor) {
     658        3620 :                                         ht->pDestructor(&p->val);
     659             :                                 }
     660        3620 :                                 ZVAL_COPY_VALUE(&p->val, pData);
     661        3620 :                                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     662           0 :                                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     663             :                                 }
     664        3620 :                                 return &p->val;
     665             :                         } else { /* we have to keep the order :( */
     666             :                                 goto convert_to_hash;
     667             :                         }
     668     3218843 :                 } else if (EXPECTED(h < ht->nTableSize)) {
     669     3202138 :                         p = ht->arData + h;
     670       33332 :                 } else if ((h >> 1) < ht->nTableSize &&
     671       16627 :                            (ht->nTableSize >> 1) < ht->nNumOfElements) {
     672       15537 :                         zend_hash_packed_grow(ht);
     673       15537 :                         p = ht->arData + h;
     674             :                 } else {
     675             :                         goto convert_to_hash;
     676             :                 }
     677             : 
     678             : add_to_packed:
     679     5045055 :                 HANDLE_BLOCK_INTERRUPTIONS();
     680             :                 /* incremental initialization of empty Buckets */
     681     5045055 :                 if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) == (HASH_ADD_NEW|HASH_ADD_NEXT)) {
     682     1165485 :                         ht->nNumUsed = h + 1;
     683     3879570 :                 } else if (h >= ht->nNumUsed) {
     684     3879570 :                         if (h > ht->nNumUsed) {
     685      893295 :                                 Bucket *q = ht->arData + ht->nNumUsed;
     686     1793598 :                                 while (q != p) {
     687      900303 :                                         ZVAL_UNDEF(&q->val);
     688      900303 :                                         q++;
     689             :                                 }
     690             :                         }
     691     3879570 :                         ht->nNumUsed = h + 1;
     692             :                 }
     693     5045055 :                 ht->nNumOfElements++;
     694     5045055 :                 if (ht->nInternalPointer == HT_INVALID_IDX) {
     695     1827520 :                         ht->nInternalPointer = h;
     696             :                 }
     697     5045055 :                 zend_hash_iterators_update(ht, HT_INVALID_IDX, h);
     698     5045055 :                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     699     5045044 :                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     700             :                 }
     701     5045055 :                 p->h = h;
     702     5045055 :                 p->key = NULL;
     703     5045055 :                 ZVAL_COPY_VALUE(&p->val, pData);
     704             : 
     705     5045055 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     706             : 
     707     5045055 :                 return &p->val;
     708             : 
     709             : convert_to_hash:
     710        1321 :                 zend_hash_packed_to_hash(ht);
     711     1954216 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     712     1306658 :                 p = zend_hash_index_find_bucket(ht, h);
     713     1306658 :                 if (p) {
     714       10420 :                         if (flag & HASH_ADD) {
     715         158 :                                 return NULL;
     716             :                         }
     717             :                         ZEND_ASSERT(&p->val != pData);
     718       10262 :                         HANDLE_BLOCK_INTERRUPTIONS();
     719       10262 :                         if (ht->pDestructor) {
     720       10204 :                                 ht->pDestructor(&p->val);
     721             :                         }
     722       10262 :                         ZVAL_COPY_VALUE(&p->val, pData);
     723       10262 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     724       10262 :                         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     725           1 :                                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     726             :                         }
     727       10262 :                         return &p->val;
     728             :                 }
     729             :         }
     730             : 
     731     1945117 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     732             : 
     733             : add_to_hash:
     734     2047386 :         HANDLE_BLOCK_INTERRUPTIONS();
     735     2047386 :         idx = ht->nNumUsed++;
     736     2047386 :         ht->nNumOfElements++;
     737     2047386 :         if (ht->nInternalPointer == HT_INVALID_IDX) {
     738      170760 :                 ht->nInternalPointer = idx;
     739             :         }
     740             :         zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
     741     2047386 :         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     742      659540 :                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     743             :         }
     744     2047386 :         p = ht->arData + idx;
     745     2047386 :         p->h = h;
     746     2047386 :         p->key = NULL;
     747     2047386 :         nIndex = h | ht->nTableMask;
     748     2047386 :         ZVAL_COPY_VALUE(&p->val, pData);
     749     2047386 :         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     750     2047386 :         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
     751     2047386 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     752             : 
     753     2047386 :         return &p->val;
     754             : }
     755             : 
     756           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)
     757             : {
     758           0 :         return _zend_hash_index_add_or_update_i(ht, h, pData, flag ZEND_FILE_LINE_RELAY_CC);
     759             : }
     760             : 
     761         520 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     762             : {
     763         520 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     764             : }
     765             : 
     766     1083693 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     767             : {
     768     1083693 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     769             : }
     770             : 
     771     2304450 : ZEND_API zval* ZEND_FASTCALL _zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     772             : {
     773     2304450 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     774             : }
     775             : 
     776     2551804 : ZEND_API zval* ZEND_FASTCALL _zend_hash_next_index_insert(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     777             : {
     778     5103608 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     779             : }
     780             : 
     781     1166014 : ZEND_API zval* ZEND_FASTCALL _zend_hash_next_index_insert_new(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     782             : {
     783     2332028 :         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);
     784             : }
     785             : 
     786     4501506 : static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
     787             : {
     788             : 
     789             :         IS_CONSISTENT(ht);
     790             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     791             : 
     792     4501506 :         if (ht->nNumUsed > ht->nNumOfElements) {
     793       24031 :                 HANDLE_BLOCK_INTERRUPTIONS();
     794       24031 :                 zend_hash_rehash(ht);
     795       24031 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     796     4477475 :         } else if (ht->nTableSize < HT_MAX_SIZE) {        /* Let's double the table size */
     797     4477475 :                 void *old_data = HT_GET_DATA_ADDR(ht);
     798     4477475 :                 Bucket *old_buckets = ht->arData;
     799             : 
     800     4477475 :                 HANDLE_BLOCK_INTERRUPTIONS();
     801     4477475 :                 ht->nTableSize += ht->nTableSize;
     802     4477475 :                 ht->nTableMask = -ht->nTableSize;
     803     8954950 :                 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
     804     4477475 :                 memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
     805     4477475 :                 pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT);
     806     4477475 :                 zend_hash_rehash(ht);
     807     4477475 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     808             :         } else {
     809           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));
     810             :         }
     811     4501506 : }
     812             : 
     813     5495498 : ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
     814             : {
     815             :         Bucket *p;
     816             :         uint32_t nIndex, i;
     817             : 
     818             :         IS_CONSISTENT(ht);
     819             : 
     820     5495498 :         if (UNEXPECTED(ht->nNumOfElements == 0)) {
     821           5 :                 if (ht->u.flags & HASH_FLAG_INITIALIZED) {
     822           2 :                         ht->nNumUsed = 0;
     823           2 :                         HT_HASH_RESET(ht);
     824             :                 }
     825           5 :                 return SUCCESS;
     826             :         }
     827             : 
     828     5495493 :         HT_HASH_RESET(ht);
     829     5495493 :         i = 0;
     830     5495493 :         p = ht->arData;
     831     5495493 :         if (ht->nNumUsed == ht->nNumOfElements) {
     832             :                 do {
     833   393577258 :                         nIndex = p->h | ht->nTableMask;
     834   393577258 :                         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     835   393577258 :                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
     836   393577258 :                         p++;
     837   393577258 :                 } while (++i < ht->nNumUsed);
     838             :         } else {
     839             :                 do {
     840      726736 :                         if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) {
     841       25521 :                                 uint32_t j = i;
     842       25521 :                                 Bucket *q = p;
     843             : 
     844       25521 :                                 if (EXPECTED(ht->u.v.nIteratorsCount == 0)) {
     845      257203 :                                         while (++i < ht->nNumUsed) {
     846      206167 :                                                 p++;
     847      206167 :                                                 if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
     848      166541 :                                                         ZVAL_COPY_VALUE(&q->val, &p->val);
     849      166541 :                                                         q->h = p->h;
     850      166541 :                                                         nIndex = q->h | ht->nTableMask;
     851      166541 :                                                         q->key = p->key;
     852      166541 :                                                         Z_NEXT(q->val) = HT_HASH(ht, nIndex);
     853      166541 :                                                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
     854      166541 :                                                         if (UNEXPECTED(ht->nInternalPointer == i)) {
     855       22385 :                                                                 ht->nInternalPointer = j;
     856             :                                                         }
     857      166541 :                                                         q++;
     858      166541 :                                                         j++;
     859             :                                                 }
     860             :                                         }
     861             :                                 } else {
     862           3 :                                         uint32_t iter_pos = zend_hash_iterators_lower_pos(ht, 0);
     863             : 
     864          27 :                                         while (++i < ht->nNumUsed) {
     865          21 :                                                 p++;
     866          21 :                                                 if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
     867          12 :                                                         ZVAL_COPY_VALUE(&q->val, &p->val);
     868          12 :                                                         q->h = p->h;
     869          12 :                                                         nIndex = q->h | ht->nTableMask;
     870          12 :                                                         q->key = p->key;
     871          12 :                                                         Z_NEXT(q->val) = HT_HASH(ht, nIndex);
     872          12 :                                                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
     873          12 :                                                         if (UNEXPECTED(ht->nInternalPointer == i)) {
     874           3 :                                                                 ht->nInternalPointer = j;
     875             :                                                         }
     876          12 :                                                         if (UNEXPECTED(i == iter_pos)) {
     877             :                                                                 zend_hash_iterators_update(ht, i, j);
     878           5 :                                                                 iter_pos = zend_hash_iterators_lower_pos(ht, iter_pos + 1);
     879             :                                                         }
     880          12 :                                                         q++;
     881          12 :                                                         j++;
     882             :                                                 }
     883             :                                         }
     884             :                                 }
     885       25521 :                                 ht->nNumUsed = j;
     886       25521 :                                 break;
     887             :                         }
     888      337847 :                         nIndex = p->h | ht->nTableMask;
     889      337847 :                         Z_NEXT(p->val) = HT_HASH(ht, nIndex);
     890      337847 :                         HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
     891      337847 :                         p++;
     892      337847 :                 } while (++i < ht->nNumUsed);
     893             :         }
     894     5495493 :         return SUCCESS;
     895             : }
     896             : 
     897             : static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
     898             : {
     899    50715915 :         HANDLE_BLOCK_INTERRUPTIONS();
     900    50715915 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     901    50611978 :                 if (prev) {
     902     2995039 :                         Z_NEXT(prev->val) = Z_NEXT(p->val);
     903             :                 } else {
     904    47616939 :                         HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
     905             :                 }
     906             :         }
     907    50715915 :         if (HT_IDX_TO_HASH(ht->nNumUsed - 1) == idx) {
     908             :                 do {
     909     3669799 :                         ht->nNumUsed--;
     910     7166426 :                 } while (ht->nNumUsed > 0 && (UNEXPECTED(Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF)));
     911             :         }
     912    50715915 :         ht->nNumOfElements--;
     913    50715915 :         if (HT_IDX_TO_HASH(ht->nInternalPointer) == idx || UNEXPECTED(ht->u.v.nIteratorsCount)) {
     914             :                 uint32_t new_idx;
     915             : 
     916     3219798 :                 new_idx = idx = HT_HASH_TO_IDX(idx);
     917             :                 while (1) {
     918    45089266 :                         new_idx++;
     919    45089266 :                         if (new_idx >= ht->nNumUsed) {
     920      131359 :                                 new_idx = HT_INVALID_IDX;
     921             :                                 break;
     922    89915814 :                         } else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
     923             :                                 break;
     924             :                         }
     925             :                 }
     926     3219798 :                 if (ht->nInternalPointer == idx) {
     927     3219761 :                         ht->nInternalPointer = new_idx;
     928             :                 }
     929             :                 zend_hash_iterators_update(ht, idx, new_idx);
     930             :         }
     931    50715915 :         if (p->key) {
     932    50441191 :                 zend_string_release(p->key);
     933             :         }
     934    50715915 :         if (ht->pDestructor) {
     935             :                 zval tmp;
     936    49911726 :                 ZVAL_COPY_VALUE(&tmp, &p->val);
     937    49911726 :                 ZVAL_UNDEF(&p->val);
     938    49911726 :                 ht->pDestructor(&tmp);
     939             :         } else {
     940      804189 :                 ZVAL_UNDEF(&p->val);
     941             :         }
     942    50715915 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     943             : }
     944             : 
     945             : static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
     946             : {
     947     7064987 :         Bucket *prev = NULL;
     948             : 
     949     7064987 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     950     7061082 :                 uint32_t nIndex = p->h | ht->nTableMask;
     951     7061082 :                 uint32_t i = HT_HASH(ht, nIndex);
     952             : 
     953     7061082 :                 if (i != idx) {
     954      585993 :                         prev = HT_HASH_TO_BUCKET(ht, i);
     955      629921 :                         while (Z_NEXT(prev->val) != idx) {
     956       43928 :                                 i = Z_NEXT(prev->val);
     957       43928 :                                 prev = HT_HASH_TO_BUCKET(ht, i);
     958             :                         }
     959             :                 }
     960             :         }
     961             : 
     962             :         _zend_hash_del_el_ex(ht, idx, p, prev);
     963             : }
     964             : 
     965          24 : ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p)
     966             : {
     967             :         IS_CONSISTENT(ht);
     968             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     969          24 :         _zend_hash_del_el(ht, HT_IDX_TO_HASH(p - ht->arData), p);
     970          24 : }
     971             : 
     972    43462572 : ZEND_API int ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
     973             : {
     974             :         zend_ulong h;
     975             :         uint32_t nIndex;
     976             :         uint32_t idx;
     977             :         Bucket *p;
     978    43462572 :         Bucket *prev = NULL;
     979             : 
     980             :         IS_CONSISTENT(ht);
     981             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
     982             : 
     983    43462572 :         h = zend_string_hash_val(key);
     984    43462572 :         nIndex = h | ht->nTableMask;
     985             : 
     986    43462572 :         idx = HT_HASH(ht, nIndex);
     987    89456574 :         while (idx != HT_INVALID_IDX) {
     988    45218695 :                 p = HT_HASH_TO_BUCKET(ht, idx);
     989   218388491 :                 if ((p->key == key) ||
     990    45190987 :                         (p->h == h &&
     991    42659603 :                      p->key &&
     992    42659603 :                      p->key->len == key->len &&
     993    42659603 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     994             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     995    42687265 :                         return SUCCESS;
     996             :                 }
     997     2531430 :                 prev = p;
     998     2531430 :                 idx = Z_NEXT(p->val);
     999             :         }
    1000      775307 :         return FAILURE;
    1001             : }
    1002             : 
    1003         399 : ZEND_API int ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key)
    1004             : {
    1005             :         zend_ulong h;
    1006             :         uint32_t nIndex;
    1007             :         uint32_t idx;
    1008             :         Bucket *p;
    1009         399 :         Bucket *prev = NULL;
    1010             : 
    1011             :         IS_CONSISTENT(ht);
    1012             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1013             : 
    1014         399 :         h = zend_string_hash_val(key);
    1015         399 :         nIndex = h | ht->nTableMask;
    1016             : 
    1017         399 :         idx = HT_HASH(ht, nIndex);
    1018         806 :         while (idx != HT_INVALID_IDX) {
    1019         218 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1020         914 :                 if ((p->key == key) ||
    1021         180 :                         (p->h == h &&
    1022         172 :                      p->key &&
    1023         172 :                      p->key->len == key->len &&
    1024         172 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
    1025         420 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
    1026          14 :                                 zval *data = Z_INDIRECT(p->val);
    1027             : 
    1028          14 :                                 if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
    1029           0 :                                         return FAILURE;
    1030             :                                 } else {
    1031          14 :                                         if (ht->pDestructor) {
    1032          14 :                                                 ht->pDestructor(data);
    1033             :                                         }
    1034          14 :                                         ZVAL_UNDEF(data);
    1035             :                                 }
    1036             :                         } else {
    1037             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
    1038             :                         }
    1039         210 :                         return SUCCESS;
    1040             :                 }
    1041           8 :                 prev = p;
    1042           8 :                 idx = Z_NEXT(p->val);
    1043             :         }
    1044         189 :         return FAILURE;
    1045             : }
    1046             : 
    1047           0 : ZEND_API int ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
    1048             : {
    1049             :         zend_ulong h;
    1050             :         uint32_t nIndex;
    1051             :         uint32_t idx;
    1052             :         Bucket *p;
    1053           0 :         Bucket *prev = NULL;
    1054             : 
    1055             :         IS_CONSISTENT(ht);
    1056             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1057             : 
    1058           0 :         h = zend_inline_hash_func(str, len);
    1059           0 :         nIndex = h | ht->nTableMask;
    1060             : 
    1061           0 :         idx = HT_HASH(ht, nIndex);
    1062           0 :         while (idx != HT_INVALID_IDX) {
    1063           0 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1064           0 :                 if ((p->h == h)
    1065             :                          && p->key
    1066           0 :                          && (p->key->len == len)
    1067           0 :                          && !memcmp(p->key->val, str, len)) {
    1068           0 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
    1069           0 :                                 zval *data = Z_INDIRECT(p->val);
    1070             : 
    1071           0 :                                 if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
    1072           0 :                                         return FAILURE;
    1073             :                                 } else {
    1074           0 :                                         if (ht->pDestructor) {
    1075           0 :                                                 ht->pDestructor(data);
    1076             :                                         }
    1077           0 :                                         ZVAL_UNDEF(data);
    1078             :                                 }
    1079             :                         } else {
    1080             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
    1081             :                         }
    1082           0 :                         return SUCCESS;
    1083             :                 }
    1084           0 :                 prev = p;
    1085           0 :                 idx = Z_NEXT(p->val);
    1086             :         }
    1087           0 :         return FAILURE;
    1088             : }
    1089             : 
    1090      737770 : ZEND_API int ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
    1091             : {
    1092             :         zend_ulong h;
    1093             :         uint32_t nIndex;
    1094             :         uint32_t idx;
    1095             :         Bucket *p;
    1096      737770 :         Bucket *prev = NULL;
    1097             : 
    1098             :         IS_CONSISTENT(ht);
    1099             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1100             : 
    1101      737770 :         h = zend_inline_hash_func(str, len);
    1102      737770 :         nIndex = h | ht->nTableMask;
    1103             : 
    1104      737770 :         idx = HT_HASH(ht, nIndex);
    1105     1517886 :         while (idx != HT_INVALID_IDX) {
    1106      756435 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1107     2898702 :                 if ((p->h == h)
    1108             :                          && p->key
    1109     1428178 :                          && (p->key->len == len)
    1110      714089 :                          && !memcmp(p->key->val, str, len)) {
    1111             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1112      714089 :                         return SUCCESS;
    1113             :                 }
    1114       42346 :                 prev = p;
    1115       42346 :                 idx = Z_NEXT(p->val);
    1116             :         }
    1117       23681 :         return FAILURE;
    1118             : }
    1119             : 
    1120      256734 : ZEND_API int ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
    1121             : {
    1122             :         uint32_t nIndex;
    1123             :         uint32_t idx;
    1124             :         Bucket *p;
    1125      256734 :         Bucket *prev = NULL;
    1126             : 
    1127             :         IS_CONSISTENT(ht);
    1128             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1129             : 
    1130      256734 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1131      106197 :                 if (h < ht->nNumUsed) {
    1132      100038 :                         p = ht->arData + h;
    1133      200076 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1134      100032 :                                 _zend_hash_del_el_ex(ht, HT_IDX_TO_HASH(h), p, NULL);
    1135      100032 :                                 return SUCCESS;
    1136             :                         }
    1137             :                 }
    1138        6165 :                 return FAILURE;
    1139             :         }
    1140      150537 :         nIndex = h | ht->nTableMask;
    1141             : 
    1142      150537 :         idx = HT_HASH(ht, nIndex);
    1143      302144 :         while (idx != HT_INVALID_IDX) {
    1144      150416 :                 p = HT_HASH_TO_BUCKET(ht, idx);
    1145      150416 :                 if ((p->h == h) && (p->key == NULL)) {
    1146             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
    1147      149346 :                         return SUCCESS;
    1148             :                 }
    1149        1070 :                 prev = p;
    1150        1070 :                 idx = Z_NEXT(p->val);
    1151             :         }
    1152        1191 :         return FAILURE;
    1153             : }
    1154             : 
    1155    15094331 : ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
    1156             : {
    1157             :         Bucket *p, *end;
    1158             : 
    1159             :         IS_CONSISTENT(ht);
    1160             :         HT_ASSERT(GC_REFCOUNT(ht) <= 1);
    1161             : 
    1162    15094331 :         if (ht->nNumUsed) {
    1163     7984474 :                 p = ht->arData;
    1164     7984474 :                 end = p + ht->nNumUsed;
    1165     7984474 :                 if (ht->pDestructor) {
    1166             :                         SET_INCONSISTENT(HT_IS_DESTROYING);
    1167             : 
    1168     7682970 :                         if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
    1169     5025276 :                                 if (ht->nNumUsed == ht->nNumOfElements) {
    1170             :                                         do {
    1171   152089343 :                                                 ht->pDestructor(&p->val);
    1172   152089342 :                                         } while (++p != end);
    1173             :                                 } else {
    1174             :                                         do {
    1175    92755878 :                                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1176     3001025 :                                                         ht->pDestructor(&p->val);
    1177             :                                                 }
    1178    46377939 :                                         } while (++p != end);
    1179             :                                 }
    1180     2657694 :                         } else if (ht->nNumUsed == ht->nNumOfElements) {
    1181             :                                 do {
    1182    88862939 :                                         ht->pDestructor(&p->val);
    1183    88862939 :                                         if (EXPECTED(p->key)) {
    1184    88856587 :                                                 zend_string_release(p->key);
    1185             :                                         }
    1186    88862939 :                                 } while (++p != end);
    1187             :                         } else {
    1188             :                                 do {
    1189     9336390 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1190      272579 :                                                 ht->pDestructor(&p->val);
    1191      272579 :                                                 if (EXPECTED(p->key)) {
    1192      272579 :                                                         zend_string_release(p->key);
    1193             :                                                 }
    1194             :                                         }
    1195     4668195 :                                 } while (++p != end);
    1196             :                         }
    1197             : 
    1198             :                         SET_INCONSISTENT(HT_DESTROYED);
    1199             :                 } else {
    1200      301504 :                         if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) {
    1201             :                                 do {
    1202    17882784 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1203     8857581 :                                                 if (EXPECTED(p->key)) {
    1204     8856951 :                                                         zend_string_release(p->key);
    1205             :                                                 }
    1206             :                                         }
    1207     8941392 :                                 } while (++p != end);
    1208             :                         }
    1209             :                 }
    1210             :                 zend_hash_iterators_remove(ht);
    1211     7109857 :         } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    1212     7041283 :                 return;
    1213             :         }
    1214     8053047 :         pefree(HT_GET_DATA_ADDR(ht), ht->u.flags & HASH_FLAG_PERSISTENT);
    1215             : }
    1216             : 
    1217     3649141 : ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
    1218             : {
    1219             :         Bucket *p, *end;
    1220             : 
    1221             :         IS_CONSISTENT(ht);
    1222             :         HT_ASSERT(GC_REFCOUNT(ht) <= 1);
    1223             : 
    1224     3649141 :         if (ht->nNumUsed) {
    1225             : 
    1226             :                 /* In some rare cases destructors of regular arrays may be changed */
    1227     2258747 :                 if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) {
    1228          71 :                         zend_hash_destroy(ht);
    1229          71 :                         goto free_ht;
    1230             :                 }
    1231             : 
    1232     2258676 :                 p = ht->arData;
    1233     2258676 :                 end = p + ht->nNumUsed;
    1234             :                 SET_INCONSISTENT(HT_IS_DESTROYING);
    1235             : 
    1236     2258676 :                 if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
    1237             :                         do {
    1238     5310769 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1239     5310767 :                         } while (++p != end);
    1240      253201 :                 } else if (ht->nNumUsed == ht->nNumOfElements) {
    1241             :                         do {
    1242     4417388 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1243     4417388 :                                 if (EXPECTED(p->key)) {
    1244     4354260 :                                         zend_string_release(p->key);
    1245             :                                 }
    1246     4417388 :                         } while (++p != end);
    1247             :                 } else {
    1248             :                         do {
    1249        4504 :                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1250        1954 :                                         i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1251        1954 :                                         if (EXPECTED(p->key)) {
    1252        1895 :                                                 zend_string_release(p->key);
    1253             :                                         }
    1254             :                                 }
    1255        2252 :                         } while (++p != end);
    1256             :                 }
    1257             :                 zend_hash_iterators_remove(ht);
    1258             :                 SET_INCONSISTENT(HT_DESTROYED);
    1259     1390394 :         } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    1260     1388115 :                 goto free_ht;
    1261             :         }
    1262     2260953 :         efree(HT_GET_DATA_ADDR(ht));
    1263             : free_ht:
    1264     3649139 :         FREE_HASHTABLE(ht);
    1265     3649139 : }
    1266             : 
    1267       50842 : ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
    1268             : {
    1269             :         Bucket *p, *end;
    1270             : 
    1271             :         IS_CONSISTENT(ht);
    1272             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1273             : 
    1274       50842 :         if (ht->nNumUsed) {
    1275        8623 :                 p = ht->arData;
    1276        8623 :                 end = p + ht->nNumUsed;
    1277        8623 :                 if (ht->pDestructor) {
    1278        3608 :                         if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) {
    1279         991 :                                 if (ht->nNumUsed == ht->nNumOfElements) {
    1280             :                                         do {
    1281      516773 :                                                 ht->pDestructor(&p->val);
    1282      516773 :                                         } while (++p != end);
    1283             :                                 } else {
    1284             :                                         do {
    1285          78 :                                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1286           9 :                                                         ht->pDestructor(&p->val);
    1287             :                                                 }
    1288          39 :                                         } while (++p != end);
    1289             :                                 }
    1290        2617 :                         } else if (ht->nNumUsed == ht->nNumOfElements) {
    1291             :                                 do {
    1292     1249087 :                                         ht->pDestructor(&p->val);
    1293     1249087 :                                         if (EXPECTED(p->key)) {
    1294     1249087 :                                                 zend_string_release(p->key);
    1295             :                                         }
    1296     1249087 :                                 } while (++p != end);
    1297             :                         } else {
    1298             :                                 do {
    1299           0 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1300           0 :                                                 ht->pDestructor(&p->val);
    1301           0 :                                                 if (EXPECTED(p->key)) {
    1302           0 :                                                         zend_string_release(p->key);
    1303             :                                                 }
    1304             :                                         }
    1305           0 :                                 } while (++p != end);
    1306             :                         }
    1307             :                 } else {
    1308        5015 :                         if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) {
    1309        4588 :                                 if (ht->nNumUsed == ht->nNumOfElements) {
    1310             :                                         do {
    1311       27553 :                                                 if (EXPECTED(p->key)) {
    1312       27553 :                                                         zend_string_release(p->key);
    1313             :                                                 }
    1314       27553 :                                         } while (++p != end);
    1315             :                                 } else {
    1316             :                                         do {
    1317           0 :                                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1318           0 :                                                         if (EXPECTED(p->key)) {
    1319           0 :                                                                 zend_string_release(p->key);
    1320             :                                                         }
    1321             :                                                 }
    1322           0 :                                         } while (++p != end);
    1323             :                                 }
    1324             :                         }
    1325             :                 }
    1326        8623 :                 if (!(ht->u.flags & HASH_FLAG_PACKED)) {
    1327        8608 :                         HT_HASH_RESET(ht);
    1328             :                 }
    1329             :         }
    1330       50842 :         ht->nNumUsed = 0;
    1331       50842 :         ht->nNumOfElements = 0;
    1332       50842 :         ht->nNextFreeElement = 0;
    1333       50842 :         ht->nInternalPointer = HT_INVALID_IDX;
    1334       50842 : }
    1335             : 
    1336       87836 : ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
    1337             : {
    1338             :         Bucket *p, *end;
    1339             : 
    1340             :         IS_CONSISTENT(ht);
    1341             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1342             : 
    1343       87836 :         if (ht->nNumUsed) {
    1344       87829 :                 p = ht->arData;
    1345       87829 :                 end = p + ht->nNumUsed;
    1346       87829 :                 if (ht->u.flags & HASH_FLAG_STATIC_KEYS) {
    1347             :                         do {
    1348      176986 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1349      176986 :                         } while (++p != end);
    1350          80 :                 } else if (ht->nNumUsed == ht->nNumOfElements) {
    1351             :                         do {
    1352         570 :                                 i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1353         570 :                                 zend_string_release(p->key);
    1354         570 :                         } while (++p != end);
    1355             :                 } else {
    1356             :                         do {
    1357           0 :                                 if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
    1358           0 :                                         i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
    1359           0 :                                         zend_string_release(p->key);
    1360             :                                 }
    1361           0 :                         } while (++p != end);
    1362             :                 }
    1363       87829 :                 HT_HASH_RESET(ht);
    1364             :         }
    1365       87836 :         ht->nNumUsed = 0;
    1366       87836 :         ht->nNumOfElements = 0;
    1367       87836 :         ht->nNextFreeElement = 0;
    1368       87836 :         ht->nInternalPointer = HT_INVALID_IDX;
    1369       87836 : }
    1370             : 
    1371           0 : ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht)
    1372             : {
    1373             :         uint32_t idx;
    1374             :         Bucket *p;
    1375             : 
    1376             :         IS_CONSISTENT(ht);
    1377             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1378             : 
    1379           0 :         p = ht->arData;
    1380           0 :         for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
    1381           0 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1382             :                 _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1383             :         }
    1384           0 :         if (ht->u.flags & HASH_FLAG_INITIALIZED) {
    1385           0 :                 pefree(HT_GET_DATA_ADDR(ht), ht->u.flags & HASH_FLAG_PERSISTENT);
    1386             :         }
    1387             : 
    1388             :         SET_INCONSISTENT(HT_DESTROYED);
    1389           0 : }
    1390             : 
    1391       83848 : ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht)
    1392             : {
    1393             :         uint32_t idx;
    1394             :         Bucket *p;
    1395             : 
    1396             :         IS_CONSISTENT(ht);
    1397             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1398             : 
    1399       83848 :         idx = ht->nNumUsed;
    1400       83848 :         p = ht->arData + ht->nNumUsed;
    1401     1867124 :         while (idx > 0) {
    1402     1699428 :                 idx--;
    1403     1699428 :                 p--;
    1404     3398856 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1405             :                 _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1406             :         }
    1407             : 
    1408       83848 :         if (ht->u.flags & HASH_FLAG_INITIALIZED) {
    1409       63719 :                 pefree(HT_GET_DATA_ADDR(ht), ht->u.flags & HASH_FLAG_PERSISTENT);
    1410             :         }
    1411             : 
    1412             :         SET_INCONSISTENT(HT_DESTROYED);
    1413       83848 : }
    1414             : 
    1415             : /* This is used to recurse elements and selectively delete certain entries
    1416             :  * from a hashtable. apply_func() receives the data and decides if the entry
    1417             :  * should be deleted or recursion should be stopped. The following three
    1418             :  * return codes are possible:
    1419             :  * ZEND_HASH_APPLY_KEEP   - continue
    1420             :  * ZEND_HASH_APPLY_STOP   - stop iteration
    1421             :  * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
    1422             :  */
    1423             : 
    1424       93207 : ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func)
    1425             : {
    1426             :         uint32_t idx;
    1427             :         Bucket *p;
    1428             :         int result;
    1429             : 
    1430             :         IS_CONSISTENT(ht);
    1431             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1432             : 
    1433       93207 :         HASH_PROTECT_RECURSION(ht);
    1434       93207 :         p = ht->arData;
    1435     1670837 :         for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
    1436     3155270 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1437     1577614 :                 result = apply_func(&p->val);
    1438             : 
    1439     1577609 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1440             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1441             :                 }
    1442     1577609 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1443           0 :                         break;
    1444             :                 }
    1445             :         }
    1446       93202 :         HASH_UNPROTECT_RECURSION(ht);
    1447       93202 : }
    1448             : 
    1449             : 
    1450      576443 : ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
    1451             : {
    1452             :     uint32_t idx;
    1453             :         Bucket *p;
    1454             :         int result;
    1455             : 
    1456             :         IS_CONSISTENT(ht);
    1457             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1458             : 
    1459      576443 :         HASH_PROTECT_RECURSION(ht);
    1460      576443 :         p = ht->arData;
    1461   122862160 :         for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
    1462   244579116 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1463    89473253 :                 result = apply_func(&p->val, argument);
    1464             : 
    1465    89473253 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1466             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1467             :                 }
    1468    89473253 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1469        3841 :                         break;
    1470             :                 }
    1471             :         }
    1472      576443 :         HASH_UNPROTECT_RECURSION(ht);
    1473      576443 : }
    1474             : 
    1475             : 
    1476         296 : ZEND_API void ZEND_FASTCALL zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int num_args, ...)
    1477             : {
    1478             :         uint32_t idx;
    1479             :         Bucket *p;
    1480             :         va_list args;
    1481             :         zend_hash_key hash_key;
    1482             :         int result;
    1483             : 
    1484             :         IS_CONSISTENT(ht);
    1485             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1486             : 
    1487         296 :         HASH_PROTECT_RECURSION(ht);
    1488             : 
    1489         296 :         p = ht->arData;
    1490      157876 :         for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
    1491      315160 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1492      157514 :                 va_start(args, num_args);
    1493      157514 :                 hash_key.h = p->h;
    1494      157514 :                 hash_key.key = p->key;
    1495             : 
    1496      157514 :                 result = apply_func(&p->val, num_args, args, &hash_key);
    1497             : 
    1498      157514 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1499             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1500             :                 }
    1501      157514 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1502           0 :                         va_end(args);
    1503           0 :                         break;
    1504             :                 }
    1505      157514 :                 va_end(args);
    1506             :         }
    1507             : 
    1508         296 :         HASH_UNPROTECT_RECURSION(ht);
    1509         296 : }
    1510             : 
    1511             : 
    1512      109560 : ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func)
    1513             : {
    1514             :         uint32_t idx;
    1515             :         Bucket *p;
    1516             :         int result;
    1517             : 
    1518             :         IS_CONSISTENT(ht);
    1519             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    1520             : 
    1521      109560 :         HASH_PROTECT_RECURSION(ht);
    1522      109560 :         idx = ht->nNumUsed;
    1523      109560 :         p = ht->arData + idx;
    1524      720587 :         while (idx > 0) {
    1525      564200 :                 idx--;
    1526      564200 :                 p--;
    1527     1128400 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1528             : 
    1529      512508 :                 result = apply_func(&p->val);
    1530             : 
    1531      512508 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1532             :                         _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
    1533             :                 }
    1534      512508 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1535       62733 :                         break;
    1536             :                 }
    1537             :         }
    1538      109560 :         HASH_UNPROTECT_RECURSION(ht);
    1539      109560 : }
    1540             : 
    1541             : 
    1542         465 : ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
    1543             : {
    1544             :     uint32_t idx;
    1545             :         Bucket *p;
    1546             :         zval *new_entry, *data;
    1547             :         zend_bool setTargetPointer;
    1548             : 
    1549             :         IS_CONSISTENT(source);
    1550             :         IS_CONSISTENT(target);
    1551             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1552             : 
    1553         465 :         setTargetPointer = (target->nInternalPointer == HT_INVALID_IDX);
    1554       11376 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1555       10911 :                 p = source->arData + idx;
    1556       21822 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1557             : 
    1558       10911 :                 if (setTargetPointer && source->nInternalPointer == idx) {
    1559         307 :                         target->nInternalPointer = HT_INVALID_IDX;
    1560             :                 }
    1561             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1562       10911 :                 data = &p->val;
    1563       10911 :                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1564          96 :                         data = Z_INDIRECT_P(data);
    1565          96 :                         if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
    1566           0 :                                 continue;
    1567             :                         }
    1568             :                 }
    1569       10911 :                 if (p->key) {
    1570       10822 :                         new_entry = zend_hash_update(target, p->key, data);
    1571             :                 } else {
    1572          89 :                         new_entry = zend_hash_index_update(target, p->h, data);
    1573             :                 }
    1574       10911 :                 if (pCopyConstructor) {
    1575         408 :                         pCopyConstructor(new_entry);
    1576             :                 }
    1577             :         }
    1578         465 :         if (target->nInternalPointer == HT_INVALID_IDX && target->nNumOfElements > 0) {
    1579           0 :                 idx = 0;
    1580           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1581           0 :                         idx++;
    1582             :                 }
    1583           0 :                 target->nInternalPointer = idx;
    1584             :         }
    1585         465 : }
    1586             : 
    1587             : 
    1588             : 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)
    1589             : {
    1590     3528567 :         zval *data = &p->val;
    1591             : 
    1592     3528567 :         if (with_holes) {
    1593     2526535 :                 if (!packed && Z_TYPE_INFO_P(data) == IS_INDIRECT) {
    1594           0 :                         data = Z_INDIRECT_P(data);
    1595             :                 }
    1596     2526535 :                 if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
    1597      841339 :                         return 0;
    1598             :                 }
    1599     1002032 :         } else if (!packed) {
    1600             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1601      695962 :                 if (Z_TYPE_INFO_P(data) == IS_INDIRECT) {
    1602       17841 :                         data = Z_INDIRECT_P(data);
    1603       17841 :                         if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
    1604        2852 :                                 return 0;
    1605             :                         }
    1606             :                 }
    1607             :         }
    1608             : 
    1609             :         do {
    1610     2684376 :                 if (Z_OPT_REFCOUNTED_P(data)) {
    1611     2500469 :                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1 &&
    1612          62 :                             (Z_TYPE_P(Z_REFVAL_P(data)) != IS_ARRAY ||
    1613          18 :                               Z_ARRVAL_P(Z_REFVAL_P(data)) != source)) {
    1614          59 :                                 data = Z_REFVAL_P(data);
    1615          59 :                                 if (!Z_OPT_REFCOUNTED_P(data)) {
    1616             :                                         break;
    1617             :                                 }
    1618             :                         }
    1619             :                         Z_ADDREF_P(data);
    1620             :                 }
    1621             :         } while (0);
    1622     2684376 :         ZVAL_COPY_VALUE(&q->val, data);
    1623             : 
    1624     2684376 :         q->h = p->h;
    1625     2684376 :         if (packed) {
    1626     1991246 :                 q->key = NULL;
    1627             :         } else {
    1628             :                 uint32_t nIndex;
    1629             : 
    1630      693130 :                 q->key = p->key;
    1631      693130 :                 if (!static_keys && q->key) {
    1632      687120 :                         zend_string_addref(q->key);
    1633             :                 }
    1634             : 
    1635      693130 :                 nIndex = q->h | target->nTableMask;
    1636      693130 :                 Z_NEXT(q->val) = HT_HASH(target, nIndex);
    1637      693130 :                 HT_HASH(target, nIndex) = HT_IDX_TO_HASH(idx);
    1638             :         }
    1639     2684376 :         return 1;
    1640             : }
    1641             : 
    1642             : static zend_always_inline void zend_array_dup_packed_elements(HashTable *source, HashTable *target, int with_holes)
    1643             : {
    1644     1041300 :         Bucket *p = source->arData;
    1645     1041300 :         Bucket *q = target->arData;
    1646     1041300 :         Bucket *end = p + source->nNumUsed;
    1647             : 
    1648             :         do {
    1649     2832581 :                 if (!zend_array_dup_element(source, target, 0, p, q, 1, 1, with_holes)) {
    1650      841335 :                         if (with_holes) {
    1651      841335 :                                 ZVAL_UNDEF(&q->val);
    1652             :                         }
    1653             :                 }
    1654     2832581 :                 p++; q++;
    1655     2832581 :         } while (p != end);
    1656             : }
    1657             : 
    1658             : static zend_always_inline uint32_t zend_array_dup_elements(HashTable *source, HashTable *target, int static_keys, int with_holes)
    1659             : {
    1660       56371 :     uint32_t idx = 0;
    1661       56371 :         Bucket *p = source->arData;
    1662       56371 :         Bucket *q = target->arData;
    1663       56371 :         Bucket *end = p + source->nNumUsed;
    1664             : 
    1665             :         do {
    1666      685128 :                 if (!zend_array_dup_element(source, target, idx, p, q, 0, static_keys, with_holes)) {
    1667        1893 :                         uint32_t target_idx = idx;
    1668             : 
    1669        1893 :                         idx++; p++;
    1670       12751 :                         while (p != end) {
    1671       10858 :                                 if (zend_array_dup_element(source, target, target_idx, p, q, 0, static_keys, with_holes)) {
    1672        9895 :                                         if (source->nInternalPointer == idx) {
    1673           0 :                                                 target->nInternalPointer = target_idx;
    1674             :                                         }
    1675        9895 :                                         target_idx++; q++;
    1676             :                                 }
    1677       10858 :                                 idx++; p++;
    1678             :                         }
    1679        1893 :                         return target_idx;
    1680             :                 }
    1681      683235 :                 idx++; p++; q++;
    1682      683235 :         } while (p != end);
    1683       54478 :         return idx;
    1684             : }
    1685             : 
    1686     1260768 : ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
    1687             : {
    1688             :     uint32_t idx;
    1689             :         HashTable *target;
    1690             : 
    1691             :         IS_CONSISTENT(source);
    1692             : 
    1693     1260768 :         ALLOC_HASHTABLE(target);
    1694     1260768 :         GC_REFCOUNT(target) = 1;
    1695     1260768 :         GC_TYPE_INFO(target) = IS_ARRAY;
    1696             : 
    1697     1260768 :         target->nTableSize = source->nTableSize;
    1698     1260768 :         target->pDestructor = source->pDestructor;
    1699             : 
    1700     1260768 :         if (source->nNumUsed == 0) {
    1701      163083 :                 target->u.flags = (source->u.flags & ~(HASH_FLAG_INITIALIZED|HASH_FLAG_PERSISTENT)) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
    1702      163083 :                 target->nTableMask = HT_MIN_MASK;
    1703      163083 :                 target->nNumUsed = 0;
    1704      163083 :                 target->nNumOfElements = 0;
    1705      163083 :                 target->nNextFreeElement = 0;
    1706      163083 :                 target->nInternalPointer = HT_INVALID_IDX;
    1707      163083 :                 HT_SET_DATA_ADDR(target, &uninitialized_bucket);
    1708     1097685 :         } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
    1709          14 :                 target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1710          14 :                 target->nTableMask = source->nTableMask;
    1711          14 :                 target->nNumUsed = source->nNumUsed;
    1712          14 :                 target->nNumOfElements = source->nNumOfElements;
    1713          14 :                 target->nNextFreeElement = source->nNextFreeElement;
    1714          14 :                 HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
    1715          14 :                 target->nInternalPointer = source->nInternalPointer;
    1716          14 :                 memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source));
    1717          28 :                 if (target->nNumOfElements > 0 &&
    1718          14 :                     target->nInternalPointer == HT_INVALID_IDX) {
    1719           0 :                         idx = 0;
    1720           0 :                         while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1721           0 :                                 idx++;
    1722             :                         }
    1723           0 :                         target->nInternalPointer = idx;
    1724             :                 }
    1725     1097671 :         } else if (source->u.flags & HASH_FLAG_PACKED) {
    1726     1041300 :                 target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1727     1041300 :                 target->nTableMask = source->nTableMask;
    1728     1041300 :                 target->nNumUsed = source->nNumUsed;
    1729     1041300 :                 target->nNumOfElements = source->nNumOfElements;
    1730     1041300 :                 target->nNextFreeElement = source->nNextFreeElement;
    1731     1041300 :                 HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
    1732     1041300 :                 target->nInternalPointer = source->nInternalPointer;
    1733     1041300 :                 HT_HASH_RESET_PACKED(target);
    1734             : 
    1735     1041300 :                 if (target->nNumUsed == target->nNumOfElements) {
    1736             :                         zend_array_dup_packed_elements(source, target, 0);
    1737             :                 } else {
    1738             :                         zend_array_dup_packed_elements(source, target, 1);
    1739             :                 }
    1740     2082600 :                 if (target->nNumOfElements > 0 &&
    1741     1041300 :                     target->nInternalPointer == HT_INVALID_IDX) {
    1742           8 :                         idx = 0;
    1743          26 :                         while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1744           1 :                                 idx++;
    1745             :                         }
    1746           8 :                         target->nInternalPointer = idx;
    1747             :                 }
    1748             :         } else {
    1749       56371 :                 target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1750       56371 :                 target->nTableMask = source->nTableMask;
    1751       56371 :                 target->nNextFreeElement = source->nNextFreeElement;
    1752       56371 :                 target->nInternalPointer = HT_INVALID_IDX;
    1753       56371 :                 HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
    1754       56371 :                 HT_HASH_RESET(target);
    1755             : 
    1756       56371 :                 if (target->u.flags & HASH_FLAG_STATIC_KEYS) {
    1757         925 :                         if (source->nNumUsed == source->nNumOfElements) {
    1758         925 :                                 idx = zend_array_dup_elements(source, target, 1, 0);
    1759             :                         } else {
    1760           0 :                                 idx = zend_array_dup_elements(source, target, 1, 1);
    1761             :                         }
    1762             :                 } else {
    1763       55446 :                         if (source->nNumUsed == source->nNumOfElements) {
    1764       55443 :                                 idx = zend_array_dup_elements(source, target, 0, 0);
    1765             :                         } else {
    1766           3 :                                 idx = zend_array_dup_elements(source, target, 0, 1);
    1767             :                         }
    1768             :                 }
    1769       56371 :                 target->nNumUsed = idx;
    1770       56371 :                 target->nNumOfElements = idx;
    1771       56371 :                 if (idx > 0 && target->nInternalPointer == HT_INVALID_IDX) {
    1772       56361 :                         target->nInternalPointer = 0;
    1773             :                 }
    1774             :         }
    1775     1260768 :         return target;
    1776             : }
    1777             : 
    1778             : 
    1779      188319 : ZEND_API void ZEND_FASTCALL _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite ZEND_FILE_LINE_DC)
    1780             : {
    1781             :     uint32_t idx;
    1782             :         Bucket *p;
    1783             :         zval *t;
    1784      188319 :         uint32_t mode = (overwrite?HASH_UPDATE:HASH_ADD);
    1785             : 
    1786             :         IS_CONSISTENT(source);
    1787             :         IS_CONSISTENT(target);
    1788             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1789             : 
    1790     3243587 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1791     3055268 :                 p = source->arData + idx;
    1792     6110536 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1793     3055268 :                 if (p->key) {
    1794     3055231 :                         t = _zend_hash_add_or_update(target, p->key, &p->val, mode ZEND_FILE_LINE_RELAY_CC);
    1795     3055231 :                         if (t && pCopyConstructor) {
    1796     3054649 :                                 pCopyConstructor(t);
    1797             :                         }
    1798             :                 } else {
    1799          37 :                         if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h))) {
    1800          26 :                                 t = zend_hash_index_update(target, p->h, &p->val);
    1801          26 :                                 if (t && pCopyConstructor) {
    1802          26 :                                         pCopyConstructor(t);
    1803             :                                 }
    1804             :                         }
    1805             :                 }
    1806             :         }
    1807      188319 :         if (target->nNumOfElements > 0) {
    1808      188317 :                 idx = 0;
    1809      564951 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1810           0 :                         idx++;
    1811             :                 }
    1812      188317 :                 target->nInternalPointer = idx;
    1813             :         }
    1814      188319 : }
    1815             : 
    1816             : 
    1817           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)
    1818             : {
    1819             :         zend_hash_key hash_key;
    1820             : 
    1821           0 :         hash_key.h = p->h;
    1822           0 :         hash_key.key = p->key;
    1823           0 :         return merge_checker_func(target, source_data, &hash_key, pParam);
    1824             : }
    1825             : 
    1826             : 
    1827           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)
    1828             : {
    1829             :         uint32_t idx;
    1830             :         Bucket *p;
    1831             :         zval *t;
    1832             : 
    1833             :         IS_CONSISTENT(source);
    1834             :         IS_CONSISTENT(target);
    1835             :         HT_ASSERT(GC_REFCOUNT(target) == 1);
    1836             : 
    1837           0 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1838           0 :                 p = source->arData + idx;
    1839           0 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    1840           0 :                 if (zend_hash_replace_checker_wrapper(target, &p->val, p, pParam, pMergeSource)) {
    1841           0 :                         t = zend_hash_update(target, p->key, &p->val);
    1842           0 :                         if (t && pCopyConstructor) {
    1843           0 :                                 pCopyConstructor(t);
    1844             :                         }
    1845             :                 }
    1846             :         }
    1847           0 :         if (target->nNumOfElements > 0) {
    1848           0 :                 idx = 0;
    1849           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1850           0 :                         idx++;
    1851             :                 }
    1852           0 :                 target->nInternalPointer = idx;
    1853             :         }
    1854           0 : }
    1855             : 
    1856             : 
    1857             : /* Returns the hash table data if found and NULL if not. */
    1858    53221781 : ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
    1859             : {
    1860             :         Bucket *p;
    1861             : 
    1862             :         IS_CONSISTENT(ht);
    1863             : 
    1864    53221781 :         p = zend_hash_find_bucket(ht, key);
    1865    53221781 :         return p ? &p->val : NULL;
    1866             : }
    1867             : 
    1868     1965606 : ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
    1869             : {
    1870             :         zend_ulong h;
    1871             :         Bucket *p;
    1872             : 
    1873             :         IS_CONSISTENT(ht);
    1874             : 
    1875     1965606 :         h = zend_inline_hash_func(str, len);
    1876     1965606 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1877     1965606 :         return p ? &p->val : NULL;
    1878             : }
    1879             : 
    1880     2672769 : ZEND_API zend_bool ZEND_FASTCALL zend_hash_exists(const HashTable *ht, zend_string *key)
    1881             : {
    1882             :         Bucket *p;
    1883             : 
    1884             :         IS_CONSISTENT(ht);
    1885             : 
    1886     2672769 :         p = zend_hash_find_bucket(ht, key);
    1887     2672769 :         return p ? 1 : 0;
    1888             : }
    1889             : 
    1890      898266 : ZEND_API zend_bool ZEND_FASTCALL zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
    1891             : {
    1892             :         zend_ulong h;
    1893             :         Bucket *p;
    1894             : 
    1895             :         IS_CONSISTENT(ht);
    1896             : 
    1897      898266 :         h = zend_inline_hash_func(str, len);
    1898      898266 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1899      898266 :         return p ? 1 : 0;
    1900             : }
    1901             : 
    1902     5764033 : ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
    1903             : {
    1904             :         Bucket *p;
    1905             : 
    1906             :         IS_CONSISTENT(ht);
    1907             : 
    1908     5764033 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1909     4577573 :                 if (h < ht->nNumUsed) {
    1910     4326147 :                         p = ht->arData + h;
    1911     8652294 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1912     4325772 :                                 return &p->val;
    1913             :                         }
    1914             :                 }
    1915      251801 :                 return NULL;
    1916             :         }
    1917             : 
    1918     1186460 :         p = zend_hash_index_find_bucket(ht, h);
    1919     1186460 :         return p ? &p->val : NULL;
    1920             : }
    1921             : 
    1922             : 
    1923     1548178 : ZEND_API zend_bool ZEND_FASTCALL zend_hash_index_exists(const HashTable *ht, zend_ulong h)
    1924             : {
    1925             :         Bucket *p;
    1926             : 
    1927             :         IS_CONSISTENT(ht);
    1928             : 
    1929     1548178 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1930          82 :                 if (h < ht->nNumUsed) {
    1931         104 :                         if (Z_TYPE(ht->arData[h].val) != IS_UNDEF) {
    1932          51 :                                 return 1;
    1933             :                         }
    1934             :                 }
    1935          31 :                 return 0;
    1936             :         }
    1937             : 
    1938     1548096 :         p = zend_hash_index_find_bucket(ht, h);
    1939     1548096 :         return p ? 1 : 0;
    1940             : }
    1941             : 
    1942             : 
    1943       19141 : ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
    1944             : {
    1945             :     uint32_t idx;
    1946             : 
    1947             :         IS_CONSISTENT(ht);
    1948             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1949             : 
    1950       19550 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1951       38808 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1952       18995 :                         *pos = idx;
    1953       18995 :                         return;
    1954             :                 }
    1955             :         }
    1956         146 :         *pos = HT_INVALID_IDX;
    1957             : }
    1958             : 
    1959             : 
    1960             : /* This function will be extremely optimized by remembering
    1961             :  * the end of the list
    1962             :  */
    1963          47 : ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
    1964             : {
    1965             :         uint32_t idx;
    1966             : 
    1967             :         IS_CONSISTENT(ht);
    1968             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1969             : 
    1970          47 :         idx = ht->nNumUsed;
    1971          94 :         while (idx > 0) {
    1972          45 :                 idx--;
    1973          90 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1974          45 :                         *pos = idx;
    1975          45 :                         return;
    1976             :                 }
    1977             :         }
    1978           2 :         *pos = HT_INVALID_IDX;
    1979             : }
    1980             : 
    1981             : 
    1982       67951 : ZEND_API int ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
    1983             : {
    1984       67951 :         uint32_t idx = *pos;
    1985             : 
    1986             :         IS_CONSISTENT(ht);
    1987             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    1988             : 
    1989       67951 :         if (idx != HT_INVALID_IDX) {
    1990             :                 while (1) {
    1991       67985 :                         idx++;
    1992       67985 :                         if (idx >= ht->nNumUsed) {
    1993       16194 :                                 *pos = HT_INVALID_IDX;
    1994       16194 :                                 return SUCCESS;
    1995             :                         }
    1996      103582 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1997       51722 :                                 *pos = idx;
    1998       51722 :                                 return SUCCESS;
    1999             :                         }
    2000          69 :                 }
    2001             :         } else {
    2002          35 :                 return FAILURE;
    2003             :         }
    2004             : }
    2005             : 
    2006          21 : ZEND_API int ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
    2007             : {
    2008          21 :         uint32_t idx = *pos;
    2009             : 
    2010             :         IS_CONSISTENT(ht);
    2011             :         HT_ASSERT(ht->nInternalPointer != &pos || GC_REFCOUNT(ht) == 1);
    2012             : 
    2013          21 :         if (idx != HT_INVALID_IDX) {
    2014          38 :                 while (idx > 0) {
    2015          14 :                         idx--;
    2016          28 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    2017          14 :                                 *pos = idx;
    2018          14 :                                 return SUCCESS;
    2019             :                         }
    2020             :                 }
    2021           5 :                 *pos = HT_INVALID_IDX;
    2022           5 :                 return SUCCESS;
    2023             :         } else {
    2024           2 :                 return FAILURE;
    2025             :         }
    2026             : }
    2027             : 
    2028             : 
    2029             : /* This function should be made binary safe  */
    2030       12811 : ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, HashPosition *pos)
    2031             : {
    2032       12811 :         uint32_t idx = *pos;
    2033             :         Bucket *p;
    2034             : 
    2035             :         IS_CONSISTENT(ht);
    2036       12811 :         if (idx != HT_INVALID_IDX) {
    2037       12380 :                 p = ht->arData + idx;
    2038       12380 :                 if (p->key) {
    2039       11046 :                         *str_index = p->key;
    2040       11046 :                         return HASH_KEY_IS_STRING;
    2041             :                 } else {
    2042        1334 :                         *num_index = p->h;
    2043        1334 :                         return HASH_KEY_IS_LONG;
    2044             :                 }
    2045             :         }
    2046         431 :         return HASH_KEY_NON_EXISTENT;
    2047             : }
    2048             : 
    2049        3187 : ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
    2050             : {
    2051        3187 :         uint32_t idx = *pos;
    2052             :         Bucket *p;
    2053             : 
    2054             :         IS_CONSISTENT(ht);
    2055        3187 :         if (idx == HT_INVALID_IDX) {
    2056          49 :                 ZVAL_NULL(key);
    2057             :         } else {
    2058        3138 :                 p = ht->arData + idx;
    2059        3138 :                 if (p->key) {
    2060         670 :                         ZVAL_STR_COPY(key, p->key);
    2061             :                 } else {
    2062        2468 :                         ZVAL_LONG(key, p->h);
    2063             :                 }
    2064             :         }
    2065        3187 : }
    2066             : 
    2067       78635 : ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
    2068             : {
    2069       78635 :     uint32_t idx = *pos;
    2070             :         Bucket *p;
    2071             : 
    2072             :         IS_CONSISTENT(ht);
    2073       78635 :         if (idx != HT_INVALID_IDX) {
    2074       63410 :                 p = ht->arData + idx;
    2075       63410 :                 if (p->key) {
    2076       60795 :                         return HASH_KEY_IS_STRING;
    2077             :                 } else {
    2078        2615 :                         return HASH_KEY_IS_LONG;
    2079             :                 }
    2080             :         }
    2081       15225 :         return HASH_KEY_NON_EXISTENT;
    2082             : }
    2083             : 
    2084             : 
    2085       65469 : ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
    2086             : {
    2087       65469 :         uint32_t idx = *pos;
    2088             :         Bucket *p;
    2089             : 
    2090             :         IS_CONSISTENT(ht);
    2091       65469 :         if (idx != HT_INVALID_IDX) {
    2092       64652 :                 p = ht->arData + idx;
    2093       64652 :                 return &p->val;
    2094             :         } else {
    2095         817 :                 return NULL;
    2096             :         }
    2097             : }
    2098             : 
    2099       88840 : ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q)
    2100             : {
    2101             :         zval val;
    2102             :         zend_ulong h;
    2103             :         zend_string *key;
    2104             : 
    2105       88840 :         ZVAL_COPY_VALUE(&val, &p->val);
    2106       88840 :         h = p->h;
    2107       88840 :         key = p->key;
    2108             : 
    2109       88840 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    2110       88840 :         p->h = q->h;
    2111       88840 :         p->key = q->key;
    2112             : 
    2113       88840 :         ZVAL_COPY_VALUE(&q->val, &val);
    2114       88840 :         q->h = h;
    2115       88840 :         q->key = key;
    2116       88840 : }
    2117             : 
    2118       68956 : ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q)
    2119             : {
    2120             :         zval val;
    2121             : 
    2122       68956 :         ZVAL_COPY_VALUE(&val, &p->val);
    2123       68956 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    2124       68956 :         ZVAL_COPY_VALUE(&q->val, &val);
    2125       68956 : }
    2126             : 
    2127        1082 : ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q)
    2128             : {
    2129             :         zval val;
    2130             :         zend_ulong h;
    2131             : 
    2132        1082 :         ZVAL_COPY_VALUE(&val, &p->val);
    2133        1082 :         h = p->h;
    2134             : 
    2135        1082 :         ZVAL_COPY_VALUE(&p->val, &q->val);
    2136        1082 :         p->h = q->h;
    2137             : 
    2138        1082 :         ZVAL_COPY_VALUE(&q->val, &val);
    2139        1082 :         q->h = h;
    2140        1082 : }
    2141             : 
    2142       22615 : ZEND_API int ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, compare_func_t compar, zend_bool renumber)
    2143             : {
    2144             :         Bucket *p;
    2145             :         uint32_t i, j;
    2146             : 
    2147             :         IS_CONSISTENT(ht);
    2148             :         HT_ASSERT(GC_REFCOUNT(ht) == 1);
    2149             : 
    2150       22615 :         if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
    2151         293 :                 return SUCCESS;
    2152             :         }
    2153             : 
    2154       22322 :         if (ht->nNumUsed == ht->nNumOfElements) {
    2155       22229 :                 i = ht->nNumUsed;
    2156             :         } else {
    2157         679 :                 for (j = 0, i = 0; j < ht->nNumUsed; j++) {
    2158         586 :                         p = ht->arData + j;
    2159        1172 :                         if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    2160         475 :                         if (i != j) {
    2161         459 :                                 ht->arData[i] = *p;
    2162             :                         }
    2163         475 :                         i++;
    2164             :                 }
    2165             :         }
    2166             : 
    2167       44347 :         sort((void *)ht->arData, i, sizeof(Bucket), compar,
    2168             :                         (swap_func_t)(renumber? zend_hash_bucket_renum_swap :
    2169       22025 :                                 ((ht->u.flags & HASH_FLAG_PACKED) ? zend_hash_bucket_packed_swap : zend_hash_bucket_swap)));
    2170             : 
    2171       22321 :         HANDLE_BLOCK_INTERRUPTIONS();
    2172       22321 :         ht->nNumUsed = i;
    2173       22321 :         ht->nInternalPointer = 0;
    2174             : 
    2175       22321 :         if (renumber) {
    2176       15807 :                 for (j = 0; j < i; j++) {
    2177       15511 :                         p = ht->arData + j;
    2178       15511 :                         p->h = j;
    2179       15511 :                         if (p->key) {
    2180         231 :                                 zend_string_release(p->key);
    2181         231 :                                 p->key = NULL;
    2182             :                         }
    2183             :                 }
    2184             : 
    2185         296 :                 ht->nNextFreeElement = i;
    2186             :         }
    2187       22321 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    2188         494 :                 if (!renumber) {
    2189         244 :                         zend_hash_packed_to_hash(ht);
    2190             :                 }
    2191             :         } else {
    2192       21827 :                 if (renumber) {
    2193          46 :                         void *old_data = HT_GET_DATA_ADDR(ht);
    2194          46 :                         Bucket *old_buckets = ht->arData;
    2195             : 
    2196          46 :                         ht->u.flags |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
    2197          46 :                         ht->nTableMask = HT_MIN_MASK;
    2198          92 :                         HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT & HASH_FLAG_PERSISTENT));
    2199          46 :                         memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
    2200          46 :                         pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT & HASH_FLAG_PERSISTENT);
    2201          46 :                         HT_HASH_RESET_PACKED(ht);
    2202             :                 } else {
    2203       21781 :                         zend_hash_rehash(ht);
    2204             :                 }
    2205             :         }
    2206             : 
    2207       22321 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    2208             : 
    2209       22321 :         return SUCCESS;
    2210             : }
    2211             : 
    2212             : 
    2213         884 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered)
    2214             : {
    2215             :         uint32_t idx1, idx2;
    2216         884 :         Bucket *p1, *p2 = NULL;
    2217             :         int result;
    2218             :         zval *pData1, *pData2;
    2219             : 
    2220             :         IS_CONSISTENT(ht1);
    2221             :         IS_CONSISTENT(ht2);
    2222             : 
    2223         884 :         HASH_PROTECT_RECURSION(ht1);
    2224         884 :         HASH_PROTECT_RECURSION(ht2);
    2225             : 
    2226         884 :         result = ht1->nNumOfElements - ht2->nNumOfElements;
    2227         884 :         if (result!=0) {
    2228         302 :                 HASH_UNPROTECT_RECURSION(ht1);
    2229         302 :                 HASH_UNPROTECT_RECURSION(ht2);
    2230         302 :                 return result;
    2231             :         }
    2232             : 
    2233        4275 :         for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
    2234        3871 :                 p1 = ht1->arData + idx1;
    2235        7742 :                 if (Z_TYPE(p1->val) == IS_UNDEF) continue;
    2236             : 
    2237        3858 :                 if (ordered) {
    2238             :                         while (1) {
    2239        1127 :                                 p2 = ht2->arData + idx2;
    2240        1127 :                                 if (idx2 == ht2->nNumUsed) {
    2241           0 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2242           0 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2243           0 :                                         return 1; /* That's not supposed to happen */
    2244             :                                 }
    2245        2254 :                                 if (Z_TYPE(p2->val) != IS_UNDEF) break;
    2246           1 :                                 idx2++;
    2247           1 :                         }
    2248        1484 :                         if (p1->key == NULL && p2->key == NULL) { /* numeric indices */
    2249         359 :                                 result = p1->h - p2->h;
    2250         359 :                                 if (result != 0) {
    2251           1 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2252           1 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2253           1 :                                         return result;
    2254             :                                 }
    2255             :                         } else { /* string indices */
    2256         767 :                                 size_t len0 = (p1->key ? p1->key->len : 0);
    2257         767 :                                 size_t len1 = (p2->key ? p2->key->len : 0);
    2258         767 :                                 if (len0 != len1) {
    2259           0 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2260           0 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2261           0 :                                         return len0 > len1 ? 1 : -1;
    2262             :                                 }
    2263         767 :                                 result = memcmp(p1->key->val, p2->key->val, p1->key->len);
    2264         767 :                                 if (result != 0) {
    2265           0 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2266           0 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2267           0 :                                         return result;
    2268             :                                 }
    2269             :                         }
    2270        1125 :                         pData2 = &p2->val;
    2271             :                 } else {
    2272        2732 :                         if (p1->key == NULL) { /* numeric index */
    2273         485 :                                 pData2 = zend_hash_index_find(ht2, p1->h);
    2274         485 :                                 if (pData2 == NULL) {
    2275           2 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2276           2 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2277           2 :                                         return 1;
    2278             :                                 }
    2279             :                         } else { /* string index */
    2280        2247 :                                 pData2 = zend_hash_find(ht2, p1->key);
    2281        2247 :                                 if (pData2 == NULL) {
    2282          11 :                                         HASH_UNPROTECT_RECURSION(ht1);
    2283          11 :                                         HASH_UNPROTECT_RECURSION(ht2);
    2284          11 :                                         return 1;
    2285             :                                 }
    2286             :                         }
    2287             :                 }
    2288        3844 :                 pData1 = &p1->val;
    2289        3844 :                 if (Z_TYPE_P(pData1) == IS_INDIRECT) {
    2290         129 :                         pData1 = Z_INDIRECT_P(pData1);
    2291             :                 }
    2292        3844 :                 if (Z_TYPE_P(pData2) == IS_INDIRECT) {
    2293         129 :                         pData2 = Z_INDIRECT_P(pData2);
    2294             :                 }
    2295        3844 :                 if (Z_TYPE_P(pData1) == IS_UNDEF) {
    2296           0 :                         if (Z_TYPE_P(pData2) != IS_UNDEF) {
    2297           0 :                                 return -1;
    2298             :                         }
    2299        3844 :                 } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
    2300           0 :                         return 1;
    2301             :                 } else {
    2302        3844 :                         result = compar(pData1, pData2);
    2303             :                 }
    2304        3844 :                 if (result != 0) {
    2305         164 :                         HASH_UNPROTECT_RECURSION(ht1);
    2306         164 :                         HASH_UNPROTECT_RECURSION(ht2);
    2307         164 :                         return result;
    2308             :                 }
    2309        3680 :                 if (ordered) {
    2310        1121 :                         idx2++;
    2311             :                 }
    2312             :         }
    2313             : 
    2314         404 :         HASH_UNPROTECT_RECURSION(ht1);
    2315         404 :         HASH_UNPROTECT_RECURSION(ht2);
    2316         404 :         return 0;
    2317             : }
    2318             : 
    2319             : 
    2320          82 : ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag)
    2321             : {
    2322             :         uint32_t idx;
    2323             :         Bucket *p, *res;
    2324             : 
    2325             :         IS_CONSISTENT(ht);
    2326             : 
    2327          82 :         if (ht->nNumOfElements == 0 ) {
    2328           4 :                 return NULL;
    2329             :         }
    2330             : 
    2331          78 :         idx = 0;
    2332             :         while (1) {
    2333          78 :                 if (idx == ht->nNumUsed) {
    2334           0 :                         return NULL;
    2335             :                 }
    2336         156 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
    2337           0 :                 idx++;
    2338           0 :         }
    2339          78 :         res = ht->arData + idx;
    2340         376 :         for (; idx < ht->nNumUsed; idx++) {
    2341         298 :                 p = ht->arData + idx;
    2342         596 :                 if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
    2343             : 
    2344         298 :                 if (flag) {
    2345         229 :                         if (compar(res, p) < 0) { /* max */
    2346          20 :                                 res = p;
    2347             :                         }
    2348             :                 } else {
    2349          69 :                         if (compar(res, p) > 0) { /* min */
    2350           6 :                                 res = p;
    2351             :                         }
    2352             :                 }
    2353             :         }
    2354          78 :         return &res->val;
    2355             : }
    2356             : 
    2357      383118 : ZEND_API int ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
    2358             : {
    2359      383118 :         register const char *tmp = key;
    2360             : 
    2361      383118 :         const char *end = key + length;
    2362             :         ZEND_ASSERT(*end == '\0');
    2363             : 
    2364      383118 :         if (*tmp == '-') {
    2365          59 :                 tmp++;
    2366             :         }
    2367             : 
    2368      746095 :         if ((*tmp == '0' && length > 1) /* numbers with leading zeros */
    2369      362977 :          || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
    2370             :          || (SIZEOF_ZEND_LONG == 4 &&
    2371             :              end - tmp == MAX_LENGTH_OF_LONG - 1 &&
    2372             :              *tmp > '2')) { /* overflow */
    2373       20168 :                 return 0;
    2374             :         }
    2375      362950 :         *idx = (*tmp - '0');
    2376             :         while (1) {
    2377     1444635 :                 ++tmp;
    2378     1444635 :                 if (tmp == end) {
    2379      362687 :                         if (*key == '-') {
    2380          28 :                                 if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
    2381           0 :                                         return 0;
    2382             :                                 }
    2383          28 :                                 *idx = 0 - *idx;
    2384      362659 :                         } else if (*idx > ZEND_LONG_MAX) { /* overflow */
    2385           0 :                                 return 0;
    2386             :                         }
    2387      362687 :                         return 1;
    2388             :                 }
    2389     2163633 :                 if (*tmp <= '9' && *tmp >= '0') {
    2390     1081685 :                         *idx = (*idx * 10) + (*tmp - '0');
    2391             :                 } else {
    2392         263 :                         return 0;
    2393             :                 }
    2394     1081685 :         }
    2395             : }
    2396             : 
    2397             : /*
    2398             :  * Local variables:
    2399             :  * tab-width: 4
    2400             :  * c-basic-offset: 4
    2401             :  * indent-tabs-mode: t
    2402             :  * End:
    2403             :  */

Generated by: LCOV version 1.10

Generated at Thu, 21 May 2015 19:58:52 +0000 (4 days ago)

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