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: 820 925 88.6 %
Date: 2014-11-22 Functions: 57 65 87.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2014 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             : 
      25             : #if ZEND_DEBUG
      26             : /*
      27             : #define HASH_MASK_CONSISTENCY   0x60
      28             : */
      29             : #define HT_OK                                   0x00
      30             : #define HT_IS_DESTROYING                0x20
      31             : #define HT_DESTROYED                    0x40
      32             : #define HT_CLEANING                             0x60
      33             : 
      34             : static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
      35             : {
      36             :         if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) {
      37             :                 return;
      38             :         }
      39             :         switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) {
      40             :                 case HT_IS_DESTROYING:
      41             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
      42             :                         break;
      43             :                 case HT_DESTROYED:
      44             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
      45             :                         break;
      46             :                 case HT_CLEANING:
      47             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
      48             :                         break;
      49             :                 default:
      50             :                         zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
      51             :                         break;
      52             :         }
      53             :         zend_bailout();
      54             : }
      55             : #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
      56             : #define SET_INCONSISTENT(n) do { \
      57             :                 (ht)->u.flags |= n; \
      58             :         } while (0)
      59             : #else
      60             : #define IS_CONSISTENT(a)
      61             : #define SET_INCONSISTENT(n)
      62             : #endif
      63             : 
      64             : #define HASH_PROTECT_RECURSION(ht)                                                                                                              \
      65             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      66             :                 if ((ht)->u.flags >= (3 << 8)) {                                                                                            \
      67             :                         zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");\
      68             :                 }                                                                                                                                                               \
      69             :                 ZEND_HASH_INC_APPLY_COUNT(ht);                                                                                                  \
      70             :         }
      71             : 
      72             : #define HASH_UNPROTECT_RECURSION(ht)                                                                                                    \
      73             :         if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) {                                                                        \
      74             :                 ZEND_HASH_DEC_APPLY_COUNT(ht);                                                                                                  \
      75             :         }
      76             : 
      77             : #define ZEND_HASH_IF_FULL_DO_RESIZE(ht)                         \
      78             :         if ((ht)->nNumUsed >= (ht)->nTableSize) {              \
      79             :                 zend_hash_do_resize(ht);                                        \
      80             :         }
      81             : 
      82             : static void zend_hash_do_resize(HashTable *ht);
      83             : 
      84             : #define CHECK_INIT(ht, packed) do {                                                                                             \
      85             :         if (UNEXPECTED((ht)->nTableMask == 0)) {                                                     \
      86             :                 if (packed) { \
      87             :                         (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT);        \
      88             :                         (ht)->u.flags |= HASH_FLAG_PACKED; \
      89             :                 } else { \
      90             :                         (ht)->arData = (Bucket *) safe_pemalloc((ht)->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, (ht)->u.flags & HASH_FLAG_PERSISTENT);     \
      91             :                         (ht)->arHash = (uint32_t*)((ht)->arData + (ht)->nTableSize);   \
      92             :                         memset((ht)->arHash, INVALID_IDX, (ht)->nTableSize * sizeof(uint32_t));   \
      93             :                 } \
      94             :                 (ht)->nTableMask = (ht)->nTableSize - 1;                                          \
      95             :         }                                                                                                                                       \
      96             : } while (0)
      97             :  
      98             : static const uint32_t uninitialized_bucket = {INVALID_IDX};
      99             : 
     100    16748564 : ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     101             : {
     102             :         /* Use big enough power of 2 */
     103             : #if defined(PHP_WIN32) && !defined(__clang__)
     104             :         if (nSize <= 8) {
     105             :                 ht->nTableSize = 8;
     106             :         } else if (nSize >= 0x80000000) {
     107             :                 /* prevent overflow */
     108             :                 ht->nTableSize = 0x80000000;
     109             :         } else {
     110             :                 ht->nTableSize = 1U << __lzcnt(nSize);
     111             :                 if (ht->nTableSize < nSize) {
     112             :                         ht->nTableSize <<= 1;
     113             :                 }
     114             :         }
     115             : #else
     116             :         /* size should be between 8 and 0x80000000 */
     117    16748564 :         nSize = (nSize <= 8 ? 8 : (nSize >= 0x80000000 ? 0x80000000 : nSize));
     118             : # if defined(__GNUC__)
     119    16748564 :         ht->nTableSize =  0x2 << (__builtin_clz(nSize - 1) ^ 0x1f);
     120             : # else
     121             :         nSize -= 1;
     122             :         nSize |= (nSize >> 1);
     123             :         nSize |= (nSize >> 2);
     124             :         nSize |= (nSize >> 4);
     125             :         nSize |= (nSize >> 8);
     126             :         nSize |= (nSize >> 16);
     127             :         ht->nTableSize = nSize + 1;
     128             : # endif
     129             : #endif
     130             : 
     131    16748564 :         ht->nTableMask = 0;  /* 0 means that ht->arBuckets is uninitialized */
     132    16748564 :         ht->nNumUsed = 0;
     133    16748564 :         ht->nNumOfElements = 0;
     134    16748564 :         ht->nNextFreeElement = 0;
     135    16748564 :         ht->arData = NULL;
     136    16748564 :         ht->arHash = (uint32_t*)&uninitialized_bucket;
     137    16748564 :         ht->pDestructor = pDestructor;
     138    16748564 :         ht->nInternalPointer = INVALID_IDX;
     139    16748564 :         ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION;
     140    16748564 : }
     141             : 
     142       37106 : static void zend_hash_packed_grow(HashTable *ht)
     143             : {
     144       37106 :         HANDLE_BLOCK_INTERRUPTIONS();
     145       37106 :         ht->arData = (Bucket *) safe_perealloc(ht->arData, (ht->nTableSize << 1), sizeof(Bucket), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
     146       37106 :         ht->nTableSize = (ht->nTableSize << 1);
     147       37106 :         ht->nTableMask = ht->nTableSize - 1;
     148       37106 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     149       37106 : }
     150             : 
     151       69405 : ZEND_API void zend_hash_real_init(HashTable *ht, zend_bool packed)
     152             : {
     153             :         IS_CONSISTENT(ht);
     154             : 
     155       69405 :         CHECK_INIT(ht, packed);
     156       69405 : }
     157             : 
     158       27495 : ZEND_API void zend_hash_packed_to_hash(HashTable *ht)
     159             : {
     160       27495 :         HANDLE_BLOCK_INTERRUPTIONS();
     161       27495 :         ht->u.flags &= ~HASH_FLAG_PACKED;
     162       27495 :         ht->arData = (Bucket *) safe_perealloc(ht->arData, ht->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
     163       27495 :         ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize);
     164       27495 :         zend_hash_rehash(ht);
     165       27495 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     166       27495 : }
     167             : 
     168          15 : ZEND_API void zend_hash_to_packed(HashTable *ht)
     169             : {
     170          15 :         HANDLE_BLOCK_INTERRUPTIONS();
     171          15 :         ht->u.flags |= HASH_FLAG_PACKED;
     172          15 :         ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
     173          15 :         ht->arHash = (uint32_t*)&uninitialized_bucket;
     174          15 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     175          15 : }
     176             : 
     177    11157154 : ZEND_API void _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC)
     178             : {
     179    11157154 :         _zend_hash_init(ht, nSize, pDestructor, persistent ZEND_FILE_LINE_CC);
     180    11157154 :         if (!bApplyProtection) {
     181    11157154 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     182             :         }
     183    11157154 : }
     184             : 
     185             : 
     186           0 : ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
     187             : {
     188           0 :         if (bApplyProtection) {
     189           0 :                 ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
     190             :         } else {
     191           0 :                 ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
     192             :         }
     193           0 : }
     194             : 
     195             : static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
     196             : {
     197             :         zend_ulong h;
     198             :         uint32_t nIndex;
     199             :         uint32_t idx;
     200             :         Bucket *p;
     201             : 
     202   267448890 :         h = zend_string_hash_val(key);
     203   267448890 :         nIndex = h & ht->nTableMask;
     204   267448890 :         idx = ht->arHash[nIndex];
     205   415014275 :         while (idx != INVALID_IDX) {
     206   161489417 :                 p = ht->arData + idx;
     207   330140284 :                 if ((p->key == key) || /* check for the the same interned string */
     208   152835137 :                         (p->h == h &&
     209     5271910 :                          p->key &&
     210     5271910 :                          p->key->len == key->len &&
     211     5271910 :                          memcmp(p->key->val, key->val, key->len) == 0)) {
     212    13924032 :                         return p;
     213             :                 }
     214   147565385 :                 idx = Z_NEXT(p->val);
     215             :         }
     216   253524858 :         return NULL;
     217             : }
     218             : 
     219             : static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
     220             : {
     221             :         uint32_t nIndex;
     222             :         uint32_t idx;
     223             :         Bucket *p;
     224             : 
     225     3445949 :         nIndex = h & ht->nTableMask;
     226     3445949 :         idx = ht->arHash[nIndex];
     227     4255594 :         while (idx != INVALID_IDX) {
     228             :                 ZEND_ASSERT(idx < ht->nTableSize);
     229     3362476 :                 p = ht->arData + idx;
     230    11021020 :                 if ((p->h == h) 
     231             :                          && p->key
     232     5105696 :                          && (p->key->len == len)
     233     2552848 :                          && !memcmp(p->key->val, str, len)) {
     234     2552831 :                         return p;
     235             :                 }
     236      809645 :                 idx = Z_NEXT(p->val);
     237             :         }
     238      893118 :         return NULL;
     239             : }
     240             : 
     241             : static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
     242             : {
     243             :         uint32_t nIndex;
     244             :         uint32_t idx;
     245             :         Bucket *p;
     246             : 
     247     4078186 :         nIndex = h & ht->nTableMask;
     248     4078186 :         idx = ht->arHash[nIndex];
     249     5406421 :         while (idx != INVALID_IDX) {
     250             :                 ZEND_ASSERT(idx < ht->nTableSize);
     251     2327958 :                 p = ht->arData + idx;
     252     2327958 :                 if (p->h == h && !p->key) {
     253      999723 :                         return p;
     254             :                 }
     255     1328235 :                 idx = Z_NEXT(p->val);
     256             :         }
     257     3078463 :         return NULL;
     258             : }
     259             : 
     260             : 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)
     261             : {
     262             :         zend_ulong h;
     263             :         uint32_t nIndex;
     264             :         uint32_t idx;
     265             :         Bucket *p;
     266             : #ifdef ZEND_SIGNALS
     267             :         TSRMLS_FETCH();
     268             : #endif
     269             : 
     270             :         IS_CONSISTENT(ht);
     271             : 
     272   250875888 :         if (UNEXPECTED(ht->nTableMask == 0)) {
     273     6697101 :                 CHECK_INIT(ht, 0);
     274             :                 goto add_to_hash; 
     275   244178787 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     276       26470 :                 zend_hash_packed_to_hash(ht);
     277   244152317 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     278   215934656 :                 p = zend_hash_find_bucket(ht, key);
     279             : 
     280   215934656 :                 if (p) {
     281             :                         zval *data;
     282             : 
     283     1025463 :                         if (flag & HASH_ADD) {
     284      256330 :                                 return NULL;
     285             :                         }
     286             :                         ZEND_ASSERT(&p->val != pData);
     287      769133 :                         data = &p->val;
     288      824131 :                         if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
     289         254 :                                 data = Z_INDIRECT_P(data);
     290             :                         }
     291      769133 :                         HANDLE_BLOCK_INTERRUPTIONS();
     292      769133 :                         if (ht->pDestructor) {
     293      727747 :                                 ht->pDestructor(data);
     294             :                         }
     295      769133 :                         ZVAL_COPY_VALUE(data, pData);
     296      769133 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     297      769133 :                         return data;
     298             :                 }
     299             :         }
     300             :         
     301   243153324 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     302             : 
     303             : add_to_hash:
     304   249850425 :         HANDLE_BLOCK_INTERRUPTIONS();
     305   249850425 :         idx = ht->nNumUsed++;
     306   249850425 :         ht->nNumOfElements++;
     307   249850425 :         if (ht->nInternalPointer == INVALID_IDX) {
     308     6838811 :                 ht->nInternalPointer = idx;
     309             :         }
     310   249850425 :         p = ht->arData + idx; 
     311   249850425 :         p->h = h = zend_string_hash_val(key);
     312   249850425 :         p->key = key;
     313             :         zend_string_addref(key);
     314   249850425 :         ZVAL_COPY_VALUE(&p->val, pData);
     315   249850425 :         nIndex = h & ht->nTableMask;
     316   249850425 :         Z_NEXT(p->val) = ht->arHash[nIndex];
     317   249850425 :         ht->arHash[nIndex] = idx;
     318   249850425 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     319             : 
     320   249850425 :         return &p->val;
     321             : }
     322             : 
     323     2995521 : ZEND_API zval *_zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     324             : {
     325     2995521 :         return _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_RELAY_CC);
     326             : }
     327             : 
     328   138934068 : ZEND_API zval *_zend_hash_add(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     329             : {
     330   138934068 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     331             : }
     332             : 
     333    53107940 : ZEND_API zval *_zend_hash_update(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     334             : {
     335    53107940 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     336             : }
     337             : 
     338        1130 : ZEND_API zval *_zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     339             : {
     340        1130 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC);
     341             : }
     342             : 
     343    29295362 : ZEND_API zval *_zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData ZEND_FILE_LINE_DC)
     344             : {
     345    29295362 :         return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     346             : }
     347             : 
     348           0 : ZEND_API zval *_zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     349             : {
     350           0 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     351           0 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, flag ZEND_FILE_LINE_CC);
     352             :         zend_string_release(key);
     353           0 :         return ret;
     354             : }
     355             : 
     356    12631483 : ZEND_API zval *_zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     357             : {
     358    25262966 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     359    12631483 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_CC);
     360             :         zend_string_release(key);
     361    12631483 :         return ret;
     362             : }
     363             : 
     364     1275602 : ZEND_API zval *_zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     365             : {
     366     2551204 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     367     1275602 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_CC);
     368             :         zend_string_release(key);
     369     1275602 :         return ret;
     370             : }
     371             : 
     372    12631952 : ZEND_API zval *_zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     373             : {
     374    25263904 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     375    12631952 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD ZEND_FILE_LINE_CC);
     376             :         zend_string_release(key);
     377    12631952 :         return ret;
     378             : }
     379             : 
     380        2830 : ZEND_API zval *_zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData ZEND_FILE_LINE_DC)
     381             : {
     382        5660 :         zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);
     383        2830 :         zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW ZEND_FILE_LINE_CC);
     384             :         zend_string_release(key);
     385        2830 :         return ret;
     386             : }
     387             : 
     388           0 : ZEND_API zval *zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
     389             : {
     390             :         
     391             :         zval dummy;
     392             : 
     393           0 :         ZVAL_NULL(&dummy);
     394           0 :         return zend_hash_index_add(ht, h, &dummy);
     395             : }
     396             : 
     397         222 : ZEND_API zval *zend_hash_add_empty_element(HashTable *ht, zend_string *key)
     398             : {
     399             :         
     400             :         zval dummy;
     401             : 
     402         222 :         ZVAL_NULL(&dummy);
     403         222 :         return zend_hash_add(ht, key, &dummy);
     404             : }
     405             : 
     406      514358 : ZEND_API zval *zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
     407             : {
     408             :         
     409             :         zval dummy;
     410             : 
     411      514358 :         ZVAL_NULL(&dummy);
     412      514358 :         return zend_hash_str_add(ht, str, len, &dummy);
     413             : }
     414             : 
     415             : 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)
     416             : {
     417             :         uint32_t nIndex;
     418             :         uint32_t idx;
     419             :         Bucket *p;
     420             : #ifdef ZEND_SIGNALS
     421             :         TSRMLS_FETCH();
     422             : #endif
     423             : 
     424             :         IS_CONSISTENT(ht);
     425             : 
     426     7612958 :         if (UNEXPECTED(ht->nTableMask == 0)) {
     427     2023788 :                 CHECK_INIT(ht, h < ht->nTableSize);
     428     2023788 :                 if (h < ht->nTableSize) {
     429     1923230 :                         p = ht->arData + h;
     430             :                         goto add_to_packed;
     431             :                 }
     432             :                 goto add_to_hash;
     433     5589170 :         } else if (ht->u.flags & HASH_FLAG_PACKED) {
     434     3696349 :                 if (h < ht->nNumUsed) {
     435        3800 :                         p = ht->arData + h;
     436        7600 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     437        3644 :                                 if (flag & HASH_ADD) {
     438          24 :                                         return NULL;
     439             :                                 }
     440        3620 :                                 if (ht->pDestructor) {
     441        3620 :                                         ht->pDestructor(&p->val);
     442             :                                 }
     443        3620 :                                 ZVAL_COPY_VALUE(&p->val, pData);
     444        3620 :                                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     445           0 :                                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     446             :                                 }
     447        3620 :                                 return &p->val;
     448             :                         } else { /* we have to keep the order :( */
     449             :                                 goto convert_to_hash;
     450             :                         }
     451     3692549 :                 } else if (EXPECTED(h < ht->nTableSize)) {
     452     3654835 :                         p = ht->arData + h;
     453       75352 :                 } else if (h < ht->nTableSize * 2 &&
     454       37638 :                                    ht->nTableSize - ht->nNumOfElements < ht->nTableSize / 2) {
     455       37106 :                         zend_hash_packed_grow(ht);
     456       37106 :                         p = ht->arData + h;
     457             :                 } else {
     458             :                         goto convert_to_hash;
     459             :                 }
     460             : 
     461             : add_to_packed:
     462     5615171 :                 HANDLE_BLOCK_INTERRUPTIONS();
     463             :                 /* incremental initialization of empty Buckets */
     464     5615171 :                 if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) == (HASH_ADD_NEW|HASH_ADD_NEXT)) {
     465      452017 :                         ht->nNumUsed = h + 1;
     466     5163154 :                 } else if (h >= ht->nNumUsed) {
     467     5163154 :                         if (h > ht->nNumUsed) {
     468      894156 :                                 Bucket *q = ht->arData + ht->nNumUsed;
     469     1792993 :                                 while (q != p) {
     470      898837 :                                         ZVAL_UNDEF(&q->val);
     471      898837 :                                         q++;
     472             :                                 }
     473             :                         }
     474     5163154 :                         ht->nNumUsed = h + 1;
     475             :                 }
     476     5615171 :                 ht->nNumOfElements++;
     477     5615171 :                 if (ht->nInternalPointer == INVALID_IDX) {
     478     1923254 :                         ht->nInternalPointer = h;
     479             :                 }
     480     5615171 :                 if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     481     5615159 :                         ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     482             :                 }
     483     5615171 :                 p->h = h;
     484     5615171 :                 p->key = NULL;
     485     5615171 :                 ZVAL_COPY_VALUE(&p->val, pData);
     486             : 
     487     5615171 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     488             : 
     489     5615171 :                 return &p->val;
     490             : 
     491             : convert_to_hash:
     492         764 :                 zend_hash_packed_to_hash(ht);
     493     1892821 :         } else if ((flag & HASH_ADD_NEW) == 0) {
     494     1413320 :                 p = zend_hash_index_find_bucket(ht, h);
     495     1413320 :                 if (p) {
     496       10251 :                         if (flag & HASH_ADD) {
     497           5 :                                 return NULL;
     498             :                         }
     499             :                         ZEND_ASSERT(&p->val != pData);
     500       10246 :                         HANDLE_BLOCK_INTERRUPTIONS();
     501       10246 :                         if (ht->pDestructor) {
     502       10201 :                                 ht->pDestructor(&p->val);
     503             :                         }
     504       10246 :                         ZVAL_COPY_VALUE(&p->val, pData);
     505       10246 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     506       10246 :                         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     507           1 :                                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     508             :                         }
     509       10246 :                         return &p->val;
     510             :                 }
     511             :         }
     512             : 
     513     1883334 :         ZEND_HASH_IF_FULL_DO_RESIZE(ht);                /* If the Hash table is full, resize it */
     514             : 
     515             : add_to_hash:
     516     1983892 :         HANDLE_BLOCK_INTERRUPTIONS();
     517     1983892 :         idx = ht->nNumUsed++;
     518     1983892 :         ht->nNumOfElements++;
     519     1983892 :         if (ht->nInternalPointer == INVALID_IDX) {
     520      168642 :                 ht->nInternalPointer = idx;
     521             :         }
     522     1983892 :         if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
     523      614707 :                 ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
     524             :         }
     525     1983892 :         p = ht->arData + idx;
     526     1983892 :         p->h = h;
     527     1983892 :         p->key = NULL;
     528     1983892 :         nIndex = h & ht->nTableMask;
     529     1983892 :         ZVAL_COPY_VALUE(&p->val, pData);
     530     1983892 :         Z_NEXT(p->val) = ht->arHash[nIndex];
     531     1983892 :         ht->arHash[nIndex] = idx;
     532     1983892 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     533             : 
     534     1983892 :         return &p->val;
     535             : }
     536             : 
     537           0 : ZEND_API zval *_zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
     538             : {
     539           0 :         return _zend_hash_index_add_or_update_i(ht, h, pData, flag ZEND_FILE_LINE_RELAY_CC);
     540             : }
     541             : 
     542         100 : ZEND_API zval *_zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     543             : {
     544         100 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD ZEND_FILE_LINE_RELAY_CC);
     545             : }
     546             : 
     547      914113 : ZEND_API zval *_zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     548             : {
     549      914113 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC);
     550             : }
     551             : 
     552     2421436 : ZEND_API zval *_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData ZEND_FILE_LINE_DC)
     553             : {
     554     2421436 :         return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
     555             : }
     556             : 
     557     3825028 : ZEND_API zval *_zend_hash_next_index_insert(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     558             : {
     559     7650056 :         return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT ZEND_FILE_LINE_RELAY_CC);
     560             : }
     561             : 
     562      452281 : ZEND_API zval *_zend_hash_next_index_insert_new(HashTable *ht, zval *pData ZEND_FILE_LINE_DC)
     563             : {
     564      904562 :         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);
     565             : }
     566             : 
     567     6282662 : static void zend_hash_do_resize(HashTable *ht)
     568             : {
     569             : #ifdef ZEND_SIGNALS
     570             :         TSRMLS_FETCH();
     571             : #endif
     572             : 
     573             :         IS_CONSISTENT(ht);
     574             : 
     575     6282662 :         if (ht->nNumUsed < ht->nNumOfElements) {
     576           0 :                 HANDLE_BLOCK_INTERRUPTIONS();
     577           0 :                 zend_hash_rehash(ht);
     578           0 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     579     6282662 :         } else if ((ht->nTableSize << 1) > 0) {     /* Let's double the table size */
     580     6282662 :                 HANDLE_BLOCK_INTERRUPTIONS();
     581     6282662 :                 ht->arData = (Bucket *) safe_perealloc(ht->arData, (ht->nTableSize << 1), sizeof(Bucket) + sizeof(uint32_t), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
     582     6282662 :                 ht->arHash = (uint32_t*)(ht->arData + (ht->nTableSize << 1));
     583     6282662 :                 ht->nTableSize = (ht->nTableSize << 1);
     584     6282662 :                 ht->nTableMask = ht->nTableSize - 1;
     585     6282662 :                 zend_hash_rehash(ht);
     586     6282662 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
     587             :         }
     588     6282662 : }
     589             : 
     590     6393075 : ZEND_API int zend_hash_rehash(HashTable *ht)
     591             : {
     592             :         Bucket *p;
     593             :         uint32_t nIndex, i, j;
     594             : 
     595             :         IS_CONSISTENT(ht);
     596             : 
     597     6393075 :         if (UNEXPECTED(ht->nNumOfElements == 0)) {
     598           3 :                 if (ht->nTableMask) {
     599           0 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
     600             :                 }
     601           3 :                 return SUCCESS;
     602             :         }
     603             : 
     604     6393072 :         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
     605   397810389 :         for (i = 0, j = 0; i < ht->nNumUsed; i++) {
     606   391417317 :                 p = ht->arData + i;
     607   782834634 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     608   391361753 :                 if (i != j) {
     609      127939 :                         ht->arData[j] = ht->arData[i];
     610      127939 :                         if (ht->nInternalPointer == i) {
     611        1065 :                                 ht->nInternalPointer = j;
     612             :                         }
     613             :                 }
     614   391361753 :                 nIndex = ht->arData[j].h & ht->nTableMask;
     615   391361753 :                 Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
     616   391361753 :                 ht->arHash[nIndex] = j;
     617   391361753 :                 j++;
     618             :         }
     619     6393072 :         ht->nNumUsed = j;
     620     6393072 :         return SUCCESS;
     621             : }
     622             : 
     623             : static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
     624             : {
     625    53486783 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     626    53382382 :                 if (prev) {
     627     2977679 :                         Z_NEXT(prev->val) = Z_NEXT(p->val);
     628             :                 } else {
     629    50404703 :                         ht->arHash[p->h & ht->nTableMask] = Z_NEXT(p->val);
     630             :                 }
     631             :         }
     632    53486783 :         if (ht->nNumUsed - 1 == idx) {
     633             :                 do {
     634     3686384 :                         ht->nNumUsed--;
     635     7202797 :                 } while (ht->nNumUsed > 0 && (Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF));
     636             :         }
     637    53486783 :         ht->nNumOfElements--;
     638    53486783 :         if (ht->nInternalPointer == idx) {
     639             :                 while (1) {
     640    47543952 :                         idx++;
     641    47543952 :                         if (idx >= ht->nNumUsed) {
     642      169962 :                                 ht->nInternalPointer = INVALID_IDX;
     643             :                                 break;
     644    94747980 :                         } else if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
     645     3011732 :                                 ht->nInternalPointer = idx;
     646             :                                 break;
     647             :                         }
     648             :                 }
     649             :         }
     650    53486783 :         if (p->key) {
     651    53215767 :                 zend_string_release(p->key);
     652             :         }
     653    53486783 :         if (ht->pDestructor) {
     654             :                 zval tmp;
     655    52697780 :                 ZVAL_COPY_VALUE(&tmp, &p->val);
     656    52697780 :                 ZVAL_UNDEF(&p->val);
     657    52697780 :                 ht->pDestructor(&tmp);
     658             :         } else {
     659      789003 :                 ZVAL_UNDEF(&p->val);
     660             :         }
     661             : }
     662             : 
     663             : static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
     664             : {
     665     7391094 :         Bucket *prev = NULL;
     666             : 
     667     7391094 :         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     668     7379106 :                 uint32_t nIndex = p->h & ht->nTableMask;
     669     7379106 :                 uint32_t i = ht->arHash[nIndex];
     670             : 
     671     7379106 :                 if (i != idx) {
     672      313199 :                         prev = ht->arData + i;
     673      354887 :                         while (Z_NEXT(prev->val) != idx) {
     674       41688 :                                 i = Z_NEXT(prev->val);
     675       41688 :                                 prev = ht->arData + i;
     676             :                         }
     677             :                 }
     678             :         }
     679             : 
     680             :         _zend_hash_del_el_ex(ht, idx, p, prev);
     681             : }
     682             : 
     683    45981360 : ZEND_API int zend_hash_del(HashTable *ht, zend_string *key)
     684             : {
     685             :         zend_ulong h;
     686             :         uint32_t nIndex;
     687             :         uint32_t idx;
     688             :         Bucket *p;
     689    45981360 :         Bucket *prev = NULL;
     690             : #ifdef ZEND_SIGNALS
     691             :         TSRMLS_FETCH();
     692             : #endif
     693             : 
     694             :         IS_CONSISTENT(ht);
     695             : 
     696    45981360 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     697           7 :                 return FAILURE;
     698             :         }
     699             : 
     700    45981353 :         h = zend_string_hash_val(key);
     701    45981353 :         nIndex = h & ht->nTableMask;
     702             : 
     703    45981353 :         idx = ht->arHash[nIndex];
     704    94767472 :         while (idx != INVALID_IDX) {
     705    47962889 :                 p = ht->arData + idx;
     706   231281281 :                 if ((p->key == key) ||
     707    47933138 :                         (p->h == h &&
     708    45128418 :                      p->key &&
     709    45128418 :                      p->key->len == key->len &&
     710    45128418 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     711    45158123 :                         HANDLE_BLOCK_INTERRUPTIONS();
     712             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     713    45158123 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     714    45158123 :                         return SUCCESS;
     715             :                 }
     716     2804766 :                 prev = p;
     717     2804766 :                 idx = Z_NEXT(p->val);
     718             :         }
     719      823230 :         return FAILURE;
     720             : }
     721             : 
     722         380 : ZEND_API int zend_hash_del_ind(HashTable *ht, zend_string *key)
     723             : {
     724             :         zend_ulong h;
     725             :         uint32_t nIndex;
     726             :         uint32_t idx;
     727             :         Bucket *p;
     728         380 :         Bucket *prev = NULL;
     729             : #ifdef ZEND_SIGNALS
     730             :         TSRMLS_FETCH();
     731             : #endif
     732             : 
     733             :         IS_CONSISTENT(ht);
     734             : 
     735         380 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     736           0 :                 return FAILURE;
     737             :         }
     738             : 
     739         380 :         h = zend_string_hash_val(key);
     740         380 :         nIndex = h & ht->nTableMask;
     741             : 
     742         380 :         idx = ht->arHash[nIndex];
     743         769 :         while (idx != INVALID_IDX) {
     744         208 :                 p = ht->arData + idx;
     745         897 :                 if ((p->key == key) ||
     746         179 :                         (p->h == h &&
     747         170 :                      p->key &&
     748         170 :                      p->key->len == key->len &&
     749         170 :                      memcmp(p->key->val, key->val, key->len) == 0)) {
     750         398 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
     751          14 :                                 zval *data = Z_INDIRECT(p->val);
     752             : 
     753          14 :                                 if (Z_TYPE_P(data) == IS_UNDEF) {
     754           0 :                                         return FAILURE;
     755             :                                 } else {
     756          14 :                                         if (ht->pDestructor) {
     757          14 :                                                 ht->pDestructor(data);
     758             :                                         }
     759          14 :                                         ZVAL_UNDEF(data);
     760             :                                 }
     761             :                         } else {
     762         185 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     763             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
     764         185 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     765             :                         }
     766         199 :                         return SUCCESS;
     767             :                 }
     768           9 :                 prev = p;
     769           9 :                 idx = Z_NEXT(p->val);
     770             :         }
     771         181 :         return FAILURE;
     772             : }
     773             : 
     774      723764 : ZEND_API int zend_hash_str_del(HashTable *ht, const char *str, size_t len)
     775             : {
     776             :         zend_ulong h;
     777             :         uint32_t nIndex;
     778             :         uint32_t idx;
     779             :         Bucket *p;
     780      723764 :         Bucket *prev = NULL;
     781             : #ifdef ZEND_SIGNALS
     782             :         TSRMLS_FETCH();
     783             : #endif
     784             : 
     785             :         IS_CONSISTENT(ht);
     786             : 
     787      723764 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     788           0 :                 return FAILURE;
     789             :         }
     790             : 
     791      723764 :         h = zend_inline_hash_func(str, len);
     792      723764 :         nIndex = h & ht->nTableMask;
     793             : 
     794      723764 :         idx = ht->arHash[nIndex];
     795     1489045 :         while (idx != INVALID_IDX) {
     796      741845 :                 p = ht->arData + idx;
     797     2842829 :                 if ((p->h == h) 
     798             :                          && p->key
     799     1400656 :                          && (p->key->len == len)
     800      700328 :                          && !memcmp(p->key->val, str, len)) {
     801     1400656 :                         if (Z_TYPE(p->val) == IS_INDIRECT) {
     802           0 :                                 zval *data = Z_INDIRECT(p->val);
     803             : 
     804           0 :                                 if (Z_TYPE_P(data) == IS_UNDEF) {
     805           0 :                                         return FAILURE;
     806             :                                 } else {
     807           0 :                                         if (ht->pDestructor) {
     808           0 :                                                 ht->pDestructor(data);
     809             :                                         }
     810           0 :                                         ZVAL_UNDEF(data);
     811             :                                 }
     812             :                         } else {
     813      700328 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     814             :                                 _zend_hash_del_el_ex(ht, idx, p, prev);
     815      700328 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     816             :                         }
     817      700328 :                         return SUCCESS;
     818             :                 }
     819       41517 :                 prev = p;
     820       41517 :                 idx = Z_NEXT(p->val);
     821             :         }
     822       23436 :         return FAILURE;
     823             : }
     824             : 
     825           0 : ZEND_API int zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
     826             : {
     827             :         zend_ulong h;
     828             :         uint32_t nIndex;
     829             :         uint32_t idx;
     830             :         Bucket *p;
     831           0 :         Bucket *prev = NULL;
     832             : #ifdef ZEND_SIGNALS
     833             :         TSRMLS_FETCH();
     834             : #endif
     835             : 
     836             :         IS_CONSISTENT(ht);
     837             : 
     838           0 :         h = zend_inline_hash_func(str, len);
     839           0 :         nIndex = h & ht->nTableMask;
     840             : 
     841           0 :         idx = ht->arHash[nIndex];
     842           0 :         while (idx != INVALID_IDX) {
     843           0 :                 p = ht->arData + idx;
     844           0 :                 if ((p->h == h) 
     845             :                          && p->key
     846           0 :                          && (p->key->len == len)
     847           0 :                          && !memcmp(p->key->val, str, len)) {
     848           0 :                         HANDLE_BLOCK_INTERRUPTIONS();
     849             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     850           0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     851           0 :                         return SUCCESS;
     852             :                 }
     853           0 :                 prev = p;
     854           0 :                 idx = Z_NEXT(p->val);
     855             :         }
     856           0 :         return FAILURE;
     857             : }
     858             : 
     859      244421 : ZEND_API int zend_hash_index_del(HashTable *ht, zend_ulong h)
     860             : {
     861             :         uint32_t nIndex;
     862             :         uint32_t idx;
     863             :         Bucket *p;
     864      244421 :         Bucket *prev = NULL;
     865             : #ifdef ZEND_SIGNALS
     866             :         TSRMLS_FETCH();
     867             : #endif
     868             : 
     869             :         IS_CONSISTENT(ht);
     870             : 
     871      244421 :         if (ht->u.flags & HASH_FLAG_PACKED) {
     872       98579 :                 if (h < ht->nNumUsed) {
     873       92420 :                         p = ht->arData + h;
     874      184840 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
     875       92413 :                                 HANDLE_BLOCK_INTERRUPTIONS();
     876       92413 :                                 _zend_hash_del_el_ex(ht, h, p, NULL);
     877       92413 :                                 HANDLE_UNBLOCK_INTERRUPTIONS();
     878       92413 :                                 return SUCCESS;
     879             :                         }
     880             :                 }
     881        6166 :                 return FAILURE;
     882             :         }
     883      145842 :         nIndex = h & ht->nTableMask;
     884             : 
     885      145842 :         idx = ht->arHash[nIndex];
     886      291942 :         while (idx != INVALID_IDX) {
     887      144898 :                 p = ht->arData + idx;
     888      144898 :                 if ((p->h == h) && (p->key == NULL)) {
     889      144640 :                         HANDLE_BLOCK_INTERRUPTIONS();
     890             :                         _zend_hash_del_el_ex(ht, idx, p, prev);
     891      144640 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
     892      144640 :                         return SUCCESS;
     893             :                 }
     894         258 :                 prev = p;
     895         258 :                 idx = Z_NEXT(p->val);
     896             :         }
     897        1202 :         return FAILURE;
     898             : }
     899             : 
     900    17968323 : ZEND_API void zend_hash_destroy(HashTable *ht)
     901             : {
     902             :         Bucket *p, *end;
     903             : 
     904             :         IS_CONSISTENT(ht);
     905             : 
     906    17968323 :         if (ht->nNumUsed) {
     907     9810503 :                 p = ht->arData;
     908     9810503 :                 end = p + ht->nNumUsed;
     909     9810503 :                 if (ht->pDestructor) {
     910             :                         SET_INCONSISTENT(HT_IS_DESTROYING);
     911             : 
     912     9517489 :                         if (ht->u.flags & HASH_FLAG_PACKED) {
     913             :                                 do {
     914    19437130 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
     915     7980379 :                                                 ht->pDestructor(&p->val);
     916             :                                         }
     917     9718562 :                                 } while (++p != end);
     918             :                         } else {
     919             :                                 do {
     920   647558832 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
     921   274109095 :                                                 ht->pDestructor(&p->val);
     922   274109095 :                                                 if (EXPECTED(p->key)) {
     923   273509062 :                                                         zend_string_release(p->key);
     924             :                                                 }
     925             :                                         }
     926   323779416 :                                 } while (++p != end);
     927             :                         }
     928             :                 
     929             :                         SET_INCONSISTENT(HT_DESTROYED);
     930             :                 } else {
     931      293014 :                         if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     932             :                                 do {
     933    21202636 :                                         if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
     934    10519150 :                                                 if (EXPECTED(p->key)) {
     935     9261930 :                                                         zend_string_release(p->key);
     936             :                                                 }
     937             :                                         }
     938    10601318 :                                 } while (++p != end);
     939             :                         }
     940             :                 }
     941     8157820 :         } else if (EXPECTED(!ht->nTableMask)) {
     942     8088085 :                 return;
     943             :         }
     944     9880235 :         pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
     945             : }
     946             : 
     947             : 
     948      137950 : ZEND_API void zend_hash_clean(HashTable *ht)
     949             : {
     950             :         uint32_t idx;
     951             :         Bucket *p;
     952             : 
     953             :         IS_CONSISTENT(ht);
     954             : 
     955     2159302 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
     956     2021352 :                 p = ht->arData + idx;
     957     4042704 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     958     2021321 :                 if (ht->pDestructor) {
     959     1990959 :                         ht->pDestructor(&p->val);
     960             :                 }
     961     2021321 :                 if (p->key) {
     962     2018489 :                         zend_string_release(p->key);
     963             :                 }
     964             :         }
     965      137950 :         ht->nNumUsed = 0;
     966      137950 :         ht->nNumOfElements = 0;
     967      137950 :         ht->nNextFreeElement = 0;
     968      137950 :         ht->nInternalPointer = INVALID_IDX;
     969      137950 :         if (ht->nTableMask) {
     970       96453 :                 if (!(ht->u.flags & HASH_FLAG_PACKED)) {
     971       96438 :                         memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));       
     972             :                 }
     973             :         }
     974      137950 : }
     975             : 
     976             : /* This function is used by the various apply() functions.
     977             :  * It deletes the passed bucket, and returns the address of the
     978             :  * next bucket.  The hash *may* be altered during that time, the
     979             :  * returned value will still be valid.
     980             :  */
     981     7391094 : static void zend_hash_apply_deleter(HashTable *ht, uint32_t idx, Bucket *p)
     982             : {
     983             : #ifdef ZEND_SIGNALS
     984             :         TSRMLS_FETCH();
     985             : #endif
     986             : 
     987     7391094 :         HANDLE_BLOCK_INTERRUPTIONS();
     988             :         _zend_hash_del_el(ht, idx, p);
     989     7391094 :         HANDLE_UNBLOCK_INTERRUPTIONS();
     990     7391094 : }
     991             : 
     992             : 
     993           0 : ZEND_API void zend_hash_graceful_destroy(HashTable *ht)
     994             : {
     995             :         uint32_t idx;
     996             :         Bucket *p;
     997             : 
     998             :         IS_CONSISTENT(ht);
     999             : 
    1000           0 :         for (idx = 0; idx < ht->nNumUsed; idx++) {                
    1001           0 :                 p = ht->arData + idx;
    1002           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1003           0 :                 zend_hash_apply_deleter(ht, idx, p);
    1004             :         }
    1005           0 :         if (ht->nTableMask) {
    1006           0 :                 pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1007             :         }
    1008             : 
    1009             :         SET_INCONSISTENT(HT_DESTROYED);
    1010           0 : }
    1011             : 
    1012       82204 : ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht)
    1013             : {
    1014             :         uint32_t idx;
    1015             :         Bucket *p;
    1016             : 
    1017             :         IS_CONSISTENT(ht);
    1018             : 
    1019       82204 :         idx = ht->nNumUsed;
    1020     1923227 :         while (idx > 0) {
    1021     1758819 :                 idx--;
    1022     1758819 :                 p = ht->arData + idx;
    1023     3517638 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1024     1713228 :                 zend_hash_apply_deleter(ht, idx, p);
    1025             :         }
    1026             : 
    1027       82204 :         if (ht->nTableMask) {
    1028       62489 :                 pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
    1029             :         }
    1030             : 
    1031             :         SET_INCONSISTENT(HT_DESTROYED);
    1032       82204 : }
    1033             : 
    1034             : /* This is used to recurse elements and selectively delete certain entries 
    1035             :  * from a hashtable. apply_func() receives the data and decides if the entry 
    1036             :  * should be deleted or recursion should be stopped. The following three 
    1037             :  * return codes are possible:
    1038             :  * ZEND_HASH_APPLY_KEEP   - continue
    1039             :  * ZEND_HASH_APPLY_STOP   - stop iteration
    1040             :  * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
    1041             :  */
    1042             : 
    1043       91770 : ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
    1044             : {
    1045             :         uint32_t idx;
    1046             :         Bucket *p;
    1047             :         int result;
    1048             : 
    1049             :         IS_CONSISTENT(ht);
    1050             : 
    1051       91770 :         HASH_PROTECT_RECURSION(ht);
    1052     1698453 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1053     1606685 :                 p = ht->arData + idx;
    1054     3213370 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1055             :                 
    1056     1606670 :                 result = apply_func(&p->val TSRMLS_CC);
    1057             :                 
    1058     1606668 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1059      107671 :                         zend_hash_apply_deleter(ht, idx, p);
    1060             :                 }
    1061     1606668 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1062           0 :                         break;
    1063             :                 }
    1064             :         }
    1065       91768 :         HASH_UNPROTECT_RECURSION(ht);
    1066       91768 : }
    1067             : 
    1068             : 
    1069      647404 : ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC)
    1070             : {
    1071             :     uint32_t idx;
    1072             :         Bucket *p;
    1073             :         int result;
    1074             : 
    1075             :         IS_CONSISTENT(ht);
    1076             : 
    1077      647404 :         HASH_PROTECT_RECURSION(ht);
    1078   189617453 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1079   188974201 :                 p = ht->arData + idx;
    1080   377948402 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1081             : 
    1082   148673452 :                 result = apply_func(&p->val, argument TSRMLS_CC);
    1083             :                 
    1084   148673452 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1085     5467581 :                         zend_hash_apply_deleter(ht, idx, p);
    1086             :                 }
    1087   148673452 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1088        4152 :                         break;
    1089             :                 }
    1090             :         }
    1091      647404 :         HASH_UNPROTECT_RECURSION(ht);
    1092      647404 : }
    1093             : 
    1094             : 
    1095         715 : ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int num_args, ...)
    1096             : {
    1097             :         uint32_t idx;
    1098             :         Bucket *p;
    1099             :         va_list args;
    1100             :         zend_hash_key hash_key;
    1101             :         int result;
    1102             : 
    1103             :         IS_CONSISTENT(ht);
    1104             : 
    1105         715 :         HASH_PROTECT_RECURSION(ht);
    1106             : 
    1107     1100069 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1108     1099354 :                 p = ht->arData + idx;
    1109     2198708 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1110     1099265 :                 va_start(args, num_args);
    1111     1099265 :                 hash_key.h = p->h;
    1112     1099265 :                 hash_key.key = p->key;
    1113             : 
    1114     1099265 :                 result = apply_func(&p->val TSRMLS_CC, num_args, args, &hash_key);
    1115             : 
    1116     1099265 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1117          24 :                         zend_hash_apply_deleter(ht, idx, p);
    1118             :                 }
    1119     1099265 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1120           0 :                         va_end(args);
    1121           0 :                         break;
    1122             :                 }
    1123     1099265 :                 va_end(args);
    1124             :         }
    1125             : 
    1126         715 :         HASH_UNPROTECT_RECURSION(ht);
    1127         715 : }
    1128             : 
    1129             : 
    1130      107206 : ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
    1131             : {
    1132             :         uint32_t idx;
    1133             :         Bucket *p;
    1134             :         int result;
    1135             : 
    1136             :         IS_CONSISTENT(ht);
    1137             : 
    1138      107206 :         HASH_PROTECT_RECURSION(ht);
    1139      107206 :         idx = ht->nNumUsed;
    1140      719216 :         while (idx > 0) {
    1141      566304 :                 idx--;
    1142      566304 :                 p = ht->arData + idx;
    1143     1132608 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1144             :                 
    1145      512709 :                 result = apply_func(&p->val TSRMLS_CC);
    1146             : 
    1147      512709 :                 if (result & ZEND_HASH_APPLY_REMOVE) {
    1148      102590 :                         zend_hash_apply_deleter(ht, idx, p);
    1149             :                 }
    1150      512709 :                 if (result & ZEND_HASH_APPLY_STOP) {
    1151       61500 :                         break;
    1152             :                 }
    1153             :         }
    1154      107206 :         HASH_UNPROTECT_RECURSION(ht);
    1155      107206 : }
    1156             : 
    1157             : 
    1158         463 : ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
    1159             : {
    1160             :     uint32_t idx;
    1161             :         Bucket *p;
    1162             :         zval *new_entry, *data;
    1163             :         zend_bool setTargetPointer;
    1164             : 
    1165             :         IS_CONSISTENT(source);
    1166             :         IS_CONSISTENT(target);
    1167             : 
    1168         463 :         setTargetPointer = (target->nInternalPointer == INVALID_IDX);
    1169       11854 :         for (idx = 0; idx < source->nNumUsed; idx++) {            
    1170       11391 :                 p = source->arData + idx;
    1171       22782 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1172             : 
    1173       11391 :                 if (setTargetPointer && source->nInternalPointer == idx) {
    1174         312 :                         target->nInternalPointer = INVALID_IDX;
    1175             :                 }
    1176             :                 /* INDIRECT element may point to UNDEF-ined slots */
    1177       11391 :                 data = &p->val;
    1178       11391 :                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1179          96 :                         data = Z_INDIRECT_P(data);
    1180          96 :                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1181           0 :                                 continue;
    1182             :                         }
    1183             :                 }
    1184       11391 :                 if (p->key) {
    1185       11302 :                         new_entry = zend_hash_update(target, p->key, data);
    1186             :                 } else {
    1187          89 :                         new_entry = zend_hash_index_update(target, p->h, data);
    1188             :                 }
    1189       11391 :                 if (pCopyConstructor) {
    1190         411 :                         pCopyConstructor(new_entry);
    1191             :                 }
    1192             :         }
    1193         463 :         if (target->nInternalPointer == INVALID_IDX && target->nNumOfElements > 0) {
    1194           0 :                 idx = 0;
    1195           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1196           0 :                         idx++;
    1197             :                 }
    1198           0 :                 target->nInternalPointer = idx;
    1199             :         }
    1200         463 : }
    1201             : 
    1202             : 
    1203     1292934 : ZEND_API void zend_array_dup(HashTable *target, HashTable *source)
    1204             : {
    1205             :     uint32_t idx, target_idx;
    1206             :         uint32_t nIndex;
    1207             :         Bucket *p, *q;
    1208             :         zval *data;
    1209             : 
    1210             :         IS_CONSISTENT(source);
    1211             :         
    1212     1292934 :         target->nTableMask = source->nTableMask;
    1213     1292934 :         target->nTableSize = source->nTableSize;
    1214     1292934 :         target->pDestructor = source->pDestructor;
    1215     1292934 :         target->nInternalPointer = INVALID_IDX;
    1216     1292934 :         target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
    1217             : 
    1218     1292934 :         target_idx = 0;
    1219     1292934 :         if (target->nTableMask) {
    1220     1131402 :                 if (target->u.flags & HASH_FLAG_PACKED) {
    1221     1074172 :                         target->nNumUsed = source->nNumUsed;
    1222     1074172 :                         target->nNumOfElements = source->nNumOfElements;
    1223     1074172 :                         target->nNextFreeElement = source->nNextFreeElement;
    1224     1074172 :                         target->arData = (Bucket *) safe_pemalloc(target->nTableSize, sizeof(Bucket), 0, 0);
    1225     1074172 :                         target->arHash = (uint32_t*)&uninitialized_bucket;
    1226     1074172 :                         target->nInternalPointer = source->nInternalPointer;
    1227             : 
    1228     4444364 :                         for (idx = 0; idx < source->nNumUsed; idx++) {            
    1229     3370192 :                                 p = source->arData + idx;
    1230     3370192 :                                 q = target->arData + idx;
    1231     6740384 :                                 if (Z_TYPE(p->val) == IS_UNDEF) {
    1232      847271 :                                         ZVAL_UNDEF(&q->val);
    1233      847271 :                                         continue;
    1234             :                                 }
    1235             :                                 /* INDIRECT element may point to UNDEF-ined slots */
    1236     2522921 :                                 data = &p->val;
    1237     2522921 :                                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1238           0 :                                         data = Z_INDIRECT_P(data);
    1239           0 :                                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1240           0 :                                                 ZVAL_UNDEF(&q->val);
    1241           0 :                                                 continue;
    1242             :                                         }
    1243             :                                 }
    1244             : 
    1245     2522921 :                                 q->h = p->h;
    1246     2522921 :                                 q->key = NULL;
    1247     2522921 :                                 if (Z_OPT_REFCOUNTED_P(data)) {
    1248     2391856 :                                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
    1249           1 :                                                 ZVAL_COPY(&q->val, Z_REFVAL_P(data));
    1250             :                                         } else {
    1251     2391833 :                                                 ZVAL_COPY(&q->val, data);
    1252             :                                         }
    1253             :                                 } else {
    1254      131087 :                                         ZVAL_COPY_VALUE(&q->val, data);
    1255             :                                 }
    1256             :                         }
    1257     2148344 :                         if (target->nNumOfElements > 0 &&
    1258     1074172 :                             target->nInternalPointer == INVALID_IDX) {
    1259          41 :                                 idx = 0;
    1260         145 :                                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1261          11 :                                         idx++;
    1262             :                                 }
    1263          41 :                                 target->nInternalPointer = idx;
    1264             :                         }
    1265             :                 } else {
    1266       57230 :                         target->nNextFreeElement = source->nNextFreeElement;
    1267       57230 :                         target->arData = (Bucket *) safe_pemalloc(target->nTableSize, sizeof(Bucket) + sizeof(uint32_t), 0, 0);
    1268       57230 :                         target->arHash = (uint32_t*)(target->arData + target->nTableSize);
    1269       57230 :                         memset(target->arHash, INVALID_IDX, target->nTableSize * sizeof(uint32_t));
    1270             : 
    1271      773529 :                         for (idx = 0; idx < source->nNumUsed; idx++) {            
    1272      716299 :                                 p = source->arData + idx;
    1273     1432598 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1274             :                                 /* INDIRECT element may point to UNDEF-ined slots */
    1275      716295 :                                 data = &p->val;
    1276      716295 :                                 if (Z_TYPE_P(data) == IS_INDIRECT) {
    1277       29526 :                                         data = Z_INDIRECT_P(data);
    1278       29526 :                                         if (Z_TYPE_P(data) == IS_UNDEF) {
    1279        5179 :                                                 continue;
    1280             :                                         }
    1281             :                                 }
    1282             : 
    1283      711116 :                                 if (source->nInternalPointer == idx) {
    1284       44212 :                                         target->nInternalPointer = target_idx;
    1285             :                                 }
    1286             : 
    1287      711116 :                                 q = target->arData + target_idx;
    1288      711116 :                                 q->h = p->h;
    1289      711116 :                                 q->key = p->key;
    1290      711116 :                                 if (q->key) {
    1291      705477 :                                         zend_string_addref(q->key);
    1292             :                                 }
    1293      711116 :                                 nIndex = q->h & target->nTableMask;
    1294      711116 :                                 Z_NEXT(q->val) = target->arHash[nIndex];
    1295      711116 :                                 target->arHash[nIndex] = target_idx;
    1296      711116 :                                 if (Z_OPT_REFCOUNTED_P(data)) {
    1297      634168 :                                         if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
    1298          97 :                                                 ZVAL_COPY(&q->val, Z_REFVAL_P(data));
    1299             :                                         } else {
    1300      633428 :                                                 ZVAL_COPY(&q->val, data);
    1301             :                                         }
    1302             :                                 } else {
    1303       77591 :                                         ZVAL_COPY_VALUE(&q->val, data);
    1304             :                                 }
    1305      711116 :                                 target_idx++;
    1306             :                         }
    1307       57230 :                         target->nNumUsed = target_idx;
    1308       57230 :                         target->nNumOfElements = target_idx;
    1309      114440 :                         if (target->nNumOfElements > 0 &&
    1310       57210 :                             target->nInternalPointer == INVALID_IDX) {
    1311       12998 :                                 target->nInternalPointer = 0;
    1312             :                         }
    1313             :                 }
    1314             :         } else {
    1315      161532 :                 target->nNumUsed = 0;
    1316      161532 :                 target->nNumOfElements = 0;
    1317      161532 :                 target->nNextFreeElement = 0;
    1318      161532 :                 target->arData = NULL;
    1319      161532 :                 target->arHash = (uint32_t*)&uninitialized_bucket;
    1320             :         }
    1321     1292934 : }
    1322             : 
    1323             : 
    1324      184640 : ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite ZEND_FILE_LINE_DC)
    1325             : {
    1326             :     uint32_t idx;
    1327             :         Bucket *p;
    1328             :         zval *t;
    1329      184640 :         uint32_t mode = (overwrite?HASH_UPDATE:HASH_ADD);
    1330             : 
    1331             :         IS_CONSISTENT(source);
    1332             :         IS_CONSISTENT(target);
    1333             : 
    1334     3180177 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1335     2995537 :                 p = source->arData + idx;
    1336     5991074 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1337     2995537 :                 if (p->key) {
    1338     2995521 :                         t = _zend_hash_add_or_update(target, p->key, &p->val, mode ZEND_FILE_LINE_RELAY_CC);
    1339     2995521 :                         if (t && pCopyConstructor) {
    1340     2994939 :                                 pCopyConstructor(t);
    1341             :                         }
    1342             :                 } else {
    1343          16 :                         if ((mode==HASH_UPDATE || !zend_hash_index_exists(target, p->h))) {
    1344           6 :                                 t = zend_hash_index_update(target, p->h, &p->val);
    1345           6 :                                 if (t && pCopyConstructor) {
    1346           6 :                                         pCopyConstructor(t);
    1347             :                                 }
    1348             :                         }
    1349             :                 }
    1350             :         }
    1351      184640 :         if (target->nNumOfElements > 0) {
    1352      184638 :                 idx = 0;
    1353      553914 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1354           0 :                         idx++;
    1355             :                 }
    1356      184638 :                 target->nInternalPointer = idx;
    1357             :         }
    1358      184640 : }
    1359             : 
    1360             : 
    1361           0 : static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, zval *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
    1362             : {
    1363             :         zend_hash_key hash_key;
    1364             : 
    1365           0 :         hash_key.h = p->h;
    1366           0 :         hash_key.key = p->key;
    1367           0 :         return merge_checker_func(target, source_data, &hash_key, pParam);
    1368             : }
    1369             : 
    1370             : 
    1371           0 : ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam)
    1372             : {
    1373             :         uint32_t idx;
    1374             :         Bucket *p;
    1375             :         zval *t;
    1376             : 
    1377             :         IS_CONSISTENT(source);
    1378             :         IS_CONSISTENT(target);
    1379             : 
    1380           0 :         for (idx = 0; idx < source->nNumUsed; idx++) {
    1381           0 :                 p = source->arData + idx;
    1382           0 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1383           0 :                 if (zend_hash_replace_checker_wrapper(target, &p->val, p, pParam, pMergeSource)) {
    1384           0 :                         t = zend_hash_update(target, p->key, &p->val);
    1385           0 :                         if (t && pCopyConstructor) {
    1386           0 :                                 pCopyConstructor(t);
    1387             :                         }
    1388             :                 }
    1389             :         }
    1390           0 :         if (target->nNumOfElements > 0) {
    1391           0 :                 idx = 0;
    1392           0 :                 while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
    1393           0 :                         idx++;
    1394             :                 }
    1395           0 :                 target->nInternalPointer = idx;
    1396             :         }
    1397           0 : }
    1398             : 
    1399             : 
    1400             : /* Returns SUCCESS if found and FAILURE if not. The pointer to the
    1401             :  * data is returned in pData. The reason is that there's no reason
    1402             :  * someone using the hash table might not want to have NULL data
    1403             :  */
    1404    50960643 : ZEND_API zval *zend_hash_find(const HashTable *ht, zend_string *key)
    1405             : {
    1406             :         Bucket *p;
    1407             : 
    1408             :         IS_CONSISTENT(ht);
    1409             : 
    1410    50960643 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1411         797 :                 return NULL;
    1412             :         }
    1413             : 
    1414    50959846 :         p = zend_hash_find_bucket(ht, key);
    1415    50959846 :         return p ? &p->val : NULL;
    1416             : }
    1417             : 
    1418     2594800 : ZEND_API zval *zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
    1419             : {
    1420             :         zend_ulong h;
    1421             :         Bucket *p;
    1422             : 
    1423             :         IS_CONSISTENT(ht);
    1424             : 
    1425     2594800 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1426         171 :                 return NULL;
    1427             :         }
    1428             : 
    1429     2594629 :         h = zend_inline_hash_func(str, len);
    1430     2594629 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1431     2594629 :         return p ? &p->val : NULL;
    1432             : }
    1433             : 
    1434      554443 : ZEND_API zend_bool zend_hash_exists(const HashTable *ht, zend_string *key)
    1435             : {
    1436             :         Bucket *p;
    1437             : 
    1438             :         IS_CONSISTENT(ht);
    1439             : 
    1440      554443 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1441          55 :                 return 0;
    1442             :         }
    1443             : 
    1444      554388 :         p = zend_hash_find_bucket(ht, key);
    1445      554388 :         return p ? 1 : 0;
    1446             : }
    1447             : 
    1448      851320 : ZEND_API zend_bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
    1449             : {
    1450             :         zend_ulong h;
    1451             :         Bucket *p;
    1452             : 
    1453             :         IS_CONSISTENT(ht);
    1454             : 
    1455      851320 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1456           0 :                 return 0;
    1457             :         }
    1458             : 
    1459      851320 :         h = zend_inline_hash_func(str, len);
    1460      851320 :         p = zend_hash_str_find_bucket(ht, str, len, h);
    1461      851320 :         return p ? 1 : 0;
    1462             : }
    1463             : 
    1464     6153506 : ZEND_API zval *zend_hash_index_find(const HashTable *ht, zend_ulong h)
    1465             : {
    1466             :         Bucket *p;
    1467             : 
    1468             :         IS_CONSISTENT(ht);
    1469             : 
    1470     6153506 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1471     5006470 :                 if (h < ht->nNumUsed) {
    1472     4754992 :                         p = ht->arData + h;
    1473     9509984 :                         if (Z_TYPE(p->val) != IS_UNDEF) {
    1474     4754542 :                                 return &p->val;
    1475             :                         }
    1476             :                 }
    1477      251928 :                 return NULL;
    1478             :         }
    1479             : 
    1480     1147036 :         p = zend_hash_index_find_bucket(ht, h);
    1481     1147036 :         return p ? &p->val : NULL;
    1482             : }
    1483             : 
    1484             : 
    1485     1517886 : ZEND_API zend_bool zend_hash_index_exists(const HashTable *ht, zend_ulong h)
    1486             : {
    1487             :         Bucket *p;
    1488             : 
    1489             :         IS_CONSISTENT(ht);
    1490             : 
    1491     1517886 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1492          56 :                 if (h < ht->nNumUsed) {
    1493         102 :                         if (Z_TYPE(ht->arData[h].val) != IS_UNDEF) {
    1494          50 :                                 return 1;
    1495             :                         }
    1496             :                 }
    1497           6 :                 return 0;
    1498             :         }
    1499             : 
    1500     1517830 :         p = zend_hash_index_find_bucket(ht, h);
    1501     1517830 :         return p ? 1 : 0;
    1502             : }
    1503             : 
    1504             : 
    1505       21634 : ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
    1506             : {
    1507             :     uint32_t idx;
    1508             :         
    1509             :         IS_CONSISTENT(ht);
    1510       22136 :         for (idx = 0; idx < ht->nNumUsed; idx++) {
    1511       42554 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1512       20775 :                         *pos = idx;
    1513       20775 :                         return;
    1514             :                 }
    1515             :         }
    1516         859 :         *pos = INVALID_IDX;
    1517             : }
    1518             : 
    1519             : 
    1520             : /* This function will be extremely optimized by remembering 
    1521             :  * the end of the list
    1522             :  */
    1523          47 : ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
    1524             : {
    1525             :         uint32_t idx;
    1526             :         
    1527             :         IS_CONSISTENT(ht);
    1528             : 
    1529          47 :         idx = ht->nNumUsed;
    1530          94 :         while (idx > 0) {
    1531          45 :                 idx--;
    1532          90 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1533          45 :                         *pos = idx;
    1534          45 :                         return;
    1535             :                 }
    1536             :         }
    1537           2 :         *pos = INVALID_IDX;
    1538             : }
    1539             : 
    1540             : 
    1541       81533 : ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
    1542             : {
    1543       81533 :         uint32_t idx = *pos;
    1544             : 
    1545             :         IS_CONSISTENT(ht);
    1546             : 
    1547       81533 :         if (idx != INVALID_IDX) {
    1548             :                 while (1) {
    1549       81586 :                         idx++;
    1550       81586 :                         if (idx >= ht->nNumUsed) {
    1551       17071 :                                 *pos = INVALID_IDX;
    1552       17071 :                                 return SUCCESS;
    1553             :                         }
    1554      129030 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1555       64438 :                                 *pos = idx;
    1556       64438 :                                 return SUCCESS;
    1557             :                         }
    1558          77 :                 }
    1559             :         } else {
    1560          24 :                 return FAILURE;
    1561             :         }
    1562             : }
    1563             : 
    1564          21 : ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
    1565             : {
    1566          21 :         uint32_t idx = *pos;
    1567             : 
    1568             :         IS_CONSISTENT(ht);
    1569             : 
    1570          21 :         if (idx != INVALID_IDX) {
    1571          38 :                 while (idx > 0) {
    1572          14 :                         idx--;
    1573          28 :                         if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
    1574          14 :                                 *pos = idx;
    1575          14 :                                 return SUCCESS;
    1576             :                         }
    1577             :                 }
    1578           5 :                 *pos = INVALID_IDX;
    1579           5 :                 return SUCCESS;
    1580             :         } else {
    1581           2 :                 return FAILURE;
    1582             :         }
    1583             : }
    1584             : 
    1585             : 
    1586             : /* This function should be made binary safe  */
    1587       23195 : ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, zend_bool duplicate, HashPosition *pos)
    1588             : {
    1589       23195 :         uint32_t idx = *pos;
    1590             :         Bucket *p;
    1591             : 
    1592             :         IS_CONSISTENT(ht);
    1593       23195 :         if (idx != INVALID_IDX) {
    1594       22274 :                 p = ht->arData + idx;
    1595       22274 :                 if (p->key) {
    1596       20786 :                         if (duplicate) {
    1597           0 :                                 *str_index = zend_string_copy(p->key);
    1598             :                         } else {
    1599       20786 :                                 *str_index = p->key;
    1600             :                         }
    1601       20786 :                         return HASH_KEY_IS_STRING;
    1602             :                 } else {
    1603        1488 :                         *num_index = p->h;
    1604        1488 :                         return HASH_KEY_IS_LONG;
    1605             :                 }
    1606             :         }
    1607         921 :         return HASH_KEY_NON_EXISTENT;
    1608             : }
    1609             : 
    1610        3576 : ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
    1611             : {
    1612        3576 :         uint32_t idx = *pos;
    1613             :         Bucket *p;
    1614             : 
    1615             :         IS_CONSISTENT(ht);
    1616        3576 :         if (idx == INVALID_IDX) {
    1617          56 :                 ZVAL_NULL(key);
    1618             :         } else {
    1619        3520 :                 p = ht->arData + idx;
    1620        3520 :                 if (p->key) {
    1621         669 :                         ZVAL_STR_COPY(key, p->key);
    1622             :                 } else {
    1623        2851 :                         ZVAL_LONG(key, p->h);
    1624             :                 }
    1625             :         }
    1626        3576 : }
    1627             : 
    1628       68692 : ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
    1629             : {
    1630       68692 :     uint32_t idx = *pos;
    1631             :         Bucket *p;
    1632             : 
    1633             :         IS_CONSISTENT(ht);
    1634       68692 :         if (idx != INVALID_IDX) {
    1635       53529 :                 p = ht->arData + idx;
    1636       53529 :                 if (p->key) {
    1637       51003 :                         return HASH_KEY_IS_STRING;
    1638             :                 } else {
    1639        2526 :                         return HASH_KEY_IS_LONG;
    1640             :                 }
    1641             :         }
    1642       15163 :         return HASH_KEY_NON_EXISTENT;
    1643             : }
    1644             : 
    1645             : 
    1646       74892 : ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
    1647             : {
    1648       74892 :         uint32_t idx = *pos;
    1649             :         Bucket *p;
    1650             : 
    1651             :         IS_CONSISTENT(ht);
    1652       74892 :         if (idx != INVALID_IDX) {
    1653       73714 :                 p = ht->arData + idx;
    1654       73714 :                 return &p->val;
    1655             :         } else {
    1656        1178 :                 return NULL;
    1657             :         }
    1658             : }
    1659             : 
    1660       22214 : ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
    1661             :                                                         compare_func_t compar, zend_bool renumber TSRMLS_DC)
    1662             : {
    1663             :         Bucket *p;
    1664             :         uint32_t i, j;
    1665             : 
    1666             :         IS_CONSISTENT(ht);
    1667             : 
    1668       22214 :         if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */
    1669         288 :                 return SUCCESS;
    1670             :         }
    1671             : 
    1672       21926 :         if (ht->nNumUsed == ht->nNumOfElements) {
    1673       21816 :                 i = ht->nNumUsed;
    1674             :         } else {
    1675         787 :                 for (j = 0, i = 0; j < ht->nNumUsed; j++) {
    1676         677 :                         p = ht->arData + j;
    1677        1354 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1678         520 :                         if (i != j) {
    1679         504 :                                 ht->arData[i] = *p;
    1680             :                         }
    1681         520 :                         i++;
    1682             :                 }
    1683             :         }
    1684             : 
    1685       21926 :         (*sort_func)((void *) ht->arData, i, sizeof(Bucket), compar TSRMLS_CC);
    1686             : 
    1687       21925 :         HANDLE_BLOCK_INTERRUPTIONS();
    1688       21925 :         ht->nNumUsed = i;
    1689       21925 :         ht->nInternalPointer = 0;
    1690             : 
    1691       21925 :         if (renumber) {
    1692       15300 :                 for (j = 0; j < i; j++) {
    1693       15011 :                         p = ht->arData + j;
    1694       15011 :                         p->h = j;
    1695       15011 :                         if (p->key) {
    1696         288 :                                 zend_string_release(p->key);
    1697         288 :                                 p->key = NULL;
    1698             :                         }
    1699             :                 }
    1700             : 
    1701         289 :                 ht->nNextFreeElement = i;
    1702             :         }
    1703       21925 :         if (ht->u.flags & HASH_FLAG_PACKED) {
    1704         502 :                 if (!renumber) {
    1705         261 :                         zend_hash_packed_to_hash(ht);
    1706             :                 }
    1707             :         } else {
    1708       21423 :                 if (renumber) {
    1709          48 :                         ht->u.flags |= HASH_FLAG_PACKED;
    1710          48 :                         ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
    1711          48 :                         ht->arHash = (uint32_t*)&uninitialized_bucket;
    1712             :                 } else {
    1713       21375 :                         zend_hash_rehash(ht);
    1714             :                 }
    1715             :         }
    1716             : 
    1717       21925 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1718             : 
    1719       21925 :         return SUCCESS;
    1720             : }
    1721             : 
    1722             : 
    1723        1113 : ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC)
    1724             : {
    1725             :         uint32_t idx1, idx2;
    1726        1113 :         Bucket *p1, *p2 = NULL;
    1727             :         int result;
    1728             :         zval *pData1, *pData2;
    1729             : 
    1730             :         IS_CONSISTENT(ht1);
    1731             :         IS_CONSISTENT(ht2);
    1732             : 
    1733        1113 :         HASH_PROTECT_RECURSION(ht1); 
    1734        1113 :         HASH_PROTECT_RECURSION(ht2); 
    1735             : 
    1736        1113 :         result = ht1->nNumOfElements - ht2->nNumOfElements;
    1737        1113 :         if (result!=0) {
    1738         531 :                 HASH_UNPROTECT_RECURSION(ht1); 
    1739         531 :                 HASH_UNPROTECT_RECURSION(ht2); 
    1740         531 :                 return result;
    1741             :         }
    1742             : 
    1743        4100 :         for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
    1744        3692 :                 p1 = ht1->arData + idx1;
    1745        7384 :                 if (Z_TYPE(p1->val) == IS_UNDEF) continue;
    1746             : 
    1747        3679 :                 if (ordered) {
    1748             :                         while (1) {
    1749        1134 :                                 p2 = ht2->arData + idx2;
    1750        1134 :                                 if (idx2 == ht2->nNumUsed) {
    1751           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1752           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1753           0 :                                         return 1; /* That's not supposed to happen */
    1754             :                                 }
    1755        2268 :                                 if (Z_TYPE(p2->val) != IS_UNDEF) break;
    1756           1 :                                 idx2++;
    1757           1 :                         }                                               
    1758        1500 :                         if (p1->key == NULL && p2->key == NULL) { /* numeric indices */
    1759         368 :                                 result = p1->h - p2->h;
    1760         368 :                                 if (result != 0) {
    1761           1 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1762           1 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1763           1 :                                         return result;
    1764             :                                 }
    1765             :                         } else { /* string indices */
    1766         765 :                                 size_t len0 = (p1->key ? p1->key->len : 0);
    1767         765 :                                 size_t len1 = (p2->key ? p2->key->len : 0);
    1768         765 :                                 if (len0 != len1) {
    1769           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1770           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1771           0 :                                         return len0 > len1 ? 1 : -1;
    1772             :                                 }
    1773         765 :                                 result = memcmp(p1->key->val, p2->key->val, p1->key->len);
    1774         765 :                                 if (result != 0) {
    1775           0 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1776           0 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1777           0 :                                         return result;
    1778             :                                 }
    1779             :                         }
    1780        1132 :                         pData2 = &p2->val;
    1781             :                 } else {
    1782        2546 :                         if (p1->key == NULL) { /* numeric index */
    1783         219 :                                 pData2 = zend_hash_index_find(ht2, p1->h);
    1784         219 :                                 if (pData2 == NULL) {
    1785           4 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1786           4 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1787           4 :                                         return 1;
    1788             :                                 }
    1789             :                         } else { /* string index */
    1790        2327 :                                 pData2 = zend_hash_find(ht2, p1->key);
    1791        2327 :                                 if (pData2 == NULL) {
    1792          24 :                                         HASH_UNPROTECT_RECURSION(ht1); 
    1793          24 :                                         HASH_UNPROTECT_RECURSION(ht2); 
    1794          24 :                                         return 1;
    1795             :                                 }
    1796             :                         }
    1797             :                 }
    1798        3650 :                 pData1 = &p1->val;
    1799        3650 :                 if (Z_TYPE_P(pData1) == IS_INDIRECT) {
    1800         118 :                         pData1 = Z_INDIRECT_P(pData1);
    1801             :                 }
    1802        3650 :                 if (Z_TYPE_P(pData2) == IS_INDIRECT) {
    1803         118 :                         pData2 = Z_INDIRECT_P(pData2);
    1804             :                 }
    1805        3650 :                 if (Z_TYPE_P(pData1) == IS_UNDEF) {
    1806           0 :                         if (Z_TYPE_P(pData2) != IS_UNDEF) {
    1807           0 :                                 return -1;
    1808             :                         }
    1809        3650 :                 } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
    1810           0 :                         return 1;
    1811             :                 } else {
    1812        3650 :                         result = compar(pData1, pData2 TSRMLS_CC);
    1813             :                 }
    1814        3650 :                 if (result != 0) {
    1815         145 :                         HASH_UNPROTECT_RECURSION(ht1); 
    1816         145 :                         HASH_UNPROTECT_RECURSION(ht2); 
    1817         145 :                         return result;
    1818             :                 }
    1819        3505 :                 if (ordered) {
    1820        1128 :                         idx2++;
    1821             :                 }
    1822             :         }
    1823             :         
    1824         408 :         HASH_UNPROTECT_RECURSION(ht1); 
    1825         408 :         HASH_UNPROTECT_RECURSION(ht2); 
    1826         408 :         return 0;
    1827             : }
    1828             : 
    1829             : 
    1830          82 : ZEND_API zval *zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag TSRMLS_DC)
    1831             : {
    1832             :         uint32_t idx;
    1833             :         Bucket *p, *res;
    1834             : 
    1835             :         IS_CONSISTENT(ht);
    1836             : 
    1837          82 :         if (ht->nNumOfElements == 0 ) {
    1838           4 :                 return NULL;
    1839             :         }
    1840             : 
    1841          78 :         idx = 0;
    1842             :         while (1) {
    1843          78 :                 if (idx == ht->nNumUsed) {
    1844           0 :                         return NULL;
    1845             :                 }
    1846         156 :                 if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
    1847           0 :                 idx++;
    1848           0 :         }
    1849          78 :         res = ht->arData + idx;
    1850         376 :         for (; idx < ht->nNumUsed; idx++) {
    1851         298 :                 p = ht->arData + idx;
    1852         596 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    1853             :                 
    1854         298 :                 if (flag) {
    1855         229 :                         if (compar(res, p TSRMLS_CC) < 0) { /* max */
    1856          20 :                                 res = p;
    1857             :                         }
    1858             :                 } else {
    1859          69 :                         if (compar(res, p TSRMLS_CC) > 0) { /* min */
    1860           6 :                                 res = p;
    1861             :                         }
    1862             :                 }
    1863             :         }
    1864          78 :         return &res->val;
    1865             : }
    1866             : 
    1867      383122 : ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
    1868             : {
    1869      383122 :         register const char *tmp = key;
    1870             :         const char *end;
    1871             : 
    1872      383122 :         if (*tmp > '9') {
    1873           0 :                 return 0;
    1874      383122 :         } else if (*tmp < '0') {
    1875          59 :                 if (*tmp != '-') {
    1876           0 :                         return 0;
    1877             :                 }
    1878          59 :                 tmp++;
    1879          59 :                 if (*tmp > '9' || *tmp < '0') {
    1880           0 :                         return 0;
    1881             :                 }
    1882             :         }
    1883             : 
    1884             :         /* possibly a numeric index */
    1885      383122 :         end = key + length;
    1886             : 
    1887     1129224 :         if ((*end != '\0') /* not a null terminated string */
    1888      383122 :          || (*tmp == '0' && length > 1) /* numbers with leading zeros */
    1889      362980 :          || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
    1890             :          || (SIZEOF_ZEND_LONG == 4 &&
    1891             :              end - tmp == MAX_LENGTH_OF_LONG - 1 &&
    1892             :              *tmp > '2')) { /* overflow */
    1893       20169 :                 return 0;
    1894             :         }
    1895      362953 :         *idx = (*tmp - '0');
    1896             :         while (1) {
    1897     1444645 :                 ++tmp;
    1898     1444645 :                 if (tmp == end) {
    1899      362690 :                         if (*key == '-') {
    1900          28 :                                 if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
    1901           0 :                                         return 0;
    1902             :                                 }
    1903          28 :                                 *idx = 0 - *idx;
    1904      362662 :                         } else if (*idx > ZEND_LONG_MAX) { /* overflow */
    1905           0 :                                 return 0;
    1906             :                         }
    1907      362690 :                         return 1;
    1908             :                 }
    1909     2163647 :                 if (*tmp <= '9' && *tmp >= '0') {
    1910     1081692 :                         *idx = (*idx * 10) + (*tmp - '0');
    1911             :                 } else {
    1912         263 :                         return 0;
    1913             :                 }
    1914     1081692 :         }
    1915             : }
    1916             : 
    1917             : /*
    1918             :  * Local variables:
    1919             :  * tab-width: 4
    1920             :  * c-basic-offset: 4
    1921             :  * indent-tabs-mode: t
    1922             :  * End:
    1923             :  */

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:12 +0000 (4 hours ago)

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