Coverage Report

Created: 2025-09-27 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/Zend/zend_hash.c
Line
Count
Source
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__) || defined(_M_ARM64)
26
# include <arm_neon.h>
27
#endif
28
29
/* Prefer to use AVX2 instructions for better latency and throughput */
30
#if defined(__AVX2__)
31
# include <immintrin.h>
32
#elif defined( __SSE2__)
33
# include <emmintrin.h>
34
#endif
35
36
#if ZEND_DEBUG
37
# define HT_ASSERT(ht, expr) \
38
2.03G
  ZEND_ASSERT((expr) || (HT_FLAGS(ht) & HASH_FLAG_ALLOW_COW_VIOLATION))
39
#else
40
# define HT_ASSERT(ht, expr)
41
#endif
42
43
2.02G
#define HT_ASSERT_RC1(ht) HT_ASSERT(ht, GC_REFCOUNT(ht) == 1)
44
45
1.78k
#define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
46
47
#if ZEND_DEBUG
48
49
3.11G
#define HT_OK         0x00
50
0
#define HT_IS_DESTROYING    0x01
51
0
#define HT_DESTROYED      0x02
52
0
#define HT_CLEANING       0x03
53
54
static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
55
3.11G
{
56
3.11G
  if ((HT_FLAGS(ht) & HASH_FLAG_CONSISTENCY) == HT_OK) {
57
3.11G
    return;
58
3.11G
  }
59
0
  switch (HT_FLAGS(ht) & HASH_FLAG_CONSISTENCY) {
60
0
    case HT_IS_DESTROYING:
61
0
      zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
62
0
      break;
63
0
    case HT_DESTROYED:
64
0
      zend_output_debug_string(1, "%s(%d) : ht=%p is already destroyed", file, line, ht);
65
0
      break;
66
0
    case HT_CLEANING:
67
0
      zend_output_debug_string(1, "%s(%d) : ht=%p is being cleaned", file, line, ht);
68
0
      break;
69
0
    default:
70
0
      zend_output_debug_string(1, "%s(%d) : ht=%p is inconsistent", file, line, ht);
71
0
      break;
72
0
  }
73
0
  ZEND_UNREACHABLE();
74
0
}
75
3.11G
#define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
76
11.8M
#define SET_INCONSISTENT(n) do { \
77
11.8M
    HT_FLAGS(ht) = (HT_FLAGS(ht) & ~HASH_FLAG_CONSISTENCY) | (n); \
78
11.8M
  } while (0)
79
#else
80
#define IS_CONSISTENT(a)
81
#define SET_INCONSISTENT(n)
82
#endif
83
84
#define ZEND_HASH_IF_FULL_DO_RESIZE(ht)       \
85
1.01G
  if ((ht)->nNumUsed >= (ht)->nTableSize) {   \
86
69.1k
    zend_hash_do_resize(ht);          \
87
69.1k
  }
88
89
216k
ZEND_API void *zend_hash_str_find_ptr_lc(const HashTable *ht, const char *str, size_t len) {
90
216k
  void *result;
91
216k
  char *lc_str;
92
93
  /* Stack allocate small strings to improve performance */
94
216k
  ALLOCA_FLAG(use_heap)
95
96
216k
  lc_str = zend_str_tolower_copy(do_alloca(len + 1, use_heap), str, len);
97
216k
  result = zend_hash_str_find_ptr(ht, lc_str, len);
98
216k
  free_alloca(lc_str, use_heap);
99
100
216k
  return result;
101
216k
}
102
103
4.64k
ZEND_API void *zend_hash_find_ptr_lc(const HashTable *ht, zend_string *key) {
104
4.64k
  void *result;
105
4.64k
  zend_string *lc_key = zend_string_tolower(key);
106
4.64k
  result = zend_hash_find_ptr(ht, lc_key);
107
4.64k
  zend_string_release(lc_key);
108
4.64k
  return result;
109
4.64k
}
110
111
static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht);
112
113
static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize)
114
11.2M
{
115
#ifdef ZEND_WIN32
116
  unsigned long index;
117
#endif
118
119
  /* Use big enough power of 2 */
120
  /* size should be between HT_MIN_SIZE and HT_MAX_SIZE */
121
11.2M
  if (nSize <= HT_MIN_SIZE) {
122
10.1M
    return HT_MIN_SIZE;
123
10.1M
  } else if (UNEXPECTED(nSize > HT_MAX_SIZE)) {
124
0
    zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket));
125
0
  }
126
127
#ifdef ZEND_WIN32
128
  if (BitScanReverse(&index, nSize - 1)) {
129
    return 0x2u << ((31 - index) ^ 0x1f);
130
  } else {
131
    /* nSize is ensured to be in the valid range, fall back to it
132
       rather than using an undefined bis scan result. */
133
    return nSize;
134
  }
135
#elif (defined(__GNUC__) || __has_builtin(__builtin_clz))  && defined(PHP_HAVE_BUILTIN_CLZ)
136
1.09M
  return 0x2u << (__builtin_clz(nSize - 1) ^ 0x1f);
137
#else
138
  nSize -= 1;
139
  nSize |= (nSize >> 1);
140
  nSize |= (nSize >> 2);
141
  nSize |= (nSize >> 4);
142
  nSize |= (nSize >> 8);
143
  nSize |= (nSize >> 16);
144
  return nSize + 1;
145
#endif
146
11.2M
}
147
148
static zend_always_inline void zend_hash_real_init_packed_ex(HashTable *ht)
149
2.94M
{
150
2.94M
  void *data;
151
152
2.94M
  if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
153
1.16k
    data = pemalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), 1);
154
2.94M
  } else if (EXPECTED(ht->nTableSize == HT_MIN_SIZE)) {
155
    /* Use specialized API with constant allocation amount for a particularly common case. */
156
2.93M
    data = emalloc(HT_PACKED_SIZE_EX(HT_MIN_SIZE, HT_MIN_MASK));
157
2.93M
  } else {
158
15.1k
    data = emalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK));
159
15.1k
  }
160
2.94M
  HT_SET_DATA_ADDR(ht, data);
161
  /* Don't overwrite iterator count. */
162
2.94M
  ht->u.v.flags = HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
163
2.94M
  HT_HASH_RESET_PACKED(ht);
164
2.94M
}
165
166
static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
167
4.14M
{
168
4.14M
  void *data;
169
4.14M
  uint32_t nSize = ht->nTableSize;
170
171
4.14M
  ZEND_ASSERT(HT_SIZE_TO_MASK(nSize));
172
173
4.14M
  if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
174
4.79k
    data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1);
175
4.14M
  } else if (EXPECTED(nSize == HT_MIN_SIZE)) {
176
3.56M
    data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)));
177
3.56M
    ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE);
178
3.56M
    HT_SET_DATA_ADDR(ht, data);
179
    /* Don't overwrite iterator count. */
180
3.56M
    ht->u.v.flags = HASH_FLAG_STATIC_KEYS;
181
#if defined(__AVX2__)
182
    do {
183
      __m256i ymm0 = _mm256_setzero_si256();
184
      ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0);
185
      _mm256_storeu_si256((__m256i*)&HT_HASH_EX(data,  0), ymm0);
186
      _mm256_storeu_si256((__m256i*)&HT_HASH_EX(data,  8), ymm0);
187
    } while(0);
188
#elif defined (__SSE2__)
189
3.56M
    do {
190
3.56M
      __m128i xmm0 = _mm_setzero_si128();
191
3.56M
      xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
192
3.56M
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  0), xmm0);
193
3.56M
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  4), xmm0);
194
3.56M
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  8), xmm0);
195
3.56M
      _mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 12), xmm0);
196
3.56M
    } while (0);
197
#elif defined(__aarch64__) || defined(_M_ARM64)
198
    do {
199
      int32x4_t t = vdupq_n_s32(-1);
200
      vst1q_s32((int32_t*)&HT_HASH_EX(data,  0), t);
201
      vst1q_s32((int32_t*)&HT_HASH_EX(data,  4), t);
202
      vst1q_s32((int32_t*)&HT_HASH_EX(data,  8), t);
203
      vst1q_s32((int32_t*)&HT_HASH_EX(data, 12), t);
204
    } while (0);
205
#else
206
    HT_HASH_EX(data,  0) = -1;
207
    HT_HASH_EX(data,  1) = -1;
208
    HT_HASH_EX(data,  2) = -1;
209
    HT_HASH_EX(data,  3) = -1;
210
    HT_HASH_EX(data,  4) = -1;
211
    HT_HASH_EX(data,  5) = -1;
212
    HT_HASH_EX(data,  6) = -1;
213
    HT_HASH_EX(data,  7) = -1;
214
    HT_HASH_EX(data,  8) = -1;
215
    HT_HASH_EX(data,  9) = -1;
216
    HT_HASH_EX(data, 10) = -1;
217
    HT_HASH_EX(data, 11) = -1;
218
    HT_HASH_EX(data, 12) = -1;
219
    HT_HASH_EX(data, 13) = -1;
220
    HT_HASH_EX(data, 14) = -1;
221
    HT_HASH_EX(data, 15) = -1;
222
#endif
223
3.56M
    return;
224
3.56M
  } else {
225
574k
    data = emalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)));
226
574k
  }
227
579k
  ht->nTableMask = HT_SIZE_TO_MASK(nSize);
228
579k
  HT_SET_DATA_ADDR(ht, data);
229
579k
  HT_FLAGS(ht) = HASH_FLAG_STATIC_KEYS;
230
579k
  HT_HASH_RESET(ht);
231
579k
}
232
233
static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, bool packed)
234
30.6k
{
235
30.6k
  HT_ASSERT_RC1(ht);
236
30.6k
  ZEND_ASSERT(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED);
237
30.6k
  if (packed) {
238
80
    zend_hash_real_init_packed_ex(ht);
239
30.5k
  } else {
240
30.5k
    zend_hash_real_init_mixed_ex(ht);
241
30.5k
  }
242
30.6k
}
243
244
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
245
  {HT_INVALID_IDX, HT_INVALID_IDX};
246
247
ZEND_API const HashTable zend_empty_array = {
248
  .gc.refcount = 2,
249
  .gc.u.type_info = IS_ARRAY | (GC_IMMUTABLE << GC_FLAGS_SHIFT),
250
  .u.flags = HASH_FLAG_UNINITIALIZED,
251
  .nTableMask = HT_MIN_MASK,
252
  {.arData = (Bucket*)&uninitialized_bucket[2]},
253
  .nNumUsed = 0,
254
  .nNumOfElements = 0,
255
  .nTableSize = HT_MIN_SIZE,
256
  .nInternalPointer = 0,
257
  .nNextFreeElement = ZEND_LONG_MIN,
258
  .pDestructor = ZVAL_PTR_DTOR
259
};
260
261
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent)
262
11.0M
{
263
11.0M
  GC_SET_REFCOUNT(ht, 1);
264
11.0M
  GC_TYPE_INFO(ht) = GC_ARRAY | (persistent ? ((GC_PERSISTENT|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT) : 0);
265
11.0M
  HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED;
266
11.0M
  ht->nTableMask = HT_MIN_MASK;
267
11.0M
  HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
268
11.0M
  ht->nNumUsed = 0;
269
11.0M
  ht->nNumOfElements = 0;
270
11.0M
  ht->nInternalPointer = 0;
271
11.0M
  ht->nNextFreeElement = ZEND_LONG_MIN;
272
11.0M
  ht->pDestructor = pDestructor;
273
11.0M
  ht->nTableSize = zend_hash_check_size(nSize);
274
11.0M
}
275
276
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent)
277
3.50M
{
278
3.50M
  _zend_hash_init_int(ht, nSize, pDestructor, persistent);
279
3.50M
}
280
281
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void)
282
0
{
283
0
  HashTable *ht = emalloc(sizeof(HashTable));
284
0
  _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, false);
285
0
  return ht;
286
0
}
287
288
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize)
289
7.52M
{
290
7.52M
  HashTable *ht = emalloc(sizeof(HashTable));
291
7.52M
  _zend_hash_init_int(ht, nSize, ZVAL_PTR_DTOR, false);
292
7.52M
  return ht;
293
7.52M
}
294
295
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(const zval *val1, const zval *val2)
296
0
{
297
0
  zval *zv;
298
0
  HashTable *ht = emalloc(sizeof(HashTable));
299
0
  _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, false);
300
0
  ht->nNumUsed = ht->nNumOfElements = ht->nNextFreeElement = 2;
301
0
  zend_hash_real_init_packed_ex(ht);
302
303
0
  zv = ht->arPacked;
304
0
  ZVAL_COPY_VALUE(zv, val1);
305
0
  zv++;
306
0
  ZVAL_COPY_VALUE(zv, val2);
307
0
  return ht;
308
0
}
309
310
ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
311
206k
{
312
206k
  HT_ASSERT_RC1(ht);
313
206k
  if (ht->nTableSize >= HT_MAX_SIZE) {
314
0
    zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket));
315
0
  }
316
206k
  uint32_t newTableSize = ht->nTableSize * 2;
317
206k
  HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
318
206k
  ht->nTableSize = newTableSize;
319
206k
}
320
321
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed)
322
30.6k
{
323
30.6k
  IS_CONSISTENT(ht);
324
325
30.6k
  HT_ASSERT_RC1(ht);
326
30.6k
  zend_hash_real_init_ex(ht, packed);
327
30.6k
}
328
329
ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht)
330
630k
{
331
630k
  IS_CONSISTENT(ht);
332
333
630k
  HT_ASSERT_RC1(ht);
334
630k
  zend_hash_real_init_packed_ex(ht);
335
630k
}
336
337
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
338
4.11M
{
339
4.11M
  IS_CONSISTENT(ht);
340
341
4.11M
  HT_ASSERT_RC1(ht);
342
4.11M
  zend_hash_real_init_mixed_ex(ht);
343
4.11M
}
344
345
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
346
18.5k
{
347
18.5k
  void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
348
18.5k
  zval *src = ht->arPacked;
349
18.5k
  Bucket *dst;
350
18.5k
  uint32_t i;
351
18.5k
  uint32_t nSize = ht->nTableSize;
352
353
18.5k
  ZEND_ASSERT(HT_SIZE_TO_MASK(nSize));
354
355
18.5k
  HT_ASSERT_RC1(ht);
356
  // Alloc before assign to avoid inconsistencies on OOM
357
18.5k
  new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
358
18.5k
  HT_FLAGS(ht) &= ~HASH_FLAG_PACKED;
359
18.5k
  ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
360
18.5k
  HT_SET_DATA_ADDR(ht, new_data);
361
18.5k
  dst = ht->arData;
362
237k
  for (i = 0; i < ht->nNumUsed; i++) {
363
219k
    ZVAL_COPY_VALUE(&dst->val, src);
364
219k
    dst->h = i;
365
219k
    dst->key = NULL;
366
219k
    dst++;
367
219k
    src++;
368
219k
  }
369
18.5k
  pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
370
18.5k
  zend_hash_rehash(ht);
371
18.5k
}
372
373
ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
374
0
{
375
0
  void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
376
0
  Bucket *src = ht->arData;
377
0
  zval *dst;
378
0
  uint32_t i;
379
380
0
  HT_ASSERT_RC1(ht);
381
0
  new_data = pemalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
382
0
  HT_FLAGS(ht) |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
383
0
  ht->nTableMask = HT_MIN_MASK;
384
0
  HT_SET_DATA_ADDR(ht, new_data);
385
0
  HT_HASH_RESET_PACKED(ht);
386
0
  dst = ht->arPacked;
387
0
  for (i = 0; i < ht->nNumUsed; i++) {
388
0
    ZVAL_COPY_VALUE(dst, &src->val);
389
0
    dst++;
390
0
    src++;
391
0
  }
392
0
  pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
393
0
}
394
395
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed)
396
340k
{
397
340k
  HT_ASSERT_RC1(ht);
398
399
340k
  if (nSize == 0) return;
400
401
337k
  ZEND_ASSERT(HT_SIZE_TO_MASK(nSize));
402
403
337k
  if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
404
30.6k
    if (nSize > ht->nTableSize) {
405
1.70k
      ht->nTableSize = zend_hash_check_size(nSize);
406
1.70k
    }
407
30.6k
    zend_hash_real_init(ht, packed);
408
307k
  } else {
409
307k
    if (packed) {
410
35
      ZEND_ASSERT(HT_IS_PACKED(ht));
411
35
      if (nSize > ht->nTableSize) {
412
1
        uint32_t newTableSize = zend_hash_check_size(nSize);
413
1
        HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
414
1
        ht->nTableSize = newTableSize;
415
1
      }
416
307k
    } else {
417
307k
      ZEND_ASSERT(!HT_IS_PACKED(ht));
418
307k
      if (nSize > ht->nTableSize) {
419
230k
        void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
420
230k
        Bucket *old_buckets = ht->arData;
421
230k
        nSize = zend_hash_check_size(nSize);
422
230k
        new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
423
230k
        ht->nTableSize = nSize;
424
230k
        ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
425
230k
        HT_SET_DATA_ADDR(ht, new_data);
426
230k
        memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
427
230k
        pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
428
230k
        zend_hash_rehash(ht);
429
230k
      }
430
307k
    }
431
307k
  }
432
337k
}
433
434
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed)
435
0
{
436
0
  Bucket *p, *end, *arData;
437
0
  uint32_t nIndex;
438
439
0
  ZEND_ASSERT(!HT_IS_PACKED(ht));
440
0
  arData = ht->arData;
441
0
  p = arData + ht->nNumUsed;
442
0
  end = arData + nNumUsed;
443
0
  ht->nNumUsed = nNumUsed;
444
0
  while (p != end) {
445
0
    p--;
446
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
447
0
    ht->nNumOfElements--;
448
    /* Collision pointers always directed from higher to lower buckets */
449
#if 0
450
    if (!(Z_NEXT(p->val) == HT_INVALID_IDX || HT_HASH_TO_BUCKET_EX(arData, Z_NEXT(p->val)) < p)) {
451
      abort();
452
    }
453
#endif
454
0
    nIndex = p->h | ht->nTableMask;
455
0
    HT_HASH_EX(arData, nIndex) = Z_NEXT(p->val);
456
0
  }
457
0
}
458
459
static uint32_t zend_array_recalc_elements(const HashTable *ht)
460
1.26k
{
461
1.26k
  zval *val;
462
1.26k
  uint32_t num = ht->nNumOfElements;
463
464
7.14k
  ZEND_HASH_MAP_FOREACH_VAL(ht, val) {
465
7.14k
    if (Z_TYPE_P(val) == IS_INDIRECT) {
466
2.21k
      if (UNEXPECTED(Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF)) {
467
1.25k
        num--;
468
1.25k
      }
469
2.21k
    }
470
7.14k
  } ZEND_HASH_FOREACH_END();
471
1.26k
  return num;
472
1.26k
}
473
/* }}} */
474
475
ZEND_API uint32_t zend_array_count(HashTable *ht)
476
23.2k
{
477
23.2k
  uint32_t num;
478
23.2k
  if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_HAS_EMPTY_IND)) {
479
1.26k
    num = zend_array_recalc_elements(ht);
480
1.26k
    if (UNEXPECTED(ht->nNumOfElements == num)) {
481
255
      HT_FLAGS(ht) &= ~HASH_FLAG_HAS_EMPTY_IND;
482
255
    }
483
21.9k
  } else if (UNEXPECTED(ht == &EG(symbol_table))) {
484
0
    num = zend_array_recalc_elements(ht);
485
21.9k
  } else {
486
21.9k
    num = zend_hash_num_elements(ht);
487
21.9k
  }
488
23.2k
  return num;
489
23.2k
}
490
/* }}} */
491
492
static zend_always_inline HashPosition _zend_hash_get_valid_pos(const HashTable *ht, HashPosition pos)
493
11.8k
{
494
11.8k
  if (HT_IS_PACKED(ht)) {
495
4.91k
    while (pos < ht->nNumUsed && Z_ISUNDEF(ht->arPacked[pos])) {
496
798
      pos++;
497
798
    }
498
7.71k
  } else {
499
7.96k
    while (pos < ht->nNumUsed && Z_ISUNDEF(ht->arData[pos].val)) {
500
250
      pos++;
501
250
    }
502
7.71k
  }
503
11.8k
  return pos;
504
11.8k
}
505
506
static zend_always_inline HashPosition _zend_hash_get_current_pos(const HashTable *ht)
507
1.21k
{
508
1.21k
  return _zend_hash_get_valid_pos(ht, ht->nInternalPointer);
509
1.21k
}
510
511
ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht)
512
185
{
513
185
  return _zend_hash_get_current_pos(ht);
514
185
}
515
516
ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos_ex(const HashTable *ht, HashPosition pos)
517
0
{
518
0
  return _zend_hash_get_valid_pos(ht, pos);
519
0
}
520
521
101
static void zend_hash_remove_iterator_copies(uint32_t idx) {
522
101
  HashTableIterator *iterators = EG(ht_iterators);
523
524
101
  HashTableIterator *iter = iterators + idx;
525
101
  uint32_t next_idx = iter->next_copy;
526
705
  while (next_idx != idx) {
527
604
    uint32_t cur_idx = next_idx;
528
604
    HashTableIterator *cur_iter = iterators + cur_idx;
529
604
    next_idx = cur_iter->next_copy;
530
604
    cur_iter->next_copy = cur_idx; // avoid recursion in zend_hash_iterator_del
531
604
    zend_hash_iterator_del(cur_idx);
532
604
  }
533
101
  iter->next_copy = idx;
534
101
}
535
536
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
537
2.56k
{
538
2.56k
  HashTableIterator *iter = EG(ht_iterators);
539
2.56k
  HashTableIterator *end  = iter + EG(ht_iterators_count);
540
2.56k
  uint32_t idx;
541
542
2.56k
  if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
543
2.56k
    HT_INC_ITERATORS_COUNT(ht);
544
2.56k
  }
545
41.3k
  while (iter != end) {
546
41.3k
    if (iter->ht == NULL) {
547
2.49k
      iter->ht = ht;
548
2.49k
      iter->pos = pos;
549
2.49k
      idx = iter - EG(ht_iterators);
550
2.49k
      iter->next_copy = idx;
551
2.49k
      if (idx + 1 > EG(ht_iterators_used)) {
552
2.49k
        EG(ht_iterators_used) = idx + 1;
553
2.49k
      }
554
2.49k
      return idx;
555
2.49k
    }
556
38.8k
    iter++;
557
38.8k
  }
558
77
  if (EG(ht_iterators) == EG(ht_iterators_slots)) {
559
8
    EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
560
8
    memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
561
69
  } else {
562
69
    EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
563
69
  }
564
77
  iter = EG(ht_iterators) + EG(ht_iterators_count);
565
77
  EG(ht_iterators_count) += 8;
566
77
  iter->ht = ht;
567
77
  iter->pos = pos;
568
77
  memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
569
77
  idx = iter - EG(ht_iterators);
570
77
  iter->next_copy = idx;
571
77
  EG(ht_iterators_used) = idx + 1;
572
77
  return idx;
573
2.56k
}
574
575
// To avoid losing track of the HashTable when separating arrays, we track all copies at once.
576
1.12k
static zend_always_inline bool zend_hash_iterator_find_copy_pos(uint32_t idx, HashTable *ht) {
577
1.12k
  HashTableIterator *iter = EG(ht_iterators) + idx;
578
579
1.12k
  uint32_t next_idx = iter->next_copy;
580
1.12k
  if (EXPECTED(next_idx != idx)) {
581
92
    HashTableIterator *copy_iter;
582
99
    while (next_idx != idx) {
583
99
      copy_iter = EG(ht_iterators) + next_idx;
584
99
      if (copy_iter->ht == ht) {
585
        // We have found the hashtable we are actually iterating over
586
        // Now clean any intermittent copies and replace the original index by the found one
587
92
        if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
588
82
          && EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
589
82
          HT_DEC_ITERATORS_COUNT(iter->ht);
590
82
        }
591
92
        if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
592
92
          HT_INC_ITERATORS_COUNT(ht);
593
92
        }
594
92
        iter->ht = copy_iter->ht;
595
92
        iter->pos = copy_iter->pos;
596
92
        zend_hash_remove_iterator_copies(idx);
597
92
        return true;
598
92
      }
599
7
      next_idx = copy_iter->next_copy;
600
7
    }
601
0
    zend_hash_remove_iterator_copies(idx);
602
0
  }
603
604
1.02k
  return false;
605
1.12k
}
606
607
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
608
1.57k
{
609
1.57k
  HashTableIterator *iter = EG(ht_iterators) + idx;
610
611
1.57k
  ZEND_ASSERT(idx != (uint32_t)-1);
612
1.57k
  if (UNEXPECTED(iter->ht != ht) && !zend_hash_iterator_find_copy_pos(idx, ht)) {
613
0
    if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
614
0
        && EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
615
0
      HT_DEC_ITERATORS_COUNT(iter->ht);
616
0
    }
617
0
    if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
618
0
      HT_INC_ITERATORS_COUNT(ht);
619
0
    }
620
0
    iter->ht = ht;
621
0
    iter->pos = _zend_hash_get_current_pos(ht);
622
0
  }
623
1.57k
  return iter->pos;
624
1.57k
}
625
626
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array)
627
7.36k
{
628
7.36k
  HashTable *ht = Z_ARRVAL_P(array);
629
7.36k
  HashTableIterator *iter = EG(ht_iterators) + idx;
630
631
7.36k
  ZEND_ASSERT(idx != (uint32_t)-1);
632
7.36k
  if (UNEXPECTED(iter->ht != ht) && !zend_hash_iterator_find_copy_pos(idx, ht)) {
633
1.02k
    if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
634
0
        && EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
635
0
      HT_DEC_ITERATORS_COUNT(iter->ht);
636
0
    }
637
638
    /* Inlined SEPARATE_ARRAY() with updating of iterator when EG(ht_iterators) grows. */
639
1.02k
    if (UNEXPECTED(GC_REFCOUNT(ht) > 1)) {
640
686
      ZVAL_ARR(array, zend_array_dup(ht));
641
686
      GC_TRY_DELREF(ht);
642
686
      iter = EG(ht_iterators) + idx;
643
686
      ht = Z_ARRVAL_P(array);
644
686
    }
645
646
1.02k
    if (EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
647
1.02k
      HT_INC_ITERATORS_COUNT(ht);
648
1.02k
    }
649
1.02k
    iter->ht = ht;
650
1.02k
    iter->pos = _zend_hash_get_current_pos(ht);
651
1.02k
  }
652
7.36k
  return iter->pos;
653
7.36k
}
654
655
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
656
2.35k
{
657
2.35k
  HashTableIterator *iter = EG(ht_iterators) + idx;
658
659
2.35k
  ZEND_ASSERT(idx != (uint32_t)-1);
660
661
2.35k
  if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
662
1.80k
      && EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
663
1.80k
    ZEND_ASSERT(HT_ITERATORS_COUNT(iter->ht) != 0);
664
1.80k
    HT_DEC_ITERATORS_COUNT(iter->ht);
665
1.80k
  }
666
2.35k
  iter->ht = NULL;
667
668
2.35k
  if (UNEXPECTED(iter->next_copy != idx)) {
669
9
    zend_hash_remove_iterator_copies(idx);
670
9
  }
671
672
2.35k
  if (idx == EG(ht_iterators_used) - 1) {
673
2.35k
    while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
674
28
      idx--;
675
28
    }
676
2.32k
    EG(ht_iterators_used) = idx;
677
2.32k
  }
678
2.35k
}
679
680
static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(const HashTable *ht)
681
1.09k
{
682
1.09k
  HashTableIterator *iter = EG(ht_iterators);
683
1.09k
  const HashTableIterator *end = iter + EG(ht_iterators_used);
684
685
40.7k
  while (iter != end) {
686
39.6k
    if (iter->ht == ht) {
687
1.78k
      iter->ht = HT_POISONED_PTR;
688
1.78k
    }
689
39.6k
    iter++;
690
39.6k
  }
691
1.09k
}
692
693
static zend_always_inline void zend_hash_iterators_remove(const HashTable *ht)
694
7.95M
{
695
7.95M
  if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
696
1.09k
    _zend_hash_iterators_remove(ht);
697
1.09k
  }
698
7.95M
}
699
700
ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(const HashTable *ht, HashPosition start)
701
1.19k
{
702
1.19k
  const HashTableIterator *iter = EG(ht_iterators);
703
1.19k
  const HashTableIterator *end = iter + EG(ht_iterators_used);
704
1.19k
  HashPosition res = ht->nNumUsed;
705
706
2.03k
  while (iter != end) {
707
842
    if (iter->ht == ht) {
708
827
      if (iter->pos >= start && iter->pos < res) {
709
221
        res = iter->pos;
710
221
      }
711
827
    }
712
842
    iter++;
713
842
  }
714
1.19k
  return res;
715
1.19k
}
716
717
ZEND_API void ZEND_FASTCALL _zend_hash_iterators_update(const HashTable *ht, HashPosition from, HashPosition to)
718
208
{
719
208
  HashTableIterator *iter = EG(ht_iterators);
720
208
  const HashTableIterator *end = iter + EG(ht_iterators_used);
721
722
463
  while (iter != end) {
723
255
    if (iter->ht == ht && iter->pos == from) {
724
180
      iter->pos = to;
725
180
    }
726
255
    iter++;
727
255
  }
728
208
}
729
730
ZEND_API void ZEND_FASTCALL zend_hash_iterators_advance(const HashTable *ht, HashPosition step)
731
7
{
732
7
  HashTableIterator *iter = EG(ht_iterators);
733
7
  const HashTableIterator *end = iter + EG(ht_iterators_used);
734
735
14
  while (iter != end) {
736
7
    if (iter->ht == ht) {
737
7
      iter->pos += step;
738
7
    }
739
7
    iter++;
740
7
  }
741
7
}
742
743
/* Hash must be known and precomputed before */
744
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, const zend_string *key)
745
50.2M
{
746
50.2M
  uint32_t nIndex;
747
50.2M
  uint32_t idx;
748
50.2M
  Bucket *p, *arData;
749
750
50.2M
  ZEND_ASSERT(ZSTR_H(key) != 0 && "Hash must be known");
751
752
50.2M
  arData = ht->arData;
753
50.2M
  nIndex = ZSTR_H(key) | ht->nTableMask;
754
50.2M
  idx = HT_HASH_EX(arData, nIndex);
755
756
50.2M
  if (UNEXPECTED(idx == HT_INVALID_IDX)) {
757
14.6M
    return NULL;
758
14.6M
  }
759
35.6M
  p = HT_HASH_TO_BUCKET_EX(arData, idx);
760
35.6M
  if (EXPECTED(p->key == key)) { /* check for the same interned string */
761
28.9M
    return p;
762
28.9M
  }
763
764
7.21M
  while (1) {
765
7.21M
    if (p->h == ZSTR_H(key) &&
766
2.31M
        EXPECTED(p->key) &&
767
2.31M
        zend_string_equal_content(p->key, key)) {
768
2.27M
      return p;
769
2.27M
    }
770
4.94M
    idx = Z_NEXT(p->val);
771
4.94M
    if (idx == HT_INVALID_IDX) {
772
4.27M
      return NULL;
773
4.27M
    }
774
666k
    p = HT_HASH_TO_BUCKET_EX(arData, idx);
775
666k
    if (p->key == key) { /* check for the same interned string */
776
130k
      return p;
777
130k
    }
778
666k
  }
779
6.68M
}
780
781
static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, const char *str, size_t len, zend_ulong h)
782
4.72M
{
783
4.72M
  uint32_t nIndex;
784
4.72M
  uint32_t idx;
785
4.72M
  Bucket *p, *arData;
786
787
4.72M
  arData = ht->arData;
788
4.72M
  nIndex = h | ht->nTableMask;
789
4.72M
  idx = HT_HASH_EX(arData, nIndex);
790
4.92M
  while (idx != HT_INVALID_IDX) {
791
1.33M
    ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
792
1.33M
    p = HT_HASH_TO_BUCKET_EX(arData, idx);
793
1.33M
    if ((p->h == h)
794
1.13M
       && p->key
795
1.13M
       && zend_string_equals_cstr(p->key, str, len)) {
796
1.13M
      return p;
797
1.13M
    }
798
202k
    idx = Z_NEXT(p->val);
799
202k
  }
800
3.59M
  return NULL;
801
4.72M
}
802
803
static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *ht, zend_ulong h)
804
2.03G
{
805
2.03G
  uint32_t nIndex;
806
2.03G
  uint32_t idx;
807
2.03G
  Bucket *p, *arData;
808
809
2.03G
  arData = ht->arData;
810
2.03G
  nIndex = h | ht->nTableMask;
811
2.03G
  idx = HT_HASH_EX(arData, nIndex);
812
2.40G
  while (idx != HT_INVALID_IDX) {
813
1.38G
    ZEND_ASSERT(idx < HT_IDX_TO_HASH(ht->nTableSize));
814
1.38G
    p = HT_HASH_TO_BUCKET_EX(arData, idx);
815
1.38G
    if (p->h == h && !p->key) {
816
1.01G
      return p;
817
1.01G
    }
818
374M
    idx = Z_NEXT(p->val);
819
374M
  }
820
1.02G
  return NULL;
821
2.03G
}
822
823
static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, uint32_t flag)
824
5.32M
{
825
5.32M
  zend_ulong h;
826
5.32M
  uint32_t nIndex;
827
5.32M
  uint32_t idx;
828
5.32M
  Bucket *p, *arData;
829
830
5.32M
  IS_CONSISTENT(ht);
831
5.32M
  HT_ASSERT_RC1(ht);
832
5.32M
  zend_string_hash_val(key);
833
834
5.32M
  if (UNEXPECTED(HT_FLAGS(ht) & (HASH_FLAG_UNINITIALIZED|HASH_FLAG_PACKED))) {
835
786k
    if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
836
778k
      zend_hash_real_init_mixed(ht);
837
778k
      goto add_to_hash;
838
778k
    } else {
839
7.80k
      zend_hash_packed_to_hash(ht);
840
7.80k
    }
841
4.54M
  } else if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
842
4.54M
    p = zend_hash_find_bucket(ht, key);
843
844
4.54M
    if (p) {
845
832k
      zval *data;
846
847
832k
      ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
848
832k
      if (flag & HASH_LOOKUP) {
849
221k
        return &p->val;
850
611k
      } else if (flag & HASH_ADD) {
851
207k
        if (!(flag & HASH_UPDATE_INDIRECT)) {
852
205k
          return NULL;
853
205k
        }
854
1.18k
        ZEND_ASSERT(&p->val != pData);
855
1.18k
        data = &p->val;
856
1.18k
        if (Z_TYPE_P(data) == IS_INDIRECT) {
857
0
          data = Z_INDIRECT_P(data);
858
0
          if (Z_TYPE_P(data) != IS_UNDEF) {
859
0
            return NULL;
860
0
          }
861
1.18k
        } else {
862
1.18k
          return NULL;
863
1.18k
        }
864
404k
      } else {
865
404k
        ZEND_ASSERT(&p->val != pData);
866
404k
        data = &p->val;
867
404k
        if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
868
0
          data = Z_INDIRECT_P(data);
869
0
        }
870
404k
      }
871
404k
      if (ht->pDestructor) {
872
404k
        ht->pDestructor(data);
873
404k
      }
874
404k
      ZVAL_COPY_VALUE(data, pData);
875
404k
      return data;
876
832k
    }
877
4.54M
  }
878
879
3.71M
  ZEND_HASH_IF_FULL_DO_RESIZE(ht);   /* If the Hash table is full, resize it */
880
881
4.49M
add_to_hash:
882
4.49M
  if (!ZSTR_IS_INTERNED(key)) {
883
1.51M
    zend_string_addref(key);
884
1.51M
    HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
885
1.51M
  }
886
4.49M
  idx = ht->nNumUsed++;
887
4.49M
  ht->nNumOfElements++;
888
4.49M
  arData = ht->arData;
889
4.49M
  p = arData + idx;
890
4.49M
  p->key = key;
891
4.49M
  p->h = h = ZSTR_H(key);
892
4.49M
  nIndex = h | ht->nTableMask;
893
4.49M
  Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex);
894
4.49M
  HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);
895
4.49M
  if (flag & HASH_LOOKUP) {
896
306k
    ZVAL_NULL(&p->val);
897
4.18M
  } else {
898
4.18M
    ZVAL_COPY_VALUE(&p->val, pData);
899
4.18M
  }
900
901
4.49M
  return &p->val;
902
3.71M
}
903
904
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)
905
333k
{
906
333k
  zend_string *key;
907
333k
  uint32_t nIndex;
908
333k
  uint32_t idx;
909
333k
  Bucket *p;
910
911
333k
  IS_CONSISTENT(ht);
912
333k
  HT_ASSERT_RC1(ht);
913
914
333k
  if (UNEXPECTED(HT_FLAGS(ht) & (HASH_FLAG_UNINITIALIZED|HASH_FLAG_PACKED))) {
915
182k
    if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
916
182k
      zend_hash_real_init_mixed(ht);
917
182k
      goto add_to_hash;
918
182k
    } else {
919
55
      zend_hash_packed_to_hash(ht);
920
55
    }
921
182k
  } else if ((flag & HASH_ADD_NEW) == 0) {
922
150k
    p = zend_hash_str_find_bucket(ht, str, len, h);
923
924
150k
    if (p) {
925
110k
      zval *data;
926
927
110k
      if (flag & HASH_LOOKUP) {
928
0
        return &p->val;
929
110k
      } else if (flag & HASH_ADD) {
930
0
        if (!(flag & HASH_UPDATE_INDIRECT)) {
931
0
          return NULL;
932
0
        }
933
0
        ZEND_ASSERT(&p->val != pData);
934
0
        data = &p->val;
935
0
        if (Z_TYPE_P(data) == IS_INDIRECT) {
936
0
          data = Z_INDIRECT_P(data);
937
0
          if (Z_TYPE_P(data) != IS_UNDEF) {
938
0
            return NULL;
939
0
          }
940
0
        } else {
941
0
          return NULL;
942
0
        }
943
110k
      } else {
944
110k
        ZEND_ASSERT(&p->val != pData);
945
110k
        data = &p->val;
946
110k
        if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
947
0
          data = Z_INDIRECT_P(data);
948
0
        }
949
110k
      }
950
110k
      if (ht->pDestructor) {
951
110k
        ht->pDestructor(data);
952
110k
      }
953
110k
      ZVAL_COPY_VALUE(data, pData);
954
110k
      return data;
955
110k
    }
956
150k
  }
957
958
40.2k
  ZEND_HASH_IF_FULL_DO_RESIZE(ht);   /* If the Hash table is full, resize it */
959
960
223k
add_to_hash:
961
223k
  idx = ht->nNumUsed++;
962
223k
  ht->nNumOfElements++;
963
223k
  p = ht->arData + idx;
964
223k
  p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
965
#if ZEND_RC_DEBUG
966
  if (GC_FLAGS(ht) & GC_PERSISTENT_LOCAL) {
967
    GC_MAKE_PERSISTENT_LOCAL(key);
968
  }
969
#endif
970
223k
  p->h = ZSTR_H(key) = h;
971
223k
  HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
972
223k
  if (flag & HASH_LOOKUP) {
973
0
    ZVAL_NULL(&p->val);
974
223k
  } else {
975
223k
    ZVAL_COPY_VALUE(&p->val, pData);
976
223k
  }
977
223k
  nIndex = h | ht->nTableMask;
978
223k
  Z_NEXT(p->val) = HT_HASH(ht, nIndex);
979
223k
  HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
980
981
223k
  return &p->val;
982
40.2k
}
983
984
ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag)
985
0
{
986
0
  if (flag == HASH_ADD) {
987
0
    return zend_hash_add(ht, key, pData);
988
0
  } else if (flag == HASH_ADD_NEW) {
989
0
    return zend_hash_add_new(ht, key, pData);
990
0
  } else if (flag == HASH_UPDATE) {
991
0
    return zend_hash_update(ht, key, pData);
992
0
  } else {
993
0
    ZEND_ASSERT(flag == (HASH_UPDATE|HASH_UPDATE_INDIRECT));
994
0
    return zend_hash_update_ind(ht, key, pData);
995
0
  }
996
0
}
997
998
ZEND_API zval* ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key, zval *pData)
999
974k
{
1000
974k
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD);
1001
974k
}
1002
1003
ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
1004
1.89M
{
1005
1.89M
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE);
1006
1.89M
}
1007
1008
ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData)
1009
4.44k
{
1010
4.44k
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT);
1011
4.44k
}
1012
1013
ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
1014
1.92M
{
1015
1.92M
  return _zend_hash_add_or_update_i(ht, key, pData, HASH_ADD_NEW);
1016
1.92M
}
1017
1018
ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key)
1019
528k
{
1020
528k
  return _zend_hash_add_or_update_i(ht, key, NULL, HASH_LOOKUP);
1021
528k
}
1022
1023
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *str, size_t len, zval *pData, uint32_t flag)
1024
0
{
1025
0
  if (flag == HASH_ADD) {
1026
0
    return zend_hash_str_add(ht, str, len, pData);
1027
0
  } else if (flag == HASH_ADD_NEW) {
1028
0
    return zend_hash_str_add_new(ht, str, len, pData);
1029
0
  } else if (flag == HASH_UPDATE) {
1030
0
    return zend_hash_str_update(ht, str, len, pData);
1031
0
  } else {
1032
0
    ZEND_ASSERT(flag == (HASH_UPDATE|HASH_UPDATE_INDIRECT));
1033
0
    return zend_hash_str_update_ind(ht, str, len, pData);
1034
0
  }
1035
0
}
1036
1037
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
1038
327k
{
1039
327k
  zend_ulong h = zend_hash_func(str, len);
1040
1041
327k
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_UPDATE);
1042
327k
}
1043
1044
ZEND_API zval* ZEND_FASTCALL zend_hash_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData)
1045
0
{
1046
0
  zend_ulong h = zend_hash_func(str, len);
1047
1048
0
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_UPDATE | HASH_UPDATE_INDIRECT);
1049
0
}
1050
1051
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add(HashTable *ht, const char *str, size_t len, zval *pData)
1052
5.83k
{
1053
5.83k
  zend_ulong h = zend_hash_func(str, len);
1054
1055
5.83k
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_ADD);
1056
5.83k
}
1057
1058
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData)
1059
189
{
1060
189
  zend_ulong h = zend_hash_func(str, len);
1061
1062
189
  return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_ADD_NEW);
1063
189
}
1064
1065
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h)
1066
5.84k
{
1067
5.84k
  zval dummy;
1068
1069
5.84k
  ZVAL_NULL(&dummy);
1070
5.84k
  return zend_hash_index_add(ht, h, &dummy);
1071
5.84k
}
1072
1073
ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
1074
522k
{
1075
522k
  zval dummy;
1076
1077
522k
  ZVAL_NULL(&dummy);
1078
522k
  return zend_hash_add(ht, key, &dummy);
1079
522k
}
1080
1081
ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
1082
0
{
1083
0
  zval dummy;
1084
1085
0
  ZVAL_NULL(&dummy);
1086
0
  return zend_hash_str_add(ht, str, len, &dummy);
1087
0
}
1088
1089
static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag)
1090
1.02G
{
1091
1.02G
  uint32_t nIndex;
1092
1.02G
  uint32_t idx;
1093
1.02G
  Bucket *p;
1094
1.02G
  zval *zv;
1095
1096
1.02G
  IS_CONSISTENT(ht);
1097
1.02G
  HT_ASSERT_RC1(ht);
1098
1099
1.02G
  if ((flag & HASH_ADD_NEXT) && h == ZEND_LONG_MIN) {
1100
2.23M
    h = 0;
1101
2.23M
  }
1102
1103
1.02G
  if (HT_IS_PACKED(ht)) {
1104
14.9M
    if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) != (HASH_ADD_NEW|HASH_ADD_NEXT)
1105
13.8M
     && h < ht->nNumUsed) {
1106
34.2k
      zv = ht->arPacked + h;
1107
34.2k
      if (Z_TYPE_P(zv) != IS_UNDEF) {
1108
30.4k
        if (flag & HASH_LOOKUP) {
1109
15
          return zv;
1110
15
        }
1111
53.6k
replace:
1112
53.6k
        if (flag & HASH_ADD) {
1113
19.9k
          return NULL;
1114
19.9k
        }
1115
33.7k
        if (ht->pDestructor) {
1116
33.7k
          ht->pDestructor(zv);
1117
33.7k
        }
1118
33.7k
        ZVAL_COPY_VALUE(zv, pData);
1119
33.7k
        return zv;
1120
53.6k
      } else { /* we have to keep the order :( */
1121
3.74k
        goto convert_to_hash;
1122
3.74k
      }
1123
14.8M
    } else if (EXPECTED(h < ht->nTableSize)) {
1124
17.1M
add_to_packed:
1125
17.1M
      zv = ht->arPacked + h;
1126
      /* incremental initialization of empty Buckets */
1127
17.1M
      if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) != (HASH_ADD_NEW|HASH_ADD_NEXT)) {
1128
14.5M
        if (h > ht->nNumUsed) {
1129
55.9k
          zval *q = ht->arPacked + ht->nNumUsed;
1130
206k
          while (q != zv) {
1131
150k
            ZVAL_UNDEF(q);
1132
150k
            q++;
1133
150k
          }
1134
55.9k
        }
1135
14.5M
      }
1136
17.1M
      ht->nNextFreeElement = ht->nNumUsed = h + 1;
1137
17.1M
      ht->nNumOfElements++;
1138
17.1M
      if (flag & HASH_LOOKUP) {
1139
13.4k
        ZVAL_NULL(zv);
1140
17.1M
      } else {
1141
17.1M
        ZVAL_COPY_VALUE(zv, pData);
1142
17.1M
      }
1143
1144
17.1M
      return zv;
1145
14.6M
    } else if ((h >> 1) < ht->nTableSize &&
1146
207k
               (ht->nTableSize >> 1) < ht->nNumOfElements) {
1147
206k
      zend_hash_packed_grow(ht);
1148
206k
      goto add_to_packed;
1149
206k
    } else {
1150
6.40k
      if (ht->nNumUsed >= ht->nTableSize) {
1151
784
        ht->nTableSize += ht->nTableSize;
1152
784
      }
1153
10.1k
convert_to_hash:
1154
10.1k
      zend_hash_packed_to_hash(ht);
1155
10.1k
    }
1156
1.01G
  } else if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
1157
2.41M
    if (h < ht->nTableSize) {
1158
2.31M
      zend_hash_real_init_packed_ex(ht);
1159
2.31M
      goto add_to_packed;
1160
2.31M
    }
1161
94.1k
    zend_hash_real_init_mixed(ht);
1162
1.00G
  } else {
1163
1.00G
    if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
1164
1.00G
      p = zend_hash_index_find_bucket(ht, h);
1165
1.00G
      if (p) {
1166
282k
        if (flag & HASH_LOOKUP) {
1167
258k
          return &p->val;
1168
258k
        }
1169
23.2k
        ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
1170
23.2k
        zv = &p->val;
1171
23.2k
        goto replace;
1172
23.2k
      }
1173
1.00G
    }
1174
1.00G
    ZEND_HASH_IF_FULL_DO_RESIZE(ht);   /* If the Hash table is full, resize it */
1175
1.00G
  }
1176
1177
1.00G
  idx = ht->nNumUsed++;
1178
1.00G
  nIndex = h | ht->nTableMask;
1179
1.00G
  p = ht->arData + idx;
1180
1.00G
  Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1181
1.00G
  HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1182
1.00G
  if ((zend_long)h >= ht->nNextFreeElement) {
1183
4.18M
    ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
1184
4.18M
  }
1185
1.00G
  ht->nNumOfElements++;
1186
1.00G
  p->h = h;
1187
1.00G
  p->key = NULL;
1188
1.00G
  if (flag & HASH_LOOKUP) {
1189
1.13M
    ZVAL_NULL(&p->val);
1190
1.00G
  } else {
1191
1.00G
    ZVAL_COPY_VALUE(&p->val, pData);
1192
1.00G
  }
1193
1194
1.00G
  return &p->val;
1195
1.02G
}
1196
1197
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag)
1198
0
{
1199
0
  if (flag == HASH_ADD) {
1200
0
    return zend_hash_index_add(ht, h, pData);
1201
0
  } else if (flag == (HASH_ADD|HASH_ADD_NEW)) {
1202
0
    return zend_hash_index_add_new(ht, h, pData);
1203
0
  } else if (flag == (HASH_ADD|HASH_ADD_NEXT)) {
1204
0
    ZEND_ASSERT(h == ht->nNextFreeElement);
1205
0
    return zend_hash_next_index_insert(ht, pData);
1206
0
  } else if (flag == (HASH_ADD|HASH_ADD_NEW|HASH_ADD_NEXT)) {
1207
0
    ZEND_ASSERT(h == ht->nNextFreeElement);
1208
0
    return zend_hash_next_index_insert_new(ht, pData);
1209
0
  } else {
1210
0
    ZEND_ASSERT(flag == HASH_UPDATE);
1211
0
    return zend_hash_index_update(ht, h, pData);
1212
0
  }
1213
0
}
1214
1215
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData)
1216
42.0k
{
1217
42.0k
  return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD);
1218
42.0k
}
1219
1220
ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData)
1221
1.00G
{
1222
1.00G
  return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_ADD | HASH_ADD_NEW);
1223
1.00G
}
1224
1225
ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
1226
5.33M
{
1227
5.33M
  return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE);
1228
5.33M
}
1229
1230
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
1231
9.63M
{
1232
9.63M
  return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEXT);
1233
9.63M
}
1234
1235
ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
1236
2.63M
{
1237
2.63M
  return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT);
1238
2.63M
}
1239
1240
ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h)
1241
1.40M
{
1242
1.40M
  return _zend_hash_index_add_or_update_i(ht, h, NULL, HASH_LOOKUP);
1243
1.40M
}
1244
1245
ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key)
1246
7.25k
{
1247
7.25k
  uint32_t nIndex;
1248
7.25k
  uint32_t idx, i;
1249
7.25k
  Bucket *p, *arData;
1250
1251
7.25k
  IS_CONSISTENT(ht);
1252
7.25k
  HT_ASSERT_RC1(ht);
1253
7.25k
  ZEND_ASSERT(!HT_IS_PACKED(ht));
1254
1255
7.25k
  (void)zend_string_hash_val(key);
1256
7.25k
  p = zend_hash_find_bucket(ht, key);
1257
7.25k
  if (UNEXPECTED(p)) {
1258
140
    return (p == b) ? &p->val : NULL;
1259
140
  }
1260
1261
7.11k
  if (!ZSTR_IS_INTERNED(key)) {
1262
260
    zend_string_addref(key);
1263
260
    HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1264
260
  }
1265
1266
7.11k
  arData = ht->arData;
1267
1268
  /* del from hash */
1269
7.11k
  idx = HT_IDX_TO_HASH(b - arData);
1270
7.11k
  nIndex = b->h | ht->nTableMask;
1271
7.11k
  i = HT_HASH_EX(arData, nIndex);
1272
7.11k
  if (i == idx) {
1273
7.11k
    HT_HASH_EX(arData, nIndex) = Z_NEXT(b->val);
1274
7.11k
  } else {
1275
6
    p = HT_HASH_TO_BUCKET_EX(arData, i);
1276
6
    while (Z_NEXT(p->val) != idx) {
1277
0
      i = Z_NEXT(p->val);
1278
0
      p = HT_HASH_TO_BUCKET_EX(arData, i);
1279
0
    }
1280
6
    Z_NEXT(p->val) = Z_NEXT(b->val);
1281
6
  }
1282
7.11k
  zend_string_release(b->key);
1283
1284
  /* add to hash */
1285
7.11k
  idx = b - arData;
1286
7.11k
  b->key = key;
1287
7.11k
  b->h = ZSTR_H(key);
1288
7.11k
  nIndex = b->h | ht->nTableMask;
1289
7.11k
  idx = HT_IDX_TO_HASH(idx);
1290
7.11k
  i = HT_HASH_EX(arData, nIndex);
1291
7.11k
  if (i == HT_INVALID_IDX || i < idx) {
1292
7.11k
    Z_NEXT(b->val) = i;
1293
7.11k
    HT_HASH_EX(arData, nIndex) = idx;
1294
7.11k
  } else {
1295
5
    p = HT_HASH_TO_BUCKET_EX(arData, i);
1296
5
    while (Z_NEXT(p->val) != HT_INVALID_IDX && Z_NEXT(p->val) > idx) {
1297
0
      i = Z_NEXT(p->val);
1298
0
      p = HT_HASH_TO_BUCKET_EX(arData, i);
1299
0
    }
1300
5
    Z_NEXT(b->val) = Z_NEXT(p->val);
1301
5
    Z_NEXT(p->val) = idx;
1302
5
  }
1303
7.11k
  return &b->val;
1304
7.25k
}
1305
1306
static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
1307
69.1k
{
1308
1309
69.1k
  IS_CONSISTENT(ht);
1310
69.1k
  HT_ASSERT_RC1(ht);
1311
1312
69.1k
  ZEND_ASSERT(!HT_IS_PACKED(ht));
1313
69.1k
  if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */
1314
44.7k
    zend_hash_rehash(ht);
1315
44.7k
  } else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
1316
24.3k
    void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
1317
24.3k
    uint32_t nSize = ht->nTableSize + ht->nTableSize;
1318
24.3k
    Bucket *old_buckets = ht->arData;
1319
1320
24.3k
    ZEND_ASSERT(HT_SIZE_TO_MASK(nSize));
1321
1322
24.3k
    new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1323
24.3k
    ht->nTableSize = nSize;
1324
24.3k
    ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
1325
24.3k
    HT_SET_DATA_ADDR(ht, new_data);
1326
24.3k
    memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
1327
24.3k
    pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1328
24.3k
    zend_hash_rehash(ht);
1329
24.3k
  } else {
1330
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));
1331
0
  }
1332
69.1k
}
1333
1334
ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
1335
317k
{
1336
317k
  Bucket *p;
1337
317k
  uint32_t nIndex, i;
1338
1339
317k
  IS_CONSISTENT(ht);
1340
1341
317k
  if (UNEXPECTED(ht->nNumOfElements == 0)) {
1342
21
    if (!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1343
21
      ht->nNumUsed = 0;
1344
21
      HT_HASH_RESET(ht);
1345
      /* Even if the array is empty, we still need to reset the iterator positions. */
1346
21
      ht->nInternalPointer = 0;
1347
21
      if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
1348
11
        HashTableIterator *iter = EG(ht_iterators);
1349
11
        HashTableIterator *end  = iter + EG(ht_iterators_used);
1350
22
        while (iter != end) {
1351
11
          if (iter->ht == ht) {
1352
11
            iter->pos = 0;
1353
11
          }
1354
11
          iter++;
1355
11
        }
1356
11
      }
1357
21
    }
1358
21
    return;
1359
21
  }
1360
1361
317k
  HT_HASH_RESET(ht);
1362
317k
  i = 0;
1363
317k
  p = ht->arData;
1364
317k
  if (HT_IS_WITHOUT_HOLES(ht)) {
1365
1.86M
    do {
1366
1.86M
      nIndex = p->h | ht->nTableMask;
1367
1.86M
      Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1368
1.86M
      HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
1369
1.86M
      p++;
1370
1.86M
    } while (++i < ht->nNumUsed);
1371
264k
  } else {
1372
53.8k
    uint32_t old_num_used = ht->nNumUsed;
1373
9.61M
    do {
1374
9.61M
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) {
1375
53.8k
        uint32_t j = i;
1376
53.8k
        Bucket *q = p;
1377
1378
53.8k
        if (EXPECTED(!HT_HAS_ITERATORS(ht))) {
1379
822M
          while (++i < ht->nNumUsed) {
1380
822M
            p++;
1381
822M
            if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
1382
210M
              ZVAL_COPY_VALUE(&q->val, &p->val);
1383
210M
              q->h = p->h;
1384
210M
              nIndex = q->h | ht->nTableMask;
1385
210M
              q->key = p->key;
1386
210M
              Z_NEXT(q->val) = HT_HASH(ht, nIndex);
1387
210M
              HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
1388
210M
              if (UNEXPECTED(ht->nInternalPointer > j && ht->nInternalPointer <= i)) {
1389
2
                ht->nInternalPointer = j;
1390
2
              }
1391
210M
              q++;
1392
210M
              j++;
1393
210M
            }
1394
822M
          }
1395
53.7k
        } else {
1396
37
          uint32_t iter_pos = zend_hash_iterators_lower_pos(ht, i + 1);
1397
1398
297
          while (++i < ht->nNumUsed) {
1399
260
            p++;
1400
260
            if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) {
1401
100
              ZVAL_COPY_VALUE(&q->val, &p->val);
1402
100
              q->h = p->h;
1403
100
              nIndex = q->h | ht->nTableMask;
1404
100
              q->key = p->key;
1405
100
              Z_NEXT(q->val) = HT_HASH(ht, nIndex);
1406
100
              HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j);
1407
100
              if (UNEXPECTED(ht->nInternalPointer > j && ht->nInternalPointer <= i)) {
1408
2
                ht->nInternalPointer = j;
1409
2
              }
1410
100
              if (UNEXPECTED(i >= iter_pos)) {
1411
32
                do {
1412
32
                  zend_hash_iterators_update(ht, iter_pos, j);
1413
32
                  iter_pos = zend_hash_iterators_lower_pos(ht, iter_pos + 1);
1414
32
                } while (iter_pos < i);
1415
32
              }
1416
100
              q++;
1417
100
              j++;
1418
100
            }
1419
260
          }
1420
37
        }
1421
53.8k
        ht->nNumUsed = j;
1422
53.8k
        break;
1423
53.8k
      }
1424
9.55M
      nIndex = p->h | ht->nTableMask;
1425
9.55M
      Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1426
9.55M
      HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i);
1427
9.55M
      p++;
1428
9.55M
    } while (++i < ht->nNumUsed);
1429
1430
    /* Migrate pointer to one past the end of the array to the new one past the end, so that
1431
     * newly inserted elements are picked up correctly. */
1432
53.8k
    if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
1433
37
      _zend_hash_iterators_update(ht, old_num_used, ht->nNumUsed);
1434
37
    }
1435
53.8k
  }
1436
317k
}
1437
1438
static zend_always_inline void zend_hash_iterators_clamp_max(const HashTable *ht, uint32_t max)
1439
58.3M
{
1440
58.3M
  if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
1441
832
    HashTableIterator *iter = EG(ht_iterators);
1442
832
    const HashTableIterator *end = iter + EG(ht_iterators_used);
1443
1.68k
    while (iter != end) {
1444
848
      if (iter->ht == ht) {
1445
832
        iter->pos = MIN(iter->pos, max);
1446
832
      }
1447
848
      iter++;
1448
848
    }
1449
832
  }
1450
58.3M
}
1451
1452
static zend_always_inline void _zend_hash_packed_del_val(HashTable *ht, uint32_t idx, zval *zv)
1453
10.6k
{
1454
10.6k
  idx = HT_HASH_TO_IDX(idx);
1455
10.6k
  ht->nNumOfElements--;
1456
10.6k
  if (ht->nNumUsed - 1 == idx) {
1457
22.1k
    do {
1458
22.1k
      ht->nNumUsed--;
1459
22.1k
    } while (ht->nNumUsed > 0 && (UNEXPECTED(Z_TYPE(ht->arPacked[ht->nNumUsed-1]) == IS_UNDEF)));
1460
9.30k
    ht->nInternalPointer = MIN(ht->nInternalPointer, ht->nNumUsed);
1461
9.30k
    zend_hash_iterators_clamp_max(ht, ht->nNumUsed);
1462
9.30k
  }
1463
10.6k
  if (ht->pDestructor) {
1464
10.6k
    zval tmp;
1465
10.6k
    ZVAL_COPY_VALUE(&tmp, zv);
1466
10.6k
    ZVAL_UNDEF(zv);
1467
10.6k
    ht->pDestructor(&tmp);
1468
10.6k
  } else {
1469
0
    ZVAL_UNDEF(zv);
1470
0
  }
1471
10.6k
}
1472
1473
static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, Bucket *p, Bucket *prev)
1474
990M
{
1475
990M
  if (prev) {
1476
95.7M
    Z_NEXT(prev->val) = Z_NEXT(p->val);
1477
894M
  } else {
1478
894M
    HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
1479
894M
  }
1480
990M
  idx = HT_HASH_TO_IDX(idx);
1481
990M
  ht->nNumOfElements--;
1482
990M
  if (ht->nNumUsed - 1 == idx) {
1483
189M
    do {
1484
189M
      ht->nNumUsed--;
1485
189M
    } while (ht->nNumUsed > 0 && (UNEXPECTED(Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF)));
1486
58.3M
    ht->nInternalPointer = MIN(ht->nInternalPointer, ht->nNumUsed);
1487
58.3M
    zend_hash_iterators_clamp_max(ht, ht->nNumUsed);
1488
58.3M
  }
1489
990M
  if (ht->pDestructor) {
1490
1.47M
    zval tmp;
1491
1.47M
    ZVAL_COPY_VALUE(&tmp, &p->val);
1492
1.47M
    ZVAL_UNDEF(&p->val);
1493
1.47M
    ht->pDestructor(&tmp);
1494
988M
  } else {
1495
988M
    ZVAL_UNDEF(&p->val);
1496
988M
  }
1497
990M
}
1498
1499
static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bucket *p)
1500
989M
{
1501
989M
  Bucket *prev = NULL;
1502
989M
  uint32_t nIndex;
1503
989M
  uint32_t i;
1504
1505
989M
  nIndex = p->h | ht->nTableMask;
1506
989M
  i = HT_HASH(ht, nIndex);
1507
1508
989M
  if (i != idx) {
1509
95.7M
    prev = HT_HASH_TO_BUCKET(ht, i);
1510
104M
    while (Z_NEXT(prev->val) != idx) {
1511
8.50M
      i = Z_NEXT(prev->val);
1512
8.50M
      prev = HT_HASH_TO_BUCKET(ht, i);
1513
8.50M
    }
1514
95.7M
  }
1515
1516
989M
  if (p->key) {
1517
1.45M
    zend_string_release(p->key);
1518
1.45M
    p->key = NULL;
1519
1.45M
  }
1520
989M
  _zend_hash_del_el_ex(ht, idx, p, prev);
1521
989M
}
1522
1523
ZEND_API void ZEND_FASTCALL zend_hash_packed_del_val(HashTable *ht, zval *zv)
1524
1.49k
{
1525
1.49k
  IS_CONSISTENT(ht);
1526
1.49k
  HT_ASSERT_RC1(ht);
1527
1.49k
  ZEND_ASSERT(HT_IS_PACKED(ht));
1528
1.49k
  _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(zv - ht->arPacked), zv);
1529
1.49k
}
1530
1531
1532
ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p)
1533
988M
{
1534
988M
  IS_CONSISTENT(ht);
1535
988M
  HT_ASSERT_RC1(ht);
1536
988M
  ZEND_ASSERT(!HT_IS_PACKED(ht));
1537
988M
  _zend_hash_del_el(ht, HT_IDX_TO_HASH(p - ht->arData), p);
1538
988M
}
1539
1540
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
1541
239k
{
1542
239k
  zend_ulong h;
1543
239k
  uint32_t nIndex;
1544
239k
  uint32_t idx;
1545
239k
  Bucket *p;
1546
239k
  Bucket *prev = NULL;
1547
1548
239k
  IS_CONSISTENT(ht);
1549
239k
  HT_ASSERT_RC1(ht);
1550
1551
239k
  h = zend_string_hash_val(key);
1552
239k
  nIndex = h | ht->nTableMask;
1553
1554
239k
  idx = HT_HASH(ht, nIndex);
1555
244k
  while (idx != HT_INVALID_IDX) {
1556
236k
    p = HT_HASH_TO_BUCKET(ht, idx);
1557
236k
    if ((p->key == key) ||
1558
5.70k
      (p->h == h &&
1559
1.76k
         p->key &&
1560
231k
         zend_string_equal_content(p->key, key))) {
1561
231k
      zend_string_release(p->key);
1562
231k
      p->key = NULL;
1563
231k
      _zend_hash_del_el_ex(ht, idx, p, prev);
1564
231k
      return SUCCESS;
1565
231k
    }
1566
4.47k
    prev = p;
1567
4.47k
    idx = Z_NEXT(p->val);
1568
4.47k
  }
1569
7.95k
  return FAILURE;
1570
239k
}
1571
1572
ZEND_API zend_result ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key)
1573
189
{
1574
189
  zend_ulong h;
1575
189
  uint32_t nIndex;
1576
189
  uint32_t idx;
1577
189
  Bucket *p;
1578
189
  Bucket *prev = NULL;
1579
1580
189
  IS_CONSISTENT(ht);
1581
189
  HT_ASSERT_RC1(ht);
1582
1583
189
  h = zend_string_hash_val(key);
1584
189
  nIndex = h | ht->nTableMask;
1585
1586
189
  idx = HT_HASH(ht, nIndex);
1587
189
  while (idx != HT_INVALID_IDX) {
1588
128
    p = HT_HASH_TO_BUCKET(ht, idx);
1589
128
    if ((p->key == key) ||
1590
1
      (p->h == h &&
1591
1
         p->key &&
1592
128
         zend_string_equal_content(p->key, key))) {
1593
128
      if (Z_TYPE(p->val) == IS_INDIRECT) {
1594
45
        zval *data = Z_INDIRECT(p->val);
1595
1596
45
        if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
1597
0
          return FAILURE;
1598
45
        } else {
1599
45
          if (ht->pDestructor) {
1600
45
            zval tmp;
1601
45
            ZVAL_COPY_VALUE(&tmp, data);
1602
45
            ZVAL_UNDEF(data);
1603
45
            ht->pDestructor(&tmp);
1604
45
          } else {
1605
0
            ZVAL_UNDEF(data);
1606
0
          }
1607
45
          HT_FLAGS(ht) |= HASH_FLAG_HAS_EMPTY_IND;
1608
45
        }
1609
83
      } else {
1610
83
        zend_string_release(p->key);
1611
83
        p->key = NULL;
1612
83
        _zend_hash_del_el_ex(ht, idx, p, prev);
1613
83
      }
1614
128
      return SUCCESS;
1615
128
    }
1616
0
    prev = p;
1617
0
    idx = Z_NEXT(p->val);
1618
0
  }
1619
61
  return FAILURE;
1620
189
}
1621
1622
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *str, size_t len)
1623
0
{
1624
0
  zend_ulong h;
1625
0
  uint32_t nIndex;
1626
0
  uint32_t idx;
1627
0
  Bucket *p;
1628
0
  Bucket *prev = NULL;
1629
1630
0
  IS_CONSISTENT(ht);
1631
0
  HT_ASSERT_RC1(ht);
1632
1633
0
  h = zend_inline_hash_func(str, len);
1634
0
  nIndex = h | ht->nTableMask;
1635
1636
0
  idx = HT_HASH(ht, nIndex);
1637
0
  while (idx != HT_INVALID_IDX) {
1638
0
    p = HT_HASH_TO_BUCKET(ht, idx);
1639
0
    if ((p->h == h)
1640
0
       && p->key
1641
0
       && zend_string_equals_cstr(p->key, str, len)) {
1642
0
      if (Z_TYPE(p->val) == IS_INDIRECT) {
1643
0
        zval *data = Z_INDIRECT(p->val);
1644
1645
0
        if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
1646
0
          return FAILURE;
1647
0
        } else {
1648
0
          if (ht->pDestructor) {
1649
0
            ht->pDestructor(data);
1650
0
          }
1651
0
          ZVAL_UNDEF(data);
1652
0
          HT_FLAGS(ht) |= HASH_FLAG_HAS_EMPTY_IND;
1653
0
        }
1654
0
      } else {
1655
0
        zend_string_release(p->key);
1656
0
        p->key = NULL;
1657
0
        _zend_hash_del_el_ex(ht, idx, p, prev);
1658
0
      }
1659
0
      return SUCCESS;
1660
0
    }
1661
0
    prev = p;
1662
0
    idx = Z_NEXT(p->val);
1663
0
  }
1664
0
  return FAILURE;
1665
0
}
1666
1667
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
1668
584
{
1669
584
  zend_ulong h;
1670
584
  uint32_t nIndex;
1671
584
  uint32_t idx;
1672
584
  Bucket *p;
1673
584
  Bucket *prev = NULL;
1674
1675
584
  IS_CONSISTENT(ht);
1676
584
  HT_ASSERT_RC1(ht);
1677
1678
584
  h = zend_inline_hash_func(str, len);
1679
584
  nIndex = h | ht->nTableMask;
1680
1681
584
  idx = HT_HASH(ht, nIndex);
1682
728
  while (idx != HT_INVALID_IDX) {
1683
664
    p = HT_HASH_TO_BUCKET(ht, idx);
1684
664
    if ((p->h == h)
1685
520
       && p->key
1686
520
       && zend_string_equals_cstr(p->key, str, len)) {
1687
520
      zend_string_release(p->key);
1688
520
      p->key = NULL;
1689
520
      _zend_hash_del_el_ex(ht, idx, p, prev);
1690
520
      return SUCCESS;
1691
520
    }
1692
144
    prev = p;
1693
144
    idx = Z_NEXT(p->val);
1694
144
  }
1695
64
  return FAILURE;
1696
584
}
1697
1698
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
1699
216k
{
1700
216k
  uint32_t nIndex;
1701
216k
  uint32_t idx;
1702
216k
  Bucket *p;
1703
216k
  Bucket *prev = NULL;
1704
1705
216k
  IS_CONSISTENT(ht);
1706
216k
  HT_ASSERT_RC1(ht);
1707
1708
216k
  if (HT_IS_PACKED(ht)) {
1709
9.26k
    if (h < ht->nNumUsed) {
1710
9.03k
      zval *zv = ht->arPacked + h;
1711
9.03k
      if (Z_TYPE_P(zv) != IS_UNDEF) {
1712
9.01k
        _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(h), zv);
1713
9.01k
        return SUCCESS;
1714
9.01k
      }
1715
9.03k
    }
1716
245
    return FAILURE;
1717
9.26k
  }
1718
207k
  nIndex = h | ht->nTableMask;
1719
1720
207k
  idx = HT_HASH(ht, nIndex);
1721
935k
  while (idx != HT_INVALID_IDX) {
1722
801k
    p = HT_HASH_TO_BUCKET(ht, idx);
1723
801k
    if ((p->h == h) && (p->key == NULL)) {
1724
73.8k
      _zend_hash_del_el_ex(ht, idx, p, prev);
1725
73.8k
      return SUCCESS;
1726
73.8k
    }
1727
727k
    prev = p;
1728
727k
    idx = Z_NEXT(p->val);
1729
727k
  }
1730
133k
  return FAILURE;
1731
207k
}
1732
1733
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
1734
2.29M
{
1735
2.29M
  IS_CONSISTENT(ht);
1736
2.29M
  HT_ASSERT(ht, GC_REFCOUNT(ht) <= 1);
1737
1738
2.29M
  if (ht->nNumUsed) {
1739
462k
    if (HT_IS_PACKED(ht)) {
1740
165k
      if (ht->pDestructor) {
1741
164k
        zval *zv = ht->arPacked;
1742
164k
        zval *end = zv + ht->nNumUsed;
1743
1744
164k
        SET_INCONSISTENT(HT_IS_DESTROYING);
1745
164k
        if (HT_IS_WITHOUT_HOLES(ht)) {
1746
756k
          do {
1747
756k
            ht->pDestructor(zv);
1748
756k
          } while (++zv != end);
1749
163k
        } else {
1750
3.19k
          do {
1751
3.19k
            if (EXPECTED(Z_TYPE_P(zv) != IS_UNDEF)) {
1752
985
              ht->pDestructor(zv);
1753
985
            }
1754
3.19k
          } while (++zv != end);
1755
814
        }
1756
164k
        SET_INCONSISTENT(HT_DESTROYED);
1757
164k
      }
1758
165k
      zend_hash_iterators_remove(ht);
1759
297k
    } else {
1760
297k
      Bucket *p = ht->arData;
1761
297k
      Bucket *end = p + ht->nNumUsed;
1762
1763
297k
      if (ht->pDestructor) {
1764
53.9k
        SET_INCONSISTENT(HT_IS_DESTROYING);
1765
1766
53.9k
        if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1767
33.2k
          if (HT_IS_WITHOUT_HOLES(ht)) {
1768
108k
            do {
1769
108k
              ht->pDestructor(&p->val);
1770
108k
            } while (++p != end);
1771
33.2k
          } else {
1772
0
            do {
1773
0
              if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1774
0
                ht->pDestructor(&p->val);
1775
0
              }
1776
0
            } while (++p != end);
1777
0
          }
1778
33.2k
        } else if (HT_IS_WITHOUT_HOLES(ht)) {
1779
30.3k
          do {
1780
30.3k
            ht->pDestructor(&p->val);
1781
30.3k
            if (EXPECTED(p->key)) {
1782
29.9k
              zend_string_release(p->key);
1783
29.9k
            }
1784
30.3k
          } while (++p != end);
1785
20.6k
        } else {
1786
0
          do {
1787
0
            if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1788
0
              ht->pDestructor(&p->val);
1789
0
              if (EXPECTED(p->key)) {
1790
0
                zend_string_release(p->key);
1791
0
              }
1792
0
            }
1793
0
          } while (++p != end);
1794
0
        }
1795
1796
53.9k
        SET_INCONSISTENT(HT_DESTROYED);
1797
243k
      } else {
1798
243k
        if (!HT_HAS_STATIC_KEYS_ONLY(ht)) {
1799
151k
          do {
1800
151k
            if (EXPECTED(p->key)) {
1801
150k
              zend_string_release(p->key);
1802
150k
            }
1803
151k
          } while (++p != end);
1804
46.6k
        }
1805
243k
      }
1806
297k
      zend_hash_iterators_remove(ht);
1807
297k
    }
1808
1.82M
  } else if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1809
1.69M
    return;
1810
1.69M
  }
1811
592k
  pefree(HT_GET_DATA_ADDR(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1812
592k
}
1813
1814
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
1815
7.49M
{
1816
7.49M
  IS_CONSISTENT(ht);
1817
7.49M
  HT_ASSERT(ht, GC_REFCOUNT(ht) <= 1);
1818
1819
  /* break possible cycles */
1820
7.49M
  GC_REMOVE_FROM_BUFFER(ht);
1821
7.49M
  GC_TYPE_INFO(ht) = GC_NULL /*???| (GC_WHITE << 16)*/;
1822
1823
7.49M
  if (ht->nNumUsed) {
1824
    /* In some rare cases destructors of regular arrays may be changed */
1825
5.16M
    if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) {
1826
3.10k
      zend_hash_destroy(ht);
1827
3.10k
      goto free_ht;
1828
3.10k
    }
1829
1830
5.16M
    SET_INCONSISTENT(HT_IS_DESTROYING);
1831
1832
5.16M
    if (HT_IS_PACKED(ht)) {
1833
2.27M
      zval *zv = ht->arPacked;
1834
2.27M
      zval *end = zv + ht->nNumUsed;
1835
1836
18.3M
      do {
1837
18.3M
        i_zval_ptr_dtor(zv);
1838
18.3M
      } while (++zv != end);
1839
2.88M
    } else {
1840
2.88M
      Bucket *p = ht->arData;
1841
2.88M
      Bucket *end = p + ht->nNumUsed;
1842
1843
2.88M
      if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1844
9.65M
        do {
1845
9.65M
          i_zval_ptr_dtor(&p->val);
1846
9.65M
        } while (++p != end);
1847
2.25M
      } else if (HT_IS_WITHOUT_HOLES(ht)) {
1848
2.58M
        do {
1849
2.58M
          i_zval_ptr_dtor(&p->val);
1850
2.58M
          if (EXPECTED(p->key)) {
1851
2.22M
            zend_string_release_ex(p->key, 0);
1852
2.22M
          }
1853
2.58M
        } while (++p != end);
1854
637k
      } else {
1855
10
        do {
1856
10
          if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1857
5
            i_zval_ptr_dtor(&p->val);
1858
5
            if (EXPECTED(p->key)) {
1859
5
              zend_string_release_ex(p->key, 0);
1860
5
            }
1861
5
          }
1862
10
        } while (++p != end);
1863
5
      }
1864
2.88M
    }
1865
5.16M
  } else if (EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
1866
1.81M
    goto free_ht;
1867
1.81M
  }
1868
5.67M
  SET_INCONSISTENT(HT_DESTROYED);
1869
5.67M
  efree(HT_GET_DATA_ADDR(ht));
1870
7.49M
free_ht:
1871
7.49M
  zend_hash_iterators_remove(ht);
1872
7.49M
  FREE_HASHTABLE(ht);
1873
7.49M
}
1874
1875
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
1876
436k
{
1877
436k
  IS_CONSISTENT(ht);
1878
436k
  HT_ASSERT_RC1(ht);
1879
1880
436k
  if (ht->nNumUsed) {
1881
209k
    if (HT_IS_PACKED(ht)) {
1882
2.22k
      zval *zv = ht->arPacked;
1883
2.22k
      zval *end = zv + ht->nNumUsed;
1884
1885
2.22k
      if (ht->pDestructor) {
1886
0
        if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1887
0
          if (HT_IS_WITHOUT_HOLES(ht)) {
1888
0
            do {
1889
0
              ht->pDestructor(zv);
1890
0
            } while (++zv != end);
1891
0
          } else {
1892
0
            do {
1893
0
              if (EXPECTED(Z_TYPE_P(zv) != IS_UNDEF)) {
1894
0
                ht->pDestructor(zv);
1895
0
              }
1896
0
            } while (++zv != end);
1897
0
          }
1898
0
        }
1899
0
      }
1900
206k
    } else {
1901
206k
      Bucket *p = ht->arData;
1902
206k
      Bucket *end = p + ht->nNumUsed;
1903
1904
206k
      if (ht->pDestructor) {
1905
193
        if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1906
193
          if (HT_IS_WITHOUT_HOLES(ht)) {
1907
517
            do {
1908
517
              ht->pDestructor(&p->val);
1909
517
            } while (++p != end);
1910
169
          } else {
1911
102
            do {
1912
102
              if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1913
69
                ht->pDestructor(&p->val);
1914
69
              }
1915
102
            } while (++p != end);
1916
24
          }
1917
193
        } else if (HT_IS_WITHOUT_HOLES(ht)) {
1918
0
          do {
1919
0
            ht->pDestructor(&p->val);
1920
0
            if (EXPECTED(p->key)) {
1921
0
              zend_string_release(p->key);
1922
0
            }
1923
0
          } while (++p != end);
1924
0
        } else {
1925
0
          do {
1926
0
            if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1927
0
              ht->pDestructor(&p->val);
1928
0
              if (EXPECTED(p->key)) {
1929
0
                zend_string_release(p->key);
1930
0
              }
1931
0
            }
1932
0
          } while (++p != end);
1933
0
        }
1934
206k
      } else {
1935
206k
        if (!HT_HAS_STATIC_KEYS_ONLY(ht)) {
1936
607k
          do {
1937
607k
            if (EXPECTED(p->key)) {
1938
519k
              zend_string_release(p->key);
1939
519k
            }
1940
607k
          } while (++p != end);
1941
92.8k
        }
1942
206k
      }
1943
206k
      HT_HASH_RESET(ht);
1944
206k
    }
1945
209k
  }
1946
436k
  ht->nNumUsed = 0;
1947
436k
  ht->nNumOfElements = 0;
1948
436k
  ht->nNextFreeElement = ZEND_LONG_MIN;
1949
436k
  ht->nInternalPointer = 0;
1950
436k
}
1951
1952
ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
1953
5.80k
{
1954
5.80k
  Bucket *p, *end;
1955
1956
5.80k
  IS_CONSISTENT(ht);
1957
5.80k
  HT_ASSERT_RC1(ht);
1958
1959
5.80k
  if (ht->nNumUsed) {
1960
5.63k
    ZEND_ASSERT(!HT_IS_PACKED(ht));
1961
5.63k
    p = ht->arData;
1962
5.63k
    end = p + ht->nNumUsed;
1963
5.63k
    if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
1964
38.1k
      do {
1965
38.1k
        i_zval_ptr_dtor(&p->val);
1966
38.1k
      } while (++p != end);
1967
5.19k
    } else if (HT_IS_WITHOUT_HOLES(ht)) {
1968
4.20k
      do {
1969
4.20k
        i_zval_ptr_dtor(&p->val);
1970
4.20k
        if (EXPECTED(p->key)) {
1971
4.20k
          zend_string_release(p->key);
1972
4.20k
        }
1973
4.20k
      } while (++p != end);
1974
438
    } else {
1975
0
      do {
1976
0
        if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
1977
0
          i_zval_ptr_dtor(&p->val);
1978
0
          if (EXPECTED(p->key)) {
1979
0
            zend_string_release(p->key);
1980
0
          }
1981
0
        }
1982
0
      } while (++p != end);
1983
0
    }
1984
5.63k
    HT_HASH_RESET(ht);
1985
5.63k
  }
1986
5.80k
  ht->nNumUsed = 0;
1987
1.97k
  ht->nNumOfElements = 0;
1988
1.97k
  ht->nNextFreeElement = ZEND_LONG_MIN;
1989
1.97k
  ht->nInternalPointer = 0;
1990
1.97k
}
1991
1992
ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht)
1993
0
{
1994
0
  uint32_t idx;
1995
1996
0
  IS_CONSISTENT(ht);
1997
0
  HT_ASSERT_RC1(ht);
1998
1999
0
  if (HT_IS_PACKED(ht)) {
2000
0
    zval *zv = ht->arPacked;
2001
2002
0
    for (idx = 0; idx < ht->nNumUsed; idx++, zv++) {
2003
0
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2004
0
      _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(idx), zv);
2005
0
    }
2006
0
  } else {
2007
0
    Bucket *p = ht->arData;
2008
2009
0
    for (idx = 0; idx < ht->nNumUsed; idx++, p++) {
2010
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2011
0
      _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
2012
0
    }
2013
0
  }
2014
0
  if (!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
2015
0
    pefree(HT_GET_DATA_ADDR(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
2016
0
  }
2017
2018
0
  SET_INCONSISTENT(HT_DESTROYED);
2019
0
}
2020
2021
ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht)
2022
556k
{
2023
556k
  uint32_t idx;
2024
2025
556k
  IS_CONSISTENT(ht);
2026
556k
  HT_ASSERT_RC1(ht);
2027
2028
556k
  idx = ht->nNumUsed;
2029
556k
  if (HT_IS_PACKED(ht)) {
2030
6.32k
    zval *zv = ht->arPacked + ht->nNumUsed;
2031
2032
6.59k
    while (idx > 0) {
2033
273
      idx--;
2034
273
      zv--;
2035
273
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2036
142
      _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(idx), zv);
2037
142
    }
2038
550k
  } else {
2039
550k
    Bucket *p = ht->arData + ht->nNumUsed;
2040
2041
1.95M
    while (idx > 0) {
2042
1.40M
      idx--;
2043
1.40M
      p--;
2044
1.40M
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2045
1.38M
      _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
2046
1.38M
    }
2047
550k
  }
2048
2049
556k
  if (!(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) {
2050
284k
    pefree(HT_GET_DATA_ADDR(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
2051
284k
  }
2052
2053
556k
  SET_INCONSISTENT(HT_DESTROYED);
2054
556k
}
2055
2056
/* This is used to recurse elements and selectively delete certain entries
2057
 * from a hashtable. apply_func() receives the data and decides if the entry
2058
 * should be deleted or recursion should be stopped. The following three
2059
 * return codes are possible:
2060
 * ZEND_HASH_APPLY_KEEP   - continue
2061
 * ZEND_HASH_APPLY_STOP   - stop iteration
2062
 * ZEND_HASH_APPLY_REMOVE - delete the element, combinable with the former
2063
 */
2064
2065
ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func)
2066
245
{
2067
245
  uint32_t idx;
2068
245
  int result;
2069
2070
245
  IS_CONSISTENT(ht);
2071
245
  if (HT_IS_PACKED(ht)) {
2072
885
    for (idx = 0; idx < ht->nNumUsed; idx++) {
2073
656
      zval *zv = ht->arPacked + idx;
2074
2075
656
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2076
656
      result = apply_func(zv);
2077
2078
656
      if (result & ZEND_HASH_APPLY_REMOVE) {
2079
0
        HT_ASSERT_RC1(ht);
2080
0
        _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(idx), zv);
2081
0
      }
2082
656
      if (result & ZEND_HASH_APPLY_STOP) {
2083
0
        break;
2084
0
      }
2085
656
    }
2086
229
  } else {
2087
224
    for (idx = 0; idx < ht->nNumUsed; idx++) {
2088
208
      Bucket *p = ht->arData + idx;
2089
2090
208
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2091
208
      result = apply_func(&p->val);
2092
2093
208
      if (result & ZEND_HASH_APPLY_REMOVE) {
2094
0
        HT_ASSERT_RC1(ht);
2095
0
        _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
2096
0
      }
2097
208
      if (result & ZEND_HASH_APPLY_STOP) {
2098
0
        break;
2099
0
      }
2100
208
    }
2101
16
  }
2102
245
}
2103
2104
2105
ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
2106
0
{
2107
0
  uint32_t idx;
2108
0
  int result;
2109
2110
0
  IS_CONSISTENT(ht);
2111
0
  if (HT_IS_PACKED(ht)) {
2112
0
    for (idx = 0; idx < ht->nNumUsed; idx++) {
2113
0
      zval *zv = ht->arPacked + idx;
2114
0
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2115
0
      result = apply_func(zv, argument);
2116
2117
0
      if (result & ZEND_HASH_APPLY_REMOVE) {
2118
0
        HT_ASSERT_RC1(ht);
2119
0
        _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(idx), zv);
2120
0
      }
2121
0
      if (result & ZEND_HASH_APPLY_STOP) {
2122
0
        break;
2123
0
      }
2124
0
    }
2125
0
  } else {
2126
0
    for (idx = 0; idx < ht->nNumUsed; idx++) {
2127
0
      Bucket *p = ht->arData + idx;
2128
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2129
0
      result = apply_func(&p->val, argument);
2130
2131
0
      if (result & ZEND_HASH_APPLY_REMOVE) {
2132
0
        HT_ASSERT_RC1(ht);
2133
0
        _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
2134
0
      }
2135
0
      if (result & ZEND_HASH_APPLY_STOP) {
2136
0
        break;
2137
0
      }
2138
0
    }
2139
0
  }
2140
0
}
2141
2142
2143
ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int num_args, ...)
2144
0
{
2145
0
  uint32_t idx;
2146
0
  va_list args;
2147
0
  zend_hash_key hash_key;
2148
0
  int result;
2149
2150
0
  IS_CONSISTENT(ht);
2151
2152
0
  if (HT_IS_PACKED(ht)) {
2153
0
    for (idx = 0; idx < ht->nNumUsed; idx++) {
2154
0
      zval *zv = ht->arPacked + idx;
2155
2156
0
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2157
0
      va_start(args, num_args);
2158
0
      hash_key.h = idx;
2159
0
      hash_key.key = NULL;
2160
2161
0
      result = apply_func(zv, num_args, args, &hash_key);
2162
2163
0
      if (result & ZEND_HASH_APPLY_REMOVE) {
2164
0
        HT_ASSERT_RC1(ht);
2165
0
        _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(idx), zv);
2166
0
      }
2167
0
      if (result & ZEND_HASH_APPLY_STOP) {
2168
0
        va_end(args);
2169
0
        break;
2170
0
      }
2171
0
      va_end(args);
2172
0
    }
2173
0
  } else {
2174
0
    for (idx = 0; idx < ht->nNumUsed; idx++) {
2175
0
      Bucket *p = ht->arData + idx;
2176
2177
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2178
0
      va_start(args, num_args);
2179
0
      hash_key.h = p->h;
2180
0
      hash_key.key = p->key;
2181
2182
0
      result = apply_func(&p->val, num_args, args, &hash_key);
2183
2184
0
      if (result & ZEND_HASH_APPLY_REMOVE) {
2185
0
        HT_ASSERT_RC1(ht);
2186
0
        _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
2187
0
      }
2188
0
      if (result & ZEND_HASH_APPLY_STOP) {
2189
0
        va_end(args);
2190
0
        break;
2191
0
      }
2192
0
      va_end(args);
2193
0
    }
2194
0
  }
2195
0
}
2196
2197
2198
ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func)
2199
305k
{
2200
305k
  uint32_t idx;
2201
305k
  int result;
2202
2203
305k
  IS_CONSISTENT(ht);
2204
2205
305k
  idx = ht->nNumUsed;
2206
305k
  if (HT_IS_PACKED(ht)) {
2207
0
    zval *zv;
2208
2209
0
    while (idx > 0) {
2210
0
      idx--;
2211
0
      zv = ht->arPacked + idx;
2212
0
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2213
2214
0
      result = apply_func(zv);
2215
2216
0
      if (result & ZEND_HASH_APPLY_REMOVE) {
2217
0
        HT_ASSERT_RC1(ht);
2218
0
        _zend_hash_packed_del_val(ht, HT_IDX_TO_HASH(idx), zv);
2219
0
      }
2220
0
      if (result & ZEND_HASH_APPLY_STOP) {
2221
0
        break;
2222
0
      }
2223
0
    }
2224
305k
  } else {
2225
305k
    Bucket *p;
2226
2227
2.05M
    while (idx > 0) {
2228
1.74M
      idx--;
2229
1.74M
      p = ht->arData + idx;
2230
1.74M
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2231
2232
1.70M
      result = apply_func(&p->val);
2233
2234
1.70M
      if (result & ZEND_HASH_APPLY_REMOVE) {
2235
37.1k
        HT_ASSERT_RC1(ht);
2236
37.1k
        _zend_hash_del_el(ht, HT_IDX_TO_HASH(idx), p);
2237
37.1k
      }
2238
1.70M
      if (result & ZEND_HASH_APPLY_STOP) {
2239
49
        break;
2240
49
      }
2241
1.70M
    }
2242
305k
  }
2243
305k
}
2244
2245
2246
ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, const HashTable *source, copy_ctor_func_t pCopyConstructor)
2247
305
{
2248
305
  uint32_t idx;
2249
305
  zval *new_entry, *data;
2250
2251
305
  IS_CONSISTENT(source);
2252
305
  IS_CONSISTENT(target);
2253
305
  HT_ASSERT_RC1(target);
2254
2255
305
  if (HT_IS_PACKED(source)) {
2256
0
    for (idx = 0; idx < source->nNumUsed; idx++) {
2257
0
      zval *zv = source->arPacked + idx;
2258
0
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
2259
2260
0
      new_entry = zend_hash_index_update(target, idx, zv);
2261
0
      if (pCopyConstructor) {
2262
0
        pCopyConstructor(new_entry);
2263
0
      }
2264
0
    }
2265
0
    return;
2266
0
  }
2267
2268
1.66k
  for (idx = 0; idx < source->nNumUsed; idx++) {
2269
1.36k
    Bucket *p = source->arData + idx;
2270
2271
1.36k
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2272
2273
    /* INDIRECT element may point to UNDEF-ined slots */
2274
1.36k
    data = &p->val;
2275
1.36k
    if (Z_TYPE_P(data) == IS_INDIRECT) {
2276
0
      data = Z_INDIRECT_P(data);
2277
0
      if (UNEXPECTED(Z_TYPE_P(data) == IS_UNDEF)) {
2278
0
        continue;
2279
0
      }
2280
0
    }
2281
1.36k
    if (p->key) {
2282
1.33k
      new_entry = zend_hash_update(target, p->key, data);
2283
1.33k
    } else {
2284
22
      new_entry = zend_hash_index_update(target, p->h, data);
2285
22
    }
2286
1.36k
    if (pCopyConstructor) {
2287
16
      pCopyConstructor(new_entry);
2288
16
    }
2289
1.36k
  }
2290
305
}
2291
2292
2293
static zend_always_inline bool zend_array_dup_value(const HashTable *source, zval *data, zval *dest, bool packed, bool with_holes)
2294
52.7k
{
2295
52.7k
  if (with_holes) {
2296
1.79k
    if (!packed && Z_TYPE_INFO_P(data) == IS_INDIRECT) {
2297
0
      data = Z_INDIRECT_P(data);
2298
0
    }
2299
1.79k
    if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
2300
942
      return 0;
2301
942
    }
2302
50.9k
  } else if (!packed) {
2303
    /* INDIRECT element may point to UNDEF-ined slots */
2304
30.7k
    if (Z_TYPE_INFO_P(data) == IS_INDIRECT) {
2305
9.70k
      data = Z_INDIRECT_P(data);
2306
9.70k
      if (UNEXPECTED(Z_TYPE_INFO_P(data) == IS_UNDEF)) {
2307
6.38k
        return 0;
2308
6.38k
      }
2309
9.70k
    }
2310
30.7k
  }
2311
2312
45.3k
  do {
2313
45.3k
    if (Z_OPT_REFCOUNTED_P(data)) {
2314
20.1k
      if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1 &&
2315
128
          (Z_TYPE_P(Z_REFVAL_P(data)) != IS_ARRAY ||
2316
115
            Z_ARRVAL_P(Z_REFVAL_P(data)) != source)) {
2317
115
        data = Z_REFVAL_P(data);
2318
115
        if (!Z_OPT_REFCOUNTED_P(data)) {
2319
115
          break;
2320
115
        }
2321
115
      }
2322
20.0k
      Z_ADDREF_P(data);
2323
20.0k
    }
2324
45.3k
  } while (0);
2325
45.3k
  ZVAL_COPY_VALUE(dest, data);
2326
2327
45.3k
  return 1;
2328
52.7k
}
2329
2330
static zend_always_inline bool zend_array_dup_element(const HashTable *source, HashTable *target, uint32_t idx, Bucket *p, Bucket *q, bool packed, bool static_keys, bool with_holes)
2331
30.7k
{
2332
30.7k
  if (!zend_array_dup_value(source, &p->val, &q->val, packed, with_holes)) {
2333
6.39k
    return 0;
2334
6.39k
  }
2335
2336
24.3k
  if (!packed) {
2337
24.3k
    uint32_t nIndex;
2338
2339
24.3k
    q->h = p->h;
2340
24.3k
    q->key = p->key;
2341
24.3k
    if (!static_keys && q->key) {
2342
9.37k
      zend_string_addref(q->key);
2343
9.37k
    }
2344
2345
24.3k
    nIndex = q->h | target->nTableMask;
2346
24.3k
    Z_NEXT(q->val) = HT_HASH(target, nIndex);
2347
24.3k
    HT_HASH(target, nIndex) = HT_IDX_TO_HASH(idx);
2348
24.3k
  }
2349
24.3k
  return 1;
2350
30.7k
}
2351
2352
// We need to duplicate iterators to be able to search through all copy-on-write copies to find the actually iterated HashTable and position back
2353
803
static void zend_array_dup_ht_iterators(const HashTable *source, HashTable *target) {
2354
803
  uint32_t iter_index = 0;
2355
803
  uint32_t end_index = EG(ht_iterators_used);
2356
2357
39.4k
  while (iter_index != end_index) {
2358
38.6k
    HashTableIterator *iter = &EG(ht_iterators)[iter_index];
2359
38.6k
    if (iter->ht == source) {
2360
803
      uint32_t copy_idx = zend_hash_iterator_add(target, iter->pos);
2361
      /* Refetch iter because the memory may be reallocated. */
2362
803
      iter = &EG(ht_iterators)[iter_index];
2363
803
      HashTableIterator *copy_iter = EG(ht_iterators) + copy_idx;
2364
803
      copy_iter->next_copy = iter->next_copy;
2365
803
      iter->next_copy = copy_idx;
2366
803
    }
2367
38.6k
    iter_index++;
2368
38.6k
  }
2369
803
}
2370
2371
static zend_always_inline void zend_array_dup_packed_elements(const HashTable *source, HashTable *target, bool with_holes)
2372
4.09k
{
2373
4.09k
  zval *p = source->arPacked;
2374
4.09k
  zval *q = target->arPacked;
2375
4.09k
  const zval *end = p + source->nNumUsed;
2376
2377
21.9k
  do {
2378
21.9k
    if (!zend_array_dup_value(source, p, q, true, with_holes)) {
2379
927
      if (with_holes) {
2380
927
        ZVAL_UNDEF(q);
2381
927
      }
2382
927
    }
2383
21.9k
    p++; q++;
2384
21.9k
  } while (p != end);
2385
2386
4.09k
  if (UNEXPECTED(HT_HAS_ITERATORS(source))) {
2387
736
    zend_array_dup_ht_iterators(source, target);
2388
736
  }
2389
4.09k
}
2390
2391
static zend_always_inline uint32_t zend_array_dup_elements(const HashTable *source, HashTable *target, bool static_keys, bool with_holes)
2392
4.25k
{
2393
4.25k
  uint32_t idx = 0;
2394
4.25k
  Bucket *p = source->arData;
2395
4.25k
  Bucket *q = target->arData;
2396
4.25k
  const Bucket *end = p + source->nNumUsed;
2397
2398
4.25k
  if (UNEXPECTED(HT_HAS_ITERATORS(source))) {
2399
67
    zend_array_dup_ht_iterators(source, target);
2400
67
  }
2401
2402
24.8k
  do {
2403
24.8k
    if (!zend_array_dup_element(source, target, idx, p, q, false, static_keys, with_holes)) {
2404
1.03k
      uint32_t target_idx = idx;
2405
2406
1.03k
      idx++; p++;
2407
1.03k
      if (EXPECTED(!HT_HAS_ITERATORS(target))) {
2408
6.91k
        while (p != end) {
2409
5.89k
          if (zend_array_dup_element(source, target, target_idx, p, q, false, static_keys, with_holes)) {
2410
532
            if (source->nInternalPointer == idx) {
2411
0
              target->nInternalPointer = target_idx;
2412
0
            }
2413
532
            target_idx++; q++;
2414
532
          }
2415
5.89k
          idx++; p++;
2416
5.89k
        }
2417
1.02k
      } else {
2418
10
        target->nNumUsed = source->nNumUsed;
2419
10
        uint32_t iter_pos = zend_hash_iterators_lower_pos(target, idx);
2420
2421
30
        while (p != end) {
2422
20
          if (zend_array_dup_element(source, target, target_idx, p, q, false, static_keys, with_holes)) {
2423
15
            if (source->nInternalPointer == idx) {
2424
0
              target->nInternalPointer = target_idx;
2425
0
            }
2426
15
            if (UNEXPECTED(idx >= iter_pos)) {
2427
5
              do {
2428
5
                zend_hash_iterators_update(target, iter_pos, target_idx);
2429
5
                iter_pos = zend_hash_iterators_lower_pos(target, iter_pos + 1);
2430
5
              } while (iter_pos < idx);
2431
5
            }
2432
15
            target_idx++; q++;
2433
15
          }
2434
20
          idx++; p++;
2435
20
        }
2436
10
      }
2437
1.03k
      return target_idx;
2438
1.03k
    }
2439
23.8k
    idx++; p++; q++;
2440
23.8k
  } while (p != end);
2441
3.22k
  return idx;
2442
4.25k
}
2443
2444
ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(const HashTable *source)
2445
23.4k
{
2446
23.4k
  uint32_t idx;
2447
23.4k
  HashTable *target;
2448
2449
23.4k
  IS_CONSISTENT(source);
2450
2451
23.4k
  ALLOC_HASHTABLE(target);
2452
23.4k
  GC_SET_REFCOUNT(target, 1);
2453
23.4k
  GC_TYPE_INFO(target) = GC_ARRAY;
2454
2455
23.4k
  target->pDestructor = ZVAL_PTR_DTOR;
2456
2457
23.4k
  if (source->nNumOfElements == 0) {
2458
7.21k
    HT_FLAGS(target) = HASH_FLAG_UNINITIALIZED;
2459
7.21k
    target->nTableMask = HT_MIN_MASK;
2460
7.21k
    target->nNumUsed = 0;
2461
7.21k
    target->nNumOfElements = 0;
2462
7.21k
    target->nNextFreeElement = source->nNextFreeElement;
2463
7.21k
    target->nInternalPointer = 0;
2464
7.21k
    target->nTableSize = HT_MIN_SIZE;
2465
7.21k
    HT_SET_DATA_ADDR(target, &uninitialized_bucket);
2466
16.1k
  } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
2467
7.84k
    ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_HAS_EMPTY_IND));
2468
7.84k
    HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK;
2469
7.84k
    target->nTableMask = source->nTableMask;
2470
7.84k
    target->nNumUsed = source->nNumUsed;
2471
7.84k
    target->nNumOfElements = source->nNumOfElements;
2472
7.84k
    target->nNextFreeElement = source->nNextFreeElement;
2473
7.84k
    target->nTableSize = source->nTableSize;
2474
7.84k
    if (HT_IS_PACKED(source)) {
2475
4.00k
      HT_SET_DATA_ADDR(target, emalloc(HT_PACKED_SIZE(target)));
2476
4.00k
      target->nInternalPointer = source->nInternalPointer;
2477
4.00k
      memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_PACKED_USED_SIZE(source));
2478
4.00k
    } else {
2479
3.83k
      HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
2480
3.83k
      target->nInternalPointer = source->nInternalPointer;
2481
3.83k
      memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source));
2482
3.83k
    }
2483
8.35k
  } else if (HT_IS_PACKED(source)) {
2484
4.09k
    ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_HAS_EMPTY_IND));
2485
4.09k
    HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK;
2486
4.09k
    target->nTableMask = HT_MIN_MASK;
2487
4.09k
    target->nNumUsed = source->nNumUsed;
2488
4.09k
    target->nNumOfElements = source->nNumOfElements;
2489
4.09k
    target->nNextFreeElement = source->nNextFreeElement;
2490
4.09k
    target->nTableSize = source->nTableSize;
2491
4.09k
    HT_SET_DATA_ADDR(target, emalloc(HT_PACKED_SIZE_EX(target->nTableSize, HT_MIN_MASK)));
2492
4.09k
    target->nInternalPointer =
2493
4.09k
      (source->nInternalPointer < source->nNumUsed) ?
2494
4.09k
        source->nInternalPointer : 0;
2495
2496
4.09k
    HT_HASH_RESET_PACKED(target);
2497
2498
4.09k
    if (HT_IS_WITHOUT_HOLES(target)) {
2499
3.92k
      zend_array_dup_packed_elements(source, target, false);
2500
3.92k
    } else {
2501
166
      zend_array_dup_packed_elements(source, target, true);
2502
166
    }
2503
4.25k
  } else {
2504
    /* Indirects are removed during duplication, remove HASH_FLAG_HAS_EMPTY_IND accordingly. */
2505
4.25k
    HT_FLAGS(target) = HT_FLAGS(source) & (HASH_FLAG_MASK & ~HASH_FLAG_HAS_EMPTY_IND);
2506
4.25k
    target->nTableMask = source->nTableMask;
2507
4.25k
    target->nNextFreeElement = source->nNextFreeElement;
2508
4.25k
    target->nInternalPointer =
2509
4.25k
      (source->nInternalPointer < source->nNumUsed) ?
2510
4.25k
        source->nInternalPointer : 0;
2511
2512
4.25k
    target->nTableSize = source->nTableSize;
2513
4.25k
    HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
2514
4.25k
    HT_HASH_RESET(target);
2515
2516
4.25k
    if (HT_HAS_STATIC_KEYS_ONLY(target)) {
2517
2.89k
      if (HT_IS_WITHOUT_HOLES(source)) {
2518
2.88k
        idx = zend_array_dup_elements(source, target, true, false);
2519
2.88k
      } else {
2520
10
        idx = zend_array_dup_elements(source, target, true, true);
2521
10
      }
2522
2.89k
    } else {
2523
1.36k
      if (HT_IS_WITHOUT_HOLES(source)) {
2524
1.36k
        idx = zend_array_dup_elements(source, target, false, false);
2525
1.36k
      } else {
2526
0
        idx = zend_array_dup_elements(source, target, false, true);
2527
0
      }
2528
1.36k
    }
2529
4.25k
    target->nNumUsed = idx;
2530
4.25k
    target->nNumOfElements = idx;
2531
4.25k
  }
2532
23.4k
  return target;
2533
23.4k
}
2534
2535
ZEND_API HashTable* zend_array_to_list(const HashTable *source)
2536
0
{
2537
0
  HashTable *result = _zend_new_array(zend_hash_num_elements(source));
2538
0
  zend_hash_real_init_packed(result);
2539
2540
0
  ZEND_HASH_FILL_PACKED(result) {
2541
0
    zval *entry;
2542
2543
0
    ZEND_HASH_FOREACH_VAL(source, entry) {
2544
0
      if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) {
2545
0
        entry = Z_REFVAL_P(entry);
2546
0
      }
2547
0
      Z_TRY_ADDREF_P(entry);
2548
0
      ZEND_HASH_FILL_ADD(entry);
2549
0
    } ZEND_HASH_FOREACH_END();
2550
0
  } ZEND_HASH_FILL_END();
2551
2552
0
  return result;
2553
0
}
2554
2555
2556
ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, const HashTable *source, copy_ctor_func_t pCopyConstructor, bool overwrite)
2557
6.68k
{
2558
6.68k
  uint32_t idx;
2559
6.68k
  Bucket *p;
2560
6.68k
  zval *t, *s;
2561
2562
6.68k
  IS_CONSISTENT(source);
2563
6.68k
  IS_CONSISTENT(target);
2564
6.68k
  HT_ASSERT_RC1(target);
2565
2566
6.68k
  if (overwrite) {
2567
0
    if (HT_IS_PACKED(source)) {
2568
0
      for (idx = 0; idx < source->nNumUsed; idx++) {
2569
0
        s = source->arPacked + idx;
2570
0
        if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) {
2571
0
          continue;
2572
0
        }
2573
0
        t = zend_hash_index_update(target, idx, s);
2574
0
        if (pCopyConstructor) {
2575
0
          pCopyConstructor(t);
2576
0
        }
2577
0
      }
2578
0
      return;
2579
0
    }
2580
2581
0
    for (idx = 0; idx < source->nNumUsed; idx++) {
2582
0
      p = source->arData + idx;
2583
0
      s = &p->val;
2584
0
      if (UNEXPECTED(Z_TYPE_P(s) == IS_INDIRECT)) {
2585
0
        s = Z_INDIRECT_P(s);
2586
0
      }
2587
0
      if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) {
2588
0
        continue;
2589
0
      }
2590
0
      if (p->key) {
2591
0
        t = _zend_hash_add_or_update_i(target, p->key, s, HASH_UPDATE | HASH_UPDATE_INDIRECT);
2592
0
        if (pCopyConstructor) {
2593
0
          pCopyConstructor(t);
2594
0
        }
2595
0
      } else {
2596
0
        t = zend_hash_index_update(target, p->h, s);
2597
0
        if (pCopyConstructor) {
2598
0
          pCopyConstructor(t);
2599
0
        }
2600
0
      }
2601
0
    }
2602
6.68k
  } else {
2603
6.68k
    if (HT_IS_PACKED(source)) {
2604
10.5k
      for (idx = 0; idx < source->nNumUsed; idx++) {
2605
8.60k
        s = source->arPacked + idx;
2606
8.60k
        if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) {
2607
905
          continue;
2608
905
        }
2609
7.70k
        t = zend_hash_index_add(target, idx, s);
2610
7.70k
        if (t && pCopyConstructor) {
2611
5.20k
          pCopyConstructor(t);
2612
5.20k
        }
2613
7.70k
      }
2614
1.89k
      return;
2615
1.89k
    }
2616
2617
14.1k
    for (idx = 0; idx < source->nNumUsed; idx++) {
2618
9.38k
      p = source->arData + idx;
2619
9.38k
      s = &p->val;
2620
9.38k
      if (UNEXPECTED(Z_TYPE_P(s) == IS_INDIRECT)) {
2621
0
        s = Z_INDIRECT_P(s);
2622
0
      }
2623
9.38k
      if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) {
2624
0
        continue;
2625
0
      }
2626
9.38k
      if (p->key) {
2627
1.36k
        t = _zend_hash_add_or_update_i(target, p->key, s, HASH_ADD | HASH_UPDATE_INDIRECT);
2628
1.36k
        if (t && pCopyConstructor) {
2629
187
          pCopyConstructor(t);
2630
187
        }
2631
8.01k
      } else {
2632
8.01k
        t = zend_hash_index_add(target, p->h, s);
2633
8.01k
        if (t && pCopyConstructor) {
2634
7.40k
          pCopyConstructor(t);
2635
7.40k
        }
2636
8.01k
      }
2637
9.38k
    }
2638
4.79k
  }
2639
6.68k
}
2640
2641
2642
static bool ZEND_FASTCALL zend_hash_replace_checker_wrapper(HashTable *target, zval *source_data, zend_ulong h, zend_string *key, void *pParam, merge_checker_func_t merge_checker_func)
2643
0
{
2644
0
  zend_hash_key hash_key;
2645
2646
0
  hash_key.h = h;
2647
0
  hash_key.key = key;
2648
0
  return merge_checker_func(target, source_data, &hash_key, pParam);
2649
0
}
2650
2651
2652
ZEND_API void ZEND_FASTCALL zend_hash_merge_ex(HashTable *target, const HashTable *source, copy_ctor_func_t pCopyConstructor, merge_checker_func_t pMergeSource, void *pParam)
2653
0
{
2654
0
  uint32_t idx;
2655
0
  Bucket *p;
2656
0
  zval *t;
2657
2658
0
  IS_CONSISTENT(source);
2659
0
  IS_CONSISTENT(target);
2660
0
  HT_ASSERT_RC1(target);
2661
2662
0
  ZEND_ASSERT(!HT_IS_PACKED(source));
2663
0
  for (idx = 0; idx < source->nNumUsed; idx++) {
2664
0
    p = source->arData + idx;
2665
0
    if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2666
0
    if (zend_hash_replace_checker_wrapper(target, &p->val, p->h, p->key, pParam, pMergeSource)) {
2667
0
      t = zend_hash_update(target, p->key, &p->val);
2668
0
      if (pCopyConstructor) {
2669
0
        pCopyConstructor(t);
2670
0
      }
2671
0
    }
2672
0
  }
2673
0
}
2674
2675
2676
/* Returns the hash table data if found and NULL if not. */
2677
ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
2678
44.4M
{
2679
44.4M
  Bucket *p;
2680
2681
44.4M
  IS_CONSISTENT(ht);
2682
2683
44.4M
  (void)zend_string_hash_val(key);
2684
44.4M
  p = zend_hash_find_bucket(ht, key);
2685
44.4M
  return p ? &p->val : NULL;
2686
44.4M
}
2687
2688
ZEND_API zval* ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
2689
1.33M
{
2690
1.33M
  Bucket *p;
2691
2692
1.33M
  IS_CONSISTENT(ht);
2693
2694
1.33M
  p = zend_hash_find_bucket(ht, key);
2695
1.33M
  return p ? &p->val : NULL;
2696
1.33M
}
2697
2698
ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
2699
4.57M
{
2700
4.57M
  zend_ulong h;
2701
4.57M
  Bucket *p;
2702
2703
4.57M
  IS_CONSISTENT(ht);
2704
2705
4.57M
  h = zend_inline_hash_func(str, len);
2706
4.57M
  p = zend_hash_str_find_bucket(ht, str, len, h);
2707
4.57M
  return p ? &p->val : NULL;
2708
4.57M
}
2709
2710
ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
2711
1.02G
{
2712
1.02G
  Bucket *p;
2713
2714
1.02G
  IS_CONSISTENT(ht);
2715
2716
1.02G
  if (HT_IS_PACKED(ht)) {
2717
26.9k
    if (h < ht->nNumUsed) {
2718
23.5k
      zval *zv = ht->arPacked + h;
2719
2720
23.5k
      if (Z_TYPE_P(zv) != IS_UNDEF) {
2721
23.1k
        return zv;
2722
23.1k
      }
2723
23.5k
    }
2724
3.86k
    return NULL;
2725
26.9k
  }
2726
2727
1.02G
  p = zend_hash_index_find_bucket(ht, h);
2728
1.02G
  return p ? &p->val : NULL;
2729
1.02G
}
2730
2731
ZEND_API zval* ZEND_FASTCALL _zend_hash_index_find(const HashTable *ht, zend_ulong h)
2732
3.33k
{
2733
3.33k
  Bucket *p;
2734
2735
3.33k
  IS_CONSISTENT(ht);
2736
3.33k
  ZEND_ASSERT(!HT_IS_PACKED(ht));
2737
2738
3.33k
  p = zend_hash_index_find_bucket(ht, h);
2739
3.33k
  return p ? &p->val : NULL;
2740
3.33k
}
2741
2742
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(const HashTable *ht, HashPosition *pos)
2743
3.39k
{
2744
3.39k
  IS_CONSISTENT(ht);
2745
3.39k
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2746
3.39k
  *pos = _zend_hash_get_valid_pos(ht, 0);
2747
3.39k
}
2748
2749
2750
/* This function will be extremely optimized by remembering
2751
 * the end of the list
2752
 */
2753
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(const HashTable *ht, HashPosition *pos)
2754
37
{
2755
37
  uint32_t idx;
2756
2757
37
  IS_CONSISTENT(ht);
2758
37
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2759
2760
37
  idx = ht->nNumUsed;
2761
37
  if (HT_IS_PACKED(ht)) {
2762
21
    while (idx > 0) {
2763
21
      idx--;
2764
21
      if (Z_TYPE(ht->arPacked[idx]) != IS_UNDEF) {
2765
21
        *pos = idx;
2766
21
        return;
2767
21
      }
2768
21
    }
2769
21
  } else {
2770
16
    while (idx > 0) {
2771
16
      idx--;
2772
16
      if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
2773
16
        *pos = idx;
2774
16
        return;
2775
16
      }
2776
16
    }
2777
16
  }
2778
0
  *pos = ht->nNumUsed;
2779
0
}
2780
2781
2782
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(const HashTable *ht, HashPosition *pos)
2783
1.61k
{
2784
1.61k
  uint32_t idx;
2785
2786
1.61k
  IS_CONSISTENT(ht);
2787
1.61k
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2788
2789
1.61k
  idx = _zend_hash_get_valid_pos(ht, *pos);
2790
1.61k
  if (idx < ht->nNumUsed) {
2791
1.61k
    if (HT_IS_PACKED(ht)) {
2792
581
      while (1) {
2793
581
        idx++;
2794
581
        if (idx >= ht->nNumUsed) {
2795
160
          *pos = ht->nNumUsed;
2796
160
          return SUCCESS;
2797
160
        }
2798
421
        if (Z_TYPE(ht->arPacked[idx]) != IS_UNDEF) {
2799
418
          *pos = idx;
2800
418
          return SUCCESS;
2801
418
        }
2802
421
      }
2803
1.04k
    } else {
2804
1.04k
      while (1) {
2805
1.04k
        idx++;
2806
1.04k
        if (idx >= ht->nNumUsed) {
2807
494
          *pos = ht->nNumUsed;
2808
494
          return SUCCESS;
2809
494
        }
2810
552
        if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
2811
547
          *pos = idx;
2812
547
          return SUCCESS;
2813
547
        }
2814
552
      }
2815
1.04k
    }
2816
1.61k
  } else {
2817
0
    return FAILURE;
2818
0
  }
2819
1.61k
}
2820
2821
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_backwards_ex(const HashTable *ht, HashPosition *pos)
2822
22
{
2823
22
  uint32_t idx = *pos;
2824
2825
22
  IS_CONSISTENT(ht);
2826
22
  HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);
2827
2828
22
  if (idx < ht->nNumUsed) {
2829
22
    if (HT_IS_PACKED(ht)) {
2830
6
      while (idx > 0) {
2831
6
        idx--;
2832
6
        if (Z_TYPE(ht->arPacked[idx]) != IS_UNDEF) {
2833
6
          *pos = idx;
2834
6
          return SUCCESS;
2835
6
        }
2836
6
      }
2837
16
    } else {
2838
16
      while (idx > 0) {
2839
5
        idx--;
2840
5
        if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
2841
5
          *pos = idx;
2842
5
          return SUCCESS;
2843
5
        }
2844
5
      }
2845
16
    }
2846
11
    *pos = ht->nNumUsed;
2847
11
    return SUCCESS;
2848
22
  } else {
2849
0
    return FAILURE;
2850
0
  }
2851
22
}
2852
2853
2854
/* This function should be made binary safe  */
2855
ZEND_API zend_hash_key_type ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos)
2856
867
{
2857
867
  uint32_t idx;
2858
867
  Bucket *p;
2859
2860
867
  IS_CONSISTENT(ht);
2861
867
  idx = _zend_hash_get_valid_pos(ht, *pos);
2862
867
  if (idx < ht->nNumUsed) {
2863
578
    if (HT_IS_PACKED(ht)) {
2864
0
      *num_index = idx;
2865
0
      return HASH_KEY_IS_LONG;
2866
0
    }
2867
578
    p = ht->arData + idx;
2868
578
    if (p->key) {
2869
490
      *str_index = p->key;
2870
490
      return HASH_KEY_IS_STRING;
2871
490
    } else {
2872
88
      *num_index = p->h;
2873
88
      return HASH_KEY_IS_LONG;
2874
88
    }
2875
578
  }
2876
289
  return HASH_KEY_NON_EXISTENT;
2877
867
}
2878
2879
ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, const HashPosition *pos)
2880
542
{
2881
542
  uint32_t idx;
2882
542
  Bucket *p;
2883
2884
542
  IS_CONSISTENT(ht);
2885
542
  idx = _zend_hash_get_valid_pos(ht, *pos);
2886
542
  if (idx >= ht->nNumUsed) {
2887
0
    ZVAL_NULL(key);
2888
542
  } else {
2889
542
    if (HT_IS_PACKED(ht)) {
2890
275
      ZVAL_LONG(key, idx);
2891
275
      return;
2892
275
    }
2893
267
    p = ht->arData + idx;
2894
267
    if (p->key) {
2895
193
      ZVAL_STR_COPY(key, p->key);
2896
193
    } else {
2897
74
      ZVAL_LONG(key, p->h);
2898
74
    }
2899
267
  }
2900
542
}
2901
2902
ZEND_API zend_hash_key_type ZEND_FASTCALL zend_hash_get_current_key_type_ex(const HashTable *ht, const HashPosition *pos)
2903
1.46k
{
2904
1.46k
  uint32_t idx;
2905
1.46k
  Bucket *p;
2906
2907
1.46k
  IS_CONSISTENT(ht);
2908
1.46k
  idx = _zend_hash_get_valid_pos(ht, *pos);
2909
1.46k
  if (idx < ht->nNumUsed) {
2910
949
    if (HT_IS_PACKED(ht)) {
2911
265
      return HASH_KEY_IS_LONG;
2912
265
    }
2913
684
    p = ht->arData + idx;
2914
684
    if (p->key) {
2915
559
      return HASH_KEY_IS_STRING;
2916
559
    } else {
2917
125
      return HASH_KEY_IS_LONG;
2918
125
    }
2919
684
  }
2920
520
  return HASH_KEY_NON_EXISTENT;
2921
1.46k
}
2922
2923
2924
ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(const HashTable *ht, const HashPosition *pos)
2925
2.72k
{
2926
2.72k
  uint32_t idx;
2927
2.72k
  Bucket *p;
2928
2929
2.72k
  IS_CONSISTENT(ht);
2930
2.72k
  idx = _zend_hash_get_valid_pos(ht, *pos);
2931
2.72k
  if (idx < ht->nNumUsed) {
2932
2.54k
    if (HT_IS_PACKED(ht)) {
2933
471
      return &ht->arPacked[idx];
2934
471
    }
2935
2.07k
    p = ht->arData + idx;
2936
2.07k
    return &p->val;
2937
2.54k
  } else {
2938
179
    return NULL;
2939
179
  }
2940
2.72k
}
2941
2942
ZEND_API void zend_hash_bucket_swap(Bucket *p, Bucket *q)
2943
8.02k
{
2944
8.02k
  zval val;
2945
8.02k
  zend_ulong h;
2946
8.02k
  zend_string *key;
2947
2948
8.02k
  val = p->val;
2949
8.02k
  h = p->h;
2950
8.02k
  key = p->key;
2951
2952
8.02k
  p->val = q->val;
2953
8.02k
  p->h = q->h;
2954
8.02k
  p->key = q->key;
2955
2956
8.02k
  q->val = val;
2957
8.02k
  q->h = h;
2958
8.02k
  q->key = key;
2959
8.02k
}
2960
2961
ZEND_API void zend_hash_bucket_renum_swap(Bucket *p, Bucket *q)
2962
80.2k
{
2963
80.2k
  zval val;
2964
2965
80.2k
  val = p->val;
2966
80.2k
  p->val = q->val;
2967
80.2k
  q->val = val;
2968
80.2k
}
2969
2970
ZEND_API void zend_hash_bucket_packed_swap(Bucket *p, Bucket *q)
2971
0
{
2972
0
  zval val;
2973
0
  zend_ulong h;
2974
2975
0
  val = p->val;
2976
0
  h = p->h;
2977
2978
0
  p->val = q->val;
2979
0
  p->h = q->h;
2980
2981
0
  q->val = val;
2982
0
  q->h = h;
2983
0
}
2984
2985
static void zend_hash_sort_internal(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
2986
732
{
2987
732
  Bucket *p;
2988
732
  uint32_t i, j;
2989
2990
732
  IS_CONSISTENT(ht);
2991
2992
732
  if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) {
2993
    /* Doesn't require sorting */
2994
12
    return;
2995
12
  }
2996
2997
720
  if (HT_IS_PACKED(ht)) {
2998
3
    zend_hash_packed_to_hash(ht); // TODO: ???
2999
3
  }
3000
3001
720
  if (HT_IS_WITHOUT_HOLES(ht)) {
3002
    /* Store original order of elements in extra space to allow stable sorting. */
3003
30.9k
    for (i = 0; i < ht->nNumUsed; i++) {
3004
30.2k
      Z_EXTRA(ht->arData[i].val) = i;
3005
30.2k
    }
3006
720
  } else {
3007
    /* Remove holes and store original order. */
3008
0
    for (j = 0, i = 0; j < ht->nNumUsed; j++) {
3009
0
      p = ht->arData + j;
3010
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
3011
0
      if (i != j) {
3012
0
        ht->arData[i] = *p;
3013
0
      }
3014
0
      Z_EXTRA(ht->arData[i].val) = i;
3015
0
      i++;
3016
0
    }
3017
0
    ht->nNumUsed = i;
3018
0
  }
3019
3020
720
  if (!HT_IS_PACKED(ht)) {
3021
    /* We broke the hash collisions chains overriding Z_NEXT() by Z_EXTRA().
3022
     * Reset the hash headers table as well to avoid possible inconsistent
3023
     * access on recursive data structures.
3024
       *
3025
       * See Zend/tests/bug63882_2.phpt
3026
     */
3027
720
    HT_HASH_RESET(ht);
3028
720
  }
3029
3030
720
  sort((void *)ht->arData, ht->nNumUsed, sizeof(Bucket), (compare_func_t) compar,
3031
720
      (swap_func_t)(renumber? zend_hash_bucket_renum_swap :
3032
720
        (HT_IS_PACKED(ht) ? zend_hash_bucket_packed_swap : zend_hash_bucket_swap)));
3033
3034
720
  ht->nInternalPointer = 0;
3035
3036
720
  if (renumber) {
3037
27.1k
    for (j = 0; j < i; j++) {
3038
26.5k
      p = ht->arData + j;
3039
26.5k
      p->h = j;
3040
26.5k
      if (p->key) {
3041
380
        zend_string_release(p->key);
3042
380
        p->key = NULL;
3043
380
      }
3044
26.5k
    }
3045
3046
559
    ht->nNextFreeElement = i;
3047
559
  }
3048
720
  if (HT_IS_PACKED(ht)) {
3049
0
    if (!renumber) {
3050
0
      zend_hash_packed_to_hash(ht);
3051
0
    }
3052
720
  } else {
3053
720
    if (renumber) {
3054
559
      void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
3055
559
      Bucket *old_buckets = ht->arData;
3056
559
      zval *zv;
3057
3058
559
      new_data = pemalloc(HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), (GC_FLAGS(ht) & IS_ARRAY_PERSISTENT));
3059
559
      HT_FLAGS(ht) |= HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
3060
559
      ht->nTableMask = HT_MIN_MASK;
3061
559
      HT_SET_DATA_ADDR(ht, new_data);
3062
559
      p = old_buckets;
3063
559
      zv = ht->arPacked;
3064
38.7k
      for (i = 0; i < ht->nTableSize; i++) {
3065
38.2k
        ZVAL_COPY_VALUE(zv, &p->val);
3066
38.2k
        zv++;
3067
38.2k
        p++;
3068
38.2k
      }
3069
559
      pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
3070
559
      HT_HASH_RESET_PACKED(ht);
3071
559
    } else {
3072
161
      zend_hash_rehash(ht);
3073
161
    }
3074
720
  }
3075
720
}
3076
3077
ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
3078
37
{
3079
37
  HT_ASSERT_RC1(ht);
3080
37
  zend_hash_sort_internal(ht, sort, compar, renumber);
3081
37
}
3082
3083
ZEND_API void ZEND_FASTCALL zend_array_sort_ex(HashTable *ht, sort_func_t sort, bucket_compare_func_t compar, bool renumber)
3084
695
{
3085
695
  HT_ASSERT_RC1(ht);
3086
3087
  /* Unpack the array early to avoid RCn assertion failures. */
3088
695
  if (HT_IS_PACKED(ht)) {
3089
520
    zend_hash_packed_to_hash(ht);
3090
520
  }
3091
3092
  /* Adding a refcount prevents the array from going away. */
3093
695
  GC_ADDREF(ht);
3094
3095
695
  zend_hash_sort_internal(ht, sort, compar, renumber);
3096
3097
695
  if (UNEXPECTED(GC_DELREF(ht) == 0)) {
3098
5
    zend_array_destroy(ht);
3099
690
  } else {
3100
690
    gc_check_possible_root((zend_refcounted *)ht);
3101
690
  }
3102
695
}
3103
3104
5.52k
static zend_always_inline int zend_hash_compare_impl(const HashTable *ht1, const HashTable *ht2, compare_func_t compar, bool ordered) {
3105
5.52k
  uint32_t idx1, idx2;
3106
5.52k
  zend_string *key1, *key2;
3107
5.52k
  zend_ulong h1, h2;
3108
5.52k
  zval *pData1, *pData2;;
3109
5.52k
  int result;
3110
3111
5.52k
  if (ht1->nNumOfElements != ht2->nNumOfElements) {
3112
2.04k
    return ht1->nNumOfElements > ht2->nNumOfElements ? 1 : -1;
3113
2.04k
  }
3114
3115
4.78k
  for (idx1 = 0, idx2 = 0; idx1 < ht1->nNumUsed; idx1++) {
3116
3.34k
    if (HT_IS_PACKED(ht1)) {
3117
1.86k
      pData1 = ht1->arPacked + idx1;
3118
1.86k
      h1 = idx1;
3119
1.86k
      key1 = NULL;
3120
1.86k
    } else {
3121
1.48k
      Bucket *p = ht1->arData + idx1;
3122
1.48k
      pData1 = &p->val;
3123
1.48k
      h1 = p->h;
3124
1.48k
      key1 = p->key;
3125
1.48k
    }
3126
3127
3.34k
    if (Z_TYPE_P(pData1) == IS_UNDEF) continue;
3128
2.52k
    if (ordered) {
3129
1.81k
      if (HT_IS_PACKED(ht2)) {
3130
1.35k
        while (1) {
3131
1.35k
          ZEND_ASSERT(idx2 != ht2->nNumUsed);
3132
1.35k
          pData2 = ht2->arPacked + idx2;
3133
1.35k
          h2 = idx2;
3134
1.35k
          key2 = NULL;
3135
1.35k
          if (Z_TYPE_P(pData2) != IS_UNDEF) break;
3136
876
          idx2++;
3137
876
        }
3138
1.33k
      } else {
3139
1.33k
        while (1) {
3140
1.33k
          Bucket *p;
3141
1.33k
          ZEND_ASSERT(idx2 != ht2->nNumUsed);
3142
1.33k
          p = ht2->arData + idx2;
3143
1.33k
          pData2 = &p->val;
3144
1.33k
          h2 = p->h;
3145
1.33k
          key2 = p->key;
3146
1.33k
          if (Z_TYPE_P(pData2) != IS_UNDEF) break;
3147
0
          idx2++;
3148
0
        }
3149
1.33k
      }
3150
1.81k
      if (key1 == NULL && key2 == NULL) { /* numeric indices */
3151
638
        if (h1 != h2) {
3152
238
          return h1 > h2 ? 1 : -1;
3153
238
        }
3154
1.17k
      } else if (key1 != NULL && key2 != NULL) { /* string indices */
3155
969
        if (ZSTR_LEN(key1) != ZSTR_LEN(key2)) {
3156
231
          return ZSTR_LEN(key1) > ZSTR_LEN(key2) ? 1 : -1;
3157
231
        }
3158
3159
738
        result = memcmp(ZSTR_VAL(key1), ZSTR_VAL(key2), ZSTR_LEN(key1));
3160
738
        if (result != 0) {
3161
448
          return result;
3162
448
        }
3163
738
      } else {
3164
        /* Mixed key types: A string key is considered as larger */
3165
204
        return key1 != NULL ? 1 : -1;
3166
204
      }
3167
690
      idx2++;
3168
716
    } else {
3169
716
      if (key1 == NULL) { /* numeric index */
3170
506
        pData2 = zend_hash_index_find(ht2, h1);
3171
506
        if (pData2 == NULL) {
3172
265
          return 1;
3173
265
        }
3174
506
      } else { /* string index */
3175
210
        pData2 = zend_hash_find(ht2, key1);
3176
210
        if (pData2 == NULL) {
3177
112
          return 1;
3178
112
        }
3179
210
      }
3180
716
    }
3181
3182
1.02k
    if (Z_TYPE_P(pData1) == IS_INDIRECT) {
3183
44
      pData1 = Z_INDIRECT_P(pData1);
3184
44
    }
3185
1.02k
    if (Z_TYPE_P(pData2) == IS_INDIRECT) {
3186
44
      pData2 = Z_INDIRECT_P(pData2);
3187
44
    }
3188
3189
1.02k
    if (Z_TYPE_P(pData1) == IS_UNDEF) {
3190
17
      if (Z_TYPE_P(pData2) != IS_UNDEF) {
3191
0
        return -1;
3192
0
      }
3193
1.01k
    } else if (Z_TYPE_P(pData2) == IS_UNDEF) {
3194
0
      return 1;
3195
1.01k
    } else {
3196
1.01k
      result = compar(pData1, pData2);
3197
1.01k
      if (result != 0) {
3198
543
        return result;
3199
543
      }
3200
1.01k
    }
3201
1.02k
  }
3202
3203
1.43k
  return 0;
3204
3.47k
}
3205
3206
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered)
3207
5.53k
{
3208
5.53k
  int result;
3209
5.53k
  IS_CONSISTENT(ht1);
3210
5.53k
  IS_CONSISTENT(ht2);
3211
3212
5.53k
  if (ht1 == ht2) {
3213
0
    return 0;
3214
0
  }
3215
3216
  /* It's enough to protect only one of the arrays.
3217
   * The second one may be referenced from the first and this may cause
3218
   * false recursion detection.
3219
   */
3220
5.53k
  if (UNEXPECTED(GC_IS_RECURSIVE(ht1))) {
3221
15
    zend_throw_error(NULL, "Nesting level too deep - recursive dependency?");
3222
15
    return ZEND_UNCOMPARABLE;
3223
15
  }
3224
3225
5.52k
  GC_TRY_PROTECT_RECURSION(ht1);
3226
5.52k
  result = zend_hash_compare_impl(ht1, ht2, compar, ordered);
3227
5.52k
  GC_TRY_UNPROTECT_RECURSION(ht1);
3228
3229
5.52k
  return result;
3230
5.53k
}
3231
3232
3233
ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag)
3234
0
{
3235
0
  uint32_t idx;
3236
0
  zval *res;
3237
3238
0
  IS_CONSISTENT(ht);
3239
3240
0
  if (ht->nNumOfElements == 0 ) {
3241
0
    return NULL;
3242
0
  }
3243
3244
0
  if (HT_IS_PACKED(ht)) {
3245
0
    zval *zv;
3246
3247
0
    idx = 0;
3248
0
    while (1) {
3249
0
      if (idx == ht->nNumUsed) {
3250
0
        return NULL;
3251
0
      }
3252
0
      if (Z_TYPE(ht->arPacked[idx]) != IS_UNDEF) break;
3253
0
      idx++;
3254
0
    }
3255
0
    res = ht->arPacked + idx;
3256
0
    for (; idx < ht->nNumUsed; idx++) {
3257
0
      zv = ht->arPacked + idx;
3258
0
      if (UNEXPECTED(Z_TYPE_P(zv) == IS_UNDEF)) continue;
3259
3260
0
      if (flag) {
3261
0
        if (compar(res, zv) < 0) { /* max */
3262
0
          res = zv;
3263
0
        }
3264
0
      } else {
3265
0
        if (compar(res, zv) > 0) { /* min */
3266
0
          res = zv;
3267
0
        }
3268
0
      }
3269
0
    }
3270
0
  } else {
3271
0
    Bucket *p;
3272
3273
0
    idx = 0;
3274
0
    while (1) {
3275
0
      if (idx == ht->nNumUsed) {
3276
0
        return NULL;
3277
0
      }
3278
0
      if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break;
3279
0
      idx++;
3280
0
    }
3281
0
    res = &ht->arData[idx].val;
3282
0
    for (; idx < ht->nNumUsed; idx++) {
3283
0
      p = ht->arData + idx;
3284
0
      if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
3285
3286
0
      if (flag) {
3287
0
        if (compar(res, &p->val) < 0) { /* max */
3288
0
          res = &p->val;
3289
0
        }
3290
0
      } else {
3291
0
        if (compar(res, &p->val) > 0) { /* min */
3292
0
          res = &p->val;
3293
0
        }
3294
0
      }
3295
0
    }
3296
0
  }
3297
0
  return res;
3298
0
}
3299
3300
ZEND_API bool ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx)
3301
151k
{
3302
151k
  const char *tmp = key;
3303
3304
151k
  const char *end = key + length;
3305
3306
151k
  if (*tmp == '-') {
3307
5.47k
    tmp++;
3308
5.47k
  }
3309
3310
151k
  if ((*tmp == '0' && length > 1) /* numbers with leading zeros */
3311
146k
   || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */
3312
0
   || (SIZEOF_ZEND_LONG == 4 &&
3313
0
       end - tmp == MAX_LENGTH_OF_LONG - 1 &&
3314
10.0k
       *tmp > '2')) { /* overflow */
3315
10.0k
    return 0;
3316
10.0k
  }
3317
141k
  *idx = (*tmp - '0');
3318
235k
  while (1) {
3319
235k
    ++tmp;
3320
235k
    if (tmp == end) {
3321
118k
      if (*key == '-') {
3322
2.20k
        if (*idx-1 > ZEND_LONG_MAX) { /* overflow */
3323
506
          return 0;
3324
506
        }
3325
1.69k
        *idx = 0 - *idx;
3326
116k
      } else if (*idx > ZEND_LONG_MAX) { /* overflow */
3327
506
        return 0;
3328
506
      }
3329
117k
      return 1;
3330
118k
    }
3331
116k
    if (*tmp <= '9' && *tmp >= '0') {
3332
93.4k
      *idx = (*idx * 10) + (*tmp - '0');
3333
93.4k
    } else {
3334
22.9k
      return 0;
3335
22.9k
    }
3336
116k
  }
3337
141k
}
3338
3339
/* Takes a "symtable" hashtable (contains integer and non-numeric string keys)
3340
 * and converts it to a "proptable" (contains only string keys).
3341
 * If the symtable didn't need duplicating, its refcount is incremented.
3342
 */
3343
ZEND_API HashTable* ZEND_FASTCALL zend_symtable_to_proptable(HashTable *ht)
3344
282
{
3345
282
  zend_ulong num_key;
3346
282
  zend_string *str_key;
3347
282
  zval *zv;
3348
3349
282
  if (UNEXPECTED(HT_IS_PACKED(ht))) {
3350
34
    goto convert;
3351
34
  }
3352
3353
1.25k
  ZEND_HASH_MAP_FOREACH_STR_KEY(ht, str_key) {
3354
1.25k
    if (!str_key) {
3355
7
      goto convert;
3356
7
    }
3357
1.25k
  } ZEND_HASH_FOREACH_END();
3358
3359
241
  if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
3360
53
    GC_ADDREF(ht);
3361
53
  }
3362
3363
241
  return ht;
3364
3365
41
convert:
3366
41
  {
3367
41
    HashTable *new_ht = zend_new_array(zend_hash_num_elements(ht));
3368
3369
271
    ZEND_HASH_FOREACH_KEY_VAL(ht, num_key, str_key, zv) {
3370
271
      if (!str_key) {
3371
107
        str_key = zend_long_to_str(num_key);
3372
107
        zend_string_delref(str_key);
3373
107
      }
3374
271
      do {
3375
114
        if (Z_OPT_REFCOUNTED_P(zv)) {
3376
2
          if (Z_ISREF_P(zv) && Z_REFCOUNT_P(zv) == 1) {
3377
0
            zv = Z_REFVAL_P(zv);
3378
0
            if (!Z_OPT_REFCOUNTED_P(zv)) {
3379
0
              break;
3380
0
            }
3381
0
          }
3382
2
          Z_ADDREF_P(zv);
3383
2
        }
3384
114
      } while (0);
3385
271
      zend_hash_update(new_ht, str_key, zv);
3386
271
    } ZEND_HASH_FOREACH_END();
3387
3388
41
    return new_ht;
3389
248
  }
3390
248
}
3391
3392
/* Takes a "proptable" hashtable (contains only string keys) and converts it to
3393
 * a "symtable" (contains integer and non-numeric string keys).
3394
 * If the proptable didn't need duplicating, its refcount is incremented.
3395
 */
3396
ZEND_API HashTable* ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate)
3397
1.62k
{
3398
1.62k
  zend_ulong num_key;
3399
1.62k
  zend_string *str_key;
3400
1.62k
  zval *zv;
3401
3402
1.62k
  if (!HT_IS_PACKED(ht)) {
3403
35.1k
    ZEND_HASH_MAP_FOREACH_STR_KEY(ht, str_key) {
3404
      /* The `str_key &&` here might seem redundant: property tables should
3405
       * only have string keys. Unfortunately, this isn't true, at the very
3406
       * least because of ArrayObject, which stores a symtable where the
3407
       * property table should be.
3408
       */
3409
35.1k
      if (str_key && ZEND_HANDLE_NUMERIC(str_key, num_key)) {
3410
102
        goto convert;
3411
102
      }
3412
35.1k
    } ZEND_HASH_FOREACH_END();
3413
1.62k
  }
3414
3415
1.52k
  if (always_duplicate) {
3416
1.51k
    return zend_array_dup(ht);
3417
1.51k
  }
3418
3419
7
  if (EXPECTED(!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE))) {
3420
7
    GC_ADDREF(ht);
3421
7
  }
3422
3423
7
  return ht;
3424
3425
102
convert:
3426
102
  {
3427
102
    HashTable *new_ht = zend_new_array(zend_hash_num_elements(ht));
3428
3429
2.70k
    ZEND_HASH_MAP_FOREACH_KEY_VAL_IND(ht, num_key, str_key, zv) {
3430
2.70k
      do {
3431
1.19k
        if (Z_OPT_REFCOUNTED_P(zv)) {
3432
641
          if (Z_ISREF_P(zv) && Z_REFCOUNT_P(zv) == 1) {
3433
23
            zv = Z_REFVAL_P(zv);
3434
23
            if (!Z_OPT_REFCOUNTED_P(zv)) {
3435
0
              break;
3436
0
            }
3437
23
          }
3438
641
          Z_ADDREF_P(zv);
3439
641
        }
3440
1.19k
      } while (0);
3441
      /* Again, thank ArrayObject for `!str_key ||`. */
3442
2.70k
      if (!str_key || ZEND_HANDLE_NUMERIC(str_key, num_key)) {
3443
179
        zend_hash_index_update(new_ht, num_key, zv);
3444
1.01k
      } else {
3445
1.01k
        zend_hash_update(new_ht, str_key, zv);
3446
1.01k
      }
3447
2.70k
    } ZEND_HASH_FOREACH_END();
3448
3449
102
    return new_ht;
3450
102
  }
3451
102
}