xref: /PHP-8.1/ext/opcache/jit/zend_jit_helpers.c (revision 87107f86)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend JIT                                                             |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP 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    | https://www.php.net/license/3_01.txt                                 |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "Zend/zend_API.h"
20 
undef_result_after_exception(void)21 static ZEND_COLD void undef_result_after_exception(void) {
22 	const zend_op *opline = EG(opline_before_exception);
23 	ZEND_ASSERT(EG(exception));
24 	if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
25 		zend_execute_data *execute_data = EG(current_execute_data);
26 		ZVAL_UNDEF(EX_VAR(opline->result.var));
27 	}
28 }
29 
zend_jit_illegal_offset(void)30 static ZEND_COLD void zend_jit_illegal_offset(void)
31 {
32 	zend_type_error("Illegal offset type");
33 }
34 
zend_jit_illegal_string_offset(zval * offset)35 static ZEND_COLD void zend_jit_illegal_string_offset(zval *offset)
36 {
37 	zend_type_error("Cannot access offset of type %s on string", zend_zval_type_name(offset));
38 }
39 
_zend_jit_init_func_run_time_cache(const zend_op_array * op_array)40 static zend_never_inline zend_function* ZEND_FASTCALL _zend_jit_init_func_run_time_cache(const zend_op_array *op_array) /* {{{ */
41 {
42 	void **run_time_cache;
43 
44 	run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
45 	memset(run_time_cache, 0, op_array->cache_size);
46 	ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
47 	return (zend_function*)op_array;
48 }
49 /* }}} */
50 
zend_jit_init_func_run_time_cache_helper(zend_op_array * op_array)51 static zend_never_inline zend_op_array* ZEND_FASTCALL zend_jit_init_func_run_time_cache_helper(zend_op_array *op_array) /* {{{ */
52 {
53 	void **run_time_cache;
54 
55 	if (!RUN_TIME_CACHE(op_array)) {
56 		run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
57 		memset(run_time_cache, 0, op_array->cache_size);
58 		ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
59 	}
60 	return op_array;
61 }
62 /* }}} */
63 
zend_jit_find_func_helper(zend_string * name,void ** cache_slot)64 static zend_function* ZEND_FASTCALL zend_jit_find_func_helper(zend_string *name, void **cache_slot)
65 {
66 	zval *func = zend_hash_find_known_hash(EG(function_table), name);
67 	zend_function *fbc;
68 
69 	if (UNEXPECTED(func == NULL)) {
70 		return NULL;
71 	}
72 	fbc = Z_FUNC_P(func);
73 	if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
74 		fbc = _zend_jit_init_func_run_time_cache(&fbc->op_array);
75 	}
76 	*cache_slot = fbc;
77 	return fbc;
78 }
79 
zend_jit_find_ns_func_helper(zval * func_name,void ** cache_slot)80 static zend_function* ZEND_FASTCALL zend_jit_find_ns_func_helper(zval *func_name, void **cache_slot)
81 {
82 	zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));
83 	zend_function *fbc;
84 
85 	if (func == NULL) {
86 		func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 2));
87 		if (UNEXPECTED(func == NULL)) {
88 			return NULL;
89 		}
90 	}
91 	fbc = Z_FUNC_P(func);
92 	if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
93 		fbc = _zend_jit_init_func_run_time_cache(&fbc->op_array);
94 	}
95 	*cache_slot = fbc;
96 	return fbc;
97 }
98 
zend_jit_invalid_method_call(zval * object)99 static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call(zval *object)
100 {
101 	zend_execute_data *execute_data = EG(current_execute_data);
102 	const zend_op *opline = EX(opline);
103 	zval *function_name = function_name = RT_CONSTANT(opline, opline->op2);;
104 
105 	if (Z_TYPE_P(object) == IS_UNDEF && opline->op1_type == IS_CV) {
106 		zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)];
107 
108 		zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
109 		if (UNEXPECTED(EG(exception) != NULL)) {
110 			return;
111 		}
112 		object = &EG(uninitialized_zval);
113 	}
114 	zend_throw_error(NULL, "Call to a member function %s() on %s",
115 		Z_STRVAL_P(function_name), zend_zval_type_name(object));
116 }
117 
zend_jit_invalid_method_call_tmp(zval * object)118 static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call_tmp(zval *object)
119 {
120 	zend_execute_data *execute_data = EG(current_execute_data);
121 	const zend_op *opline = EX(opline);
122 
123 	zend_jit_invalid_method_call(object);
124 	zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
125 }
126 
zend_undefined_method(const zend_class_entry * ce,const zend_string * method)127 static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(const zend_class_entry *ce, const zend_string *method)
128 {
129 	zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(method));
130 }
131 
zend_jit_unref_helper(zval * zv)132 static void ZEND_FASTCALL zend_jit_unref_helper(zval *zv)
133 {
134 	zend_reference *ref;
135 
136 	ZEND_ASSERT(Z_ISREF_P(zv));
137 	ref = Z_REF_P(zv);
138 	ZVAL_COPY_VALUE(zv, &ref->val);
139 	if (GC_DELREF(ref) == 0) {
140 		efree_size(ref, sizeof(zend_reference));
141 	} else {
142 		Z_TRY_ADDREF_P(zv);
143 	}
144 }
145 
zend_jit_find_method_helper(zend_object * obj,zval * function_name,zend_object ** obj_ptr)146 static zend_function* ZEND_FASTCALL zend_jit_find_method_helper(zend_object *obj, zval *function_name, zend_object **obj_ptr)
147 {
148 	zend_execute_data *execute_data = EG(current_execute_data);
149 	const zend_op *opline = EX(opline);
150 	zend_class_entry *called_scope = obj->ce;
151 	zend_function *fbc;
152 
153 	fbc = obj->handlers->get_method(obj_ptr, Z_STR_P(function_name), function_name + 1);
154 	if (UNEXPECTED(fbc == NULL)) {
155 		if (EXPECTED(!EG(exception))) {
156 			zend_undefined_method(called_scope, Z_STR_P(function_name));
157 		}
158 		return NULL;
159 	}
160 
161 	if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
162 		zend_init_func_run_time_cache(&fbc->op_array);
163 	}
164 
165 	if (UNEXPECTED(obj != *obj_ptr)) {
166 		return fbc;
167 	}
168 
169 	if (EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
170 		CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc);
171 	}
172 
173 	return fbc;
174 }
175 
zend_jit_find_method_tmp_helper(zend_object * obj,zval * function_name,zend_object ** obj_ptr)176 static zend_function* ZEND_FASTCALL zend_jit_find_method_tmp_helper(zend_object *obj, zval *function_name, zend_object **obj_ptr)
177 {
178 	zend_function *fbc;
179 
180 	fbc = zend_jit_find_method_helper(obj, function_name, obj_ptr);
181 	if (!fbc) {
182 		if (GC_DELREF(obj) == 0) {
183 			zend_objects_store_del(obj);
184 		}
185 	} else if (obj != *obj_ptr) {
186 		GC_ADDREF(*obj_ptr);
187 		if (GC_DELREF(obj) == 0) {
188 			zend_objects_store_del(obj);
189 		}
190 	}
191 	return fbc;
192 }
193 
zend_jit_push_static_metod_call_frame(zend_object * obj,zend_function * fbc,uint32_t num_args)194 static zend_execute_data* ZEND_FASTCALL zend_jit_push_static_metod_call_frame(zend_object *obj, zend_function *fbc, uint32_t num_args)
195 {
196 	zend_class_entry *scope = obj->ce;
197 
198 	return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, num_args, scope);
199 }
200 
zend_jit_push_static_metod_call_frame_tmp(zend_object * obj,zend_function * fbc,uint32_t num_args)201 static zend_execute_data* ZEND_FASTCALL zend_jit_push_static_metod_call_frame_tmp(zend_object *obj, zend_function *fbc, uint32_t num_args)
202 {
203 	zend_class_entry *scope = obj->ce;
204 
205 	if (GC_DELREF(obj) == 0) {
206 		zend_objects_store_del(obj);
207 		if (UNEXPECTED(EG(exception))) {
208 			return NULL;
209 		}
210 	}
211 
212 	return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, num_args, scope);
213 }
214 
zend_jit_extend_stack_helper(uint32_t used_stack,zend_function * fbc)215 static zend_execute_data* ZEND_FASTCALL zend_jit_extend_stack_helper(uint32_t used_stack, zend_function *fbc)
216 {
217 	zend_execute_data *call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
218 	call->func = fbc;
219 	ZEND_CALL_INFO(call) = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_ALLOCATED;
220 	return call;
221 }
222 
zend_jit_int_extend_stack_helper(uint32_t used_stack)223 static zend_execute_data* ZEND_FASTCALL zend_jit_int_extend_stack_helper(uint32_t used_stack)
224 {
225 	zend_execute_data *call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
226 	ZEND_CALL_INFO(call) = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_ALLOCATED;
227 	return call;
228 }
229 
zend_jit_symtable_find(HashTable * ht,zend_string * str)230 static zval* ZEND_FASTCALL zend_jit_symtable_find(HashTable *ht, zend_string *str)
231 {
232 	zend_ulong idx;
233 	register const char *tmp = str->val;
234 
235 	do {
236 		if (*tmp > '9') {
237 			break;
238 		} else if (*tmp < '0') {
239 			if (*tmp != '-') {
240 				break;
241 			}
242 			tmp++;
243 			if (*tmp > '9' || *tmp < '0') {
244 				break;
245 			}
246 		}
247 		if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
248 			return zend_hash_index_find(ht, idx);
249 		}
250 	} while (0);
251 
252 	return zend_hash_find(ht, str);
253 }
254 
zend_jit_hash_index_lookup_rw_no_packed(HashTable * ht,zend_long idx)255 static zval* ZEND_FASTCALL zend_jit_hash_index_lookup_rw_no_packed(HashTable *ht, zend_long idx)
256 {
257 	zval *retval = NULL;
258 
259 	if (!HT_IS_PACKED(ht)) {
260 		retval = _zend_hash_index_find(ht, idx);
261 	}
262 	if (!retval) {
263 		retval = zend_undefined_offset_write(ht, idx);
264 	}
265 	return retval;
266 }
267 
zend_jit_hash_index_lookup_rw(HashTable * ht,zend_long idx)268 static zval* ZEND_FASTCALL zend_jit_hash_index_lookup_rw(HashTable *ht, zend_long idx)
269 {
270 	zval *retval = zend_hash_index_find(ht, idx);
271 
272 	if (!retval) {
273 		retval = zend_undefined_offset_write(ht, idx);
274 	}
275 	return retval;
276 }
277 
zend_jit_hash_lookup_rw(HashTable * ht,zend_string * str)278 static zval* ZEND_FASTCALL zend_jit_hash_lookup_rw(HashTable *ht, zend_string *str)
279 {
280 	zval *retval = zend_hash_find_known_hash(ht, str);
281 	if (!retval) {
282 		/* Key may be released while throwing the undefined index warning. */
283 		retval = zend_undefined_index_write(ht, str);
284 	}
285 	return retval;
286 }
287 
zend_jit_symtable_lookup_rw(HashTable * ht,zend_string * str)288 static zval* ZEND_FASTCALL zend_jit_symtable_lookup_rw(HashTable *ht, zend_string *str)
289 {
290 	zend_ulong idx;
291 	register const char *tmp = str->val;
292 	zval *retval;
293 
294 	do {
295 		if (*tmp > '9') {
296 			break;
297 		} else if (*tmp < '0') {
298 			if (*tmp != '-') {
299 				break;
300 			}
301 			tmp++;
302 			if (*tmp > '9' || *tmp < '0') {
303 				break;
304 			}
305 		}
306 		if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
307 			retval = zend_hash_index_find(ht, idx);
308 			if (!retval) {
309 				retval = zend_undefined_offset_write(ht, idx);
310 			}
311 			return retval;
312 		}
313 	} while (0);
314 
315 	retval = zend_hash_find(ht, str);
316 	if (!retval) {
317 		/* Key may be released while throwing the undefined index warning. */
318 		retval = zend_undefined_index_write(ht, str);
319 	}
320 	return retval;
321 }
322 
zend_jit_symtable_lookup_w(HashTable * ht,zend_string * str)323 static zval* ZEND_FASTCALL zend_jit_symtable_lookup_w(HashTable *ht, zend_string *str)
324 {
325 	zend_ulong idx;
326 	register const char *tmp = str->val;
327 
328 	do {
329 		if (*tmp > '9') {
330 			break;
331 		} else if (*tmp < '0') {
332 			if (*tmp != '-') {
333 				break;
334 			}
335 			tmp++;
336 			if (*tmp > '9' || *tmp < '0') {
337 				break;
338 			}
339 		}
340 		if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
341 			return zend_hash_index_lookup(ht, idx);
342 		}
343 	} while (0);
344 
345 	return zend_hash_lookup(ht, str);
346 }
347 
zend_jit_undefined_op_helper(uint32_t var)348 static int ZEND_FASTCALL zend_jit_undefined_op_helper(uint32_t var)
349 {
350 	const zend_execute_data *execute_data = EG(current_execute_data);
351 	zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)];
352 
353 	zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
354 	return EG(exception) == NULL;
355 }
356 
zend_jit_undefined_op_helper_write(HashTable * ht,uint32_t var)357 static int ZEND_FASTCALL zend_jit_undefined_op_helper_write(HashTable *ht, uint32_t var)
358 {
359 	const zend_execute_data *execute_data = EG(current_execute_data);
360 	zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)];
361 
362 	/* The array may be destroyed while throwing the notice.
363 	 * Temporarily increase the refcount to detect this situation. */
364 	if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
365 		GC_ADDREF(ht);
366 	}
367 	zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
368 	if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
369 		if (!GC_REFCOUNT(ht)) {
370 			zend_array_destroy(ht);
371 		}
372 		return 0;
373 	}
374 	return EG(exception) == NULL;
375 }
376 
zend_jit_fetch_dim_r_helper(zend_array * ht,zval * dim,zval * result)377 static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim, zval *result)
378 {
379 	zend_ulong hval;
380 	zend_string *offset_key;
381 	zval *retval;
382 	zend_execute_data *execute_data;
383 	const zend_op *opline;
384 
385 	if (Z_TYPE_P(dim) == IS_REFERENCE) {
386 		dim = Z_REFVAL_P(dim);
387 	}
388 
389 	switch (Z_TYPE_P(dim)) {
390 		case IS_LONG:
391 			hval = Z_LVAL_P(dim);
392 			goto num_index;
393 		case IS_STRING:
394 			offset_key = Z_STR_P(dim);
395 			goto str_index;
396 		case IS_UNDEF:
397 			/* The array may be destroyed while throwing the notice.
398 			 * Temporarily increase the refcount to detect this situation. */
399 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
400 				GC_ADDREF(ht);
401 			}
402 			execute_data = EG(current_execute_data);
403 			opline = EX(opline);
404 			zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
405 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
406 				zend_array_destroy(ht);
407 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
408 					if (EG(exception)) {
409 						ZVAL_UNDEF(EX_VAR(opline->result.var));
410 					} else {
411 						ZVAL_NULL(EX_VAR(opline->result.var));
412 					}
413 				}
414 				return;
415 			}
416 			if (EG(exception)) {
417 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
418 					ZVAL_UNDEF(EX_VAR(opline->result.var));
419 				}
420 				return;
421 			}
422 			ZEND_FALLTHROUGH;
423 		case IS_NULL:
424 			offset_key = ZSTR_EMPTY_ALLOC();
425 			goto str_index;
426 		case IS_DOUBLE:
427 			hval = zend_dval_to_lval(Z_DVAL_P(dim));
428 			if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
429 				/* The array may be destroyed while throwing the notice.
430 				 * Temporarily increase the refcount to detect this situation. */
431 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
432 					GC_ADDREF(ht);
433 				}
434 				execute_data = EG(current_execute_data);
435 				opline = EX(opline);
436 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
437 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
438 					zend_array_destroy(ht);
439 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
440 						if (EG(exception)) {
441 							ZVAL_UNDEF(EX_VAR(opline->result.var));
442 						} else {
443 							ZVAL_NULL(EX_VAR(opline->result.var));
444 						}
445 					}
446 					return;
447 				}
448 				if (EG(exception)) {
449 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
450 						ZVAL_UNDEF(EX_VAR(opline->result.var));
451 					}
452 					return;
453 				}
454 			}
455 			goto num_index;
456 		case IS_RESOURCE:
457 			/* The array may be destroyed while throwing the notice.
458 			 * Temporarily increase the refcount to detect this situation. */
459 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
460 				GC_ADDREF(ht);
461 			}
462 			execute_data = EG(current_execute_data);
463 			opline = EX(opline);
464 			zend_use_resource_as_offset(dim);
465 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
466 				zend_array_destroy(ht);
467 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
468 					if (EG(exception)) {
469 						ZVAL_UNDEF(EX_VAR(opline->result.var));
470 					} else {
471 						ZVAL_NULL(EX_VAR(opline->result.var));
472 					}
473 				}
474 				return;
475 			}
476 			if (EG(exception)) {
477 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
478 					ZVAL_UNDEF(EX_VAR(opline->result.var));
479 				}
480 				return;
481 			}
482 			hval = Z_RES_HANDLE_P(dim);
483 			goto num_index;
484 		case IS_FALSE:
485 			hval = 0;
486 			goto num_index;
487 		case IS_TRUE:
488 			hval = 1;
489 			goto num_index;
490 		default:
491 			zend_jit_illegal_offset();
492 			undef_result_after_exception();
493 			return;
494 	}
495 
496 str_index:
497 	if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
498 		goto num_index;
499 	}
500 	retval = zend_hash_find(ht, offset_key);
501 	if (!retval) {
502 		zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
503 		ZVAL_NULL(result);
504 		return;
505 	}
506 	ZVAL_COPY_DEREF(result, retval);
507 	return;
508 
509 num_index:
510 	ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
511 	ZVAL_COPY_DEREF(result, retval);
512 	return;
513 
514 num_undef:
515 	zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, hval);
516 	ZVAL_NULL(result);
517 }
518 
zend_jit_fetch_dim_is_helper(zend_array * ht,zval * dim,zval * result)519 static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim, zval *result)
520 {
521 	zend_ulong hval;
522 	zend_string *offset_key;
523 	zval *retval;
524 	zend_execute_data *execute_data;
525 	const zend_op *opline;
526 
527 	if (Z_TYPE_P(dim) == IS_REFERENCE) {
528 		dim = Z_REFVAL_P(dim);
529 	}
530 
531 	switch (Z_TYPE_P(dim)) {
532 		case IS_LONG:
533 			hval = Z_LVAL_P(dim);
534 			goto num_index;
535 		case IS_STRING:
536 			offset_key = Z_STR_P(dim);
537 			goto str_index;
538 		case IS_UNDEF:
539 			/* The array may be destroyed while throwing the notice.
540 			 * Temporarily increase the refcount to detect this situation. */
541 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
542 				GC_ADDREF(ht);
543 			}
544 			execute_data = EG(current_execute_data);
545 			opline = EX(opline);
546 			zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
547 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
548 				zend_array_destroy(ht);
549 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
550 					if (EG(exception)) {
551 						ZVAL_UNDEF(EX_VAR(opline->result.var));
552 					} else {
553 						ZVAL_NULL(EX_VAR(opline->result.var));
554 					}
555 				}
556 				return;
557 			}
558 			if (EG(exception)) {
559 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
560 					ZVAL_UNDEF(EX_VAR(opline->result.var));
561 				}
562 				return;
563 			}
564 			ZEND_FALLTHROUGH;
565 		case IS_NULL:
566 			offset_key = ZSTR_EMPTY_ALLOC();
567 			goto str_index;
568 		case IS_DOUBLE:
569 			hval = zend_dval_to_lval(Z_DVAL_P(dim));
570 			if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
571 				/* The array may be destroyed while throwing the notice.
572 				 * Temporarily increase the refcount to detect this situation. */
573 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
574 					GC_ADDREF(ht);
575 				}
576 				execute_data = EG(current_execute_data);
577 				opline = EX(opline);
578 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
579 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
580 					zend_array_destroy(ht);
581 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
582 						if (EG(exception)) {
583 							ZVAL_UNDEF(EX_VAR(opline->result.var));
584 						} else {
585 							ZVAL_NULL(EX_VAR(opline->result.var));
586 						}
587 					}
588 					return;
589 				}
590 				if (EG(exception)) {
591 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
592 						ZVAL_UNDEF(EX_VAR(opline->result.var));
593 					}
594 					return;
595 				}
596 			}
597 			goto num_index;
598 		case IS_RESOURCE:
599 			/* The array may be destroyed while throwing the notice.
600 			 * Temporarily increase the refcount to detect this situation. */
601 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
602 				GC_ADDREF(ht);
603 			}
604 			execute_data = EG(current_execute_data);
605 			opline = EX(opline);
606 			zend_use_resource_as_offset(dim);
607 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
608 				zend_array_destroy(ht);
609 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
610 					if (EG(exception)) {
611 						ZVAL_UNDEF(EX_VAR(opline->result.var));
612 					} else {
613 						ZVAL_NULL(EX_VAR(opline->result.var));
614 					}
615 				}
616 				return;
617 			}
618 			if (EG(exception)) {
619 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
620 					ZVAL_UNDEF(EX_VAR(opline->result.var));
621 				}
622 				return;
623 			}
624 			hval = Z_RES_HANDLE_P(dim);
625 			goto num_index;
626 		case IS_FALSE:
627 			hval = 0;
628 			goto num_index;
629 		case IS_TRUE:
630 			hval = 1;
631 			goto num_index;
632 		default:
633 			zend_jit_illegal_offset();
634 			undef_result_after_exception();
635 			return;
636 	}
637 
638 str_index:
639 	if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
640 		goto num_index;
641 	}
642 	retval = zend_hash_find(ht, offset_key);
643 	if (!retval) {
644 		ZVAL_NULL(result);
645 		return;
646 	}
647 	ZVAL_COPY_DEREF(result, retval);
648 	return;
649 
650 num_index:
651 	ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
652 	ZVAL_COPY_DEREF(result, retval);
653 	return;
654 
655 num_undef:
656 	ZVAL_NULL(result);
657 }
658 
zend_jit_fetch_dim_isset_helper(zend_array * ht,zval * dim)659 static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *dim)
660 {
661 	zend_ulong hval;
662 	zend_string *offset_key;
663 	zval *retval;
664 
665 	if (Z_TYPE_P(dim) == IS_REFERENCE) {
666 		dim = Z_REFVAL_P(dim);
667 	}
668 
669 	switch (Z_TYPE_P(dim)) {
670 		case IS_LONG:
671 			hval = Z_LVAL_P(dim);
672 			goto num_index;
673 		case IS_STRING:
674 			offset_key = Z_STR_P(dim);
675 			goto str_index;
676 		case IS_UNDEF:
677 			/* The array may be destroyed while throwing the notice.
678 			 * Temporarily increase the refcount to detect this situation. */
679 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
680 				GC_ADDREF(ht);
681 			}
682 			zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
683 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
684 				zend_array_destroy(ht);
685 				return 0;
686 			}
687 			if (EG(exception)) {
688 				return 0;
689 			}
690 			ZEND_FALLTHROUGH;
691 		case IS_NULL:
692 			offset_key = ZSTR_EMPTY_ALLOC();
693 			goto str_index;
694 		case IS_DOUBLE:
695 			hval = zend_dval_to_lval(Z_DVAL_P(dim));
696 			if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
697 				/* The array may be destroyed while throwing the notice.
698 				 * Temporarily increase the refcount to detect this situation. */
699 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
700 					GC_ADDREF(ht);
701 				}
702 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
703 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
704 					zend_array_destroy(ht);
705 					return 0;
706 				}
707 				if (EG(exception)) {
708 					return 0;
709 				}
710 			}
711 			goto num_index;
712 		case IS_RESOURCE:
713 			/* The array may be destroyed while throwing the notice.
714 			 * Temporarily increase the refcount to detect this situation. */
715 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
716 				GC_ADDREF(ht);
717 			}
718 			zend_use_resource_as_offset(dim);
719 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
720 				zend_array_destroy(ht);
721 				return 0;
722 			}
723 			if (EG(exception)) {
724 				return 0;
725 			}
726 			hval = Z_RES_HANDLE_P(dim);
727 			goto num_index;
728 		case IS_FALSE:
729 			hval = 0;
730 			goto num_index;
731 		case IS_TRUE:
732 			hval = 1;
733 			goto num_index;
734 		default:
735 			zend_type_error("Illegal offset type in isset or empty");
736 			return 0;
737 	}
738 
739 str_index:
740 	if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
741 		goto num_index;
742 	}
743 	retval = zend_hash_find(ht, offset_key);
744 	if (!retval) {
745 		return 0;
746 	}
747 	if (UNEXPECTED(Z_TYPE_P(retval) == IS_REFERENCE)) {
748 		retval = Z_REFVAL_P(retval);
749 	}
750 	return Z_TYPE_P(retval) > IS_NULL;
751 
752 num_index:
753 	ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
754 	if (UNEXPECTED(Z_TYPE_P(retval) == IS_REFERENCE)) {
755 		retval = Z_REFVAL_P(retval);
756 	}
757 	return (Z_TYPE_P(retval) > IS_NULL);
758 
759 num_undef:
760 	return 0;
761 }
762 
zend_jit_fetch_dim_rw_helper(zend_array * ht,zval * dim)763 static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *dim)
764 {
765 	zend_ulong hval;
766 	zend_string *offset_key;
767 	zval *retval;
768 	zend_execute_data *execute_data;
769 	const zend_op *opline;
770 
771 	if (Z_TYPE_P(dim) == IS_REFERENCE) {
772 		dim = Z_REFVAL_P(dim);
773 	}
774 
775 	switch (Z_TYPE_P(dim)) {
776 		case IS_LONG:
777 			hval = Z_LVAL_P(dim);
778 			goto num_index;
779 		case IS_STRING:
780 			offset_key = Z_STR_P(dim);
781 			goto str_index;
782 		case IS_UNDEF:
783 			execute_data = EG(current_execute_data);
784 			opline = EX(opline);
785 			if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) {
786 				opline = EG(opline_before_exception);
787 			}
788 			if (!zend_jit_undefined_op_helper_write(ht, opline->op2.var)) {
789 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
790 					if (EG(exception)) {
791 						ZVAL_UNDEF(EX_VAR(opline->result.var));
792 					} else {
793 						ZVAL_NULL(EX_VAR(opline->result.var));
794 					}
795 				}
796 				return NULL;
797 			}
798 			ZEND_FALLTHROUGH;
799 		case IS_NULL:
800 			offset_key = ZSTR_EMPTY_ALLOC();
801 			goto str_index;
802 		case IS_DOUBLE:
803 			hval = zend_dval_to_lval(Z_DVAL_P(dim));
804 			if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
805 				/* The array may be destroyed while throwing the notice.
806 				 * Temporarily increase the refcount to detect this situation. */
807 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
808 					GC_ADDREF(ht);
809 				}
810 				execute_data = EG(current_execute_data);
811 				opline = EX(opline);
812 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
813 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
814 					if (!GC_REFCOUNT(ht)) {
815 						zend_array_destroy(ht);
816 					}
817 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
818 						if (EG(exception)) {
819 							ZVAL_UNDEF(EX_VAR(opline->result.var));
820 						} else {
821 							ZVAL_NULL(EX_VAR(opline->result.var));
822 						}
823 					}
824 					return NULL;
825 				}
826 				if (EG(exception)) {
827 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
828 						ZVAL_UNDEF(EX_VAR(opline->result.var));
829 					}
830 					return NULL;
831 				}
832 			}
833 			goto num_index;
834 		case IS_RESOURCE:
835 			/* The array may be destroyed while throwing the notice.
836 			 * Temporarily increase the refcount to detect this situation. */
837 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
838 				GC_ADDREF(ht);
839 			}
840 			execute_data = EG(current_execute_data);
841 			opline = EX(opline);
842 			zend_use_resource_as_offset(dim);
843 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
844 				if (!GC_REFCOUNT(ht)) {
845 					zend_array_destroy(ht);
846 				}
847 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
848 					if (EG(exception)) {
849 						ZVAL_UNDEF(EX_VAR(opline->result.var));
850 					} else {
851 						ZVAL_NULL(EX_VAR(opline->result.var));
852 					}
853 				}
854 				return NULL;
855 			}
856 			if (EG(exception)) {
857 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
858 					ZVAL_UNDEF(EX_VAR(opline->result.var));
859 				}
860 				return NULL;
861 			}
862 			hval = Z_RES_HANDLE_P(dim);
863 			goto num_index;
864 		case IS_FALSE:
865 			hval = 0;
866 			goto num_index;
867 		case IS_TRUE:
868 			hval = 1;
869 			goto num_index;
870 		default:
871 			zend_jit_illegal_offset();
872 			undef_result_after_exception();
873 			return NULL;
874 	}
875 
876 str_index:
877 	if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
878 		goto num_index;
879 	}
880 	retval = zend_hash_find(ht, offset_key);
881 	if (!retval) {
882 		/* Key may be released while throwing the undefined index warning. */
883 		retval = zend_undefined_index_write(ht, offset_key);
884 	}
885 	return retval;
886 
887 num_index:
888 	ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
889 	return retval;
890 
891 num_undef:
892 	return zend_undefined_offset_write(ht, hval);
893 }
894 
zend_jit_fetch_dim_w_helper(zend_array * ht,zval * dim)895 static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim)
896 {
897 	zend_ulong hval;
898 	zend_string *offset_key;
899 	zval *retval;
900 	zend_execute_data *execute_data;
901 	const zend_op *opline;
902 
903 	if (Z_TYPE_P(dim) == IS_REFERENCE) {
904 		dim = Z_REFVAL_P(dim);
905 	}
906 
907 	switch (Z_TYPE_P(dim)) {
908 		case IS_LONG:
909 			hval = Z_LVAL_P(dim);
910 			goto num_index;
911 		case IS_STRING:
912 			offset_key = Z_STR_P(dim);
913 			goto str_index;
914 		case IS_UNDEF:
915 			execute_data = EG(current_execute_data);
916 			opline = EX(opline);
917 			if (!zend_jit_undefined_op_helper_write(ht, opline->op2.var)) {
918 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
919 					if (EG(exception)) {
920 						ZVAL_UNDEF(EX_VAR(opline->result.var));
921 					} else {
922 						ZVAL_NULL(EX_VAR(opline->result.var));
923 					}
924 				}
925 				if (opline->opcode == ZEND_ASSIGN_DIM
926 				 && ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) {
927 					zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
928 				}
929 				return NULL;
930 			}
931 			ZEND_FALLTHROUGH;
932 		case IS_NULL:
933 			offset_key = ZSTR_EMPTY_ALLOC();
934 			goto str_index;
935 		case IS_DOUBLE:
936 			hval = zend_dval_to_lval(Z_DVAL_P(dim));
937 			if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
938 				/* The array may be destroyed while throwing the notice.
939 				 * Temporarily increase the refcount to detect this situation. */
940 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
941 					GC_ADDREF(ht);
942 				}
943 				execute_data = EG(current_execute_data);
944 				opline = EX(opline);
945 				zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
946 				if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
947 					if (!GC_REFCOUNT(ht)) {
948 						zend_array_destroy(ht);
949 					}
950 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
951 						if (EG(exception)) {
952 							ZVAL_UNDEF(EX_VAR(opline->result.var));
953 						} else {
954 							ZVAL_NULL(EX_VAR(opline->result.var));
955 						}
956 					}
957 					return NULL;
958 				}
959 				if (EG(exception)) {
960 					if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
961 						ZVAL_UNDEF(EX_VAR(opline->result.var));
962 					}
963 					return NULL;
964 				}
965 			}
966 			goto num_index;
967 		case IS_RESOURCE:
968 			/* The array may be destroyed while throwing the notice.
969 			 * Temporarily increase the refcount to detect this situation. */
970 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
971 				GC_ADDREF(ht);
972 			}
973 			execute_data = EG(current_execute_data);
974 			opline = EX(opline);
975 			zend_use_resource_as_offset(dim);
976 			if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
977 				if (!GC_REFCOUNT(ht)) {
978 					zend_array_destroy(ht);
979 				}
980 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
981 					if (EG(exception)) {
982 						ZVAL_UNDEF(EX_VAR(opline->result.var));
983 					} else {
984 						ZVAL_NULL(EX_VAR(opline->result.var));
985 					}
986 				}
987 				return NULL;
988 			}
989 			if (EG(exception)) {
990 				if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
991 					ZVAL_UNDEF(EX_VAR(opline->result.var));
992 				}
993 				return NULL;
994 			}
995 			hval = Z_RES_HANDLE_P(dim);
996 			goto num_index;
997 		case IS_FALSE:
998 			hval = 0;
999 			goto num_index;
1000 		case IS_TRUE:
1001 			hval = 1;
1002 			goto num_index;
1003 		default:
1004 			zend_jit_illegal_offset();
1005 			undef_result_after_exception();
1006 			if ((EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA
1007 			 && ((EG(opline_before_exception)+1)->op1_type & (IS_VAR|IS_TMP_VAR))) {
1008 				zend_execute_data *execute_data = EG(current_execute_data);
1009 
1010 				zval_ptr_dtor_nogc(EX_VAR((EG(opline_before_exception)+1)->op1.var));
1011 			}
1012 			return NULL;
1013 	}
1014 
1015 str_index:
1016 	if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
1017 		goto num_index;
1018 	}
1019 	return zend_hash_lookup(ht, offset_key);
1020 
1021 num_index:
1022 	ZEND_HASH_INDEX_LOOKUP(ht, hval, retval);
1023 	return retval;
1024 }
1025 
zend_check_string_offset(zval * dim)1026 static zend_never_inline zend_long zend_check_string_offset(zval *dim/*, int type*/)
1027 {
1028 	zend_long offset;
1029 
1030 try_again:
1031 	switch(Z_TYPE_P(dim)) {
1032 		case IS_LONG:
1033 			return Z_LVAL_P(dim);
1034 		case IS_STRING:
1035 		{
1036 			bool trailing_data = false;
1037 			/* For BC reasons we allow errors so that we can warn on leading numeric string */
1038 			if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL,
1039 					/* allow errors */ true, NULL, &trailing_data)) {
1040 				if (UNEXPECTED(trailing_data)
1041 				 && EG(current_execute_data)->opline->opcode != ZEND_FETCH_DIM_UNSET) {
1042 					zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
1043 				}
1044 				return offset;
1045 			}
1046 			zend_jit_illegal_string_offset(dim);
1047 			return 0;
1048 		}
1049 		case IS_UNDEF:
1050 			zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1051 			ZEND_FALLTHROUGH;
1052 		case IS_DOUBLE:
1053 		case IS_NULL:
1054 		case IS_FALSE:
1055 		case IS_TRUE:
1056 			zend_error(E_WARNING, "String offset cast occurred");
1057 			break;
1058 		case IS_REFERENCE:
1059 			dim = Z_REFVAL_P(dim);
1060 			goto try_again;
1061 		default:
1062 			zend_jit_illegal_string_offset(dim);
1063 			return 0;
1064 	}
1065 
1066 	return zval_get_long_func(dim, /* is_strict */ false);
1067 }
1068 
zend_jit_fetch_dim_str_offset(zend_string * str,zend_long offset)1069 static zend_always_inline zend_string* zend_jit_fetch_dim_str_offset(zend_string *str, zend_long offset)
1070 {
1071 	if (UNEXPECTED((zend_ulong)offset >= (zend_ulong)ZSTR_LEN(str))) {
1072 		if (EXPECTED(offset < 0)) {
1073 			/* Handle negative offset */
1074 			zend_long real_offset = (zend_long)ZSTR_LEN(str) + offset;
1075 
1076 			if (EXPECTED(real_offset >= 0)) {
1077 				return ZSTR_CHAR((zend_uchar)ZSTR_VAL(str)[real_offset]);
1078 			}
1079 		}
1080 		zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset);
1081 		return ZSTR_EMPTY_ALLOC();
1082 	} else {
1083 		return ZSTR_CHAR((zend_uchar)ZSTR_VAL(str)[offset]);
1084 	}
1085 }
1086 
zend_jit_fetch_dim_str_offset_r_helper(zend_string * str,zend_long offset)1087 static zend_string* ZEND_FASTCALL zend_jit_fetch_dim_str_offset_r_helper(zend_string *str, zend_long offset)
1088 {
1089 	return zend_jit_fetch_dim_str_offset(str, offset);
1090 }
1091 
zend_jit_fetch_dim_str_r_helper(zend_string * str,zval * dim)1092 static zend_string* ZEND_FASTCALL zend_jit_fetch_dim_str_r_helper(zend_string *str, zval *dim)
1093 {
1094 	zend_long offset;
1095 
1096 	if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1097 		if (!(GC_FLAGS(str) & IS_STR_INTERNED)) {
1098 			GC_ADDREF(str);
1099 		}
1100 		offset = zend_check_string_offset(dim/*, BP_VAR_R*/);
1101 		if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) {
1102 			zend_string *ret = zend_jit_fetch_dim_str_offset(str, offset);
1103 			zend_string_efree(str);
1104 			return ret;
1105 		}
1106 	} else {
1107 		offset = Z_LVAL_P(dim);
1108 	}
1109 	return zend_jit_fetch_dim_str_offset(str, offset);
1110 }
1111 
zend_jit_fetch_dim_str_is_helper(zend_string * str,zval * dim,zval * result)1112 static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zend_string *str, zval *dim, zval *result)
1113 {
1114 	zend_long offset;
1115 
1116 try_string_offset:
1117 	if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1118 		switch (Z_TYPE_P(dim)) {
1119 			/* case IS_LONG: */
1120 			case IS_STRING:
1121 				if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
1122 					break;
1123 				}
1124 				ZVAL_NULL(result);
1125 				return;
1126 			case IS_UNDEF:
1127 				zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1128 			case IS_DOUBLE:
1129 			case IS_NULL:
1130 			case IS_FALSE:
1131 			case IS_TRUE:
1132 				break;
1133 			case IS_REFERENCE:
1134 				dim = Z_REFVAL_P(dim);
1135 				goto try_string_offset;
1136 			default:
1137 				zend_jit_illegal_string_offset(dim);
1138 				ZVAL_NULL(result);
1139 				return;
1140 		}
1141 
1142 		offset = zval_get_long_func(dim, /* is_strict */ false);
1143 	} else {
1144 		offset = Z_LVAL_P(dim);
1145 	}
1146 
1147 	if ((zend_ulong)offset >= (zend_ulong)ZSTR_LEN(str)) {
1148 		if (offset < 0) {
1149 			/* Handle negative offset */
1150 			zend_long real_offset = (zend_long)ZSTR_LEN(str) + offset;
1151 
1152 			if (real_offset >= 0) {
1153 				ZVAL_CHAR(result, (zend_uchar)ZSTR_VAL(str)[real_offset]);
1154 				return;
1155 			}
1156 		}
1157 		ZVAL_NULL(result);
1158 	} else {
1159 		ZVAL_CHAR(result, (zend_uchar)ZSTR_VAL(str)[offset]);
1160 	}
1161 }
1162 
zend_jit_fetch_dim_obj_r_helper(zval * container,zval * dim,zval * result)1163 static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval *dim, zval *result)
1164 {
1165 	zval *retval;
1166 	zend_object *obj = Z_OBJ_P(container);
1167 
1168 	GC_ADDREF(obj);
1169 	if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1170 		zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1171 		dim = &EG(uninitialized_zval);
1172 	}
1173 
1174 	retval = obj->handlers->read_dimension(obj, dim, BP_VAR_R, result);
1175 
1176 	if (retval) {
1177 		if (result != retval) {
1178 			ZVAL_COPY_DEREF(result, retval);
1179 		} else if (UNEXPECTED(Z_ISREF_P(retval))) {
1180 			zend_unwrap_reference(retval);
1181 		}
1182 	} else {
1183 		ZVAL_NULL(result);
1184 	}
1185 	if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1186 		zend_objects_store_del(obj);
1187 	}
1188 }
1189 
zend_jit_fetch_dim_obj_is_helper(zval * container,zval * dim,zval * result)1190 static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval *dim, zval *result)
1191 {
1192 	zval *retval;
1193 	zend_object *obj = Z_OBJ_P(container);
1194 
1195 	GC_ADDREF(obj);
1196 	if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1197 		zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1198 		dim = &EG(uninitialized_zval);
1199 	}
1200 
1201 	retval = obj->handlers->read_dimension(obj, dim, BP_VAR_IS, result);
1202 
1203 	if (retval) {
1204 		if (result != retval) {
1205 			ZVAL_COPY_DEREF(result, retval);
1206 		} else if (UNEXPECTED(Z_ISREF_P(retval))) {
1207 			zend_unwrap_reference(result);
1208 		}
1209 	} else {
1210 		ZVAL_NULL(result);
1211 	}
1212 	if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1213 		zend_objects_store_del(obj);
1214 	}
1215 }
1216 
zend_assign_to_string_offset(zval * str,zval * dim,zval * value,zval * result)1217 static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result)
1218 {
1219 	zend_uchar c;
1220 	size_t string_len;
1221 	zend_long offset;
1222 	zend_string *s;
1223 
1224 	/* separate string */
1225 	if (Z_REFCOUNTED_P(str) && Z_REFCOUNT_P(str) == 1) {
1226 		s = Z_STR_P(str);
1227 	} else {
1228 		s = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
1229 		ZSTR_H(s) = ZSTR_H(Z_STR_P(str));
1230 		if (Z_REFCOUNTED_P(str)) {
1231 			GC_DELREF(Z_STR_P(str));
1232 		}
1233 		ZVAL_NEW_STR(str, s);
1234 	}
1235 
1236 	if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1237 		/* The string may be destroyed while throwing the notice.
1238 		 * Temporarily increase the refcount to detect this situation. */
1239 		GC_ADDREF(s);
1240 		offset = zend_check_string_offset(dim/*, BP_VAR_W*/);
1241 		if (UNEXPECTED(GC_DELREF(s) == 0)) {
1242 			zend_string_efree(s);
1243 			if (result) {
1244 				ZVAL_NULL(result);
1245 			}
1246 			return;
1247 		}
1248 		if (UNEXPECTED(EG(exception) != NULL)) {
1249 			if (UNEXPECTED(result)) {
1250 				ZVAL_UNDEF(result);
1251 			}
1252 			return;
1253 		}
1254 	} else {
1255 		offset = Z_LVAL_P(dim);
1256 	}
1257 	if (offset < -(zend_long)ZSTR_LEN(s)) {
1258 		/* Error on negative offset */
1259 		zend_error(E_WARNING, "Illegal string offset " ZEND_LONG_FMT, offset);
1260 		if (result) {
1261 			ZVAL_NULL(result);
1262 		}
1263 		return;
1264 	}
1265 
1266 	if (Z_TYPE_P(value) != IS_STRING) {
1267 		zend_string *tmp;
1268 
1269 		/* The string may be destroyed while throwing the notice.
1270 		 * Temporarily increase the refcount to detect this situation. */
1271 		GC_ADDREF(s);
1272 
1273 		if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1274 			const zend_op *op_data = EG(current_execute_data)->opline + 1;
1275 			ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
1276 			zend_jit_undefined_op_helper(op_data->op1.var);
1277 			value = &EG(uninitialized_zval);
1278 		}
1279 
1280 		/* Convert to string, just the time to pick the 1st byte */
1281 		tmp = zval_try_get_string_func(value);
1282 
1283 		if (UNEXPECTED(GC_DELREF(s) == 0)) {
1284 			zend_string_efree(s);
1285 			if (tmp) {
1286 				zend_string_release_ex(tmp, 0);
1287 			}
1288 			if (result) {
1289 				ZVAL_NULL(result);
1290 			}
1291 			return;
1292 		}
1293 		if (UNEXPECTED(!tmp)) {
1294 			if (result) {
1295 				ZVAL_UNDEF(result);
1296 			}
1297 			return;
1298 		}
1299 
1300 		if (UNEXPECTED(!tmp)) {
1301 			if (result) {
1302 				ZVAL_UNDEF(result);
1303 			}
1304 			return;
1305 		}
1306 
1307 		string_len = ZSTR_LEN(tmp);
1308 		c = (zend_uchar)ZSTR_VAL(tmp)[0];
1309 		zend_string_release(tmp);
1310 	} else {
1311 		string_len = Z_STRLEN_P(value);
1312 		c = (zend_uchar)Z_STRVAL_P(value)[0];
1313 	}
1314 
1315 
1316 	if (string_len != 1) {
1317 		if (string_len == 0) {
1318 			/* Error on empty input string */
1319 			zend_throw_error(NULL, "Cannot assign an empty string to a string offset");
1320 			if (result) {
1321 				ZVAL_NULL(result);
1322 			}
1323 			return;
1324 		}
1325 
1326 		/* The string may be destroyed while throwing the notice.
1327 		 * Temporarily increase the refcount to detect this situation. */
1328 		GC_ADDREF(s);
1329 		zend_error(E_WARNING, "Only the first byte will be assigned to the string offset");
1330 		if (UNEXPECTED(GC_DELREF(s) == 0)) {
1331 			zend_string_efree(s);
1332 			if (result) {
1333 				ZVAL_NULL(result);
1334 			}
1335 			return;
1336 		}
1337 		/* Illegal offset assignment */
1338 		if (UNEXPECTED(EG(exception) != NULL)) {
1339 			if (result) {
1340 				ZVAL_UNDEF(result);
1341 			}
1342 			return;
1343 		}
1344 	}
1345 
1346 	if (offset < 0) { /* Handle negative offset */
1347 		offset += (zend_long)ZSTR_LEN(s);
1348 	}
1349 
1350 	if ((size_t)offset >= ZSTR_LEN(s)) {
1351 		/* Extend string if needed */
1352 		zend_long old_len = ZSTR_LEN(s);
1353 		ZVAL_NEW_STR(str, zend_string_extend(s, (size_t)offset + 1, 0));
1354 		memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
1355 		Z_STRVAL_P(str)[offset+1] = 0;
1356 	} else {
1357 		zend_string_forget_hash_val(Z_STR_P(str));
1358 	}
1359 
1360 	Z_STRVAL_P(str)[offset] = c;
1361 
1362 	if (result) {
1363 		/* Return the new character */
1364 		ZVAL_CHAR(result, c);
1365 	}
1366 }
1367 
zend_jit_fetch_dim_obj_helper(zval * object_ptr,zval * dim,zval * result,int type)1368 static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval *object_ptr, zval *dim, zval *result, int type)
1369 {
1370 	zval *retval;
1371 
1372 	if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
1373 		zend_object *obj = Z_OBJ_P(object_ptr);
1374 
1375 		GC_ADDREF(obj);
1376 		if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) {
1377 			const zend_op *opline = EG(current_execute_data)->opline;
1378 			zend_jit_undefined_op_helper(opline->op2.var);
1379 			dim = &EG(uninitialized_zval);
1380 		}
1381 
1382 		retval = obj->handlers->read_dimension(obj, dim, type, result);
1383 		if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
1384 			zend_class_entry *ce = obj->ce;
1385 
1386 			ZVAL_NULL(result);
1387 			zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
1388 		} else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) {
1389 			if (!Z_ISREF_P(retval)) {
1390 				if (result != retval) {
1391 					ZVAL_COPY(result, retval);
1392 					retval = result;
1393 				}
1394 				if (Z_TYPE_P(retval) != IS_OBJECT) {
1395 					zend_class_entry *ce = obj->ce;
1396 					zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
1397 				}
1398 			} else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) {
1399 				ZVAL_UNREF(retval);
1400 			}
1401 			if (result != retval) {
1402 				ZVAL_INDIRECT(result, retval);
1403 			}
1404 		} else {
1405 			ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
1406 			ZVAL_UNDEF(result);
1407 		}
1408 		if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1409 			zend_objects_store_del(obj);
1410 		}
1411 	} else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
1412 		if (!dim) {
1413 			zend_throw_error(NULL, "[] operator not supported for strings");
1414 		} else {
1415 			if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1416 				zend_check_string_offset(dim/*, BP_VAR_RW*/);
1417 			}
1418 			zend_wrong_string_offset_error();
1419 		}
1420 		ZVAL_UNDEF(result);
1421 	} else if (Z_TYPE_P(object_ptr) == IS_FALSE) {
1422 		zend_array *arr = zend_new_array(0);
1423 		ZVAL_ARR(object_ptr, arr);
1424 		GC_ADDREF(arr);
1425 		zend_false_to_array_deprecated();
1426 		if (UNEXPECTED(GC_DELREF(arr) == 0)) {
1427 			zend_array_destroy(arr);
1428 			ZVAL_NULL(result);
1429 			return;
1430 		}
1431 		SEPARATE_ARRAY(object_ptr);
1432 		arr = Z_ARRVAL_P(object_ptr);
1433 		zval *var;
1434 		if (dim) {
1435 			if (type == BP_VAR_W) {
1436 				var = zend_jit_fetch_dim_w_helper(arr, dim);
1437 			} else {
1438 				ZEND_ASSERT(type == BP_VAR_RW);
1439 				var = zend_jit_fetch_dim_rw_helper(arr, dim);
1440 			}
1441 		} else {
1442 			var = zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval));
1443 		}
1444 		if (var) {
1445 			ZVAL_INDIRECT(result, var);
1446 		} else {
1447 			ZVAL_UNDEF(result);
1448 		}
1449 	} else {
1450 		if (type == BP_VAR_UNSET) {
1451 			zend_throw_error(NULL, "Cannot unset offset in a non-array variable");
1452 			ZVAL_UNDEF(result);
1453 		} else {
1454 			zend_throw_error(NULL, "Cannot use a scalar value as an array");
1455 			ZVAL_UNDEF(result);
1456 		}
1457 	}
1458 }
1459 
zend_jit_fetch_dim_obj_w_helper(zval * object_ptr,zval * dim,zval * result)1460 static void ZEND_FASTCALL zend_jit_fetch_dim_obj_w_helper(zval *object_ptr, zval *dim, zval *result)
1461 {
1462 	zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_W);
1463 }
1464 
zend_jit_fetch_dim_obj_rw_helper(zval * object_ptr,zval * dim,zval * result)1465 static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zval *dim, zval *result)
1466 {
1467 	zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_RW);
1468 }
1469 
1470 //static void ZEND_FASTCALL zend_jit_fetch_dim_obj_unset_helper(zval *object_ptr, zval *dim, zval *result)
1471 //{
1472 //	zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_UNSET);
1473 //}
1474 
zend_jit_assign_dim_helper(zval * object_ptr,zval * dim,zval * value,zval * result)1475 static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim, zval *value, zval *result)
1476 {
1477 	if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
1478 		zend_object *obj = Z_OBJ_P(object_ptr);
1479 
1480 		GC_ADDREF(obj);
1481 		if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1482 			const zend_op *opline = EG(current_execute_data)->opline;
1483 			zend_jit_undefined_op_helper(opline->op2.var);
1484 			dim = &EG(uninitialized_zval);
1485 		}
1486 
1487 		if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1488 			const zend_op *op_data = EG(current_execute_data)->opline + 1;
1489 			ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
1490 			zend_jit_undefined_op_helper(op_data->op1.var);
1491 			value = &EG(uninitialized_zval);
1492 		} else {
1493 			ZVAL_DEREF(value);
1494 		}
1495 
1496 		obj->handlers->write_dimension(obj, dim, value);
1497 		if (result) {
1498 			if (EXPECTED(!EG(exception))) {
1499 				ZVAL_COPY(result, value);
1500 			} else {
1501 				ZVAL_UNDEF(result);
1502 			}
1503 		}
1504 		if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1505 			zend_objects_store_del(obj);
1506 		}
1507 		return;
1508 	} else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && EXPECTED(dim != NULL)) {
1509 		zend_assign_to_string_offset(object_ptr, dim, value, result);
1510 		return;
1511 	}
1512 
1513 	if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1514 		const zend_op *op_data = EG(current_execute_data)->opline + 1;
1515 		ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
1516 		zend_jit_undefined_op_helper(op_data->op1.var);
1517 		value = &EG(uninitialized_zval);
1518 	}
1519 
1520 	if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
1521 		zend_throw_error(NULL, "[] operator not supported for strings");
1522 		if (result) {
1523 			ZVAL_UNDEF(result);
1524 		}
1525 	} else if (Z_TYPE_P(object_ptr) == IS_FALSE) {
1526 		zend_array *arr = zend_new_array(0);
1527 		ZVAL_ARR(object_ptr, arr);
1528 		GC_ADDREF(arr);
1529 		zend_false_to_array_deprecated();
1530 		if (UNEXPECTED(GC_DELREF(arr) == 0)) {
1531 			zend_array_destroy(arr);
1532 			if (result) {
1533 				ZVAL_NULL(result);
1534 			}
1535 			return;
1536 		}
1537 		SEPARATE_ARRAY(object_ptr);
1538 		arr = Z_ARRVAL_P(object_ptr);
1539 		zval *var = dim
1540 			? zend_jit_fetch_dim_w_helper(arr, dim)
1541 			: zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval));
1542 		if (!var) {
1543 			if (result) {
1544 				ZVAL_UNDEF(result);
1545 			}
1546 			return;
1547 		}
1548 
1549 		ZVAL_COPY_DEREF(var, value);
1550 		if (result) {
1551 			ZVAL_COPY(result, var);
1552 		}
1553 	} else {
1554 		if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1555 			const zend_op *opline = EG(current_execute_data)->opline;
1556 			zend_jit_undefined_op_helper(opline->op2.var);
1557 			dim = &EG(uninitialized_zval);
1558 		}
1559 		zend_throw_error(NULL, "Cannot use a scalar value as an array");
1560 		if (result) {
1561 			ZVAL_UNDEF(result);
1562 		}
1563 	}
1564 }
1565 
zend_jit_assign_dim_op_helper(zval * container,zval * dim,zval * value,binary_op_type binary_op)1566 static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *dim, zval *value, binary_op_type binary_op)
1567 {
1568 	if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1569 		zend_object *obj = Z_OBJ_P(container);
1570 		zval *z;
1571 		zval rv, res;
1572 
1573 		GC_ADDREF(obj);
1574 		if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) {
1575 			const zend_op *opline = EG(current_execute_data)->opline;
1576 			zend_jit_undefined_op_helper(opline->op2.var);
1577 			dim = &EG(uninitialized_zval);
1578 		}
1579 
1580 		z = obj->handlers->read_dimension(obj, dim, BP_VAR_R, &rv);
1581 		if (z != NULL) {
1582 
1583 			if (binary_op(&res, Z_ISREF_P(z) ? Z_REFVAL_P(z) : z, value) == SUCCESS) {
1584 				obj->handlers->write_dimension(obj, dim, &res);
1585 			}
1586 			if (z == &rv) {
1587 				zval_ptr_dtor(&rv);
1588 			}
1589 			zval_ptr_dtor(&res);
1590 		} else {
1591 			zend_error(E_WARNING, "Attempt to assign property of non-object");
1592 		}
1593 		if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1594 			zend_objects_store_del(obj);
1595 //???		if (retval) {
1596 //???			ZVAL_NULL(retval);
1597 //???		}
1598 		}
1599 	} else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1600 		if (!dim) {
1601 			zend_throw_error(NULL, "[] operator not supported for strings");
1602 		} else {
1603 			if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1604 				zend_check_string_offset(dim/*, BP_VAR_RW*/);
1605 			}
1606 			zend_wrong_string_offset_error();
1607 		}
1608 	} else if (Z_TYPE_P(container) == IS_FALSE) {
1609 		zend_array *arr = zend_new_array(0);
1610 		ZVAL_ARR(container, arr);
1611 		GC_ADDREF(arr);
1612 		zend_false_to_array_deprecated();
1613 		if (UNEXPECTED(GC_DELREF(arr) == 0)) {
1614 			zend_array_destroy(arr);
1615 			return;
1616 		}
1617 		SEPARATE_ARRAY(container);
1618 		arr = Z_ARRVAL_P(container);
1619 		zval *var = dim
1620 			? zend_jit_fetch_dim_rw_helper(arr, dim)
1621 			: zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval));
1622 		if (var) {
1623 			binary_op(var, var, value);
1624 		}
1625 	} else {
1626 		zend_throw_error(NULL, "Cannot use a scalar value as an array");
1627 	}
1628 }
1629 
zend_jit_fast_assign_concat_helper(zval * op1,zval * op2)1630 static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op2)
1631 {
1632 	size_t op1_len = Z_STRLEN_P(op1);
1633 	size_t op2_len = Z_STRLEN_P(op2);
1634 	size_t result_len = op1_len + op2_len;
1635 	zend_string *result_str;
1636 
1637 	if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
1638 		zend_throw_error(NULL, "String size overflow");
1639 		return;
1640 	}
1641 
1642 	do {
1643 		if (Z_REFCOUNTED_P(op1)) {
1644 			if (GC_REFCOUNT(Z_STR_P(op1)) == 1) {
1645 				result_str = perealloc(Z_STR_P(op1), ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(result_len)), 0);
1646 				ZSTR_LEN(result_str) = result_len;
1647 				zend_string_forget_hash_val(result_str);
1648 				if (UNEXPECTED(Z_STR_P(op1) == Z_STR_P(op2))) {
1649 					ZVAL_NEW_STR(op2, result_str);
1650 				}
1651 				break;
1652 			}
1653 			GC_DELREF(Z_STR_P(op1));
1654 		}
1655 		result_str = zend_string_alloc(result_len, 0);
1656 		memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
1657 	} while(0);
1658 
1659 	ZVAL_NEW_STR(op1, result_str);
1660 	memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1661 	ZSTR_VAL(result_str)[result_len] = '\0';
1662 }
1663 
zend_jit_fast_concat_helper(zval * result,zval * op1,zval * op2)1664 static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, zval *op2)
1665 {
1666 	size_t op1_len = Z_STRLEN_P(op1);
1667 	size_t op2_len = Z_STRLEN_P(op2);
1668 	size_t result_len = op1_len + op2_len;
1669 	zend_string *result_str;
1670 
1671 	if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
1672 		zend_throw_error(NULL, "String size overflow");
1673 		return;
1674 	}
1675 
1676 	result_str = zend_string_alloc(result_len, 0);
1677 	memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
1678 
1679 	ZVAL_NEW_STR(result, result_str);
1680 
1681 	memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1682 	ZSTR_VAL(result_str)[result_len] = '\0';
1683 }
1684 
zend_jit_fast_concat_tmp_helper(zval * result,zval * op1,zval * op2)1685 static void ZEND_FASTCALL zend_jit_fast_concat_tmp_helper(zval *result, zval *op1, zval *op2)
1686 {
1687 	zend_string *op1_str = Z_STR_P(op1);
1688 	size_t op1_len = ZSTR_LEN(op1_str);
1689 	size_t op2_len = Z_STRLEN_P(op2);
1690 	size_t result_len = op1_len + op2_len;
1691 	zend_string *result_str;
1692 
1693 	if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
1694 		zend_throw_error(NULL, "String size overflow");
1695 		return;
1696 	}
1697 
1698 	do {
1699 		if (!ZSTR_IS_INTERNED(op1_str)) {
1700 			if (GC_REFCOUNT(op1_str) == 1) {
1701 				Z_STR_P(op1) = result_str =
1702 					perealloc(op1_str, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(result_len)), 0);
1703 				ZSTR_LEN(result_str) = result_len;
1704 				zend_string_forget_hash_val(result_str);
1705 				break;
1706 			}
1707 			GC_DELREF(op1_str);
1708 		}
1709 		result_str = zend_string_alloc(result_len, 0);
1710 		memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_str), op1_len);
1711 	} while (0);
1712 
1713 	ZVAL_NEW_STR(result, result_str);
1714 
1715 	memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1716 	ZSTR_VAL(result_str)[result_len] = '\0';
1717 }
1718 
zend_jit_isset_dim_helper(zval * container,zval * offset)1719 static int ZEND_FASTCALL zend_jit_isset_dim_helper(zval *container, zval *offset)
1720 {
1721 	if (UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
1722 		zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1723 		offset = &EG(uninitialized_zval);
1724 	}
1725 
1726 	if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1727 		return Z_OBJ_HT_P(container)->has_dimension(Z_OBJ_P(container), offset, 0);
1728 	} else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
1729 		zend_long lval;
1730 
1731 		if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
1732 			lval = Z_LVAL_P(offset);
1733 isset_str_offset:
1734 			if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
1735 				lval += (zend_long)Z_STRLEN_P(container);
1736 			}
1737 			if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
1738 				return 1;
1739 			}
1740 		} else {
1741 			ZVAL_DEREF(offset);
1742 			if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
1743 					|| (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
1744 						&& IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, false))) {
1745 				lval = zval_get_long_ex(offset, /* is_strict */ true);
1746 				goto isset_str_offset;
1747 			}
1748 		}
1749 	}
1750 	return 0;
1751 }
1752 
zend_jit_free_call_frame(zend_execute_data * call)1753 static void ZEND_FASTCALL zend_jit_free_call_frame(zend_execute_data *call)
1754 {
1755 	zend_vm_stack_free_call_frame(call);
1756 }
1757 
zend_jit_fetch_global_helper(zend_string * varname,void ** cache_slot)1758 static zend_reference* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_string *varname, void **cache_slot)
1759 {
1760 	zval *value;
1761 	uintptr_t idx;
1762 	zend_reference *ref;
1763 
1764 	/* We store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1765 	idx = (uintptr_t)CACHED_PTR_EX(cache_slot) - 1;
1766 	if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) {
1767 		Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
1768 
1769 		if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
1770 	        (EXPECTED(p->key == varname) ||
1771 	         (EXPECTED(p->h == ZSTR_H(varname)) &&
1772 	          EXPECTED(p->key != NULL) &&
1773 	          EXPECTED(zend_string_equal_content(p->key, varname))))) {
1774 
1775 			value = (zval*)p; /* value = &p->val; */
1776 			goto check_indirect;
1777 		}
1778 	}
1779 
1780 	value = zend_hash_find_known_hash(&EG(symbol_table), varname);
1781 	if (UNEXPECTED(value == NULL)) {
1782 		value = zend_hash_add_new(&EG(symbol_table), varname, &EG(uninitialized_zval));
1783 		idx = (char*)value - (char*)EG(symbol_table).arData;
1784 		/* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1785 		CACHE_PTR_EX(cache_slot, (void*)(idx + 1));
1786 	} else {
1787 		idx = (char*)value - (char*)EG(symbol_table).arData;
1788 		/* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1789 		CACHE_PTR_EX(cache_slot, (void*)(idx + 1));
1790 check_indirect:
1791 		/* GLOBAL variable may be an INDIRECT pointer to CV */
1792 		if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
1793 			value = Z_INDIRECT_P(value);
1794 			if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1795 				ZVAL_NULL(value);
1796 			}
1797 		}
1798 	}
1799 
1800 	if (UNEXPECTED(!Z_ISREF_P(value))) {
1801 		ZVAL_MAKE_REF_EX(value, 2);
1802 		ref = Z_REF_P(value);
1803 	} else {
1804 		ref = Z_REF_P(value);
1805 		GC_ADDREF(ref);
1806 	}
1807 
1808 	return ref;
1809 }
1810 
zend_jit_verify_arg_slow(zval * arg,zend_arg_info * arg_info)1811 static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg_info)
1812 {
1813 	zend_execute_data *execute_data = EG(current_execute_data);
1814 	const zend_op *opline = EX(opline);
1815 	void **cache_slot = CACHE_ADDR(opline->extended_value);
1816 	bool ret = zend_check_user_type_slow(
1817 		&arg_info->type, arg, /* ref */ NULL, cache_slot, /* is_return_type */ false);
1818 	if (UNEXPECTED(!ret)) {
1819 		zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg);
1820 		return 0;
1821 	}
1822 	return ret;
1823 }
1824 
zend_jit_verify_return_slow(zval * arg,const zend_op_array * op_array,zend_arg_info * arg_info,void ** cache_slot)1825 static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot)
1826 {
1827 	if (UNEXPECTED(!zend_check_user_type_slow(
1828 			&arg_info->type, arg, /* ref */ NULL, cache_slot, /* is_return_type */ true))) {
1829 		zend_verify_return_error((zend_function*)op_array, arg);
1830 	}
1831 }
1832 
zend_jit_fetch_obj_r_slow(zend_object * zobj)1833 static void ZEND_FASTCALL zend_jit_fetch_obj_r_slow(zend_object *zobj)
1834 {
1835 	zval *retval;
1836 	zend_execute_data *execute_data = EG(current_execute_data);
1837 	const zend_op *opline = EX(opline);
1838 	zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
1839 	zval *result = EX_VAR(opline->result.var);
1840 	void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
1841 
1842 	retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, result);
1843 	if (retval != result) {
1844 		ZVAL_COPY_DEREF(result, retval);
1845 	} else if (UNEXPECTED(Z_ISREF_P(retval))) {
1846 		zend_unwrap_reference(retval);
1847 	}
1848 }
1849 
zend_jit_fetch_obj_r_dynamic(zend_object * zobj,intptr_t prop_offset)1850 static void ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic(zend_object *zobj, intptr_t prop_offset)
1851 {
1852 	if (zobj->properties) {
1853 		zval *retval;
1854 		zend_execute_data *execute_data = EG(current_execute_data);
1855 		const zend_op *opline = EX(opline);
1856 		zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
1857 		zval *result = EX_VAR(opline->result.var);
1858 		void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
1859 
1860 		if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
1861 			intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
1862 
1863 			if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
1864 				Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
1865 
1866 				if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
1867 			        (EXPECTED(p->key == name) ||
1868 			         (EXPECTED(p->h == ZSTR_H(name)) &&
1869 			          EXPECTED(p->key != NULL) &&
1870 			          EXPECTED(ZSTR_LEN(p->key) == ZSTR_LEN(name)) &&
1871 			          EXPECTED(memcmp(ZSTR_VAL(p->key), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)))) {
1872 					ZVAL_COPY_DEREF(result, &p->val);
1873 					return;
1874 				}
1875 			}
1876 			CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
1877 		}
1878 
1879 		retval = zend_hash_find_known_hash(zobj->properties, name);
1880 
1881 		if (EXPECTED(retval)) {
1882 			intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
1883 			CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
1884 			ZVAL_COPY_DEREF(result, retval);
1885 			return;
1886 		}
1887 	}
1888 	zend_jit_fetch_obj_r_slow(zobj);
1889 }
1890 
zend_jit_fetch_obj_is_slow(zend_object * zobj)1891 static void ZEND_FASTCALL zend_jit_fetch_obj_is_slow(zend_object *zobj)
1892 {
1893 	zval *retval;
1894 	zend_execute_data *execute_data = EG(current_execute_data);
1895 	const zend_op *opline = EX(opline);
1896 	zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
1897 	zval *result = EX_VAR(opline->result.var);
1898 	void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
1899 
1900 	retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, result);
1901 	if (retval != result) {
1902 		ZVAL_COPY_DEREF(result, retval);
1903 	} else if (UNEXPECTED(Z_ISREF_P(retval))) {
1904 		zend_unwrap_reference(retval);
1905 	}
1906 }
1907 
zend_jit_fetch_obj_is_dynamic(zend_object * zobj,intptr_t prop_offset)1908 static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intptr_t prop_offset)
1909 {
1910 	if (zobj->properties) {
1911 		zval *retval;
1912 		zend_execute_data *execute_data = EG(current_execute_data);
1913 		const zend_op *opline = EX(opline);
1914 		zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
1915 		zval *result = EX_VAR(opline->result.var);
1916 		void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
1917 
1918 		if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
1919 			intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
1920 
1921 			if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
1922 				Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
1923 
1924 				if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
1925 			        (EXPECTED(p->key == name) ||
1926 			         (EXPECTED(p->h == ZSTR_H(name)) &&
1927 			          EXPECTED(p->key != NULL) &&
1928 			          EXPECTED(ZSTR_LEN(p->key) == ZSTR_LEN(name)) &&
1929 			          EXPECTED(memcmp(ZSTR_VAL(p->key), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)))) {
1930 					ZVAL_COPY_DEREF(result, &p->val);
1931 					return;
1932 				}
1933 			}
1934 			CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
1935 		}
1936 
1937 		retval = zend_hash_find_known_hash(zobj->properties, name);
1938 
1939 		if (EXPECTED(retval)) {
1940 			intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
1941 			CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
1942 			ZVAL_COPY_DEREF(result, retval);
1943 			return;
1944 		}
1945 	}
1946 	zend_jit_fetch_obj_is_slow(zobj);
1947 }
1948 
promotes_to_array(zval * val)1949 static zend_always_inline bool promotes_to_array(zval *val) {
1950 	return Z_TYPE_P(val) <= IS_FALSE
1951 		|| (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE);
1952 }
1953 
check_type_array_assignable(zend_type type)1954 static zend_always_inline bool check_type_array_assignable(zend_type type) {
1955 	if (!ZEND_TYPE_IS_SET(type)) {
1956 		return 1;
1957 	}
1958 	return (ZEND_TYPE_FULL_MASK(type) & (MAY_BE_ITERABLE|MAY_BE_ARRAY)) != 0;
1959 }
1960 
zend_object_fetch_property_type_info(zend_object * obj,zval * slot)1961 static zend_property_info *zend_object_fetch_property_type_info(
1962 		zend_object *obj, zval *slot)
1963 {
1964 	if (EXPECTED(!ZEND_CLASS_HAS_TYPE_HINTS(obj->ce))) {
1965 		return NULL;
1966 	}
1967 
1968 	/* Not a declared property */
1969 	if (UNEXPECTED(slot < obj->properties_table ||
1970 			slot >= obj->properties_table + obj->ce->default_properties_count)) {
1971 		return NULL;
1972 	}
1973 
1974 	return zend_get_typed_property_info_for_slot(obj, slot);
1975 }
1976 
zend_throw_auto_init_in_prop_error(zend_property_info * prop,const char * type)1977 static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error(zend_property_info *prop, const char *type) {
1978 	zend_string *type_str = zend_type_to_string(prop->type);
1979 	zend_type_error(
1980 		"Cannot auto-initialize an %s inside property %s::$%s of type %s",
1981 		type,
1982 		ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name),
1983 		ZSTR_VAL(type_str)
1984 	);
1985 	zend_string_release(type_str);
1986 }
1987 
zend_throw_access_uninit_prop_by_ref_error(zend_property_info * prop)1988 static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_error(
1989 		zend_property_info *prop) {
1990 	zend_throw_error(NULL,
1991 		"Cannot access uninitialized non-nullable property %s::$%s by reference",
1992 		ZSTR_VAL(prop->ce->name),
1993 		zend_get_unmangled_property_name(prop->name));
1994 }
1995 
zend_handle_fetch_obj_flags(zval * result,zval * ptr,zend_object * obj,zend_property_info * prop_info,uint32_t flags)1996 static zend_never_inline bool zend_handle_fetch_obj_flags(
1997 		zval *result, zval *ptr, zend_object *obj, zend_property_info *prop_info, uint32_t flags)
1998 {
1999 	switch (flags) {
2000 		case ZEND_FETCH_DIM_WRITE:
2001 			if (promotes_to_array(ptr)) {
2002 				if (!prop_info) {
2003 					prop_info = zend_object_fetch_property_type_info(obj, ptr);
2004 					if (!prop_info) {
2005 						break;
2006 					}
2007 				}
2008 				if (!check_type_array_assignable(prop_info->type)) {
2009 					zend_throw_auto_init_in_prop_error(prop_info, "array");
2010 					if (result) ZVAL_ERROR(result);
2011 					return 0;
2012 				}
2013 			}
2014 			break;
2015 		case ZEND_FETCH_REF:
2016 			if (Z_TYPE_P(ptr) != IS_REFERENCE) {
2017 				if (!prop_info) {
2018 					prop_info = zend_object_fetch_property_type_info(obj, ptr);
2019 					if (!prop_info) {
2020 						break;
2021 					}
2022 				}
2023 				if (Z_TYPE_P(ptr) == IS_UNDEF) {
2024 					if (!ZEND_TYPE_ALLOW_NULL(prop_info->type)) {
2025 						zend_throw_access_uninit_prop_by_ref_error(prop_info);
2026 						if (result) ZVAL_ERROR(result);
2027 						return 0;
2028 					}
2029 					ZVAL_NULL(ptr);
2030 				}
2031 
2032 				ZVAL_NEW_REF(ptr, ptr);
2033 				ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(ptr), prop_info);
2034 			}
2035 			break;
2036 		EMPTY_SWITCH_DEFAULT_CASE()
2037 	}
2038 	return 1;
2039 }
2040 
zend_jit_fetch_obj_w_slow(zend_object * zobj)2041 static void ZEND_FASTCALL zend_jit_fetch_obj_w_slow(zend_object *zobj)
2042 {
2043 	zval *retval;
2044 	zend_execute_data *execute_data = EG(current_execute_data);
2045 	const zend_op *opline = EX(opline);
2046 	zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2047 	zval *result = EX_VAR(opline->result.var);
2048 	void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2049 
2050 	retval = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_W, cache_slot);
2051 	if (NULL == retval) {
2052 		retval = zobj->handlers->read_property(zobj, name, BP_VAR_W, cache_slot, result);
2053 		if (retval == result) {
2054 			if (UNEXPECTED(Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1)) {
2055 				ZVAL_UNREF(retval);
2056 			}
2057 			return;
2058 		}
2059 		if (UNEXPECTED(EG(exception))) {
2060 			ZVAL_ERROR(result);
2061 			return;
2062 		}
2063 	} else if (UNEXPECTED(Z_ISERROR_P(retval))) {
2064 		ZVAL_ERROR(result);
2065 		return;
2066 	}
2067 
2068 	ZVAL_INDIRECT(result, retval);
2069 
2070 	/* Support for typed properties */
2071 	do {
2072 		uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
2073 
2074 		if (flags) {
2075 			zend_property_info *prop_info = NULL;
2076 
2077 			if (opline->op2_type == IS_CONST) {
2078 				prop_info = CACHED_PTR_EX(cache_slot + 2);
2079 				if (!prop_info) {
2080 					break;
2081 				}
2082 			}
2083 			if (UNEXPECTED(!zend_handle_fetch_obj_flags(result, retval, zobj, prop_info, flags))) {
2084 				return;
2085 			}
2086 		}
2087 	} while (0);
2088 
2089 	if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
2090 		ZVAL_NULL(retval);
2091 	}
2092 }
2093 
zend_jit_check_array_promotion(zval * val,zend_property_info * prop)2094 static void ZEND_FASTCALL zend_jit_check_array_promotion(zval *val, zend_property_info *prop)
2095 {
2096 	zend_execute_data *execute_data = EG(current_execute_data);
2097 	const zend_op *opline = execute_data->opline;
2098 	zval *result = EX_VAR(opline->result.var);
2099 
2100 	if ((Z_TYPE_P(val) <= IS_FALSE
2101 		|| (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE))
2102 		&& ZEND_TYPE_IS_SET(prop->type)
2103 		&& (ZEND_TYPE_FULL_MASK(prop->type) & (MAY_BE_ITERABLE|MAY_BE_ARRAY)) == 0) {
2104 		zend_string *type_str = zend_type_to_string(prop->type);
2105 		zend_type_error(
2106 			"Cannot auto-initialize an array inside property %s::$%s of type %s",
2107 			ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name),
2108 			ZSTR_VAL(type_str)
2109 		);
2110 		zend_string_release(type_str);
2111 		ZVAL_ERROR(result);
2112 	} else {
2113 		ZVAL_INDIRECT(result, val);
2114 	}
2115 }
2116 
zend_jit_create_typed_ref(zval * val,zend_property_info * prop,zval * result)2117 static void ZEND_FASTCALL zend_jit_create_typed_ref(zval *val, zend_property_info *prop, zval *result)
2118 {
2119 	if (!Z_ISREF_P(val)) {
2120 		ZVAL_NEW_REF(val, val);
2121 		ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(val), prop);
2122 	}
2123 	ZVAL_INDIRECT(result, val);
2124 }
2125 
zend_jit_extract_helper(zend_refcounted * garbage)2126 static void ZEND_FASTCALL zend_jit_extract_helper(zend_refcounted *garbage)
2127 {
2128 	zend_execute_data *execute_data = EG(current_execute_data);
2129 	const zend_op *opline = execute_data->opline;
2130 	zval *zv = EX_VAR(opline->result.var);
2131 
2132 	if (EXPECTED(Z_TYPE_P(zv) == IS_INDIRECT)) {
2133 		ZVAL_COPY(zv, Z_INDIRECT_P(zv));
2134 	}
2135 	rc_dtor_func(garbage);
2136 }
2137 
zend_jit_vm_stack_free_args_helper(zend_execute_data * call)2138 static void ZEND_FASTCALL zend_jit_vm_stack_free_args_helper(zend_execute_data *call)
2139 {
2140 	zend_vm_stack_free_args(call);
2141 }
2142 
zend_jit_assign_to_typed_ref_helper(zend_reference * ref,zval * value,zend_uchar value_type)2143 static zend_always_inline zval* zend_jit_assign_to_typed_ref_helper(zend_reference *ref, zval *value, zend_uchar value_type)
2144 {
2145 	zval variable;
2146 
2147 	ZVAL_REF(&variable, ref);
2148 	return zend_assign_to_variable(&variable, value, value_type, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)));
2149 }
2150 
zend_jit_assign_const_to_typed_ref(zend_reference * ref,zval * value)2151 static zval* ZEND_FASTCALL zend_jit_assign_const_to_typed_ref(zend_reference *ref, zval *value)
2152 {
2153 	return zend_jit_assign_to_typed_ref_helper(ref, value, IS_CONST);
2154 }
2155 
zend_jit_assign_tmp_to_typed_ref(zend_reference * ref,zval * value)2156 static zval* ZEND_FASTCALL zend_jit_assign_tmp_to_typed_ref(zend_reference *ref, zval *value)
2157 {
2158 	return zend_jit_assign_to_typed_ref_helper(ref, value, IS_TMP_VAR);
2159 }
2160 
zend_jit_assign_var_to_typed_ref(zend_reference * ref,zval * value)2161 static zval* ZEND_FASTCALL zend_jit_assign_var_to_typed_ref(zend_reference *ref, zval *value)
2162 {
2163 	return zend_jit_assign_to_typed_ref_helper(ref, value, IS_VAR);
2164 }
2165 
zend_jit_assign_cv_to_typed_ref(zend_reference * ref,zval * value)2166 static zval* ZEND_FASTCALL zend_jit_assign_cv_to_typed_ref(zend_reference *ref, zval *value)
2167 {
2168 	if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2169 		const zend_op *opline = EG(current_execute_data)->opline;
2170 		uint32_t var;
2171 		if (opline->opcode == ZEND_ASSIGN) {
2172 			var = opline->op2.var;
2173 		} else {
2174 			ZEND_ASSERT((opline + 1)->opcode == ZEND_OP_DATA);
2175 			var = (opline + 1)->op1.var;
2176 		}
2177 		zend_jit_undefined_op_helper(var);
2178 		value = &EG(uninitialized_zval);
2179 	}
2180 	return zend_jit_assign_to_typed_ref_helper(ref, value, IS_CV);
2181 }
2182 
2183 
zend_jit_get_prop_not_accepting_double(zend_reference * ref)2184 static zend_property_info *zend_jit_get_prop_not_accepting_double(zend_reference *ref)
2185 {
2186 	zend_property_info *prop;
2187 	ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
2188 		if (!(ZEND_TYPE_FULL_MASK(prop->type) & MAY_BE_DOUBLE)) {
2189 			return prop;
2190 		}
2191 	} ZEND_REF_FOREACH_TYPE_SOURCES_END();
2192 	return NULL;
2193 }
2194 
zend_jit_throw_inc_ref_error(zend_reference * ref,zend_property_info * error_prop)2195 static ZEND_COLD void zend_jit_throw_inc_ref_error(zend_reference *ref, zend_property_info *error_prop)
2196 {
2197 	zend_string *type_str = zend_type_to_string(error_prop->type);
2198 
2199 	zend_type_error(
2200 		"Cannot increment a reference held by property %s::$%s of type %s past its maximal value",
2201 		ZSTR_VAL(error_prop->ce->name),
2202 		zend_get_unmangled_property_name(error_prop->name),
2203 		ZSTR_VAL(type_str));
2204 	zend_string_release(type_str);
2205 }
2206 
zend_jit_throw_dec_ref_error(zend_reference * ref,zend_property_info * error_prop)2207 static ZEND_COLD void zend_jit_throw_dec_ref_error(zend_reference *ref, zend_property_info *error_prop)
2208 {
2209 	zend_string *type_str = zend_type_to_string(error_prop->type);
2210 
2211 	zend_type_error(
2212 		"Cannot decrement a reference held by property %s::$%s of type %s past its minimal value",
2213 		ZSTR_VAL(error_prop->ce->name),
2214 		zend_get_unmangled_property_name(error_prop->name),
2215 		ZSTR_VAL(type_str));
2216 	zend_string_release(type_str);
2217 }
2218 
zend_jit_pre_inc_typed_ref(zend_reference * ref,zval * ret)2219 static void ZEND_FASTCALL zend_jit_pre_inc_typed_ref(zend_reference *ref, zval *ret)
2220 {
2221 	zval *var_ptr = &ref->val;
2222 	zval tmp;
2223 
2224 	ZVAL_COPY(&tmp, var_ptr);
2225 
2226 	increment_function(var_ptr);
2227 
2228 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
2229 		zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2230 		if (UNEXPECTED(error_prop)) {
2231 			zend_jit_throw_inc_ref_error(ref, error_prop);
2232 			ZVAL_LONG(var_ptr, ZEND_LONG_MAX);
2233 		}
2234 	} else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2235 		zval_ptr_dtor(var_ptr);
2236 		ZVAL_COPY_VALUE(var_ptr, &tmp);
2237 	} else {
2238 		zval_ptr_dtor(&tmp);
2239 	}
2240 	if (ret) {
2241 		ZVAL_COPY(ret, var_ptr);
2242 	}
2243 }
2244 
zend_jit_pre_dec_typed_ref(zend_reference * ref,zval * ret)2245 static void ZEND_FASTCALL zend_jit_pre_dec_typed_ref(zend_reference *ref, zval *ret)
2246 {
2247 	zval *var_ptr = &ref->val;
2248 	zval tmp;
2249 
2250 	ZVAL_COPY(&tmp, var_ptr);
2251 
2252 	decrement_function(var_ptr);
2253 
2254 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
2255 		zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2256 		if (UNEXPECTED(error_prop)) {
2257 			zend_jit_throw_dec_ref_error(ref, error_prop);
2258 			ZVAL_LONG(var_ptr, ZEND_LONG_MIN);
2259 		}
2260 	} else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2261 		zval_ptr_dtor(var_ptr);
2262 		ZVAL_COPY_VALUE(var_ptr, &tmp);
2263 	} else {
2264 		zval_ptr_dtor(&tmp);
2265 	}
2266 	if (ret) {
2267 		ZVAL_COPY(ret, var_ptr);
2268 	}
2269 }
2270 
zend_jit_post_inc_typed_ref(zend_reference * ref,zval * ret)2271 static void ZEND_FASTCALL zend_jit_post_inc_typed_ref(zend_reference *ref, zval *ret)
2272 {
2273 	zval *var_ptr = &ref->val;
2274 	ZVAL_COPY(ret, var_ptr);
2275 
2276 	increment_function(var_ptr);
2277 
2278 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(ret) == IS_LONG) {
2279 		zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2280 		if (UNEXPECTED(error_prop)) {
2281 			zend_jit_throw_inc_ref_error(ref, error_prop);
2282 			ZVAL_LONG(var_ptr, ZEND_LONG_MAX);
2283 		}
2284 	} else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2285 		zval_ptr_dtor(var_ptr);
2286 		ZVAL_COPY_VALUE(var_ptr, ret);
2287 	}
2288 }
2289 
zend_jit_post_dec_typed_ref(zend_reference * ref,zval * ret)2290 static void ZEND_FASTCALL zend_jit_post_dec_typed_ref(zend_reference *ref, zval *ret)
2291 {
2292 	zval *var_ptr = &ref->val;
2293 	ZVAL_COPY(ret, var_ptr);
2294 
2295 	decrement_function(var_ptr);
2296 
2297 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(ret) == IS_LONG) {
2298 		zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2299 		if (UNEXPECTED(error_prop)) {
2300 			zend_jit_throw_dec_ref_error(ref, error_prop);
2301 			ZVAL_LONG(var_ptr, ZEND_LONG_MIN);
2302 		}
2303 	} else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2304 		zval_ptr_dtor(var_ptr);
2305 		ZVAL_COPY_VALUE(var_ptr, ret);
2306 	}
2307 }
2308 
zend_jit_assign_op_to_typed_ref(zend_reference * ref,zval * val,binary_op_type binary_op)2309 static void ZEND_FASTCALL zend_jit_assign_op_to_typed_ref(zend_reference *ref, zval *val, binary_op_type binary_op)
2310 {
2311 	zval z_copy;
2312 
2313 	/* Make sure that in-place concatenation is used if the LHS is a string. */
2314 	if (binary_op == concat_function && Z_TYPE(ref->val) == IS_STRING) {
2315 		concat_function(&ref->val, &ref->val, val);
2316 		ZEND_ASSERT(Z_TYPE(ref->val) == IS_STRING && "Concat should return string");
2317 		return;
2318 	}
2319 
2320 	binary_op(&z_copy, &ref->val, val);
2321 	if (EXPECTED(zend_verify_ref_assignable_zval(ref, &z_copy, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2322 		zval_ptr_dtor(&ref->val);
2323 		ZVAL_COPY_VALUE(&ref->val, &z_copy);
2324 	} else {
2325 		zval_ptr_dtor(&z_copy);
2326 	}
2327 }
2328 
zend_jit_assign_op_to_typed_ref_tmp(zend_reference * ref,zval * val,binary_op_type binary_op)2329 static void ZEND_FASTCALL zend_jit_assign_op_to_typed_ref_tmp(zend_reference *ref, zval *val, binary_op_type binary_op)
2330 {
2331 	zval z_copy;
2332 
2333 	binary_op(&z_copy, &ref->val, val);
2334 	if (EXPECTED(zend_verify_ref_assignable_zval(ref, &z_copy, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2335 		zval_ptr_dtor(&ref->val);
2336 		ZVAL_COPY_VALUE(&ref->val, &z_copy);
2337 	} else {
2338 		zval_ptr_dtor(&z_copy);
2339 	}
2340 	zval_ptr_dtor_nogc(val);
2341 }
2342 
zend_jit_only_vars_by_reference(zval * arg)2343 static void ZEND_FASTCALL zend_jit_only_vars_by_reference(zval *arg)
2344 {
2345 	ZVAL_NEW_REF(arg, arg);
2346 	zend_error(E_NOTICE, "Only variables should be passed by reference");
2347 }
2348 
zend_jit_invalid_array_access(zval * container)2349 static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container)
2350 {
2351 	zend_error(E_WARNING, "Trying to access array offset on value of type %s", zend_zval_type_name(container));
2352 }
2353 
zend_jit_invalid_property_read(zval * container,const char * property_name)2354 static void ZEND_FASTCALL zend_jit_invalid_property_read(zval *container, const char *property_name)
2355 {
2356 	zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", property_name, zend_zval_type_name(container));
2357 }
2358 
zend_jit_invalid_property_write(zval * container,const char * property_name)2359 static void ZEND_FASTCALL zend_jit_invalid_property_write(zval *container, const char *property_name)
2360 {
2361 	zend_throw_error(NULL,
2362 		"Attempt to modify property \"%s\" on %s",
2363 		property_name, zend_zval_type_name(container));
2364 }
2365 
zend_jit_invalid_property_incdec(zval * container,const char * property_name)2366 static void ZEND_FASTCALL zend_jit_invalid_property_incdec(zval *container, const char *property_name)
2367 {
2368 	zend_execute_data *execute_data = EG(current_execute_data);
2369 	const zend_op *opline = EX(opline);
2370 
2371 	if (Z_TYPE_P(container) == IS_UNDEF && opline->op1_type == IS_CV) {
2372 		zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)];
2373 
2374 		zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(cv));
2375 	}
2376 	if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
2377 		ZVAL_UNDEF(EX_VAR(opline->result.var));
2378 	}
2379 	zend_throw_error(NULL,
2380 		"Attempt to increment/decrement property \"%s\" on %s",
2381 		property_name, zend_zval_type_name(container));
2382 	if (opline->op1_type == IS_VAR) {
2383 		zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
2384 	}
2385 }
2386 
zend_jit_invalid_property_assign(zval * container,const char * property_name)2387 static void ZEND_FASTCALL zend_jit_invalid_property_assign(zval *container, const char *property_name)
2388 {
2389 	zend_throw_error(NULL,
2390 		"Attempt to assign property \"%s\" on %s",
2391 		property_name, zend_zval_type_name(container));
2392 }
2393 
zend_jit_invalid_property_assign_op(zval * container,const char * property_name)2394 static void ZEND_FASTCALL zend_jit_invalid_property_assign_op(zval *container, const char *property_name)
2395 {
2396 	if (Z_TYPE_P(container) == IS_UNDEF) {
2397 		const zend_execute_data *execute_data = EG(current_execute_data);
2398 
2399 		zend_jit_undefined_op_helper(EX(opline)->op1.var);
2400 	}
2401 	zend_jit_invalid_property_assign(container, property_name);
2402 }
2403 
zend_jit_prepare_assign_dim_ref(zval * ref)2404 static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
2405 	zval *val = Z_REFVAL_P(ref);
2406 	if (Z_TYPE_P(val) <= IS_FALSE) {
2407 		if (ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(ref))
2408 				&& !zend_verify_ref_array_assignable(Z_REF_P(ref))) {
2409 			return NULL;
2410 		}
2411 		if (Z_TYPE_P(val) == IS_FALSE) {
2412 			ZVAL_ARR(val, zend_new_array(8));
2413 			zend_false_to_array_deprecated();
2414 			if (EG(exception)) {
2415 				return NULL;
2416 			}
2417 		} else {
2418 			ZVAL_ARR(val, zend_new_array(8));
2419 		}
2420 	}
2421 	return val;
2422 }
2423 
zend_jit_pre_inc(zval * var_ptr,zval * ret)2424 static void ZEND_FASTCALL zend_jit_pre_inc(zval *var_ptr, zval *ret)
2425 {
2426 	increment_function(var_ptr);
2427 	ZVAL_COPY(ret, var_ptr);
2428 }
2429 
zend_jit_pre_dec(zval * var_ptr,zval * ret)2430 static void ZEND_FASTCALL zend_jit_pre_dec(zval *var_ptr, zval *ret)
2431 {
2432 	decrement_function(var_ptr);
2433 	ZVAL_COPY(ret, var_ptr);
2434 }
2435 
2436 #define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
2437 
_zend_hash_iterators_remove(HashTable * ht)2438 static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(HashTable *ht)
2439 {
2440 	HashTableIterator *iter = EG(ht_iterators);
2441 	HashTableIterator *end  = iter + EG(ht_iterators_used);
2442 
2443 	while (iter != end) {
2444 		if (iter->ht == ht) {
2445 			iter->ht = HT_POISONED_PTR;
2446 		}
2447 		iter++;
2448 	}
2449 }
2450 
zend_jit_array_free(HashTable * ht)2451 static void ZEND_FASTCALL zend_jit_array_free(HashTable *ht)
2452 {
2453 	GC_REMOVE_FROM_BUFFER(ht);
2454 	if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
2455 		_zend_hash_iterators_remove(ht);
2456 	}
2457 	if (!(EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED))) {
2458 		efree(HT_GET_DATA_ADDR(ht));
2459 	}
2460 	FREE_HASHTABLE(ht);
2461 }
2462 
zend_jit_zval_array_dup(zval * arr)2463 static HashTable *ZEND_FASTCALL zend_jit_zval_array_dup(zval *arr)
2464 {
2465 	HashTable *ht;
2466 
2467 	Z_TRY_DELREF_P(arr);
2468 	ht = Z_ARRVAL_P(arr);
2469 	ht = zend_array_dup(ht);
2470 	ZVAL_ARR(arr, ht);
2471 	return ht;
2472 }
2473 
zend_jit_add_arrays_helper(zend_array * op1,zend_array * op2)2474 static zend_array *ZEND_FASTCALL zend_jit_add_arrays_helper(zend_array *op1, zend_array *op2)
2475 {
2476 	zend_array *res;
2477 	res = zend_array_dup(op1);
2478 	zend_hash_merge(res, op2, zval_add_ref, 0);
2479 	return res;
2480 }
2481 
zend_jit_assign_obj_helper(zend_object * zobj,zend_string * name,zval * value,void ** cache_slot,zval * result)2482 static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, zval *result)
2483 {
2484 	if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2485 		const zend_op *op_data = EG(current_execute_data)->opline + 1;
2486 		ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
2487 		zend_jit_undefined_op_helper(op_data->op1.var);
2488 		value = &EG(uninitialized_zval);
2489 	}
2490 
2491 	ZVAL_DEREF(value);
2492 	value = zobj->handlers->write_property(zobj, name, value, cache_slot);
2493 	if (result) {
2494 		ZVAL_COPY_DEREF(result, value);
2495 	}
2496 }
2497 
zend_jit_assign_to_typed_prop(zval * property_val,zend_property_info * info,zval * value,zval * result)2498 static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result)
2499 {
2500 	zend_execute_data *execute_data = EG(current_execute_data);
2501 	zval tmp;
2502 
2503 	if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2504 		const zend_op *op_data = execute_data->opline + 1;
2505 		ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
2506 		zend_jit_undefined_op_helper(op_data->op1.var);
2507 		value = &EG(uninitialized_zval);
2508 	}
2509 
2510 	if (UNEXPECTED(info->flags & ZEND_ACC_READONLY)) {
2511 		zend_readonly_property_modification_error(info);
2512 		if (result) {
2513 			ZVAL_UNDEF(result);
2514 		}
2515 		return;
2516 	}
2517 
2518 	ZVAL_DEREF(value);
2519 	ZVAL_COPY(&tmp, value);
2520 
2521 	if (UNEXPECTED(!zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
2522 		zval_ptr_dtor(&tmp);
2523 		if (result) {
2524 			ZVAL_NULL(result);
2525 		}
2526 		return;
2527 	}
2528 
2529 	value = zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
2530 	if (result) {
2531 		ZVAL_COPY_DEREF(result, value);
2532 	}
2533 }
2534 
_zend_jit_assign_op_overloaded_property(zend_object * object,zend_string * name,void ** cache_slot,zval * value,binary_op_type binary_op)2535 static zend_never_inline void _zend_jit_assign_op_overloaded_property(zend_object *object, zend_string *name, void **cache_slot, zval *value, binary_op_type binary_op)
2536 {
2537 	zval *z;
2538 	zval rv, res;
2539 
2540 	GC_ADDREF(object);
2541 	z = object->handlers->read_property(object, name, BP_VAR_R, cache_slot, &rv);
2542 	if (UNEXPECTED(EG(exception))) {
2543 		OBJ_RELEASE(object);
2544 //???		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2545 //???			ZVAL_UNDEF(EX_VAR(opline->result.var));
2546 //???		}
2547 		return;
2548 	}
2549 	if (binary_op(&res, z, value) == SUCCESS) {
2550 		object->handlers->write_property(object, name, &res, cache_slot);
2551 	}
2552 //???	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2553 //???		ZVAL_COPY(EX_VAR(opline->result.var), &res);
2554 //???	}
2555 	if (z == &rv) {
2556 		zval_ptr_dtor(z);
2557 	}
2558 	zval_ptr_dtor(&res);
2559 	OBJ_RELEASE(object);
2560 }
2561 
zend_jit_assign_op_to_typed_prop(zval * zptr,zend_property_info * prop_info,zval * value,binary_op_type binary_op)2562 static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_property_info *prop_info, zval *value, binary_op_type binary_op)
2563 {
2564 	zend_execute_data *execute_data = EG(current_execute_data);
2565 	zval z_copy;
2566 
2567 	if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) {
2568 		zend_readonly_property_modification_error(prop_info);
2569 		return;
2570 	}
2571 
2572 	ZVAL_DEREF(zptr);
2573 	/* Make sure that in-place concatenation is used if the LHS is a string. */
2574 	if (binary_op == concat_function && Z_TYPE_P(zptr) == IS_STRING) {
2575 		concat_function(zptr, zptr, value);
2576 		ZEND_ASSERT(Z_TYPE_P(zptr) == IS_STRING && "Concat should return string");
2577 		return;
2578 	}
2579 
2580 	binary_op(&z_copy, zptr, value);
2581 	if (EXPECTED(zend_verify_property_type(prop_info, &z_copy, EX_USES_STRICT_TYPES()))) {
2582 		zval_ptr_dtor(zptr);
2583 		ZVAL_COPY_VALUE(zptr, &z_copy);
2584 	} else {
2585 		zval_ptr_dtor(&z_copy);
2586 	}
2587 }
2588 
zend_jit_assign_obj_op_helper(zend_object * zobj,zend_string * name,zval * value,void ** cache_slot,binary_op_type binary_op)2589 static void ZEND_FASTCALL zend_jit_assign_obj_op_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, binary_op_type binary_op)
2590 {
2591 	zval *zptr;
2592 	zend_property_info *prop_info;
2593 
2594 	if (EXPECTED((zptr = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2595 		if (UNEXPECTED(Z_ISERROR_P(zptr))) {
2596 //???			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2597 //???				ZVAL_NULL(EX_VAR(opline->result.var));
2598 //???			}
2599 		} else {
2600 //???			zval *orig_zptr = zptr;
2601 			zend_reference *ref;
2602 
2603 			do {
2604 				if (UNEXPECTED(Z_ISREF_P(zptr))) {
2605 					ref = Z_REF_P(zptr);
2606 					zptr = Z_REFVAL_P(zptr);
2607 					if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
2608 						zend_jit_assign_op_to_typed_ref(ref, value, binary_op);
2609 						break;
2610 					}
2611 				}
2612 
2613 //???				if (OP2_TYPE == IS_CONST) {
2614 				prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
2615 //???				} else {
2616 //???					prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), orig_zptr);
2617 //???				}
2618 				if (UNEXPECTED(prop_info)) {
2619 					/* special case for typed properties */
2620 					zend_jit_assign_op_to_typed_prop(zptr, prop_info, value, binary_op);
2621 				} else {
2622 					binary_op(zptr, zptr, value);
2623 				}
2624 			} while (0);
2625 
2626 //???			if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2627 //???				ZVAL_COPY(EX_VAR(opline->result.var), zptr);
2628 //???			}
2629 		}
2630 	} else {
2631 		_zend_jit_assign_op_overloaded_property(zobj, name, cache_slot, value, binary_op);
2632 	}
2633 }
2634 
_zend_jit_throw_inc_prop_error(zend_property_info * prop)2635 static ZEND_COLD zend_long _zend_jit_throw_inc_prop_error(zend_property_info *prop)
2636 {
2637 	zend_string *type_str = zend_type_to_string(prop->type);
2638 	zend_type_error("Cannot increment property %s::$%s of type %s past its maximal value",
2639 		ZSTR_VAL(prop->ce->name),
2640 		zend_get_unmangled_property_name(prop->name),
2641 		ZSTR_VAL(type_str));
2642 	zend_string_release(type_str);
2643 	return ZEND_LONG_MAX;
2644 }
2645 
_zend_jit_throw_dec_prop_error(zend_property_info * prop)2646 static ZEND_COLD zend_long _zend_jit_throw_dec_prop_error(zend_property_info *prop)
2647 {
2648 	zend_string *type_str = zend_type_to_string(prop->type);
2649 	zend_type_error("Cannot decrement property %s::$%s of type %s past its minimal value",
2650 		ZSTR_VAL(prop->ce->name),
2651 		zend_get_unmangled_property_name(prop->name),
2652 		ZSTR_VAL(type_str));
2653 	zend_string_release(type_str);
2654 	return ZEND_LONG_MIN;
2655 }
2656 
zend_jit_inc_typed_prop(zval * var_ptr,zend_property_info * prop_info)2657 static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info)
2658 {
2659 	ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
2660 
2661 	if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY))) {
2662 		zend_readonly_property_modification_error(prop_info);
2663 		return;
2664 	}
2665 
2666 	zend_execute_data *execute_data = EG(current_execute_data);
2667 	zval tmp;
2668 
2669 	ZVAL_DEREF(var_ptr);
2670 	ZVAL_COPY(&tmp, var_ptr);
2671 
2672 	increment_function(var_ptr);
2673 
2674 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
2675 		if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2676 			zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
2677 			ZVAL_LONG(var_ptr, val);
2678 		}
2679 	} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
2680 		zval_ptr_dtor(var_ptr);
2681 		ZVAL_COPY_VALUE(var_ptr, &tmp);
2682 	} else {
2683 		zval_ptr_dtor(&tmp);
2684 	}
2685 }
2686 
zend_jit_dec_typed_prop(zval * var_ptr,zend_property_info * prop_info)2687 static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info)
2688 {
2689 	ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
2690 
2691 	if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY))) {
2692 		zend_readonly_property_modification_error(prop_info);
2693 		return;
2694 	}
2695 
2696 	zend_execute_data *execute_data = EG(current_execute_data);
2697 	zval tmp;
2698 
2699 	ZVAL_DEREF(var_ptr);
2700 	ZVAL_COPY(&tmp, var_ptr);
2701 
2702 	decrement_function(var_ptr);
2703 
2704 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
2705 		if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2706 			zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
2707 			ZVAL_LONG(var_ptr, val);
2708 		}
2709 	} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
2710 		zval_ptr_dtor(var_ptr);
2711 		ZVAL_COPY_VALUE(var_ptr, &tmp);
2712 	} else {
2713 		zval_ptr_dtor(&tmp);
2714 	}
2715 }
2716 
zend_jit_pre_inc_typed_prop(zval * var_ptr,zend_property_info * prop_info,zval * result)2717 static void ZEND_FASTCALL zend_jit_pre_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
2718 {
2719 	ZVAL_DEREF(var_ptr);
2720 	zend_jit_inc_typed_prop(var_ptr, prop_info);
2721 	ZVAL_COPY(result, var_ptr);
2722 }
2723 
zend_jit_pre_dec_typed_prop(zval * var_ptr,zend_property_info * prop_info,zval * result)2724 static void ZEND_FASTCALL zend_jit_pre_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
2725 {
2726 	ZVAL_DEREF(var_ptr);
2727 	zend_jit_dec_typed_prop(var_ptr, prop_info);
2728 	ZVAL_COPY(result, var_ptr);
2729 }
2730 
zend_jit_post_inc_typed_prop(zval * var_ptr,zend_property_info * prop_info,zval * result)2731 static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
2732 {
2733 	ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
2734 
2735 	if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY))) {
2736 		zend_readonly_property_modification_error(prop_info);
2737 		if (result) {
2738 			ZVAL_UNDEF(result);
2739 		}
2740 		return;
2741 	}
2742 
2743 	zend_execute_data *execute_data = EG(current_execute_data);
2744 
2745 	ZVAL_DEREF(var_ptr);
2746 	ZVAL_COPY(result, var_ptr);
2747 
2748 	increment_function(var_ptr);
2749 
2750 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
2751 		if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2752 			zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
2753 			ZVAL_LONG(var_ptr, val);
2754 		}
2755 	} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
2756 		zval_ptr_dtor(var_ptr);
2757 		ZVAL_COPY_VALUE(var_ptr, result);
2758 		ZVAL_UNDEF(result);
2759 	}
2760 }
2761 
zend_jit_post_dec_typed_prop(zval * var_ptr,zend_property_info * prop_info,zval * result)2762 static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
2763 {
2764 	ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
2765 
2766 	if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY))) {
2767 		zend_readonly_property_modification_error(prop_info);
2768 		if (result) {
2769 			ZVAL_UNDEF(result);
2770 		}
2771 		return;
2772 	}
2773 
2774 	zend_execute_data *execute_data = EG(current_execute_data);
2775 
2776 	ZVAL_DEREF(var_ptr);
2777 	ZVAL_COPY(result, var_ptr);
2778 
2779 	decrement_function(var_ptr);
2780 
2781 	if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
2782 		if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2783 			zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
2784 			ZVAL_LONG(var_ptr, val);
2785 		}
2786 	} else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
2787 		zval_ptr_dtor(var_ptr);
2788 		ZVAL_COPY_VALUE(var_ptr, result);
2789 		ZVAL_UNDEF(result);
2790 	}
2791 }
2792 
zend_jit_pre_inc_obj_helper(zend_object * zobj,zend_string * name,void ** cache_slot,zval * result)2793 static void ZEND_FASTCALL zend_jit_pre_inc_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
2794 {
2795 	zval *prop;
2796 
2797 	if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2798 		if (UNEXPECTED(Z_ISERROR_P(prop))) {
2799 			if (UNEXPECTED(result)) {
2800 				ZVAL_NULL(result);
2801 			}
2802 		} else {
2803 			zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2);
2804 
2805 			if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
2806 				fast_long_increment_function(prop);
2807 				if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
2808 						&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2809 					zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
2810 					ZVAL_LONG(prop, val);
2811 				}
2812 			} else {
2813 				do {
2814 					if (Z_ISREF_P(prop)) {
2815 						zend_reference *ref = Z_REF_P(prop);
2816 						prop = Z_REFVAL_P(prop);
2817 						if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
2818 							zend_jit_pre_inc_typed_ref(ref, result);
2819 							break;
2820 						}
2821 					}
2822 
2823 					if (UNEXPECTED(prop_info)) {
2824 						zend_jit_inc_typed_prop(prop, prop_info);
2825 					} else {
2826 						increment_function(prop);
2827 					}
2828 				} while (0);
2829 			}
2830 			if (UNEXPECTED(result)) {
2831 				ZVAL_COPY(result, prop);
2832 			}
2833 		}
2834 	} else {
2835 		zval rv;
2836 		zval *z;
2837 		zval z_copy;
2838 
2839 		GC_ADDREF(zobj);
2840 		z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
2841 		if (UNEXPECTED(EG(exception))) {
2842 			OBJ_RELEASE(zobj);
2843 			if (UNEXPECTED(result)) {
2844 				ZVAL_NULL(result);
2845 			}
2846 			return;
2847 		}
2848 
2849 		ZVAL_COPY_DEREF(&z_copy, z);
2850 		increment_function(&z_copy);
2851 		if (UNEXPECTED(result)) {
2852 			ZVAL_COPY(result, &z_copy);
2853 		}
2854 		zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
2855 		OBJ_RELEASE(zobj);
2856 		zval_ptr_dtor(&z_copy);
2857 		if (z == &rv) {
2858 			zval_ptr_dtor(z);
2859 		}
2860 	}
2861 }
2862 
zend_jit_pre_dec_obj_helper(zend_object * zobj,zend_string * name,void ** cache_slot,zval * result)2863 static void ZEND_FASTCALL zend_jit_pre_dec_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
2864 {
2865 	zval *prop;
2866 
2867 	if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2868 		if (UNEXPECTED(Z_ISERROR_P(prop))) {
2869 			if (UNEXPECTED(result)) {
2870 				ZVAL_NULL(result);
2871 			}
2872 		} else {
2873 			zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2);
2874 
2875 			if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
2876 				fast_long_decrement_function(prop);
2877 				if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
2878 						&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2879 					zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
2880 					ZVAL_LONG(prop, val);
2881 				}
2882 			} else {
2883 				do {
2884 					if (Z_ISREF_P(prop)) {
2885 						zend_reference *ref = Z_REF_P(prop);
2886 						prop = Z_REFVAL_P(prop);
2887 						if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
2888 							zend_jit_pre_dec_typed_ref(ref, result);
2889 							break;
2890 						}
2891 					}
2892 
2893 					if (UNEXPECTED(prop_info)) {
2894 						zend_jit_dec_typed_prop(prop, prop_info);
2895 					} else {
2896 						decrement_function(prop);
2897 					}
2898 				} while (0);
2899 			}
2900 			if (UNEXPECTED(result)) {
2901 				ZVAL_COPY(result, prop);
2902 			}
2903 		}
2904 	} else {
2905 		zval rv;
2906 		zval *z;
2907 		zval z_copy;
2908 
2909 		GC_ADDREF(zobj);
2910 		z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
2911 		if (UNEXPECTED(EG(exception))) {
2912 			OBJ_RELEASE(zobj);
2913 			if (UNEXPECTED(result)) {
2914 				ZVAL_NULL(result);
2915 			}
2916 			return;
2917 		}
2918 
2919 		ZVAL_COPY_DEREF(&z_copy, z);
2920 		decrement_function(&z_copy);
2921 		if (UNEXPECTED(result)) {
2922 			ZVAL_COPY(result, &z_copy);
2923 		}
2924 		zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
2925 		OBJ_RELEASE(zobj);
2926 		zval_ptr_dtor(&z_copy);
2927 		if (z == &rv) {
2928 			zval_ptr_dtor(z);
2929 		}
2930 	}
2931 }
2932 
zend_jit_post_inc_obj_helper(zend_object * zobj,zend_string * name,void ** cache_slot,zval * result)2933 static void ZEND_FASTCALL zend_jit_post_inc_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
2934 {
2935 	zval *prop;
2936 
2937 	if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2938 		if (UNEXPECTED(Z_ISERROR_P(prop))) {
2939 			ZVAL_NULL(result);
2940 		} else {
2941 			zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
2942 
2943 			if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
2944 				ZVAL_LONG(result, Z_LVAL_P(prop));
2945 				fast_long_increment_function(prop);
2946 				if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
2947 						&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
2948 					zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
2949 					ZVAL_LONG(prop, val);
2950 				}
2951 			} else {
2952 				if (Z_ISREF_P(prop)) {
2953 					zend_reference *ref = Z_REF_P(prop);
2954 					prop = Z_REFVAL_P(prop);
2955 					if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
2956 						zend_jit_post_inc_typed_ref(ref, result);
2957 						return;
2958 					}
2959 				}
2960 
2961 				if (UNEXPECTED(prop_info)) {
2962 					zend_jit_post_inc_typed_prop(prop, prop_info, result);
2963 				} else {
2964 					ZVAL_COPY(result, prop);
2965 					increment_function(prop);
2966 				}
2967 			}
2968 		}
2969 	} else {
2970 		zval rv;
2971 		zval *z;
2972 		zval z_copy;
2973 
2974 		GC_ADDREF(zobj);
2975 		z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
2976 		if (UNEXPECTED(EG(exception))) {
2977 			OBJ_RELEASE(zobj);
2978 			ZVAL_UNDEF(result);
2979 			return;
2980 		}
2981 
2982 		ZVAL_COPY_DEREF(&z_copy, z);
2983 		ZVAL_COPY(result, &z_copy);
2984 		increment_function(&z_copy);
2985 		zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
2986 		OBJ_RELEASE(zobj);
2987 		zval_ptr_dtor(&z_copy);
2988 		if (z == &rv) {
2989 			zval_ptr_dtor(z);
2990 		}
2991 	}
2992 }
2993 
zend_jit_post_dec_obj_helper(zend_object * zobj,zend_string * name,void ** cache_slot,zval * result)2994 static void ZEND_FASTCALL zend_jit_post_dec_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
2995 {
2996 	zval *prop;
2997 
2998 	if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2999 		if (UNEXPECTED(Z_ISERROR_P(prop))) {
3000 			ZVAL_NULL(result);
3001 		} else {
3002 			zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
3003 
3004 			if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
3005 				ZVAL_LONG(result, Z_LVAL_P(prop));
3006 				fast_long_decrement_function(prop);
3007 				if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && UNEXPECTED(prop_info)
3008 						&& !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3009 					zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
3010 					ZVAL_LONG(prop, val);
3011 				}
3012 			} else {
3013 				if (Z_ISREF_P(prop)) {
3014 					zend_reference *ref = Z_REF_P(prop);
3015 					prop = Z_REFVAL_P(prop);
3016 					if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
3017 						zend_jit_post_dec_typed_ref(ref, result);
3018 						return;
3019 					}
3020 				}
3021 
3022 				if (UNEXPECTED(prop_info)) {
3023 					zend_jit_post_dec_typed_prop(prop, prop_info, result);
3024 				} else {
3025 					ZVAL_COPY(result, prop);
3026 					decrement_function(prop);
3027 				}
3028 			}
3029 		}
3030 	} else {
3031 		zval rv;
3032 		zval *z;
3033 		zval z_copy;
3034 
3035 		GC_ADDREF(zobj);
3036 		z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
3037 		if (UNEXPECTED(EG(exception))) {
3038 			OBJ_RELEASE(zobj);
3039 			ZVAL_UNDEF(result);
3040 			return;
3041 		}
3042 
3043 		ZVAL_COPY_DEREF(&z_copy, z);
3044 		ZVAL_COPY(result, &z_copy);
3045 		decrement_function(&z_copy);
3046 		zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
3047 		OBJ_RELEASE(zobj);
3048 		zval_ptr_dtor(&z_copy);
3049 		if (z == &rv) {
3050 			zval_ptr_dtor(z);
3051 		}
3052 	}
3053 }
3054 
3055 #if (PHP_VERSION_ID <= 80100) && (SIZEOF_SIZE_T == 4)
zval_jit_update_constant_ex(zval * p,zend_class_entry * scope)3056 static zend_result ZEND_FASTCALL zval_jit_update_constant_ex(zval *p, zend_class_entry *scope)
3057 {
3058 	if (Z_TYPE_P(p) == IS_CONSTANT_AST) {
3059 		zend_ast *ast = Z_ASTVAL_P(p);
3060 
3061 		if (ast->kind == ZEND_AST_CONSTANT) {
3062 			zend_string *name = zend_ast_get_constant_name(ast);
3063 			zval *zv = zend_get_constant_ex(name, scope, ast->attr);
3064 			if (UNEXPECTED(zv == NULL)) {
3065 				return FAILURE;
3066 			}
3067 
3068 			zval_ptr_dtor_nogc(p);
3069 			ZVAL_COPY_OR_DUP(p, zv);
3070 		} else {
3071 			zval tmp;
3072 
3073 			// Increase the refcount during zend_ast_evaluate to avoid releasing the ast too early
3074 			// on nested calls to zval_update_constant_ex which can happen when retriggering ast
3075 			// evaluation during autoloading.
3076 			zend_ast_ref *ast_ref = Z_AST_P(p);
3077 			bool ast_is_refcounted = !(GC_FLAGS(ast_ref) & GC_IMMUTABLE);
3078 			if (ast_is_refcounted) {
3079 				GC_ADDREF(ast_ref);
3080 			}
3081 			zend_result result = zend_ast_evaluate(&tmp, ast, scope);
3082 			if (ast_is_refcounted && !GC_DELREF(ast_ref)) {
3083 				rc_dtor_func((zend_refcounted *)ast_ref);
3084 			}
3085 			if (UNEXPECTED(result != SUCCESS)) {
3086 				return FAILURE;
3087 			}
3088 			zval_ptr_dtor_nogc(p);
3089 			ZVAL_COPY_VALUE(p, &tmp);
3090 		}
3091 	}
3092 	return SUCCESS;
3093 }
3094 #endif
3095 
zend_jit_free_trampoline_helper(zend_function * func)3096 static void ZEND_FASTCALL zend_jit_free_trampoline_helper(zend_function *func)
3097 {
3098 	ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
3099 	zend_string_release_ex(func->common.function_name, 0);
3100 	zend_free_trampoline(func);
3101 }
3102 
zend_jit_exception_in_interrupt_handler_helper(void)3103 static void ZEND_FASTCALL zend_jit_exception_in_interrupt_handler_helper(void)
3104 {
3105 	if (EG(exception)) {
3106 		/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
3107 		const zend_op *throw_op = EG(opline_before_exception);
3108 
3109 		if (throw_op
3110 		 && throw_op->result_type & (IS_TMP_VAR|IS_VAR)
3111 		 && throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
3112 		 && throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
3113 		 && throw_op->opcode != ZEND_ROPE_INIT
3114 		 && throw_op->opcode != ZEND_ROPE_ADD) {
3115 			ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));
3116 		}
3117 	}
3118 }
3119 
zend_jit_rope_end(zend_string ** rope,uint32_t count)3120 static zend_string* ZEND_FASTCALL zend_jit_rope_end(zend_string **rope, uint32_t count)
3121 {
3122 	zend_string *ret;
3123 	uint32_t i;
3124 	size_t len = 0;
3125 	char *target;
3126 
3127 	for (i = 0; i <= count; i++) {
3128 		len += ZSTR_LEN(rope[i]);
3129 	}
3130 	ret = zend_string_alloc(len, 0);
3131 	target = ZSTR_VAL(ret);
3132 	for (i = 0; i <= count; i++) {
3133 		memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i]));
3134 		target += ZSTR_LEN(rope[i]);
3135 		zend_string_release_ex(rope[i], 0);
3136 	}
3137 	*target = '\0';
3138 	return ret;
3139 }
3140