Coverage Report

Created: 2022-02-19 20:31

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