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