Coverage Report

Created: 2022-10-14 11:23

/src/php-src/Zend/zend_hash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend Engine                                                          |
4
   +----------------------------------------------------------------------+
5
   | Copyright (c) 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@php.net>                                 |
16
   |          Zeev Suraski <zeev@php.net>                                 |
17
   |          Dmitry Stogov <dmitry@php.net>                              |
18
   +----------------------------------------------------------------------+
19
*/
20
21
#include "zend.h"
22
#include "zend_globals.h"
23
#include "zend_variables.h"
24
25
#if defined(__aarch64__)
26
# include <arm_neon.h>
27
#endif
28
29
#ifdef __SSE2__
30
# include <mmintrin.h>
31
# include <emmintrin.h>
32
#endif
33
34
#if ZEND_DEBUG
35
# define HT_ASSERT(ht, expr) \
36
  ZEND_ASSERT((expr) || (HT_FLAGS(ht) & HASH_FLAG_ALLOW_COW_VIOLATION))
37
#else
38
# define HT_ASSERT(ht, expr)
39
#endif
40
41
#define HT_ASSERT_RC1(ht) HT_ASSERT(ht, GC_REFCOUNT(ht) == 1)
42
43
0
#define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
44
45
#if ZEND_DEBUG
46
47
#define HT_OK         0x00
48
#define HT_IS_DESTROYING    0x01
49
#define HT_DESTROYED      0x02
50
#define HT_CLEANING       0x03
51
52
static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
53
{
54
  if ((HT_FLAGS(ht) & HASH_FLAG_CONSISTENCY) == HT_OK) {
55
    return;
56
  }
57
  switch (HT_FLAGS(ht) & HASH_FLAG_CONSISTENCY) {
58
    case HT_IS_DESTROYING:
59
      zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
60
      break;
61
    case HT_DESTROYED:
62
      zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
63
      break;
64
    case HT_CLEANING:
65
      zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
66
      break;
67
    default:
68
      zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
69
      break;
70
  }
71
  ZEND_UNREACHABLE();
72
}
73
#define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
74
#define SET_INCONSISTENT(n) do { \
75
    HT_FLAGS(ht) = (HT_FLAGS(ht) & ~HASH_FLAG_CONSISTENCY) | (n); \
76
  } while (0)
77
#else
78
#define IS_CONSISTENT(a)
79
#define SET_INCONSISTENT(n)
80
#endif
81
82
#define ZEND_HASH_IF_FULL_DO_RESIZE(ht)       \
83
2.26G
  if ((ht)->nNumUsed >= (ht)->nTableSize) {   \
84
217k
    zend_hash_do_resize(ht);          \
85
217k
  }
86
87
30.9k
ZEND_API void *zend_hash_str_find_ptr_lc(const HashTable *ht, const char *str, size_t len) {
88
30.9k
  void *result;
89
30.9k
  char *lc_str;
90
91
  /* Stack allocate small strings to improve performance */
92
30.9k
  ALLOCA_FLAG(use_heap)
93
94
30.9k
  lc_str = zend_str_tolower_copy(do_alloca(len + 1, use_heap), str, len);
95
30.9k
  result = zend_hash_str_find_ptr(ht, lc_str, len);
96
30.9k
  free_alloca(lc_str, use_heap);
97
98
30.9k
  return result;
99
30.9k
}
100
101
156k
ZEND_API void *zend_hash_find_ptr_lc(const HashTable *ht, zend_string *key) {
102
156k
  void *result;
103
156k
  zend_string *lc_key = zend_string_tolower(key);
104
156k
  result = zend_hash_find_ptr(ht, lc_key);
105
156k
  zend_string_release(lc_key);
106
156k
  return result;
107
156k
}
108
109
static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht);
110
111
static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize)
112
9.85M
{
113
#ifdef ZEND_WIN32
114
  unsigned long index;
115
#endif
116
117
  /* Use big enough power of 2 */
118
  /* size should be between HT_MIN_SIZE and HT_MAX_SIZE */
119
9.85M
  if (nSize <= HT_MIN_SIZE) {
120
8.84M
    return HT_MIN_SIZE;
121
1.00M
  } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) {
122
0
    zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket));
123
0
  }
124
125
#ifdef ZEND_WIN32
126
  if (BitScanReverse(&index, nSize - 1)) {
127
    return 0x2u << ((31 - index) ^ 0x1f);
128
  } else {
129
    /* nSize is ensured to be in the valid range, fall back to it
130
       rather than using an undefined bis scan result. */
131
    return nSize;
132
  }
133
#elif (defined(__GNUC__) || __has_builtin(__builtin_clz))  && defined(PHP_HAVE_BUILTIN_CLZ)
134
1.00M
  return 0x2u << (__builtin_clz(nSize - 1) ^ 0x1f);
135
#else
136
  nSize -= 1;
137
  nSize |= (nSize >> 1);
138
  nSize |= (nSize >> 2);
139
  nSize |= (nSize >> 4);
140
  nSize |= (nSize >> 8);
141
  nSize |= (nSize >> 16);
142
  return nSize + 1;
143
#endif
144
1.00M
}
145
146
static zend_always_inline void zend_hash_real_init_packed_ex(HashTable *ht)
147
115k
{
148
115k
  void *data;
149
150
115k
  if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
151
6.95k
    data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), 1);
152
108k
  } else if (EXPECTED(ht->nTableSize == HT_MIN_SIZE)) {
153
105k
    data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_MIN_MASK));
154
2.53k
  } else {
155
2.53k
    data = emalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK));
156
2.53k
  }
157
115k
  HT_SET_DATA_ADDR(ht, data);
158
  /* Don't overwrite iterator count. */
159
115k
  ht->u.v.flags = HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
160
115k
  HT_HASH_RESET_PACKED(ht);
161
115k
}
162
163
static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
164
2.46M
{
165
2.46M
  void *data;
166
2.46M
  uint32_t nSize = ht->nTableSize;
167
168
2.46M
  if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
169
699k
    data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1);
170
1.76M
  } else if (EXPECTED(nSize == HT_MIN_SIZE)) {
171
979k
    data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)));
172
979k
    ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE);
173
979k
    HT_SET_DATA_ADDR(ht, data);
174
    /* Don't overwrite iterator count. */
175
979k
    ht->u.v.flags = HASH_FLAG_STATIC_KEYS;
176
979k
#ifdef __SSE2__
177
979k
    do {
178
979k
      __m128i xmm0 = _mm_setzero_si128();
179
979k
      xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
180
979k
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  0), xmm0);
181
979k
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  4), xmm0);
182
979k
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  8), xmm0);
183
979k
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 12), xmm0);
184
979k
    } while (0);
185
#elif defined(__aarch64__)
186
    do {
187
      int32x4_t t = vdupq_n_s32(-1);
188
      vst1q_s32((int32_t*)&HT_HASH_EX(data,  0), t);
189
      vst1q_s32((int32_t*)&HT_HASH_EX(data,  4), t);
190
      vst1q_s32((int32_t*)&HT_HASH_EX(data,  8), t);
191
      vst1q_s32((int32_t*)&HT_HASH_EX(data, 12), t);
192
    } while (0);
193
#else
194
    HT_HASH_EX(data,  0) = -1;
195
    HT_HASH_EX(data,  1) = -1;
196
    HT_HASH_EX(data,  2) = -1;
197
    HT_HASH_EX(data,  3) = -1;
198
    HT_HASH_EX(data,  4) = -1;
199
    HT_HASH_EX(data,  5) = -1;
200
    HT_HASH_EX(data,  6) = -1;
201
    HT_HASH_EX(data,  7) = -1;
202
    HT_HASH_EX(data,  8) = -1;
203
    HT_HASH_EX(data,  9) = -1;
204
    HT_HASH_EX(data, 10) = -1;
205
    HT_HASH_EX(data, 11) = -1;
206
    HT_HASH_EX(data, 12) = -1;
207
    HT_HASH_EX(data, 13) = -1;
208
    HT_HASH_EX(data, 14) = -1;
209
    HT_HASH_EX(data, 15) = -1;
210
#endif
211
979k
    return;
212
782k
  } else {
213
782k
    data = emalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)));
214
782k
  }
215
1.48M
  ht->nTableMask = HT_SIZE_TO_MASK(nSize);
216
1.48M
  HT_SET_DATA_ADDR(ht, data);
217
1.48M
  HT_FLAGS(ht) = HASH_FLAG_STATIC_KEYS;
218
1.48M
  HT_HASH_RESET(ht);
219
1.48M
}
220
221
static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, int packed)
222
237k
{
223
237k
  HT_ASSERT_RC1(ht);
224
237k
  ZEND_ASSERT(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED);
225
237k
  if (packed) {
226
0
    zend_hash_real_init_packed_ex(ht);
227
237k
  } else {
228
237k
    zend_hash_real_init_mixed_ex(ht);
229
237k
  }
230
237k
}
231
232
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
233
  {HT_INVALID_IDX, HT_INVALID_IDX};
234
235
ZEND_API const HashTable zend_empty_array = {
236
  .gc.refcount = 2,
237
  .gc.u.type_info = IS_ARRAY | (GC_IMMUTABLE << GC_FLAGS_SHIFT),
238
  .u.flags = HASH_FLAG_UNINITIALIZED,
239
  .nTableMask = HT_MIN_MASK,
240
  .arData = (Bucket*)&uninitialized_bucket[2],
241
  .nNumUsed = 0,
242
  .nNumOfElements = 0,
243
  .nTableSize = HT_MIN_SIZE,
244
  .nInternalPointer = 0,
245
  .nNextFreeElement = 0,
246
  .pDestructor = ZVAL_PTR_DTOR
247
};
248
249
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
250
9.66M
{
251
9.66M
  GC_SET_REFCOUNT(ht, 1);
252
9.66M
  GC_TYPE_INFO(ht) = GC_ARRAY | (persistent ? ((GC_PERSISTENT|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT) : 0);
253
9.66M
  HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED;
254
9.66M
  ht->nTableMask = HT_MIN_MASK;
255
9.66M
  HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
256
9.66M
  ht->nNumUsed = 0;
257
9.66M
  ht->nNumOfElements = 0;
258
9.66M
  ht->nInternalPointer = 0;
259
9.66M
  ht->nNextFreeElement = ZEND_LONG_MIN;
260
9.66M
  ht->pDestructor = pDestructor;
261
9.66M
  ht->nTableSize = zend_hash_check_size(nSize);
262
9.66M
}
263
264
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
265
5.33M
{
266
5.33M
  _zend_hash_init_int(ht, nSize, pDestructor, persistent);
267
5.33M
}
268
269
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void)
270
4.19M
{
271
4.19M
  HashTable *ht = emalloc(sizeof(HashTable));
272
4.19M
  _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0);
273
4.19M
  return ht;
274
4.19M
}
275
276
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize)
277
123k
{
278
123k
  HashTable *ht = emalloc(sizeof(HashTable));
279
123k
  _zend_hash_init_int(ht, nSize, ZVAL_PTR_DTOR, 0);
280
123k
  return ht;
281
123k
}
282
283
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2)
284
0
{
285
0
  Bucket *p;
286
0
  HashTable *ht = emalloc(sizeof(HashTable));
287
0
  _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0);
288
0
  ht->nNumUsed = ht->nNumOfElements = ht->nNextFreeElement = 2;
289
0
  zend_hash_real_init_packed_ex(ht);
290
291
0
  p = ht->arData;
292
0
  ZVAL_COPY_VALUE(&p->val, val1);
293
0
  p->h = 0;
294
0
  p->key = NULL;
295
296
0
  p++;
297
0
  ZVAL_COPY_VALUE(&p->val, val2);
298
0
  p->h = 1;
299
0
  p->key = NULL;
300
0
  return ht;
301
0
}
302
303
static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
304
127
{
305
127
  HT_ASSERT_RC1(ht);
306
127
  if (ht->nTableSize >= HT_MAX_SIZE) {
307
0
    zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
308
0
  }
309
127
  ht->nTableSize += ht->nTableSize;
310
127
  HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
311
127
}
312
313
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed)
314
237k
{
315
237k
  IS_CONSISTENT(ht);
316
317
237k
  HT_ASSERT_RC1(ht);
318
237k
  zend_hash_real_init_ex(ht, packed);
319
237k
}
320
321
ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht)
322
0
{
323
0
  IS_CONSISTENT(ht);
324
325
0
  HT_ASSERT_RC1(ht);
326
0
  zend_hash_real_init_packed_ex(ht);
327
0
}
328
329
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
330
2.22M
{
331
2.22M
  IS_CONSISTENT(ht);
332
333
2.22M
  HT_ASSERT_RC1(ht);
334
2.22M
  zend_hash_real_init_mixed_ex(ht);
335
2.22M
}
336
337
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
338
6.32k
{
339
6.32k
  void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
340
6.32k
  Bucket *old_buckets = ht->arData;
341
6.32k
  uint32_t nSize = ht->nTableSize;
342
343
6.32k
  HT_ASSERT_RC1(ht);
344
6.32k
  HT_FLAGS(ht) &= ~HASH_FLAG_PACKED;
345
6.32k
  new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
346
6.32k
  ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
347
6.32k
  HT_SET_DATA_ADDR(ht, new_data);
348
6.32k
  memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
349
6.32k
  pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
350
6.32k
  zend_hash_rehash(ht);
351
6.32k
}
352
353
ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
354
0
{
355
0
  void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
356
0
  Bucket *old_buckets = ht->arData;
357
358
0
  HT_ASSERT_RC1(ht);
359
0
  new_data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
360
0
  HT_FLAGS(ht) |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
361
0
  ht->nTableMask = HT_MIN_MASK;
362
0
  HT_SET_DATA_ADDR(ht, new_data);
363
0
  HT_HASH_RESET_PACKED(ht);
364
0
  memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
365
0
  pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
366
0
}
367
368
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, zend_bool packed)
369
354k
{
370
354k
  HT_ASSERT_RC1(ht);
371
354k
  if (nSize == 0) return;
372
354k
  if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
373
237k
    if (nSize > ht->nTableSize) {
374
94.8k
      ht->nTableSize = zend_hash_check_size(nSize);
375
94.8k
    }
376
237k
    zend_hash_real_init(ht, packed);
377
116k
  } else {
378
116k
    if (packed) {
379
0
      ZEND_ASSERT(HT_FLAGS(ht) & HASH_FLAG_PACKED);
380
0
      if (nSize > ht->nTableSize) {
381
0
        ht->nTableSize = zend_hash_check_size(nSize);
382
0
        HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
383
0
      }
384
116k
    } else {
385
116k
      ZEND_ASSERT(!(HT_FLAGS(ht) & HASH_FLAG_PACKED));
386
116k
      if (nSize > ht->nTableSize) {
387
98.6k
        void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
388
98.6k
        Bucket *old_buckets = ht->arData;
389
98.6k
        nSize = zend_hash_check_size(nSize);
390
98.6k
        ht->nTableSize = nSize;
391
98.6k
        new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
392
98.6k
        ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
393
98.6k
        HT_SET_DATA_ADDR(ht, new_data);
394
98.6k
        memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
395
98.6k
        pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
396
98.6k
        zend_hash_rehash(ht);
397
98.6k
      }
398
116k
    }
399
116k
  }
400
354k
}
401
402
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed)
403
0
{
404
0
  Bucket *p, *end, *arData;
405
0
  uint32_t nIndex;
406
407
0
  arData = ht->arData;
408
0
  p = arData + ht->nNumUsed;
409
0
  end = arData + nNumUsed;
410
0
  ht->nNumUsed = nNumUsed;
411
0
  while (p != end) {
412
0
    p--;
413
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
414
0
    ht->nNumOfElements--;
415
    /* Collision pointers always directed from higher to lower buckets */
416
#if 0
417
    if (!(Z_NEXT(p->val) == HT_INVALID_IDX || HT_HASH_TO_BUCKET_EX(arData, Z_NEXT(p->val)) < p)) {
418
      abort();
419
    }
420
#endif
421
0
    nIndex = p->h | ht->nTableMask;
422
0
    HT_HASH_EX(arData, nIndex) = Z_NEXT(p->val);
423
0
  }
424
0
}
425
426
static uint32_t zend_array_recalc_elements(HashTable *ht)
427
0
{
428
0
       zval *val;
429
0
       uint32_t num = ht->nNumOfElements;
430
431
0
     ZEND_HASH_FOREACH_VAL(ht, val) {
432
0
       if (Z_TYPE_P(val) == IS_INDIRECT) {
433
0
         if (UNEXPECTED(Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF)) {
434
0
           num--;
435
0
         }
436
0
       }
437
0
       } ZEND_HASH_FOREACH_END();
438
0
       return num;
439
0
}
440
/* }}} */
441
442
ZEND_API uint32_t zend_array_count(HashTable *ht)
443
0
{
444
0
  uint32_t num;
445
0
  if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_HAS_EMPTY_IND)) {
446
0
    num = zend_array_recalc_elements(ht);
447
0
    if (UNEXPECTED(ht->nNumOfElements == num)) {
448
0
      HT_FLAGS(ht) &= ~HASH_FLAG_HAS_EMPTY_IND;
449
0
    }
450
0
  } else if (UNEXPECTED(ht == &EG(symbol_table))) {
451
0
    num = zend_array_recalc_elements(ht);
452
0
  } else {
453
0
    num = zend_hash_num_elements(ht);
454
0
  }
455
0
  return num;
456
0
}
457
/* }}} */
458
459
static zend_always_inline HashPosition _zend_hash_get_valid_pos(const HashTable *ht, HashPosition pos)
460
0
{
461
0
  while (pos < ht->nNumUsed && Z_ISUNDEF(ht->arData[pos].val)) {
462
0
    pos++;
463
0
  }
464
0
  return pos;
465
0
}
466
467
static zend_always_inline HashPosition _zend_hash_get_current_pos(const HashTable *ht)
468
0
{
469
0
  return _zend_hash_get_valid_pos(ht, ht->nInternalPointer);
470
0
}
471
472
ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht)
473
0
{
474
0
  return _zend_hash_get_current_pos(ht);
475
0
}
476
477
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
478
0
{
479
0
  HashTableIterator *iter = EG(ht_iterators);
480
0
  HashTableIterator *end  = iter + EG(ht_iterators_count);
481
0
  uint32_t idx;
482
483
0
  if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
484
0
    HT_INC_ITERATORS_COUNT(ht);
485
0
  }
486
0
  while (iter != end) {
487
0
    if (iter->ht == NULL) {
488
0
      iter->ht = ht;
489
0
      iter->pos = pos;
490
0
      idx = iter - EG(ht_iterators);
491
0
      if (idx + 1 > EG(ht_iterators_used)) {
492
0
        EG(ht_iterators_used) = idx + 1;
493
0
      }
494
0
      return idx;
495
0
    }
496
0
    iter++;
497
0
  }
498
0
  if (EG(ht_iterators) == EG(ht_iterators_slots)) {
499
0
    EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
500
0
    memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
501
0
  } else {
502
0
    EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
503
0
  }
504
0
  iter = EG(ht_iterators) + EG(ht_iterators_count);
505
0
  EG(ht_iterators_count) += 8;
506
0
  iter->ht = ht;
507
0
  iter->pos = pos;
508
0
  memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
509
0
  idx = iter - EG(ht_iterators);
510
0
  EG(ht_iterators_used) = idx + 1;
511
0
  return idx;
512
0
}
513
514
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
515
0
{
516
0
  HashTableIterator *iter = EG(ht_iterators) + idx;
517
518
0
  ZEND_ASSERT(idx != (uint32_t)-1);
519
0
  if (UNEXPECTED(iter->ht != ht)) {
520
0
    if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
521
0
        && EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
522
0
      HT_DEC_ITERATORS_COUNT(iter->ht);
523
0
    }
524
0
    if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
525
0
      HT_INC_ITERATORS_COUNT(ht);
526
0
    }
527
0
    iter->ht = ht;
528
0
    iter->pos = _zend_hash_get_current_pos(ht);
529
0
  }
530
0
  return iter->pos;
531
0
}
532
533
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array)
534
0
{
535
0
  HashTable *ht = Z_ARRVAL_P(array);
536
0
  HashTableIterator *iter = EG(ht_iterators) + idx;
537
538
0
  ZEND_ASSERT(idx != (uint32_t)-1);
539
0
  if (UNEXPECTED(iter->ht != ht)) {
540
0
    if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
541
0
        && EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
542
0
      HT_DEC_ITERATORS_COUNT(iter->ht);
543
0
    }
544
0
    SEPARATE_ARRAY(array);
545
0
    ht = Z_ARRVAL_P(array);
546
0
    if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
547
0
      HT_INC_ITERATORS_COUNT(ht);
548
0
    }
549
0
    iter->ht = ht;
550
0
    iter->pos = _zend_hash_get_current_pos(ht);
551
0
  }
552
0
  return iter->pos;
553
0
}
554
555
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
556
0
{
557
0
  HashTableIterator *iter = EG(ht_iterators) + idx;
558
559
0
  ZEND_ASSERT(idx != (uint32_t)-1);
560
561
0
  if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
562
0
      && EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
563
0
    ZEND_ASSERT(HT_ITERATORS_COUNT(iter->ht) != 0);
564
0
    HT_DEC_ITERATORS_COUNT(iter->ht);
565
0
  }
566
0
  iter->ht = NULL;
567
568
0
  if (idx == EG(ht_iterators_used) - 1) {
569
0
    while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
570
0
      idx--;
571
0
    }
572
0
    EG(ht_iterators_used) = idx;
573
0
  }
574
0
}
575
576
static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(HashTable *ht)
577
0
{
578
0
  HashTableIterator *iter = EG(ht_iterators);
579
0
  HashTableIterator *end  = iter + EG(ht_iterators_used);
580
581
0
  while (iter != end) {
582
0
    if (iter->ht == ht) {
583
0
      iter->ht = HT_POISONED_PTR;
584
0
    }
585
0
    iter++;
586
0
  }
587
0
}
588
589
static zend_always_inline void zend_hash_iterators_remove(HashTable *ht)
590
1.46M
{
591
1.46M
  if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
592
0
    _zend_hash_iterators_remove(ht);
593
0
  }
594
1.46M
}
595
596
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start)
597
0
{
598
0
  HashTableIterator *iter = EG(ht_iterators);
599
0
  HashTableIterator *end  = iter + EG(ht_iterators_used);
600
0
  HashPosition res = ht->nNumUsed;
601
602
0
  while (iter != end) {
603
0
    if (iter->ht == ht) {
604
0
      if (iter->pos >= start && iter->pos < res) {
605
0
        res = iter->pos;
606
0
      }
607
0
    }
608
0
    iter++;
609
0
  }
610
0
  return res;
611
0
}
612
613
ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
614
0
{
615
0
  HashTableIterator *iter = EG(ht_iterators);
616
0
  HashTableIterator *end  = iter + EG(ht_iterators_used);
617
618
0
  while (iter != end) {
619
0
    if (iter->ht == ht && iter->pos == from) {
620
0
      iter->pos = to;
621
0
    }
622
0
    iter++;
623
0
  }
624
0
}
625
626
ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step)
627
0
{
628
0
  HashTableIterator *iter = EG(ht_iterators);
629
0
  HashTableIterator *end  = iter + EG(ht_iterators_used);
630
631
0
  while (iter != end) {
632
0
    if (iter->ht == ht) {
633
0
      iter->pos += step;
634
0
    }
635
0
    iter++;
636
0
  }
637
0
}
638
639
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key, zend_bool known_hash)
640
31.1M
{
641
31.1M
  zend_ulong h;
642
31.1M
  uint32_t nIndex;
643
31.1M
  uint32_t idx;
644
31.1M
  Bucket *p, *arData;
645
646
31.1M
  if (known_hash) {
647
4.93M
    h = ZSTR_H(key);
648
26.2M
  } else {
649
26.2M
    h = zend_string_hash_val(key);
650
26.2M
  }
651
31.1M
  arData = ht->arData;
652
31.1M
  nIndex = h | ht->nTableMask;
653
31.1M
  idx = HT_HASH_EX(arData, nIndex);
654
655
31.1M
  if (UNEXPECTED(idx == HT_INVALID_IDX)) {
656
15.0M
    return NULL;
657
15.0M
  }
658
16.0M
  p = HT_HASH_TO_BUCKET_EX(arData, idx);
659
16.0M
  if (EXPECTED(p->key == key)) { /* check for the same interned string */
660
9.96M
    return p;
661
9.96M
  }
662
663
7.00M
  while (1) {
664
7.00M
    if (p->h == ZSTR_H(key) &&
665
1.17M
        EXPECTED(p->key) &&
666
1.17M
        zend_string_equal_content(p->key, key)) {
667
1.17M
      return p;
668
1.17M
    }
669
5.82M
    idx = Z_NEXT(p->val);
670
5.82M
    if (idx == HT_INVALID_IDX) {
671
4.70M
      return NULL;
672
4.70M
    }
673
1.12M
    p = HT_HASH_TO_BUCKET_EX(arData, idx);
674
1.12M
    if (p->key == key) { /* check for the same interned string */
675
235k
      return p;
676
235k
    }
677
1.12M
  }
678
6.11M
}
679
680
static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
681
136k
{
682
136k
  uint32_t nIndex;
683
136k
  uint32_t idx;
684
136k
  Bucket *p, *arData;
685
686
136k
  arData = ht->arData;
687
136k
  nIndex = h | ht->nTableMask;
688
136k
  idx = HT_HASH_EX(arData, nIndex);
689
169k
  while (idx != HT_INVALID_IDX) {
690
83.2k
    ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
691
83.2k
    p = HT_HASH_TO_BUCKET_EX(arData, idx);
692
83.2k
    if ((p->h == h)
693
49.8k
       && p->key
694
49.8k
       && (ZSTR_LEN(p->key) == len)
695
49.8k
       && !memcmp(ZSTR_VAL(p->key), str, len)) {
696
49.8k
      return p;
697
49.8k
    }
698
33.3k
    idx = Z_NEXT(p->val);
699
33.3k
  }
700
86.2k
  return NULL;
701
136k
}
702
703
static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
704
1.11G
{
705
1.11G
  uint32_t nIndex;
706
1.11G
  uint32_t idx;
707
1.11G
  Bucket *p, *arData;
708
709
1.11G
  arData = ht->arData;
710
1.11G
  nIndex = h | ht->nTableMask;
711
1.11G
  idx = HT_HASH_EX(arData, nIndex);
712
1.29G
  while (idx != HT_INVALID_IDX) {
713
179M
    ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
714
179M
    p = HT_HASH_TO_BUCKET_EX(arData, idx);
715
179M
    if (p->h == h && !p->key) {
716
418k
      return p;
717
418k
    }
718
178M
    idx = Z_NEXT(p->val);
719
178M
  }
720
1.11G
  return NULL;
721
1.11G
}
722
723
static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, uint32_t flag)
724
23.8M
{
725
23.8M
  zend_ulong h;
726
23.8M
  uint32_t nIndex;
727
23.8M
  uint32_t idx;
728
23.8M
  Bucket *p, *arData;
729
730
23.8M
  IS_CONSISTENT(ht);
731
23.8M
  HT_ASSERT_RC1(ht);
732
733
23.8M
  if (UNEXPECTED(HT_FLAGS(ht) & (HASH_FLAG_UNINITIALIZED|HASH_FLAG_PACKED))) {
734
1.95M
    if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
735
1.94M
      zend_hash_real_init_mixed(ht);
736
1.94M
      if (!ZSTR_IS_INTERNED(key)) {
737
162k
        zend_string_addref(key);
738
162k
        HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
739
162k
        zend_string_hash_val(key);
740
162k
      }
741
1.94M
      goto add_to_hash;
742
5.08k
    } else {
743
5.08k
      zend_hash_packed_to_hash(ht);
744
5.08k
      if (!ZSTR_IS_INTERNED(key)) {
745
3.77k
        zend_string_addref(key);
746
3.77k
        HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
747
3.77k
        zend_string_hash_val(key);
748
3.77k
      }
749
5.08k
    }
750
21.8M
  } else if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
751
10.3M
    p = zend_hash_find_bucket(ht, key, 0);
752
753
10.3M
    if (p) {
754
332k
      zval *data;
755
756
332k
      ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
757
332k
      if (flag & HASH_ADD) {
758
236k
        if (!(flag & HASH_UPDATE_INDIRECT)) {
759
232k
          return NULL;
760
232k
        }
761
4.54k
        ZEND_ASSERT(&p->val != pData);
762
4.54k
        data = &p->val;
763
4.54k
        if (Z_TYPE_P(data) == IS_INDIRECT) {
764
0
          data = Z_INDIRECT_P(data);
765
0
          if (Z_TYPE_P(data) != IS_UNDEF) {
766
0
            return NULL;
767
0
          }
768
4.54k
        } else {
769
4.54k
          return NULL;
770
4.54k
        }
771
95.0k
      } else {
772
95.0k
        ZEND_ASSERT(&p->val != pData);
773
95.0k
        data = &p->val;
774
95.0k
        if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
775
0
          data = Z_INDIRECT_P(data);
776
0
        }
777
95.0k
      }
778
95.0k
      if (ht->pDestructor) {
779
95.0k
        ht->pDestructor(data);
780
95.0k
      }
781
95.0k
      ZVAL_COPY_VALUE(data, pData);
782
95.0k
      return data;
783
9.99M
    }
784
9.99M
    if (!ZSTR_IS_INTERNED(key)) {
785
200k
      zend_string_addref(key);
786
200k
      HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
787
200k
    }
788
11.5M
  } else if (!ZSTR_IS_INTERNED(key)) {
789
73.3k
    zend_string_addref(key);
790
73.3k
    HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
791
73.3k
    zend_string_hash_val(key);
792
73.3k
  }
793
794
21.5M
  ZEND_HASH_IF_FULL_DO_RESIZE(ht);   /* If the Hash table is full, resize it */
795
796
23.4M
add_to_hash:
797
23.4M
  idx = ht->nNumUsed++;
798
23.4M
  ht->nNumOfElements++;
799
23.4M
  arData = ht->arData;
800
23.4M
  p = arData + idx;
801
23.4M
  p->key = key;
802
23.4M
  p->h = h = ZSTR_H(key);
803
23.4M
  nIndex = h | ht->nTableMask;
804
23.4M
  Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex);
805
23.4M
  HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);
806
23.4M
  ZVAL_COPY_VALUE(&p->val, pData);
807
808
23.4M
  return &p->val;
809
21.5M
}
810
811
static zend_always_inline zval *_zend_hash_str_add_or_update_i(HashTable *ht, const char *str, size_t len, zend_ulong h, zval *pData, uint32_t flag)
812
3.47k
{
813
3.47k
  zend_string *key;
814
3.47k
  uint32_t nIndex;
815
3.47k
  uint32_t idx;
816
3.47k
  Bucket *p;
817
818
3.47k
  IS_CONSISTENT(ht);
819
3.47k
  HT_ASSERT_RC1(ht);
820
821
3.47k
  if (UNEXPECTED(HT_FLAGS(ht) & (HASH_FLAG_UNINITIALIZED|HASH_FLAG_PACKED))) {
822
3.47k
    if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
823
3.47k
      zend_hash_real_init_mixed(ht);
824
3.47k
      goto add_to_hash;
825
0
    } else {
826
0
      zend_hash_packed_to_hash(ht);
827
0
    }
828
0
  } else if ((flag & HASH_ADD_NEW) == 0) {
829
0
    p = zend_hash_str_find_bucket(ht, str, len, h);
830
831
0
    if (p) {
832
0
      zval *data;
833
834
0
      if (flag & HASH_ADD) {
835
0
        if (!(flag & HASH_UPDATE_INDIRECT)) {
836
0
          return NULL;
837
0
        }
838
0
        ZEND_ASSERT(&p->val != pData);
839
0
        data = &p->val;
840
0
        if (Z_TYPE_P(data) == IS_INDIRECT) {
841
0
          data = Z_INDIRECT_P(data);
842
0
          if (Z_TYPE_P(data) != IS_UNDEF) {
843
0
            return NULL;
844
0
          }
845
0
        } else {
846
0
          return NULL;
847
0
        }
848
0
      } else {
849
0
        ZEND_ASSERT(&p->val != pData);
850
0
        data = &p->val;
851
0
        if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
852
0
          data = Z_INDIRECT_P(data);
853
0
        }
854
0
      }
855
0
      if (ht->pDestructor) {
856
0
        ht->pDestructor(data);
857
0
      }
858
0
      ZVAL_COPY_VALUE(data, pData);
859
0
      return data;
860
0
    }
861
0
  }
862
863
0
  ZEND_HASH_IF_FULL_DO_RESIZE(ht);   /* If the Hash table is full, resize it */
864
865
3.47k
add_to_hash:
866
3.47k
  idx = ht->nNumUsed++;
867
3.47k
  ht->nNumOfElements++;
868
3.47k
  p = ht->arData + idx;
869
3.47k
  p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
870
3.47k
  p->h = ZSTR_H(key) = h;
871
3.47k
  HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
872
3.47k
  ZVAL_COPY_VALUE(&p->val, pData);
873
3.47k
  nIndex = h | ht->nTableMask;
874
3.47k
  Z_NEXT(p->val) = HT_HASH(ht, nIndex);
875
3.47k
  HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
876
877
3.47k
  return &p->val;
878
0
}
879
880
ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag)
881
0
{
882
0
  if (flag == HASH_ADD) {
883
0
    return zend_hash_add(ht, key, pData);
884
0
  } else if (flag == HASH_ADD_NEW) {
885
0
    return zend_hash_add_new(ht, key, pData);
886
0
  } else if (flag == HASH_UPDATE) {
887
0
    return zend_hash_update(ht, key, pData);
888
0
  } else {
889
0
    ZEND_ASSERT(flag == (HASH_UPDATE|HASH_UPDATE_INDIRECT));
890
0
    return zend_hash_update_ind(ht, key, pData);
891
0
  }
892
0
}
893
894
ZEND_API zval* ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key, zval *pData)
895
8.96M
{
896
8.96M
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD);
897
8.96M
}
898
899
ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
900
2.43M
{
901
2.43M
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE);
902
2.43M
}
903
904
ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData)
905
13.1k
{
906
13.1k
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT);
907
13.1k
}
908
909
ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
910
12.3M
{
911
12.3M
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW);
912
12.3M
}
913
914
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag)
915
0
{
916
0
  if (flag == HASH_ADD) {
917
0
    return zend_hash_str_add(ht, str, len, pData);
918
0
  } else if (flag == HASH_ADD_NEW) {
919
0
    return zend_hash_str_add_new(ht, str, len, pData);
920
0
  } else if (flag == HASH_UPDATE) {
921
0
    return zend_hash_str_update(ht, str, len, pData);
922
0
  } else {
923
0
    ZEND_ASSERT(flag == (HASH_UPDATE|HASH_UPDATE_INDIRECT));
924
0
    return zend_hash_str_update_ind(ht, str, len, pData);
925
0
  }
926
0
}
927
928
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
929
0
{
930
0
  zend_ulong h = zend_hash_func(str, len);
931
932
0
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_UPDATE);
933
0
}
934
935
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData)
936
0
{
937
0
  zend_ulong h = zend_hash_func(str, len);
938
939
0
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT);
940
0
}
941
942
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData)
943
3.47k
{
944
3.47k
  zend_ulong h = zend_hash_func(str, len);
945
946
3.47k
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_ADD);
947
3.47k
}
948
949
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData)
950
0
{
951
0
  zend_ulong h = zend_hash_func(str, len);
952
953
0
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_ADD_NEW);
954
0
}
955
956
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
957
1.11G
{
958
1.11G
  zval dummy;
959
960
1.11G
  ZVAL_NULL(&dummy);
961
1.11G
  return zend_hash_index_add(ht, h, &dummy);
962
1.11G
}
963
964
ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
965
305k
{
966
305k
  zval dummy;
967
968
305k
  ZVAL_NULL(&dummy);
969
305k
  return zend_hash_add(ht, key, &dummy);
970
305k
}
971
972
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
973
0
{
974
0
  zval dummy;
975
976
0
  ZVAL_NULL(&dummy);
977
0
  return zend_hash_str_add(ht, str, len, &dummy);
978
0
}
979
980
static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag)
981
1.11G
{
982
1.11G
  uint32_t nIndex;
983
1.11G
  uint32_t idx;
984
1.11G
  Bucket *p;
985
986
1.11G
  IS_CONSISTENT(ht);
987
1.11G
  HT_ASSERT_RC1(ht);
988
989
1.11G
  if ((flag & HASH_ADD_NEXT) && h == ZEND_LONG_MIN) {
990
101k
    h = 0;
991
101k
  }
992
993
1.11G
  if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
994
140k
    if (h < ht->nNumUsed) {
995
5.38k
      p = ht->arData + h;
996
5.38k
      if (Z_TYPE(p->val) != IS_UNDEF) {
997
13.8k
replace:
998
13.8k
        if (flag & HASH_ADD) {
999
9.69k
          return NULL;
1000
9.69k
        }
1001
4.12k
        if (ht->pDestructor) {
1002
4.12k
          ht->pDestructor(&p->val);
1003
4.12k
        }
1004
4.12k
        ZVAL_COPY_VALUE(&p->val, pData);
1005
4.12k
        return &p->val;
1006
654
      } else { /* we have to keep the order :( */
1007
654
        goto convert_to_hash;
1008
654
      }
1009
135k
    } else if (EXPECTED(h < ht->nTableSize)) {
1010
250k
add_to_packed:
1011
250k
      p = ht->arData + h;
1012
      /* incremental initialization of empty Buckets */
1013
250k
      if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) != (HASH_ADD_NEW|HASH_ADD_NEXT)) {
1014
250k
        if (h > ht->nNumUsed) {
1015
11.5k
          Bucket *q = ht->arData + ht->nNumUsed;
1016
33.1k
          while (q != p) {
1017
21.5k
            ZVAL_UNDEF(&q->val);
1018
21.5k
            q++;
1019
21.5k
          }
1020
11.5k
        }
1021
250k
      }
1022
250k
      ht->nNextFreeElement = ht->nNumUsed = h + 1;
1023
250k
      goto add;
1024
714
    } else if ((h >> 1) < ht->nTableSize &&
1025
467
               (ht->nTableSize >> 1) < ht->nNumOfElements) {
1026
127
      zend_hash_packed_grow(ht);
1027
127
      goto add_to_packed;
1028
587
    } else {
1029
587
      if (ht->nNumUsed >= ht->nTableSize) {
1030
127
        ht->nTableSize += ht->nTableSize;
1031
127
      }
1032
1.24k
convert_to_hash:
1033
1.24k
      zend_hash_packed_to_hash(ht);
1034
1.24k
    }
1035
1.11G
  } else if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
1036
385k
    if (h < ht->nTableSize) {
1037
115k
      zend_hash_real_init_packed_ex(ht);
1038
115k
      goto add_to_packed;
1039
115k
    }
1040
270k
    zend_hash_real_init_mixed(ht);
1041
1.11G
  } else {
1042
1.11G
    if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
1043
1.11G
      p = zend_hash_index_find_bucket(ht, h);
1044
1.11G
      if (p) {
1045
9.09k
        ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
1046
9.09k
        goto replace;
1047
1.11G
      }
1048
1.11G
    }
1049
1.11G
    ZEND_HASH_IF_FULL_DO_RESIZE(ht);   /* If the Hash table is full, resize it */
1050
1.11G
  }
1051
1052
1.11G
  idx = ht->nNumUsed++;
1053
1.11G
  nIndex = h | ht->nTableMask;
1054
1.11G
  p = ht->arData + idx;
1055
1.11G
  Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1056
1.11G
  HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1057
1.11G
  if ((zend_long)h >= ht->nNextFreeElement) {
1058
5.81M
    ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
1059
5.81M
  }
1060
1.11G
add:
1061
1.11G
  ht->nNumOfElements++;
1062
1.11G
  p->h = h;
1063
1.11G
  p->key = NULL;
1064
1.11G
  ZVAL_COPY_VALUE(&p->val, pData);
1065
1066
1.11G
  return &p->val;
1067
1.11G
}
1068
1069
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag)
1070
0
{
1071
0
  if (flag == HASH_ADD) {
1072
0
    return zend_hash_index_add(ht, h, pData);
1073
0
  } else if (flag == (HASH_ADD|HASH_ADD_NEW)) {
1074
0
    return zend_hash_index_add_new(ht, h, pData);
1075
0
  } else if (flag == (HASH_ADD|HASH_ADD_NEXT)) {
1076
0
    ZEND_ASSERT(h == ht->nNextFreeElement);
1077
0
    return zend_hash_next_index_insert(ht, pData);
1078
0
  } else if (flag == (HASH_ADD|HASH_ADD_NEW|HASH_ADD_NEXT)) {
1079
0
    ZEND_ASSERT(h == ht->nNextFreeElement);
1080
0
    return zend_hash_next_index_insert_new(ht, pData);
1081
0
  } else {
1082
0
    ZEND_ASSERT(flag == HASH_UPDATE);
1083
0
    return zend_hash_index_update(ht, h, pData);
1084
0
  }
1085
0
}
1086
1087
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData)
1088
1.11G
{
1089
1.11G
  return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD);
1090
1.11G
}
1091
1092
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData)
1093
309
{
1094
309
  return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW);
1095
309
}
1096
1097
ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
1098
434k
{
1099
434k
  return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE);
1100
434k
}
1101
1102
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
1103
237k
{
1104
237k
  return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT);
1105
237k
}
1106
1107
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
1108
0
{
1109
0
  return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT);
1110
0
}
1111
1112
ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key)
1113
0
{
1114
0
  uint32_t nIndex;
1115
0
  uint32_t idx, i;
1116
0
  Bucket *p, *arData;
1117
1118
0
  IS_CONSISTENT(ht);
1119
0
  HT_ASSERT_RC1(ht);
1120
0
  ZEND_ASSERT(!(HT_FLAGS(ht) & HASH_FLAG_PACKED));
1121
1122
0
  p = zend_hash_find_bucket(ht, key, 0);
1123
0
  if (UNEXPECTED(p)) {
1124
0
    return (p == b) ? &p->val : NULL;
1125
0
  }
1126
1127
0
  if (!ZSTR_IS_INTERNED(key)) {
1128
0
    zend_string_addref(key);
1129
0
    HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1130
0
  }
1131
1132
0
  arData = ht->arData;
1133
1134
  /* del from hash */
1135
0
  idx = HT_IDX_TO_HASH(b - arData);
1136
0
  nIndex = b->h | ht->nTableMask;
1137
0
  i = HT_HASH_EX(arData, nIndex);
1138
0
  if (i == idx) {
1139
0
    HT_HASH_EX(arData, nIndex) = Z_NEXT(b->val);
1140
0
  } else {
1141
0
    p = HT_HASH_TO_BUCKET_EX(arData, i);
1142
0
    while (Z_NEXT(p->val) != idx) {
1143
0
      i = Z_NEXT(p->val);
1144
0
      p = HT_HASH_TO_BUCKET_EX(arData, i);
1145
0
    }
1146
0
    Z_NEXT(p->val) = Z_NEXT(b->val);
1147
0
  }
1148
0
  zend_string_release(b->key);
1149
1150
  /* add to hash */
1151
0
  idx = b - arData;
1152
0
  b->key = key;
1153
0
  b->h = ZSTR_H(key);
1154
0
  nIndex = b->h | ht->nTableMask;
1155
0
  idx = HT_IDX_TO_HASH(idx);
1156
0
  i = HT_HASH_EX(arData, nIndex);
1157
0
  if (i == HT_INVALID_IDX || i < idx) {
1158
0
    Z_NEXT(b->val) = i;
1159
0
    HT_HASH_EX(arData, nIndex) = idx;
1160
0
  } else {
1161
0
    p = HT_HASH_TO_BUCKET_EX(arData, i);
1162
0
    while (Z_NEXT(p->val) != HT_INVALID_IDX && Z_NEXT(p->val) > idx) {
1163
0
      i = Z_NEXT(p->val);
1164
0
      p = HT_HASH_TO_BUCKET_EX(arData, i);
1165
0
    }
1166
0
    Z_NEXT(b->val) = Z_NEXT(p->val);
1167
0
    Z_NEXT(p->val) = idx;
1168
0
  }
1169
0
  return &b->val;
1170
0
}
1171
1172
static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
1173
217k
{
1174
1175
217k
  IS_CONSISTENT(ht);
1176
217k
  HT_ASSERT_RC1(ht);
1177
1178
217k
  if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */
1179
16.5k
    zend_hash_rehash(ht);
1180
200k
  } else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
1181
200k
    void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
1182
200k
    uint32_t nSize = ht->nTableSize + ht->nTableSize;
1183
200k
    Bucket *old_buckets = ht->arData;
1184
1185
200k
    ht->nTableSize = nSize;
1186
200k
    new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1187
200k
    ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
1188
200k
    HT_SET_DATA_ADDR(ht, new_data);
1189
200k
    memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
1190
200k
    pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1191
200k
    zend_hash_rehash(ht);
1192
0
  } else {
1193
0
    zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket) + sizeof(uint32_t), sizeof(Bucket));
1194
0
  }
1195
217k
}
1196
1197
ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
1198
325k
{
1199
325k
  Bucket *p;
1200
325k
  uint32_t nIndex, i;
1201
1202
325k
  IS_CONSISTENT(ht);
1203
1204
325k
  if (UNEXPECTED(ht->nNumOfElements == 0)) {
1205
0
    if (!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1206
0
      ht->nNumUsed = 0;
1207
0
      HT_HASH_RESET(ht);
1208
0
    }
1209
0
    return;
1210
325k
  }
1211
1212
325k
  HT_HASH_RESET(ht);
1213
325k
  i = 0;
1214
325k
  p = ht->arData;
1215
325k
  if (HT_IS_WITHOUT_HOLES(ht)) {
1216
16.7M
    do {
1217
16.7M
      nIndex = p->h | ht->nTableMask;
1218
16.7M
      Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1219
16.7M
      HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
1220
16.7M
      p++;
1221
16.7M
    } while (++i < ht->nNumUsed);
1222
19.3k
  } else {
1223
19.3k
    uint32_t old_num_used = ht->nNumUsed;
1224
4.17M
    do {
1225
4.17M
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) {
1226
19.3k
        uint32_t j = i;
1227
19.3k
        Bucket *q = p;
1228
1229
19.3k
        if (EXPECTED(!HT_HAS_ITERATORS(ht))) {
1230
16.6M
          while (++i < ht->nNumUsed) {
1231
16.6M
            p++;
1232
16.6M
            if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
1233
4.99M
              ZVAL_COPY_VALUE(&q->val, &p->val);
1234
4.99M
              q->h = p->h;
1235
4.99M
              nIndex = q->h | ht->nTableMask;
1236
4.99M
              q->key = p->key;
1237
4.99M
              Z_NEXT(q->val) = HT_HASH(ht, nIndex);
1238
4.99M
              HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
1239
4.99M
              if (UNEXPECTED(ht->nInternalPointer == i)) {
1240
0
                ht->nInternalPointer = j;
1241
0
              }
1242
4.99M
              q++;
1243
4.99M
              j++;
1244
4.99M
            }
1245
16.6M
          }
1246
0
        } else {
1247
0
          uint32_t iter_pos = zend_hash_iterators_lower_pos(ht, 0);
1248
1249
0
          while (++i < ht->nNumUsed) {
1250
0
            p++;
1251
0
            if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
1252
0
              ZVAL_COPY_VALUE(&q->val, &p->val);
1253
0
              q->h = p->h;
1254
0
              nIndex = q->h | ht->nTableMask;
1255
0
              q->key = p->key;
1256
0
              Z_NEXT(q->val) = HT_HASH(ht, nIndex);
1257
0
              HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
1258
0
              if (UNEXPECTED(ht->nInternalPointer == i)) {
1259
0
                ht->nInternalPointer = j;
1260
0
              }
1261
0
              if (UNEXPECTED(i >= iter_pos)) {
1262
0
                do {
1263
0
                  zend_hash_iterators_update(ht, iter_pos, j);
1264
0
                  iter_pos = zend_hash_iterators_lower_pos(ht, iter_pos + 1);
1265
0
                } while (iter_pos < i);
1266
0
              }
1267
0
              q++;
1268
0
              j++;
1269
0
            }
1270
0
          }
1271
0
        }
1272
19.3k
        ht->nNumUsed = j;
1273
19.3k
        break;
1274
19.3k
      }
1275
4.15M
      nIndex = p->h | ht->nTableMask;
1276
4.15M
      Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1277
4.15M
      HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
1278
4.15M
      p++;
1279
4.15M
    } while (++i < ht->nNumUsed);
1280
1281
    /* Migrate pointer to one past the end of the array to the new one past the end, so that
1282
     * newly inserted elements are picked up correctly. */
1283
19.3k
    if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
1284
0
      _zend_hash_iterators_update(ht, old_num_used, ht->nNumUsed);
1285
0
    }
1286
19.3k
  }
1287
325k
}
1288
1289
static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
1290
1.11G
{
1291
1.11G
  if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED)) {
1292
1.11G
    if (prev) {
1293
5.74M
      Z_NEXT(prev->val) = Z_NEXT(p->val);
1294
1.11G
    } else {
1295
1.11G
      HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
1296
1.11G
    }
1297
1.11G
  }
1298
1.11G
  idx = HT_HASH_TO_IDX(idx);
1299
1.11G
  ht->nNumOfElements--;
1300
1.11G
  if (ht->nInternalPointer == idx || UNEXPECTED(HT_HAS_ITERATORS(ht))) {
1301
2.36M
    uint32_t new_idx;
1302
1303
2.36M
    new_idx = idx;
1304
6.29M
    while (1) {
1305
6.29M
      new_idx++;
1306
6.29M
      if (new_idx >= ht->nNumUsed) {
1307
780k
        break;
1308
5.51M
      } else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
1309
1.58M
        break;
1310
1.58M
      }
1311
6.29M
    }
1312
2.36M
    if (ht->nInternalPointer == idx) {
1313
2.36M
      ht->nInternalPointer = new_idx;
1314
2.36M
    }
1315
2.36M
    zend_hash_iterators_update(ht, idx, new_idx);
1316
2.36M
  }
1317
1.11G
  if (ht->nNumUsed - 1 == idx) {
1318
1.10G
    do {
1319
1.10G
      ht->nNumUsed--;
1320
1.10G
    } while (ht->nNumUsed > 0 && (UNEXPECTED(Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF)));
1321
756M
    ht->nInternalPointer = MIN(ht->nInternalPointer, ht->nNumUsed);
1322
756M
  }
1323
1.11G
  if (p->key) {
1324
1.58M
    zend_string_release(p->key);
1325
1.58M
  }
1326
1.11G
  if (ht->pDestructor) {
1327
1.57M
    zval tmp;
1328
1.57M
    ZVAL_COPY_VALUE(&tmp, &p->val);
1329
1.57M
    ZVAL_UNDEF(&p->val);
1330
1.57M
    ht->pDestructor(&tmp);
1331
1.11G
  } else {
1332
1.11G
    ZVAL_UNDEF(&p->val);
1333
1.11G
  }
1334
1.11G
}
1335
1336
static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
1337
1.56M
{
1338
1.56M
  Bucket *prev = NULL;
1339
1340
1.56M
  if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED)) {
1341
1.56M
    uint32_t nIndex = p->h | ht->nTableMask;
1342
1.56M
    uint32_t i = HT_HASH(ht, nIndex);
1343
1344
1.56M
    if (i != idx) {
1345
0
      prev = HT_HASH_TO_BUCKET(ht, i);
1346
0
      while (Z_NEXT(prev->val) != idx) {
1347
0
        i = Z_NEXT(prev->val);
1348
0
        prev = HT_HASH_TO_BUCKET(ht, i);
1349
0
      }
1350
0
    }
1351
1.56M
  }
1352
1353
1.56M
  _zend_hash_del_el_ex(ht, idx, p, prev);
1354
1.56M
}
1355
1356
ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p)
1357
0
{
1358
0
  IS_CONSISTENT(ht);
1359
0
  HT_ASSERT_RC1(ht);
1360
0
  _zend_hash_del_el(ht, HT_IDX_TO_HASH(p - ht->arData), p);
1361
0
}
1362
1363
ZEND_API int ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
1364
33.8k
{
1365
33.8k
  zend_ulong h;
1366
33.8k
  uint32_t nIndex;
1367
33.8k
  uint32_t idx;
1368
33.8k
  Bucket *p;
1369
33.8k
  Bucket *prev = NULL;
1370
1371
33.8k
  IS_CONSISTENT(ht);
1372
33.8k
  HT_ASSERT_RC1(ht);
1373
1374
33.8k
  h = zend_string_hash_val(key);
1375
33.8k
  nIndex = h | ht->nTableMask;
1376
1377
33.8k
  idx = HT_HASH(ht, nIndex);
1378
39.5k
  while (idx != HT_INVALID_IDX) {
1379
25.5k
    p = HT_HASH_TO_BUCKET(ht, idx);
1380
25.5k
    if ((p->key == key) ||
1381
14.7k
      (p->h == h &&
1382
9.07k
         p->key &&
1383
19.9k
         zend_string_equal_content(p->key, key))) {
1384
19.9k
      _zend_hash_del_el_ex(ht, idx, p, prev);
1385
19.9k
      return SUCCESS;
1386
19.9k
    }
1387
5.65k
    prev = p;
1388
5.65k
    idx = Z_NEXT(p->val);
1389
5.65k
  }
1390
13.9k
  return FAILURE;
1391
33.8k
}
1392
1393
ZEND_API int ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key)
1394
0
{
1395
0
  zend_ulong h;
1396
0
  uint32_t nIndex;
1397
0
  uint32_t idx;
1398
0
  Bucket *p;
1399
0
  Bucket *prev = NULL;
1400
1401
0
  IS_CONSISTENT(ht);
1402
0
  HT_ASSERT_RC1(ht);
1403
1404
0
  h = zend_string_hash_val(key);
1405
0
  nIndex = h | ht->nTableMask;
1406
1407
0
  idx = HT_HASH(ht, nIndex);
1408
0
  while (idx != HT_INVALID_IDX) {
1409
0
    p = HT_HASH_TO_BUCKET(ht, idx);
1410
0
    if ((p->key == key) ||
1411
0
      (p->h == h &&
1412
0
         p->key &&
1413
0
         zend_string_equal_content(p->key, key))) {
1414
0
      if (Z_TYPE(p->val) == IS_INDIRECT) {
1415
0
        zval *data = Z_INDIRECT(p->val);
1416
1417
0
        if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
1418
0
          return FAILURE;
1419
0
        } else {
1420
0
          if (ht->pDestructor) {
1421
0
            zval tmp;
1422
0
            ZVAL_COPY_VALUE(&tmp, data);
1423
0
            ZVAL_UNDEF(data);
1424
0
            ht->pDestructor(&tmp);
1425
0
          } else {
1426
0
            ZVAL_UNDEF(data);
1427
0
          }
1428
0
          HT_FLAGS(ht) |= HASH_FLAG_HAS_EMPTY_IND;
1429
0
        }
1430
0
      } else {
1431
0
        _zend_hash_del_el_ex(ht, idx, p, prev);
1432
0
      }
1433
0
      return SUCCESS;
1434
0
    }
1435
0
    prev = p;
1436
0
    idx = Z_NEXT(p->val);
1437
0
  }
1438
0
  return FAILURE;
1439
0
}
1440
1441
ZEND_API int ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
1442
0
{
1443
0
  zend_ulong h;
1444
0
  uint32_t nIndex;
1445
0
  uint32_t idx;
1446
0
  Bucket *p;
1447
0
  Bucket *prev = NULL;
1448
1449
0
  IS_CONSISTENT(ht);
1450
0
  HT_ASSERT_RC1(ht);
1451
1452
0
  h = zend_inline_hash_func(str, len);
1453
0
  nIndex = h | ht->nTableMask;
1454
1455
0
  idx = HT_HASH(ht, nIndex);
1456
0
  while (idx != HT_INVALID_IDX) {
1457
0
    p = HT_HASH_TO_BUCKET(ht, idx);
1458
0
    if ((p->h == h)
1459
0
       && p->key
1460
0
       && (ZSTR_LEN(p->key) == len)
1461
0
       && !memcmp(ZSTR_VAL(p->key), str, len)) {
1462
0
      if (Z_TYPE(p->val) == IS_INDIRECT) {
1463
0
        zval *data = Z_INDIRECT(p->val);
1464
1465
0
        if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
1466
0
          return FAILURE;
1467
0
        } else {
1468
0
          if (ht->pDestructor) {
1469
0
            ht->pDestructor(data);
1470
0
          }
1471
0
          ZVAL_UNDEF(data);
1472
0
          HT_FLAGS(ht) |= HASH_FLAG_HAS_EMPTY_IND;
1473
0
        }
1474
0
      } else {
1475
0
        _zend_hash_del_el_ex(ht, idx, p, prev);
1476
0
      }
1477
0
      return SUCCESS;
1478
0
    }
1479
0
    prev = p;
1480
0
    idx = Z_NEXT(p->val);
1481
0
  }
1482
0
  return FAILURE;
1483
0
}
1484
1485
ZEND_API int ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
1486
3.47k
{
1487
3.47k
  zend_ulong h;
1488
3.47k
  uint32_t nIndex;
1489
3.47k
  uint32_t idx;
1490
3.47k
  Bucket *p;
1491
3.47k
  Bucket *prev = NULL;
1492
1493
3.47k
  IS_CONSISTENT(ht);
1494
3.47k
  HT_ASSERT_RC1(ht);
1495
1496
3.47k
  h = zend_inline_hash_func(str, len);
1497
3.47k
  nIndex = h | ht->nTableMask;
1498
1499
3.47k
  idx = HT_HASH(ht, nIndex);
1500
3.47k
  while (idx != HT_INVALID_IDX) {
1501
3.47k
    p = HT_HASH_TO_BUCKET(ht, idx);
1502
3.47k
    if ((p->h == h)
1503
3.47k
       && p->key
1504
3.47k
       && (ZSTR_LEN(p->key) == len)
1505
3.47k
       && !memcmp(ZSTR_VAL(p->key), str, len)) {
1506
3.47k
      _zend_hash_del_el_ex(ht, idx, p, prev);
1507
3.47k
      return SUCCESS;
1508
3.47k
    }
1509
0
    prev = p;
1510
0
    idx = Z_NEXT(p->val);
1511
0
  }
1512
0
  return FAILURE;
1513
3.47k
}
1514
1515
ZEND_API int ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
1516
1.12G
{
1517
1.12G
  uint32_t nIndex;
1518
1.12G
  uint32_t idx;
1519
1.12G
  Bucket *p;
1520
1.12G
  Bucket *prev = NULL;
1521
1522
1.12G
  IS_CONSISTENT(ht);
1523
1.12G
  HT_ASSERT_RC1(ht);
1524
1525
1.12G
  if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
1526
0
    if (h < ht->nNumUsed) {
1527
0
      p = ht->arData + h;
1528
0
      if (Z_TYPE(p->val) != IS_UNDEF) {
1529
0
        _zend_hash_del_el_ex(ht, HT_IDX_TO_HASH(h), p, NULL);
1530
0
        return SUCCESS;
1531
0
      }
1532
0
    }
1533
0
    return FAILURE;
1534
0
  }
1535
1.12G
  nIndex = h | ht->nTableMask;
1536
1537
1.12G
  idx = HT_HASH(ht, nIndex);
1538
1.13G
  while (idx != HT_INVALID_IDX) {
1539
1.12G
    p = HT_HASH_TO_BUCKET(ht, idx);
1540
1.12G
    if ((p->h == h) && (p->key == NULL)) {
1541
1.11G
      _zend_hash_del_el_ex(ht, idx, p, prev);
1542
1.11G
      return SUCCESS;
1543
1.11G
    }
1544
7.01M
    prev = p;
1545
7.01M
    idx = Z_NEXT(p->val);
1546
7.01M
  }
1547
8.13M
  return FAILURE;
1548
1.12G
}
1549
1550
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
1551
3.24M
{
1552
3.24M
  Bucket *p, *end;
1553
1554
3.24M
  IS_CONSISTENT(ht);
1555
3.24M
  HT_ASSERT(ht, GC_REFCOUNT(ht) <= 1);
1556
1557
3.24M
  if (ht->nNumUsed) {
1558
1.29M
    p = ht->arData;
1559
1.29M
    end = p + ht->nNumUsed;
1560
1.29M
    if (ht->pDestructor) {
1561
1.14M
      SET_INCONSISTENT(HT_IS_DESTROYING);
1562
1563
1.14M
      if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1564
1.13M
        if (HT_IS_WITHOUT_HOLES(ht)) {
1565
3.23M
          do {
1566
3.23M
            ht->pDestructor(&p->val);
1567
3.23M
          } while (++p != end);
1568
0
        } else {
1569
0
          do {
1570
0
            if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1571
0
              ht->pDestructor(&p->val);
1572
0
            }
1573
0
          } while (++p != end);
1574
0
        }
1575
13.0k
      } else if (HT_IS_WITHOUT_HOLES(ht)) {
1576
19.7k
        do {
1577
19.7k
          ht->pDestructor(&p->val);
1578
19.7k
          if (EXPECTED(p->key)) {
1579
19.7k
            zend_string_release(p->key);
1580
19.7k
          }
1581
19.7k
        } while (++p != end);
1582
0
      } else {
1583
0
        do {
1584
0
          if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1585
0
            ht->pDestructor(&p->val);
1586
0
            if (EXPECTED(p->key)) {
1587
0
              zend_string_release(p->key);
1588
0
            }
1589
0
          }
1590
0
        } while (++p != end);
1591
0
      }
1592
1593
1.14M
      SET_INCONSISTENT(HT_DESTROYED);
1594
152k
    } else {
1595
152k
      if (!HT_HAS_STATIC_KEYS_ONLY(ht)) {
1596
215k
        do {
1597
215k
          if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1598
212k
            if (EXPECTED(p->key)) {
1599
212k
              zend_string_release(p->key);
1600
212k
            }
1601
212k
          }
1602
215k
        } while (++p != end);
1603
82.7k
      }
1604
152k
    }
1605
1.29M
    zend_hash_iterators_remove(ht);
1606
1.95M
  } else if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1607
1.94M
    return;
1608
1.94M
  }
1609
1.30M
  pefree(HT_GET_DATA_ADDR(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1610
1.30M
}
1611
1612
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
1613
4.33M
{
1614
4.33M
  Bucket *p, *end;
1615
1616
4.33M
  IS_CONSISTENT(ht);
1617
4.33M
  HT_ASSERT(ht, GC_REFCOUNT(ht) <= 1);
1618
1619
  /* break possible cycles */
1620
4.33M
  GC_REMOVE_FROM_BUFFER(ht);
1621
4.33M
  GC_TYPE_INFO(ht) = GC_NULL /*???| (GC_WHITE << 16)*/;
1622
1623
4.33M
  if (ht->nNumUsed) {
1624
    /* In some rare cases destructors of regular arrays may be changed */
1625
173k
    if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) {
1626
1.57k
      zend_hash_destroy(ht);
1627
1.57k
      goto free_ht;
1628
1.57k
    }
1629
1630
171k
    p = ht->arData;
1631
171k
    end = p + ht->nNumUsed;
1632
171k
    SET_INCONSISTENT(HT_IS_DESTROYING);
1633
1634
171k
    if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1635
225k
      do {
1636
225k
        i_zval_ptr_dtor(&p->val);
1637
225k
      } while (++p != end);
1638
61.6k
    } else if (HT_IS_WITHOUT_HOLES(ht)) {
1639
253k
      do {
1640
253k
        i_zval_ptr_dtor(&p->val);
1641
253k
        if (EXPECTED(p->key)) {
1642
225k
          zend_string_release_ex(p->key, 0);
1643
225k
        }
1644
253k
      } while (++p != end);
1645
0
    } else {
1646
0
      do {
1647
0
        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1648
0
          i_zval_ptr_dtor(&p->val);
1649
0
          if (EXPECTED(p->key)) {
1650
0
            zend_string_release_ex(p->key, 0);
1651
0
          }
1652
0
        }
1653
0
      } while (++p != end);
1654
0
    }
1655
171k
    zend_hash_iterators_remove(ht);
1656
171k
    SET_INCONSISTENT(HT_DESTROYED);
1657
4.16M
  } else if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1658
4.16M
    goto free_ht;
1659
4.16M
  }
1660
171k
  efree(HT_GET_DATA_ADDR(ht));
1661
4.33M
free_ht:
1662
4.33M
  FREE_HASHTABLE(ht);
1663
4.33M
}
1664
1665
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
1666
401k
{
1667
401k
  Bucket *p, *end;
1668
1669
401k
  IS_CONSISTENT(ht);
1670
401k
  HT_ASSERT_RC1(ht);
1671
1672
401k
  if (ht->nNumUsed) {
1673
17.9k
    p = ht->arData;
1674
17.9k
    end = p + ht->nNumUsed;
1675
17.9k
    if (ht->pDestructor) {
1676
0
      if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1677
0
        if (HT_IS_WITHOUT_HOLES(ht)) {
1678
0
          do {
1679
0
            ht->pDestructor(&p->val);
1680
0
          } while (++p != end);
1681
0
        } else {
1682
0
          do {
1683
0
            if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1684
0
              ht->pDestructor(&p->val);
1685
0
            }
1686
0
          } while (++p != end);
1687
0
        }
1688
0
      } else if (HT_IS_WITHOUT_HOLES(ht)) {
1689
0
        do {
1690
0
          ht->pDestructor(&p->val);
1691
0
          if (EXPECTED(p->key)) {
1692
0
            zend_string_release(p->key);
1693
0
          }
1694
0
        } while (++p != end);
1695
0
      } else {
1696
0
        do {
1697
0
          if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1698
0
            ht->pDestructor(&p->val);
1699
0
            if (EXPECTED(p->key)) {
1700
0
              zend_string_release(p->key);
1701
0
            }
1702
0
          }
1703
0
        } while (++p != end);
1704
0
      }
1705
17.9k
    } else {
1706
17.9k
      if (!HT_HAS_STATIC_KEYS_ONLY(ht)) {
1707
0
        if (HT_IS_WITHOUT_HOLES(ht)) {
1708
0
          do {
1709
0
            if (EXPECTED(p->key)) {
1710
0
              zend_string_release(p->key);
1711
0
            }
1712
0
          } while (++p != end);
1713
0
        } else {
1714
0
          do {
1715
0
            if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1716
0
              if (EXPECTED(p->key)) {
1717
0
                zend_string_release(p->key);
1718
0
              }
1719
0
            }
1720
0
          } while (++p != end);
1721
0
        }
1722
0
      }
1723
17.9k
    }
1724
17.9k
    if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED)) {
1725
17.9k
      HT_HASH_RESET(ht);
1726
17.9k
    }
1727
17.9k
  }
1728
401k
  ht->nNumUsed = 0;
1729
401k
  ht->nNumOfElements = 0;
1730
401k
  ht->nNextFreeElement = ZEND_LONG_MIN;
1731
401k
  ht->nInternalPointer = 0;
1732
401k
}
1733
1734
ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
1735
0
{
1736
0
  Bucket *p, *end;
1737
1738
0
  IS_CONSISTENT(ht);
1739
0
  HT_ASSERT_RC1(ht);
1740
1741
0
  if (ht->nNumUsed) {
1742
0
    p = ht->arData;
1743
0
    end = p + ht->nNumUsed;
1744
0
    if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1745
0
      do {
1746
0
        i_zval_ptr_dtor(&p->val);
1747
0
      } while (++p != end);
1748
0
    } else if (HT_IS_WITHOUT_HOLES(ht)) {
1749
0
      do {
1750
0
        i_zval_ptr_dtor(&p->val);
1751
0
        if (EXPECTED(p->key)) {
1752
0
          zend_string_release(p->key);
1753
0
        }
1754
0
      } while (++p != end);
1755
0
    } else {
1756
0
      do {
1757
0
        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1758
0
          i_zval_ptr_dtor(&p->val);
1759
0
          if (EXPECTED(p->key)) {
1760
0
            zend_string_release(p->key);
1761
0
          }
1762
0
        }
1763
0
      } while (++p != end);
1764
0
    }
1765
0
    HT_HASH_RESET(ht);
1766
0
  }
1767
0
  ht->nNumUsed = 0;
1768
0
  ht->nNumOfElements = 0;
1769
0
  ht->nNextFreeElement = ZEND_LONG_MIN;
1770
0
  ht->nInternalPointer = 0;
1771
0
}
1772
1773
ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht)
1774
0
{
1775
0
  uint32_t idx;
1776
0
  Bucket *p;
1777
1778
0
  IS_CONSISTENT(ht);
1779
0
  HT_ASSERT_RC1(ht);
1780
1781
0
  p = ht->arData;
1782
0
  for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
1783
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1784
0
    _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
1785
0
  }
1786
0
  if (!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1787
0
    pefree(HT_GET_DATA_ADDR(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1788
0
  }
1789
1790
0
  SET_INCONSISTENT(HT_DESTROYED);
1791
0
}
1792
1793
ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht)
1794
781k
{
1795
781k
  uint32_t idx;
1796
781k
  Bucket *p;
1797
1798
781k
  IS_CONSISTENT(ht);
1799
781k
  HT_ASSERT_RC1(ht);
1800
1801
781k
  idx = ht->nNumUsed;
1802
781k
  p = ht->arData + ht->nNumUsed;
1803
2.34M
  while (idx > 0) {
1804
1.56M
    idx--;
1805
1.56M
    p--;
1806
1.56M
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1807
1.56M
    _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
1808
1.56M
  }
1809
1810
781k
  if (!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1811
390k
    pefree(HT_GET_DATA_ADDR(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1812
390k
  }
1813
1814
781k
  SET_INCONSISTENT(HT_DESTROYED);
1815
781k
}
1816
1817
/* This is used to recurse elements and selectively delete certain entries
1818
 * from a hashtable. apply_func() receives the data and decides if the entry
1819
 * should be deleted or recursion should be stopped. The following three
1820
 * return codes are possible:
1821
 * ZEND_HASH_APPLY_KEEP   - continue
1822
 * ZEND_HASH_APPLY_STOP   - stop iteration
1823
 * ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former
1824
 */
1825
1826
ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func)
1827
3.47k
{
1828
3.47k
  uint32_t idx;
1829
3.47k
  Bucket *p;
1830
3.47k
  int result;
1831
1832
3.47k
  IS_CONSISTENT(ht);
1833
1834
38.2k
  for (idx = 0; idx < ht->nNumUsed; idx++) {
1835
34.7k
    p = ht->arData + idx;
1836
34.7k
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1837
34.7k
    result = apply_func(&p->val);
1838
1839
34.7k
    if (result & ZEND_HASH_APPLY_REMOVE) {
1840
0
      HT_ASSERT_RC1(ht);
1841
0
      _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
1842
0
    }
1843
34.7k
    if (result & ZEND_HASH_APPLY_STOP) {
1844
0
      break;
1845
0
    }
1846
34.7k
  }
1847
3.47k
}
1848
1849
1850
ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
1851
0
{
1852
0
    uint32_t idx;
1853
0
  Bucket *p;
1854
0
  int result;
1855
1856
0
  IS_CONSISTENT(ht);
1857
1858
0
  for (idx = 0; idx < ht->nNumUsed; idx++) {
1859
0
    p = ht->arData + idx;
1860
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1861
0
    result = apply_func(&p->val, argument);
1862
1863
0
    if (result & ZEND_HASH_APPLY_REMOVE) {
1864
0
      HT_ASSERT_RC1(ht);
1865
0
      _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
1866
0
    }
1867
0
    if (result & ZEND_HASH_APPLY_STOP) {
1868
0
      break;
1869
0
    }
1870
0
  }
1871
0
}
1872
1873
1874
ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int num_args, ...)
1875
0
{
1876
0
  uint32_t idx;
1877
0
  Bucket *p;
1878
0
  va_list args;
1879
0
  zend_hash_key hash_key;
1880
0
  int result;
1881
1882
0
  IS_CONSISTENT(ht);
1883
1884
0
  for (idx = 0; idx < ht->nNumUsed; idx++) {
1885
0
    p = ht->arData + idx;
1886
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1887
0
    va_start(args, num_args);
1888
0
    hash_key.h = p->h;
1889
0
    hash_key.key = p->key;
1890
1891
0
    result = apply_func(&p->val, num_args, args, &hash_key);
1892
1893
0
    if (result & ZEND_HASH_APPLY_REMOVE) {
1894
0
      HT_ASSERT_RC1(ht);
1895
0
      _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
1896
0
    }
1897
0
    if (result & ZEND_HASH_APPLY_STOP) {
1898
0
      va_end(args);
1899
0
      break;
1900
0
    }
1901
0
    va_end(args);
1902
0
  }
1903
0
}
1904
1905
1906
ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func)
1907
390k
{
1908
390k
  uint32_t idx;
1909
390k
  Bucket *p;
1910
390k
  int result;
1911
1912
390k
  IS_CONSISTENT(ht);
1913
1914
390k
  idx = ht->nNumUsed;
1915
1.95M
  while (idx > 0) {
1916
1.56M
    idx--;
1917
1.56M
    p = ht->arData + idx;
1918
1.56M
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1919
1920
1.56M
    result = apply_func(&p->val);
1921
1922
1.56M
    if (result & ZEND_HASH_APPLY_REMOVE) {
1923
0
      HT_ASSERT_RC1(ht);
1924
0
      _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
1925
0
    }
1926
1.56M
    if (result & ZEND_HASH_APPLY_STOP) {
1927
0
      break;
1928
0
    }
1929
1.56M
  }
1930
390k
}
1931
1932
1933
ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
1934
0
{
1935
0
    uint32_t idx;
1936
0
  Bucket *p;
1937
0
  zval *new_entry, *data;
1938
1939
0
  IS_CONSISTENT(source);
1940
0
  IS_CONSISTENT(target);
1941
0
  HT_ASSERT_RC1(target);
1942
1943
0
  for (idx = 0; idx < source->nNumUsed; idx++) {
1944
0
    p = source->arData + idx;
1945
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
1946
1947
    /* INDIRECT element may point to UNDEF-ined slots */
1948
0
    data = &p->val;
1949
0
    if (Z_TYPE_P(data) == IS_INDIRECT) {
1950
0
      data = Z_INDIRECT_P(data);
1951
0
      if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
1952
0
        continue;
1953
0
      }
1954
0
    }
1955
0
    if (p->key) {
1956
0
      new_entry = zend_hash_update(target, p->key, data);
1957
0
    } else {
1958
0
      new_entry = zend_hash_index_update(target, p->h, data);
1959
0
    }
1960
0
    if (pCopyConstructor) {
1961
0
      pCopyConstructor(new_entry);
1962
0
    }
1963
0
  }
1964
0
}
1965
1966
1967
static zend_always_inline int zend_array_dup_element(HashTable *source, HashTable *target, uint32_t idx, Bucket *p, Bucket *q, int packed, int static_keys, int with_holes)
1968
134k
{
1969
134k
  zval *data = &p->val;
1970
1971
134k
  if (with_holes) {
1972
2.17k
    if (!packed && Z_TYPE_INFO_P(data) == IS_INDIRECT) {
1973
0
      data = Z_INDIRECT_P(data);
1974
0
    }
1975
2.17k
    if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
1976
1.07k
      return 0;
1977
1.07k
    }
1978
132k
  } else if (!packed) {
1979
    /* INDIRECT element may point to UNDEF-ined slots */
1980
123k
    if (Z_TYPE_INFO_P(data) == IS_INDIRECT) {
1981
0
      data = Z_INDIRECT_P(data);
1982
0
      if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
1983
0
        return 0;
1984
0
      }
1985
133k
    }
1986
123k
  }
1987
1988
133k
  do {
1989
133k
    if (Z_OPT_REFCOUNTED_P(data)) {
1990
35.2k
      if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1 &&
1991
0
          (Z_TYPE_P(Z_REFVAL_P(data)) != IS_ARRAY ||
1992
0
            Z_ARRVAL_P(Z_REFVAL_P(data)) != source)) {
1993
0
        data = Z_REFVAL_P(data);
1994
0
        if (!Z_OPT_REFCOUNTED_P(data)) {
1995
0
          break;
1996
0
        }
1997
35.2k
      }
1998
35.2k
      Z_ADDREF_P(data);
1999
35.2k
    }
2000
133k
  } while (0);
2001
133k
  ZVAL_COPY_VALUE(&q->val, data);
2002
2003
133k
  q->h = p->h;
2004
133k
  if (packed) {
2005
10.2k
    q->key = NULL;
2006
123k
  } else {
2007
123k
    uint32_t nIndex;
2008
2009
123k
    q->key = p->key;
2010
123k
    if (!static_keys && q->key) {
2011
104k
      zend_string_addref(q->key);
2012
104k
    }
2013
2014
123k
    nIndex = q->h | target->nTableMask;
2015
123k
    Z_NEXT(q->val) = HT_HASH(target, nIndex);
2016
123k
    HT_HASH(target, nIndex) = HT_IDX_TO_HASH(idx);
2017
123k
  }
2018
133k
  return 1;
2019
133k
}
2020
2021
static zend_always_inline void zend_array_dup_packed_elements(HashTable *source, HashTable *target, int with_holes)
2022
7.31k
{
2023
7.31k
  Bucket *p = source->arData;
2024
7.31k
  Bucket *q = target->arData;
2025
7.31k
  Bucket *end = p + source->nNumUsed;
2026
2027
11.3k
  do {
2028
11.3k
    if (!zend_array_dup_element(source, target, 0, p, q, 1, 1, with_holes)) {
2029
1.07k
      if (with_holes) {
2030
1.07k
        ZVAL_UNDEF(&q->val);
2031
1.07k
      }
2032
1.07k
    }
2033
11.3k
    p++; q++;
2034
11.3k
  } while (p != end);
2035
7.31k
}
2036
2037
static zend_always_inline uint32_t zend_array_dup_elements(HashTable *source, HashTable *target, int static_keys, int with_holes)
2038
18.1k
{
2039
18.1k
  uint32_t idx = 0;
2040
18.1k
  Bucket *p = source->arData;
2041
18.1k
  Bucket *q = target->arData;
2042
18.1k
  Bucket *end = p + source->nNumUsed;
2043
2044
123k
  do {
2045
123k
    if (!zend_array_dup_element(source, target, idx, p, q, 0, static_keys, with_holes)) {
2046
0
      uint32_t target_idx = idx;
2047
2048
0
      idx++; p++;
2049
0
      while (p != end) {
2050
0
        if (zend_array_dup_element(source, target, target_idx, p, q, 0, static_keys, with_holes)) {
2051
0
          if (source->nInternalPointer == idx) {
2052
0
            target->nInternalPointer = target_idx;
2053
0
          }
2054
0
          target_idx++; q++;
2055
0
        }
2056
0
        idx++; p++;
2057
0
      }
2058
0
      return target_idx;
2059
0
    }
2060
123k
    idx++; p++; q++;
2061
123k
  } while (p != end);
2062
18.1k
  return idx;
2063
18.1k
}
2064
2065
ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
2066
25.9k
{
2067
25.9k
  uint32_t idx;
2068
25.9k
  HashTable *target;
2069
2070
25.9k
  IS_CONSISTENT(source);
2071
2072
25.9k
  ALLOC_HASHTABLE(target);
2073
25.9k
  GC_SET_REFCOUNT(target, 1);
2074
25.9k
  GC_TYPE_INFO(target) = GC_ARRAY;
2075
2076
25.9k
  target->pDestructor = ZVAL_PTR_DTOR;
2077
2078
25.9k
  if (source->nNumOfElements == 0) {
2079
512
    HT_FLAGS(target) = HASH_FLAG_UNINITIALIZED;
2080
512
    target->nTableMask = HT_MIN_MASK;
2081
512
    target->nNumUsed = 0;
2082
512
    target->nNumOfElements = 0;
2083
512
    target->nNextFreeElement = source->nNextFreeElement;
2084
512
    target->nInternalPointer = 0;
2085
512
    target->nTableSize = HT_MIN_SIZE;
2086
512
    HT_SET_DATA_ADDR(target, &uninitialized_bucket);
2087
25.4k
  } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
2088
0
    HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK;
2089
0
    target->nTableMask = source->nTableMask;
2090
0
    target->nNumUsed = source->nNumUsed;
2091
0
    target->nNumOfElements = source->nNumOfElements;
2092
0
    target->nNextFreeElement = source->nNextFreeElement;
2093
0
    target->nTableSize = source->nTableSize;
2094
0
    HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
2095
0
    target->nInternalPointer = source->nInternalPointer;
2096
0
    memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source));
2097
25.4k
  } else if (HT_FLAGS(source) & HASH_FLAG_PACKED) {
2098
7.31k
    HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK;
2099
7.31k
    target->nTableMask = HT_MIN_MASK;
2100
7.31k
    target->nNumUsed = source->nNumUsed;
2101
7.31k
    target->nNumOfElements = source->nNumOfElements;
2102
7.31k
    target->nNextFreeElement = source->nNextFreeElement;
2103
7.31k
    target->nTableSize = source->nTableSize;
2104
7.31k
    HT_SET_DATA_ADDR(target, emalloc(HT_SIZE_EX(target->nTableSize, HT_MIN_MASK)));
2105
7.31k
    target->nInternalPointer =
2106
7.31k
      (source->nInternalPointer < source->nNumUsed) ?
2107
7.31k
        source->nInternalPointer : 0;
2108
2109
7.31k
    HT_HASH_RESET_PACKED(target);
2110
2111
7.31k
    if (HT_IS_WITHOUT_HOLES(target)) {
2112
6.76k
      zend_array_dup_packed_elements(source, target, 0);
2113
551
    } else {
2114
551
      zend_array_dup_packed_elements(source, target, 1);
2115
551
    }
2116
18.1k
  } else {
2117
18.1k
    HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK;
2118
18.1k
    target->nTableMask = source->nTableMask;
2119
18.1k
    target->nNextFreeElement = source->nNextFreeElement;
2120
18.1k
    target->nInternalPointer =
2121
18.1k
      (source->nInternalPointer < source->nNumUsed) ?
2122
18.1k
        source->nInternalPointer : 0;
2123
2124
18.1k
    target->nTableSize = source->nTableSize;
2125
18.1k
    HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
2126
18.1k
    HT_HASH_RESET(target);
2127
2128
18.1k
    if (HT_HAS_STATIC_KEYS_ONLY(target)) {
2129
2.04k
      if (HT_IS_WITHOUT_HOLES(source)) {
2130
2.04k
        idx = zend_array_dup_elements(source, target, 1, 0);
2131
0
      } else {
2132
0
        idx = zend_array_dup_elements(source, target, 1, 1);
2133
0
      }
2134
16.1k
    } else {
2135
16.1k
      if (HT_IS_WITHOUT_HOLES(source)) {
2136
16.1k
        idx = zend_array_dup_elements(source, target, 0, 0);
2137
0
      } else {
2138
0
        idx = zend_array_dup_elements(source, target, 0, 1);
2139
0
      }
2140
16.1k
    }
2141
18.1k
    target->nNumUsed = idx;
2142
18.1k
    target->nNumOfElements = idx;
2143
18.1k
  }
2144
25.9k
  return target;
2145
25.9k
}
2146
2147
2148
ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, zend_bool overwrite)
2149
25.9k
{
2150
25.9k
    uint32_t idx;
2151
25.9k
  Bucket *p;
2152
25.9k
  zval *t;
2153
2154
25.9k
  IS_CONSISTENT(source);
2155
25.9k
  IS_CONSISTENT(target);
2156
25.9k
  HT_ASSERT_RC1(target);
2157
2158
25.9k
  if (overwrite) {
2159
0
    for (idx = 0; idx < source->nNumUsed; idx++) {
2160
0
      p = source->arData + idx;
2161
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2162
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_INDIRECT) &&
2163
0
          UNEXPECTED(Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) {
2164
0
          continue;
2165
0
      }
2166
0
      if (p->key) {
2167
0
        t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_UPDATE | HASH_UPDATE_INDIRECT);
2168
0
        if (pCopyConstructor) {
2169
0
          pCopyConstructor(t);
2170
0
        }
2171
0
      } else {
2172
0
        t = zend_hash_index_update(target, p->h, &p->val);
2173
0
        if (pCopyConstructor) {
2174
0
          pCopyConstructor(t);
2175
0
        }
2176
0
      }
2177
0
    }
2178
25.9k
  } else {
2179
45.6k
    for (idx = 0; idx < source->nNumUsed; idx++) {
2180
19.6k
      p = source->arData + idx;
2181
19.6k
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2182
18.2k
      if (UNEXPECTED(Z_TYPE(p->val) == IS_INDIRECT) &&
2183
0
          UNEXPECTED(Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) {
2184
0
          continue;
2185
0
      }
2186
18.2k
      if (p->key) {
2187
9.90k
        t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_ADD | HASH_UPDATE_INDIRECT);
2188
9.90k
        if (t && pCopyConstructor) {
2189
5.35k
          pCopyConstructor(t);
2190
5.35k
        }
2191
8.32k
      } else {
2192
8.32k
        t = zend_hash_index_add(target, p->h, &p->val);
2193
8.32k
        if (t && pCopyConstructor) {
2194
2.33k
          pCopyConstructor(t);
2195
2.33k
        }
2196
8.32k
      }
2197
18.2k
    }
2198
25.9k
  }
2199
25.9k
}
2200
2201
2202
static zend_bool ZEND_FASTCALL zend_hash_replace_checker_wrapper(HashTable *target, zval *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func)
2203
0
{
2204
0
  zend_hash_key hash_key;
2205
2206
0
  hash_key.h = p->h;
2207
0
  hash_key.key = p->key;
2208
0
  return merge_checker_func(target, source_data, &hash_key, pParam);
2209
0
}
2210
2211
2212
ZEND_API void ZEND_FASTCALL zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam)
2213
0
{
2214
0
  uint32_t idx;
2215
0
  Bucket *p;
2216
0
  zval *t;
2217
2218
0
  IS_CONSISTENT(source);
2219
0
  IS_CONSISTENT(target);
2220
0
  HT_ASSERT_RC1(target);
2221
2222
0
  for (idx = 0; idx < source->nNumUsed; idx++) {
2223
0
    p = source->arData + idx;
2224
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2225
0
    if (zend_hash_replace_checker_wrapper(target, &p->val, p, pParam, pMergeSource)) {
2226
0
      t = zend_hash_update(target, p->key, &p->val);
2227
0
      if (pCopyConstructor) {
2228
0
        pCopyConstructor(t);
2229
0
      }
2230
0
    }
2231
0
  }
2232
0
}
2233
2234
2235
/* Returns the hash table data if found and NULL if not. */
2236
ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
2237
15.9M
{
2238
15.9M
  Bucket *p;
2239
2240
15.9M
  IS_CONSISTENT(ht);
2241
2242
15.9M
  p = zend_hash_find_bucket(ht, key, 0);
2243
10.0M
  return p ? &p->val : NULL;
2244
15.9M
}
2245
2246
ZEND_API zval* ZEND_FASTCALL _zend_hash_find_known_hash(const HashTable *ht, zend_string *key)
2247
4.93M
{
2248
4.93M
  Bucket *p;
2249
2250
4.93M
  IS_CONSISTENT(ht);
2251
2252
4.93M
  p = zend_hash_find_bucket(ht, key, 1);
2253
1.03M
  return p ? &p->val : NULL;
2254
4.93M
}
2255
2256
ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
2257
136k
{
2258
136k
  zend_ulong h;
2259
136k
  Bucket *p;
2260
2261
136k
  IS_CONSISTENT(ht);
2262
2263
136k
  h = zend_inline_hash_func(str, len);
2264
136k
  p = zend_hash_str_find_bucket(ht, str, len, h);
2265
49.8k
  return p ? &p->val : NULL;
2266
136k
}
2267
2268
ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
2269
413k
{
2270
413k
  Bucket *p;
2271
2272
413k
  IS_CONSISTENT(ht);
2273
2274
413k
  if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
2275
3.22k
    if (h < ht->nNumUsed) {
2276
2.45k
      p = ht->arData + h;
2277
2.45k
      if (Z_TYPE(p->val) != IS_UNDEF) {
2278
2.30k
        return &p->val;
2279
2.30k
      }
2280
924
    }
2281
924
    return NULL;
2282
924
  }
2283
2284
409k
  p = zend_hash_index_find_bucket(ht, h);
2285
409k
  return p ? &p->val : NULL;
2286
409k
}
2287
2288
ZEND_API zval* ZEND_FASTCALL _zend_hash_index_find(const HashTable *ht, zend_ulong h)
2289
0
{
2290
0
  Bucket *p;
2291
2292
0
  IS_CONSISTENT(ht);
2293
2294
0
  p = zend_hash_index_find_bucket(ht, h);
2295
0
  return p ? &p->val : NULL;
2296
0
}
2297
2298
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
2299
0
{
2300
0
  IS_CONSISTENT(ht);
2301
0
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2302
0
  *pos = _zend_hash_get_valid_pos(ht, 0);
2303
0
}
2304
2305
2306
/* This function will be extremely optimized by remembering
2307
 * the end of the list
2308
 */
2309
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
2310
0
{
2311
0
  uint32_t idx;
2312
2313
0
  IS_CONSISTENT(ht);
2314
0
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2315
2316
0
  idx = ht->nNumUsed;
2317
0
  while (idx > 0) {
2318
0
    idx--;
2319
0
    if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
2320
0
      *pos = idx;
2321
0
      return;
2322
0
    }
2323
0
  }
2324
0
  *pos = ht->nNumUsed;
2325
0
}
2326
2327
2328
ZEND_API int ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
2329
0
{
2330
0
  uint32_t idx;
2331
2332
0
  IS_CONSISTENT(ht);
2333
0
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2334
2335
0
  idx = _zend_hash_get_valid_pos(ht, *pos);
2336
0
  if (idx < ht->nNumUsed) {
2337
0
    while (1) {
2338
0
      idx++;
2339
0
      if (idx >= ht->nNumUsed) {
2340
0
        *pos = ht->nNumUsed;
2341
0
        return SUCCESS;
2342
0
      }
2343
0
      if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
2344
0
        *pos = idx;
2345
0
        return SUCCESS;
2346
0
      }
2347
0
    }
2348
0
  } else {
2349
0
    return FAILURE;
2350
0
  }
2351
0
}
2352
2353
ZEND_API int ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
2354
0
{
2355
0
  uint32_t idx = *pos;
2356
2357
0
  IS_CONSISTENT(ht);
2358
0
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2359
2360
0
  if (idx < ht->nNumUsed) {
2361
0
    while (idx > 0) {
2362
0
      idx--;
2363
0
      if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
2364
0
        *pos = idx;
2365
0
        return SUCCESS;
2366
0
      }
2367
0
    }
2368
0
    *pos = ht->nNumUsed;
2369
0
    return SUCCESS;
2370
0
  } else {
2371
0
    return FAILURE;
2372
0
  }
2373
0
}
2374
2375
2376
/* This function should be made binary safe  */
2377
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, HashPosition *pos)
2378
0
{
2379
0
  uint32_t idx;
2380
0
  Bucket *p;
2381
2382
0
  IS_CONSISTENT(ht);
2383
0
  idx = _zend_hash_get_valid_pos(ht, *pos);
2384
0
  if (idx < ht->nNumUsed) {
2385
0
    p = ht->arData + idx;
2386
0
    if (p->key) {
2387
0
      *str_index = p->key;
2388
0
      return HASH_KEY_IS_STRING;
2389
0
    } else {
2390
0
      *num_index = p->h;
2391
0
      return HASH_KEY_IS_LONG;
2392
0
    }
2393
0
  }
2394
0
  return HASH_KEY_NON_EXISTENT;
2395
0
}
2396
2397
ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
2398
0
{
2399
0
  uint32_t idx;
2400
0
  Bucket *p;
2401
2402
0
  IS_CONSISTENT(ht);
2403
0
  idx = _zend_hash_get_valid_pos(ht, *pos);
2404
0
  if (idx >= ht->nNumUsed) {
2405
0
    ZVAL_NULL(key);
2406
0
  } else {
2407
0
    p = ht->arData + idx;
2408
0
    if (p->key) {
2409
0
      ZVAL_STR_COPY(key, p->key);
2410
0
    } else {
2411
0
      ZVAL_LONG(key, p->h);
2412
0
    }
2413
0
  }
2414
0
}
2415
2416
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
2417
0
{
2418
0
  uint32_t idx;
2419
0
  Bucket *p;
2420
2421
0
  IS_CONSISTENT(ht);
2422
0
  idx = _zend_hash_get_valid_pos(ht, *pos);
2423
0
  if (idx < ht->nNumUsed) {
2424
0
    p = ht->arData + idx;
2425
0
    if (p->key) {
2426
0
      return HASH_KEY_IS_STRING;
2427
0
    } else {
2428
0
      return HASH_KEY_IS_LONG;
2429
0
    }
2430
0
  }
2431
0
  return HASH_KEY_NON_EXISTENT;
2432
0
}
2433
2434
2435
ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
2436
0
{
2437
0
  uint32_t idx;
2438
0
  Bucket *p;
2439
2440
0
  IS_CONSISTENT(ht);
2441
0
  idx = _zend_hash_get_valid_pos(ht, *pos);
2442
0
  if (idx < ht->nNumUsed) {
2443
0
    p = ht->arData + idx;
2444
0
    return &p->val;
2445
0
  } else {
2446
0
    return NULL;
2447
0
  }
2448
0
}
2449
2450
ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q)
2451
0
{
2452
0
  zval val;
2453
0
  zend_ulong h;
2454
0
  zend_string *key;
2455
2456
0
  val = p->val;
2457
0
  h = p->h;
2458
0
  key = p->key;
2459
2460
0
  p->val = q->val;
2461
0
  p->h = q->h;
2462
0
  p->key = q->key;
2463
2464
0
  q->val = val;
2465
0
  q->h = h;
2466
0
  q->key = key;
2467
0
}
2468
2469
ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q)
2470
0
{
2471
0
  zval val;
2472
2473
0
  val = p->val;
2474
0
  p->val = q->val;
2475
0
  q->val = val;
2476
0
}
2477
2478
ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q)
2479
0
{
2480
0
  zval val;
2481
0
  zend_ulong h;
2482
2483
0
  val = p->val;
2484
0
  h = p->h;
2485
2486
0
  p->val = q->val;
2487
0
  p->h = q->h;
2488
2489
0
  q->val = val;
2490
0
  q->h = h;
2491
0
}
2492
2493
ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, zend_bool renumber)
2494
3.47k
{
2495
3.47k
  Bucket *p;
2496
3.47k
  uint32_t i, j;
2497
2498
3.47k
  IS_CONSISTENT(ht);
2499
3.47k
  HT_ASSERT_RC1(ht);
2500
2501
3.47k
  if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) {
2502
    /* Doesn't require sorting */
2503
0
    return;
2504
0
  }
2505
2506
3.47k
  if (HT_IS_WITHOUT_HOLES(ht)) {
2507
    /* Store original order of elements in extra space to allow stable sorting. */
2508
38.2k
    for (i = 0; i < ht->nNumUsed; i++) {
2509
34.7k
      Z_EXTRA(ht->arData[i].val) = i;
2510
34.7k
    }
2511
0
  } else {
2512
    /* Remove holes and store original order. */
2513
0
    for (j = 0, i = 0; j < ht->nNumUsed; j++) {
2514
0
      p = ht->arData + j;
2515
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2516
0
      if (i != j) {
2517
0
        ht->arData[i] = *p;
2518
0
      }
2519
0
      Z_EXTRA(ht->arData[i].val) = i;
2520
0
      i++;
2521
0
    }
2522
0
    ht->nNumUsed = i;
2523
0
  }
2524
2525
3.47k
  sort((void *)ht->arData, ht->nNumUsed, sizeof(Bucket), (compare_func_t) compar,
2526
0
      (swap_func_t)(renumber? zend_hash_bucket_renum_swap :
2527
3.47k
        ((HT_FLAGS(ht) & HASH_FLAG_PACKED) ? zend_hash_bucket_packed_swap : zend_hash_bucket_swap)));
2528
2529
3.47k
  ht->nInternalPointer = 0;
2530
2531
3.47k
  if (renumber) {
2532
0
    for (j = 0; j < i; j++) {
2533
0
      p = ht->arData + j;
2534
0
      p->h = j;
2535
0
      if (p->key) {
2536
0
        zend_string_release(p->key);
2537
0
        p->key = NULL;
2538
0
      }
2539
0
    }
2540
2541
0
    ht->nNextFreeElement = i;
2542
0
  }
2543
3.47k
  if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
2544
0
    if (!renumber) {
2545
0
      zend_hash_packed_to_hash(ht);
2546
0
    }
2547
3.47k
  } else {
2548
3.47k
    if (renumber) {
2549
0
      void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
2550
0
      Bucket *old_buckets = ht->arData;
2551
2552
0
      new_data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), (GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
2553
0
      HT_FLAGS(ht) |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
2554
0
      ht->nTableMask = HT_MIN_MASK;
2555
0
      HT_SET_DATA_ADDR(ht, new_data);
2556
0
      memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
2557
0
      pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
2558
0
      HT_HASH_RESET_PACKED(ht);
2559
3.47k
    } else {
2560
3.47k
      zend_hash_rehash(ht);
2561
3.47k
    }
2562
3.47k
  }
2563
3.47k
}
2564
2565
5.30k
static zend_always_inline int zend_hash_compare_impl(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered) {
2566
5.30k
  uint32_t idx1, idx2;
2567
2568
5.30k
  if (ht1->nNumOfElements != ht2->nNumOfElements) {
2569
1.57k
    return ht1->nNumOfElements > ht2->nNumOfElements ? 1 : -1;
2570
1.80k
  }
2571
2572
6.37k
  for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
2573
5.35k
    Bucket *p1 = ht1->arData + idx1, *p2;
2574
5.35k
    zval *pData1, *pData2;
2575
5.35k
    int result;
2576
2577
5.35k
    if (Z_TYPE(p1->val) == IS_UNDEF) continue;
2578
3.80k
    if (ordered) {
2579
564
      while (1) {
2580
564
        ZEND_ASSERT(idx2 != ht2->nNumUsed);
2581
564
        p2 = ht2->arData + idx2;
2582
564
        if (Z_TYPE(p2->val) != IS_UNDEF) break;
2583
8
        idx2++;
2584
8
      }
2585
556
      if (p1->key == NULL && p2->key == NULL) { /* numeric indices */
2586
525
        if (p1->h != p2->h) {
2587
136
          return p1->h > p2->h ? 1 : -1;
2588
214
        }
2589
31
      } else if (p1->key != NULL && p2->key != NULL) { /* string indices */
2590
0
        if (ZSTR_LEN(p1->key) != ZSTR_LEN(p2->key)) {
2591
0
          return ZSTR_LEN(p1->key) > ZSTR_LEN(p2->key) ? 1 : -1;
2592
0
        }
2593
2594
0
        result = memcmp(ZSTR_VAL(p1->key), ZSTR_VAL(p2->key), ZSTR_LEN(p1->key));
2595
0
        if (result != 0) {
2596
0
          return result;
2597
0
        }
2598
31
      } else {
2599
        /* Mixed key types: A string key is considered as larger */
2600
31
        return p1->key != NULL ? 1 : -1;
2601
31
      }
2602
311
      pData2 = &p2->val;
2603
311
      idx2++;
2604
3.24k
    } else {
2605
3.24k
      if (p1->key == NULL) { /* numeric index */
2606
3.11k
        pData2 = zend_hash_index_find(ht2, p1->h);
2607
3.11k
        if (pData2 == NULL) {
2608
1.13k
          return 1;
2609
1.13k
        }
2610
132
      } else { /* string index */
2611
132
        pData2 = zend_hash_find(ht2, p1->key);
2612
132
        if (pData2 == NULL) {
2613
121
          return 1;
2614
121
        }
2615
2.30k
      }
2616
3.24k
    }
2617
2618
2.30k
    pData1 = &p1->val;
2619
2.30k
    if (Z_TYPE_P(pData1) == IS_INDIRECT) {
2620
0
      pData1 = Z_INDIRECT_P(pData1);
2621
0
    }
2622
2.30k
    if (Z_TYPE_P(pData2) == IS_INDIRECT) {
2623
0
      pData2 = Z_INDIRECT_P(pData2);
2624
0
    }
2625
2626
2.30k
    if (Z_TYPE_P(pData1) == IS_UNDEF) {
2627
0
      if (Z_TYPE_P(pData2) != IS_UNDEF) {
2628
0
        return -1;
2629
0
      }
2630
2.30k
    } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
2631
0
      return 1;
2632
2.30k
    } else {
2633
2.30k
      result = compar(pData1, pData2);
2634
2.30k
      if (result != 0) {
2635
973
        return result;
2636
973
      }
2637
2.30k
    }
2638
2.30k
  }
2639
2640
1.02k
  return 0;
2641
3.49k
}
2642
2643
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered)
2644
5.30k
{
2645
5.30k
  int result;
2646
5.30k
  IS_CONSISTENT(ht1);
2647
5.30k
  IS_CONSISTENT(ht2);
2648
2649
5.30k
  if (ht1 == ht2) {
2650
0
    return 0;
2651
0
  }
2652
2653
  /* It's enough to protect only one of the arrays.
2654
   * The second one may be referenced from the first and this may cause
2655
   * false recursion detection.
2656
   */
2657
5.30k
  if (UNEXPECTED(GC_IS_RECURSIVE(ht1))) {
2658
0
    zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
2659
0
  }
2660
2661
5.30k
  if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) {
2662
4.50k
    GC_PROTECT_RECURSION(ht1);
2663
4.50k
  }
2664
5.30k
  result = zend_hash_compare_impl(ht1, ht2, compar, ordered);
2665
5.30k
  if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) {
2666
4.50k
    GC_UNPROTECT_RECURSION(ht1);
2667
4.50k
  }
2668
2669
5.30k
  return result;
2670
5.30k
}
2671
2672
2673
ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, bucket_compare_func_t compar, uint32_t flag)
2674
0
{
2675
0
  uint32_t idx;
2676
0
  Bucket *p, *res;
2677
2678
0
  IS_CONSISTENT(ht);
2679
2680
0
  if (ht->nNumOfElements == 0 ) {
2681
0
    return NULL;
2682
0
  }
2683
2684
0
  idx = 0;
2685
0
  while (1) {
2686
0
    if (idx == ht->nNumUsed) {
2687
0
      return NULL;
2688
0
    }
2689
0
    if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
2690
0
    idx++;
2691
0
  }
2692
0
  res = ht->arData + idx;
2693
0
  for (; idx < ht->nNumUsed; idx++) {
2694
0
    p = ht->arData + idx;
2695
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2696
2697
0
    if (flag) {
2698
0
      if (compar(res, p) < 0) { /* max */
2699
0
        res = p;
2700
0
      }
2701
0
    } else {
2702
0
      if (compar(res, p) > 0) { /* min */
2703
0
        res = p;
2704
0
      }
2705
0
    }
2706
0
  }
2707
0
  return &res->val;
2708
0
}
2709
2710
ZEND_API int ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
2711
51.7k
{
2712
51.7k
  register const char *tmp = key;
2713
2714
51.7k
  const char *end = key + length;
2715
2716
51.7k
  if (*tmp == '-') {
2717
21.7k
    tmp++;
2718
21.7k
  }
2719
2720
51.7k
  if ((*tmp == '0' && length > 1) /* numbers with leading zeros */
2721
30.9k
   || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
2722
0
   || (SIZEOF_ZEND_LONG == 4 &&
2723
0
       end - tmp == MAX_LENGTH_OF_LONG - 1 &&
2724
24.0k
       *tmp > '2')) { /* overflow */
2725
24.0k
    return 0;
2726
24.0k
  }
2727
27.6k
  *idx = (*tmp - '0');
2728
146k
  while (1) {
2729
146k
    ++tmp;
2730
146k
    if (tmp == end) {
2731
23.9k
      if (*key == '-') {
2732
6.31k
        if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
2733
96
          return 0;
2734
96
        }
2735
6.22k
        *idx = 0 - *idx;
2736
17.5k
      } else if (*idx > ZEND_LONG_MAX) { /* overflow */
2737
2.33k
        return 0;
2738
2.33k
      }
2739
21.4k
      return 1;
2740
21.4k
    }
2741
122k
    if (*tmp <= '9' && *tmp >= '0') {
2742
119k
      *idx = (*idx * 10) + (*tmp - '0');
2743
3.76k
    } else {
2744
3.76k
      return 0;
2745
3.76k
    }
2746
122k
  }
2747
27.6k
}
2748
2749
/* Takes a "symtable" hashtable (contains integer and non-numeric string keys)
2750
 * and converts it to a "proptable" (contains only string keys).
2751
 * If the symtable didn't need duplicating, its refcount is incremented.
2752
 */
2753
ZEND_API HashTable* ZEND_FASTCALL zend_symtable_to_proptable(HashTable *ht)
2754
0
{
2755
0
  zend_ulong num_key;
2756
0
  zend_string *str_key;
2757
0
  zval *zv;
2758
2759
0
  if (UNEXPECTED(HT_IS_PACKED(ht))) {
2760
0
    goto convert;
2761
0
  }
2762
2763
0
  ZEND_HASH_FOREACH_STR_KEY(ht, str_key) {
2764
0
    if (!str_key) {
2765
0
      goto convert;
2766
0
    }
2767
0
  } ZEND_HASH_FOREACH_END();
2768
2769
0
  if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2770
0
    GC_ADDREF(ht);
2771
0
  }
2772
2773
0
  return ht;
2774
2775
0
convert:
2776
0
  {
2777
0
    HashTable *new_ht = zend_new_array(zend_hash_num_elements(ht));
2778
2779
0
    ZEND_HASH_FOREACH_KEY_VAL(ht, num_key, str_key, zv) {
2780
0
      if (!str_key) {
2781
0
        str_key = zend_long_to_str(num_key);
2782
0
        zend_string_delref(str_key);
2783
0
      }
2784
0
      do {
2785
0
        if (Z_OPT_REFCOUNTED_P(zv)) {
2786
0
          if (Z_ISREF_P(zv) && Z_REFCOUNT_P(zv) == 1) {
2787
0
            zv = Z_REFVAL_P(zv);
2788
0
            if (!Z_OPT_REFCOUNTED_P(zv)) {
2789
0
              break;
2790
0
            }
2791
0
          }
2792
0
          Z_ADDREF_P(zv);
2793
0
        }
2794
0
      } while (0);
2795
0
      zend_hash_update(new_ht, str_key, zv);
2796
0
    } ZEND_HASH_FOREACH_END();
2797
2798
0
    return new_ht;
2799
0
  }
2800
0
}
2801
2802
/* Takes a "proptable" hashtable (contains only string keys) and converts it to
2803
 * a "symtable" (contains integer and non-numeric string keys).
2804
 * If the proptable didn't need duplicating, its refcount is incremented.
2805
 */
2806
ZEND_API HashTable* ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, zend_bool always_duplicate)
2807
0
{
2808
0
  zend_ulong num_key;
2809
0
  zend_string *str_key;
2810
0
  zval *zv;
2811
2812
0
  ZEND_HASH_FOREACH_STR_KEY(ht, str_key) {
2813
    /* The `str_key &&` here might seem redundant: property tables should
2814
     * only have string keys. Unfortunately, this isn't true, at the very
2815
     * least because of ArrayObject, which stores a symtable where the
2816
     * property table should be.
2817
     */
2818
0
    if (str_key && ZEND_HANDLE_NUMERIC(str_key, num_key)) {
2819
0
      goto convert;
2820
0
    }
2821
0
  } ZEND_HASH_FOREACH_END();
2822
2823
0
  if (always_duplicate) {
2824
0
    return zend_array_dup(ht);
2825
0
  }
2826
2827
0
  if (EXPECTED(!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE))) {
2828
0
    GC_ADDREF(ht);
2829
0
  }
2830
2831
0
  return ht;
2832
2833
0
convert:
2834
0
  {
2835
0
    HashTable *new_ht = zend_new_array(zend_hash_num_elements(ht));
2836
2837
0
    ZEND_HASH_FOREACH_KEY_VAL_IND(ht, num_key, str_key, zv) {
2838
0
      do {
2839
0
        if (Z_OPT_REFCOUNTED_P(zv)) {
2840
0
          if (Z_ISREF_P(zv) && Z_REFCOUNT_P(zv) == 1) {
2841
0
            zv = Z_REFVAL_P(zv);
2842
0
            if (!Z_OPT_REFCOUNTED_P(zv)) {
2843
0
              break;
2844
0
            }
2845
0
          }
2846
0
          Z_ADDREF_P(zv);
2847
0
        }
2848
0
      } while (0);
2849
      /* Again, thank ArrayObject for `!str_key ||`. */
2850
0
      if (!str_key || ZEND_HANDLE_NUMERIC(str_key, num_key)) {
2851
0
        zend_hash_index_update(new_ht, num_key, zv);
2852
0
      } else {
2853
0
        zend_hash_update(new_ht, str_key, zv);
2854
0
      }
2855
0
    } ZEND_HASH_FOREACH_END();
2856
2857
0
    return new_ht;
2858
0
  }
2859
0
}