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