xref: /PHP-8.3/Zend/zend_hash.h (revision 2ef1930a)
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 #ifndef ZEND_HASH_H
22 #define ZEND_HASH_H
23 
24 #include "zend.h"
25 #include "zend_sort.h"
26 
27 #define HASH_KEY_IS_STRING 1
28 #define HASH_KEY_IS_LONG 2
29 #define HASH_KEY_NON_EXISTENT 3
30 
31 #define HASH_UPDATE 			(1<<0)
32 #define HASH_ADD				(1<<1)
33 #define HASH_UPDATE_INDIRECT	(1<<2)
34 #define HASH_ADD_NEW			(1<<3)
35 #define HASH_ADD_NEXT			(1<<4)
36 #define HASH_LOOKUP				(1<<5)
37 
38 #define HASH_FLAG_CONSISTENCY      ((1<<0) | (1<<1))
39 #define HASH_FLAG_PACKED           (1<<2)
40 #define HASH_FLAG_UNINITIALIZED    (1<<3)
41 #define HASH_FLAG_STATIC_KEYS      (1<<4) /* long and interned strings */
42 #define HASH_FLAG_HAS_EMPTY_IND    (1<<5)
43 #define HASH_FLAG_ALLOW_COW_VIOLATION (1<<6)
44 
45 /* Only the low byte are real flags */
46 #define HASH_FLAG_MASK 0xff
47 
48 #define HT_FLAGS(ht) (ht)->u.flags
49 
50 #define HT_INVALIDATE(ht) do { \
51 		HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED; \
52 	} while (0)
53 
54 #define HT_IS_INITIALIZED(ht) \
55 	((HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) == 0)
56 
57 #define HT_IS_PACKED(ht) \
58 	((HT_FLAGS(ht) & HASH_FLAG_PACKED) != 0)
59 
60 #define HT_IS_WITHOUT_HOLES(ht) \
61 	((ht)->nNumUsed == (ht)->nNumOfElements)
62 
63 #define HT_HAS_STATIC_KEYS_ONLY(ht) \
64 	((HT_FLAGS(ht) & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) != 0)
65 
66 #if ZEND_DEBUG
67 # define HT_ALLOW_COW_VIOLATION(ht) HT_FLAGS(ht) |= HASH_FLAG_ALLOW_COW_VIOLATION
68 #else
69 # define HT_ALLOW_COW_VIOLATION(ht)
70 #endif
71 
72 #define HT_ITERATORS_COUNT(ht) (ht)->u.v.nIteratorsCount
73 #define HT_ITERATORS_OVERFLOW(ht) (HT_ITERATORS_COUNT(ht) == 0xff)
74 #define HT_HAS_ITERATORS(ht) (HT_ITERATORS_COUNT(ht) != 0)
75 
76 #define HT_SET_ITERATORS_COUNT(ht, iters) \
77 	do { HT_ITERATORS_COUNT(ht) = (iters); } while (0)
78 #define HT_INC_ITERATORS_COUNT(ht) \
79 	HT_SET_ITERATORS_COUNT(ht, HT_ITERATORS_COUNT(ht) + 1)
80 #define HT_DEC_ITERATORS_COUNT(ht) \
81 	HT_SET_ITERATORS_COUNT(ht, HT_ITERATORS_COUNT(ht) - 1)
82 
83 extern ZEND_API const HashTable zend_empty_array;
84 
85 #define ZVAL_EMPTY_ARRAY(z) do {						\
86 		zval *__z = (z);								\
87 		Z_ARR_P(__z) = (zend_array*)&zend_empty_array;	\
88 		Z_TYPE_INFO_P(__z) = IS_ARRAY; \
89 	} while (0)
90 
91 
92 typedef struct _zend_hash_key {
93 	zend_ulong h;
94 	zend_string *key;
95 } zend_hash_key;
96 
97 typedef bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
98 
99 BEGIN_EXTERN_C()
100 
101 /* startup/shutdown */
102 ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent);
103 ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht);
104 ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht);
105 
106 #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) \
107 	_zend_hash_init((ht), (nSize), (pDestructor), (persistent))
108 
109 ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed);
110 ZEND_API void ZEND_FASTCALL zend_hash_real_init_packed(HashTable *ht);
111 ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht);
112 ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht);
113 ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht);
114 ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed);
115 ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed);
116 ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht);
117 
118 /* additions/updates/changes */
119 ZEND_API zval* ZEND_FASTCALL zend_hash_add_or_update(HashTable *ht, zend_string *key, zval *pData, uint32_t flag);
120 ZEND_API zval* ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key,zval *pData);
121 ZEND_API zval* ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key,zval *pData);
122 ZEND_API zval* ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key,zval *pData);
123 ZEND_API zval* ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key,zval *pData);
124 
125 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_or_update(HashTable *ht, const char *key, size_t len, zval *pData, uint32_t flag);
126 ZEND_API zval* ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData);
127 ZEND_API zval* ZEND_FASTCALL zend_hash_str_update_ind(HashTable *ht, const char *key, size_t len, zval *pData);
128 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add(HashTable *ht, const char *key, size_t len, zval *pData);
129 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *key, size_t len, zval *pData);
130 
131 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_or_update(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag);
132 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData);
133 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData);
134 ZEND_API zval* ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData);
135 ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData);
136 ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData);
137 
138 ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h);
139 ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key);
140 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *key, size_t len);
141 
142 ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *p, zend_string *key);
143 
144 #define ZEND_HASH_APPLY_KEEP				0
145 #define ZEND_HASH_APPLY_REMOVE				1<<0
146 #define ZEND_HASH_APPLY_STOP				1<<1
147 
148 typedef int (*apply_func_t)(zval *pDest);
149 typedef int (*apply_func_arg_t)(zval *pDest, void *argument);
150 typedef int (*apply_func_args_t)(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key);
151 
152 ZEND_API void ZEND_FASTCALL zend_hash_graceful_destroy(HashTable *ht);
153 ZEND_API void ZEND_FASTCALL zend_hash_graceful_reverse_destroy(HashTable *ht);
154 ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_func);
155 ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *);
156 ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, apply_func_args_t apply_func, int, ...);
157 
158 /* This function should be used with special care (in other words,
159  * it should usually not be used).  When used with the ZEND_HASH_APPLY_STOP
160  * return value, it assumes things about the order of the elements in the hash.
161  * Also, it does not provide the same kind of reentrancy protection that
162  * the standard apply functions do.
163  */
164 ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func);
165 
166 
167 /* Deletes */
168 ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key);
169 ZEND_API zend_result ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key);
170 ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *key, size_t len);
171 ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *key, size_t len);
172 ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h);
173 ZEND_API void ZEND_FASTCALL zend_hash_del_bucket(HashTable *ht, Bucket *p);
174 ZEND_API void ZEND_FASTCALL zend_hash_packed_del_val(HashTable *ht, zval *zv);
175 
176 /* Data retrieval */
177 ZEND_API zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key);
178 ZEND_API zval* ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *key, size_t len);
179 ZEND_API zval* ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h);
180 ZEND_API zval* ZEND_FASTCALL _zend_hash_index_find(const HashTable *ht, zend_ulong h);
181 
182 /* The same as zend_hash_find(), but hash value of the key must be already calculated. */
183 ZEND_API zval* ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key);
184 
zend_hash_find_ex(const HashTable * ht,zend_string * key,bool known_hash)185 static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_string *key, bool known_hash)
186 {
187 	if (known_hash) {
188 		return zend_hash_find_known_hash(ht, key);
189 	} else {
190 		return zend_hash_find(ht, key);
191 	}
192 }
193 
194 #define ZEND_HASH_INDEX_FIND(_ht, _h, _ret, _not_found) do { \
195 		if (EXPECTED(HT_IS_PACKED(_ht))) { \
196 			if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
197 				_ret = &_ht->arPacked[_h]; \
198 				if (UNEXPECTED(Z_TYPE_P(_ret) == IS_UNDEF)) { \
199 					goto _not_found; \
200 				} \
201 			} else { \
202 				goto _not_found; \
203 			} \
204 		} else { \
205 			_ret = _zend_hash_index_find(_ht, _h); \
206 			if (UNEXPECTED(_ret == NULL)) { \
207 				goto _not_found; \
208 			} \
209 		} \
210 	} while (0)
211 
212 
213 /* Find or add NULL, if doesn't exist */
214 ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key);
215 ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h);
216 
217 #define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \
218 		if (EXPECTED(HT_IS_PACKED(_ht))) { \
219 			if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
220 				_ret = &_ht->arPacked[_h]; \
221 				if (EXPECTED(Z_TYPE_P(_ret) != IS_UNDEF)) { \
222 					break; \
223 				} \
224 			} \
225 		} \
226 		_ret = zend_hash_index_lookup(_ht, _h); \
227 	} while (0)
228 
229 /* Misc */
zend_hash_exists(const HashTable * ht,zend_string * key)230 static zend_always_inline bool zend_hash_exists(const HashTable *ht, zend_string *key)
231 {
232 	return zend_hash_find(ht, key) != NULL;
233 }
234 
zend_hash_str_exists(const HashTable * ht,const char * str,size_t len)235 static zend_always_inline bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
236 {
237 	return zend_hash_str_find(ht, str, len) != NULL;
238 }
239 
zend_hash_index_exists(const HashTable * ht,zend_ulong h)240 static zend_always_inline bool zend_hash_index_exists(const HashTable *ht, zend_ulong h)
241 {
242 	return zend_hash_index_find(ht, h) != NULL;
243 }
244 
245 /* traversing */
246 ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht);
247 
248 ZEND_API zend_result   ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos);
249 ZEND_API zend_result   ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos);
250 ZEND_API int   ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos);
251 ZEND_API void  ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, const HashPosition *pos);
252 ZEND_API int   ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos);
253 ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos);
254 ZEND_API void  ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
255 ZEND_API void  ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
256 
zend_hash_has_more_elements_ex(HashTable * ht,HashPosition * pos)257 static zend_always_inline zend_result zend_hash_has_more_elements_ex(HashTable *ht, HashPosition *pos) {
258 	return (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS);
259 }
zend_hash_has_more_elements(HashTable * ht)260 static zend_always_inline zend_result zend_hash_has_more_elements(HashTable *ht) {
261 	return zend_hash_has_more_elements_ex(ht, &ht->nInternalPointer);
262 }
zend_hash_move_forward(HashTable * ht)263 static zend_always_inline zend_result zend_hash_move_forward(HashTable *ht) {
264 	return zend_hash_move_forward_ex(ht, &ht->nInternalPointer);
265 }
zend_hash_move_backwards(HashTable * ht)266 static zend_always_inline zend_result zend_hash_move_backwards(HashTable *ht) {
267 	return zend_hash_move_backwards_ex(ht, &ht->nInternalPointer);
268 }
zend_hash_get_current_key(const HashTable * ht,zend_string ** str_index,zend_ulong * num_index)269 static zend_always_inline int zend_hash_get_current_key(const HashTable *ht, zend_string **str_index, zend_ulong *num_index) {
270 	return zend_hash_get_current_key_ex(ht, str_index, num_index, &ht->nInternalPointer);
271 }
zend_hash_get_current_key_zval(const HashTable * ht,zval * key)272 static zend_always_inline void zend_hash_get_current_key_zval(const HashTable *ht, zval *key) {
273 	zend_hash_get_current_key_zval_ex(ht, key, &ht->nInternalPointer);
274 }
zend_hash_get_current_key_type(HashTable * ht)275 static zend_always_inline int zend_hash_get_current_key_type(HashTable *ht) {
276 	return zend_hash_get_current_key_type_ex(ht, &ht->nInternalPointer);
277 }
zend_hash_get_current_data(HashTable * ht)278 static zend_always_inline zval* zend_hash_get_current_data(HashTable *ht) {
279 	return zend_hash_get_current_data_ex(ht, &ht->nInternalPointer);
280 }
zend_hash_internal_pointer_reset(HashTable * ht)281 static zend_always_inline void zend_hash_internal_pointer_reset(HashTable *ht) {
282 	zend_hash_internal_pointer_reset_ex(ht, &ht->nInternalPointer);
283 }
zend_hash_internal_pointer_end(HashTable * ht)284 static zend_always_inline void zend_hash_internal_pointer_end(HashTable *ht) {
285 	zend_hash_internal_pointer_end_ex(ht, &ht->nInternalPointer);
286 }
287 
288 /* Copying, merging and sorting */
289 ZEND_API void  ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor);
290 ZEND_API void  ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, bool overwrite);
291 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);
292 ZEND_API void  zend_hash_bucket_swap(Bucket *p, Bucket *q);
293 ZEND_API void  zend_hash_bucket_renum_swap(Bucket *p, Bucket *q);
294 ZEND_API void  zend_hash_bucket_packed_swap(Bucket *p, Bucket *q);
295 
296 typedef int (*bucket_compare_func_t)(Bucket *a, Bucket *b);
297 ZEND_API int   zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered);
298 ZEND_API void  ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber);
299 ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag);
300 
zend_hash_sort(HashTable * ht,bucket_compare_func_t compare_func,bool renumber)301 static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) {
302 	zend_hash_sort_ex(ht, zend_sort, compare_func, renumber);
303 }
304 
zend_hash_num_elements(const HashTable * ht)305 static zend_always_inline uint32_t zend_hash_num_elements(const HashTable *ht) {
306 	return ht->nNumOfElements;
307 }
308 
zend_hash_next_free_element(const HashTable * ht)309 static zend_always_inline zend_long zend_hash_next_free_element(const HashTable *ht) {
310 	return ht->nNextFreeElement;
311 }
312 
313 ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht);
314 
315 #if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P)
316 # define zend_new_array(size) \
317 	(__builtin_constant_p(size) ? \
318 		((((uint32_t)(size)) <= HT_MIN_SIZE) ? \
319 			_zend_new_array_0() \
320 		: \
321 			_zend_new_array((size)) \
322 		) \
323 	: \
324 		_zend_new_array((size)) \
325 	)
326 #else
327 # define zend_new_array(size) \
328 	_zend_new_array(size)
329 #endif
330 
331 ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void);
332 ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size);
333 ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2);
334 ZEND_API uint32_t zend_array_count(HashTable *ht);
335 ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source);
336 ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht);
337 ZEND_API HashTable* zend_array_to_list(HashTable *source);
338 ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht);
339 ZEND_API HashTable* ZEND_FASTCALL zend_symtable_to_proptable(HashTable *ht);
340 ZEND_API HashTable* ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate);
341 
342 ZEND_API bool ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
343 
344 ZEND_API uint32_t     ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos);
345 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
346 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array);
347 ZEND_API void         ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx);
348 ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start);
349 ZEND_API void         ZEND_FASTCALL _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to);
350 ZEND_API void         ZEND_FASTCALL zend_hash_iterators_advance(HashTable *ht, HashPosition step);
351 
zend_hash_iterators_update(HashTable * ht,HashPosition from,HashPosition to)352 static zend_always_inline void zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
353 {
354 	if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
355 		_zend_hash_iterators_update(ht, from, to);
356 	}
357 }
358 
359 /* For regular arrays (non-persistent, storing zvals). */
zend_array_release(zend_array * array)360 static zend_always_inline void zend_array_release(zend_array *array)
361 {
362 	if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) {
363 		if (GC_DELREF(array) == 0) {
364 			zend_array_destroy(array);
365 		}
366 	}
367 }
368 
369 /* For general hashes (possibly persistent, storing any kind of value). */
zend_hash_release(zend_array * array)370 static zend_always_inline void zend_hash_release(zend_array *array)
371 {
372 	if (!(GC_FLAGS(array) & IS_ARRAY_IMMUTABLE)) {
373 		if (GC_DELREF(array) == 0) {
374 			zend_hash_destroy(array);
375 			pefree(array, GC_FLAGS(array) & IS_ARRAY_PERSISTENT);
376 		}
377 	}
378 }
379 
END_EXTERN_C()380 END_EXTERN_C()
381 
382 #define ZEND_INIT_SYMTABLE(ht)								\
383 	ZEND_INIT_SYMTABLE_EX(ht, 8, 0)
384 
385 #define ZEND_INIT_SYMTABLE_EX(ht, n, persistent)			\
386 	zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent)
387 
388 static zend_always_inline bool _zend_handle_numeric_str(const char *key, size_t length, zend_ulong *idx)
389 {
390 	const char *tmp = key;
391 
392 	if (EXPECTED(*tmp > '9')) {
393 		return 0;
394 	} else if (*tmp < '0') {
395 		if (*tmp != '-') {
396 			return 0;
397 		}
398 		tmp++;
399 		if (*tmp > '9' || *tmp < '0') {
400 			return 0;
401 		}
402 	}
403 	return _zend_handle_numeric_str_ex(key, length, idx);
404 }
405 
406 #define ZEND_HANDLE_NUMERIC_STR(key, length, idx) \
407 	_zend_handle_numeric_str(key, length, &idx)
408 
409 #define ZEND_HANDLE_NUMERIC(key, idx) \
410 	ZEND_HANDLE_NUMERIC_STR(ZSTR_VAL(key), ZSTR_LEN(key), idx)
411 
412 
zend_hash_find_ind(const HashTable * ht,zend_string * key)413 static zend_always_inline zval *zend_hash_find_ind(const HashTable *ht, zend_string *key)
414 {
415 	zval *zv;
416 
417 	zv = zend_hash_find(ht, key);
418 	return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
419 		((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
420 }
421 
422 
zend_hash_find_ex_ind(const HashTable * ht,zend_string * key,bool known_hash)423 static zend_always_inline zval *zend_hash_find_ex_ind(const HashTable *ht, zend_string *key, bool known_hash)
424 {
425 	zval *zv;
426 
427 	zv = zend_hash_find_ex(ht, key, known_hash);
428 	return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
429 		((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
430 }
431 
432 
zend_hash_exists_ind(const HashTable * ht,zend_string * key)433 static zend_always_inline bool zend_hash_exists_ind(const HashTable *ht, zend_string *key)
434 {
435 	zval *zv;
436 
437 	zv = zend_hash_find(ht, key);
438 	return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
439 			Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
440 }
441 
442 
zend_hash_str_find_ind(const HashTable * ht,const char * str,size_t len)443 static zend_always_inline zval *zend_hash_str_find_ind(const HashTable *ht, const char *str, size_t len)
444 {
445 	zval *zv;
446 
447 	zv = zend_hash_str_find(ht, str, len);
448 	return (zv && Z_TYPE_P(zv) == IS_INDIRECT) ?
449 		((Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF) ? Z_INDIRECT_P(zv) : NULL) : zv;
450 }
451 
452 
zend_hash_str_exists_ind(const HashTable * ht,const char * str,size_t len)453 static zend_always_inline bool zend_hash_str_exists_ind(const HashTable *ht, const char *str, size_t len)
454 {
455 	zval *zv;
456 
457 	zv = zend_hash_str_find(ht, str, len);
458 	return zv && (Z_TYPE_P(zv) != IS_INDIRECT ||
459 			Z_TYPE_P(Z_INDIRECT_P(zv)) != IS_UNDEF);
460 }
461 
zend_symtable_add_new(HashTable * ht,zend_string * key,zval * pData)462 static zend_always_inline zval *zend_symtable_add_new(HashTable *ht, zend_string *key, zval *pData)
463 {
464 	zend_ulong idx;
465 
466 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
467 		return zend_hash_index_add_new(ht, idx, pData);
468 	} else {
469 		return zend_hash_add_new(ht, key, pData);
470 	}
471 }
472 
zend_symtable_update(HashTable * ht,zend_string * key,zval * pData)473 static zend_always_inline zval *zend_symtable_update(HashTable *ht, zend_string *key, zval *pData)
474 {
475 	zend_ulong idx;
476 
477 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
478 		return zend_hash_index_update(ht, idx, pData);
479 	} else {
480 		return zend_hash_update(ht, key, pData);
481 	}
482 }
483 
484 
zend_symtable_update_ind(HashTable * ht,zend_string * key,zval * pData)485 static zend_always_inline zval *zend_symtable_update_ind(HashTable *ht, zend_string *key, zval *pData)
486 {
487 	zend_ulong idx;
488 
489 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
490 		return zend_hash_index_update(ht, idx, pData);
491 	} else {
492 		return zend_hash_update_ind(ht, key, pData);
493 	}
494 }
495 
496 
zend_symtable_del(HashTable * ht,zend_string * key)497 static zend_always_inline zend_result zend_symtable_del(HashTable *ht, zend_string *key)
498 {
499 	zend_ulong idx;
500 
501 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
502 		return zend_hash_index_del(ht, idx);
503 	} else {
504 		return zend_hash_del(ht, key);
505 	}
506 }
507 
508 
zend_symtable_del_ind(HashTable * ht,zend_string * key)509 static zend_always_inline zend_result zend_symtable_del_ind(HashTable *ht, zend_string *key)
510 {
511 	zend_ulong idx;
512 
513 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
514 		return zend_hash_index_del(ht, idx);
515 	} else {
516 		return zend_hash_del_ind(ht, key);
517 	}
518 }
519 
520 
zend_symtable_find(const HashTable * ht,zend_string * key)521 static zend_always_inline zval *zend_symtable_find(const HashTable *ht, zend_string *key)
522 {
523 	zend_ulong idx;
524 
525 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
526 		return zend_hash_index_find(ht, idx);
527 	} else {
528 		return zend_hash_find(ht, key);
529 	}
530 }
531 
532 
zend_symtable_find_ind(const HashTable * ht,zend_string * key)533 static zend_always_inline zval *zend_symtable_find_ind(const HashTable *ht, zend_string *key)
534 {
535 	zend_ulong idx;
536 
537 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
538 		return zend_hash_index_find(ht, idx);
539 	} else {
540 		return zend_hash_find_ind(ht, key);
541 	}
542 }
543 
544 
zend_symtable_exists(HashTable * ht,zend_string * key)545 static zend_always_inline bool zend_symtable_exists(HashTable *ht, zend_string *key)
546 {
547 	zend_ulong idx;
548 
549 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
550 		return zend_hash_index_exists(ht, idx);
551 	} else {
552 		return zend_hash_exists(ht, key);
553 	}
554 }
555 
556 
zend_symtable_exists_ind(HashTable * ht,zend_string * key)557 static zend_always_inline bool zend_symtable_exists_ind(HashTable *ht, zend_string *key)
558 {
559 	zend_ulong idx;
560 
561 	if (ZEND_HANDLE_NUMERIC(key, idx)) {
562 		return zend_hash_index_exists(ht, idx);
563 	} else {
564 		return zend_hash_exists_ind(ht, key);
565 	}
566 }
567 
568 
zend_symtable_str_update(HashTable * ht,const char * str,size_t len,zval * pData)569 static zend_always_inline zval *zend_symtable_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
570 {
571 	zend_ulong idx;
572 
573 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
574 		return zend_hash_index_update(ht, idx, pData);
575 	} else {
576 		return zend_hash_str_update(ht, str, len, pData);
577 	}
578 }
579 
580 
zend_symtable_str_update_ind(HashTable * ht,const char * str,size_t len,zval * pData)581 static zend_always_inline zval *zend_symtable_str_update_ind(HashTable *ht, const char *str, size_t len, zval *pData)
582 {
583 	zend_ulong idx;
584 
585 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
586 		return zend_hash_index_update(ht, idx, pData);
587 	} else {
588 		return zend_hash_str_update_ind(ht, str, len, pData);
589 	}
590 }
591 
592 
zend_symtable_str_del(HashTable * ht,const char * str,size_t len)593 static zend_always_inline zend_result zend_symtable_str_del(HashTable *ht, const char *str, size_t len)
594 {
595 	zend_ulong idx;
596 
597 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
598 		return zend_hash_index_del(ht, idx);
599 	} else {
600 		return zend_hash_str_del(ht, str, len);
601 	}
602 }
603 
604 
zend_symtable_str_del_ind(HashTable * ht,const char * str,size_t len)605 static zend_always_inline zend_result zend_symtable_str_del_ind(HashTable *ht, const char *str, size_t len)
606 {
607 	zend_ulong idx;
608 
609 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
610 		return zend_hash_index_del(ht, idx);
611 	} else {
612 		return zend_hash_str_del_ind(ht, str, len);
613 	}
614 }
615 
616 
zend_symtable_str_find(HashTable * ht,const char * str,size_t len)617 static zend_always_inline zval *zend_symtable_str_find(HashTable *ht, const char *str, size_t len)
618 {
619 	zend_ulong idx;
620 
621 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
622 		return zend_hash_index_find(ht, idx);
623 	} else {
624 		return zend_hash_str_find(ht, str, len);
625 	}
626 }
627 
628 
zend_symtable_str_exists(HashTable * ht,const char * str,size_t len)629 static zend_always_inline bool zend_symtable_str_exists(HashTable *ht, const char *str, size_t len)
630 {
631 	zend_ulong idx;
632 
633 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
634 		return zend_hash_index_exists(ht, idx);
635 	} else {
636 		return zend_hash_str_exists(ht, str, len);
637 	}
638 }
639 
zend_hash_add_ptr(HashTable * ht,zend_string * key,void * pData)640 static zend_always_inline void *zend_hash_add_ptr(HashTable *ht, zend_string *key, void *pData)
641 {
642 	zval tmp, *zv;
643 
644 	ZVAL_PTR(&tmp, pData);
645 	zv = zend_hash_add(ht, key, &tmp);
646 	if (zv) {
647 		ZEND_ASSUME(Z_PTR_P(zv));
648 		return Z_PTR_P(zv);
649 	} else {
650 		return NULL;
651 	}
652 }
653 
zend_hash_add_new_ptr(HashTable * ht,zend_string * key,void * pData)654 static zend_always_inline void *zend_hash_add_new_ptr(HashTable *ht, zend_string *key, void *pData)
655 {
656 	zval tmp, *zv;
657 
658 	ZVAL_PTR(&tmp, pData);
659 	zv = zend_hash_add_new(ht, key, &tmp);
660 	if (zv) {
661 		ZEND_ASSUME(Z_PTR_P(zv));
662 		return Z_PTR_P(zv);
663 	} else {
664 		return NULL;
665 	}
666 }
667 
zend_hash_str_add_ptr(HashTable * ht,const char * str,size_t len,void * pData)668 static zend_always_inline void *zend_hash_str_add_ptr(HashTable *ht, const char *str, size_t len, void *pData)
669 {
670 	zval tmp, *zv;
671 
672 	ZVAL_PTR(&tmp, pData);
673 	zv = zend_hash_str_add(ht, str, len, &tmp);
674 	if (zv) {
675 		ZEND_ASSUME(Z_PTR_P(zv));
676 		return Z_PTR_P(zv);
677 	} else {
678 		return NULL;
679 	}
680 }
681 
zend_hash_str_add_new_ptr(HashTable * ht,const char * str,size_t len,void * pData)682 static zend_always_inline void *zend_hash_str_add_new_ptr(HashTable *ht, const char *str, size_t len, void *pData)
683 {
684 	zval tmp, *zv;
685 
686 	ZVAL_PTR(&tmp, pData);
687 	zv = zend_hash_str_add_new(ht, str, len, &tmp);
688 	if (zv) {
689 		ZEND_ASSUME(Z_PTR_P(zv));
690 		return Z_PTR_P(zv);
691 	} else {
692 		return NULL;
693 	}
694 }
695 
zend_hash_update_ptr(HashTable * ht,zend_string * key,void * pData)696 static zend_always_inline void *zend_hash_update_ptr(HashTable *ht, zend_string *key, void *pData)
697 {
698 	zval tmp, *zv;
699 
700 	ZVAL_PTR(&tmp, pData);
701 	zv = zend_hash_update(ht, key, &tmp);
702 	ZEND_ASSUME(Z_PTR_P(zv));
703 	return Z_PTR_P(zv);
704 }
705 
zend_hash_str_update_ptr(HashTable * ht,const char * str,size_t len,void * pData)706 static zend_always_inline void *zend_hash_str_update_ptr(HashTable *ht, const char *str, size_t len, void *pData)
707 {
708 	zval tmp, *zv;
709 
710 	ZVAL_PTR(&tmp, pData);
711 	zv = zend_hash_str_update(ht, str, len, &tmp);
712 	ZEND_ASSUME(Z_PTR_P(zv));
713 	return Z_PTR_P(zv);
714 }
715 
zend_hash_add_mem(HashTable * ht,zend_string * key,void * pData,size_t size)716 static zend_always_inline void *zend_hash_add_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
717 {
718 	zval tmp, *zv;
719 
720 	ZVAL_PTR(&tmp, NULL);
721 	if ((zv = zend_hash_add(ht, key, &tmp))) {
722 		Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
723 		memcpy(Z_PTR_P(zv), pData, size);
724 		return Z_PTR_P(zv);
725 	}
726 	return NULL;
727 }
728 
zend_hash_add_new_mem(HashTable * ht,zend_string * key,void * pData,size_t size)729 static zend_always_inline void *zend_hash_add_new_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
730 {
731 	zval tmp, *zv;
732 
733 	ZVAL_PTR(&tmp, NULL);
734 	if ((zv = zend_hash_add_new(ht, key, &tmp))) {
735 		Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
736 		memcpy(Z_PTR_P(zv), pData, size);
737 		return Z_PTR_P(zv);
738 	}
739 	return NULL;
740 }
741 
zend_hash_str_add_mem(HashTable * ht,const char * str,size_t len,void * pData,size_t size)742 static zend_always_inline void *zend_hash_str_add_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
743 {
744 	zval tmp, *zv;
745 
746 	ZVAL_PTR(&tmp, NULL);
747 	if ((zv = zend_hash_str_add(ht, str, len, &tmp))) {
748 		Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
749 		memcpy(Z_PTR_P(zv), pData, size);
750 		return Z_PTR_P(zv);
751 	}
752 	return NULL;
753 }
754 
zend_hash_str_add_new_mem(HashTable * ht,const char * str,size_t len,void * pData,size_t size)755 static zend_always_inline void *zend_hash_str_add_new_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
756 {
757 	zval tmp, *zv;
758 
759 	ZVAL_PTR(&tmp, NULL);
760 	if ((zv = zend_hash_str_add_new(ht, str, len, &tmp))) {
761 		Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
762 		memcpy(Z_PTR_P(zv), pData, size);
763 		return Z_PTR_P(zv);
764 	}
765 	return NULL;
766 }
767 
zend_hash_update_mem(HashTable * ht,zend_string * key,void * pData,size_t size)768 static zend_always_inline void *zend_hash_update_mem(HashTable *ht, zend_string *key, void *pData, size_t size)
769 {
770 	void *p;
771 
772 	p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
773 	memcpy(p, pData, size);
774 	return zend_hash_update_ptr(ht, key, p);
775 }
776 
zend_hash_str_update_mem(HashTable * ht,const char * str,size_t len,void * pData,size_t size)777 static zend_always_inline void *zend_hash_str_update_mem(HashTable *ht, const char *str, size_t len, void *pData, size_t size)
778 {
779 	void *p;
780 
781 	p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
782 	memcpy(p, pData, size);
783 	return zend_hash_str_update_ptr(ht, str, len, p);
784 }
785 
zend_hash_index_add_ptr(HashTable * ht,zend_ulong h,void * pData)786 static zend_always_inline void *zend_hash_index_add_ptr(HashTable *ht, zend_ulong h, void *pData)
787 {
788 	zval tmp, *zv;
789 
790 	ZVAL_PTR(&tmp, pData);
791 	zv = zend_hash_index_add(ht, h, &tmp);
792 	return zv ? Z_PTR_P(zv) : NULL;
793 }
794 
zend_hash_index_add_new_ptr(HashTable * ht,zend_ulong h,void * pData)795 static zend_always_inline void *zend_hash_index_add_new_ptr(HashTable *ht, zend_ulong h, void *pData)
796 {
797 	zval tmp, *zv;
798 
799 	ZVAL_PTR(&tmp, pData);
800 	zv = zend_hash_index_add_new(ht, h, &tmp);
801 	return zv ? Z_PTR_P(zv) : NULL;
802 }
803 
zend_hash_index_update_ptr(HashTable * ht,zend_ulong h,void * pData)804 static zend_always_inline void *zend_hash_index_update_ptr(HashTable *ht, zend_ulong h, void *pData)
805 {
806 	zval tmp, *zv;
807 
808 	ZVAL_PTR(&tmp, pData);
809 	zv = zend_hash_index_update(ht, h, &tmp);
810 	ZEND_ASSUME(Z_PTR_P(zv));
811 	return Z_PTR_P(zv);
812 }
813 
zend_hash_index_add_mem(HashTable * ht,zend_ulong h,void * pData,size_t size)814 static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
815 {
816 	zval tmp, *zv;
817 
818 	ZVAL_PTR(&tmp, NULL);
819 	if ((zv = zend_hash_index_add(ht, h, &tmp))) {
820 		Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
821 		memcpy(Z_PTR_P(zv), pData, size);
822 		return Z_PTR_P(zv);
823 	}
824 	return NULL;
825 }
826 
zend_hash_next_index_insert_ptr(HashTable * ht,void * pData)827 static zend_always_inline void *zend_hash_next_index_insert_ptr(HashTable *ht, void *pData)
828 {
829 	zval tmp, *zv;
830 
831 	ZVAL_PTR(&tmp, pData);
832 	zv = zend_hash_next_index_insert(ht, &tmp);
833 	if (zv) {
834 		ZEND_ASSUME(Z_PTR_P(zv));
835 		return Z_PTR_P(zv);
836 	} else {
837 		return NULL;
838 	}
839 }
840 
zend_hash_index_update_mem(HashTable * ht,zend_ulong h,void * pData,size_t size)841 static zend_always_inline void *zend_hash_index_update_mem(HashTable *ht, zend_ulong h, void *pData, size_t size)
842 {
843 	void *p;
844 
845 	p = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
846 	memcpy(p, pData, size);
847 	return zend_hash_index_update_ptr(ht, h, p);
848 }
849 
zend_hash_next_index_insert_mem(HashTable * ht,void * pData,size_t size)850 static zend_always_inline void *zend_hash_next_index_insert_mem(HashTable *ht, void *pData, size_t size)
851 {
852 	zval tmp, *zv;
853 
854 	ZVAL_PTR(&tmp, NULL);
855 	if ((zv = zend_hash_next_index_insert(ht, &tmp))) {
856 		Z_PTR_P(zv) = pemalloc(size, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
857 		memcpy(Z_PTR_P(zv), pData, size);
858 		return Z_PTR_P(zv);
859 	}
860 	return NULL;
861 }
862 
zend_hash_find_ptr(const HashTable * ht,zend_string * key)863 static zend_always_inline void *zend_hash_find_ptr(const HashTable *ht, zend_string *key)
864 {
865 	zval *zv;
866 
867 	zv = zend_hash_find(ht, key);
868 	if (zv) {
869 		ZEND_ASSUME(Z_PTR_P(zv));
870 		return Z_PTR_P(zv);
871 	} else {
872 		return NULL;
873 	}
874 }
875 
zend_hash_find_ex_ptr(const HashTable * ht,zend_string * key,bool known_hash)876 static zend_always_inline void *zend_hash_find_ex_ptr(const HashTable *ht, zend_string *key, bool known_hash)
877 {
878 	zval *zv;
879 
880 	zv = zend_hash_find_ex(ht, key, known_hash);
881 	if (zv) {
882 		ZEND_ASSUME(Z_PTR_P(zv));
883 		return Z_PTR_P(zv);
884 	} else {
885 		return NULL;
886 	}
887 }
888 
zend_hash_str_find_ptr(const HashTable * ht,const char * str,size_t len)889 static zend_always_inline void *zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len)
890 {
891 	zval *zv;
892 
893 	zv = zend_hash_str_find(ht, str, len);
894 	if (zv) {
895 		ZEND_ASSUME(Z_PTR_P(zv));
896 		return Z_PTR_P(zv);
897 	} else {
898 		return NULL;
899 	}
900 }
901 
902 /* Will lowercase the str; use only if you don't need the lowercased string for
903  * anything else. If you have a lowered string, use zend_hash_str_find_ptr. */
904 ZEND_API void *zend_hash_str_find_ptr_lc(const HashTable *ht, const char *str, size_t len);
905 
906 /* Will lowercase the str; use only if you don't need the lowercased string for
907  * anything else. If you have a lowered string, use zend_hash_find_ptr. */
908 ZEND_API void *zend_hash_find_ptr_lc(const HashTable *ht, zend_string *key);
909 
zend_hash_index_find_ptr(const HashTable * ht,zend_ulong h)910 static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht, zend_ulong h)
911 {
912 	zval *zv;
913 
914 	zv = zend_hash_index_find(ht, h);
915 	if (zv) {
916 		ZEND_ASSUME(Z_PTR_P(zv));
917 		return Z_PTR_P(zv);
918 	} else {
919 		return NULL;
920 	}
921 }
922 
zend_hash_index_find_deref(HashTable * ht,zend_ulong h)923 static zend_always_inline zval *zend_hash_index_find_deref(HashTable *ht, zend_ulong h)
924 {
925 	zval *zv = zend_hash_index_find(ht, h);
926 	if (zv) {
927 		ZVAL_DEREF(zv);
928 	}
929 	return zv;
930 }
931 
zend_hash_find_deref(HashTable * ht,zend_string * str)932 static zend_always_inline zval *zend_hash_find_deref(HashTable *ht, zend_string *str)
933 {
934 	zval *zv = zend_hash_find(ht, str);
935 	if (zv) {
936 		ZVAL_DEREF(zv);
937 	}
938 	return zv;
939 }
940 
zend_hash_str_find_deref(HashTable * ht,const char * str,size_t len)941 static zend_always_inline zval *zend_hash_str_find_deref(HashTable *ht, const char *str, size_t len)
942 {
943 	zval *zv = zend_hash_str_find(ht, str, len);
944 	if (zv) {
945 		ZVAL_DEREF(zv);
946 	}
947 	return zv;
948 }
949 
zend_symtable_str_find_ptr(HashTable * ht,const char * str,size_t len)950 static zend_always_inline void *zend_symtable_str_find_ptr(HashTable *ht, const char *str, size_t len)
951 {
952 	zend_ulong idx;
953 
954 	if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
955 		return zend_hash_index_find_ptr(ht, idx);
956 	} else {
957 		return zend_hash_str_find_ptr(ht, str, len);
958 	}
959 }
960 
zend_hash_get_current_data_ptr_ex(HashTable * ht,HashPosition * pos)961 static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPosition *pos)
962 {
963 	zval *zv;
964 
965 	zv = zend_hash_get_current_data_ex(ht, pos);
966 	if (zv) {
967 		ZEND_ASSUME(Z_PTR_P(zv));
968 		return Z_PTR_P(zv);
969 	} else {
970 		return NULL;
971 	}
972 }
973 
974 #define zend_hash_get_current_data_ptr(ht) \
975 	zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
976 
977 /* Common hash/packed array iterators */
978 #if 0
979 # define ZEND_HASH_ELEMENT_SIZE(__ht) \
980 	(HT_IS_PACKED(__ht) ? sizeof(zval) : sizeof(Bucket))
981 #else /* optimized version */
982 # define ZEND_HASH_ELEMENT_SIZE(__ht) \
983 	(sizeof(zval) + (~HT_FLAGS(__ht) & HASH_FLAG_PACKED) * ((sizeof(Bucket)-sizeof(zval))/HASH_FLAG_PACKED))
984 #endif
985 
986 #define ZEND_HASH_ELEMENT_EX(__ht, _idx, _size) \
987 	((zval*)(((char*)(__ht)->arPacked) + ((_idx) * (_size))))
988 
989 #define ZEND_HASH_ELEMENT(__ht, _idx) \
990 	ZEND_HASH_ELEMENT_EX(__ht, _idx, ZEND_HASH_ELEMENT_SIZE(__ht))
991 
992 #define ZEND_HASH_NEXT_ELEMENT(_el, _size) \
993 	((zval*)(((char*)(_el)) + (_size)))
994 
995 #define ZEND_HASH_PREV_ELEMENT(_el, _size) \
996 	((zval*)(((char*)(_el)) - (_size)))
997 
998 #define _ZEND_HASH_FOREACH_VAL(_ht) do { \
999 		HashTable *__ht = (_ht); \
1000 		uint32_t _count = __ht->nNumUsed; \
1001 		size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1002 		zval *_z = __ht->arPacked; \
1003 		for (; _count > 0; _z = ZEND_HASH_NEXT_ELEMENT(_z, _size), _count--) { \
1004 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1005 
1006 #define _ZEND_HASH_REVERSE_FOREACH_VAL(_ht) do { \
1007 		HashTable *__ht = (_ht); \
1008 		uint32_t _idx = __ht->nNumUsed; \
1009 		size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1010 		zval *_z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
1011 		for (;_idx > 0; _idx--) { \
1012 			_z = ZEND_HASH_PREV_ELEMENT(_z, _size); \
1013 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1014 
1015 #define ZEND_HASH_FOREACH_FROM(_ht, indirect, _from) do { \
1016 		HashTable *__ht = (_ht); \
1017 		zend_ulong __h; \
1018 		zend_string *__key = NULL; \
1019 		uint32_t _idx = (_from); \
1020 		size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1021 		zval *__z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
1022 		uint32_t _count = __ht->nNumUsed - _idx; \
1023 		for (;_count > 0; _count--) { \
1024 			zval *_z = __z; \
1025 			if (HT_IS_PACKED(__ht)) { \
1026 				__z++; \
1027 				__h = _idx; \
1028 				_idx++; \
1029 			} else { \
1030 				Bucket *_p = (Bucket*)__z; \
1031 				__z = &(_p + 1)->val; \
1032 				__h = _p->h; \
1033 				__key = _p->key; \
1034 				if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1035 					_z = Z_INDIRECT_P(_z); \
1036 				} \
1037 			} \
1038 			(void) __h; (void) __key; (void) _idx; \
1039 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1040 
1041 #define ZEND_HASH_FOREACH(_ht, indirect) ZEND_HASH_FOREACH_FROM(_ht, indirect, 0)
1042 
1043 #define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
1044 		HashTable *__ht = (_ht); \
1045 		uint32_t _idx = __ht->nNumUsed; \
1046 		zval *_z; \
1047 		zend_ulong __h; \
1048 		zend_string *__key = NULL; \
1049 		size_t _size = ZEND_HASH_ELEMENT_SIZE(__ht); \
1050 		zval *__z = ZEND_HASH_ELEMENT_EX(__ht, _idx, _size); \
1051 		for (;_idx > 0; _idx--) { \
1052 			if (HT_IS_PACKED(__ht)) { \
1053 				__z--; \
1054 				_z = __z; \
1055 				__h = _idx - 1; \
1056 			} else { \
1057 				Bucket *_p = (Bucket*)__z; \
1058 				_p--; \
1059 				__z = &_p->val; \
1060 				_z = __z; \
1061 				__h = _p->h; \
1062 				__key = _p->key; \
1063 				if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1064 					_z = Z_INDIRECT_P(_z); \
1065 				} \
1066 			} \
1067 			(void) __h; (void) __key; (void) __z; \
1068 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1069 
1070 #define ZEND_HASH_FOREACH_END() \
1071 		} \
1072 	} while (0)
1073 
1074 #define ZEND_HASH_FOREACH_END_DEL() \
1075 	ZEND_HASH_MAP_FOREACH_END_DEL()
1076 
1077 #define ZEND_HASH_FOREACH_BUCKET(ht, _bucket) \
1078 	ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket)
1079 
1080 #define ZEND_HASH_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
1081 	ZEND_HASH_MAP_FOREACH_BUCKET_FROM(ht, _bucket, _from)
1082 
1083 #define ZEND_HASH_REVERSE_FOREACH_BUCKET(ht, _bucket) \
1084 	ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(ht, _bucket)
1085 
1086 #define ZEND_HASH_FOREACH_VAL(ht, _val) \
1087 	_ZEND_HASH_FOREACH_VAL(ht); \
1088 	_val = _z;
1089 
1090 #define ZEND_HASH_REVERSE_FOREACH_VAL(ht, _val) \
1091 	_ZEND_HASH_REVERSE_FOREACH_VAL(ht); \
1092 	_val = _z;
1093 
1094 #define ZEND_HASH_FOREACH_VAL_IND(ht, _val) \
1095 	ZEND_HASH_FOREACH(ht, 1); \
1096 	_val = _z;
1097 
1098 #define ZEND_HASH_REVERSE_FOREACH_VAL_IND(ht, _val) \
1099 	ZEND_HASH_REVERSE_FOREACH(ht, 1); \
1100 	_val = _z;
1101 
1102 #define ZEND_HASH_FOREACH_PTR(ht, _ptr) \
1103 	_ZEND_HASH_FOREACH_VAL(ht); \
1104 	_ptr = Z_PTR_P(_z);
1105 
1106 #define ZEND_HASH_FOREACH_PTR_FROM(ht, _ptr, _from) \
1107 	ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
1108 	_ptr = Z_PTR_P(_z);
1109 
1110 #define ZEND_HASH_REVERSE_FOREACH_PTR(ht, _ptr) \
1111 	_ZEND_HASH_REVERSE_FOREACH_VAL(ht); \
1112 	_ptr = Z_PTR_P(_z);
1113 
1114 #define ZEND_HASH_FOREACH_NUM_KEY(ht, _h) \
1115 	ZEND_HASH_FOREACH(ht, 0); \
1116 	_h = __h;
1117 
1118 #define ZEND_HASH_REVERSE_FOREACH_NUM_KEY(ht, _h) \
1119 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1120 	_h = __h;
1121 
1122 #define ZEND_HASH_FOREACH_STR_KEY(ht, _key) \
1123 	ZEND_HASH_FOREACH(ht, 0); \
1124 	_key = __key;
1125 
1126 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY(ht, _key) \
1127 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1128 	_key = __key;
1129 
1130 #define ZEND_HASH_FOREACH_KEY(ht, _h, _key) \
1131 	ZEND_HASH_FOREACH(ht, 0); \
1132 	_h = __h; \
1133 	_key = __key;
1134 
1135 #define ZEND_HASH_REVERSE_FOREACH_KEY(ht, _h, _key) \
1136 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1137 	_h = __h; \
1138 	_key = __key;
1139 
1140 #define ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1141 	ZEND_HASH_FOREACH(ht, 0); \
1142 	_h = __h; \
1143 	_val = _z;
1144 
1145 #define ZEND_HASH_REVERSE_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1146 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1147 	_h = __h; \
1148 	_val = _z;
1149 
1150 #define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1151 	ZEND_HASH_FOREACH(ht, 0); \
1152 	_key = __key; \
1153 	_val = _z;
1154 
1155 #define ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
1156 	ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
1157 	_key = __key; \
1158 	_val = _z;
1159 
1160 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1161 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1162 	_key = __key; \
1163 	_val = _z;
1164 
1165 #define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1166 	ZEND_HASH_FOREACH(ht, 0); \
1167 	_h = __h; \
1168 	_key = __key; \
1169 	_val = _z;
1170 
1171 #define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1172 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1173 	_h = __h; \
1174 	_key = __key; \
1175 	_val = _z;
1176 
1177 #define ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1178 	ZEND_HASH_FOREACH(ht, 1); \
1179 	_key = __key; \
1180 	_val = _z;
1181 
1182 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1183 	ZEND_HASH_REVERSE_FOREACH(ht, 1); \
1184 	_key = __key; \
1185 	_val = _z;
1186 
1187 #define ZEND_HASH_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1188 	ZEND_HASH_FOREACH(ht, 1); \
1189 	_h = __h; \
1190 	_key = __key; \
1191 	_val = _z;
1192 
1193 #define ZEND_HASH_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1194 	ZEND_HASH_REVERSE_FOREACH(ht, 1); \
1195 	_h = __h; \
1196 	_key = __key; \
1197 	_val = _z;
1198 
1199 #define ZEND_HASH_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1200 	ZEND_HASH_FOREACH(ht, 0); \
1201 	_h = __h; \
1202 	_ptr = Z_PTR_P(_z);
1203 
1204 #define ZEND_HASH_REVERSE_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1205 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1206 	_h = __h; \
1207 	_ptr = Z_PTR_P(_z);
1208 
1209 #define ZEND_HASH_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1210 	ZEND_HASH_FOREACH(ht, 0); \
1211 	_key = __key; \
1212 	_ptr = Z_PTR_P(_z);
1213 
1214 #define ZEND_HASH_REVERSE_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1215 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1216 	_key = __key; \
1217 	_ptr = Z_PTR_P(_z);
1218 
1219 #define ZEND_HASH_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1220 	ZEND_HASH_FOREACH(ht, 0); \
1221 	_h = __h; \
1222 	_key = __key; \
1223 	_ptr = Z_PTR_P(_z);
1224 
1225 #define ZEND_HASH_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1226 	ZEND_HASH_REVERSE_FOREACH(ht, 0); \
1227 	_h = __h; \
1228 	_key = __key; \
1229 	_ptr = Z_PTR_P(_z);
1230 
1231 /* Hash array iterators */
1232 #define ZEND_HASH_MAP_FOREACH_FROM(_ht, indirect, _from) do { \
1233 		HashTable *__ht = (_ht); \
1234 		Bucket *_p = __ht->arData + (_from); \
1235 		Bucket *_end = __ht->arData + __ht->nNumUsed; \
1236 		ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
1237 		for (; _p != _end; _p++) { \
1238 			zval *_z = &_p->val; \
1239 			if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1240 				_z = Z_INDIRECT_P(_z); \
1241 			} \
1242 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1243 
1244 #define ZEND_HASH_MAP_FOREACH(_ht, indirect) ZEND_HASH_MAP_FOREACH_FROM(_ht, indirect, 0)
1245 
1246 #define ZEND_HASH_MAP_REVERSE_FOREACH(_ht, indirect) do { \
1247 		HashTable *__ht = (_ht); \
1248 		uint32_t _idx = __ht->nNumUsed; \
1249 		Bucket *_p = __ht->arData + _idx; \
1250 		zval *_z; \
1251 		ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
1252 		for (_idx = __ht->nNumUsed; _idx > 0; _idx--) { \
1253 			_p--; \
1254 			_z = &_p->val; \
1255 			if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
1256 				_z = Z_INDIRECT_P(_z); \
1257 			} \
1258 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1259 
1260 #define ZEND_HASH_MAP_FOREACH_END_DEL() \
1261 			ZEND_ASSERT(!HT_IS_PACKED(__ht)); \
1262 			__ht->nNumOfElements--; \
1263 			do { \
1264 				uint32_t j = HT_IDX_TO_HASH(_idx - 1); \
1265 				uint32_t nIndex = _p->h | __ht->nTableMask; \
1266 				uint32_t i = HT_HASH(__ht, nIndex); \
1267 				if (UNEXPECTED(j != i)) { \
1268 					Bucket *prev = HT_HASH_TO_BUCKET(__ht, i); \
1269 					while (Z_NEXT(prev->val) != j) { \
1270 						i = Z_NEXT(prev->val); \
1271 						prev = HT_HASH_TO_BUCKET(__ht, i); \
1272 					} \
1273 					Z_NEXT(prev->val) = Z_NEXT(_p->val); \
1274 				} else { \
1275 					HT_HASH(__ht, nIndex) = Z_NEXT(_p->val); \
1276 				} \
1277 			} while (0); \
1278 		} \
1279 		__ht->nNumUsed = _idx; \
1280 	} while (0)
1281 
1282 #define ZEND_HASH_MAP_FOREACH_BUCKET(ht, _bucket) \
1283 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1284 	_bucket = _p;
1285 
1286 #define ZEND_HASH_MAP_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
1287 	ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
1288 	_bucket = _p;
1289 
1290 #define ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(ht, _bucket) \
1291 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1292 	_bucket = _p;
1293 
1294 #define ZEND_HASH_MAP_FOREACH_VAL(ht, _val) \
1295 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1296 	_val = _z;
1297 
1298 #define ZEND_HASH_MAP_REVERSE_FOREACH_VAL(ht, _val) \
1299 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1300 	_val = _z;
1301 
1302 #define ZEND_HASH_MAP_FOREACH_VAL_IND(ht, _val) \
1303 	ZEND_HASH_MAP_FOREACH(ht, 1); \
1304 	_val = _z;
1305 
1306 #define ZEND_HASH_MAP_REVERSE_FOREACH_VAL_IND(ht, _val) \
1307 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
1308 	_val = _z;
1309 
1310 #define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr) \
1311 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1312 	_ptr = Z_PTR_P(_z);
1313 
1314 #define ZEND_HASH_MAP_FOREACH_PTR_FROM(ht, _ptr, _from) \
1315 	ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
1316 	_ptr = Z_PTR_P(_z);
1317 
1318 #define ZEND_HASH_MAP_REVERSE_FOREACH_PTR(ht, _ptr) \
1319 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1320 	_ptr = Z_PTR_P(_z);
1321 
1322 #define ZEND_HASH_MAP_FOREACH_NUM_KEY(ht, _h) \
1323 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1324 	_h = _p->h;
1325 
1326 #define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY(ht, _h) \
1327 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1328 	_h = _p->h;
1329 
1330 #define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key) \
1331 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1332 	_key = _p->key;
1333 
1334 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY(ht, _key) \
1335 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1336 	_key = _p->key;
1337 
1338 #define ZEND_HASH_MAP_FOREACH_KEY(ht, _h, _key) \
1339 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1340 	_h = _p->h; \
1341 	_key = _p->key;
1342 
1343 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY(ht, _h, _key) \
1344 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1345 	_h = _p->h; \
1346 	_key = _p->key;
1347 
1348 #define ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1349 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1350 	_h = _p->h; \
1351 	_val = _z;
1352 
1353 #define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY_VAL(ht, _h, _val) \
1354 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1355 	_h = _p->h; \
1356 	_val = _z;
1357 
1358 #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1359 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1360 	_key = _p->key; \
1361 	_val = _z;
1362 
1363 #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
1364 	ZEND_HASH_MAP_FOREACH_FROM(ht, 0, _from); \
1365 	_key = _p->key; \
1366 	_val = _z;
1367 
1368 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
1369 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1370 	_key = _p->key; \
1371 	_val = _z;
1372 
1373 #define ZEND_HASH_MAP_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1374 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1375 	_h = _p->h; \
1376 	_key = _p->key; \
1377 	_val = _z;
1378 
1379 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
1380 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1381 	_h = _p->h; \
1382 	_key = _p->key; \
1383 	_val = _z;
1384 
1385 #define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1386 	ZEND_HASH_MAP_FOREACH(ht, 1); \
1387 	_key = _p->key; \
1388 	_val = _z;
1389 
1390 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL_IND(ht, _key, _val) \
1391 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
1392 	_key = _p->key; \
1393 	_val = _z;
1394 
1395 #define ZEND_HASH_MAP_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1396 	ZEND_HASH_MAP_FOREACH(ht, 1); \
1397 	_h = _p->h; \
1398 	_key = _p->key; \
1399 	_val = _z;
1400 
1401 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_VAL_IND(ht, _h, _key, _val) \
1402 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 1); \
1403 	_h = _p->h; \
1404 	_key = _p->key; \
1405 	_val = _z;
1406 
1407 #define ZEND_HASH_MAP_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1408 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1409 	_h = _p->h; \
1410 	_ptr = Z_PTR_P(_z);
1411 
1412 #define ZEND_HASH_MAP_REVERSE_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \
1413 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1414 	_h = _p->h; \
1415 	_ptr = Z_PTR_P(_z);
1416 
1417 #define ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1418 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1419 	_key = _p->key; \
1420 	_ptr = Z_PTR_P(_z);
1421 
1422 #define ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_PTR(ht, _key, _ptr) \
1423 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1424 	_key = _p->key; \
1425 	_ptr = Z_PTR_P(_z);
1426 
1427 #define ZEND_HASH_MAP_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1428 	ZEND_HASH_MAP_FOREACH(ht, 0); \
1429 	_h = _p->h; \
1430 	_key = _p->key; \
1431 	_ptr = Z_PTR_P(_z);
1432 
1433 #define ZEND_HASH_MAP_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \
1434 	ZEND_HASH_MAP_REVERSE_FOREACH(ht, 0); \
1435 	_h = _p->h; \
1436 	_key = _p->key; \
1437 	_ptr = Z_PTR_P(_z);
1438 
1439 /* Packed array iterators */
1440 #define ZEND_HASH_PACKED_FOREACH_FROM(_ht, _from) do { \
1441 		HashTable *__ht = (_ht); \
1442 		zend_ulong _idx = (_from); \
1443 		zval *_z = __ht->arPacked + (_from); \
1444 		zval *_end = __ht->arPacked + __ht->nNumUsed; \
1445 		ZEND_ASSERT(HT_IS_PACKED(__ht)); \
1446 		for (;_z != _end; _z++, _idx++) { \
1447 			(void) _idx; \
1448 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1449 
1450 #define ZEND_HASH_PACKED_FOREACH(_ht) ZEND_HASH_PACKED_FOREACH_FROM(_ht, 0)
1451 
1452 #define ZEND_HASH_PACKED_REVERSE_FOREACH(_ht) do { \
1453 		HashTable *__ht = (_ht); \
1454 		zend_ulong _idx = __ht->nNumUsed; \
1455 		zval *_z = __ht->arPacked + _idx; \
1456 		ZEND_ASSERT(HT_IS_PACKED(__ht)); \
1457 		while (_idx > 0) { \
1458 			_z--; \
1459 			_idx--; \
1460 			(void) _idx; \
1461 			if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
1462 
1463 #define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val) \
1464 	ZEND_HASH_PACKED_FOREACH(ht); \
1465 	_val = _z;
1466 
1467 #define ZEND_HASH_PACKED_REVERSE_FOREACH_VAL(ht, _val) \
1468 	ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1469 	_val = _z;
1470 
1471 #define ZEND_HASH_PACKED_FOREACH_PTR(ht, _ptr) \
1472 	ZEND_HASH_PACKED_FOREACH(ht); \
1473 	_ptr = Z_PTR_P(_z);
1474 
1475 #define ZEND_HASH_PACKED_REVERSE_FOREACH_PTR(ht, _ptr) \
1476 	ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1477 	_ptr = Z_PTR_P(_z);
1478 
1479 #define ZEND_HASH_PACKED_FOREACH_KEY(ht, _h) \
1480 	ZEND_HASH_PACKED_FOREACH(ht); \
1481 	_h = _idx;
1482 
1483 #define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY(ht, _h) \
1484 	ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1485 	_h = _idx;
1486 
1487 #define ZEND_HASH_PACKED_FOREACH_KEY_VAL(ht, _h, _val) \
1488 	ZEND_HASH_PACKED_FOREACH(ht); \
1489 	_h = _idx; \
1490 	_val = _z;
1491 
1492 #define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY_VAL(ht, _h, _val) \
1493 	ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1494 	_h = _idx; \
1495 	_val = _z;
1496 
1497 #define ZEND_HASH_PACKED_FOREACH_KEY_PTR(ht, _h, _ptr) \
1498 	ZEND_HASH_PACKED_FOREACH(ht); \
1499 	_h = _idx; \
1500 	_ptr = Z_PTR_P(_z);
1501 
1502 #define ZEND_HASH_PACKED_REVERSE_FOREACH_KEY_PTR(ht, _h, _ptr) \
1503 	ZEND_HASH_PACKED_REVERSE_FOREACH(ht); \
1504 	_h = _idx; \
1505 	_ptr = Z_PTR_P(_z);
1506 
1507 /* The following macros are useful to insert a sequence of new elements
1508  * of packed array. They may be used instead of series of
1509  * zend_hash_next_index_insert_new()
1510  * (HashTable must have enough free buckets).
1511  */
1512 #define ZEND_HASH_FILL_PACKED(ht) do { \
1513 		HashTable *__fill_ht = (ht); \
1514 		zval *__fill_val = __fill_ht->arPacked + __fill_ht->nNumUsed; \
1515 		uint32_t __fill_idx = __fill_ht->nNumUsed; \
1516 		ZEND_ASSERT(HT_IS_PACKED(__fill_ht));
1517 
1518 #define ZEND_HASH_FILL_GROW() do { \
1519 		if (UNEXPECTED(__fill_idx >= __fill_ht->nTableSize)) { \
1520 			__fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \
1521 			__fill_ht->nNumUsed = __fill_idx; \
1522 			__fill_ht->nNextFreeElement = __fill_idx; \
1523 			zend_hash_packed_grow(__fill_ht); \
1524 			__fill_val = __fill_ht->arPacked + __fill_idx; \
1525 		} \
1526 	} while (0);
1527 
1528 #define ZEND_HASH_FILL_SET(_val) \
1529 		ZVAL_COPY_VALUE(__fill_val, _val)
1530 
1531 #define ZEND_HASH_FILL_SET_NULL() \
1532 		ZVAL_NULL(__fill_val)
1533 
1534 #define ZEND_HASH_FILL_SET_LONG(_val) \
1535 		ZVAL_LONG(__fill_val, _val)
1536 
1537 #define ZEND_HASH_FILL_SET_DOUBLE(_val) \
1538 		ZVAL_DOUBLE(__fill_val, _val)
1539 
1540 #define ZEND_HASH_FILL_SET_STR(_val) \
1541 		ZVAL_STR(__fill_val, _val)
1542 
1543 #define ZEND_HASH_FILL_SET_STR_COPY(_val) \
1544 		ZVAL_STR_COPY(__fill_val, _val)
1545 
1546 #define ZEND_HASH_FILL_SET_INTERNED_STR(_val) \
1547 		ZVAL_INTERNED_STR(__fill_val, _val)
1548 
1549 #define ZEND_HASH_FILL_NEXT() do {\
1550 		__fill_val++; \
1551 		__fill_idx++; \
1552 	} while (0)
1553 
1554 #define ZEND_HASH_FILL_ADD(_val) do { \
1555 		ZEND_HASH_FILL_SET(_val); \
1556 		ZEND_HASH_FILL_NEXT(); \
1557 	} while (0)
1558 
1559 #define ZEND_HASH_FILL_FINISH() do { \
1560 		__fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \
1561 		__fill_ht->nNumUsed = __fill_idx; \
1562 		__fill_ht->nNextFreeElement = __fill_idx; \
1563 		__fill_ht->nInternalPointer = 0; \
1564 	} while (0)
1565 
1566 #define ZEND_HASH_FILL_END() \
1567 		ZEND_HASH_FILL_FINISH(); \
1568 	} while (0)
1569 
1570 /* Check if an array is a list */
zend_array_is_list(zend_array * array)1571 static zend_always_inline bool zend_array_is_list(zend_array *array)
1572 {
1573 	zend_ulong expected_idx = 0;
1574 	zend_ulong num_idx;
1575 	zend_string* str_idx;
1576 	/* Empty arrays are lists */
1577 	if (zend_hash_num_elements(array) == 0) {
1578 		return 1;
1579 	}
1580 
1581 	/* Packed arrays are lists */
1582 	if (HT_IS_PACKED(array)) {
1583 		if (HT_IS_WITHOUT_HOLES(array)) {
1584 			return 1;
1585 		}
1586 		/* Check if the list could theoretically be repacked */
1587 		ZEND_HASH_PACKED_FOREACH_KEY(array, num_idx) {
1588 			if (num_idx != expected_idx++) {
1589 				return 0;
1590 			}
1591 		} ZEND_HASH_FOREACH_END();
1592 	} else {
1593 		/* Check if the list could theoretically be repacked */
1594 		ZEND_HASH_MAP_FOREACH_KEY(array, num_idx, str_idx) {
1595 			if (str_idx != NULL || num_idx != expected_idx++) {
1596 				return 0;
1597 			}
1598 		} ZEND_HASH_FOREACH_END();
1599 	}
1600 
1601 	return 1;
1602 }
1603 
1604 
_zend_hash_append_ex(HashTable * ht,zend_string * key,zval * zv,bool interned)1605 static zend_always_inline zval *_zend_hash_append_ex(HashTable *ht, zend_string *key, zval *zv, bool interned)
1606 {
1607 	uint32_t idx = ht->nNumUsed++;
1608 	uint32_t nIndex;
1609 	Bucket *p = ht->arData + idx;
1610 
1611 	ZVAL_COPY_VALUE(&p->val, zv);
1612 	if (!interned && !ZSTR_IS_INTERNED(key)) {
1613 		HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1614 		zend_string_addref(key);
1615 		zend_string_hash_val(key);
1616 	}
1617 	p->key = key;
1618 	p->h = ZSTR_H(key);
1619 	nIndex = (uint32_t)p->h | ht->nTableMask;
1620 	Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1621 	HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1622 	ht->nNumOfElements++;
1623 	return &p->val;
1624 }
1625 
_zend_hash_append(HashTable * ht,zend_string * key,zval * zv)1626 static zend_always_inline zval *_zend_hash_append(HashTable *ht, zend_string *key, zval *zv)
1627 {
1628 	return _zend_hash_append_ex(ht, key, zv, 0);
1629 }
1630 
_zend_hash_append_ptr_ex(HashTable * ht,zend_string * key,void * ptr,bool interned)1631 static zend_always_inline zval *_zend_hash_append_ptr_ex(HashTable *ht, zend_string *key, void *ptr, bool interned)
1632 {
1633 	uint32_t idx = ht->nNumUsed++;
1634 	uint32_t nIndex;
1635 	Bucket *p = ht->arData + idx;
1636 
1637 	ZVAL_PTR(&p->val, ptr);
1638 	if (!interned && !ZSTR_IS_INTERNED(key)) {
1639 		HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1640 		zend_string_addref(key);
1641 		zend_string_hash_val(key);
1642 	}
1643 	p->key = key;
1644 	p->h = ZSTR_H(key);
1645 	nIndex = (uint32_t)p->h | ht->nTableMask;
1646 	Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1647 	HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1648 	ht->nNumOfElements++;
1649 	return &p->val;
1650 }
1651 
_zend_hash_append_ptr(HashTable * ht,zend_string * key,void * ptr)1652 static zend_always_inline zval *_zend_hash_append_ptr(HashTable *ht, zend_string *key, void *ptr)
1653 {
1654 	return _zend_hash_append_ptr_ex(ht, key, ptr, 0);
1655 }
1656 
_zend_hash_append_ind(HashTable * ht,zend_string * key,zval * ptr)1657 static zend_always_inline void _zend_hash_append_ind(HashTable *ht, zend_string *key, zval *ptr)
1658 {
1659 	uint32_t idx = ht->nNumUsed++;
1660 	uint32_t nIndex;
1661 	Bucket *p = ht->arData + idx;
1662 
1663 	ZVAL_INDIRECT(&p->val, ptr);
1664 	if (!ZSTR_IS_INTERNED(key)) {
1665 		HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
1666 		zend_string_addref(key);
1667 		zend_string_hash_val(key);
1668 	}
1669 	p->key = key;
1670 	p->h = ZSTR_H(key);
1671 	nIndex = (uint32_t)p->h | ht->nTableMask;
1672 	Z_NEXT(p->val) = HT_HASH(ht, nIndex);
1673 	HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1674 	ht->nNumOfElements++;
1675 }
1676 
1677 #endif							/* ZEND_HASH_H */
1678