xref: /PHP-8.2/ext/opcache/jit/zend_jit_trace.c (revision 24d5912a)
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 static zend_op_array dummy_op_array;
20 static zend_jit_trace_info *zend_jit_traces = NULL;
21 static const void **zend_jit_exit_groups = NULL;
22 
23 #define ZEND_JIT_COUNTER_NUM   zend_jit_traces[0].root
24 #define ZEND_JIT_TRACE_NUM     zend_jit_traces[0].id
25 #define ZEND_JIT_EXIT_NUM      zend_jit_traces[0].exit_count
26 #define ZEND_JIT_EXIT_COUNTERS zend_jit_traces[0].exit_counters
27 
28 #define ZEND_JIT_TRACE_STOP_DESCRIPTION(name, description) \
29 	description,
30 
31 static const char * zend_jit_trace_stop_description[] = {
32 	ZEND_JIT_TRACE_STOP(ZEND_JIT_TRACE_STOP_DESCRIPTION)
33 };
34 
zend_jit_trace_star_desc(uint8_t trace_flags)35 static zend_always_inline const char *zend_jit_trace_star_desc(uint8_t trace_flags)
36 {
37 	if (trace_flags & ZEND_JIT_TRACE_START_LOOP) {
38 		return "loop";
39 	} else if (trace_flags & ZEND_JIT_TRACE_START_ENTER) {
40 		return "enter";
41 	} else if (trace_flags & ZEND_JIT_TRACE_START_RETURN) {
42 		return "return";
43 	} else {
44 		ZEND_UNREACHABLE();
45 		return "???";
46 	}
47 }
48 
zend_jit_trace_startup(zend_bool reattached)49 static int zend_jit_trace_startup(zend_bool reattached)
50 {
51 	if (!reattached) {
52 		zend_jit_traces = (zend_jit_trace_info*)zend_shared_alloc(sizeof(zend_jit_trace_info) * JIT_G(max_root_traces));
53 		if (!zend_jit_traces) {
54 			return FAILURE;
55 		}
56 		zend_jit_exit_groups = (const void**)zend_shared_alloc(sizeof(void*) * (ZEND_JIT_TRACE_MAX_EXITS/ZEND_JIT_EXIT_POINTS_PER_GROUP));
57 		if (!zend_jit_exit_groups) {
58 			return FAILURE;
59 		}
60 		ZEND_JIT_TRACE_NUM = 1;
61 		ZEND_JIT_COUNTER_NUM = 0;
62 		ZEND_JIT_EXIT_NUM = 0;
63 		ZEND_JIT_EXIT_COUNTERS = 0;
64 		ZCSG(jit_traces) = zend_jit_traces;
65 		ZCSG(jit_exit_groups) = zend_jit_exit_groups;
66 	} else {
67 		zend_jit_traces = ZCSG(jit_traces);
68 		if (!zend_jit_traces) {
69 			return FAILURE;
70 		}
71 		zend_jit_exit_groups = ZCSG(jit_exit_groups);
72 		if (!zend_jit_exit_groups) {
73 			return FAILURE;
74 		}
75 	}
76 
77 	memset(&dummy_op_array, 0, sizeof(dummy_op_array));
78 	dummy_op_array.fn_flags = ZEND_ACC_DONE_PASS_TWO;
79 
80 	JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
81 	if (JIT_G(exit_counters) == NULL) {
82 		return FAILURE;
83 	}
84 
85 	return SUCCESS;
86 }
87 
zend_jit_trace_allocate_exit_group(uint32_t n)88 static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
89 {
90 	dasm_State* dasm_state = NULL;
91 	const void *entry;
92 	char name[32];
93 
94 	dasm_init(&dasm_state, DASM_MAXSECTION);
95 	dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
96 	dasm_setup(&dasm_state, dasm_actions);
97 	zend_jit_trace_exit_group_stub(&dasm_state, n);
98 
99 	sprintf(name, "jit$$trace_exit_%d", n);
100 	entry = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, name, 0, SP_ADJ_JIT, SP_ADJ_NONE);
101 	dasm_free(&dasm_state);
102 
103 #ifdef HAVE_DISASM
104 	if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
105 		uint32_t i;
106 
107 		for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
108 			sprintf(name, "jit$$trace_exit_%d", n + i);
109 			zend_jit_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
110 		}
111 	}
112 #endif
113 
114 	return entry;
115 }
116 
zend_jit_trace_allocate_exit_point(uint32_t n)117 static const void *zend_jit_trace_allocate_exit_point(uint32_t n)
118 {
119 	const void *group = NULL;
120 
121 	if (UNEXPECTED(n >= ZEND_JIT_TRACE_MAX_EXITS)) {
122 		return NULL;
123 	}
124 	do {
125 		group = zend_jit_trace_allocate_exit_group(ZEND_JIT_EXIT_NUM);
126 		if (!group) {
127 			return NULL;
128 		}
129 		zend_jit_exit_groups[ZEND_JIT_EXIT_NUM / ZEND_JIT_EXIT_POINTS_PER_GROUP] =
130 			group;
131 		ZEND_JIT_EXIT_NUM += ZEND_JIT_EXIT_POINTS_PER_GROUP;
132 	} while (n >= ZEND_JIT_EXIT_NUM);
133 	return (const void*)
134 		((const char*)group +
135 		((n % ZEND_JIT_EXIT_POINTS_PER_GROUP) * ZEND_JIT_EXIT_POINTS_SPACING));
136 }
137 
zend_jit_trace_get_exit_addr(uint32_t n)138 static const void *zend_jit_trace_get_exit_addr(uint32_t n)
139 {
140 	if (UNEXPECTED(n >= ZEND_JIT_EXIT_NUM)) {
141 		return zend_jit_trace_allocate_exit_point(n);
142 	}
143 	return (const void*)
144 		((const char*)zend_jit_exit_groups[n / ZEND_JIT_EXIT_POINTS_PER_GROUP] +
145 		((n % ZEND_JIT_EXIT_POINTS_PER_GROUP) * ZEND_JIT_EXIT_POINTS_SPACING));
146 }
147 
148 #if ZEND_JIT_TARGET_ARM64
zend_jit_get_current_trace_info(void)149 static zend_jit_trace_info *zend_jit_get_current_trace_info(void)
150 {
151 	return &zend_jit_traces[ZEND_JIT_TRACE_NUM];
152 }
153 
zend_jit_trace_find_exit_point(const void * addr)154 static uint32_t zend_jit_trace_find_exit_point(const void* addr)
155 {
156 	uint32_t n = ZEND_JIT_EXIT_NUM / ZEND_JIT_EXIT_POINTS_PER_GROUP;
157 	uint32_t i;
158 
159 	for (i = 0; i < n; i++) {
160 		if ((const char*)addr >= (const char*)zend_jit_exit_groups[i]
161 			&& (const char*)addr < (const char*)zend_jit_exit_groups[i] +
162 				(ZEND_JIT_EXIT_POINTS_PER_GROUP * ZEND_JIT_EXIT_POINTS_SPACING)) {
163 			return (i * ZEND_JIT_EXIT_POINTS_PER_GROUP) +
164 				 ((const char*)addr - (const char*)zend_jit_exit_groups[i]) / ZEND_JIT_EXIT_POINTS_SPACING;
165 		}
166 	}
167 	return (uint32_t)-1;
168 }
169 #endif
170 
zend_jit_trace_get_exit_point(const zend_op * to_opline,uint32_t flags)171 static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags)
172 {
173 	zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
174 	uint32_t exit_point;
175 	const zend_op_array *op_array;
176 	uint32_t stack_offset = (uint32_t)-1;
177 	uint32_t stack_size;
178 	zend_jit_trace_stack *stack = NULL;
179 
180 	if (delayed_call_chain) {
181 		assert(to_opline != NULL); /* CALL and IP share the same register */
182 		flags |= ZEND_JIT_EXIT_RESTORE_CALL;
183 	}
184 	if (JIT_G(current_frame)) {
185 		op_array = &JIT_G(current_frame)->func->op_array;
186 		stack_size = op_array->last_var + op_array->T;
187 		if (stack_size) {
188 			stack = JIT_G(current_frame)->stack;
189 			do {
190 				if (STACK_TYPE(stack, stack_size-1) != IS_UNKNOWN
191 				 || STACK_MEM_TYPE(stack, stack_size-1) != IS_UNKNOWN
192 				 || STACK_REG(stack, stack_size-1) != ZREG_NONE) {
193 					break;
194 				}
195 				stack_size--;
196 			} while (stack_size);
197 		}
198 	} else {
199 		op_array = NULL;
200 		stack_size = 0;
201 	}
202 
203 	/* Try to reuse exit points */
204 	if (to_opline != NULL && t->exit_count > 0) {
205 		uint32_t i = t->exit_count;
206 
207 		do {
208 			i--;
209 			if (stack_size == 0
210 			 || (t->exit_info[i].stack_size >= stack_size
211 			  && memcmp(t->stack_map + t->exit_info[i].stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack)) == 0)) {
212 				stack_offset = t->exit_info[i].stack_offset;
213 				if (t->exit_info[i].opline == to_opline
214 				 && t->exit_info[i].flags == flags
215 				 && t->exit_info[i].stack_size == stack_size) {
216 					return i;
217 				}
218 			}
219 		} while (i > 0);
220 	}
221 
222 	exit_point = t->exit_count;
223 	if (exit_point < ZEND_JIT_TRACE_MAX_EXITS) {
224 		if (stack_size != 0 && stack_offset == (uint32_t)-1) {
225 			stack_offset = t->stack_map_size;
226 			t->stack_map_size += stack_size;
227 			// TODO: reduce number of reallocations ???
228 			t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
229 			memcpy(t->stack_map + stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack));
230 		}
231 		t->exit_count++;
232 		t->exit_info[exit_point].opline = to_opline;
233 		t->exit_info[exit_point].op_array = op_array;
234 		t->exit_info[exit_point].flags = flags;
235 		t->exit_info[exit_point].stack_size = stack_size;
236 		t->exit_info[exit_point].stack_offset = stack_offset;
237 	}
238 
239 	return exit_point;
240 }
241 
zend_jit_trace_add_code(const void * start,uint32_t size)242 static void zend_jit_trace_add_code(const void *start, uint32_t size)
243 {
244 	zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
245 
246 	t->code_start = start;
247 	t->code_size  = size;
248 }
249 
250 /**
251  * Locate a trace in the #zend_jit_traces array with the specified
252  * #code_start address.
253  *
254  * @return the #zend_jit_traces index or 0 if no such #code_start
255  * address was found
256  */
zend_jit_find_trace(const void * addr)257 static uint32_t zend_jit_find_trace(const void *addr)
258 {
259 	uint32_t i;
260 
261 	for (i = 1; i < ZEND_JIT_TRACE_NUM; i++) {
262 		if (zend_jit_traces[i].code_start == addr) {
263 			return i;
264 		}
265 	}
266 	return 0;
267 }
268 
zend_jit_trace_name(const zend_op_array * op_array,uint32_t lineno)269 static zend_string *zend_jit_trace_name(const zend_op_array *op_array, uint32_t lineno)
270 {
271 	smart_str buf = {0};
272 
273 	smart_str_appends(&buf, TRACE_PREFIX);
274 	smart_str_append_long(&buf, (zend_long)ZEND_JIT_TRACE_NUM);
275 	smart_str_appendc(&buf, '$');
276 	if (op_array->function_name) {
277 		if (op_array->scope) {
278 			smart_str_appendl(&buf, ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name));
279 			smart_str_appends(&buf, "::");
280 			smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
281 		} else {
282 			smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
283 		}
284 	} else if (op_array->filename) {
285 		smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
286 	}
287 	smart_str_appendc(&buf, '$');
288 	smart_str_append_long(&buf, (zend_long)lineno);
289 	smart_str_0(&buf);
290 	return buf.s;
291 }
292 
zend_jit_trace_may_exit(const zend_op_array * op_array,const zend_op * opline)293 static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline)
294 {
295 	switch (opline->opcode) {
296 		case ZEND_IS_IDENTICAL:
297 		case ZEND_IS_NOT_IDENTICAL:
298 		case ZEND_IS_EQUAL:
299 		case ZEND_IS_NOT_EQUAL:
300 		case ZEND_IS_SMALLER:
301 		case ZEND_IS_SMALLER_OR_EQUAL:
302 		case ZEND_CASE:
303 		case ZEND_CASE_STRICT:
304 		case ZEND_ISSET_ISEMPTY_CV:
305 		case ZEND_ISSET_ISEMPTY_VAR:
306 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
307 		case ZEND_ISSET_ISEMPTY_PROP_OBJ:
308 		case ZEND_ISSET_ISEMPTY_STATIC_PROP:
309 		case ZEND_INSTANCEOF:
310 		case ZEND_TYPE_CHECK:
311 		case ZEND_DEFINED:
312 		case ZEND_IN_ARRAY:
313 		case ZEND_ARRAY_KEY_EXISTS:
314 			if (opline->result_type & (IS_SMART_BRANCH_JMPNZ | IS_SMART_BRANCH_JMPZ)) {
315 				/* smart branch */
316 				return 1;
317 			}
318 			break;
319 		case ZEND_JMPZ:
320 		case ZEND_JMPNZ:
321 		case ZEND_JMPZ_EX:
322 		case ZEND_JMPNZ_EX:
323 		case ZEND_JMP_SET:
324 		case ZEND_COALESCE:
325 		case ZEND_JMP_NULL:
326 		case ZEND_FE_RESET_R:
327 		case ZEND_FE_RESET_RW:
328 		case ZEND_ASSERT_CHECK:
329 		case ZEND_FE_FETCH_R:
330 		case ZEND_FE_FETCH_RW:
331 		case ZEND_SWITCH_LONG:
332 		case ZEND_SWITCH_STRING:
333 		case ZEND_MATCH:
334 			/* branch opcodes */
335 			return 1;
336 		case ZEND_NEW:
337 			if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
338 				/* NEW may skip constructor without arguments */
339 				return 1;
340 			}
341 			break;
342 		case ZEND_CATCH:
343 		case ZEND_FAST_CALL:
344 		case ZEND_FAST_RET:
345 		case ZEND_GENERATOR_CREATE:
346 		case ZEND_GENERATOR_RETURN:
347 		case ZEND_EXIT:
348 		case ZEND_YIELD:
349 		case ZEND_YIELD_FROM:
350 		case ZEND_INCLUDE_OR_EVAL:
351 		case ZEND_MATCH_ERROR:
352 			/* unsupported */
353 			return 1;
354 		case ZEND_DO_FCALL:
355 			/* potentially polymorphic call */
356 			return 1;
357 #if 0
358 		case ZEND_DO_UCALL:
359 		case ZEND_DO_FCALL_BY_NAME:
360 			/* monomorphic call */
361 			// TODO: recompilation may change target ???
362 			return 0;
363 #endif
364 		case ZEND_RETURN_BY_REF:
365 		case ZEND_RETURN:
366 			/* return */
367 			return !JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame));
368 		default:
369 			break;
370 	}
371 	return 0;
372 }
373 
zend_jit_trace_type_to_info_ex(zend_uchar type,uint32_t info)374 static zend_always_inline uint32_t zend_jit_trace_type_to_info_ex(zend_uchar type, uint32_t info)
375 {
376 	if (type == IS_UNKNOWN) {
377 		return info;
378 	}
379 	ZEND_ASSERT(info & (1 << type));
380 	if (type < IS_STRING) {
381 		return (1 << type);
382 	} else if (type != IS_ARRAY) {
383 		return (1 << type) | (info & (MAY_BE_RC1|MAY_BE_RCN));
384 	} else {
385 		return MAY_BE_ARRAY | (info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
386 	}
387 }
388 
zend_jit_trace_type_to_info(zend_uchar type)389 static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
390 {
391 	return zend_jit_trace_type_to_info_ex(type, -1);
392 }
393 
zend_jit_var_may_alias(const zend_op_array * op_array,const zend_ssa * ssa,uint32_t var)394 static zend_always_inline zend_ssa_alias_kind zend_jit_var_may_alias(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t var)
395 {
396 	if (var >= op_array->last_var) {
397 		return NO_ALIAS;
398 	} else if ((!op_array->function_name || (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS))) {
399 		return SYMTABLE_ALIAS;
400 	} else if (ssa->vars) {
401 		return ssa->vars[var].alias;
402 	} else if (zend_string_equals_literal(op_array->vars[var], "http_response_header")) {
403 		return HTTP_RESPONSE_HEADER_ALIAS;
404 	}
405 	return NO_ALIAS;
406 }
407 
zend_jit_trace_add_op_guard(zend_ssa * tssa,int ssa_var,uint8_t op_type)408 static zend_always_inline void zend_jit_trace_add_op_guard(zend_ssa             *tssa,
409                                                            int                   ssa_var,
410                                                            uint8_t               op_type)
411 {
412 	zend_ssa_var_info *info = &tssa->var_info[ssa_var];
413 
414 	if ((info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << op_type)) {
415 		if (UNEXPECTED(tssa->vars[ssa_var].alias != NO_ALIAS)) {
416 			info->type |= MAY_BE_GUARD;
417 		} else {
418 			info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex(op_type, info->type);
419 		}
420 	}
421 }
422 
423 #define ADD_OP_GUARD(_ssa_var, _op_type) do { \
424 		if (_ssa_var >= 0 && _op_type != IS_UNKNOWN) { \
425 			zend_jit_trace_add_op_guard(tssa, _ssa_var, _op_type); \
426 		} \
427 	} while (0)
428 
429 #define CHECK_OP_TRACE_TYPE(_var, _ssa_var, op_info, op_type) do { \
430 		if (op_type != IS_UNKNOWN) { \
431 			if ((op_info & MAY_BE_GUARD) != 0) { \
432 				if (!zend_jit_type_guard(&dasm_state, opline, _var, op_type)) { \
433 					goto jit_failure; \
434 				} \
435 				if (ssa->vars[_ssa_var].alias != NO_ALIAS) { \
436 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), IS_UNKNOWN, 1); \
437 					op_info = zend_jit_trace_type_to_info(op_type); \
438 				} else { \
439 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), op_type, 1); \
440 					op_info &= ~MAY_BE_GUARD; \
441 					ssa->var_info[_ssa_var].type &= op_info; \
442 				} \
443 			} \
444 		} \
445 	} while (0)
446 
447 #define ADD_OP1_TRACE_GUARD() \
448 	ADD_OP_GUARD(tssa->ops[idx].op1_use, op1_type)
449 #define ADD_OP2_TRACE_GUARD() \
450 	ADD_OP_GUARD(tssa->ops[idx].op2_use, op2_type)
451 #define ADD_OP1_DATA_TRACE_GUARD() \
452 	ADD_OP_GUARD(tssa->ops[idx+1].op1_use, op3_type)
453 
454 #define CHECK_OP1_TRACE_TYPE() \
455 	CHECK_OP_TRACE_TYPE(opline->op1.var, ssa_op->op1_use, op1_info, op1_type)
456 #define CHECK_OP2_TRACE_TYPE() \
457 	CHECK_OP_TRACE_TYPE(opline->op2.var, ssa_op->op2_use, op2_info, op2_type)
458 #define CHECK_OP1_DATA_TRACE_TYPE() \
459 	CHECK_OP_TRACE_TYPE((opline+1)->op1.var, (ssa_op+1)->op1_use, op1_data_info, op3_type)
460 
zend_jit_trace_frame_size(const zend_op_array * op_array)461 static zend_always_inline size_t zend_jit_trace_frame_size(const zend_op_array *op_array)
462 {
463 	if (op_array && op_array->type == ZEND_USER_FUNCTION) {
464 		return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE((op_array->last_var + op_array->T) * sizeof(zend_jit_trace_stack)));
465 	} else if (op_array) {
466 		return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE(op_array->num_args * sizeof(zend_jit_trace_stack)));
467 	} else {
468 		return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack));
469 	}
470 }
471 
zend_jit_trace_call_frame(zend_jit_trace_stack_frame * frame,const zend_op_array * op_array)472 static zend_jit_trace_stack_frame* zend_jit_trace_call_frame(zend_jit_trace_stack_frame *frame, const zend_op_array *op_array)
473 {
474 	return (zend_jit_trace_stack_frame*)((char*)frame + zend_jit_trace_frame_size(op_array));
475 }
476 
zend_jit_trace_ret_frame(zend_jit_trace_stack_frame * frame,const zend_op_array * op_array)477 static zend_jit_trace_stack_frame* zend_jit_trace_ret_frame(zend_jit_trace_stack_frame *frame, const zend_op_array *op_array)
478 {
479 	return (zend_jit_trace_stack_frame*)((char*)frame - zend_jit_trace_frame_size(op_array));
480 }
481 
zend_jit_trace_send_type(const zend_op * opline,zend_jit_trace_stack_frame * call,zend_uchar type)482 static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack_frame *call, zend_uchar type)
483 {
484 	zend_jit_trace_stack *stack = call->stack;
485 	const zend_op_array *op_array = &call->func->op_array;
486 	uint32_t arg_num = opline->op2.num;
487 
488 	if (arg_num > op_array->num_args) {
489 		return;
490 	}
491 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
492 		zend_arg_info *arg_info;
493 
494 		ZEND_ASSERT(arg_num <= op_array->num_args);
495 		arg_info = &op_array->arg_info[arg_num-1];
496 
497 		if (ZEND_TYPE_IS_SET(arg_info->type)) {
498 			if (!(ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))) {
499 				return;
500 			}
501 		}
502 	}
503 	SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
504 }
505 
zend_jit_needs_arg_dtor(const zend_function * func,uint32_t arg_num,zend_call_info * call_info)506 static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info)
507 {
508 	if (func
509 	 && func->type == ZEND_INTERNAL_FUNCTION
510 	 && (func->internal_function.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0
511 	 && arg_num < func->internal_function.num_args) {
512 		const zend_internal_arg_info *arg_info = &func->internal_function.arg_info[arg_num];
513 
514 		if (ZEND_ARG_SEND_MODE(arg_info) == ZEND_SEND_BY_VAL
515 		 && ZEND_TYPE_IS_SET(arg_info->type)
516 		 && (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_ANY) != MAY_BE_ANY) {
517 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
518 			 && JIT_G(current_frame)
519 			 && JIT_G(current_frame)->call
520 			 && JIT_G(current_frame)->call->func) {
521 				uint32_t type = STACK_TYPE(JIT_G(current_frame)->call->stack, arg_num);
522 
523 				if (type != IS_UNKNOWN
524 				 && type < IS_STRING
525 				 && ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type)) {
526 					return 0;
527 				}
528 			}
529 			if (call_info && arg_num < call_info->num_args && call_info->arg_info[arg_num].opline) {
530 				const zend_op *opline = call_info->arg_info[arg_num].opline;
531 
532 				if (opline->opcode == ZEND_SEND_VAL && opline->op1_type == IS_CONST) {
533 					zval *zv = RT_CONSTANT(opline, opline->op1);
534 
535 					if (!Z_REFCOUNTED_P(zv)) {
536 						uint32_t type = Z_TYPE_P(zv);
537 
538 						// TODO: few functions (e.g. pcntl_exec) modify arrays in-place ???
539 						if (type != IS_ARRAY
540 						 && (ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))) {
541 							return 0;
542 						}
543 					}
544 				}
545 			}
546 		}
547 	}
548 
549 	return 1;
550 }
551 
zend_jit_trace_build_ssa(const zend_op_array * op_array,zend_script * script)552 static zend_ssa *zend_jit_trace_build_ssa(const zend_op_array *op_array, zend_script *script)
553 {
554 	zend_jit_op_array_trace_extension *jit_extension;
555 	zend_ssa *ssa;
556 
557 	jit_extension =
558 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
559 	jit_extension->func_info.num = 0;
560 	jit_extension->func_info.flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
561 		| ZEND_FUNC_JIT_ON_PROF_REQUEST
562 		| ZEND_FUNC_JIT_ON_HOT_COUNTERS
563 		| ZEND_FUNC_JIT_ON_HOT_TRACE;
564 	memset(&jit_extension->func_info.ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
565 	ssa = &jit_extension->func_info.ssa;
566 
567 	if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) {
568 		do {
569 			if (zend_jit_op_array_analyze1(op_array, script, ssa) != SUCCESS) {
570 				break;
571 			}
572 
573 			if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNCS) {
574 				zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, (zend_op_array*)op_array, &jit_extension->func_info);
575 				jit_extension->func_info.call_map = zend_build_call_map(&CG(arena), &jit_extension->func_info, op_array);
576 				if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
577 					zend_init_func_return_info(op_array, script, &jit_extension->func_info.return_info);
578 				}
579 			}
580 
581 			if (zend_jit_op_array_analyze2(op_array, script, ssa, 0) != SUCCESS) {
582 				break;
583 			}
584 
585 			if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
586 				zend_dump_op_array(op_array, ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", ssa);
587 			}
588 			return ssa;
589 		} while (0);
590 	}
591 
592 	memset(ssa, 0, sizeof(zend_ssa));
593 	ssa->cfg.blocks_count = 1;
594 
595 	if (JIT_G(opt_level) == ZEND_JIT_LEVEL_INLINE) {
596 		zend_cfg cfg;
597 		void *checkpoint = zend_arena_checkpoint(CG(arena));
598 
599 		if (zend_jit_build_cfg(op_array, &cfg) == SUCCESS) {
600 			ssa->cfg.flags = cfg.flags;
601 		} else{
602 			ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
603 		}
604 
605 		/* TODO: move this to zend_cfg.c ? */
606 		if (!op_array->function_name) {
607 			ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
608 		}
609 
610 		zend_arena_release(&CG(arena), checkpoint);
611 	}
612 
613 	return ssa;
614 }
615 
616 static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa);
617 static void zend_jit_dump_exit_info(zend_jit_trace_info *t);
618 
zend_jit_trace_op_len(const zend_op * opline)619 static zend_always_inline int zend_jit_trace_op_len(const zend_op *opline)
620 {
621 	int len;
622 
623 	switch (opline->opcode) {
624 		case ZEND_ASSIGN_DIM:
625 		case ZEND_ASSIGN_OBJ:
626 		case ZEND_ASSIGN_STATIC_PROP:
627 		case ZEND_ASSIGN_DIM_OP:
628 		case ZEND_ASSIGN_OBJ_OP:
629 		case ZEND_ASSIGN_STATIC_PROP_OP:
630 		case ZEND_ASSIGN_OBJ_REF:
631 		case ZEND_ASSIGN_STATIC_PROP_REF:
632 			return 2; /* OP_DATA */
633 		case ZEND_RECV_INIT:
634 			len = 1;
635 			opline++;
636 			while (opline->opcode == ZEND_RECV_INIT) {
637 				len++;
638 				opline++;
639 			}
640 			return len;
641 		case ZEND_BIND_GLOBAL:
642 			len = 1;
643 			opline++;
644 			while (opline->opcode == ZEND_BIND_GLOBAL) {
645 				len++;
646 				opline++;
647 			}
648 			return len;
649 //		case ZEND_IS_IDENTICAL:
650 //		case ZEND_IS_NOT_IDENTICAL:
651 //		case ZEND_IS_EQUAL:
652 //		case ZEND_IS_NOT_EQUAL:
653 //		case ZEND_IS_SMALLER:
654 //		case ZEND_IS_SMALLER_OR_EQUAL:
655 //		case ZEND_CASE:
656 //		case ZEND_ISSET_ISEMPTY_CV:
657 //		case ZEND_ISSET_ISEMPTY_VAR:
658 //		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
659 //		case ZEND_ISSET_ISEMPTY_PROP_OBJ:
660 //		case ZEND_ISSET_ISEMPTY_STATIC_PROP:
661 //		case ZEND_INSTANCEOF:
662 //		case ZEND_TYPE_CHECK:
663 //		case ZEND_DEFINED:
664 //		case ZEND_IN_ARRAY:
665 //		case ZEND_ARRAY_KEY_EXISTS:
666 		default:
667 			if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
668 				return 2; /* JMPZ/JMPNZ */
669 			}
670 			return 1;
671 	}
672 }
673 
zend_jit_trace_add_phis(zend_jit_trace_rec * trace_buffer,uint32_t ssa_vars_count,zend_ssa * tssa,zend_jit_trace_stack * stack)674 static int zend_jit_trace_add_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
675 {
676 	const zend_op_array *op_array;
677 	zend_jit_trace_rec *p;
678 	int k, vars_count;
679 	zend_bitset use, def;
680 	uint32_t build_flags = ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS;
681 	uint32_t set_size;
682 	zend_ssa_phi *prev = NULL;
683 	int level = 0;
684 	ALLOCA_FLAG(use_heap);
685 
686 	op_array = trace_buffer->op_array;
687 	set_size = zend_bitset_len(op_array->last_var + op_array->T);
688 	use = ZEND_BITSET_ALLOCA(set_size * 2, use_heap);
689 	memset(use, 0, set_size * 2 * ZEND_BITSET_ELM_SIZE);
690 	def = use + set_size;
691 	p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
692 	for (;;p++) {
693 		if (p->op == ZEND_JIT_TRACE_VM && level == 0) {
694 			const zend_op *opline = p->opline;
695 			int len;
696 
697 			zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
698 			len = zend_jit_trace_op_len(opline);
699 			while (len > 1) {
700 				opline++;
701 				if (opline->opcode != ZEND_OP_DATA) {
702 					zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
703 				}
704 				len--;
705 			}
706 		} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
707 		} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
708 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
709 			level++;
710 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
711 			if (level == 0) {
712 				// Phi for recursive calls and returns are not supported yet ???
713 				assert(0);
714 			} else {
715 				level--;
716 			}
717 		} else if (p->op == ZEND_JIT_TRACE_END) {
718 			break;
719 		}
720 	}
721 
722 	zend_bitset_intersection(use, def, set_size);
723 
724 	if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
725 		vars_count = op_array->last_var;
726 	} else {
727 		vars_count = op_array->last_var + op_array->T;
728 	}
729 	for (k = 0; k < vars_count; k++) {
730 		if (zend_bitset_in(use, k)) {
731 			zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
732 				ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
733 				ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
734 				sizeof(void*) * 2);
735 			phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
736 			phi->sources[0] = STACK_VAR(stack, k);
737 			phi->sources[1] = -1;
738 			phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
739 			phi->pi = -1;
740 			phi->var = k;
741 			phi->ssa_var = ssa_vars_count;
742 			SET_STACK_VAR(stack, k, ssa_vars_count);
743 			ssa_vars_count++;
744 			phi->block = 1;
745 			if (prev) {
746 				prev->next = phi;
747 			} else {
748 				tssa->blocks[1].phis = phi;
749 			}
750 			prev = phi;
751 		}
752 	}
753 
754 	free_alloca(use, use_heap);
755 
756 	return ssa_vars_count;
757 }
758 
zend_jit_trace_add_call_phis(zend_jit_trace_rec * trace_buffer,uint32_t ssa_vars_count,zend_ssa * tssa,zend_jit_trace_stack * stack)759 static int zend_jit_trace_add_call_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
760 {
761 	zend_ssa_phi *prev = NULL;
762 	const zend_op_array *op_array = trace_buffer->op_array;
763 	const zend_op *opline = trace_buffer[1].opline;
764 	int count = opline - op_array->opcodes;
765 	int i;
766 
767 	for(i = 0; i < count; i++) {
768 		zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
769 			ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
770 			ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
771 			sizeof(void*) * 2);
772 		phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
773 		phi->sources[0] = STACK_VAR(stack, i);
774 		phi->sources[1] = -1;
775 		phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
776 		phi->pi = -1;
777 		phi->var = i;
778 		phi->ssa_var = ssa_vars_count;
779 		SET_STACK_VAR(stack, i, ssa_vars_count);
780 		ssa_vars_count++;
781 		phi->block = 1;
782 		if (prev) {
783 			prev->next = phi;
784 		} else {
785 			tssa->blocks[1].phis = phi;
786 		}
787 		prev = phi;
788 	}
789 	return ssa_vars_count;
790 }
791 
zend_jit_trace_add_ret_phis(zend_jit_trace_rec * trace_buffer,uint32_t ssa_vars_count,zend_ssa * tssa,zend_jit_trace_stack * stack)792 static int zend_jit_trace_add_ret_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
793 {
794 	const zend_op *opline = trace_buffer[1].opline - 1;
795 	int i;
796 
797 	if (RETURN_VALUE_USED(opline)) {
798 		zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
799 			ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
800 			ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
801 			sizeof(void*) * 2);
802 
803 		i = EX_VAR_TO_NUM(opline->result.var);
804 		phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
805 		phi->sources[0] = STACK_VAR(stack, i);
806 		phi->sources[1] = -1;
807 		phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
808 		phi->pi = -1;
809 		phi->var = i;
810 		phi->ssa_var = ssa_vars_count;
811 		SET_STACK_VAR(stack, i, ssa_vars_count);
812 		ssa_vars_count++;
813 		phi->block = 1;
814 		tssa->blocks[1].phis = phi;
815 	}
816 	return ssa_vars_count;
817 }
818 
zend_jit_trace_copy_ssa_var_info(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)819 static int zend_jit_trace_copy_ssa_var_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
820 {
821 	int var, use;
822 	zend_ssa_op *op;
823 	zend_ssa_var_info *info;
824 	unsigned int no_val;
825 	zend_ssa_alias_kind alias;
826 
827 	if (tssa->vars[ssa_var].phi_use_chain) {
828 		// TODO: this may be incorrect ???
829 		var = tssa->vars[ssa_var].phi_use_chain->ssa_var;
830 	} else {
831 		var = ssa_var;
832 	}
833 	use = tssa->vars[var].use_chain;
834 	if (use >= 0) {
835 		ZEND_ASSERT((tssa_opcodes[use] - op_array->opcodes) < op_array->last);
836 		op = ssa->ops + (tssa_opcodes[use] - op_array->opcodes);
837 		if (tssa->ops[use].op1_use == var) {
838 			no_val = ssa->vars[op->op1_use].no_val;
839 			alias = ssa->vars[op->op1_use].alias;
840 			info = ssa->var_info + op->op1_use;
841 		} else if (tssa->ops[use].op2_use == var) {
842 			no_val = ssa->vars[op->op2_use].no_val;
843 			alias = ssa->vars[op->op2_use].alias;
844 			info = ssa->var_info + op->op2_use;
845 		} else if (tssa->ops[use].result_use == var) {
846 			no_val = ssa->vars[op->result_use].no_val;
847 			alias = ssa->vars[op->result_use].alias;
848 			info = ssa->var_info + op->result_use;
849 		} else {
850 			assert(0);
851 			return 0;
852 		}
853 		tssa->vars[ssa_var].no_val = no_val;
854 		tssa->vars[ssa_var].alias = alias;
855 		memcpy(&tssa->var_info[ssa_var], info, sizeof(zend_ssa_var_info));
856 		return 1;
857 	}
858 	return 0;
859 }
860 
zend_jit_trace_propagate_range(const zend_op_array * op_array,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)861 static void zend_jit_trace_propagate_range(const zend_op_array *op_array, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
862 {
863 	zend_ssa_range tmp;
864 	int def = tssa->vars[ssa_var].definition;
865 
866 	if (tssa->vars[ssa_var].alias == NO_ALIAS
867 	 && zend_inference_propagate_range(op_array, tssa, (zend_op*)tssa_opcodes[def], (zend_ssa_op*)&tssa->ops[def], ssa_var, &tmp)) {
868 		tssa->var_info[ssa_var].range.min = tmp.min;
869 		tssa->var_info[ssa_var].range.max = tmp.max;
870 		tssa->var_info[ssa_var].range.underflow = tmp.underflow;
871 		tssa->var_info[ssa_var].range.overflow = tmp.overflow;
872 		tssa->var_info[ssa_var].has_range = 1;
873 	}
874 }
875 
zend_jit_trace_copy_ssa_var_range(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)876 static void zend_jit_trace_copy_ssa_var_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
877 {
878 	int def;
879 	zend_ssa_op *op;
880 	zend_ssa_var_info *info;
881 	unsigned int no_val;
882 	zend_ssa_alias_kind alias;
883 
884 	def = tssa->vars[ssa_var].definition;
885 	if (def >= 0) {
886 		ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
887 		op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
888 		if (tssa->ops[def].op1_def == ssa_var) {
889 			no_val = ssa->vars[op->op1_def].no_val;
890 			alias = ssa->vars[op->op1_def].alias;
891 			info = ssa->var_info + op->op1_def;
892 		} else if (tssa->ops[def].op2_def == ssa_var) {
893 			no_val = ssa->vars[op->op2_def].no_val;
894 			alias = ssa->vars[op->op2_def].alias;
895 			info = ssa->var_info + op->op2_def;
896 		} else if (tssa->ops[def].result_def == ssa_var) {
897 			no_val = ssa->vars[op->result_def].no_val;
898 			alias = ssa->vars[op->result_def].alias;
899 			info = ssa->var_info + op->result_def;
900 		} else {
901 			assert(0);
902 			return;
903 		}
904 
905 		tssa->vars[ssa_var].no_val = no_val;
906 		tssa->vars[ssa_var].alias = alias;
907 
908 		if (!(info->type & MAY_BE_REF)) {
909 			zend_jit_trace_propagate_range(op_array, tssa_opcodes, tssa, ssa_var);
910 		}
911 
912 		if (info->has_range) {
913 			if (tssa->var_info[ssa_var].has_range) {
914 				tssa->var_info[ssa_var].range.min = MAX(tssa->var_info[ssa_var].range.min, info->range.min);
915 				tssa->var_info[ssa_var].range.max = MIN(tssa->var_info[ssa_var].range.max, info->range.max);
916 				tssa->var_info[ssa_var].range.underflow = tssa->var_info[ssa_var].range.underflow && info->range.underflow;
917 				tssa->var_info[ssa_var].range.overflow = tssa->var_info[ssa_var].range.overflow && info->range.overflow;
918 			} else {
919 				tssa->var_info[ssa_var].has_range = 1;
920 				tssa->var_info[ssa_var].range = info->range;
921 			}
922 		}
923 	}
924 }
925 
zend_jit_trace_restrict_ssa_var_info(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)926 static int zend_jit_trace_restrict_ssa_var_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
927 {
928 	int def;
929 	zend_ssa_op *op;
930 	zend_ssa_var_info *info;
931 
932 	def = tssa->vars[ssa_var].definition;
933 	if (def >= 0) {
934 		ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
935 		op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
936 		if (tssa->ops[def].op1_def == ssa_var) {
937 			info = ssa->var_info + op->op1_def;
938 		} else if (tssa->ops[def].op2_def == ssa_var) {
939 			info = ssa->var_info + op->op2_def;
940 		} else if (tssa->ops[def].result_def == ssa_var) {
941 			info = ssa->var_info + op->result_def;
942 		} else {
943 			assert(0);
944 			return 0;
945 		}
946 		tssa->var_info[ssa_var].type &= info->type;
947 		if (info->ce) {
948 			if (tssa->var_info[ssa_var].ce) {
949 				if (tssa->var_info[ssa_var].ce != info->ce) {
950 					if (instanceof_function(tssa->var_info[ssa_var].ce, info->ce)) {
951 						/* everything fine */
952 					} else if (instanceof_function(info->ce, tssa->var_info[ssa_var].ce)) {
953 						// TODO: TSSA may miss Pi() functions and corresponding instanceof() constraints ???
954 					} else {
955 						// TODO: classes may implement the same interface ???
956 						//ZEND_UNREACHABLE();
957 					}
958 				}
959 				tssa->var_info[ssa_var].is_instanceof =
960 					tssa->var_info[ssa_var].is_instanceof && info->is_instanceof;
961 			} else {
962 				tssa->var_info[ssa_var].ce = info->ce;
963 				tssa->var_info[ssa_var].is_instanceof = info->is_instanceof;
964 			}
965 		}
966 		if (info->has_range) {
967 			if (tssa->var_info[ssa_var].has_range) {
968 				tssa->var_info[ssa_var].range.min = MAX(tssa->var_info[ssa_var].range.min, info->range.min);
969 				tssa->var_info[ssa_var].range.max = MIN(tssa->var_info[ssa_var].range.max, info->range.max);
970 				tssa->var_info[ssa_var].range.underflow = tssa->var_info[ssa_var].range.underflow && info->range.underflow;
971 				tssa->var_info[ssa_var].range.overflow = tssa->var_info[ssa_var].range.overflow && info->range.overflow;
972 			} else {
973 				tssa->var_info[ssa_var].has_range = 1;
974 				tssa->var_info[ssa_var].range = info->range;
975 			}
976 		}
977 		return 1;
978 	}
979 	return 0;
980 }
981 
find_return_ssa_var(zend_jit_trace_rec * p,zend_ssa_op * ssa_op)982 static int find_return_ssa_var(zend_jit_trace_rec *p, zend_ssa_op *ssa_op)
983 {
984 	while (1) {
985 		if (p->op == ZEND_JIT_TRACE_VM) {
986 			if (p->opline->opcode == ZEND_DO_UCALL
987 			 || p->opline->opcode == ZEND_DO_FCALL_BY_NAME
988 			 || p->opline->opcode == ZEND_DO_FCALL) {
989 				if (p->opline->result_type != IS_UNUSED) {
990 					return ssa_op->result_def;
991 				}
992 			}
993 			return -1;
994 		} else if (p->op >= ZEND_JIT_TRACE_OP1_TYPE && p->op <= ZEND_JIT_TRACE_VAL_INFO) {
995 			/*skip */
996 		} else {
997 			return -1;
998 		}
999 		p--;
1000 	}
1001 }
1002 
zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec * p,const zend_op_array * op_array)1003 static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, const zend_op_array *op_array)
1004 {
1005 	if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
1006 		p--;
1007 		while (1) {
1008 			if (p->op == ZEND_JIT_TRACE_VM) {
1009 				if (p->opline->opcode == ZEND_INIT_FCALL
1010 				 || p->opline->opcode == ZEND_INIT_FCALL_BY_NAME
1011 				 || p->opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME
1012 				 || p->opline->opcode == ZEND_INIT_DYNAMIC_CALL
1013 				 || p->opline->opcode == ZEND_INIT_USER_CALL
1014 				 || p->opline->opcode == ZEND_NEW
1015 				 || p->opline->opcode == ZEND_INIT_METHOD_CALL
1016 				 || p->opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
1017 					return p->opline;
1018 				}
1019 				return NULL;
1020 			} else if (p->op >= ZEND_JIT_TRACE_OP1_TYPE && p->op <= ZEND_JIT_TRACE_VAL_INFO) {
1021 				/*skip */
1022 			} else {
1023 				return NULL;
1024 			}
1025 			p--;
1026 		}
1027 	} else {
1028 		const zend_op *opline = NULL;
1029 		int call_level = 0;
1030 
1031 		p++;
1032 		while (1) {
1033 			if (p->op == ZEND_JIT_TRACE_VM) {
1034 				opline = p->opline;
1035 				break;
1036 			} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1037 				call_level++;
1038 				/*skip */
1039 			} else {
1040 				return NULL;
1041 			}
1042 			p--;
1043 		}
1044 		if (opline) {
1045 			while (opline > op_array->opcodes) {
1046 				opline--;
1047 				switch (opline->opcode) {
1048 					case ZEND_INIT_FCALL:
1049 					case ZEND_INIT_FCALL_BY_NAME:
1050 					case ZEND_INIT_NS_FCALL_BY_NAME:
1051 					case ZEND_INIT_METHOD_CALL:
1052 					case ZEND_INIT_DYNAMIC_CALL:
1053 					case ZEND_INIT_STATIC_METHOD_CALL:
1054 					case ZEND_INIT_USER_CALL:
1055 					case ZEND_NEW:
1056 						if (call_level == 0) {
1057 							return opline;
1058 						}
1059 						call_level--;
1060 						break;
1061 					case ZEND_DO_FCALL:
1062 					case ZEND_DO_ICALL:
1063 					case ZEND_DO_UCALL:
1064 					case ZEND_DO_FCALL_BY_NAME:
1065 					case ZEND_CALLABLE_CONVERT:
1066 						call_level++;
1067 						break;
1068 				}
1069 			}
1070 		}
1071 	}
1072 	return NULL;
1073 }
1074 
is_checked_guard(const zend_ssa * tssa,const zend_op ** ssa_opcodes,uint32_t var,uint32_t phi_var)1075 static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, uint32_t var, uint32_t phi_var)
1076 {
1077 	if ((tssa->var_info[phi_var].type & MAY_BE_ANY) == MAY_BE_LONG
1078 	 && !(tssa->var_info[var].type & MAY_BE_REF)) {
1079 		int idx = tssa->vars[var].definition;
1080 
1081 		if (idx >= 0) {
1082 			if (tssa->ops[idx].op1_def == var) {
1083 				const zend_op *opline = ssa_opcodes[idx];
1084 				if (opline->opcode == ZEND_PRE_DEC
1085 				 || opline->opcode == ZEND_PRE_INC
1086 				 || opline->opcode == ZEND_POST_DEC
1087 				 || opline->opcode == ZEND_POST_INC) {
1088 					if (tssa->ops[idx].op1_use >= 0
1089 					 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_STRING)) {
1090 						return 0;
1091 					}
1092 					if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1093 						return 0;
1094 					}
1095 					return 1;
1096 				} else if (opline->opcode == ZEND_ASSIGN_OP
1097 				 && (opline->extended_value == ZEND_ADD
1098 				  || opline->extended_value == ZEND_SUB
1099 				  || opline->extended_value == ZEND_MUL)) {
1100 					if ((opline->op2_type & (IS_VAR|IS_CV))
1101 					  && tssa->ops[idx].op2_use >= 0
1102 					  && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) {
1103 						return 0;
1104 					}
1105 					if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1106 						return 0;
1107 					}
1108 					if (opline->op2_type == IS_CONST) {
1109 						zval *zv = RT_CONSTANT(opline, opline->op2);
1110 						if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1111 							return 0;
1112 						}
1113 					} else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1114 						return 0;
1115 					}
1116 					return 1;
1117 				}
1118 			}
1119 			if (tssa->ops[idx].result_def == var) {
1120 				const zend_op *opline = ssa_opcodes[idx];
1121 				if (opline->opcode == ZEND_ADD
1122 				 || opline->opcode == ZEND_SUB
1123 				 || opline->opcode == ZEND_MUL) {
1124 					if ((opline->op1_type & (IS_VAR|IS_CV))
1125 					  && tssa->ops[idx].op1_use >= 0
1126 					  && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1127 						return 0;
1128 					}
1129 					if ((opline->op2_type & (IS_VAR|IS_CV))
1130 					  && tssa->ops[idx].op2_use >= 0
1131 					  && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) {
1132 						return 0;
1133 					}
1134 					if (opline->op1_type == IS_CONST) {
1135 						zval *zv = RT_CONSTANT(opline, opline->op1);
1136 						if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1137 							return 0;
1138 						}
1139 					} else if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1140 						return 0;
1141 					}
1142 					if (opline->op2_type == IS_CONST) {
1143 						zval *zv = RT_CONSTANT(opline, opline->op2);
1144 						if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1145 							return 0;
1146 						}
1147 					} else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1148 						return 0;
1149 					}
1150 				} else if (opline->opcode == ZEND_PRE_DEC
1151 				 || opline->opcode == ZEND_PRE_INC
1152 				 || opline->opcode == ZEND_POST_DEC
1153 				 || opline->opcode == ZEND_POST_INC) {
1154 					if ((opline->op1_type & (IS_VAR|IS_CV))
1155 					  && tssa->ops[idx].op1_use >= 0
1156 					  && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1157 						return 0;
1158 					}
1159 					if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1160 						return 0;
1161 					}
1162 					return 1;
1163 				}
1164 			}
1165 		}
1166 	}
1167 	return 0;
1168 }
1169 
1170 typedef struct _zend_tssa {
1171 	zend_ssa        ssa;
1172 	const zend_op **tssa_opcodes;
1173 	int             used_stack;
1174 } zend_tssa;
1175 
1176 static const zend_op _nop_opcode = {0};
1177 
zend_jit_trace_build_tssa(zend_jit_trace_rec * trace_buffer,uint32_t parent_trace,uint32_t exit_num,zend_script * script,const zend_op_array ** op_arrays,int * num_op_arrays_ptr)1178 static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num, zend_script *script, const zend_op_array **op_arrays, int *num_op_arrays_ptr)
1179 {
1180 	zend_ssa *tssa;
1181 	zend_ssa_op *ssa_ops, *op;
1182 	zend_ssa_var *ssa_vars;
1183 	zend_ssa_var_info *ssa_var_info;
1184 	const zend_op_array *op_array;
1185 	const zend_op *opline;
1186 	const zend_op **ssa_opcodes;
1187 	zend_jit_trace_rec *p;
1188 	int i, v, idx, len, ssa_ops_count, vars_count, ssa_vars_count;
1189 	zend_jit_trace_stack *stack;
1190 	uint32_t build_flags = ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS;
1191 	uint32_t optimization_level = 0;
1192 	int call_level, level, num_op_arrays, used_stack, max_used_stack;
1193 	size_t frame_size, stack_top, stack_size, stack_bottom;
1194 	zend_jit_op_array_trace_extension *jit_extension;
1195 	zend_ssa *ssa;
1196 	zend_jit_trace_stack_frame *frame, *top, *call;
1197 	zend_ssa_var_info return_value_info;
1198 
1199 	/* 1. Count number of TSSA opcodes;
1200 	 *    Count number of activation frames;
1201 	 *    Calculate size of abstract stack;
1202 	 *    Construct regular SSA for involved op_array */
1203 	op_array = trace_buffer->op_array;
1204 	stack_top = stack_size = zend_jit_trace_frame_size(op_array);
1205 	stack_bottom = 0;
1206 	p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1207 	ssa_ops_count = 0;
1208 	call_level = 0;
1209 	level = 0;
1210 	num_op_arrays = 0;
1211 	/* Remember op_array to cleanup */
1212 	op_arrays[num_op_arrays++] = op_array;
1213 	/* Build SSA */
1214 	ssa = zend_jit_trace_build_ssa(op_array, script);
1215 	for (;;p++) {
1216 		if (p->op == ZEND_JIT_TRACE_VM) {
1217 			if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
1218 				const zend_op *opline = p->opline;
1219 
1220 				switch (opline->opcode) {
1221 					case ZEND_INCLUDE_OR_EVAL:
1222 						ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1223 						break;
1224 					case ZEND_FETCH_R:
1225 					case ZEND_FETCH_W:
1226 					case ZEND_FETCH_RW:
1227 					case ZEND_FETCH_FUNC_ARG:
1228 					case ZEND_FETCH_IS:
1229 					case ZEND_FETCH_UNSET:
1230 					case ZEND_UNSET_VAR:
1231 					case ZEND_ISSET_ISEMPTY_VAR:
1232 						if (opline->extended_value & ZEND_FETCH_LOCAL) {
1233 							ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1234 						} else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
1235 						           !op_array->function_name) {
1236 							ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1237 						}
1238 						break;
1239 				}
1240 			}
1241 			ssa_ops_count += zend_jit_trace_op_len(p->opline);
1242 		} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1243 			call_level++;
1244 			stack_top += zend_jit_trace_frame_size(p->op_array);
1245 			if (stack_top > stack_size) {
1246 				stack_size = stack_top;
1247 			}
1248 		} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
1249 			if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
1250 				if (p->func
1251 				 && p->func != (zend_function*)&zend_pass_function
1252 				 && (zend_string_equals_literal(p->func->common.function_name, "extract")
1253 				  || zend_string_equals_literal(p->func->common.function_name, "compact")
1254 				  || zend_string_equals_literal(p->func->common.function_name, "get_defined_vars"))) {
1255 					ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1256 				}
1257 			}
1258 			frame_size = zend_jit_trace_frame_size(p->op_array);
1259 			if (call_level == 0) {
1260 				if (stack_top + frame_size > stack_size) {
1261 					stack_size = stack_top + frame_size;
1262 				}
1263 			} else {
1264 				call_level--;
1265 				stack_top -= frame_size;
1266 			}
1267 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
1268 			op_array = p->op_array;
1269 			if (call_level == 0) {
1270 				stack_top += zend_jit_trace_frame_size(op_array);
1271 				if (stack_top > stack_size) {
1272 					stack_size = stack_top;
1273 				}
1274 			} else {
1275 				call_level--;
1276 			}
1277 			level++;
1278 			jit_extension =
1279 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1280 			ssa = &jit_extension->func_info.ssa;
1281 			if (ssa->cfg.blocks_count) {
1282 				/* pass */
1283 			} else if (num_op_arrays == ZEND_JIT_TRACE_MAX_FUNCS) {
1284 				/* Too many functions in single trace */
1285 				*num_op_arrays_ptr = num_op_arrays;
1286 				return NULL;
1287 			} else {
1288 				/* Remember op_array to cleanup */
1289 				op_arrays[num_op_arrays++] = op_array;
1290 				/* Build SSA */
1291 				ssa = zend_jit_trace_build_ssa(op_array, script);
1292 			}
1293 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
1294 			if (level == 0) {
1295 				stack_bottom += zend_jit_trace_frame_size(p->op_array);
1296 				jit_extension =
1297 					(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1298 				ssa = &jit_extension->func_info.ssa;
1299 				if (ssa->cfg.blocks_count) {
1300 					/* pass */
1301 				} else if (num_op_arrays == ZEND_JIT_TRACE_MAX_FUNCS) {
1302 					/* Too many functions in single trace */
1303 					*num_op_arrays_ptr = num_op_arrays;
1304 					return NULL;
1305 				} else {
1306 					/* Remember op_array to cleanup */
1307 					op_arrays[num_op_arrays++] = op_array;
1308 					/* Build SSA */
1309 					ssa = zend_jit_trace_build_ssa(op_array, script);
1310 				}
1311 			} else {
1312 				stack_top -= zend_jit_trace_frame_size(op_array);
1313 				level--;
1314 			}
1315 			op_array = p->op_array;
1316 		} else if (p->op == ZEND_JIT_TRACE_END) {
1317 			break;
1318 		}
1319 	}
1320 	*num_op_arrays_ptr = num_op_arrays;
1321 
1322 	/* Allocate space for abstract stack */
1323 	JIT_G(current_frame) = frame = (zend_jit_trace_stack_frame*)((char*)zend_arena_alloc(&CG(arena), stack_bottom + stack_size) + stack_bottom);
1324 
1325 	/* 2. Construct TSSA */
1326 	tssa = zend_arena_calloc(&CG(arena), 1, sizeof(zend_tssa));
1327 	tssa->cfg.flags = ZEND_SSA_TSSA;
1328 	tssa->cfg.blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_basic_block));
1329 	tssa->blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_ssa_block));
1330 	tssa->cfg.predecessors = zend_arena_calloc(&CG(arena), 2, sizeof(int));
1331 
1332 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1333 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1334 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1335 		tssa->cfg.blocks_count = 2;
1336 		tssa->cfg.edges_count = 2;
1337 
1338 		tssa->cfg.predecessors[0] = 0;
1339 		tssa->cfg.predecessors[1] = 1;
1340 
1341 		tssa->cfg.blocks[0].flags = ZEND_BB_START|ZEND_BB_REACHABLE;
1342 		tssa->cfg.blocks[0].successors_count = 1;
1343 		tssa->cfg.blocks[0].predecessors_count = 0;
1344 		tssa->cfg.blocks[0].successors = tssa->cfg.blocks[0].successors_storage;
1345 		tssa->cfg.blocks[0].successors[0] = 1;
1346 
1347 		tssa->cfg.blocks[0].flags = ZEND_BB_FOLLOW|ZEND_BB_TARGET|ZEND_BB_LOOP_HEADER|ZEND_BB_REACHABLE;
1348 		tssa->cfg.blocks[1].successors_count = 1;
1349 		tssa->cfg.blocks[1].predecessors_count = 2;
1350 		tssa->cfg.blocks[1].successors = tssa->cfg.blocks[1].successors_storage;
1351 		tssa->cfg.blocks[1].successors[1] = 1;
1352 	} else {
1353 		tssa->cfg.blocks_count = 1;
1354 		tssa->cfg.edges_count = 0;
1355 
1356 		tssa->cfg.blocks[0].flags = ZEND_BB_START|ZEND_BB_EXIT|ZEND_BB_REACHABLE;
1357 		tssa->cfg.blocks[0].successors_count = 0;
1358 		tssa->cfg.blocks[0].predecessors_count = 0;
1359 	}
1360 	((zend_tssa*)tssa)->used_stack = -1;
1361 
1362 	if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1363 		return tssa;
1364 	}
1365 
1366 	tssa->ops = ssa_ops = zend_arena_alloc(&CG(arena), ssa_ops_count * sizeof(zend_ssa_op));
1367 	memset(ssa_ops, -1, ssa_ops_count * sizeof(zend_ssa_op));
1368 	ssa_opcodes = zend_arena_calloc(&CG(arena), ssa_ops_count + 1, sizeof(zend_op*));
1369 	((zend_tssa*)tssa)->tssa_opcodes = ssa_opcodes;
1370 	ssa_opcodes[ssa_ops_count] = &_nop_opcode;
1371 
1372 	op_array = trace_buffer->op_array;
1373 	if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1374 		ssa_vars_count = op_array->last_var;
1375 	} else {
1376 		ssa_vars_count = op_array->last_var + op_array->T;
1377 	}
1378 	stack = frame->stack;
1379 	for (i = 0; i < ssa_vars_count; i++) {
1380 		SET_STACK_VAR(stack, i, i);
1381 	}
1382 
1383 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1384 		// TODO: For tracing, it's possible, to create pseudo Phi functions
1385 		//       at the end of loop, without this additional pass (like LuaJIT) ???
1386 		ssa_vars_count = zend_jit_trace_add_phis(trace_buffer, ssa_vars_count, tssa, stack);
1387 	} else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
1388 		ssa_vars_count = zend_jit_trace_add_call_phis(trace_buffer, ssa_vars_count, tssa, stack);
1389 	} else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1390 		ssa_vars_count = zend_jit_trace_add_ret_phis(trace_buffer, ssa_vars_count, tssa, stack);
1391 	}
1392 
1393 	p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1394 	idx = 0;
1395 	level = 0;
1396 	for (;;p++) {
1397 		if (p->op == ZEND_JIT_TRACE_VM) {
1398 			opline = p->opline;
1399 			ssa_opcodes[idx] = opline;
1400 			ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
1401 			idx++;
1402 			len = zend_jit_trace_op_len(p->opline);
1403 			while (len > 1) {
1404 				opline++;
1405 				ssa_opcodes[idx] = opline;
1406 				if (opline->opcode != ZEND_OP_DATA) {
1407 					ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
1408 				}
1409 				idx++;
1410 				len--;
1411 			}
1412 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
1413 			frame = zend_jit_trace_call_frame(frame, op_array);
1414 			stack = frame->stack;
1415 			op_array = p->op_array;
1416 			level++;
1417 			if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
1418 				return NULL;
1419 			}
1420 			ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
1421 			for (i = 0; i < op_array->last_var; i++) {
1422 				SET_STACK_VAR(stack, i, ssa_vars_count++);
1423 			}
1424 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
1425 			op_array = p->op_array;
1426 			frame = zend_jit_trace_ret_frame(frame, op_array);
1427 			stack = frame->stack;
1428 			if (level == 0) {
1429 				if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
1430 					return NULL;
1431 				}
1432 				ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
1433 				for (i = 0; i < op_array->last_var + op_array->T; i++) {
1434 					SET_STACK_VAR(stack, i, ssa_vars_count++);
1435 				}
1436 			} else {
1437 				level--;
1438 			}
1439 		} else if (p->op == ZEND_JIT_TRACE_END) {
1440 			break;
1441 		}
1442 	}
1443 
1444 	op_array = trace_buffer->op_array;
1445 	tssa->vars_count = ssa_vars_count;
1446 	tssa->vars = ssa_vars = zend_arena_calloc(&CG(arena), tssa->vars_count, sizeof(zend_ssa_var));
1447 	if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1448 		vars_count = op_array->last_var;
1449 	} else {
1450 		vars_count = op_array->last_var + op_array->T;
1451 	}
1452 	i = 0;
1453 	while (i < vars_count) {
1454 		ssa_vars[i].var = i;
1455 		ssa_vars[i].scc = -1;
1456 		ssa_vars[i].definition = -1;
1457 		ssa_vars[i].use_chain = -1;
1458 		i++;
1459 	}
1460 	while (i < tssa->vars_count) {
1461 		ssa_vars[i].var = -1;
1462 		ssa_vars[i].scc = -1;
1463 		ssa_vars[i].definition = -1;
1464 		ssa_vars[i].use_chain = -1;
1465 		i++;
1466 	}
1467 
1468 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1469 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1470 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1471 		/* Update Phi sources */
1472 		zend_ssa_phi *phi = tssa->blocks[1].phis;
1473 
1474 		while (phi) {
1475 			phi->sources[1] = STACK_VAR(stack, phi->var);
1476 			ssa_vars[phi->ssa_var].var = phi->var;
1477 			ssa_vars[phi->ssa_var].definition_phi = phi;
1478 			ssa_vars[phi->sources[0]].phi_use_chain = phi;
1479 			ssa_vars[phi->sources[1]].phi_use_chain = phi;
1480 			phi = phi->next;
1481 		}
1482 	}
1483 
1484 	/* 3. Compute use-def chains */
1485 	idx = (ssa_ops_count - 1);
1486 	op = ssa_ops + idx;
1487 	while (idx >= 0) {
1488 		opline = ssa_opcodes[idx];
1489 		if (op->op1_use >= 0) {
1490 			op->op1_use_chain = ssa_vars[op->op1_use].use_chain;
1491 			ssa_vars[op->op1_use].use_chain = idx;
1492 		}
1493 		if (op->op2_use >= 0 && op->op2_use != op->op1_use) {
1494 			op->op2_use_chain = ssa_vars[op->op2_use].use_chain;
1495 			ssa_vars[op->op2_use].use_chain = idx;
1496 		}
1497 		if (op->result_use >= 0 && op->result_use != op->op1_use && op->result_use != op->op2_use) {
1498 			op->res_use_chain = ssa_vars[op->result_use].use_chain;
1499 			ssa_vars[op->result_use].use_chain = idx;
1500 		}
1501 		if (op->op1_def >= 0) {
1502 			ssa_vars[op->op1_def].var = EX_VAR_TO_NUM(opline->op1.var);
1503 			ssa_vars[op->op1_def].definition = idx;
1504 		}
1505 		if (op->op2_def >= 0) {
1506 			ssa_vars[op->op2_def].var = EX_VAR_TO_NUM(opline->op2.var);
1507 			ssa_vars[op->op2_def].definition = idx;
1508 		}
1509 		if (op->result_def >= 0) {
1510 			ssa_vars[op->result_def].var = EX_VAR_TO_NUM(opline->result.var);
1511 			ssa_vars[op->result_def].definition = idx;
1512 		}
1513 		op--;
1514 		idx--;
1515 	}
1516 
1517 	/* 4. Type inference */
1518 	op_array = trace_buffer->op_array;
1519 	jit_extension =
1520 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1521 	ssa = &jit_extension->func_info.ssa;
1522 
1523 	tssa->var_info = ssa_var_info = zend_arena_calloc(&CG(arena), tssa->vars_count, sizeof(zend_ssa_var_info));
1524 
1525 	if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1526 		i = 0;
1527 		while (i < op_array->last_var) {
1528 			if (i < op_array->num_args) {
1529 				if (ssa->var_info
1530 				 && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i)) {
1531 					/* pass */
1532 				} else {
1533 					if (ssa->vars) {
1534 						ssa_vars[i].no_val = ssa->vars[i].no_val;
1535 						ssa_vars[i].alias = ssa->vars[i].alias;
1536 					} else {
1537 						ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1538 					}
1539 					if (op_array->arg_info) {
1540 						zend_arg_info *arg_info = &op_array->arg_info[i];
1541 						zend_class_entry *ce;
1542 						uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
1543 
1544 						if (ZEND_ARG_SEND_MODE(arg_info)) {
1545 							tmp |= MAY_BE_REF;
1546 						}
1547 						ssa_var_info[i].type = tmp;
1548 						ssa_var_info[i].ce = ce;
1549 						ssa_var_info[i].is_instanceof = 1;
1550 					} else {
1551 						ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1552 					}
1553 				}
1554 			} else {
1555 				if (ssa->vars) {
1556 					ssa_vars[i].no_val = ssa->vars[i].no_val;
1557 					ssa_vars[i].alias = ssa->vars[i].alias;
1558 				} else {
1559 					ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1560 				}
1561 				if (ssa_vars[i].alias == NO_ALIAS) {
1562 					ssa_var_info[i].type = MAY_BE_UNDEF;
1563 				} else {
1564 					ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1565 				}
1566 			}
1567 			i++;
1568 		}
1569 	} else {
1570 		int parent_vars_count = 0;
1571 		zend_jit_trace_stack *parent_stack = NULL;
1572 
1573 		i = 0;
1574 		if (parent_trace) {
1575 			parent_vars_count = MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
1576 				op_array->last_var + op_array->T);
1577 			if (parent_vars_count) {
1578 				parent_stack =
1579 					zend_jit_traces[parent_trace].stack_map +
1580 					zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
1581 			}
1582 		}
1583 		while (i < op_array->last_var + op_array->T) {
1584 			if (!ssa->var_info
1585 			 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i)) {
1586 				if (ssa->vars && i < ssa->vars_count) {
1587 					ssa_vars[i].alias = ssa->vars[i].alias;
1588 				} else {
1589 					ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1590 				}
1591 				if (i < op_array->last_var) {
1592 					ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1593 				} else {
1594 					ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1595 				}
1596 			}
1597 			if (i < parent_vars_count) {
1598 				/* Initialize TSSA variable from parent trace */
1599 				zend_uchar op_type = STACK_TYPE(parent_stack, i);
1600 
1601 				if (op_type != IS_UNKNOWN) {
1602 					ssa_var_info[i].type &= zend_jit_trace_type_to_info(op_type);
1603 					if (!ssa_var_info[i].type
1604 					 && op_type == IS_UNDEF
1605 					 && i >= op_array->last_var) {
1606 						// TODO: It's better to use NULL instead of UNDEF for temporary variables
1607 						ssa_var_info[i].type |= MAY_BE_UNDEF;
1608 					}
1609 				}
1610 			}
1611 			i++;
1612 		}
1613 	}
1614 
1615 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1616 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1617 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1618 		/* Propagate initial value through Phi functions */
1619 		zend_ssa_phi *phi = tssa->blocks[1].phis;
1620 
1621 		while (phi) {
1622 			if (!ssa->var_info
1623 			 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, phi->ssa_var)) {
1624 				ssa_vars[phi->ssa_var].alias = ssa_vars[phi->sources[0]].alias;
1625 				ssa_var_info[phi->ssa_var].type = ssa_var_info[phi->sources[0]].type;
1626 			}
1627 			phi = phi->next;
1628 		}
1629 	}
1630 
1631 	frame = JIT_G(current_frame);
1632 	top = zend_jit_trace_call_frame(frame, op_array);
1633 	TRACE_FRAME_INIT(frame, op_array, 0, 0);
1634 	TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
1635 	frame->used_stack = 0;
1636 	for (i = 0; i < op_array->last_var + op_array->T; i++) {
1637 		SET_STACK_TYPE(frame->stack, i, IS_UNKNOWN, 1);
1638 	}
1639 	memset(&return_value_info, 0, sizeof(return_value_info));
1640 
1641 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1642 		max_used_stack = used_stack = 0;
1643 	} else {
1644 		max_used_stack = used_stack = -1;
1645 	}
1646 
1647 	p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1648 	idx = 0;
1649 	level = 0;
1650 	opline = NULL;
1651 	for (;;p++) {
1652 		if (p->op == ZEND_JIT_TRACE_VM) {
1653 			uint8_t orig_op1_type, orig_op2_type, op1_type, op2_type, op3_type;
1654 			uint8_t val_type = IS_UNKNOWN;
1655 //			zend_class_entry *op1_ce = NULL;
1656 			zend_class_entry *op2_ce = NULL;
1657 
1658 			opline = p->opline;
1659 
1660 			op1_type = orig_op1_type = p->op1_type;
1661 			op2_type = orig_op2_type = p->op2_type;
1662 			op3_type = p->op3_type;
1663 			if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1664 				op1_type = IS_UNKNOWN;
1665 			}
1666 			if (op1_type != IS_UNKNOWN) {
1667 				op1_type &= ~IS_TRACE_PACKED;
1668 			}
1669 			if (op2_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1670 				op2_type = IS_UNKNOWN;
1671 			}
1672 			if (op3_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1673 				op3_type = IS_UNKNOWN;
1674 			}
1675 
1676 			if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
1677 //				op1_ce = (zend_class_entry*)(p+1)->ce;
1678 				p++;
1679 			}
1680 			if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
1681 				op2_ce = (zend_class_entry*)(p+1)->ce;
1682 				p++;
1683 			}
1684 			if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
1685 				val_type = (p+1)->op1_type;
1686 				p++;
1687 			}
1688 
1689 			switch (opline->opcode) {
1690 				case ZEND_ASSIGN_OP:
1691 					if (opline->extended_value == ZEND_POW
1692 					 || opline->extended_value == ZEND_DIV) {
1693 						// TODO: check for division by zero ???
1694 						break;
1695 					}
1696 					if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1697 						break;
1698 					}
1699 					ADD_OP1_TRACE_GUARD();
1700 					ADD_OP2_TRACE_GUARD();
1701 					break;
1702 				case ZEND_ASSIGN_DIM_OP:
1703 					if (opline->extended_value == ZEND_POW
1704 					 || opline->extended_value == ZEND_DIV) {
1705 						// TODO: check for division by zero ???
1706 						break;
1707 					}
1708 					if (opline->result_type != IS_UNUSED) {
1709 						break;
1710 					}
1711 					if (op3_type != IS_UNKNOWN
1712 					 && !zend_jit_supported_binary_op(
1713 							opline->extended_value, MAY_BE_ANY, (1<<op3_type))) {
1714 						break;
1715 					}
1716 					ZEND_FALLTHROUGH;
1717 				case ZEND_ASSIGN_DIM:
1718 					if (opline->op1_type == IS_CV) {
1719 						if ((opline+1)->op1_type == IS_CV
1720 						 && (opline+1)->op1.var == opline->op1.var) {
1721 							/* skip $a[x] = $a; */
1722 							break;
1723 						}
1724 						ADD_OP1_DATA_TRACE_GUARD();
1725 						ADD_OP2_TRACE_GUARD();
1726 						ADD_OP1_TRACE_GUARD();
1727 					} else if (orig_op1_type != IS_UNKNOWN
1728 					        && (orig_op1_type & IS_TRACE_INDIRECT)
1729 					        && opline->result_type == IS_UNUSED) {
1730 						if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
1731 							ADD_OP1_DATA_TRACE_GUARD();
1732 						}
1733 						ADD_OP2_TRACE_GUARD();
1734 					}
1735 					if (op1_type == IS_ARRAY
1736 					 && ((opline->op2_type == IS_CONST
1737 					   && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1738 					  || (opline->op2_type != IS_CONST
1739 					   && op2_type == IS_LONG))) {
1740 
1741 						if (!(orig_op1_type & IS_TRACE_PACKED)) {
1742 							zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1743 
1744 							if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1745 								info->type |= MAY_BE_PACKED_GUARD;
1746 								info->type &= ~MAY_BE_ARRAY_PACKED;
1747 							}
1748 						} else if (opline->opcode == ZEND_ASSIGN_DIM_OP
1749 								&& val_type != IS_UNKNOWN
1750 								&& val_type != IS_UNDEF) {
1751 							zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1752 
1753 							if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1754 								info->type |= MAY_BE_PACKED_GUARD;
1755 								info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
1756 							}
1757 						}
1758 					}
1759 					break;
1760 				case ZEND_ASSIGN_OBJ_OP:
1761 					if (opline->extended_value == ZEND_POW
1762 					 || opline->extended_value == ZEND_DIV) {
1763 						// TODO: check for division by zero ???
1764 						break;
1765 					}
1766 					if (opline->result_type != IS_UNUSED) {
1767 						break;
1768 					}
1769 					ZEND_FALLTHROUGH;
1770 				case ZEND_ASSIGN_OBJ:
1771 				case ZEND_PRE_INC_OBJ:
1772 				case ZEND_PRE_DEC_OBJ:
1773 				case ZEND_POST_INC_OBJ:
1774 				case ZEND_POST_DEC_OBJ:
1775 					if (opline->op2_type != IS_CONST
1776 					 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1777 					 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1778 						break;
1779 					}
1780 					if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
1781 						if (opline->op1_type == IS_CV
1782 						 && (opline+1)->op1_type == IS_CV
1783 						 && (opline+1)->op1.var == opline->op1.var) {
1784 							/* skip $a->prop += $a; */
1785 							break;
1786 						}
1787 						ADD_OP1_DATA_TRACE_GUARD();
1788 					}
1789 					ADD_OP1_TRACE_GUARD();
1790 					break;
1791 				case ZEND_CONCAT:
1792 				case ZEND_FAST_CONCAT:
1793 					if ((opline->op1_type == IS_CONST || orig_op1_type == IS_STRING)
1794 					 && (opline->op2_type == IS_CONST || orig_op2_type == IS_STRING)) {
1795 						ADD_OP2_TRACE_GUARD();
1796 						ADD_OP1_TRACE_GUARD();
1797 					}
1798 					break;
1799 				case ZEND_IS_EQUAL:
1800 				case ZEND_IS_NOT_EQUAL:
1801 				case ZEND_IS_SMALLER:
1802 				case ZEND_IS_SMALLER_OR_EQUAL:
1803 				case ZEND_CASE:
1804 				case ZEND_IS_IDENTICAL:
1805 				case ZEND_IS_NOT_IDENTICAL:
1806 				case ZEND_CASE_STRICT:
1807 				case ZEND_BW_OR:
1808 				case ZEND_BW_AND:
1809 				case ZEND_BW_XOR:
1810 				case ZEND_SL:
1811 				case ZEND_SR:
1812 				case ZEND_MOD:
1813 				case ZEND_ADD:
1814 				case ZEND_SUB:
1815 				case ZEND_MUL:
1816 //				case ZEND_DIV: // TODO: check for division by zero ???
1817 					ADD_OP2_TRACE_GUARD();
1818 					ZEND_FALLTHROUGH;
1819 				case ZEND_ECHO:
1820 				case ZEND_STRLEN:
1821 				case ZEND_COUNT:
1822 				case ZEND_QM_ASSIGN:
1823 				case ZEND_FE_RESET_R:
1824 					ADD_OP1_TRACE_GUARD();
1825 					break;
1826 				case ZEND_FE_FETCH_R:
1827 					ADD_OP1_TRACE_GUARD();
1828 					if (op1_type == IS_ARRAY && (orig_op1_type & ~IS_TRACE_PACKED) == IS_ARRAY) {
1829 
1830 						zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1831 
1832 						if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1833 							info->type |= MAY_BE_PACKED_GUARD;
1834 							if (orig_op1_type & IS_TRACE_PACKED) {
1835 								info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
1836 							} else {
1837 								info->type &= ~MAY_BE_ARRAY_PACKED;
1838 							}
1839 						}
1840 					}
1841 					break;
1842 				case ZEND_VERIFY_RETURN_TYPE:
1843 					if (opline->op1_type == IS_UNUSED) {
1844 						/* Always throws */
1845 						break;
1846 					}
1847 					if (opline->op1_type == IS_CONST) {
1848 						/* TODO Different instruction format, has return value */
1849 						break;
1850 					}
1851 					if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
1852 						/* Not worth bothering with */
1853 						break;
1854 					}
1855 					ADD_OP1_TRACE_GUARD();
1856 					break;
1857 				case ZEND_FETCH_DIM_FUNC_ARG:
1858 					if (!frame
1859 					 || !frame->call
1860 					 || !frame->call->func
1861 					 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
1862 						break;
1863 					}
1864 					ADD_OP2_TRACE_GUARD();
1865 					ADD_OP1_TRACE_GUARD();
1866 					break;
1867 				case ZEND_PRE_INC:
1868 				case ZEND_PRE_DEC:
1869 				case ZEND_POST_INC:
1870 				case ZEND_POST_DEC:
1871 					if (opline->op1_type != IS_CV) {
1872 						break;
1873 					}
1874 					ADD_OP1_TRACE_GUARD();
1875 					break;
1876 				case ZEND_ASSIGN:
1877 					if (opline->op1_type != IS_CV) {
1878 						break;
1879 					}
1880 					ADD_OP2_TRACE_GUARD();
1881 					if (op1_type != IS_UNKNOWN
1882 					 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1883 						ADD_OP1_TRACE_GUARD();
1884 					}
1885 					break;
1886 				case ZEND_CAST:
1887 					if (opline->extended_value != op1_type) {
1888 						break;
1889 					}
1890 					ADD_OP1_TRACE_GUARD();
1891 					break;
1892 				case ZEND_JMPZ:
1893 				case ZEND_JMPNZ:
1894 				case ZEND_JMPZ_EX:
1895 				case ZEND_JMPNZ_EX:
1896 				case ZEND_BOOL:
1897 				case ZEND_BOOL_NOT:
1898 					ADD_OP1_TRACE_GUARD();
1899 					break;
1900 				case ZEND_ISSET_ISEMPTY_CV:
1901 					if ((opline->extended_value & ZEND_ISEMPTY)) {
1902 						// TODO: support for empty() ???
1903 						break;
1904 					}
1905 					ADD_OP1_TRACE_GUARD();
1906 					break;
1907 				case ZEND_IN_ARRAY:
1908 					if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
1909 						break;
1910 					}
1911 					ADD_OP1_TRACE_GUARD();
1912 					break;
1913 				case ZEND_ISSET_ISEMPTY_DIM_OBJ:
1914 					if ((opline->extended_value & ZEND_ISEMPTY)) {
1915 						// TODO: support for empty() ???
1916 						break;
1917 					}
1918 					ZEND_FALLTHROUGH;
1919 				case ZEND_FETCH_DIM_R:
1920 				case ZEND_FETCH_DIM_IS:
1921 				case ZEND_FETCH_LIST_R:
1922 					ADD_OP1_TRACE_GUARD();
1923 					ADD_OP2_TRACE_GUARD();
1924 
1925 					if (op1_type == IS_ARRAY
1926 					 && opline->op1_type != IS_CONST
1927 					 && ((opline->op2_type == IS_CONST
1928 					   && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1929 					  || (opline->op2_type != IS_CONST
1930 					   && op2_type == IS_LONG))) {
1931 
1932 						zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1933 
1934 						if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1935 							info->type |= MAY_BE_PACKED_GUARD;
1936 							if (orig_op1_type & IS_TRACE_PACKED) {
1937 								info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
1938 							} else {
1939 								info->type &= ~MAY_BE_ARRAY_PACKED;
1940 							}
1941 						}
1942 					}
1943 					break;
1944 				case ZEND_FETCH_DIM_W:
1945 				case ZEND_FETCH_DIM_RW:
1946 //				case ZEND_FETCH_DIM_UNSET:
1947 				case ZEND_FETCH_LIST_W:
1948 					if (opline->op1_type != IS_CV
1949 					 && (orig_op1_type == IS_UNKNOWN
1950 					  || !(orig_op1_type & IS_TRACE_INDIRECT))) {
1951 						break;
1952 					}
1953 					ADD_OP1_TRACE_GUARD();
1954 					ADD_OP2_TRACE_GUARD();
1955 					if (op1_type == IS_ARRAY
1956 					 && !(orig_op1_type & IS_TRACE_PACKED)
1957 					 && ((opline->op2_type == IS_CONST
1958 					   && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1959 					  || (opline->op2_type != IS_CONST
1960 					   && op2_type == IS_LONG))) {
1961 
1962 						zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1963 
1964 						if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1965 							info->type |= MAY_BE_PACKED_GUARD;
1966 							info->type &= ~MAY_BE_ARRAY_PACKED;
1967 						}
1968 					}
1969 					break;
1970 				case ZEND_SEND_VAL_EX:
1971 				case ZEND_SEND_VAR_EX:
1972 				case ZEND_SEND_VAR_NO_REF_EX:
1973 					if (opline->op2_type == IS_CONST) {
1974 						/* Named parameters not supported in JIT */
1975 						break;
1976 					}
1977 					if (opline->op2.num > MAX_ARG_FLAG_NUM) {
1978 						goto propagate_arg;
1979 					}
1980 					ZEND_FALLTHROUGH;
1981 				case ZEND_SEND_VAL:
1982 				case ZEND_SEND_VAR:
1983 				case ZEND_SEND_VAR_NO_REF:
1984 				case ZEND_SEND_FUNC_ARG:
1985 					if (opline->op2_type == IS_CONST) {
1986 						/* Named parameters not supported in JIT */
1987 						break;
1988 					}
1989 					ADD_OP1_TRACE_GUARD();
1990 propagate_arg:
1991 					/* Propagate argument type */
1992 					if (frame->call
1993 					 && frame->call->func
1994 					 && frame->call->func->type == ZEND_USER_FUNCTION
1995 					 && opline->op2.num <= frame->call->func->op_array.num_args) {
1996 						uint32_t info;
1997 
1998 						if (opline->op1_type == IS_CONST) {
1999 							info = _const_op_type(RT_CONSTANT(opline, opline->op1));
2000 						} else {
2001 							ZEND_ASSERT(ssa_ops[idx].op1_use >= 0);
2002 							info = ssa_var_info[ssa_ops[idx].op1_use].type & ~MAY_BE_GUARD;
2003 						}
2004 						if (frame->call->func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
2005 							zend_arg_info *arg_info;
2006 
2007 							ZEND_ASSERT(frame->call->func->op_array.arg_info);
2008 							arg_info = &frame->call->func->op_array.arg_info[opline->op2.num - 1];
2009 							if (ZEND_TYPE_IS_SET(arg_info->type)) {
2010 								zend_class_entry *ce;
2011 								uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
2012 								info &= tmp;
2013 								if (!info) {
2014 									break;
2015 								}
2016 							}
2017 						}
2018 						if (opline->op1_type == IS_CV && (info & MAY_BE_RC1)) {
2019 							info |= MAY_BE_RCN;
2020 						}
2021 						if (info & MAY_BE_UNDEF) {
2022 							info |= MAY_BE_NULL;
2023 							info &= ~MAY_BE_UNDEF;
2024 						}
2025 						if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2026 							info |= MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY;
2027 						}
2028 						SET_STACK_INFO(frame->call->stack, opline->op2.num - 1, info);
2029 					}
2030 					break;
2031 				case ZEND_RETURN:
2032 					ADD_OP1_TRACE_GUARD();
2033 					/* Propagate return value types */
2034 					if (opline->op1_type == IS_UNUSED) {
2035 						return_value_info.type = MAY_BE_NULL;
2036 					} else if (opline->op1_type == IS_CONST) {
2037 						return_value_info.type = _const_op_type(RT_CONSTANT(opline, opline->op1));
2038 					} else {
2039 						ZEND_ASSERT(ssa_ops[idx].op1_use >= 0);
2040 						return_value_info = ssa_var_info[ssa_ops[idx].op1_use];
2041 						if (return_value_info.type & MAY_BE_UNDEF) {
2042 							return_value_info.type &= ~MAY_BE_UNDEF;
2043 							return_value_info.type |= MAY_BE_NULL;
2044 						}
2045 						if (return_value_info.type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2046 							/* CVs are going to be destructed and the reference-counter
2047 							   of return value may be decremented to 1 */
2048 							return_value_info.type |= MAY_BE_RC1;
2049 						}
2050 						return_value_info.type &= ~MAY_BE_GUARD;
2051 					}
2052 					break;
2053 				case ZEND_CHECK_FUNC_ARG:
2054 					if (!frame
2055 					 || !frame->call
2056 					 || !frame->call->func) {
2057 						break;
2058 					}
2059 					if (opline->op2_type == IS_CONST
2060 					 || opline->op2.num > MAX_ARG_FLAG_NUM) {
2061 						/* Named parameters not supported in JIT */
2062 						TRACE_FRAME_SET_LAST_SEND_UNKNOWN(frame->call);
2063 						break;
2064 					}
2065 					if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2066 						TRACE_FRAME_SET_LAST_SEND_BY_REF(frame->call);
2067 					} else {
2068 						TRACE_FRAME_SET_LAST_SEND_BY_VAL(frame->call);
2069 					}
2070 					break;
2071 				case ZEND_FETCH_OBJ_FUNC_ARG:
2072 					if (!frame
2073 					 || !frame->call
2074 					 || !frame->call->func
2075 					 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
2076 						break;
2077 					}
2078 					ZEND_FALLTHROUGH;
2079 				case ZEND_FETCH_OBJ_R:
2080 				case ZEND_FETCH_OBJ_IS:
2081 				case ZEND_FETCH_OBJ_W:
2082 					if (opline->op2_type != IS_CONST
2083 					 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
2084 					 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
2085 						break;
2086 					}
2087 					if (opline->op1_type != IS_UNUSED && op1_type == IS_OBJECT) {
2088 						ADD_OP1_TRACE_GUARD();
2089 					}
2090 					break;
2091 				case ZEND_INIT_METHOD_CALL:
2092 					if (opline->op2_type != IS_CONST
2093 					 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
2094 						break;
2095 					}
2096 					ADD_OP1_TRACE_GUARD();
2097 					break;
2098 				case ZEND_INIT_DYNAMIC_CALL:
2099 					if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
2100 						ADD_OP2_TRACE_GUARD();
2101 					}
2102 					break;
2103 				case ZEND_SEND_ARRAY:
2104 				case ZEND_SEND_UNPACK:
2105 				case ZEND_CHECK_UNDEF_ARGS:
2106 				case ZEND_INCLUDE_OR_EVAL:
2107 					max_used_stack = used_stack = -1;
2108 					break;
2109 				case ZEND_TYPE_CHECK:
2110 					if (opline->extended_value == MAY_BE_RESOURCE) {
2111 						// TODO: support for is_resource() ???
2112 						break;
2113 					}
2114 					if (op1_type != IS_UNKNOWN
2115 					 && (opline->extended_value == (1 << op1_type)
2116 					  || opline->extended_value == MAY_BE_ANY - (1 << op1_type))) {
2117 						/* add guards only for exact checks, to avoid code duplication */
2118 						ADD_OP1_TRACE_GUARD();
2119 					}
2120 					break;
2121 				case ZEND_ROPE_INIT:
2122 				case ZEND_ROPE_ADD:
2123 				case ZEND_ROPE_END:
2124 					if (op2_type == IS_STRING) {
2125 						ADD_OP2_TRACE_GUARD();
2126 					}
2127 					break;
2128 				default:
2129 					break;
2130 			}
2131 			len = zend_jit_trace_op_len(opline);
2132 			if (ssa->var_info) {
2133 				/* Add statically inferred ranges */
2134 				if (ssa_ops[idx].op1_def >= 0) {
2135 					zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2136 				}
2137 				if (ssa_ops[idx].op2_def >= 0) {
2138 					zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2139 				}
2140 				if (ssa_ops[idx].result_def >= 0) {
2141 					zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2142 				}
2143 				if (len == 2 && (opline+1)->opcode == ZEND_OP_DATA) {
2144 					if (ssa_ops[idx+1].op1_def >= 0) {
2145 						zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2146 					}
2147 					if (ssa_ops[idx+1].op2_def >= 0) {
2148 						zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2149 					}
2150 					if (ssa_ops[idx+1].result_def >= 0) {
2151 						zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2152 					}
2153 				}
2154 			} else {
2155 				if (ssa_ops[idx].op1_def >= 0) {
2156 					ssa_vars[ssa_ops[idx].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op1.var));
2157 					if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].type & MAY_BE_REF)) {
2158 						zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2159 					}
2160 				}
2161 				if (ssa_ops[idx].op2_def >= 0) {
2162 					ssa_vars[ssa_ops[idx].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op2.var));
2163 					if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].type & MAY_BE_REF)) {
2164 						zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2165 					}
2166 				}
2167 				if (ssa_ops[idx].result_def >= 0) {
2168 					ssa_vars[ssa_ops[idx].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->result.var));
2169 					if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].type & MAY_BE_REF)) {
2170 						zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2171 					}
2172 				}
2173 				if (len == 2 && (opline+1)->opcode == ZEND_OP_DATA) {
2174 					if (ssa_ops[idx+1].op1_def >= 0) {
2175 						ssa_vars[ssa_ops[idx+1].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->op1.var));
2176 						if (ssa_ops[idx+1].op1_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op1_use].type & MAY_BE_REF)) {
2177 							zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2178 						}
2179 					}
2180 					if (ssa_ops[idx+1].op2_def >= 0) {
2181 						ssa_vars[ssa_ops[idx+1].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->op2.var));
2182 						if (ssa_ops[idx+1].op2_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op2_use].type & MAY_BE_REF)) {
2183 							zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2184 						}
2185 					}
2186 					if (ssa_ops[idx+1].result_def >= 0) {
2187 						ssa_vars[ssa_ops[idx+1].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->result.var));
2188 						if (ssa_ops[idx+1].result_use < 0 || !(ssa_var_info[ssa_ops[idx+1].result_use].type & MAY_BE_REF)) {
2189 							zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2190 						}
2191 					}
2192 				}
2193 			}
2194 			if (opline->opcode == ZEND_RECV_INIT
2195 			 && !(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2196 				/* RECV_INIT always copy the constant */
2197 				ssa_var_info[ssa_ops[idx].result_def].type = _const_op_type(RT_CONSTANT(opline, opline->op2));
2198 			} else if ((opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW)
2199 			 && ssa_opcodes[idx + 1] == ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)) {
2200 				if (ssa_ops[idx].op2_use >= 0 && ssa_ops[idx].op2_def >= 0) {
2201 					ssa_var_info[ssa_ops[idx].op2_def] = ssa_var_info[ssa_ops[idx].op2_use];
2202 				}
2203 			} else {
2204 				if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
2205 					// TODO:
2206 					assert(0);
2207 				}
2208 				if (opline->opcode == ZEND_ASSIGN_DIM_OP
2209 				 && ssa_ops[idx].op1_def >= 0
2210 				 && op1_type == IS_ARRAY
2211 				 && (orig_op1_type & IS_TRACE_PACKED)
2212 				 && val_type != IS_UNKNOWN
2213 				 && val_type != IS_UNDEF
2214 				 && ((opline->op2_type == IS_CONST
2215 				   && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
2216 				  || (opline->op2_type != IS_CONST
2217 				   && op2_type == IS_LONG))) {
2218 					zend_ssa_var_info *info = &ssa_var_info[ssa_ops[idx].op1_def];
2219 
2220 					info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2221 				}
2222 			}
2223 			if (ssa->var_info) {
2224 				/* Add statically inferred restrictions */
2225 				if (ssa_ops[idx].op1_def >= 0) {
2226 					if (opline->opcode == ZEND_SEND_VAR_EX
2227 					 && frame
2228 					 && frame->call
2229 					 && frame->call->func
2230 					 && !ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2231 						ssa_var_info[ssa_ops[idx].op1_def] = ssa_var_info[ssa_ops[idx].op1_use];
2232 						ssa_var_info[ssa_ops[idx].op1_def].type &= ~MAY_BE_GUARD;
2233 						if (ssa_var_info[ssa_ops[idx].op1_def].type & MAY_BE_RC1) {
2234 							ssa_var_info[ssa_ops[idx].op1_def].type |= MAY_BE_RCN;
2235 						}
2236 					} else {
2237 						zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2238 					}
2239 				}
2240 				if (ssa_ops[idx].op2_def >= 0) {
2241 					if ((opline->opcode != ZEND_FE_FETCH_R && opline->opcode != ZEND_FE_FETCH_RW)
2242 					 || ssa_opcodes[idx + 1] != ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)) {
2243 						zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2244 					}
2245 				}
2246 				if (ssa_ops[idx].result_def >= 0) {
2247 					zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2248 				}
2249 			}
2250 			idx++;
2251 			while (len > 1) {
2252 				opline++;
2253 				if (opline->opcode != ZEND_OP_DATA) {
2254 					if (ssa->var_info) {
2255 						/* Add statically inferred ranges */
2256 						if (ssa_ops[idx].op1_def >= 0) {
2257 							zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2258 						}
2259 						if (ssa_ops[idx].op2_def >= 0) {
2260 							zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2261 						}
2262 						if (ssa_ops[idx].result_def >= 0) {
2263 							zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2264 						}
2265 					} else {
2266 						if (ssa_ops[idx].op1_def >= 0) {
2267 							ssa_vars[ssa_ops[idx].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op1.var));
2268 							if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].type & MAY_BE_REF)) {
2269 								zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2270 							}
2271 						}
2272 						if (ssa_ops[idx].op2_def >= 0) {
2273 							ssa_vars[ssa_ops[idx].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op2.var));
2274 							if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].type & MAY_BE_REF)) {
2275 								zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2276 							}
2277 						}
2278 						if (ssa_ops[idx].result_def >= 0) {
2279 							ssa_vars[ssa_ops[idx].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->result.var));
2280 							if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].type & MAY_BE_REF)) {
2281 								zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2282 							}
2283 						}
2284 					}
2285 					if (opline->opcode == ZEND_RECV_INIT
2286 					 && !(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2287 						/* RECV_INIT always copy the constant */
2288 						ssa_var_info[ssa_ops[idx].result_def].type = _const_op_type(RT_CONSTANT(opline, opline->op2));
2289 					} else {
2290 						if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
2291 							// TODO:
2292 							assert(0);
2293 						}
2294 					}
2295 				}
2296 				if (ssa->var_info) {
2297 					/* Add statically inferred restrictions */
2298 					if (ssa_ops[idx].op1_def >= 0) {
2299 						zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2300 					}
2301 					if (ssa_ops[idx].op2_def >= 0) {
2302 						zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2303 					}
2304 					if (ssa_ops[idx].result_def >= 0) {
2305 						zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2306 					}
2307 				}
2308 				idx++;
2309 				len--;
2310 			}
2311 
2312 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
2313 			op_array = p->op_array;
2314 			jit_extension =
2315 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2316 			ssa = &jit_extension->func_info.ssa;
2317 
2318 			call = frame->call;
2319 			if (!call) {
2320 				/* Trace missed INIT_FCALL opcode */
2321 				call = top;
2322 				TRACE_FRAME_INIT(call, op_array, 0, 0);
2323 				call->used_stack = 0;
2324 				top = zend_jit_trace_call_frame(top, op_array);
2325 				for (i = 0; i < op_array->last_var + op_array->T; i++) {
2326 					SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
2327 				}
2328 			} else {
2329 				ZEND_ASSERT(&call->func->op_array == op_array);
2330 			}
2331 			frame->call = call->prev;
2332 			call->prev = frame;
2333 			TRACE_FRAME_SET_RETURN_SSA_VAR(call, find_return_ssa_var(p - 1, ssa_ops + (idx - 1)));
2334 			frame = call;
2335 
2336 			level++;
2337 			i = 0;
2338 			v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
2339 			while (i < op_array->last_var) {
2340 				ssa_vars[v].var = i;
2341 				if (i < op_array->num_args) {
2342 					if (ssa->var_info
2343 					 && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v)) {
2344 						/* pass */
2345 					} else {
2346 						ssa_vars[v].alias = zend_jit_var_may_alias(op_array, ssa, i);
2347 						if (op_array->arg_info) {
2348 							zend_arg_info *arg_info = &op_array->arg_info[i];
2349 							zend_class_entry *ce;
2350 							uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
2351 
2352 							if (ZEND_ARG_SEND_MODE(arg_info)) {
2353 								tmp |= MAY_BE_REF;
2354 							}
2355 							ssa_var_info[v].type = tmp;
2356 							ssa_var_info[v].ce = ce;
2357 							ssa_var_info[v].is_instanceof = 1;
2358 						} else {
2359 							ssa_var_info[v].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2360 						}
2361 					}
2362 				} else {
2363 					if (ssa->vars) {
2364 						ssa_vars[v].no_val = ssa->vars[i].no_val;
2365 						ssa_vars[v].alias = ssa->vars[i].alias;
2366 					} else {
2367 						ssa_vars[v].alias = zend_jit_var_may_alias(op_array, ssa, i);
2368 					}
2369 					if (ssa_vars[v].alias == NO_ALIAS) {
2370 						ssa_var_info[v].type = MAY_BE_UNDEF;
2371 					} else {
2372 						ssa_var_info[v].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2373 					}
2374 				}
2375 				if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
2376 				 && i < op_array->num_args) {
2377 					/* Propagate argument type */
2378 					ssa_var_info[v].type &= STACK_INFO(frame->stack, i);
2379 				}
2380 				i++;
2381 				v++;
2382 			}
2383 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
2384 			op_array = p->op_array;
2385 			jit_extension =
2386 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2387 			ssa = &jit_extension->func_info.ssa;
2388 			if (level == 0) {
2389 				i = 0;
2390 				v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
2391 				while (i < op_array->last_var) {
2392 					ssa_vars[v].var = i;
2393 					if (!ssa->var_info
2394 					 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v)) {
2395 						ssa_var_info[v].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2396 					}
2397 					i++;
2398 					v++;
2399 				}
2400 				while (i < op_array->last_var + op_array->T) {
2401 					ssa_vars[v].var = i;
2402 					if (!ssa->var_info
2403 					 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v)) {
2404 						ssa_var_info[v].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2405 					}
2406 					i++;
2407 					v++;
2408 				}
2409 				if (return_value_info.type != 0) {
2410 					zend_jit_trace_rec *q = p + 1;
2411 					while (q->op == ZEND_JIT_TRACE_INIT_CALL) {
2412 						q++;
2413 					}
2414 					if (q->op == ZEND_JIT_TRACE_VM
2415 					 || (q->op == ZEND_JIT_TRACE_END
2416 					  && q->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)) {
2417 						const zend_op *opline = q->opline - 1;
2418 						if (opline->result_type != IS_UNUSED) {
2419 							ssa_var_info[
2420 								ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info) +
2421 								EX_VAR_TO_NUM(opline->result.var)] = return_value_info;
2422 						}
2423 					}
2424 					memset(&return_value_info, 0, sizeof(return_value_info));
2425 				}
2426 			} else {
2427 				level--;
2428 				if (return_value_info.type != 0) {
2429 					if ((p+1)->op == ZEND_JIT_TRACE_VM) {
2430 						const zend_op *opline = (p+1)->opline - 1;
2431 						if (opline->result_type != IS_UNUSED) {
2432 							if (TRACE_FRAME_RETURN_SSA_VAR(frame) >= 0) {
2433 								ssa_var_info[TRACE_FRAME_RETURN_SSA_VAR(frame)] = return_value_info;
2434 							}
2435 						}
2436 					}
2437 					memset(&return_value_info, 0, sizeof(return_value_info));
2438 				}
2439 			}
2440 
2441 			top = frame;
2442 			if (frame->prev) {
2443 				if (used_stack > 0) {
2444 					used_stack -= frame->used_stack;
2445 				}
2446 				frame = frame->prev;
2447 				ZEND_ASSERT(&frame->func->op_array == op_array);
2448 			} else {
2449 				max_used_stack = used_stack = -1;
2450 				frame = zend_jit_trace_ret_frame(frame, op_array);
2451 				TRACE_FRAME_INIT(frame, op_array, 0, 0);
2452 				TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
2453 				frame->used_stack = 0;
2454 				for (i = 0; i < op_array->last_var + op_array->T; i++) {
2455 					SET_STACK_TYPE(frame->stack, i, IS_UNKNOWN, 1);
2456 				}
2457 			}
2458 
2459 		} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
2460 			call = top;
2461 			TRACE_FRAME_INIT(call, p->func, 0, 0);
2462 			call->prev = frame->call;
2463 			call->used_stack = 0;
2464 			frame->call = call;
2465 			top = zend_jit_trace_call_frame(top, p->op_array);
2466 			if (p->func && p->func->type == ZEND_USER_FUNCTION) {
2467 				for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
2468 					SET_STACK_INFO(call->stack, i, -1);
2469 				}
2470 			}
2471 			if (used_stack >= 0
2472 			 && !(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
2473 				if (p->func == NULL || (p-1)->op != ZEND_JIT_TRACE_VM) {
2474 					max_used_stack = used_stack = -1;
2475 				} else {
2476 					const zend_op *opline = (p-1)->opline;
2477 
2478 					switch (opline->opcode) {
2479 						case ZEND_INIT_FCALL:
2480 						case ZEND_INIT_FCALL_BY_NAME:
2481 						case ZEND_INIT_NS_FCALL_BY_NAME:
2482 						case ZEND_INIT_METHOD_CALL:
2483 						case ZEND_INIT_DYNAMIC_CALL:
2484 						//case ZEND_INIT_STATIC_METHOD_CALL:
2485 						//case ZEND_INIT_USER_CALL:
2486 						//case ZEND_NEW:
2487 							frame->used_stack = zend_vm_calc_used_stack(opline->extended_value, (zend_function*)p->func);
2488 							used_stack += frame->used_stack;
2489 							if (used_stack > max_used_stack) {
2490 								max_used_stack = used_stack;
2491 							}
2492 							break;
2493 						default:
2494 							max_used_stack = used_stack = -1;
2495 					}
2496 				}
2497 			}
2498 		} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
2499 			call = frame->call;
2500 			if (call) {
2501 				top = call;
2502 				frame->call = call->prev;
2503 			}
2504 
2505 			if (idx > 0
2506 			 && ssa_ops[idx-1].result_def >= 0
2507 			 && (p->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)
2508 			 && !(p->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
2509 				ZEND_ASSERT(ssa_opcodes[idx-1] == opline);
2510 				ZEND_ASSERT(opline->opcode == ZEND_DO_ICALL ||
2511 					opline->opcode == ZEND_DO_FCALL ||
2512 					opline->opcode == ZEND_DO_FCALL_BY_NAME);
2513 
2514 				if (opline->result_type != IS_UNDEF) {
2515 					zend_class_entry *ce;
2516 					const zend_function *func = p->func;
2517 					zend_arg_info *ret_info = func->common.arg_info - 1;
2518 					uint32_t ret_type = zend_fetch_arg_info_type(NULL, ret_info, &ce);
2519 
2520 					ssa_var_info[ssa_ops[idx-1].result_def].type &= ret_type;
2521 				}
2522 			}
2523 		} else if (p->op == ZEND_JIT_TRACE_END) {
2524 			break;
2525 		}
2526 	}
2527 
2528 	((zend_tssa*)tssa)->used_stack = max_used_stack;
2529 
2530 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2531 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2532 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2533 		/* Propagate guards through Phi sources */
2534 		zend_ssa_phi *phi = tssa->blocks[1].phis;
2535 
2536 		op_array = trace_buffer->op_array;
2537 		jit_extension =
2538 			(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2539 		ssa = &jit_extension->func_info.ssa;
2540 
2541 		while (phi) {
2542 			uint32_t t = ssa_var_info[phi->ssa_var].type;
2543 
2544 			if ((t & MAY_BE_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
2545 				uint32_t t0 = ssa_var_info[phi->sources[0]].type;
2546 				uint32_t t1 = ssa_var_info[phi->sources[1]].type;
2547 
2548 				if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2549 					if (!((t0 | t1) & MAY_BE_GUARD)) {
2550 						ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2551 					}
2552 				} else if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2553 					if (!(t1 & MAY_BE_GUARD)
2554 					 || is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
2555 						ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2556 						t0 = (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2557 							(t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2558 							MAY_BE_GUARD;
2559 						if (!(t0 & MAY_BE_ARRAY)) {
2560 							t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2561 						}
2562 						if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2563 							t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2564 						}
2565 						ssa_var_info[phi->sources[0]].type = t0;
2566 						ssa_var_info[phi->sources[0]].type = t0;
2567 					}
2568 				} else {
2569 					if ((t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2570 						t0 = (t & t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2571 							(t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2572 							MAY_BE_GUARD;
2573 						if (!(t0 & MAY_BE_ARRAY)) {
2574 							t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2575 						}
2576 						if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2577 							t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2578 						}
2579 						ssa_var_info[phi->sources[0]].type = t0;
2580 					}
2581 					if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2582 						if (((t & t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != 0
2583 						 && is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
2584 							t1 = (t & t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2585 								(t1 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2586 								MAY_BE_GUARD;
2587 							if (!(t1 & MAY_BE_ARRAY)) {
2588 								t1 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2589 							}
2590 							if (!(t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2591 								t1 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2592 							}
2593 							ssa_var_info[phi->sources[1]].type = t1;
2594 							ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2595 						}
2596 					}
2597 				}
2598 				t = ssa_var_info[phi->ssa_var].type;
2599 			}
2600 
2601 			if ((t & MAY_BE_PACKED_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
2602 				uint32_t t0 = ssa_var_info[phi->sources[0]].type;
2603 				uint32_t t1 = ssa_var_info[phi->sources[1]].type;
2604 
2605 				if (((t0 | t1) & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
2606 					if (!((t0 | t1) & MAY_BE_PACKED_GUARD)) {
2607 						ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
2608 					}
2609 				} else if ((t1 & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
2610 					if (!(t1 & MAY_BE_PACKED_GUARD)) {
2611 						ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
2612 						ssa_var_info[phi->sources[0]].type =
2613 							(t0 & ~MAY_BE_ARRAY_KEY_ANY) | (t & MAY_BE_ARRAY_KEY_ANY) | MAY_BE_PACKED_GUARD;
2614 					}
2615 				}
2616 			}
2617 			phi = phi->next;
2618 		}
2619 	}
2620 
2621 	if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_TSSA)) {
2622 		if (parent_trace) {
2623 			fprintf(stderr, "---- TRACE %d TSSA start (side trace %d/%d) %s%s%s() %s:%d\n",
2624 				ZEND_JIT_TRACE_NUM,
2625 				parent_trace,
2626 				exit_num,
2627 				trace_buffer->op_array->scope ? ZSTR_VAL(trace_buffer->op_array->scope->name) : "",
2628 				trace_buffer->op_array->scope ? "::" : "",
2629 				trace_buffer->op_array->function_name ?
2630 					ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
2631 				ZSTR_VAL(trace_buffer->op_array->filename),
2632 				trace_buffer[1].opline->lineno);
2633 		} else {
2634 			fprintf(stderr, "---- TRACE %d TSSA start (%s) %s%s%s() %s:%d\n",
2635 				ZEND_JIT_TRACE_NUM,
2636 				zend_jit_trace_star_desc(trace_buffer->start),
2637 				trace_buffer->op_array->scope ? ZSTR_VAL(trace_buffer->op_array->scope->name) : "",
2638 				trace_buffer->op_array->scope ? "::" : "",
2639 				trace_buffer->op_array->function_name ?
2640 					ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
2641 				ZSTR_VAL(trace_buffer->op_array->filename),
2642 				trace_buffer[1].opline->lineno);
2643 		}
2644 		zend_jit_dump_trace(trace_buffer, tssa);
2645 		if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LINK) {
2646 			uint32_t idx = trace_buffer[1].last;
2647 			uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
2648 			fprintf(stderr, "---- TRACE %d TSSA stop (link to %d)\n",
2649 				ZEND_JIT_TRACE_NUM,
2650 				link_to);
2651 		} else {
2652 			fprintf(stderr, "---- TRACE %d TSSA stop (%s)\n",
2653 				ZEND_JIT_TRACE_NUM,
2654 				zend_jit_trace_stop_description[trace_buffer->stop]);
2655 		}
2656 	}
2657 
2658 	return tssa;
2659 }
2660 
zend_jit_close_var(zend_jit_trace_stack * stack,uint32_t n,int * start,int * end,uint8_t * flags,int line)2661 static void zend_jit_close_var(zend_jit_trace_stack *stack, uint32_t n, int *start, int *end, uint8_t *flags, int line)
2662 {
2663 	int32_t var = STACK_VAR(stack, n);
2664 
2665 	if (var >= 0 && start[var] >= 0 && !(flags[var] & ZREG_LAST_USE)) {
2666 		// TODO: shrink interval to last side exit ????
2667 		end[var] = line;
2668 	}
2669 }
2670 
zend_jit_trace_use_var(int line,int var,int def,int use_chain,int * start,int * end,uint8_t * flags,const zend_ssa * ssa,const zend_op ** ssa_opcodes,const zend_op_array * op_array,const zend_ssa * op_array_ssa)2671 static void zend_jit_trace_use_var(int line, int var, int def, int use_chain, int *start, int *end, uint8_t *flags, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array, const zend_ssa *op_array_ssa)
2672 {
2673 	ZEND_ASSERT(start[var] >= 0);
2674 	ZEND_ASSERT(!(flags[var] & ZREG_LAST_USE));
2675 	end[var] = line;
2676 	if (def >= 0) {
2677 		flags[var] |= ZREG_LAST_USE;
2678 	} else if (use_chain < 0 && (flags[var] & (ZREG_LOAD|ZREG_STORE))) {
2679 		flags[var] |= ZREG_LAST_USE;
2680 	} else if (use_chain >= 0 && !zend_ssa_is_no_val_use(ssa_opcodes[use_chain], ssa->ops + use_chain, var)) {
2681 		/* pass */
2682 	} else if (op_array_ssa->vars) {
2683 		uint32_t use = ssa_opcodes[line] - op_array->opcodes;
2684 
2685 		if (ssa->ops[line].op1_use == var) {
2686 			if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op1_use, use)) {
2687 				flags[var] |= ZREG_LAST_USE;
2688 			}
2689 		} else if (ssa->ops[line].op2_use == var) {
2690 			if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op2_use, use)) {
2691 				flags[var] |= ZREG_LAST_USE;
2692 			}
2693 		} else if (ssa->ops[line].result_use == var) {
2694 			if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].result_use, use)) {
2695 				flags[var] |= ZREG_LAST_USE;
2696 			}
2697 		}
2698 	}
2699 }
2700 
zend_jit_trace_allocate_registers(zend_jit_trace_rec * trace_buffer,zend_ssa * ssa,uint32_t parent_trace,uint32_t exit_num)2701 static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace_rec *trace_buffer, zend_ssa *ssa, uint32_t parent_trace, uint32_t exit_num)
2702 {
2703 	const zend_op **ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
2704 	zend_jit_trace_rec *p;
2705 	const zend_op_array *op_array;
2706 	zend_jit_op_array_trace_extension *jit_extension;
2707 	const zend_ssa *op_array_ssa;
2708 	const zend_ssa_op *ssa_op;
2709 	int i, j, idx, count, level;
2710 	int last_idx = -1;
2711 	int *start, *end;
2712 	uint8_t *flags;
2713 	const zend_op_array **vars_op_array;
2714 	zend_lifetime_interval **intervals, *list, *ival;
2715 	void *checkpoint;
2716 	zend_jit_trace_stack_frame *frame;
2717 	zend_jit_trace_stack *stack;
2718 	uint32_t parent_vars_count = parent_trace ?
2719 		zend_jit_traces[parent_trace].exit_info[exit_num].stack_size : 0;
2720 	zend_jit_trace_stack *parent_stack = parent_trace ?
2721 		zend_jit_traces[parent_trace].stack_map +
2722 		zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset : NULL;
2723 	ALLOCA_FLAG(use_heap);
2724 
2725 	ZEND_ASSERT(ssa->var_info != NULL);
2726 
2727 	start = do_alloca(sizeof(int) * ssa->vars_count * 2 +
2728 		ZEND_MM_ALIGNED_SIZE(sizeof(uint8_t) * ssa->vars_count),
2729 		use_heap);
2730 	if (!start) {
2731 		return NULL;
2732 	}
2733 	end = start + ssa->vars_count;
2734 	flags = (uint8_t*)(end + ssa->vars_count);
2735 	checkpoint = zend_arena_checkpoint(CG(arena));
2736 	vars_op_array = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_op_array*));
2737 
2738 	memset(start, -1, sizeof(int) * ssa->vars_count * 2);
2739 	memset(flags, 0, sizeof(uint8_t) * ssa->vars_count);
2740 	memset(ZEND_VOIDP(vars_op_array), 0, sizeof(zend_op_array*) * ssa->vars_count);
2741 
2742 	op_array = trace_buffer->op_array;
2743 	jit_extension =
2744 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2745 	op_array_ssa = &jit_extension->func_info.ssa;
2746 	frame = JIT_G(current_frame);
2747 	frame->prev = NULL;
2748 	frame->func = (const zend_function*)op_array;
2749 	stack = frame->stack;
2750 
2751 	count = 0;
2752 
2753 	i = 0;
2754 	j = op_array->last_var;
2755 	if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
2756 		j += op_array->T;
2757 	}
2758 	while (i < j) {
2759 		SET_STACK_VAR(stack, i, i);
2760 		vars_op_array[i] = op_array;
2761 		/* We don't start intervals for variables used in Phi */
2762 		if ((ssa->vars[i].use_chain >= 0 /*|| ssa->vars[i].phi_use_chain*/)
2763 		 && !zend_ssa_is_no_val_use(ssa_opcodes[ssa->vars[i].use_chain], ssa->ops + ssa->vars[i].use_chain, i)
2764 		 && ssa->vars[i].alias == NO_ALIAS
2765 		 && zend_jit_var_supports_reg(ssa, i)) {
2766 			start[i] = 0;
2767 			if (i < parent_vars_count
2768 			 && STACK_REG(parent_stack, i) != ZREG_NONE
2769 			 && STACK_REG(parent_stack, i) < ZREG_NUM) {
2770 				/* We will try to reuse register from parent trace */
2771 				flags[i] = STACK_FLAGS(parent_stack, i);
2772 				count += 2;
2773 			} else {
2774 				flags[i] = ZREG_LOAD;
2775 				count++;
2776 			}
2777 		}
2778 		i++;
2779 	}
2780 
2781 	if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
2782 		j = op_array->last_var + op_array->T;
2783 		while (i < j) {
2784 			SET_STACK_VAR(stack, i, -1);
2785 			i++;
2786 		}
2787 	}
2788 
2789 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2790 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2791 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2792 		zend_ssa_phi *phi = ssa->blocks[1].phis;
2793 
2794 		while (phi) {
2795 			SET_STACK_VAR(stack, phi->var, phi->ssa_var);
2796 			vars_op_array[phi->ssa_var] = op_array;
2797 			if (ssa->vars[phi->ssa_var].use_chain >= 0
2798 			 && ssa->vars[phi->ssa_var].alias == NO_ALIAS
2799 			 && zend_jit_var_supports_reg(ssa, phi->ssa_var)) {
2800 				start[phi->ssa_var] = 0;
2801 				count++;
2802 			}
2803 			phi = phi->next;
2804 		}
2805 	}
2806 
2807 	p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
2808 	level = 0;
2809 	ssa_op = ssa->ops;
2810 	idx = 0;
2811 	for (;;p++) {
2812 		if (p->op == ZEND_JIT_TRACE_VM) {
2813 			const zend_op *opline = p->opline;
2814 			int len;
2815 			bool support_opline;
2816 
2817 			support_opline =
2818 				zend_jit_opline_supports_reg(op_array, ssa, opline, ssa_op, p);
2819 
2820 			if (support_opline
2821 			 && opline->opcode == ZEND_ASSIGN
2822 			 && opline->op1_type == IS_CV
2823 			 && ssa_op->op1_def >= 0
2824 			 && ssa->vars[ssa_op->op1_def].alias != NO_ALIAS) {
2825 				/* avoid register allocation in case of possibility of indirect modification*/
2826 				support_opline = 0;
2827 			}
2828 
2829 			if (ssa_op->op1_use >= 0
2830 			 && start[ssa_op->op1_use] >= 0
2831 			 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
2832 				if (support_opline) {
2833 					zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2834 					if (opline->op1_type != IS_CV) {
2835 						if (opline->opcode == ZEND_CASE
2836 						 || opline->opcode == ZEND_CASE_STRICT
2837 						 || opline->opcode == ZEND_SWITCH_LONG
2838 						 || opline->opcode == ZEND_MATCH
2839 						 || opline->opcode == ZEND_FETCH_LIST_R
2840 						 || opline->opcode == ZEND_COPY_TMP
2841 						 || opline->opcode == ZEND_SWITCH_STRING
2842 						 || opline->opcode == ZEND_FE_FETCH_R
2843 						 || opline->opcode == ZEND_FE_FETCH_RW
2844 						 || opline->opcode == ZEND_FETCH_LIST_W
2845 						 || opline->opcode == ZEND_VERIFY_RETURN_TYPE
2846 						 || opline->opcode == ZEND_BIND_LEXICAL
2847 						 || opline->opcode == ZEND_ROPE_ADD) {
2848 							/* The value is kept alive and may be used outside of the trace */
2849 							flags[ssa_op->op1_use] |= ZREG_STORE;
2850 						} else {
2851 							flags[ssa_op->op1_use] |= ZREG_LAST_USE;
2852 						}
2853 					}
2854 				} else {
2855 					start[ssa_op->op1_use] = -1;
2856 					end[ssa_op->op1_use] = -1;
2857 					count--;
2858 				}
2859 			}
2860 			if (ssa_op->op2_use >= 0
2861 			 && ssa_op->op2_use != ssa_op->op1_use
2862 			 && start[ssa_op->op2_use] >= 0
2863 			 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)) {
2864 				if (support_opline) {
2865 					zend_jit_trace_use_var(idx, ssa_op->op2_use, ssa_op->op2_def, ssa_op->op2_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2866 					if (opline->op2_type != IS_CV) {
2867 						flags[ssa_op->op2_use] |= ZREG_LAST_USE;
2868 					}
2869 				} else {
2870 					start[ssa_op->op2_use] = -1;
2871 					end[ssa_op->op2_use] = -1;
2872 					count--;
2873 				}
2874 			}
2875 			if (ssa_op->result_use >= 0
2876 			 && ssa_op->result_use != ssa_op->op1_use
2877 			 && ssa_op->result_use != ssa_op->op2_use
2878 			 && start[ssa_op->result_use] >= 0
2879 			 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->result_use)) {
2880 				if (support_opline) {
2881 					zend_jit_trace_use_var(idx, ssa_op->result_use, ssa_op->result_def, ssa_op->res_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2882 				} else {
2883 					start[ssa_op->result_use] = -1;
2884 					end[ssa_op->result_use] = -1;
2885 					count--;
2886 				}
2887 			}
2888 
2889 			if (ssa_op->op1_def >= 0) {
2890 				zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
2891 				SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
2892 			}
2893 			if (ssa_op->op2_def >= 0) {
2894 				zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op2.var), start, end, flags, idx);
2895 				SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op2.var), ssa_op->op2_def);
2896 			}
2897 			if (ssa_op->result_def >= 0) {
2898 				zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), start, end, flags, idx);
2899 				SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
2900 			}
2901 
2902 			if (support_opline) {
2903 				if (ssa_op->result_def >= 0
2904 				 && (ssa->vars[ssa_op->result_def].use_chain >= 0
2905 			      || ssa->vars[ssa_op->result_def].phi_use_chain)
2906 				 && ssa->vars[ssa_op->result_def].alias == NO_ALIAS
2907 				 && zend_jit_var_supports_reg(ssa, ssa_op->result_def)) {
2908 					if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
2909 					 || opline->opcode == ZEND_PRE_INC
2910 					 || opline->opcode == ZEND_PRE_DEC
2911 					 || opline->opcode == ZEND_POST_INC
2912 					 || opline->opcode == ZEND_POST_DEC
2913 					 || opline->opcode == ZEND_ADD
2914 					 || opline->opcode == ZEND_SUB
2915 					 || opline->opcode == ZEND_MUL
2916 					 || opline->opcode == ZEND_FETCH_DIM_R
2917 					 || opline->opcode == ZEND_FETCH_CONSTANT) {
2918 						if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_DOUBLE)
2919 						 || (opline->opcode != ZEND_PRE_INC && opline->opcode != ZEND_PRE_DEC)) {
2920 							start[ssa_op->result_def] = idx;
2921 							vars_op_array[ssa_op->result_def] = op_array;
2922 							count++;
2923 						}
2924 					}
2925 				}
2926 				if (ssa_op->op1_def >= 0
2927 				 && (ssa->vars[ssa_op->op1_def].use_chain >= 0
2928 			      || ssa->vars[ssa_op->op1_def].phi_use_chain)
2929 				 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS
2930 				 && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
2931 					start[ssa_op->op1_def] = idx;
2932 					vars_op_array[ssa_op->op1_def] = op_array;
2933 					count++;
2934 				}
2935 				if (ssa_op->op2_def >= 0
2936 				 && (ssa->vars[ssa_op->op2_def].use_chain >= 0
2937 			      || ssa->vars[ssa_op->op2_def].phi_use_chain)
2938 				 && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS
2939 				 && zend_jit_var_supports_reg(ssa, ssa_op->op2_def)) {
2940 					start[ssa_op->op2_def] = idx;
2941 					vars_op_array[ssa_op->op2_def] = op_array;
2942 					count++;
2943 				}
2944 			}
2945 
2946 			len = zend_jit_trace_op_len(opline);
2947 			switch (opline->opcode) {
2948 				case ZEND_ASSIGN_DIM:
2949 				case ZEND_ASSIGN_OBJ:
2950 				case ZEND_ASSIGN_STATIC_PROP:
2951 				case ZEND_ASSIGN_DIM_OP:
2952 				case ZEND_ASSIGN_OBJ_OP:
2953 				case ZEND_ASSIGN_STATIC_PROP_OP:
2954 				case ZEND_ASSIGN_OBJ_REF:
2955 				case ZEND_ASSIGN_STATIC_PROP_REF:
2956 					/* OP_DATA */
2957 					ssa_op++;
2958 					opline++;
2959 					if (ssa_op->op1_use >= 0
2960 					 && start[ssa_op->op1_use] >= 0
2961 					 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
2962 						if (support_opline) {
2963 							zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2964 							if (opline->op1_type != IS_CV) {
2965 								flags[ssa_op->op1_use] |= ZREG_LAST_USE;
2966 							}
2967 						} else {
2968 							start[ssa_op->op1_use] = -1;
2969 							end[ssa_op->op1_use] = -1;
2970 							count--;
2971 						}
2972 					}
2973 					if (ssa_op->op1_def >= 0) {
2974 						zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
2975 						SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
2976 						if (support_opline
2977 						 && (ssa->vars[ssa_op->op1_def].use_chain >= 0
2978 					      || ssa->vars[ssa_op->op1_def].phi_use_chain)
2979 						 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS
2980 						 && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
2981 							start[ssa_op->op1_def] = idx;
2982 							vars_op_array[ssa_op->op1_def] = op_array;
2983 							count++;
2984 						}
2985 					}
2986 					ssa_op++;
2987 					opline++;
2988 					idx+=2;
2989 					break;
2990 				case ZEND_RECV_INIT:
2991 				    ssa_op++;
2992 					opline++;
2993 					idx++;
2994 					while (opline->opcode == ZEND_RECV_INIT) {
2995 						/* RECV_INIT doesn't support registers */
2996 						if (ssa_op->result_def >= 0) {
2997 							zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), start, end, flags, idx);
2998 							SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
2999 						}
3000 						ssa_op++;
3001 						opline++;
3002 						idx++;
3003 					}
3004 					break;
3005 				case ZEND_BIND_GLOBAL:
3006 					ssa_op++;
3007 					opline++;
3008 					idx++;
3009 					while (opline->opcode == ZEND_BIND_GLOBAL) {
3010 						/* BIND_GLOBAL doesn't support registers */
3011 						if (ssa_op->op1_def >= 0) {
3012 							zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
3013 							SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
3014 						}
3015 						ssa_op++;
3016 						opline++;
3017 						idx++;
3018 					}
3019 					break;
3020 				default:
3021 					ssa_op += len;
3022 					idx += len;
3023 					break;
3024 			}
3025 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
3026 			/* New call frames */
3027 			zend_jit_trace_stack_frame *prev_frame = frame;
3028 
3029 			frame = zend_jit_trace_call_frame(frame, op_array);
3030 			frame->prev = prev_frame;
3031 			frame->func = (const zend_function*)p->op_array;
3032 			stack = frame->stack;
3033 			op_array = p->op_array;
3034 			jit_extension =
3035 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3036 			op_array_ssa = &jit_extension->func_info.ssa;
3037 			j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
3038 			for (i = 0; i < op_array->last_var; i++) {
3039 				SET_STACK_VAR(stack, i, j);
3040 				vars_op_array[j] = op_array;
3041 				if (ssa->vars[j].use_chain >= 0
3042 				 && ssa->vars[j].alias == NO_ALIAS
3043 				 && zend_jit_var_supports_reg(ssa, j)) {
3044 					start[j] = idx;
3045 					flags[j] = ZREG_LOAD;
3046 					count++;
3047 				}
3048 				j++;
3049 			}
3050 			for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) {
3051 				SET_STACK_VAR(stack, i, -1);
3052 			}
3053 			level++;
3054 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
3055 			/* Close exiting call frames */
3056 			for (i = 0; i < op_array->last_var; i++) {
3057 				zend_jit_close_var(stack, i, start, end, flags, idx-1);
3058 			}
3059 			op_array = p->op_array;
3060 			jit_extension =
3061 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3062 			op_array_ssa = &jit_extension->func_info.ssa;
3063 			frame = zend_jit_trace_ret_frame(frame, op_array);
3064 			stack = frame->stack;
3065 			if (level == 0) {
3066 				/* New return frames */
3067 				frame->prev = NULL;
3068 				frame->func = (const zend_function*)op_array;
3069 				j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
3070 				for (i = 0; i < op_array->last_var + op_array->T; i++) {
3071 					SET_STACK_VAR(stack, i, j);
3072 					vars_op_array[j] = op_array;
3073 					if (ssa->vars[j].use_chain >= 0
3074 					 && ssa->vars[j].alias == NO_ALIAS
3075 					 && zend_jit_var_supports_reg(ssa, j)) {
3076 						start[j] = idx;
3077 						flags[j] = ZREG_LOAD;
3078 						count++;
3079 					}
3080 					j++;
3081 				}
3082 			} else {
3083 				level--;
3084 			}
3085 		} else if (p->op == ZEND_JIT_TRACE_END) {
3086 			break;
3087 		}
3088 	}
3089 
3090 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3091 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3092 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3093 		zend_ssa_phi *phi = ssa->blocks[1].phis;
3094 
3095 		while (phi) {
3096 			i = phi->sources[1];
3097 			if (start[i] >= 0 && !ssa->vars[phi->ssa_var].no_val) {
3098 				end[i] = idx;
3099 				flags[i] &= ~ZREG_LAST_USE;
3100 			}
3101 			phi = phi->next;
3102 		}
3103 
3104 		if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
3105 			for (i = 0; i < op_array->last_var; i++) {
3106 				if (start[i] >= 0 && !ssa->vars[i].phi_use_chain) {
3107 					end[i] = idx;
3108 					flags[i] &= ~ZREG_LAST_USE;
3109 				} else {
3110 					zend_jit_close_var(stack, i, start, end, flags, idx);
3111 				}
3112 			}
3113 		}
3114 	} else {
3115 		last_idx = idx;
3116 		for (i = 0; i < op_array->last_var; i++) {
3117 			zend_jit_close_var(stack, i, start, end, flags, idx);
3118 		}
3119 		while (frame->prev) {
3120 			frame = frame->prev;
3121 			op_array = &frame->func->op_array;
3122 			stack = frame->stack;
3123 			for (i = 0; i < op_array->last_var; i++) {
3124 				zend_jit_close_var(stack, i, start, end, flags, idx);
3125 			}
3126 		}
3127 	}
3128 
3129 	if (!count) {
3130 		free_alloca(start, use_heap);
3131 		zend_arena_release(&CG(arena), checkpoint);
3132 		return NULL;
3133 	}
3134 
3135 	intervals = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_lifetime_interval));
3136 	memset(intervals, 0, sizeof(zend_lifetime_interval*) * ssa->vars_count);
3137 	list = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval) * count);
3138 	j = 0;
3139 	for (i = 0; i < ssa->vars_count; i++) {
3140 		if (start[i] >= 0 && end[i] >= 0) {
3141 			ZEND_ASSERT(j < count);
3142 			if ((flags[i] & ZREG_LOAD) &&
3143 			    (flags[i] & ZREG_LAST_USE) &&
3144 			    end[i] == ssa->vars[i].use_chain) {
3145 				/* skip life range with single use */
3146 				continue;
3147 			}
3148 			intervals[i] = &list[j];
3149 			list[j].ssa_var = i;
3150 			list[j].reg = ZREG_NONE;
3151 			list[j].flags = flags[i];
3152 			list[j].range.start = start[i];
3153 			list[j].range.end = end[i];
3154 			list[j].range.next = NULL;
3155 			list[j].hint = NULL;
3156 			list[j].used_as_hint = NULL;
3157 			list[j].list_next = NULL;
3158 			j++;
3159 		}
3160 	}
3161 	count = j;
3162 	free_alloca(start, use_heap);
3163 	start = end = NULL;
3164 
3165 	if (!count) {
3166 		zend_arena_release(&CG(arena), checkpoint);
3167 		return NULL;
3168 	}
3169 
3170 	/* Add hints */
3171 	if (parent_vars_count) {
3172 		i = trace_buffer->op_array->last_var;
3173 		if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
3174 			i += trace_buffer->op_array->T;
3175 		}
3176 		if ((uint32_t)i > parent_vars_count) {
3177 			i = parent_vars_count;
3178 		}
3179 		while (i > 0) {
3180 			i--;
3181 			if (intervals[i]
3182 			 && STACK_REG(parent_stack, i) != ZREG_NONE
3183 			 && STACK_REG(parent_stack, i) < ZREG_NUM) {
3184 				list[j].ssa_var = - 1;
3185 				list[j].reg = STACK_REG(parent_stack, i);
3186 				list[j].flags = 0;
3187 				list[j].range.start = -1;
3188 				list[j].range.end = -1;
3189 				list[j].range.next = NULL;
3190 				list[j].hint = NULL;
3191 				list[j].used_as_hint = NULL;
3192 				list[j].list_next = NULL;
3193 				intervals[i]->hint = &list[j];
3194 				j++;
3195 			}
3196 		}
3197 	}
3198 
3199 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3200 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3201 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3202 		zend_ssa_phi *phi = ssa->blocks[1].phis;
3203 
3204 		while (phi) {
3205 			if (intervals[phi->ssa_var]) {
3206 				if (intervals[phi->sources[1]]
3207 				 && (ssa->var_info[phi->sources[1]].type & MAY_BE_ANY) ==
3208 						(ssa->var_info[phi->ssa_var].type & MAY_BE_ANY)) {
3209 					intervals[phi->sources[1]]->hint = intervals[phi->ssa_var];
3210 				}
3211 			}
3212 			phi = phi->next;
3213 		}
3214 	}
3215 
3216 	for (i = 0; i < ssa->vars_count; i++) {
3217 		if (intervals[i] && !intervals[i]->hint) {
3218 
3219 			if (ssa->vars[i].definition >= 0) {
3220 				uint32_t line = ssa->vars[i].definition;
3221 				const zend_op *opline = ssa_opcodes[line];
3222 
3223 				switch (opline->opcode) {
3224 					case ZEND_QM_ASSIGN:
3225 					case ZEND_POST_INC:
3226 					case ZEND_POST_DEC:
3227 						if (ssa->ops[line].op1_use >= 0 &&
3228 						    intervals[ssa->ops[line].op1_use] &&
3229 						    (i == ssa->ops[line].op1_def ||
3230 						     (i == ssa->ops[line].result_def &&
3231 						      (ssa->ops[line].op1_def < 0 ||
3232 						       !intervals[ssa->ops[line].op1_def])))) {
3233 							zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
3234 						}
3235 						break;
3236 					case ZEND_SEND_VAR:
3237 						if (opline->op2_type == IS_CONST) {
3238 							/* Named parameters not supported in JIT */
3239 							break;
3240 						}
3241 					case ZEND_PRE_INC:
3242 					case ZEND_PRE_DEC:
3243 						if (i == ssa->ops[line].op1_def &&
3244 						    ssa->ops[line].op1_use >= 0 &&
3245 						    intervals[ssa->ops[line].op1_use]) {
3246 							zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
3247 						}
3248 						break;
3249 					case ZEND_ASSIGN:
3250 						if (ssa->ops[line].op2_use >= 0 &&
3251 						    intervals[ssa->ops[line].op2_use] &&
3252 						    (i == ssa->ops[line].op2_def ||
3253 							 (i == ssa->ops[line].op1_def &&
3254 						      (ssa->ops[line].op2_def < 0 ||
3255 						       !intervals[ssa->ops[line].op2_def])) ||
3256 							 (i == ssa->ops[line].result_def &&
3257 						      (ssa->ops[line].op2_def < 0 ||
3258 						       !intervals[ssa->ops[line].op2_def]) &&
3259 						      (ssa->ops[line].op1_def < 0 ||
3260 						       !intervals[ssa->ops[line].op1_def])))) {
3261 							zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
3262 						}
3263 						break;
3264 					case ZEND_SUB:
3265 					case ZEND_ADD:
3266 					case ZEND_MUL:
3267 					case ZEND_BW_OR:
3268 					case ZEND_BW_AND:
3269 					case ZEND_BW_XOR:
3270 						if (i == ssa->ops[line].result_def) {
3271 							if (ssa->ops[line].op1_use >= 0 &&
3272 							    intervals[ssa->ops[line].op1_use] &&
3273 							    ssa->ops[line].op1_use_chain < 0 &&
3274 							    !ssa->vars[ssa->ops[line].op1_use].phi_use_chain &&
3275 							    (ssa->var_info[i].type & MAY_BE_ANY) ==
3276 							        (ssa->var_info[ssa->ops[line].op1_use].type & MAY_BE_ANY)) {
3277 
3278 								zend_ssa_phi *phi = ssa->vars[ssa->ops[line].op1_use].definition_phi;
3279 								if (phi &&
3280 								    intervals[phi->sources[1]] &&
3281 								    intervals[phi->sources[1]]->hint == intervals[ssa->ops[line].op1_use]) {
3282 									break;
3283 								}
3284 								zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
3285 							} else if (opline->opcode != ZEND_SUB &&
3286 							    ssa->ops[line].op2_use >= 0 &&
3287 							    intervals[ssa->ops[line].op2_use] &&
3288 							    ssa->ops[line].op2_use_chain < 0 &&
3289 							    !ssa->vars[ssa->ops[line].op2_use].phi_use_chain &&
3290 							    (ssa->var_info[i].type & MAY_BE_ANY) ==
3291 							        (ssa->var_info[ssa->ops[line].op2_use].type & MAY_BE_ANY)) {
3292 
3293 								zend_ssa_phi *phi = ssa->vars[ssa->ops[line].op2_use].definition_phi;
3294 								if (phi &&
3295 								    intervals[phi->sources[1]] &&
3296 								    intervals[phi->sources[1]]->hint == intervals[ssa->ops[line].op2_use]) {
3297 									break;
3298 								}
3299 								zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
3300 							}
3301 						}
3302 						break;
3303 				}
3304 			}
3305 		}
3306 	}
3307 
3308 	list = zend_jit_sort_intervals(intervals, ssa->vars_count);
3309 
3310 	if (list) {
3311 		ival = list;
3312 		while (ival) {
3313 			if (ival->hint) {
3314 				ival->hint->used_as_hint = ival;
3315 			}
3316 			ival = ival->list_next;
3317 		}
3318 	}
3319 
3320 	if (list) {
3321 		if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
3322 			fprintf(stderr, "---- TRACE %d Live Ranges\n", ZEND_JIT_TRACE_NUM);
3323 			ival = list;
3324 			while (ival) {
3325 				zend_jit_dump_lifetime_interval(vars_op_array[ival->ssa_var], ssa, ival);
3326 				ival = ival->list_next;
3327 			}
3328 		}
3329 	}
3330 
3331 	/* Linear Scan Register Allocation (op_array is not actually used, only fn_flags matters) */
3332 	list = zend_jit_linear_scan(&dummy_op_array, ssa_opcodes, ssa, list);
3333 
3334 	if (list) {
3335 		zend_lifetime_interval *ival, *next;
3336 
3337 		memset(intervals, 0, ssa->vars_count * sizeof(zend_lifetime_interval*));
3338 		ival = list;
3339 		count = 0;
3340 		while (ival != NULL) {
3341 			ZEND_ASSERT(ival->reg != ZREG_NONE);
3342 			count++;
3343 			next = ival->list_next;
3344 			ival->list_next = intervals[ival->ssa_var];
3345 			intervals[ival->ssa_var] = ival;
3346 			ival = next;
3347 		}
3348 
3349 		if (!count) {
3350 			zend_arena_release(&CG(arena), checkpoint);
3351 			return NULL;
3352 		}
3353 
3354 		/* Add LOAD flag to registers that can't reuse register from parent trace */
3355 		if (parent_vars_count) {
3356 			i = trace_buffer->op_array->last_var;
3357 			if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
3358 				i += trace_buffer->op_array->T;
3359 			}
3360 			if ((uint32_t)i > parent_vars_count) {
3361 				i = parent_vars_count;
3362 			}
3363 			while (i > 0) {
3364 				i--;
3365 				if (intervals[i] && intervals[i]->reg != STACK_REG(parent_stack, i)) {
3366 					intervals[i]->flags |= ZREG_LOAD;
3367 				}
3368 			}
3369 		}
3370 
3371 		/* SSA resolution */
3372 		if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3373 		 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3374 		 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3375 			zend_ssa_phi *phi = ssa->blocks[1].phis;
3376 
3377 			while (phi) {
3378 				int def = phi->ssa_var;
3379 				int use = phi->sources[1];
3380 
3381 				if (intervals[def]) {
3382 					if (!intervals[use]) {
3383 						intervals[def]->flags |= ZREG_LOAD;
3384 						if ((intervals[def]->flags & ZREG_LAST_USE)
3385 						 && ssa->vars[def].use_chain >= 0
3386 						 && ssa->vars[def].use_chain == intervals[def]->range.end) {
3387 							/* remove interval used once */
3388 							intervals[def] = NULL;
3389 							count--;
3390 						}
3391 					} else if (intervals[def]->reg != intervals[use]->reg) {
3392 						intervals[def]->flags |= ZREG_LOAD;
3393 						if (ssa->vars[use].use_chain >= 0) {
3394 							intervals[use]->flags |= ZREG_STORE;
3395 						} else {
3396 							intervals[use] = NULL;
3397 							count--;
3398 						}
3399 					} else {
3400 						use = phi->sources[0];
3401 						ZEND_ASSERT(!intervals[use]);
3402 						intervals[use] = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval));
3403 						intervals[use]->ssa_var = phi->sources[0];
3404 						intervals[use]->reg = intervals[def]->reg;
3405 						intervals[use]->flags = ZREG_LOAD;
3406 						intervals[use]->range.start = 0;
3407 						intervals[use]->range.end = 0;
3408 						intervals[use]->range.next = NULL;
3409 						intervals[use]->hint = NULL;
3410 						intervals[use]->used_as_hint = NULL;
3411 						intervals[use]->list_next = NULL;
3412 					}
3413 				} else if (intervals[use]
3414 						&& (!ssa->vars[def].no_val
3415 							|| ssa->var_info[def].type != ssa->var_info[use].type)) {
3416 					if (ssa->vars[use].use_chain >= 0) {
3417 						intervals[use]->flags |= ZREG_STORE;
3418 					} else {
3419 						intervals[use] = NULL;
3420 						count--;
3421 					}
3422 				}
3423 				phi = phi->next;
3424 			}
3425 		} else {
3426 			for (i = 0; i < ssa->vars_count; i++) {
3427 				if (intervals[i]
3428 				 && intervals[i]->range.end == last_idx
3429 				 && !(intervals[i]->flags & (ZREG_LOAD|ZREG_STORE))) {
3430 					intervals[i]->flags |= ZREG_STORE;
3431 				}
3432 			}
3433 		}
3434 
3435 		if (!count) {
3436 			zend_arena_release(&CG(arena), checkpoint);
3437 			return NULL;
3438 		}
3439 
3440 		if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
3441 			fprintf(stderr, "---- TRACE %d Allocated Live Ranges\n", ZEND_JIT_TRACE_NUM);
3442 			for (i = 0; i < ssa->vars_count; i++) {
3443 				ival = intervals[i];
3444 				while (ival) {
3445 					zend_jit_dump_lifetime_interval(vars_op_array[ival->ssa_var], ssa, ival);
3446 					ival = ival->list_next;
3447 				}
3448 			}
3449 		}
3450 
3451 		return intervals;
3452 	}
3453 
3454 	zend_arena_release(&CG(arena), checkpoint); //???
3455 	return NULL;
3456 }
3457 
zend_jit_trace_clenup_stack(zend_jit_trace_stack * stack,const zend_op * opline,const zend_ssa_op * ssa_op,const zend_ssa * ssa,zend_lifetime_interval ** ra)3458 static void zend_jit_trace_clenup_stack(zend_jit_trace_stack *stack, const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, zend_lifetime_interval **ra)
3459 {
3460 	uint32_t line = ssa_op - ssa->ops;
3461 
3462 	if (ssa_op->op1_use >= 0
3463 	 && ra[ssa_op->op1_use]
3464 	 && ra[ssa_op->op1_use]->range.end == line) {
3465 		SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
3466 	}
3467 	if (ssa_op->op2_use >= 0
3468 	 && ra[ssa_op->op2_use]
3469 	 && ra[ssa_op->op2_use]->range.end == line) {
3470 		SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op2.var), ZREG_NONE);
3471 	}
3472 	if (ssa_op->result_use >= 0
3473 	 && ra[ssa_op->result_use]
3474 	 && ra[ssa_op->result_use]->range.end == line) {
3475 		SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE);
3476 	}
3477 }
3478 
zend_jit_trace_setup_ret_counter(const zend_op * opline,size_t offset)3479 static void zend_jit_trace_setup_ret_counter(const zend_op *opline, size_t offset)
3480 {
3481 	zend_op *next_opline = (zend_op*)(opline + 1);
3482 
3483 	if (JIT_G(hot_return) && !ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags) {
3484 		ZEND_ASSERT(zend_jit_ret_trace_counter_handler != NULL);
3485 		if (!ZEND_OP_TRACE_INFO(next_opline, offset)->counter) {
3486 			ZEND_OP_TRACE_INFO(next_opline, offset)->counter =
3487 				&zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
3488 			ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
3489 		}
3490 		ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags = ZEND_JIT_TRACE_START_RETURN;
3491 		next_opline->handler = (const void*)zend_jit_ret_trace_counter_handler;
3492 	}
3493 }
3494 
zend_jit_may_delay_fetch_this(const zend_op_array * op_array,zend_ssa * ssa,const zend_op ** ssa_opcodes,const zend_ssa_op * ssa_op)3495 static bool zend_jit_may_delay_fetch_this(const zend_op_array *op_array, zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_ssa_op *ssa_op)
3496 {
3497 	int var = ssa_op->result_def;
3498 	int i;
3499 	int use = ssa->vars[var].use_chain;
3500 	const zend_op *opline;
3501 
3502 	if (use < 0
3503 	 || ssa->vars[var].phi_use_chain
3504 	 || ssa->ops[use].op1_use != var
3505 	 || ssa->ops[use].op1_use_chain != -1) {
3506 		return 0;
3507 	}
3508 
3509 	opline = ssa_opcodes[use];
3510 	if (opline->opcode == ZEND_INIT_METHOD_CALL) {
3511 		return (opline->op2_type == IS_CONST &&
3512 			Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING);
3513 	} else if (opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
3514 		if (!JIT_G(current_frame)
3515 		 || !JIT_G(current_frame)->call
3516 		 || !JIT_G(current_frame)->call->func
3517 		 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
3518 			return 0;
3519 		}
3520 	} else if (opline->opcode != ZEND_FETCH_OBJ_R
3521 			&& opline->opcode != ZEND_FETCH_OBJ_IS
3522 			&& opline->opcode != ZEND_FETCH_OBJ_W
3523 			&& opline->opcode != ZEND_ASSIGN_OBJ
3524 			&& opline->opcode != ZEND_ASSIGN_OBJ_OP
3525 			&& opline->opcode != ZEND_PRE_INC_OBJ
3526 			&& opline->opcode != ZEND_PRE_DEC_OBJ
3527 			&& opline->opcode != ZEND_POST_INC_OBJ
3528 			&& opline->opcode != ZEND_POST_DEC_OBJ) {
3529 		return 0;
3530 	}
3531 
3532 	if (opline->op2_type != IS_CONST
3533 	 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3534 	 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3535 		return 0;
3536 	}
3537 
3538 	if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
3539 		if (opline->op1_type == IS_CV
3540 		 && (opline+1)->op1_type == IS_CV
3541 		 && (opline+1)->op1.var == opline->op1.var) {
3542 			/* skip $a->prop += $a; */
3543 			return 0;
3544 		}
3545 		if (!zend_jit_supported_binary_op(
3546 				opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
3547 			return 0;
3548 		}
3549 	}
3550 
3551 	for (i = ssa->vars[var].definition; i < use; i++) {
3552 		if (ssa_opcodes[i]->opcode == ZEND_DO_UCALL
3553 		 || ssa_opcodes[i]->opcode == ZEND_DO_FCALL_BY_NAME
3554 		 || ssa_opcodes[i]->opcode == ZEND_DO_FCALL
3555 		 || ssa_opcodes[i]->opcode == ZEND_INCLUDE_OR_EVAL) {
3556 			return 0;
3557 		}
3558 	}
3559 
3560 	return 1;
3561 }
3562 
zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack * stack,uint32_t stack_size)3563 static int zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack *stack, uint32_t stack_size)
3564 {
3565 	uint32_t i;
3566 
3567 	for (i = 0; i < stack_size; i++) {
3568 		if (STACK_REG(stack, i) != ZREG_NONE
3569 		 && !(STACK_FLAGS(stack, i) & (ZREG_LOAD|ZREG_STORE))) {
3570 			return 1;
3571 		}
3572 	}
3573 	return 0;
3574 }
3575 
zend_jit_trace_exit_needs_deoptimization(uint32_t trace_num,uint32_t exit_num)3576 static int zend_jit_trace_exit_needs_deoptimization(uint32_t trace_num, uint32_t exit_num)
3577 {
3578 	const zend_op *opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
3579 	uint32_t flags = zend_jit_traces[trace_num].exit_info[exit_num].flags;
3580 	uint32_t stack_size;
3581 	zend_jit_trace_stack *stack;
3582 
3583 	if (opline || (flags & (ZEND_JIT_EXIT_RESTORE_CALL|ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2))) {
3584 		return 1;
3585 	}
3586 
3587 	stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
3588 	stack = zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset;
3589 	return zend_jit_trace_stack_needs_deoptimization(stack, stack_size);
3590 }
3591 
zend_jit_trace_deoptimization(dasm_State ** Dst,uint32_t flags,const zend_op * opline,zend_jit_trace_stack * parent_stack,int parent_vars_count,zend_ssa * ssa,zend_jit_trace_stack * stack,zend_lifetime_interval ** ra,bool polymorphic_side_trace)3592 static int zend_jit_trace_deoptimization(dasm_State             **Dst,
3593                                          uint32_t                 flags,
3594                                          const zend_op           *opline,
3595                                          zend_jit_trace_stack    *parent_stack,
3596                                          int                      parent_vars_count,
3597                                          zend_ssa                *ssa,
3598                                          zend_jit_trace_stack    *stack,
3599                                          zend_lifetime_interval **ra,
3600                                          bool                polymorphic_side_trace)
3601 {
3602 	int i;
3603 	bool has_constants = 0;
3604 	bool has_unsaved_vars = 0;
3605 
3606 	// TODO: Merge this loop with the following register LOAD loop to implement parallel move ???
3607 	for (i = 0; i < parent_vars_count; i++) {
3608 		int8_t reg = STACK_REG(parent_stack, i);
3609 
3610 		if (reg != ZREG_NONE) {
3611 			if (reg < ZREG_NUM) {
3612 				if (ssa && ssa->vars[i].no_val) {
3613 					/* pass */
3614 				} else if (ra && ra[i] && ra[i]->reg == reg) {
3615 					/* register already loaded by parent trace */
3616 					if (stack) {
3617 						SET_STACK_REG_EX(stack, i, reg, STACK_FLAGS(parent_stack, i));
3618 					}
3619 					has_unsaved_vars = 1;
3620 				} else {
3621 					uint8_t type = STACK_TYPE(parent_stack, i);
3622 
3623 					if (!(STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE))
3624 					 && !zend_jit_store_var(Dst, 1 << type, i, reg,
3625 							STACK_MEM_TYPE(parent_stack, i) != type)) {
3626 						return 0;
3627 					}
3628 					if (stack) {
3629 						SET_STACK_TYPE(stack, i, type, 1);
3630 					}
3631 				}
3632 			} else {
3633 				/* delay custom deoptimization instructions to prevent register clobbering */
3634 				has_constants = 1;
3635 			}
3636 		}
3637 	}
3638 
3639 	if (has_unsaved_vars
3640 	 && (has_constants
3641 	  || (flags & (ZEND_JIT_EXIT_RESTORE_CALL|ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)))) {
3642 		for (i = 0; i < parent_vars_count; i++) {
3643 			int8_t reg = STACK_REG(parent_stack, i);
3644 
3645 			if (reg != ZREG_NONE) {
3646 				if (reg < ZREG_NUM) {
3647 					if (ssa && ssa->vars[i].no_val) {
3648 						/* pass */
3649 					} else if (ra && ra[i] && ra[i]->reg == reg) {
3650 						uint8_t type = STACK_TYPE(parent_stack, i);
3651 
3652 					    if (stack) {
3653 							SET_STACK_TYPE(stack, i, type, 1);
3654 						}
3655 						if (!(STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE))
3656 						 && !zend_jit_store_var(Dst, 1 << type, i, reg,
3657 								STACK_MEM_TYPE(parent_stack, i) != type)) {
3658 							return 0;
3659 						}
3660 					}
3661 				}
3662 			}
3663 		}
3664 	}
3665 
3666 	if (has_constants) {
3667 		for (i = 0; i < parent_vars_count; i++) {
3668 			int8_t reg = STACK_REG(parent_stack, i);
3669 
3670 			if (reg != ZREG_NONE) {
3671 				if (reg < ZREG_NUM) {
3672 					/* pass */
3673 				} else if (reg == ZREG_THIS) {
3674 					if (polymorphic_side_trace) {
3675 						ssa->var_info[i].delayed_fetch_this = 1;
3676 						if (stack) {
3677 							SET_STACK_REG(stack, i, ZREG_THIS);
3678 						}
3679 					} else if (!zend_jit_load_this(Dst, EX_NUM_TO_VAR(i))) {
3680 						return 0;
3681 					}
3682 				} else {
3683 					if (reg == ZREG_ZVAL_COPY_GPR0
3684 					 &&!zend_jit_escape_if_undef_r0(Dst, i, flags, opline)) {
3685 						return 0;
3686 					}
3687 					if (!zend_jit_store_const(Dst, i, reg)) {
3688 						return 0;
3689 					}
3690 				}
3691 			}
3692 		}
3693 	}
3694 
3695 	if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
3696 		if (!zend_jit_save_call_chain(Dst, -1)) {
3697 			return 0;
3698 		}
3699 	}
3700 
3701 	if (flags & ZEND_JIT_EXIT_FREE_OP2) {
3702 		const zend_op *op = opline - 1;
3703 
3704 		if (!zend_jit_free_op(Dst, op, -1, op->op2.var)) {
3705 			return 0;
3706 		}
3707 	}
3708 
3709 	if (flags & ZEND_JIT_EXIT_FREE_OP1) {
3710 		const zend_op *op = opline - 1;
3711 
3712 		if (!zend_jit_free_op(Dst, op, -1, op->op1.var)) {
3713 			return 0;
3714 		}
3715 	}
3716 
3717 	if (flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) {
3718 		if (!zend_jit_check_exception(Dst)) {
3719 			return 0;
3720 		}
3721 	}
3722 
3723 	if ((flags & ZEND_JIT_EXIT_METHOD_CALL) && !polymorphic_side_trace) {
3724 		if (!zend_jit_free_trampoline(Dst)) {
3725 			return 0;
3726 		}
3727 	}
3728 
3729 	return 1;
3730 }
3731 
zend_jit_trace_set_var_range(zend_ssa_var_info * info,zend_long min,zend_long max)3732 static void zend_jit_trace_set_var_range(zend_ssa_var_info *info, zend_long min, zend_long max)
3733 {
3734 	info->has_range = 1;
3735 	info->range.min = min;
3736 	info->range.max = max;
3737 	info->range.underflow = 0;
3738 	info->range.overflow = 0;
3739 }
3740 
zend_jit_trace_update_condition_ranges(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,zend_ssa * ssa,bool exit_if_true)3741 static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, bool exit_if_true)
3742 {
3743 	zend_long op1_min, op1_max, op2_min, op2_max;
3744 
3745 	if ((OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG
3746 	 || (OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG) {
3747 		return;
3748 	}
3749 
3750 	op1_min = OP1_MIN_RANGE();
3751 	op1_max = OP1_MAX_RANGE();
3752 	op2_min = OP2_MIN_RANGE();
3753 	op2_max = OP2_MAX_RANGE();
3754 
3755 	switch (opline->opcode) {
3756 		case ZEND_IS_EQUAL:
3757 		case ZEND_CASE:
3758 		case ZEND_IS_IDENTICAL:
3759 		case ZEND_CASE_STRICT:
3760 		case ZEND_IS_NOT_IDENTICAL:
3761 			if (!exit_if_true) {
3762 				/* op1 == op2 */
3763 				if (ssa_op->op1_use >= 0) {
3764 					zend_jit_trace_set_var_range(
3765 						&ssa->var_info[ssa_op->op1_use],
3766 						MAX(op1_min, op2_min),
3767 						MIN(op1_max, op2_max));
3768 				}
3769 				if (ssa_op->op2_use >= 0) {
3770 					zend_jit_trace_set_var_range(
3771 						&ssa->var_info[ssa_op->op2_use],
3772 						MAX(op2_min, op1_min),
3773 						MIN(op2_max, op1_max));
3774 				}
3775 			}
3776 			break;
3777 		case ZEND_IS_NOT_EQUAL:
3778 			if (exit_if_true) {
3779 				/* op1 == op2 */
3780 				if (ssa_op->op1_use >= 0) {
3781 					zend_jit_trace_set_var_range(
3782 						&ssa->var_info[ssa_op->op1_use],
3783 						MAX(op1_min, op2_min),
3784 						MIN(op1_max, op2_max));
3785 				}
3786 				if (ssa_op->op2_use >= 0) {
3787 					zend_jit_trace_set_var_range(
3788 						&ssa->var_info[ssa_op->op2_use],
3789 						MAX(op2_min, op1_min),
3790 						MIN(op2_max, op1_max));
3791 				}
3792 			}
3793 			break;
3794 		case ZEND_IS_SMALLER_OR_EQUAL:
3795 			if (!exit_if_true) {
3796 				/* op1 <= op2 */
3797 				if (ssa_op->op1_use >= 0) {
3798 					zend_jit_trace_set_var_range(
3799 						&ssa->var_info[ssa_op->op1_use],
3800 						op1_min,
3801 						MIN(op1_max, op2_max));
3802 				}
3803 				if (ssa_op->op2_use >= 0) {
3804 					zend_jit_trace_set_var_range(
3805 						&ssa->var_info[ssa_op->op2_use],
3806 						MAX(op2_min, op1_min),
3807 						op2_max);
3808 				}
3809 			} else {
3810 				/* op1 > op2 */
3811 				if (ssa_op->op1_use >= 0) {
3812 					zend_jit_trace_set_var_range(
3813 						&ssa->var_info[ssa_op->op1_use],
3814 						op2_min != ZEND_LONG_MAX ? MAX(op1_min, op2_min + 1) : op1_min,
3815 						op1_max);
3816 				}
3817 				if (ssa_op->op2_use >= 0) {
3818 					zend_jit_trace_set_var_range(
3819 						&ssa->var_info[ssa_op->op2_use],
3820 						op2_min,
3821 						op2_max != ZEND_LONG_MIN ?MIN(op2_max, op1_max - 1) : op1_max);
3822 				}
3823 			}
3824 			break;
3825 		case ZEND_IS_SMALLER:
3826 			if (!exit_if_true) {
3827 				/* op1 < op2 */
3828 				if (ssa_op->op1_use >= 0) {
3829 					zend_jit_trace_set_var_range(
3830 						&ssa->var_info[ssa_op->op1_use],
3831 						op1_min,
3832 						op2_max != ZEND_LONG_MIN ? MIN(op1_max, op2_max - 1) : op1_max);
3833 				}
3834 				if (ssa_op->op2_use >= 0) {
3835 					zend_jit_trace_set_var_range(
3836 						&ssa->var_info[ssa_op->op2_use],
3837 						op1_min != ZEND_LONG_MAX ? MAX(op2_min, op1_min + 1) : op2_min,
3838 						op2_max);
3839 				}
3840 			} else {
3841 				/* op1 >= op2 */
3842 				if (ssa_op->op1_use >= 0) {
3843 					zend_jit_trace_set_var_range(
3844 						&ssa->var_info[ssa_op->op1_use],
3845 						MAX(op1_min, op2_min),
3846 						op1_max);
3847 				}
3848 				if (ssa_op->op2_use >= 0) {
3849 					zend_jit_trace_set_var_range(
3850 						&ssa->var_info[ssa_op->op2_use],
3851 						op2_min,
3852 						MIN(op2_max, op1_max));
3853 				}
3854 			}
3855 			break;
3856 	}
3857 }
3858 
zend_jit_may_skip_comparison(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_ssa * ssa,const zend_op ** ssa_opcodes,const zend_op_array * op_array)3859 static bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array)
3860 {
3861 	zend_uchar prev_opcode;
3862 
3863 	if (opline->op1_type == IS_CONST
3864 	 && Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
3865 	 && Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
3866 		if (ssa_op->op2_use >= 0) {
3867 			if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
3868 				ssa_op--;
3869 				opline = ssa_opcodes[ssa_op - ssa->ops];
3870 				prev_opcode = opline->opcode;
3871 				if (prev_opcode == ZEND_PRE_INC
3872 				 || prev_opcode == ZEND_PRE_DEC
3873 				 || prev_opcode == ZEND_POST_INC
3874 				 || prev_opcode == ZEND_POST_DEC) {
3875 					return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3876 				}
3877 			} else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
3878 				ssa_op--;
3879 				opline = ssa_opcodes[ssa_op - ssa->ops];
3880 				prev_opcode = opline->opcode;
3881 				if (prev_opcode == ZEND_ADD
3882 				 || prev_opcode == ZEND_SUB) {
3883 					return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0 &&
3884 						(OP2_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3885 				}
3886 			}
3887 		}
3888 	} else if (opline->op2_type == IS_CONST
3889 	 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
3890 	 && Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
3891 		if (ssa_op->op1_use >= 0) {
3892 			if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
3893 				ssa_op--;
3894 				opline = ssa_opcodes[ssa_op - ssa->ops];
3895 				prev_opcode = opline->opcode;
3896 				if (prev_opcode == ZEND_PRE_INC
3897 				 || prev_opcode == ZEND_PRE_DEC
3898 				 || prev_opcode == ZEND_POST_INC
3899 				 || prev_opcode == ZEND_POST_DEC) {
3900 					return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3901 				}
3902 			} else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
3903 				ssa_op--;
3904 				opline = ssa_opcodes[ssa_op - ssa->ops];
3905 				prev_opcode = opline->opcode;
3906 				if (prev_opcode == ZEND_ADD
3907 				 || prev_opcode == ZEND_SUB) {
3908 					return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0 &&
3909 						(OP2_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3910 				}
3911 			}
3912 		}
3913 	} else {
3914 		const zend_ssa_op *prev_ssa_op = ssa_op - 1;
3915 		prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3916 
3917 		if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
3918 		 && prev_ssa_op != ssa->ops
3919 		 && prev_ssa_op->op1_use >= 0
3920 		 && prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
3921 			prev_ssa_op--;
3922 			prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3923 		}
3924 
3925 		if (ssa_op->op1_use == prev_ssa_op->op1_use
3926 		 && ssa_op->op2_use == prev_ssa_op->op2_use) {
3927 			if (prev_opcode == ZEND_IS_EQUAL
3928 			 || prev_opcode == ZEND_IS_NOT_EQUAL
3929 			 || prev_opcode == ZEND_IS_SMALLER
3930 			 || prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
3931 			 || prev_opcode == ZEND_CASE
3932 			 || prev_opcode == ZEND_IS_IDENTICAL
3933 			 || prev_opcode == ZEND_IS_NOT_IDENTICAL
3934 			 || prev_opcode == ZEND_CASE_STRICT) {
3935 				if (ssa_op->op1_use < 0) {
3936 					if (RT_CONSTANT(opline, opline->op1) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op1)) {
3937 						return 0;
3938 					}
3939 				}
3940 				if (ssa_op->op2_use < 0) {
3941 					if (RT_CONSTANT(opline, opline->op2) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op2)) {
3942 						return 0;
3943 					}
3944 				}
3945 				return 1;
3946 			}
3947 		}
3948 	}
3949 	return 0;
3950 }
3951 
zend_jit_trace_next_is_send_result(const zend_op * opline,zend_jit_trace_rec * p,zend_jit_trace_stack_frame * frame)3952 static bool zend_jit_trace_next_is_send_result(const zend_op              *opline,
3953                                                zend_jit_trace_rec         *p,
3954                                                zend_jit_trace_stack_frame *frame)
3955 {
3956 	if (opline->result_type == IS_TMP_VAR
3957 	 && (p+1)->op == ZEND_JIT_TRACE_VM
3958 	 && (p+1)->opline == opline + 1
3959 	 && ((opline+1)->opcode == ZEND_SEND_VAL
3960 	  || ((opline+1)->opcode == ZEND_SEND_VAL_EX
3961 	   && frame
3962 	   && frame->call
3963 	   && frame->call->func
3964 	   && !ARG_MUST_BE_SENT_BY_REF(frame->call->func, (opline+1)->op2.num)))
3965 	 && (opline+1)->op1_type == IS_TMP_VAR
3966 	 && (opline+1)->op2_type != IS_CONST /* Named parameters not supported in JIT */
3967 	 && (opline+1)->op1.var == opline->result.var) {
3968 
3969 		if (frame->call && frame->call->func) {
3970 			uint8_t res_type = (p+1)->op1_type;
3971 
3972 			if (res_type != IS_UNKNOWN && !(res_type & IS_TRACE_REFERENCE) ) {
3973 				zend_jit_trace_send_type(opline+1, frame->call, res_type);
3974 			}
3975 		}
3976 		return 1;
3977 	}
3978 	return 0;
3979 }
3980 
zend_jit_trace(zend_jit_trace_rec * trace_buffer,uint32_t parent_trace,uint32_t exit_num)3981 static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
3982 {
3983 	const void *handler = NULL;
3984 	dasm_State* dasm_state = NULL;
3985 	zend_script *script = NULL;
3986 	zend_lifetime_interval **ra = NULL;
3987 	zend_string *name = NULL;
3988 	void *checkpoint;
3989 	const zend_op_array *op_array;
3990 	zend_ssa *ssa, *op_array_ssa;
3991 	const zend_op **ssa_opcodes;
3992 	zend_jit_trace_rec *p;
3993 	zend_jit_op_array_trace_extension *jit_extension;
3994 	int num_op_arrays = 0;
3995 	zend_jit_trace_info *t;
3996 	const zend_op_array *op_arrays[ZEND_JIT_TRACE_MAX_FUNCS];
3997 	zend_uchar smart_branch_opcode;
3998 	const void *exit_addr;
3999 	uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
4000 	bool send_result = 0;
4001 	bool skip_comparison;
4002 	zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
4003 	zend_class_entry *ce;
4004 	bool ce_is_instanceof;
4005 	bool on_this = 0;
4006 	bool delayed_fetch_this = 0;
4007 	bool avoid_refcounting = 0;
4008 	bool polymorphic_side_trace =
4009 		parent_trace &&
4010 		(zend_jit_traces[parent_trace].exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL);
4011 	uint32_t i;
4012 	zend_jit_trace_stack_frame *frame, *top, *call;
4013 	zend_jit_trace_stack *stack;
4014 	zend_uchar res_type = IS_UNKNOWN;
4015 	const zend_op *opline, *orig_opline;
4016 	const zend_ssa_op *ssa_op, *orig_ssa_op;
4017 	int checked_stack;
4018 	int peek_checked_stack;
4019 	uint32_t frame_flags = 0;
4020 
4021 	JIT_G(current_trace) = trace_buffer;
4022 
4023 	checkpoint = zend_arena_checkpoint(CG(arena));
4024 
4025 	ssa = zend_jit_trace_build_tssa(trace_buffer, parent_trace, exit_num, script, op_arrays, &num_op_arrays);
4026 
4027 	if (!ssa) {
4028 		goto jit_cleanup;
4029 	}
4030 
4031 	ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
4032 
4033 	/* Register allocation */
4034 	if ((JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL))
4035 	 && JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4036 		ra = zend_jit_trace_allocate_registers(trace_buffer, ssa, parent_trace, exit_num);
4037 	}
4038 
4039 	p = trace_buffer;
4040 	ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
4041 	op_array = p->op_array;
4042 	frame = JIT_G(current_frame);
4043 	top = zend_jit_trace_call_frame(frame, op_array);
4044 	TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
4045 	frame->used_stack = checked_stack = peek_checked_stack = 0;
4046 	stack = frame->stack;
4047 	for (i = 0; i < op_array->last_var + op_array->T; i++) {
4048 		SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
4049 	}
4050 
4051 	opline = p[1].opline;
4052 	name = zend_jit_trace_name(op_array, opline->lineno);
4053 	p += ZEND_JIT_TRACE_START_REC_SIZE;
4054 
4055 	dasm_init(&dasm_state, DASM_MAXSECTION);
4056 	dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
4057 	dasm_setup(&dasm_state, dasm_actions);
4058 
4059 	jit_extension =
4060 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
4061 	op_array_ssa = &jit_extension->func_info.ssa;
4062 
4063 	dasm_growpc(&dasm_state, 2); /* =>0: loop header */
4064 	                             /* =>1: end of code */
4065 
4066 	zend_jit_align_func(&dasm_state);
4067 	if (!parent_trace) {
4068 		zend_jit_prologue(&dasm_state);
4069 	}
4070 	zend_jit_trace_begin(&dasm_state, ZEND_JIT_TRACE_NUM,
4071 		parent_trace ? &zend_jit_traces[parent_trace] : NULL, exit_num);
4072 
4073 	if (!parent_trace) {
4074 		zend_jit_set_last_valid_opline(opline);
4075 		zend_jit_track_last_valid_opline();
4076 	} else {
4077 		if (zend_jit_traces[parent_trace].exit_info[exit_num].opline == NULL) {
4078 			zend_jit_trace_opline_guard(&dasm_state, opline);
4079 		} else {
4080 			zend_jit_reset_last_valid_opline();
4081 		}
4082 	}
4083 
4084 	if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4085 		int last_var;
4086 		int parent_vars_count = 0;
4087 		zend_jit_trace_stack *parent_stack = NULL;
4088 		int used_stack = ((zend_tssa*)ssa)->used_stack;
4089 
4090 		if (used_stack > 0) {
4091 			peek_checked_stack = used_stack;
4092 			if (!zend_jit_stack_check(&dasm_state, opline, used_stack)) {
4093 				goto jit_failure;
4094 			}
4095 		}
4096 
4097 		if (parent_trace) {
4098 			parent_vars_count = MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
4099 				op_array->last_var + op_array->T);
4100 			if (parent_vars_count) {
4101 				parent_stack =
4102 					zend_jit_traces[parent_trace].stack_map +
4103 					zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
4104 			}
4105 		}
4106 
4107 		last_var = op_array->last_var;
4108 		if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
4109 			last_var += op_array->T;
4110 		}
4111 
4112 		for (i = 0; i < last_var; i++) {
4113 			uint32_t info = ssa->var_info[i].type;
4114 
4115 			if (!(info & MAY_BE_GUARD) && has_concrete_type(info)) {
4116 				uint8_t type, mem_type;
4117 
4118 				type = concrete_type(info);
4119 				if (i < parent_vars_count
4120 				 && STACK_TYPE(parent_stack, i) == type) {
4121 					mem_type = STACK_MEM_TYPE(parent_stack, i);
4122 					if (mem_type != IS_UNKNOWN) {
4123 						SET_STACK_TYPE(stack, i, mem_type, 1);
4124 					}
4125 					SET_STACK_TYPE(stack, i, type, 0);
4126 				} else {
4127 					SET_STACK_TYPE(stack, i, type, 1);
4128 				}
4129 			} else if (ssa->vars[i].alias != NO_ALIAS) {
4130 				SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
4131 			} else if (i < parent_vars_count
4132 			 && STACK_TYPE(parent_stack, i) != IS_UNKNOWN) {
4133 				/* This must be already handled by trace type inference */
4134 				ZEND_UNREACHABLE();
4135 				// SET_STACK_TYPE(stack, i, STACK_TYPE(parent_stack, i));
4136 			} else if ((info & MAY_BE_GUARD) != 0
4137 			 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4138 			  || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4139 			  || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
4140 			   && (opline-1)->result_type == IS_VAR
4141 			   && EX_VAR_TO_NUM((opline-1)->result.var) == i))
4142 			 && (ssa->vars[i].use_chain != -1
4143 			  || (ssa->vars[i].phi_use_chain
4144 			   && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_GUARD)))) {
4145 				/* Check loop-invariant variable type */
4146 				if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), concrete_type(info))) {
4147 					goto jit_failure;
4148 				}
4149 				info &= ~MAY_BE_GUARD;
4150 				ssa->var_info[i].type = info;
4151 				SET_STACK_TYPE(stack, i, concrete_type(info), 1);
4152 			} else if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER
4153 			 && op_array->function_name
4154 			 && i >= op_array->num_args) {
4155 				/* This must be already handled by trace type inference */
4156 				ZEND_UNREACHABLE();
4157 				// SET_STACK_TYPE(stack, i, IS_UNDEF, 1);
4158 			}
4159 
4160 			if ((info & MAY_BE_PACKED_GUARD) != 0
4161 			 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4162 			  || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4163 			  || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)
4164 			 && (ssa->vars[i].use_chain != -1
4165 			  || (ssa->vars[i].phi_use_chain
4166 			   && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_PACKED_GUARD)))) {
4167 				if (!zend_jit_packed_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), info)) {
4168 					goto jit_failure;
4169 				}
4170 				info &= ~MAY_BE_PACKED_GUARD;
4171 				ssa->var_info[i].type = info;
4172 			}
4173 		}
4174 
4175 		if (parent_trace) {
4176 			/* Deoptimization */
4177 			if (!zend_jit_trace_deoptimization(&dasm_state,
4178 					zend_jit_traces[parent_trace].exit_info[exit_num].flags,
4179 					zend_jit_traces[parent_trace].exit_info[exit_num].opline,
4180 					parent_stack, parent_vars_count, ssa, stack, ra,
4181 					polymorphic_side_trace)) {
4182 				goto jit_failure;
4183 			}
4184 		}
4185 
4186 		if (ra
4187 		 && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4188 		 && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4189 			for (i = 0; i < last_var; i++) {
4190 				if (ra[i]
4191 				 && (ra[i]->flags & ZREG_LOAD) != 0
4192 				 && ra[i]->reg != stack[i].reg) {
4193 
4194 					if ((ssa->var_info[i].type & MAY_BE_GUARD) != 0) {
4195 						uint8_t op_type;
4196 
4197 						ssa->var_info[i].type &= ~MAY_BE_GUARD;
4198 						op_type = concrete_type(ssa->var_info[i].type);
4199 						if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), op_type)) {
4200 							goto jit_failure;
4201 						}
4202 						SET_STACK_TYPE(stack, i, op_type, 1);
4203 					}
4204 
4205 					SET_STACK_REG_EX(stack, i, ra[i]->reg, ZREG_LOAD);
4206 					if (!zend_jit_load_var(&dasm_state, ssa->var_info[i].type, i, ra[i]->reg)) {
4207 						goto jit_failure;
4208 					}
4209 				}
4210 			}
4211 		}
4212 	}
4213 
4214 	if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4215 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4216 	 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4217 
4218 		zend_jit_label(&dasm_state, 0); /* start of of trace loop */
4219 
4220 		if (ra) {
4221 			zend_ssa_phi *phi = ssa->blocks[1].phis;
4222 
4223 			while (phi) {
4224 				zend_lifetime_interval *ival = ra[phi->ssa_var];
4225 
4226 				if (ival) {
4227 					if (ival->flags & ZREG_LOAD) {
4228 						uint32_t info = ssa->var_info[phi->ssa_var].type;
4229 						ZEND_ASSERT(ival->reg != ZREG_NONE);
4230 
4231 						if (info & MAY_BE_GUARD) {
4232 							if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(phi->var), concrete_type(info))) {
4233 								goto jit_failure;
4234 							}
4235 							info &= ~MAY_BE_GUARD;
4236 							ssa->var_info[phi->ssa_var].type = info;
4237 							SET_STACK_TYPE(stack, phi->var, concrete_type(info), 1);
4238 						}
4239 						SET_STACK_REG_EX(stack, phi->var, ival->reg, ZREG_LOAD);
4240 						if (!zend_jit_load_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg)) {
4241 							goto jit_failure;
4242 						}
4243 					} else if (ival->flags & ZREG_STORE) {
4244 						ZEND_ASSERT(ival->reg != ZREG_NONE);
4245 
4246 						SET_STACK_REG_EX(stack, phi->var, ival->reg, ZREG_STORE);
4247 						if (!zend_jit_store_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg,
4248 								STACK_MEM_TYPE(stack, phi->var) != ssa->var_info[phi->ssa_var].type)) {
4249 							goto jit_failure;
4250 						}
4251 					} else {
4252 						/* Register has to be written back on side exit */
4253 						SET_STACK_REG(stack, phi->var, ival->reg);
4254 					}
4255 				}
4256 				phi = phi->next;
4257 			}
4258 		}
4259 
4260 //		if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4261 //			if (ra && zend_jit_trace_stack_needs_deoptimization(stack, op_array->last_var + op_array->T)) {
4262 //				uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
4263 //
4264 //				timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4265 //				if (!timeout_exit_addr) {
4266 //					goto jit_failure;
4267 //				}
4268 //			}
4269 //		}
4270 
4271 		if (ra && trace_buffer->stop != ZEND_JIT_TRACE_STOP_LOOP) {
4272 			int last_var = op_array->last_var;
4273 
4274 			if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
4275 				last_var += op_array->T;
4276 			}
4277 			for (i = 0; i < last_var; i++) {
4278 				if (ra && ra[i] && (ra[i]->flags & ZREG_LOAD) != 0) {
4279 					SET_STACK_REG_EX(stack, i, ra[i]->reg, ZREG_LOAD);
4280 					if (!zend_jit_load_var(&dasm_state, ssa->var_info[i].type, i, ra[i]->reg)) {
4281 						goto jit_failure;
4282 					}
4283 				}
4284 			}
4285 		}
4286 	}
4287 
4288 	ssa_op = (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) ? ssa->ops : NULL;
4289 	for (;;p++) {
4290 		if (p->op == ZEND_JIT_TRACE_VM) {
4291 			uint8_t op1_type = p->op1_type;
4292 			uint8_t op2_type = p->op2_type;
4293 			uint8_t op3_type = p->op3_type;
4294 			uint8_t orig_op1_type = op1_type;
4295 			uint8_t orig_op2_type = op2_type;
4296 			uint8_t val_type = IS_UNKNOWN;
4297 			bool op1_indirect;
4298 			zend_class_entry *op1_ce = NULL;
4299 			zend_class_entry *op2_ce = NULL;
4300 			bool gen_handler;
4301 
4302 			opline = p->opline;
4303 			if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4304 				op1_type = IS_UNKNOWN;
4305 			}
4306 			if (op1_type != IS_UNKNOWN) {
4307 				op1_type &= ~IS_TRACE_PACKED;
4308 			}
4309 			if (op2_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4310 				op2_type = IS_UNKNOWN;
4311 			}
4312 			if (op3_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4313 				op3_type = IS_UNKNOWN;
4314 			}
4315 
4316 			if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
4317 				op1_ce = (zend_class_entry*)(p+1)->ce;
4318 				p++;
4319 			}
4320 			if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
4321 				op2_ce = (zend_class_entry*)(p+1)->ce;
4322 				p++;
4323 			}
4324 			if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
4325 				val_type = (p+1)->op1_type;
4326 				p++;
4327 			}
4328 
4329 			frame_flags = 0;
4330 
4331 			switch (opline->opcode) {
4332 				case ZEND_INIT_FCALL:
4333 				case ZEND_INIT_FCALL_BY_NAME:
4334 				case ZEND_INIT_NS_FCALL_BY_NAME:
4335 				case ZEND_INIT_METHOD_CALL:
4336 				case ZEND_INIT_DYNAMIC_CALL:
4337 				case ZEND_INIT_STATIC_METHOD_CALL:
4338 				case ZEND_INIT_USER_CALL:
4339 				case ZEND_NEW:
4340 					frame->call_level++;
4341 			}
4342 
4343 			if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4344 				gen_handler = 0;
4345 				switch (opline->opcode) {
4346 					case ZEND_PRE_INC:
4347 					case ZEND_PRE_DEC:
4348 					case ZEND_POST_INC:
4349 					case ZEND_POST_DEC:
4350 						if (opline->op1_type != IS_CV) {
4351 							break;
4352 						}
4353 						op1_info = OP1_INFO();
4354 						CHECK_OP1_TRACE_TYPE();
4355 						if (!(op1_info & MAY_BE_LONG)) {
4356 							break;
4357 						}
4358 						if (opline->result_type != IS_UNUSED) {
4359 							res_use_info = zend_jit_trace_type_to_info(
4360 								STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
4361 									& (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4362 							res_info = RES_INFO();
4363 							res_addr = RES_REG_ADDR();
4364 						} else {
4365 							res_use_info = -1;
4366 							res_info = -1;
4367 							res_addr = 0;
4368 						}
4369 						op1_def_info = OP1_DEF_INFO();
4370 						if (op1_def_info & MAY_BE_GUARD
4371 						 && !has_concrete_type(op1_def_info)) {
4372 							op1_def_info &= ~MAY_BE_GUARD;
4373 						}
4374 						if (!zend_jit_inc_dec(&dasm_state, opline,
4375 								op1_info, OP1_REG_ADDR(),
4376 								op1_def_info, OP1_DEF_REG_ADDR(),
4377 								res_use_info, res_info,
4378 								res_addr,
4379 								(op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4380 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
4381 							goto jit_failure;
4382 						}
4383 						if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4384 						 && !(op1_info & MAY_BE_STRING)) {
4385 							ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4386 							if (opline->result_type != IS_UNUSED) {
4387 								ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4388 							}
4389 						}
4390 						if (opline->result_type != IS_UNUSED
4391 						 && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4392 						 && !(op1_info & MAY_BE_STRING)) {
4393 							ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4394 						}
4395 						goto done;
4396 					case ZEND_BW_OR:
4397 					case ZEND_BW_AND:
4398 					case ZEND_BW_XOR:
4399 					case ZEND_SL:
4400 					case ZEND_SR:
4401 					case ZEND_MOD:
4402 						op1_info = OP1_INFO();
4403 						CHECK_OP1_TRACE_TYPE();
4404 						op2_info = OP2_INFO();
4405 						CHECK_OP2_TRACE_TYPE();
4406 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4407 							break;
4408 						}
4409 						if (!(op1_info & MAY_BE_LONG)
4410 						 || !(op2_info & MAY_BE_LONG)) {
4411 							break;
4412 						}
4413 						res_addr = RES_REG_ADDR();
4414 						if (Z_MODE(res_addr) != IS_REG
4415 						 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4416 							send_result = 1;
4417 							res_use_info = -1;
4418 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4419 							if (!zend_jit_reuse_ip(&dasm_state)) {
4420 								goto jit_failure;
4421 							}
4422 						} else {
4423 							res_use_info = zend_jit_trace_type_to_info(
4424 								STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
4425 									& (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4426 						}
4427 						res_info = RES_INFO();
4428 						if (!zend_jit_long_math(&dasm_state, opline,
4429 								op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4430 								op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4431 								res_use_info, res_info, res_addr,
4432 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
4433 							goto jit_failure;
4434 						}
4435 						goto done;
4436 					case ZEND_ADD:
4437 					case ZEND_SUB:
4438 					case ZEND_MUL:
4439 //					case ZEND_DIV: // TODO: check for division by zero ???
4440 						op1_info = OP1_INFO();
4441 						op1_addr = OP1_REG_ADDR();
4442 						op2_info = OP2_INFO();
4443 						op2_addr = OP2_REG_ADDR();
4444 						if (orig_op1_type != IS_UNKNOWN
4445 						 && (orig_op1_type & IS_TRACE_REFERENCE)
4446 						 && opline->op1_type == IS_CV
4447 						 && (Z_MODE(op2_addr) != IS_REG || Z_REG(op2_addr) != ZREG_FCARG1)
4448 						 && (orig_op2_type == IS_UNKNOWN || !(orig_op2_type & IS_TRACE_REFERENCE))) {
4449 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4450 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4451 								goto jit_failure;
4452 							}
4453 							if (ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
4454 								ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
4455 							}
4456 						} else {
4457 							CHECK_OP1_TRACE_TYPE();
4458 						}
4459 						if (orig_op2_type != IS_UNKNOWN
4460 						 && (orig_op2_type & IS_TRACE_REFERENCE)
4461 						 && opline->op2_type == IS_CV
4462 						 && (Z_MODE(op1_addr) != IS_REG || Z_REG(op1_addr) != ZREG_FCARG1)
4463 						 && (orig_op1_type == IS_UNKNOWN || !(orig_op1_type & IS_TRACE_REFERENCE))) {
4464 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op2_type, &op2_info, &op2_addr,
4465 									!ssa->var_info[ssa_op->op2_use].guarded_reference, 1)) {
4466 								goto jit_failure;
4467 							}
4468 							if (ssa->vars[ssa_op->op2_use].alias == NO_ALIAS) {
4469 								ssa->var_info[ssa_op->op2_use].guarded_reference = 1;
4470 							}
4471 						} else {
4472 							CHECK_OP2_TRACE_TYPE();
4473 						}
4474 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4475 							break;
4476 						}
4477 						if (opline->opcode == ZEND_ADD &&
4478 						    (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
4479 						    (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
4480 							/* pass */
4481 						} else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
4482 						    !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4483 							break;
4484 						}
4485 						res_addr = RES_REG_ADDR();
4486 						if (Z_MODE(res_addr) != IS_REG
4487 						 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4488 							send_result = 1;
4489 							res_use_info = -1;
4490 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4491 							if (!zend_jit_reuse_ip(&dasm_state)) {
4492 								goto jit_failure;
4493 							}
4494 						} else {
4495 							res_use_info = zend_jit_trace_type_to_info(
4496 								STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
4497 									& (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4498 						}
4499 						res_info = RES_INFO();
4500 						if (opline->opcode == ZEND_ADD &&
4501 						    (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
4502 						    (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
4503 							if (!zend_jit_add_arrays(&dasm_state, opline, op1_info, op1_addr, op2_info, op2_addr, res_addr)) {
4504 								goto jit_failure;
4505 							}
4506 						} else {
4507 							if (!zend_jit_math(&dasm_state, opline,
4508 									op1_info, op1_addr,
4509 									op2_info, op2_addr,
4510 									res_use_info, res_info, res_addr,
4511 									(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4512 									zend_may_throw(opline, ssa_op, op_array, ssa))) {
4513 								goto jit_failure;
4514 							}
4515 							if (((res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4516 							  || (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4517 							 && has_concrete_type(op1_info)
4518 							 && has_concrete_type(op2_info)) {
4519 								ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4520 							}
4521 						}
4522 						goto done;
4523 					case ZEND_CONCAT:
4524 					case ZEND_FAST_CONCAT:
4525 						op1_info = OP1_INFO();
4526 						CHECK_OP1_TRACE_TYPE();
4527 						op2_info = OP2_INFO();
4528 						CHECK_OP2_TRACE_TYPE();
4529 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4530 							break;
4531 						}
4532 						if (!(op1_info & MAY_BE_STRING) ||
4533 						    !(op2_info & MAY_BE_STRING)) {
4534 							break;
4535 						}
4536 						res_addr = RES_REG_ADDR();
4537 						if (zend_jit_trace_next_is_send_result(opline, p, frame)) {
4538 							send_result = 1;
4539 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4540 							if (!zend_jit_reuse_ip(&dasm_state)) {
4541 								goto jit_failure;
4542 							}
4543 						}
4544 						if (!zend_jit_concat(&dasm_state, opline,
4545 								op1_info, op2_info, res_addr,
4546 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
4547 							goto jit_failure;
4548 						}
4549 						goto done;
4550 					case ZEND_ASSIGN_OP:
4551 						if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
4552 							break;
4553 						}
4554 						op1_info = OP1_INFO();
4555 						CHECK_OP1_TRACE_TYPE();
4556 						op2_info = OP2_INFO();
4557 						CHECK_OP2_TRACE_TYPE();
4558 						if (!zend_jit_supported_binary_op(
4559 								opline->extended_value, op1_info, op2_info)) {
4560 							break;
4561 						}
4562 						op1_def_info = OP1_DEF_INFO();
4563 						if (op1_def_info & MAY_BE_GUARD
4564 						 && !has_concrete_type(op1_def_info)) {
4565 							op1_def_info &= ~MAY_BE_GUARD;
4566 						}
4567 						if (!zend_jit_assign_op(&dasm_state, opline,
4568 								op1_info, op1_def_info, OP1_RANGE(),
4569 								op2_info, OP2_RANGE(),
4570 								(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4571 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
4572 							goto jit_failure;
4573 						}
4574 						if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4575 						 && has_concrete_type(op1_info)
4576 						 && has_concrete_type(op2_info)) {
4577 							ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4578 							if (opline->result_type != IS_UNUSED) {
4579 								ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4580 							}
4581 						}
4582 						goto done;
4583 					case ZEND_ASSIGN_DIM_OP:
4584 						if (opline->result_type != IS_UNUSED) {
4585 							break;
4586 						}
4587 						if (!zend_jit_supported_binary_op(
4588 								opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
4589 							break;
4590 						}
4591 						if (opline->op1_type == IS_CV
4592 						 && (opline+1)->op1_type == IS_CV
4593 						 && (opline+1)->op1.var == opline->op1.var) {
4594 							/* skip $a[x] += $a; */
4595 							break;
4596 						}
4597 						op1_info = OP1_INFO();
4598 						op1_addr = OP1_REG_ADDR();
4599 						if (opline->op1_type == IS_VAR) {
4600 							if (orig_op1_type != IS_UNKNOWN
4601 							 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4602 								if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4603 										&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4604 									goto jit_failure;
4605 								}
4606 							} else {
4607 								break;
4608 							}
4609 						}
4610 						if (orig_op1_type != IS_UNKNOWN
4611 						 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4612 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4613 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4614 								goto jit_failure;
4615 							}
4616 							if (opline->op1_type == IS_CV
4617 							 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4618 								ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4619 							}
4620 						} else {
4621 							CHECK_OP1_TRACE_TYPE();
4622 						}
4623 						op2_info = OP2_INFO();
4624 						CHECK_OP2_TRACE_TYPE();
4625 						op1_data_info = OP1_DATA_INFO();
4626 						CHECK_OP1_DATA_TRACE_TYPE();
4627 						op1_def_info = OP1_DEF_INFO();
4628 						if (!zend_jit_assign_dim_op(&dasm_state, opline,
4629 								op1_info, op1_def_info, op1_addr, op2_info,
4630 								op1_data_info, OP1_DATA_RANGE(), val_type,
4631 								zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
4632 							goto jit_failure;
4633 						}
4634 						goto done;
4635 					case ZEND_PRE_INC_OBJ:
4636 					case ZEND_PRE_DEC_OBJ:
4637 					case ZEND_POST_INC_OBJ:
4638 					case ZEND_POST_DEC_OBJ:
4639 						if (opline->op2_type != IS_CONST
4640 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4641 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4642 							break;
4643 						}
4644 						ce = NULL;
4645 						ce_is_instanceof = 0;
4646 						on_this = delayed_fetch_this = 0;
4647 						op1_indirect = 0;
4648 						if (opline->op1_type == IS_UNUSED) {
4649 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4650 							ce = op_array->scope;
4651 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4652 							op1_addr = 0;
4653 							on_this = 1;
4654 						} else {
4655 							if (ssa_op->op1_use >= 0) {
4656 								delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4657 							}
4658 							op1_info = OP1_INFO();
4659 							if (!(op1_info & MAY_BE_OBJECT)) {
4660 								break;
4661 							}
4662 							op1_addr = OP1_REG_ADDR();
4663 							if (opline->op1_type == IS_VAR) {
4664 								if (orig_op1_type != IS_UNKNOWN
4665 								 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4666 									op1_indirect = 1;
4667 									if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4668 											&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4669 										goto jit_failure;
4670 									}
4671 								}
4672 							}
4673 							if (orig_op1_type != IS_UNKNOWN
4674 							 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4675 								if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4676 										!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4677 									goto jit_failure;
4678 								}
4679 								if (opline->op1_type == IS_CV
4680 								 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4681 									ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4682 								}
4683 							} else {
4684 								CHECK_OP1_TRACE_TYPE();
4685 							}
4686 							if (!(op1_info & MAY_BE_OBJECT)) {
4687 								break;
4688 							}
4689 							if (ssa->var_info && ssa->ops) {
4690 								if (ssa_op->op1_use >= 0) {
4691 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4692 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4693 										ce = op1_ssa->ce;
4694 										ce_is_instanceof = op1_ssa->is_instanceof;
4695 									}
4696 								}
4697 							}
4698 							if (delayed_fetch_this) {
4699 								on_this = 1;
4700 							} else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4701 								on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4702 							} else if (op_array_ssa->ops
4703 							        && op_array_ssa->vars
4704 									&& op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4705 									&& op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4706 								on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4707 							}
4708 						}
4709 						if (!zend_jit_incdec_obj(&dasm_state, opline, op_array, ssa, ssa_op,
4710 								op1_info, op1_addr,
4711 								op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4712 								val_type)) {
4713 							goto jit_failure;
4714 						}
4715 						goto done;
4716 					case ZEND_ASSIGN_OBJ_OP:
4717 						if (opline->result_type != IS_UNUSED) {
4718 							break;
4719 						}
4720 						if (opline->op2_type != IS_CONST
4721 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4722 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4723 							break;
4724 						}
4725 						if (opline->op1_type == IS_CV
4726 						 && (opline+1)->op1_type == IS_CV
4727 						 && (opline+1)->op1.var == opline->op1.var) {
4728 							/* skip $a->prop += $a; */
4729 							break;
4730 						}
4731 						if (!zend_jit_supported_binary_op(
4732 								opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
4733 							break;
4734 						}
4735 						ce = NULL;
4736 						ce_is_instanceof = 0;
4737 						on_this = delayed_fetch_this = 0;
4738 						op1_indirect = 0;
4739 						if (opline->op1_type == IS_UNUSED) {
4740 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4741 							ce = op_array->scope;
4742 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4743 							op1_addr = 0;
4744 							on_this = 1;
4745 						} else {
4746 							if (ssa_op->op1_use >= 0) {
4747 								delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4748 							}
4749 							op1_info = OP1_INFO();
4750 							if (!(op1_info & MAY_BE_OBJECT)) {
4751 								break;
4752 							}
4753 							op1_addr = OP1_REG_ADDR();
4754 							if (opline->op1_type == IS_VAR) {
4755 								if (orig_op1_type != IS_UNKNOWN
4756 								 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4757 									op1_indirect = 1;
4758 									if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4759 											&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4760 										goto jit_failure;
4761 									}
4762 								}
4763 							}
4764 							if (orig_op1_type != IS_UNKNOWN
4765 							 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4766 								if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4767 										!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4768 									goto jit_failure;
4769 								}
4770 								if (opline->op1_type == IS_CV
4771 								 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4772 									ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4773 								}
4774 							} else {
4775 								CHECK_OP1_TRACE_TYPE();
4776 							}
4777 							if (!(op1_info & MAY_BE_OBJECT)) {
4778 								break;
4779 							}
4780 							if (ssa->var_info && ssa->ops) {
4781 								if (ssa_op->op1_use >= 0) {
4782 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4783 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4784 										ce = op1_ssa->ce;
4785 										ce_is_instanceof = op1_ssa->is_instanceof;
4786 									}
4787 								}
4788 							}
4789 							if (delayed_fetch_this) {
4790 								on_this = 1;
4791 							} else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4792 								on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4793 							} else if (op_array_ssa->ops
4794 							        && op_array_ssa->vars
4795 									&& op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4796 									&& op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4797 								on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4798 							}
4799 						}
4800 						op1_data_info = OP1_DATA_INFO();
4801 						CHECK_OP1_DATA_TRACE_TYPE();
4802 						if (!zend_jit_assign_obj_op(&dasm_state, opline, op_array, ssa, ssa_op,
4803 								op1_info, op1_addr, op1_data_info, OP1_DATA_RANGE(),
4804 								op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4805 								val_type)) {
4806 							goto jit_failure;
4807 						}
4808 						goto done;
4809 					case ZEND_ASSIGN_OBJ:
4810 						if (opline->op2_type != IS_CONST
4811 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4812 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4813 							break;
4814 						}
4815 						ce = NULL;
4816 						ce_is_instanceof = 0;
4817 						on_this = delayed_fetch_this = 0;
4818 						op1_indirect = 0;
4819 						if (opline->op1_type == IS_UNUSED) {
4820 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4821 							ce = op_array->scope;
4822 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4823 							op1_addr = 0;
4824 							on_this = 1;
4825 						} else {
4826 							if (ssa_op->op1_use >= 0) {
4827 								delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4828 							}
4829 							op1_info = OP1_INFO();
4830 							if (!(op1_info & MAY_BE_OBJECT)) {
4831 								break;
4832 							}
4833 							op1_addr = OP1_REG_ADDR();
4834 							if (opline->op1_type == IS_VAR) {
4835 								if (orig_op1_type != IS_UNKNOWN
4836 								 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4837 									op1_indirect = 1;
4838 									if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4839 											&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4840 										goto jit_failure;
4841 									}
4842 								}
4843 							}
4844 							if (orig_op1_type != IS_UNKNOWN
4845 							 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4846 								if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4847 										!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4848 									goto jit_failure;
4849 								}
4850 								if (opline->op1_type == IS_CV
4851 								 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4852 									ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4853 								}
4854 							} else {
4855 								CHECK_OP1_TRACE_TYPE();
4856 							}
4857 							if (!(op1_info & MAY_BE_OBJECT)) {
4858 								break;
4859 							}
4860 							if (ssa->var_info && ssa->ops) {
4861 								if (ssa_op->op1_use >= 0) {
4862 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4863 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4864 										ce = op1_ssa->ce;
4865 										ce_is_instanceof = op1_ssa->is_instanceof;
4866 									}
4867 								}
4868 							}
4869 							if (delayed_fetch_this) {
4870 								on_this = 1;
4871 							} else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4872 								on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4873 							} else if (op_array_ssa->ops
4874 							        && op_array_ssa->vars
4875 									&& op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4876 									&& op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4877 								on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4878 							}
4879 						}
4880 						op1_data_info = OP1_DATA_INFO();
4881 						CHECK_OP1_DATA_TRACE_TYPE();
4882 						if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
4883 								op1_info, op1_addr, op1_data_info,
4884 								op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4885 								val_type,
4886 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
4887 							goto jit_failure;
4888 						}
4889 						if ((opline+1)->op1_type == IS_CV
4890 						 && (ssa_op+1)->op1_def >= 0
4891 						 && ssa->vars[(ssa_op+1)->op1_def].alias == NO_ALIAS) {
4892 							ssa->var_info[(ssa_op+1)->op1_def].guarded_reference = ssa->var_info[(ssa_op+1)->op1_use].guarded_reference;
4893 						}
4894 						goto done;
4895 					case ZEND_ASSIGN_DIM:
4896 						op1_info = OP1_INFO();
4897 						op1_addr = OP1_REG_ADDR();
4898 						if (opline->op1_type == IS_CV
4899 						 && (opline+1)->op1_type == IS_CV
4900 						 && (opline+1)->op1.var == opline->op1.var) {
4901 							/* skip $a[x] = $a; */
4902 							break;
4903 						}
4904 						if (opline->op1_type == IS_VAR) {
4905 							if (orig_op1_type != IS_UNKNOWN
4906 							 && (orig_op1_type & IS_TRACE_INDIRECT)
4907 							 && opline->result_type == IS_UNUSED) {
4908 								if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4909 										&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4910 									goto jit_failure;
4911 								}
4912 							} else {
4913 								break;
4914 							}
4915 						}
4916 						if (orig_op1_type != IS_UNKNOWN
4917 						 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4918 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4919 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4920 								goto jit_failure;
4921 							}
4922 							if (opline->op1_type == IS_CV
4923 							 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4924 								ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4925 							}
4926 						} else {
4927 							CHECK_OP1_TRACE_TYPE();
4928 						}
4929 						op2_info = OP2_INFO();
4930 						CHECK_OP2_TRACE_TYPE();
4931 						op1_data_info = OP1_DATA_INFO();
4932 						CHECK_OP1_DATA_TRACE_TYPE();
4933 						if (!zend_jit_assign_dim(&dasm_state, opline,
4934 								op1_info, op1_addr, op2_info, op1_data_info, val_type,
4935 								zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
4936 							goto jit_failure;
4937 						}
4938 						if ((opline+1)->op1_type == IS_CV
4939 						 && (ssa_op+1)->op1_def >= 0
4940 						 && ssa->vars[(ssa_op+1)->op1_def].alias == NO_ALIAS) {
4941 							ssa->var_info[(ssa_op+1)->op1_def].guarded_reference = ssa->var_info[(ssa_op+1)->op1_use].guarded_reference;
4942 						}
4943 						goto done;
4944 					case ZEND_ASSIGN:
4945 						if (opline->op1_type != IS_CV) {
4946 							break;
4947 						}
4948 						op2_addr = OP2_REG_ADDR();
4949 						op2_info = OP2_INFO();
4950 
4951 						if (ssa_op->op2_def < 0 || (Z_MODE(op2_addr) == IS_REG && ssa->vars[ssa_op->op2_def].no_val)) {
4952 							op2_def_addr = op2_addr;
4953 						} else {
4954 							op2_def_addr = OP2_DEF_REG_ADDR();
4955 						}
4956 						CHECK_OP2_TRACE_TYPE();
4957 						op1_info = OP1_INFO();
4958 						op1_def_info = OP1_DEF_INFO();
4959 						if (op1_type != IS_UNKNOWN && (op1_info & MAY_BE_GUARD)) {
4960 							if (op1_type < IS_STRING
4961 							 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (op1_def_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
4962 								if (!zend_jit_scalar_type_guard(&dasm_state, opline, opline->op1.var)) {
4963 									goto jit_failure;
4964 								}
4965 								op1_info &= ~(MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD);
4966 							} else {
4967 								CHECK_OP1_TRACE_TYPE();
4968 							}
4969 						}
4970 						op1_addr = OP1_REG_ADDR();
4971 						op1_def_addr = OP1_DEF_REG_ADDR();
4972 						if (Z_MODE(op1_def_addr) != IS_REG &&
4973 								STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) !=
4974 								STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var))) {
4975 							/* type may be not set */
4976 							op1_info |= MAY_BE_NULL;
4977 						}
4978 						if (orig_op1_type != IS_UNKNOWN) {
4979 							if (orig_op1_type & IS_TRACE_REFERENCE) {
4980 								if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4981 										!ssa->var_info[ssa_op->op1_use].guarded_reference, 0)) {
4982 									goto jit_failure;
4983 								}
4984 								if (opline->op1_type == IS_CV
4985 								 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4986 									ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4987 								}
4988 								if (opline->result_type == IS_UNUSED) {
4989 									res_addr = 0;
4990 								} else {
4991 									res_addr = RES_REG_ADDR();
4992 									if (Z_MODE(res_addr) != IS_REG
4993 									 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4994 										send_result = 1;
4995 										res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4996 										if (!zend_jit_reuse_ip(&dasm_state)) {
4997 											goto jit_failure;
4998 										}
4999 									}
5000 								}
5001 								if (!zend_jit_assign_to_typed_ref(&dasm_state, opline, opline->op2_type, op2_addr, res_addr, 1)) {
5002 									goto jit_failure;
5003 								}
5004 								op1_def_addr = op1_addr;
5005 								op1_def_info &= ~MAY_BE_REF;
5006 							} else if (op1_info & MAY_BE_REF) {
5007 								if (!zend_jit_noref_guard(&dasm_state, opline, op1_addr)) {
5008 									goto jit_failure;
5009 								}
5010 								op1_info &= ~MAY_BE_REF;
5011 								op1_def_info &= ~MAY_BE_REF;
5012 							}
5013 						}
5014 						if (opline->result_type == IS_UNUSED) {
5015 							res_addr = 0;
5016 							res_info = -1;
5017 						} else {
5018 							res_addr = RES_REG_ADDR();
5019 							res_info = RES_INFO();
5020 							if (Z_MODE(res_addr) != IS_REG
5021 							 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
5022 								send_result = 1;
5023 								res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
5024 								if (!zend_jit_reuse_ip(&dasm_state)) {
5025 									goto jit_failure;
5026 								}
5027 							}
5028 						}
5029 						if (!zend_jit_assign(&dasm_state, opline,
5030 								op1_info, op1_addr,
5031 								op1_def_info, op1_def_addr,
5032 								op2_info, op2_addr, op2_def_addr,
5033 								res_info, res_addr,
5034 								zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
5035 							goto jit_failure;
5036 						}
5037 						if (ssa_op->op2_def >= 0
5038 						 && Z_MODE(op2_addr) == IS_REG
5039 						 && ssa->vars[ssa_op->op2_def].no_val) {
5040 							uint8_t type = (op2_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5041 							uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var);
5042 
5043 							if (STACK_MEM_TYPE(stack, var_num) != type
5044 							 && ssa->vars[ssa_op->op2_def].use_chain < 0
5045 							 && !ssa->vars[ssa_op->op2_def].phi_use_chain) {
5046 								if (!zend_jit_store_var_type(&dasm_state, var_num, type)) {
5047 									return 0;
5048 								}
5049 								SET_STACK_TYPE(stack, var_num, type, 1);
5050 							}
5051 						}
5052 						if (opline->op2_type == IS_CV
5053 						 && ssa_op->op2_def >= 0
5054 						 && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS) {
5055 							ssa->var_info[ssa_op->op2_def].guarded_reference = ssa->var_info[ssa_op->op2_use].guarded_reference;
5056 						}
5057 						goto done;
5058 					case ZEND_CAST:
5059 						if (opline->extended_value != op1_type) {
5060 							break;
5061 						}
5062 						ZEND_FALLTHROUGH;
5063 					case ZEND_QM_ASSIGN:
5064 						op1_addr = OP1_REG_ADDR();
5065 						if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
5066 							op1_def_addr = op1_addr;
5067 						} else {
5068 							op1_def_addr = OP1_DEF_REG_ADDR();
5069 						}
5070 						op1_info = OP1_INFO();
5071 						CHECK_OP1_TRACE_TYPE();
5072 						res_info = RES_INFO();
5073 						res_use_info = zend_jit_trace_type_to_info(
5074 							STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)));
5075 						res_addr = RES_REG_ADDR();
5076 						if (Z_MODE(res_addr) != IS_REG &&
5077 								STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) !=
5078 								STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var))) {
5079 							/* type may be not set */
5080 							res_use_info |= MAY_BE_NULL;
5081 						}
5082 						if (!zend_jit_qm_assign(&dasm_state, opline,
5083 								op1_info, op1_addr, op1_def_addr,
5084 								res_use_info, res_info, res_addr)) {
5085 							goto jit_failure;
5086 						}
5087 						if (ssa_op->op1_def >= 0
5088 						 && Z_MODE(op1_addr) == IS_REG
5089 						 && ssa->vars[ssa_op->op1_def].no_val) {
5090 							uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5091 							uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var);
5092 
5093 							if (STACK_MEM_TYPE(stack, var_num) != type
5094 							 && ssa->vars[ssa_op->op1_def].use_chain < 0
5095 							 && !ssa->vars[ssa_op->op1_def].phi_use_chain) {
5096 								if (!zend_jit_store_var_type(&dasm_state, var_num, type)) {
5097 									return 0;
5098 								}
5099 								SET_STACK_TYPE(stack, var_num, type, 1);
5100 							}
5101 						}
5102 						if (opline->op1_type == IS_CV
5103 						 && ssa_op->op1_def >= 0
5104 						 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5105 							ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
5106 						}
5107 						goto done;
5108 					case ZEND_INIT_FCALL:
5109 					case ZEND_INIT_FCALL_BY_NAME:
5110 					case ZEND_INIT_NS_FCALL_BY_NAME:
5111 						frame_flags = TRACE_FRAME_MASK_NESTED;
5112 						if (!zend_jit_init_fcall(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
5113 							goto jit_failure;
5114 						}
5115 						goto done;
5116 					case ZEND_SEND_VAL:
5117 					case ZEND_SEND_VAL_EX:
5118 						if (opline->op2_type == IS_CONST) {
5119 							/* Named parameters not supported in JIT */
5120 							break;
5121 						}
5122 						if (opline->opcode == ZEND_SEND_VAL_EX
5123 						 && opline->op2.num > MAX_ARG_FLAG_NUM) {
5124 							break;
5125 						}
5126 						op1_info = OP1_INFO();
5127 						CHECK_OP1_TRACE_TYPE();
5128 						if (!zend_jit_send_val(&dasm_state, opline,
5129 								op1_info, OP1_REG_ADDR())) {
5130 							goto jit_failure;
5131 						}
5132 						if (frame->call && frame->call->func) {
5133 							if (opline->op1_type == IS_CONST) {
5134 								zend_jit_trace_send_type(opline, frame->call, Z_TYPE_P(RT_CONSTANT(opline, opline->op1)));
5135 							} else if (op1_type != IS_UNKNOWN) {
5136 								if (op1_type == IS_UNDEF) {
5137 									op1_type = IS_NULL;
5138 								}
5139 								zend_jit_trace_send_type(opline, frame->call, op1_type);
5140 							}
5141 						}
5142 						goto done;
5143 					case ZEND_SEND_REF:
5144 						if (opline->op2_type == IS_CONST) {
5145 							/* Named parameters not supported in JIT */
5146 							break;
5147 						}
5148 						op1_info = OP1_INFO();
5149 						if (!zend_jit_send_ref(&dasm_state, opline, op_array,
5150 								op1_info, 0)) {
5151 							goto jit_failure;
5152 						}
5153 						if (opline->op1_type == IS_CV
5154 						 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5155 							ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5156 						}
5157 						goto done;
5158 					case ZEND_SEND_VAR:
5159 					case ZEND_SEND_VAR_EX:
5160 					case ZEND_SEND_VAR_NO_REF:
5161 					case ZEND_SEND_VAR_NO_REF_EX:
5162 					case ZEND_SEND_FUNC_ARG:
5163 						if (opline->op2_type == IS_CONST) {
5164 							/* Named parameters not supported in JIT */
5165 							break;
5166 						}
5167 						if ((opline->opcode == ZEND_SEND_VAR_EX
5168 						  || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
5169 						 && opline->op2.num > MAX_ARG_FLAG_NUM) {
5170 							break;
5171 						}
5172 						op1_addr = OP1_REG_ADDR();
5173 						if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
5174 							op1_def_addr = op1_addr;
5175 						} else {
5176 							op1_def_addr = OP1_DEF_REG_ADDR();
5177 						}
5178 						op1_info = OP1_INFO();
5179 						CHECK_OP1_TRACE_TYPE();
5180 						if (!zend_jit_send_var(&dasm_state, opline, op_array,
5181 								op1_info, op1_addr, op1_def_addr)) {
5182 							goto jit_failure;
5183 						}
5184 						if (ssa_op->op1_def >= 0
5185 						 && Z_MODE(op1_addr) == IS_REG
5186 						 && ssa->vars[ssa_op->op1_def].no_val) {
5187 							uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5188 							uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var);
5189 
5190 							if (STACK_MEM_TYPE(stack, var_num) != type
5191 							 && ssa->vars[ssa_op->op1_def].use_chain < 0
5192 							 && !ssa->vars[ssa_op->op1_def].phi_use_chain) {
5193 								if (!zend_jit_store_var_type(&dasm_state, var_num, type)) {
5194 									return 0;
5195 								}
5196 								SET_STACK_TYPE(stack, var_num, type, 1);
5197 							}
5198 						}
5199 						if (opline->op1_type == IS_CV
5200 						 && ssa_op->op1_def >= 0
5201 						 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5202 							ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
5203 						}
5204 						if (frame->call && frame->call->func) {
5205 							if ((opline->opcode == ZEND_SEND_VAR_EX
5206 							  || opline->opcode == ZEND_SEND_FUNC_ARG)
5207 							 && ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
5208 								goto done;
5209 							}
5210 							if (op1_type != IS_UNKNOWN) {
5211 								if (op1_type == IS_UNDEF) {
5212 									op1_type = IS_NULL;
5213 								}
5214 								zend_jit_trace_send_type(opline, frame->call, op1_type);
5215 							}
5216 						}
5217 						goto done;
5218 					case ZEND_CHECK_FUNC_ARG:
5219 						if (!JIT_G(current_frame)
5220 						 || !JIT_G(current_frame)->call
5221 						 || !JIT_G(current_frame)->call->func) {
5222 							break;
5223 						}
5224 						if (opline->op2_type == IS_CONST
5225 						 || opline->op2.num > MAX_ARG_FLAG_NUM) {
5226 							/* Named parameters not supported in JIT */
5227 							TRACE_FRAME_SET_LAST_SEND_UNKNOWN(JIT_G(current_frame)->call);
5228 							break;
5229 						}
5230 						if (!zend_jit_check_func_arg(&dasm_state, opline)) {
5231 							goto jit_failure;
5232 						}
5233 						goto done;
5234 					case ZEND_CHECK_UNDEF_ARGS:
5235 						if (JIT_G(current_frame)
5236 						 && JIT_G(current_frame)->call) {
5237 							TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(JIT_G(current_frame)->call);
5238 						}
5239 						if (!zend_jit_check_undef_args(&dasm_state, opline)) {
5240 							goto jit_failure;
5241 						}
5242 						goto done;
5243 					case ZEND_DO_UCALL:
5244 					case ZEND_DO_ICALL:
5245 					case ZEND_DO_FCALL_BY_NAME:
5246 					case ZEND_DO_FCALL:
5247 						if (!zend_jit_do_fcall(&dasm_state, opline, op_array, op_array_ssa, frame->call_level, -1, p + 1)) {
5248 							goto jit_failure;
5249 						}
5250 						goto done;
5251 					case ZEND_IS_EQUAL:
5252 					case ZEND_IS_NOT_EQUAL:
5253 					case ZEND_IS_SMALLER:
5254 					case ZEND_IS_SMALLER_OR_EQUAL:
5255 					case ZEND_CASE:
5256 						op1_info = OP1_INFO();
5257 						op2_info = OP2_INFO();
5258 						skip_comparison =
5259 							ssa_op != ssa->ops &&
5260 							(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5261 							(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5262 							zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5263 						CHECK_OP1_TRACE_TYPE();
5264 						CHECK_OP2_TRACE_TYPE();
5265 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5266 							bool exit_if_true = 0;
5267 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5268 							uint32_t exit_point;
5269 
5270 							if (ra) {
5271 								zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5272 							}
5273 							exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5274 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5275 							if (!exit_addr) {
5276 								goto jit_failure;
5277 							}
5278 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5279 							if (!zend_jit_cmp(&dasm_state, opline,
5280 									op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5281 									op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5282 									RES_REG_ADDR(),
5283 									zend_may_throw(opline, ssa_op, op_array, ssa),
5284 									smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5285 								goto jit_failure;
5286 							}
5287 							zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5288 						} else {
5289 							smart_branch_opcode = 0;
5290 							exit_addr = NULL;
5291 							if (!zend_jit_cmp(&dasm_state, opline,
5292 									op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5293 									op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5294 									RES_REG_ADDR(),
5295 									zend_may_throw(opline, ssa_op, op_array, ssa),
5296 									smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5297 								goto jit_failure;
5298 							}
5299 						}
5300 						goto done;
5301 					case ZEND_IS_IDENTICAL:
5302 					case ZEND_IS_NOT_IDENTICAL:
5303 					case ZEND_CASE_STRICT:
5304 						op1_info = OP1_INFO();
5305 						op2_info = OP2_INFO();
5306 						skip_comparison =
5307 							ssa_op != ssa->ops &&
5308 							(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5309 							(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5310 							zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5311 						CHECK_OP1_TRACE_TYPE();
5312 						CHECK_OP2_TRACE_TYPE();
5313 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5314 							bool exit_if_true = 0;
5315 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5316 							uint32_t exit_point;
5317 
5318 							if (ra) {
5319 								zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5320 							}
5321 							exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5322 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5323 							if (!exit_addr) {
5324 								goto jit_failure;
5325 							}
5326 							if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
5327 								exit_if_true = !exit_if_true;
5328 							}
5329 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5330 							if (!zend_jit_identical(&dasm_state, opline,
5331 									op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5332 									op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5333 									RES_REG_ADDR(),
5334 									zend_may_throw(opline, ssa_op, op_array, ssa),
5335 									smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5336 								goto jit_failure;
5337 							}
5338 							zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5339 						} else {
5340 							smart_branch_opcode = 0;
5341 							exit_addr = NULL;
5342 							if (!zend_jit_identical(&dasm_state, opline,
5343 									op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5344 									op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5345 									RES_REG_ADDR(),
5346 									zend_may_throw(opline, ssa_op, op_array, ssa),
5347 									smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5348 								goto jit_failure;
5349 							}
5350 						}
5351 						goto done;
5352 					case ZEND_DEFINED:
5353 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5354 							bool exit_if_true = 0;
5355 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5356 							uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5357 
5358 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5359 							if (!exit_addr) {
5360 								goto jit_failure;
5361 							}
5362 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5363 						} else {
5364 							smart_branch_opcode = 0;
5365 							exit_addr = NULL;
5366 						}
5367 						if (!zend_jit_defined(&dasm_state, opline, smart_branch_opcode, -1, -1, exit_addr)) {
5368 							goto jit_failure;
5369 						}
5370 						goto done;
5371 					case ZEND_TYPE_CHECK:
5372 						if (opline->extended_value == MAY_BE_RESOURCE) {
5373 							// TODO: support for is_resource() ???
5374 							break;
5375 						}
5376 						op1_info = OP1_INFO();
5377 						CHECK_OP1_TRACE_TYPE();
5378 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5379 							bool exit_if_true = 0;
5380 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5381 							uint32_t exit_point;
5382 
5383 							if (ra) {
5384 								zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5385 							}
5386 							exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5387 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5388 							if (!exit_addr) {
5389 								goto jit_failure;
5390 							}
5391 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5392 						} else {
5393 							smart_branch_opcode = 0;
5394 							exit_addr = NULL;
5395 						}
5396 						if (!zend_jit_type_check(&dasm_state, opline, op1_info, smart_branch_opcode, -1, -1, exit_addr)) {
5397 							goto jit_failure;
5398 						}
5399 						goto done;
5400 					case ZEND_RETURN:
5401 						op1_info = OP1_INFO();
5402 						CHECK_OP1_TRACE_TYPE();
5403 						if (opline->op1_type == IS_CONST) {
5404 							res_type = Z_TYPE_P(RT_CONSTANT(opline, opline->op1));
5405 						} else if (op1_type != IS_UNKNOWN) {
5406 							res_type = op1_type;
5407 						}
5408 						if (op_array->type == ZEND_EVAL_CODE
5409 						 // TODO: support for top-level code
5410 						 || !op_array->function_name
5411 						 // TODO: support for IS_UNDEF ???
5412 						 || (op1_info & MAY_BE_UNDEF)) {
5413 							if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
5414 								goto jit_failure;
5415 							}
5416 						} else {
5417 							int j;
5418 							int may_throw = 0;
5419 							bool left_frame = 0;
5420 
5421 							if (!zend_jit_return(&dasm_state, opline, op_array,
5422 									op1_info, OP1_REG_ADDR())) {
5423 								goto jit_failure;
5424 							}
5425 							if (op_array->last_var > 100) {
5426 								/* To many CVs to unroll */
5427 								if (!zend_jit_free_cvs(&dasm_state)) {
5428 									goto jit_failure;
5429 								}
5430 								left_frame = 1;
5431 							}
5432 							if (!left_frame) {
5433 								for (j = 0 ; j < op_array->last_var; j++) {
5434 									uint32_t info;
5435 									zend_uchar type;
5436 
5437 									info = zend_ssa_cv_info(op_array, op_array_ssa, j);
5438 									type = STACK_TYPE(stack, j);
5439 									info = zend_jit_trace_type_to_info_ex(type, info);
5440 									if (opline->op1_type == IS_CV
5441 									 && EX_VAR_TO_NUM(opline->op1.var) == j
5442 									 && !(op1_info & (MAY_BE_REF|MAY_BE_OBJECT))) {
5443 										if (JIT_G(current_frame)
5444 										 && TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
5445 											continue;
5446 										} else {
5447 											info |= MAY_BE_NULL;
5448 										}
5449 									}
5450 									if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
5451 										if (!left_frame) {
5452 											left_frame = 1;
5453 										    if (!zend_jit_leave_frame(&dasm_state)) {
5454 												goto jit_failure;
5455 										    }
5456 										}
5457 										if (!zend_jit_free_cv(&dasm_state, info, j)) {
5458 											goto jit_failure;
5459 										}
5460 										if (info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE)) {
5461 											if (info & MAY_BE_RC1) {
5462 												may_throw = 1;
5463 											}
5464 										}
5465 									}
5466 								}
5467 							}
5468 							if (!zend_jit_leave_func(&dasm_state, op_array, opline, op1_info, left_frame,
5469 									p + 1, &zend_jit_traces[ZEND_JIT_TRACE_NUM],
5470 									(op_array_ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, may_throw)) {
5471 								goto jit_failure;
5472 							}
5473 						}
5474 						goto done;
5475 					case ZEND_BOOL:
5476 					case ZEND_BOOL_NOT:
5477 						op1_info = OP1_INFO();
5478 						CHECK_OP1_TRACE_TYPE();
5479 						if (!zend_jit_bool_jmpznz(&dasm_state, opline,
5480 								op1_info, OP1_REG_ADDR(), RES_REG_ADDR(),
5481 								-1, -1,
5482 								zend_may_throw(opline, ssa_op, op_array, ssa),
5483 								opline->opcode, NULL)) {
5484 							goto jit_failure;
5485 						}
5486 						goto done;
5487 					case ZEND_JMPZ:
5488 					case ZEND_JMPNZ:
5489 					case ZEND_JMPZ_EX:
5490 					case ZEND_JMPNZ_EX:
5491 						op1_info = OP1_INFO();
5492 						CHECK_OP1_TRACE_TYPE();
5493 						if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
5494 							const zend_op *exit_opline = NULL;
5495 							uint32_t exit_point;
5496 
5497 							if ((p+1)->opline == OP_JMP_ADDR(opline, opline->op2)) {
5498 								/* taken branch */
5499 								if (opline->opcode == ZEND_JMPNZ_EX) {
5500 									smart_branch_opcode = ZEND_JMPZ_EX;
5501 								} else if (opline->opcode == ZEND_JMPZ_EX) {
5502 									smart_branch_opcode = ZEND_JMPNZ_EX;
5503 								} else if (opline->opcode == ZEND_JMPNZ) {
5504 									smart_branch_opcode = ZEND_JMPZ;
5505 								} else {
5506 									smart_branch_opcode = ZEND_JMPNZ;
5507 								}
5508 								exit_opline = opline + 1;
5509 							} else if ((p+1)->opline == opline + 1) {
5510 								/* not taken branch */
5511 								smart_branch_opcode = opline->opcode;
5512 								exit_opline = OP_JMP_ADDR(opline, opline->op2);
5513 							} else {
5514 								ZEND_UNREACHABLE();
5515 							}
5516 							if (ra) {
5517 								zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5518 							}
5519 							if (!(op1_info & MAY_BE_GUARD)
5520 							 && has_concrete_type(op1_info)
5521 							 && concrete_type(op1_info) <= IS_TRUE) {
5522 								/* unconditional branch */
5523 								exit_addr = NULL;
5524 							} else if (opline->result_type == IS_TMP_VAR) {
5525 								zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5526 								uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5527 
5528 								SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
5529 								exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5530 								SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
5531 								exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5532 								if (!exit_addr) {
5533 									goto jit_failure;
5534 								}
5535 							} else {
5536 								exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5537 								exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5538 								if (!exit_addr) {
5539 									goto jit_failure;
5540 								}
5541 							}
5542 						} else  {
5543 							ZEND_UNREACHABLE();
5544 						}
5545 						if (opline->result_type == IS_UNDEF) {
5546 							res_addr = 0;
5547 						} else {
5548 							res_addr = RES_REG_ADDR();
5549 						}
5550 						if (!zend_jit_bool_jmpznz(&dasm_state, opline,
5551 								op1_info, OP1_REG_ADDR(), res_addr,
5552 								-1, -1,
5553 								zend_may_throw(opline, ssa_op, op_array, ssa),
5554 								smart_branch_opcode, exit_addr)) {
5555 							goto jit_failure;
5556 						}
5557 						goto done;
5558 					case ZEND_ISSET_ISEMPTY_CV:
5559 						if ((opline->extended_value & ZEND_ISEMPTY)) {
5560 							// TODO: support for empty() ???
5561 							break;
5562 						}
5563 						op1_info = OP1_INFO();
5564 						op1_addr = OP1_REG_ADDR();
5565 						if (orig_op1_type != IS_UNKNOWN
5566 						 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5567 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5568 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5569 								goto jit_failure;
5570 							}
5571 							if (opline->op1_type == IS_CV
5572 							 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5573 								ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5574 							}
5575 						} else {
5576 							CHECK_OP1_TRACE_TYPE();
5577 						}
5578 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5579 							bool exit_if_true = 0;
5580 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5581 							uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5582 
5583 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5584 							if (!exit_addr) {
5585 								goto jit_failure;
5586 							}
5587 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5588 						} else {
5589 							smart_branch_opcode = 0;
5590 							exit_addr = NULL;
5591 						}
5592 						if (!zend_jit_isset_isempty_cv(&dasm_state, opline,
5593 								op1_info, op1_addr,
5594 								smart_branch_opcode, -1, -1, exit_addr)) {
5595 							goto jit_failure;
5596 						}
5597 						goto done;
5598 					case ZEND_IN_ARRAY:
5599 						if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
5600 							break;
5601 						}
5602 						op1_info = OP1_INFO();
5603 						op1_addr = OP1_REG_ADDR();
5604 						CHECK_OP1_TRACE_TYPE();
5605 						if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
5606 							break;
5607 						}
5608 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5609 							bool exit_if_true = 0;
5610 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5611 							uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5612 
5613 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5614 							if (!exit_addr) {
5615 								goto jit_failure;
5616 							}
5617 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5618 						} else {
5619 							smart_branch_opcode = 0;
5620 							exit_addr = NULL;
5621 						}
5622 						if (!zend_jit_in_array(&dasm_state, opline,
5623 								op1_info, op1_addr,
5624 								smart_branch_opcode, -1, -1, exit_addr)) {
5625 							goto jit_failure;
5626 						}
5627 						goto done;
5628 					case ZEND_FETCH_DIM_FUNC_ARG:
5629 						if (!JIT_G(current_frame)
5630 						 || !JIT_G(current_frame)->call
5631 						 || !JIT_G(current_frame)->call->func
5632 						 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
5633 							break;
5634 						}
5635 						ZEND_FALLTHROUGH;
5636 					case ZEND_FETCH_DIM_R:
5637 					case ZEND_FETCH_DIM_IS:
5638 					case ZEND_FETCH_LIST_R:
5639 						op1_info = OP1_INFO();
5640 						op1_addr = OP1_REG_ADDR();
5641 						if (orig_op1_type != IS_UNKNOWN
5642 						 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5643 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5644 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5645 								goto jit_failure;
5646 							}
5647 							if (opline->op1_type == IS_CV
5648 							 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5649 								ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5650 								if (ssa_op->op1_def >= 0) {
5651 									ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5652 								}
5653 							}
5654 						} else {
5655 							CHECK_OP1_TRACE_TYPE();
5656 						}
5657 						op2_info = OP2_INFO();
5658 						CHECK_OP2_TRACE_TYPE();
5659 						res_info = RES_INFO();
5660 						avoid_refcounting =
5661 							ssa_op->op1_use >= 0 &&
5662 							ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5663 						if (op1_info & MAY_BE_PACKED_GUARD) {
5664 							ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
5665 						} else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
5666 								&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
5667 								&& MAY_BE_PACKED(op1_info)
5668 								&& MAY_BE_HASH(op1_info)
5669 								&& orig_op1_type != IS_UNKNOWN) {
5670 							op1_info |= MAY_BE_PACKED_GUARD;
5671 							if (orig_op1_type & IS_TRACE_PACKED) {
5672 								op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5673 								if (op1_type != IS_UNKNOWN) {
5674 									ssa->var_info[ssa_op->op1_use].type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5675 								}
5676 							} else {
5677 								op1_info &= ~MAY_BE_ARRAY_PACKED;
5678 								if (op1_type != IS_UNKNOWN) {
5679 									ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_ARRAY_PACKED;
5680 								}
5681 							}
5682 						}
5683 						if (!zend_jit_fetch_dim_read(&dasm_state, opline, ssa, ssa_op,
5684 								op1_info, op1_addr, avoid_refcounting,
5685 								op2_info, res_info, RES_REG_ADDR(), val_type)) {
5686 							goto jit_failure;
5687 						}
5688 						if (ssa_op->op1_def >= 0 && op1_type != IS_UNKNOWN) {
5689 							ssa->var_info[ssa_op->op1_def].type = ssa->var_info[ssa_op->op1_use].type;
5690 						}
5691 						goto done;
5692 					case ZEND_FETCH_DIM_W:
5693 					case ZEND_FETCH_DIM_RW:
5694 //					case ZEND_FETCH_DIM_UNSET:
5695 					case ZEND_FETCH_LIST_W:
5696 						if (opline->op1_type != IS_CV
5697 						 && (orig_op1_type == IS_UNKNOWN
5698 						  || !(orig_op1_type & IS_TRACE_INDIRECT))) {
5699 							break;
5700 						}
5701 						op1_info = OP1_INFO();
5702 						op1_addr = OP1_REG_ADDR();
5703 						if (opline->op1_type == IS_VAR) {
5704 							if (orig_op1_type != IS_UNKNOWN
5705 							 && (orig_op1_type & IS_TRACE_INDIRECT)) {
5706 								if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
5707 										&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5708 									goto jit_failure;
5709 								}
5710 							} else {
5711 								break;
5712 							}
5713 						}
5714 						if (orig_op1_type != IS_UNKNOWN
5715 						 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5716 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5717 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5718 								goto jit_failure;
5719 							}
5720 							if (opline->op1_type == IS_CV
5721 							 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5722 								ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5723 							}
5724 						} else {
5725 							CHECK_OP1_TRACE_TYPE();
5726 						}
5727 						op2_info = OP2_INFO();
5728 						CHECK_OP2_TRACE_TYPE();
5729 						op1_def_info = OP1_DEF_INFO();
5730 						if (!zend_jit_fetch_dim(&dasm_state, opline,
5731 								op1_info, op1_addr, op2_info, RES_REG_ADDR(), val_type)) {
5732 							goto jit_failure;
5733 						}
5734 						if (ssa_op->result_def >= 0
5735 						 && (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_LIST_W)
5736 						 && !(op1_info & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
5737 						 && !(op2_info & (MAY_BE_UNDEF|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
5738 							ssa->var_info[ssa_op->result_def].indirect_reference = 1;
5739 						}
5740 						goto done;
5741 					case ZEND_ISSET_ISEMPTY_DIM_OBJ:
5742 						if ((opline->extended_value & ZEND_ISEMPTY)) {
5743 							// TODO: support for empty() ???
5744 							break;
5745 						}
5746 						op1_info = OP1_INFO();
5747 						op1_addr = OP1_REG_ADDR();
5748 						if (orig_op1_type != IS_UNKNOWN
5749 						 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5750 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5751 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5752 								goto jit_failure;
5753 							}
5754 							if (opline->op1_type == IS_CV
5755 							 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5756 								ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5757 							}
5758 						} else {
5759 							CHECK_OP1_TRACE_TYPE();
5760 						}
5761 						op2_info = OP2_INFO();
5762 						CHECK_OP2_TRACE_TYPE();
5763 						if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5764 							bool exit_if_true = 0;
5765 							const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5766 							uint32_t exit_point;
5767 
5768 							if (ra) {
5769 								zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5770 							}
5771 							if (ssa_op->op1_use >= 0
5772 							 && ssa->var_info[ssa_op->op1_use].avoid_refcounting) {
5773 								/* Temporary reset ZREG_ZVAL_TRY_ADDREF */
5774 								zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5775 								uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
5776 
5777 								SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
5778 								exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5779 								SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
5780 							} else {
5781 								exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5782 							}
5783 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5784 							if (!exit_addr) {
5785 								goto jit_failure;
5786 							}
5787 							smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5788 						} else {
5789 							smart_branch_opcode = 0;
5790 							exit_addr = NULL;
5791 						}
5792 						avoid_refcounting =
5793 							ssa_op->op1_use >= 0 &&
5794 							ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5795 						if (op1_info & MAY_BE_PACKED_GUARD) {
5796 							ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
5797 						} else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
5798 								&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
5799 								&& MAY_BE_PACKED(op1_info)
5800 								&& MAY_BE_HASH(op1_info)
5801 								&& orig_op1_type != IS_UNKNOWN) {
5802 							op1_info |= MAY_BE_PACKED_GUARD;
5803 							if (orig_op1_type & IS_TRACE_PACKED) {
5804 								op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5805 							} else {
5806 								op1_info &= ~MAY_BE_ARRAY_PACKED;
5807 							}
5808 						}
5809 						if (!zend_jit_isset_isempty_dim(&dasm_state, opline,
5810 								op1_info, op1_addr, avoid_refcounting,
5811 								op2_info, val_type,
5812 								zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info),
5813 								smart_branch_opcode, -1, -1,
5814 								exit_addr)) {
5815 							goto jit_failure;
5816 						}
5817 						goto done;
5818 					case ZEND_FETCH_OBJ_FUNC_ARG:
5819 						if (!JIT_G(current_frame)
5820 						 || !JIT_G(current_frame)->call
5821 						 || !JIT_G(current_frame)->call->func
5822 						 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
5823 							break;
5824 						}
5825 						ZEND_FALLTHROUGH;
5826 					case ZEND_FETCH_OBJ_R:
5827 					case ZEND_FETCH_OBJ_IS:
5828 					case ZEND_FETCH_OBJ_W:
5829 						on_this = delayed_fetch_this = 0;
5830 						avoid_refcounting = 0;
5831 						if (opline->op2_type != IS_CONST
5832 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
5833 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
5834 							break;
5835 						}
5836 						ce = NULL;
5837 						ce_is_instanceof = 0;
5838 						op1_indirect = 0;
5839 						if (opline->op1_type == IS_UNUSED) {
5840 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
5841 							ce = op_array->scope;
5842 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
5843 							op1_addr = 0;
5844 							on_this = 1;
5845 						} else {
5846 							op1_info = OP1_INFO();
5847 							if (!(op1_info & MAY_BE_OBJECT)) {
5848 								break;
5849 							}
5850 							op1_addr = OP1_REG_ADDR();
5851 							if (opline->op1_type == IS_VAR
5852 							 && opline->opcode == ZEND_FETCH_OBJ_W) {
5853 								if (orig_op1_type != IS_UNKNOWN
5854 								 && (orig_op1_type & IS_TRACE_INDIRECT)) {
5855 									op1_indirect = 1;
5856 									if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
5857 											&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5858 										goto jit_failure;
5859 									}
5860 								}
5861 							}
5862 							if (orig_op1_type != IS_UNKNOWN
5863 							 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5864 								if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5865 										!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5866 									goto jit_failure;
5867 								}
5868 								if (opline->op1_type == IS_CV
5869 								 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5870 									ssa->var_info[ssa_op->op1_def >= 0 ? ssa_op->op1_def : ssa_op->op1_use].guarded_reference = 1;
5871 								}
5872 							} else {
5873 								CHECK_OP1_TRACE_TYPE();
5874 							}
5875 							if (!(op1_info & MAY_BE_OBJECT)) {
5876 								break;
5877 							}
5878 							if (ssa->var_info && ssa->ops) {
5879 								if (ssa_op->op1_use >= 0) {
5880 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
5881 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
5882 										ce = op1_ssa->ce;
5883 										ce_is_instanceof = op1_ssa->is_instanceof;
5884 									}
5885 								}
5886 							}
5887 							if (ssa_op->op1_use >= 0) {
5888 								delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
5889 								avoid_refcounting = ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5890 							}
5891 							if (delayed_fetch_this) {
5892 								on_this = 1;
5893 							} else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
5894 								on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
5895 							} else if (op_array_ssa->ops
5896 							        && op_array_ssa->vars
5897 									&& op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
5898 									&& op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
5899 								on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
5900 							}
5901 						}
5902 						if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, ssa, ssa_op,
5903 								op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof,
5904 								on_this, delayed_fetch_this, avoid_refcounting, op1_ce, val_type,
5905 								zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, MAY_BE_STRING))) {
5906 							goto jit_failure;
5907 						}
5908 						goto done;
5909 					case ZEND_BIND_GLOBAL:
5910 						orig_opline = opline;
5911 						orig_ssa_op = ssa_op;
5912 						while (1) {
5913 							if (!ssa->ops || !ssa->var_info) {
5914 								op1_info = MAY_BE_ANY|MAY_BE_REF;
5915 							} else {
5916 								op1_info = OP1_INFO();
5917 							}
5918 							if (ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5919 								ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5920 							}
5921 							if (!zend_jit_bind_global(&dasm_state, opline, op1_info)) {
5922 								goto jit_failure;
5923 							}
5924 							if ((opline+1)->opcode == ZEND_BIND_GLOBAL) {
5925 								opline++;
5926 								ssa_op++;
5927 							} else {
5928 								break;
5929 							}
5930 						}
5931 						opline = orig_opline;
5932 						ssa_op = orig_ssa_op;
5933 						goto done;
5934 					case ZEND_RECV:
5935 						if (!zend_jit_recv(&dasm_state, opline, op_array)) {
5936 							goto jit_failure;
5937 						}
5938 						goto done;
5939 					case ZEND_RECV_INIT:
5940 						orig_opline = opline;
5941 						orig_ssa_op = ssa_op;
5942 						while (1) {
5943 							if (!zend_jit_recv_init(&dasm_state, opline, op_array,
5944 									(opline + 1)->opcode != ZEND_RECV_INIT,
5945 									zend_may_throw(opline, ssa_op, op_array, ssa))) {
5946 								goto jit_failure;
5947 							}
5948 							if ((opline+1)->opcode == ZEND_RECV_INIT) {
5949 								opline++;
5950 								ssa_op++;
5951 							} else {
5952 								break;
5953 							}
5954 						}
5955 						opline = orig_opline;
5956 						ssa_op = orig_ssa_op;
5957 						goto done;
5958 					case ZEND_FREE:
5959 					case ZEND_FE_FREE:
5960 						op1_info = OP1_INFO();
5961 						if (!zend_jit_free(&dasm_state, opline, op1_info,
5962 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
5963 							goto jit_failure;
5964 						}
5965 						goto done;
5966 					case ZEND_ECHO:
5967 						op1_info = OP1_INFO();
5968 						CHECK_OP1_TRACE_TYPE();
5969 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
5970 							break;
5971 						}
5972 						if (!zend_jit_echo(&dasm_state, opline, op1_info)) {
5973 							goto jit_failure;
5974 						}
5975 						goto done;
5976 					case ZEND_STRLEN:
5977 						op1_info = OP1_INFO();
5978 						op1_addr = OP1_REG_ADDR();
5979 						if (orig_op1_type == (IS_TRACE_REFERENCE|IS_STRING)) {
5980 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5981 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5982 								goto jit_failure;
5983 							}
5984 							if (opline->op1_type == IS_CV
5985 							 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5986 								ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5987 							}
5988 						} else {
5989 							CHECK_OP1_TRACE_TYPE();
5990 							if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
5991 								break;
5992 							}
5993 						}
5994 						if (!zend_jit_strlen(&dasm_state, opline, op1_info, op1_addr, RES_REG_ADDR())) {
5995 							goto jit_failure;
5996 						}
5997 						goto done;
5998 					case ZEND_COUNT:
5999 						op1_info = OP1_INFO();
6000 						op1_addr = OP1_REG_ADDR();
6001 						if (orig_op1_type == (IS_TRACE_REFERENCE|IS_ARRAY)) {
6002 							if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
6003 									!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6004 								goto jit_failure;
6005 							}
6006 							if (opline->op1_type == IS_CV
6007 							 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6008 								ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6009 							}
6010 						} else {
6011 							CHECK_OP1_TRACE_TYPE();
6012 							if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
6013 								break;
6014 							}
6015 						}
6016 						if (!zend_jit_count(&dasm_state, opline, op1_info, op1_addr, RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
6017 							goto jit_failure;
6018 						}
6019 						goto done;
6020 					case ZEND_FETCH_THIS:
6021 						delayed_fetch_this = 0;
6022 						if (ssa_op->result_def >= 0 && opline->result_type != IS_CV) {
6023 							if (zend_jit_may_delay_fetch_this(op_array, ssa, ssa_opcodes, ssa_op)) {
6024 								ssa->var_info[ssa_op->result_def].delayed_fetch_this = 1;
6025 								delayed_fetch_this = 1;
6026 							}
6027 						}
6028 						if (!zend_jit_fetch_this(&dasm_state, opline, op_array, delayed_fetch_this)) {
6029 							goto jit_failure;
6030 						}
6031 						goto done;
6032 					case ZEND_SWITCH_LONG:
6033 					case ZEND_SWITCH_STRING:
6034 					case ZEND_MATCH:
6035 						if (!zend_jit_switch(&dasm_state, opline, op_array, op_array_ssa, p+1, &zend_jit_traces[ZEND_JIT_TRACE_NUM])) {
6036 							goto jit_failure;
6037 						}
6038 						goto done;
6039 					case ZEND_VERIFY_RETURN_TYPE:
6040 						if (opline->op1_type == IS_UNUSED) {
6041 							/* Always throws */
6042 							break;
6043 						}
6044 						if (opline->op1_type == IS_CONST) {
6045 							/* TODO Different instruction format, has return value */
6046 							break;
6047 						}
6048 						if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
6049 							/* Not worth bothering with */
6050 							break;
6051 						}
6052 						op1_info = OP1_INFO();
6053 						CHECK_OP1_TRACE_TYPE();
6054 						if (op1_info & MAY_BE_REF) {
6055 							/* TODO May need reference unwrapping. */
6056 							break;
6057 						}
6058 						if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, op1_info)) {
6059 							goto jit_failure;
6060 						}
6061 						goto done;
6062 					case ZEND_FE_RESET_R:
6063 						op1_info = OP1_INFO();
6064 						CHECK_OP1_TRACE_TYPE();
6065 						if ((op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) != MAY_BE_ARRAY) {
6066 							break;
6067 						}
6068 						if (!zend_jit_fe_reset(&dasm_state, opline, op1_info)) {
6069 							goto jit_failure;
6070 						}
6071 						goto done;
6072 					case ZEND_FE_FETCH_R:
6073 						op1_info = OP1_INFO();
6074 						CHECK_OP1_TRACE_TYPE();
6075 						if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
6076 							break;
6077 						}
6078 						if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
6079 							const zend_op *exit_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
6080 							uint32_t exit_point;
6081 
6082 							if ((p+1)->opline == exit_opline) {
6083 								/* taken branch (exit from loop) */
6084 								exit_opline = opline;
6085 								smart_branch_opcode = ZEND_NOP;
6086 							} else if ((p+1)->opline == opline + 1) {
6087 								/* not taken branch (loop) */
6088 								smart_branch_opcode = ZEND_JMP;
6089 							} else {
6090 								ZEND_UNREACHABLE();
6091 							}
6092 							exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
6093 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6094 							if (!exit_addr) {
6095 								goto jit_failure;
6096 							}
6097 						} else  {
6098 							ZEND_UNREACHABLE();
6099 						}
6100 						if (!zend_jit_fe_fetch(&dasm_state, opline, op1_info, OP2_INFO(),
6101 								-1, smart_branch_opcode, exit_addr)) {
6102 							goto jit_failure;
6103 						}
6104 						goto done;
6105 					case ZEND_FETCH_CONSTANT:
6106 						if (!zend_jit_fetch_constant(&dasm_state, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
6107 							goto jit_failure;
6108 						}
6109 						goto done;
6110 					case ZEND_INIT_METHOD_CALL:
6111 						if (opline->op2_type != IS_CONST
6112 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
6113 							break;
6114 						}
6115 						on_this = delayed_fetch_this = 0;
6116 						ce = NULL;
6117 						ce_is_instanceof = 0;
6118 						if (opline->op1_type == IS_UNUSED) {
6119 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
6120 							ce = op_array->scope;
6121 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
6122 							op1_addr = 0;
6123 							on_this = 1;
6124 						} else {
6125 							op1_info = OP1_INFO();
6126 							op1_addr = OP1_REG_ADDR();
6127 							if (polymorphic_side_trace) {
6128 								op1_info = MAY_BE_OBJECT;
6129 								op1_addr = 0;
6130 							} else if (orig_op1_type != IS_UNKNOWN
6131 							 && (orig_op1_type & IS_TRACE_REFERENCE)) {
6132 								if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
6133 										!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6134 									goto jit_failure;
6135 								}
6136 								if (opline->op1_type == IS_CV
6137 								 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6138 									ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6139 								}
6140 							} else {
6141 								CHECK_OP1_TRACE_TYPE();
6142 							}
6143 							if (ssa->var_info && ssa->ops) {
6144 								if (ssa_op->op1_use >= 0) {
6145 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
6146 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
6147 										ce = op1_ssa->ce;
6148 										ce_is_instanceof = op1_ssa->is_instanceof;
6149 									}
6150 								}
6151 							}
6152 							if (ssa_op->op1_use >= 0) {
6153 								delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
6154 							}
6155 							if (delayed_fetch_this) {
6156 								on_this = 1;
6157 							} else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
6158 								on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
6159 							} else if (op_array_ssa->ops
6160 							        && op_array_ssa->vars
6161 									&& op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
6162 									&& op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
6163 								on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
6164 							}
6165 						}
6166 						frame_flags = TRACE_FRAME_MASK_NESTED;
6167 						if (!zend_jit_init_method_call(&dasm_state, opline,
6168 								op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1,
6169 								op_array, ssa, ssa_op, frame->call_level,
6170 								op1_info, op1_addr, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
6171 								p + 1, peek_checked_stack - checked_stack, polymorphic_side_trace)) {
6172 							goto jit_failure;
6173 						}
6174 						goto done;
6175 					case ZEND_INIT_DYNAMIC_CALL:
6176 						if (orig_op2_type != IS_OBJECT || op2_ce != zend_ce_closure) {
6177 							break;
6178 						}
6179 						op2_info = OP2_INFO();
6180 						CHECK_OP2_TRACE_TYPE();
6181 						frame_flags = TRACE_FRAME_MASK_NESTED;
6182 						if (!zend_jit_init_closure_call(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
6183 							goto jit_failure;
6184 						}
6185 						goto done;
6186 					case ZEND_SEND_ARRAY:
6187 					case ZEND_SEND_UNPACK:
6188 						if (JIT_G(current_frame)
6189 						 && JIT_G(current_frame)->call) {
6190 							TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(JIT_G(current_frame)->call);
6191 						}
6192 						break;
6193 					case ZEND_ROPE_INIT:
6194 					case ZEND_ROPE_ADD:
6195 					case ZEND_ROPE_END:
6196 						op2_info = OP2_INFO();
6197 						CHECK_OP2_TRACE_TYPE();
6198 						if ((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
6199 							break;
6200 						}
6201 						if (!zend_jit_rope(&dasm_state, opline, op2_info)) {
6202 							goto jit_failure;
6203 						}
6204 						goto done;
6205 					default:
6206 						break;
6207 				}
6208 			}
6209 
6210 			if (opline->opcode != ZEND_NOP && opline->opcode != ZEND_JMP) {
6211 				gen_handler = 1;
6212 				op1_info = OP1_INFO();
6213 				op2_info = OP2_INFO();
6214 				if (op1_info & MAY_BE_GUARD) {
6215 					op1_info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
6216 				}
6217 				if (op2_info & MAY_BE_GUARD) {
6218 					op2_info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
6219 				}
6220 				if (!zend_jit_trace_handler(&dasm_state, op_array, opline,
6221 						zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info), p + 1)) {
6222 					goto jit_failure;
6223 				}
6224 				if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) {
6225 					if (opline->opcode == ZEND_NEW && opline->result_type != IS_UNUSED) {
6226 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_OBJECT, 1);
6227 					}
6228 					if (zend_jit_may_be_polymorphic_call(opline) ||
6229 							zend_jit_may_be_modified((p+1)->func, op_array)) {
6230 						if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
6231 							goto jit_failure;
6232 						}
6233 					}
6234 				}
6235 			}
6236 
6237 done:
6238 			polymorphic_side_trace = 0;
6239 			switch (opline->opcode) {
6240 				case ZEND_DO_FCALL:
6241 				case ZEND_DO_ICALL:
6242 				case ZEND_DO_UCALL:
6243 				case ZEND_DO_FCALL_BY_NAME:
6244 				case ZEND_CALLABLE_CONVERT:
6245 					frame->call_level--;
6246 			}
6247 
6248 			if (ra) {
6249 				zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
6250 			}
6251 
6252 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
6253 			 && STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var)) > ZREG_NUM) {
6254 				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
6255 			}
6256 
6257 			if (opline->opcode == ZEND_ROPE_INIT) {
6258 				/* clear stack slots used by rope */
6259 				uint32_t var = EX_VAR_TO_NUM(opline->result.var);
6260 				uint32_t count =
6261 					((opline->extended_value * sizeof(void*)) + (sizeof(zval)-1)) / sizeof(zval);
6262 
6263 				do {
6264 					SET_STACK_TYPE(stack, var, IS_UNKNOWN, 1);
6265 					var++;
6266 					count--;
6267 				} while (count);
6268 			}
6269 
6270 			if (ssa_op) {
6271 				zend_ssa_range tmp;
6272 
6273 				/* Keep information about known types on abstract stack */
6274 				if (ssa_op->result_def >= 0) {
6275 					zend_uchar type = IS_UNKNOWN;
6276 
6277 					if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0
6278 					 || send_result) {
6279 						/* we didn't set result variable */
6280 						type = IS_UNKNOWN;
6281 					} else if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
6282 					 && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) {
6283 						type = concrete_type(ssa->var_info[ssa_op->result_def].type);
6284 					} else if (opline->opcode == ZEND_QM_ASSIGN) {
6285 						if (opline->op1_type != IS_CONST) {
6286 							/* copy */
6287 							type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6288 						}
6289 					} else if (opline->opcode == ZEND_ASSIGN) {
6290 						if (opline->op2_type != IS_CONST
6291 						 && ssa_op->op1_use >= 0
6292 						 /* assignment to typed reference may cause conversion */
6293 						 && (ssa->var_info[ssa_op->op1_use].type & MAY_BE_REF) == 0) {
6294 							/* copy */
6295 							type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6296 						}
6297 					} else if (opline->opcode == ZEND_POST_INC
6298 			         || opline->opcode == ZEND_POST_DEC) {
6299 						/* copy */
6300 						type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6301 					}
6302 					if (opline->opcode == ZEND_JMP_SET
6303 					  || opline->opcode == ZEND_COALESCE
6304 					  || opline->opcode == ZEND_JMP_NULL) {
6305 						if ((p+1)->op != ZEND_JIT_TRACE_VM) {
6306 							SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
6307 						} else if ((p+1)->opline != (opline + 1)) {
6308 							SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
6309 						}
6310 					} else {
6311 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
6312 							(gen_handler || type == IS_UNKNOWN || !ra || !ra[ssa_op->result_def]));
6313 						if (ssa->var_info[ssa_op->result_def].type & MAY_BE_INDIRECT) {
6314 							RESET_STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
6315 						}
6316 						if (type != IS_UNKNOWN) {
6317 							ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
6318 							if (opline->opcode == ZEND_FETCH_THIS
6319 							 && delayed_fetch_this) {
6320 								SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_THIS);
6321 							} else if (ssa->var_info[ssa_op->result_def].avoid_refcounting) {
6322 								SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_TRY_ADDREF);
6323 							} else if (ra && ra[ssa_op->result_def]) {
6324 								SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ra[ssa_op->result_def]->reg,
6325 									ra[ssa_op->result_def]->flags & ZREG_STORE);
6326 							}
6327 						}
6328 					}
6329 
6330 					if (type == IS_LONG
6331 					 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->result_def, &tmp)) {
6332 						ssa->var_info[ssa_op->result_def].range.min = tmp.min;
6333 						ssa->var_info[ssa_op->result_def].range.max = tmp.max;
6334 						ssa->var_info[ssa_op->result_def].range.underflow = 0;
6335 						ssa->var_info[ssa_op->result_def].range.overflow = 0;
6336 						ssa->var_info[ssa_op->result_def].has_range = 1;
6337 					}
6338 				}
6339 				if (ssa_op->op1_def >= 0
6340 				 && ((opline->opcode != ZEND_QM_ASSIGN && opline->opcode != ZEND_CAST)
6341 				  || opline->result_type != IS_CV
6342 				  || opline->result.var != opline->op1.var)) {
6343 					zend_uchar type = IS_UNKNOWN;
6344 
6345 					if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6346 					 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6347 						type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6348 					} else if (opline->opcode == ZEND_ASSIGN) {
6349 						if (!(OP1_INFO() & MAY_BE_REF)
6350 						 || STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_UNKNOWN) {
6351 							if (opline->op2_type != IS_CONST) {
6352 								/* copy */
6353 								type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6354 							}
6355 						}
6356 					} else if (opline->opcode == ZEND_SEND_VAR
6357 					 || opline->opcode == ZEND_CAST
6358 					 || opline->opcode == ZEND_QM_ASSIGN
6359 					 || opline->opcode == ZEND_JMP_SET
6360 					 || opline->opcode == ZEND_COALESCE
6361 					 || opline->opcode == ZEND_JMP_NULL
6362 					 || opline->opcode == ZEND_FE_RESET_R) {
6363 						/* keep old value */
6364 						type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6365 					}
6366 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6367 						(gen_handler || type == IS_UNKNOWN || !ra ||
6368 							(!ra[ssa_op->op1_def] &&
6369 								!(ssa->vars[ssa_op->op1_def].no_val &&
6370 									Z_MODE(OP1_REG_ADDR()) == IS_REG &&
6371 										(opline->opcode == ZEND_QM_ASSIGN ||
6372 											opline->opcode == ZEND_SEND_VAR ||
6373 											opline->opcode == ZEND_SEND_VAR_EX ||
6374 											opline->opcode == ZEND_SEND_VAR_NO_REF ||
6375 											opline->opcode == ZEND_SEND_VAR_NO_REF_EX ||
6376 											opline->opcode == ZEND_SEND_FUNC_ARG)))));
6377 					if (type != IS_UNKNOWN) {
6378 						ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
6379 						if (ra && ra[ssa_op->op1_def]) {
6380 							uint8_t flags = ra[ssa_op->op1_def]->flags & ZREG_STORE;
6381 
6382 							if (ssa_op->op1_use >= 0) {
6383 								if (opline->opcode == ZEND_SEND_VAR
6384 								 || opline->opcode == ZEND_CAST
6385 								 || opline->opcode == ZEND_QM_ASSIGN
6386 								 || opline->opcode == ZEND_JMP_SET
6387 								 || opline->opcode == ZEND_COALESCE
6388 								 || opline->opcode == ZEND_JMP_NULL
6389 								 || opline->opcode == ZEND_FE_RESET_R) {
6390 									if (!ra[ssa_op->op1_use]) {
6391 										flags |= ZREG_LOAD;
6392 									}
6393 								}
6394 							}
6395 							SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def]->reg, flags);
6396 						}
6397 					}
6398 					if (type == IS_LONG
6399 					 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op1_def, &tmp)) {
6400 						ssa->var_info[ssa_op->op1_def].range.min = tmp.min;
6401 						ssa->var_info[ssa_op->op1_def].range.max = tmp.max;
6402 						ssa->var_info[ssa_op->op1_def].range.underflow = 0;
6403 						ssa->var_info[ssa_op->op1_def].range.overflow = 0;
6404 						ssa->var_info[ssa_op->op1_def].has_range = 1;
6405 					}
6406 				}
6407 				if (ssa_op->op2_def >= 0
6408 				 && (opline->opcode != ZEND_ASSIGN
6409 				  || opline->op1_type != IS_CV
6410 				  || opline->op1.var != opline->op2.var)) {
6411 					zend_uchar type = IS_UNKNOWN;
6412 
6413 					if (!(ssa->var_info[ssa_op->op2_def].type & MAY_BE_GUARD)
6414 					 && has_concrete_type(ssa->var_info[ssa_op->op2_def].type)) {
6415 						type = concrete_type(ssa->var_info[ssa_op->op2_def].type);
6416 					} else if (opline->opcode == ZEND_ASSIGN) {
6417 						/* keep old value */
6418 						type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6419 					}
6420 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), type,
6421 						(gen_handler || type == IS_UNKNOWN || !ra ||
6422 							(!ra[ssa_op->op2_def] &&
6423 								!(ssa->vars[ssa_op->op2_def].no_val &&
6424 									Z_MODE(OP2_REG_ADDR()) == IS_REG &&
6425 									opline->opcode == ZEND_ASSIGN))));
6426 					if (type != IS_UNKNOWN) {
6427 						ssa->var_info[ssa_op->op2_def].type &= ~MAY_BE_GUARD;
6428 						if (ra && ra[ssa_op->op2_def]) {
6429 							uint8_t flags = ra[ssa_op->op2_def]->flags & ZREG_STORE;
6430 
6431 							if (ssa_op->op2_use >= 0) {
6432 								if (opline->opcode == ZEND_ASSIGN) {
6433 									if (!ra[ssa_op->op2_use]
6434 									 || ra[ssa_op->op2_use]->reg != ra[ssa_op->op2_def]->reg) {
6435 										flags |= ZREG_LOAD;
6436 									}
6437 								}
6438 							}
6439 							SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op2.var), ra[ssa_op->op2_def]->reg, flags);
6440 						}
6441 					}
6442 					if (type == IS_LONG
6443 					 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op2_def, &tmp)) {
6444 						ssa->var_info[ssa_op->op2_def].range.min = tmp.min;
6445 						ssa->var_info[ssa_op->op2_def].range.max = tmp.max;
6446 						ssa->var_info[ssa_op->op2_def].range.underflow = 0;
6447 						ssa->var_info[ssa_op->op2_def].range.overflow = 0;
6448 						ssa->var_info[ssa_op->op2_def].has_range = 1;
6449 					}
6450 				}
6451 
6452 				switch (opline->opcode) {
6453 					case ZEND_ASSIGN_DIM:
6454 					case ZEND_ASSIGN_OBJ:
6455 					case ZEND_ASSIGN_STATIC_PROP:
6456 					case ZEND_ASSIGN_DIM_OP:
6457 					case ZEND_ASSIGN_OBJ_OP:
6458 					case ZEND_ASSIGN_STATIC_PROP_OP:
6459 					case ZEND_ASSIGN_OBJ_REF:
6460 					case ZEND_ASSIGN_STATIC_PROP_REF:
6461 						/* OP_DATA */
6462 						ssa_op++;
6463 						opline++;
6464 						if (ssa_op->op1_def >= 0) {
6465 							zend_uchar type = IS_UNKNOWN;
6466 
6467 							if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6468 							 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6469 								type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6470 							} else if ((opline-1)->opcode == ZEND_ASSIGN_DIM
6471 							 || (opline-1)->opcode == ZEND_ASSIGN_OBJ
6472 							 || (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP) {
6473 								/* keep old value */
6474 								type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6475 							}
6476 							SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6477 								(gen_handler || type == IS_UNKNOWN || !ra || !ra[ssa_op->op1_def]));
6478 							if (type != IS_UNKNOWN) {
6479 								ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
6480 								if (ra && ra[ssa_op->op1_def]) {
6481 									SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def]->reg,
6482 										ra[ssa_op->op1_def]->flags & ZREG_STORE);
6483 								}
6484 							}
6485 							if (type == IS_LONG
6486 							 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op1_def, &tmp)) {
6487 								ssa->var_info[ssa_op->op1_def].range.min = tmp.min;
6488 								ssa->var_info[ssa_op->op1_def].range.max = tmp.max;
6489 								ssa->var_info[ssa_op->op1_def].range.underflow = 0;
6490 								ssa->var_info[ssa_op->op1_def].range.overflow = 0;
6491 								ssa->var_info[ssa_op->op1_def].has_range = 1;
6492 							}
6493 						}
6494 						ssa_op++;
6495 						break;
6496 					case ZEND_RECV_INIT:
6497 					    ssa_op++;
6498 						opline++;
6499 						while (opline->opcode == ZEND_RECV_INIT) {
6500 							if (ssa_op->result_def >= 0) {
6501 								zend_uchar type = IS_UNKNOWN;
6502 
6503 								if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
6504 								 && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) {
6505 									type = concrete_type(ssa->var_info[ssa_op->result_def].type);
6506 								}
6507 								SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
6508 									(gen_handler || !ra || !ra[ssa_op->result_def]));
6509 								if (ra && ra[ssa_op->result_def]) {
6510 									SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ra[ssa_op->result_def]->reg,
6511 										ra[ssa_op->result_def]->flags & ZREG_STORE);
6512 								}
6513 							}
6514 							ssa_op++;
6515 							opline++;
6516 						}
6517 						break;
6518 					case ZEND_BIND_GLOBAL:
6519 						ssa_op++;
6520 						opline++;
6521 						while (opline->opcode == ZEND_BIND_GLOBAL) {
6522 							if (ssa_op->op1_def >= 0) {
6523 								zend_uchar type = IS_UNKNOWN;
6524 
6525 								if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6526 								 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6527 									type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6528 								}
6529 								SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6530 									(gen_handler || !ra || !ra[ssa_op->op1_def]));
6531 								if (ra && ra[ssa_op->op1_def]) {
6532 									SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def]->reg,
6533 										ra[ssa_op->op1_def]->flags & ZREG_STORE);
6534 								}
6535 							}
6536 							ssa_op++;
6537 							opline++;
6538 						}
6539 						break;
6540 					default:
6541 						ssa_op += zend_jit_trace_op_len(opline);
6542 						break;
6543 				}
6544 
6545 				if (send_result) {
6546 					ssa_op++;
6547 					p++;
6548 					if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
6549 						p++;
6550 					}
6551 					send_result = 0;
6552 				}
6553 			}
6554 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
6555 			call = frame->call;
6556 			assert(call && &call->func->op_array == p->op_array);
6557 
6558 			if (opline->opcode == ZEND_DO_UCALL
6559 			 || opline->opcode == ZEND_DO_FCALL_BY_NAME
6560 			 || opline->opcode == ZEND_DO_FCALL) {
6561 
6562 				frame->call_opline = opline;
6563 
6564 				/* Check if SEND_UNPACK/SEND_ARRAY may cause enter at different opline */
6565 				if (opline > op_array->opcodes) {
6566 					const zend_op *prev_opline = opline - 1;
6567 
6568 					while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
6569 						prev_opline--;
6570 					}
6571 					JIT_G(current_frame) = call;
6572 					if ((prev_opline->opcode == ZEND_SEND_ARRAY
6573 					  || prev_opline->opcode == ZEND_SEND_UNPACK
6574 					  || prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS)
6575 					 && p->op_array->num_args
6576 					 && (p->op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0
6577 					 && ((p+1)->op == ZEND_JIT_TRACE_VM
6578 					  || (p+1)->op == ZEND_JIT_TRACE_END)
6579 					 && (TRACE_FRAME_NUM_ARGS(call) < 0
6580 					  || TRACE_FRAME_NUM_ARGS(call) < p->op_array->num_args)
6581 					 && !zend_jit_trace_opline_guard(&dasm_state, (p+1)->opline)) {
6582 						goto jit_failure;
6583 					}
6584 					JIT_G(current_frame) = frame;
6585 				}
6586 			}
6587 
6588 			if ((p+1)->op == ZEND_JIT_TRACE_END) {
6589 				p++;
6590 				break;
6591 			}
6592 			if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
6593 				if (TRACE_FRAME_IS_THIS_CHECKED(frame)) {
6594 					TRACE_FRAME_SET_THIS_CHECKED(call);
6595 				}
6596 			} else if (op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) {
6597 				TRACE_FRAME_SET_THIS_CHECKED(call);
6598 			}
6599 			op_array = (zend_op_array*)p->op_array;
6600 			jit_extension =
6601 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
6602 			op_array_ssa = &jit_extension->func_info.ssa;
6603 			frame->call = call->prev;
6604 			call->prev = frame;
6605 			if (p->info & ZEND_JIT_TRACE_RETURN_VALUE_USED) {
6606 				TRACE_FRAME_SET_RETURN_VALUE_USED(call);
6607 			} else {
6608 				TRACE_FRAME_SET_RETURN_VALUE_UNUSED(call);
6609 			}
6610 			JIT_G(current_frame) = frame = call;
6611 			stack = frame->stack;
6612 			if (ra) {
6613 				int j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6614 
6615 				for (i = 0; i < op_array->last_var; i++,j++) {
6616 					if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) {
6617 						SET_STACK_REG_EX(stack, i, ra[j]->reg, ZREG_LOAD);
6618 						if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) {
6619 							goto jit_failure;
6620 						}
6621 					}
6622 				}
6623 			}
6624 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
6625 			op_array = (zend_op_array*)p->op_array;
6626 			jit_extension =
6627 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
6628 			op_array_ssa = &jit_extension->func_info.ssa;
6629 			top = frame;
6630 			if (frame->prev) {
6631 				checked_stack = frame->old_checked_stack;
6632 				peek_checked_stack = frame->old_peek_checked_stack;
6633 				frame = frame->prev;
6634 				stack = frame->stack;
6635 				ZEND_ASSERT(&frame->func->op_array == op_array);
6636 			} else {
6637 				frame = zend_jit_trace_ret_frame(frame, op_array);
6638 				TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
6639 				frame->used_stack = checked_stack = peek_checked_stack = 0;
6640 				stack = frame->stack;
6641 				if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
6642 					uint32_t j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6643 
6644 					for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
6645 						/* Initialize abstract stack using SSA */
6646 						if (!(ssa->var_info[j].type & MAY_BE_GUARD)
6647 						 && has_concrete_type(ssa->var_info[j].type)) {
6648 							SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[j].type), 1);
6649 						} else {
6650 							SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
6651 						}
6652 					}
6653 					if (ra) {
6654 						j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6655 						for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
6656 							if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) {
6657 								SET_STACK_REG_EX(stack, i, ra[j]->reg, ZREG_LOAD);
6658 								if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) {
6659 									goto jit_failure;
6660 								}
6661 							}
6662 						}
6663 					}
6664 				} else {
6665 					for (i = 0; i < op_array->last_var + op_array->T; i++) {
6666 						SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
6667 					}
6668 				}
6669 				opline = NULL;
6670 			}
6671 			JIT_G(current_frame) = frame;
6672 			if (res_type != IS_UNKNOWN
6673 			 && (p+1)->op == ZEND_JIT_TRACE_VM) {
6674 				const zend_op *opline = (p+1)->opline - 1;
6675 				if (opline->result_type != IS_UNUSED) {
6676 				    SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), res_type, 1);
6677 				}
6678 			}
6679 			res_type = IS_UNKNOWN;
6680 		} else if (p->op == ZEND_JIT_TRACE_END) {
6681 			break;
6682 		} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
6683 			const zend_op *init_opline = zend_jit_trace_find_init_fcall_op(p, op_array);
6684 			int num_args = -1;
6685 
6686 			if (init_opline
6687 			 && init_opline->extended_value <= TRACE_FRAME_MAX_NUM_ARGS) {
6688 				num_args = init_opline->extended_value;
6689 			}
6690 
6691 			call = top;
6692 			TRACE_FRAME_INIT(call, p->func, frame_flags, num_args);
6693 			call->prev = frame->call;
6694 			if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
6695 				TRACE_FRAME_SET_LAST_SEND_BY_VAL(call);
6696 				if (init_opline && init_opline->opcode == ZEND_INIT_DYNAMIC_CALL) {
6697 					TRACE_FRAME_SET_CLOSURE_CALL(call);
6698 				}
6699 			}
6700 			if (init_opline) {
6701 				if (init_opline->opcode != ZEND_NEW
6702 				 && (init_opline->opcode != ZEND_INIT_METHOD_CALL
6703 				  || init_opline->op1_type == IS_UNDEF
6704 				  || (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)
6705 				   && ssa_op
6706 				   && (ssa_op-1)->op1_use >=0
6707 				   && ssa->var_info[(ssa_op-1)->op1_use].delayed_fetch_this))
6708 				 && (init_opline->opcode != ZEND_INIT_USER_CALL
6709 				  || (p->func && (!p->func->common.scope || (p->func->common.fn_flags & ZEND_ACC_STATIC))))
6710 				 && (init_opline->opcode != ZEND_INIT_DYNAMIC_CALL
6711 				  || (p->func && (!p->func->common.scope || (p->func->common.fn_flags & ZEND_ACC_STATIC))))
6712 				) {
6713 					TRACE_FRAME_SET_NO_NEED_RELEASE_THIS(call);
6714 				} else if (init_opline->opcode == ZEND_NEW
6715 				 || (init_opline->opcode == ZEND_INIT_METHOD_CALL
6716 				  && init_opline->op1_type != IS_UNDEF
6717 				  && !(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)
6718 				  && p->func && p->func->common.scope && !(p->func->common.fn_flags & ZEND_ACC_STATIC))) {
6719 					TRACE_FRAME_SET_ALWAYS_RELEASE_THIS(call);
6720 				}
6721 			}
6722 			frame->call = call;
6723 			top = zend_jit_trace_call_frame(top, p->op_array);
6724 			if (p->func) {
6725 				if (p->func->type == ZEND_USER_FUNCTION) {
6726 					if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
6727 						zend_jit_op_array_trace_extension *jit_extension =
6728 							(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(p->op_array);
6729 
6730 						i = 0;
6731 						while (i < p->op_array->num_args) {
6732 							/* Types of arguments are going to be stored in abstract stack when processing SEV instruction */
6733 							SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6734 							i++;
6735 						}
6736 						while (i < p->op_array->last_var) {
6737 							if (jit_extension
6738 							 && zend_jit_var_may_alias(p->op_array, &jit_extension->func_info.ssa, i) != NO_ALIAS) {
6739 								SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6740 							} else {
6741 								SET_STACK_TYPE(call->stack, i, IS_UNDEF, 1);
6742 							}
6743 							i++;
6744 						}
6745 						while (i < p->op_array->last_var + p->op_array->T) {
6746 							SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6747 							i++;
6748 						}
6749 					} else {
6750 						for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
6751 							SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6752 						}
6753 					}
6754 				} else {
6755 					ZEND_ASSERT(p->func->type == ZEND_INTERNAL_FUNCTION);
6756 					for (i = 0; i < p->op_array->num_args; i++) {
6757 						SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6758 					}
6759 				}
6760 				if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
6761 					int skip_guard = 0;
6762 
6763 					if (init_opline) {
6764 						zend_call_info *call_info = jit_extension->func_info.callee_info;
6765 
6766 						while (call_info) {
6767 							if (call_info->caller_init_opline == init_opline
6768 									&& !call_info->is_prototype) {
6769 								if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
6770 									if (init_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL
6771 									 && init_opline->op1_type != IS_CONST) {
6772 										break;
6773 									} else if (init_opline->opcode == ZEND_INIT_METHOD_CALL) {
6774 										break;
6775 									}
6776 								}
6777 								skip_guard = 1;
6778 								break;
6779 							}
6780 							call_info = call_info->next_callee;
6781 						}
6782 						if (!skip_guard
6783 						 && !zend_jit_may_be_polymorphic_call(init_opline)
6784 						 && !zend_jit_may_be_modified(p->func, op_array)) {
6785 							skip_guard = 1;
6786 						}
6787 					}
6788 
6789 					if (!skip_guard) {
6790 						if (!opline) {
6791 							zend_jit_trace_rec *q = p + 1;
6792 							while (q->op != ZEND_JIT_TRACE_VM && q->op != ZEND_JIT_TRACE_END) {
6793 								q++;
6794 							}
6795 							opline = q->opline;
6796 							ZEND_ASSERT(opline != NULL);
6797 						}
6798 						if (!zend_jit_init_fcall_guard(&dasm_state,
6799 								ZEND_JIT_TRACE_FAKE_LEVEL(p->info), p->func, opline)) {
6800 							goto jit_failure;
6801 						}
6802 					}
6803 				}
6804 			}
6805 			call->old_checked_stack = checked_stack;
6806 			call->old_peek_checked_stack = peek_checked_stack;
6807 			if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
6808 				frame->call_level++;
6809 				call->used_stack = checked_stack = peek_checked_stack = 0;
6810 			} else {
6811 				if (p->func) {
6812 					call->used_stack = zend_vm_calc_used_stack(init_opline->extended_value, (zend_function*)p->func);
6813 				} else {
6814 					call->used_stack = (ZEND_CALL_FRAME_SLOT + init_opline->extended_value) * sizeof(zval);
6815 				}
6816 				switch (init_opline->opcode) {
6817 					case ZEND_INIT_FCALL:
6818 					case ZEND_INIT_FCALL_BY_NAME:
6819 					case ZEND_INIT_NS_FCALL_BY_NAME:
6820 					case ZEND_INIT_METHOD_CALL:
6821 					case ZEND_INIT_DYNAMIC_CALL:
6822 					//case ZEND_INIT_STATIC_METHOD_CALL:
6823 					//case ZEND_INIT_USER_CALL:
6824 					//case ZEND_NEW:
6825 						checked_stack += call->used_stack;
6826 						if (checked_stack > peek_checked_stack) {
6827 							peek_checked_stack = checked_stack;
6828 						}
6829 						break;
6830 					default:
6831 						checked_stack = peek_checked_stack = 0;
6832 				}
6833 			}
6834 		} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
6835 			call = frame->call;
6836 			if (call) {
6837 				checked_stack = call->old_checked_stack;
6838 				peek_checked_stack = call->old_peek_checked_stack;
6839 				top = call;
6840 				frame->call = call->prev;
6841 			}
6842 		} else {
6843 			ZEND_UNREACHABLE();
6844 		}
6845 	}
6846 
6847 	ZEND_ASSERT(p->op == ZEND_JIT_TRACE_END);
6848 
6849 	t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
6850 
6851 	if (!parent_trace && zend_jit_trace_uses_initial_ip()) {
6852 		t->flags |= ZEND_JIT_TRACE_USES_INITIAL_IP;
6853 	}
6854 
6855 	if (p->stop == ZEND_JIT_TRACE_STOP_LOOP
6856 	 || p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
6857 	 || p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6858 		if (ra) {
6859 			zend_ssa_phi *phi = ssa->blocks[1].phis;
6860 
6861 			while (phi) {
6862 				if (ra[phi->ssa_var]
6863 				 && ra[phi->sources[1]]
6864 				 && STACK_MEM_TYPE(stack, phi->var) != STACK_TYPE(stack, phi->var)
6865 				 && (ra[phi->ssa_var]->flags & (ZREG_LOAD|ZREG_STORE)) == 0
6866 				 && (ra[phi->sources[1]]->flags & (ZREG_LOAD|ZREG_STORE)) == 0) {
6867 					/* Store actual type to memory to avoid deoptimization mistakes */
6868 					/* TODO: Alternatively, we may try to update alredy generated deoptimization info */
6869 					zend_jit_store_var_type(&dasm_state, phi->var, STACK_TYPE(stack, phi->var));
6870 				}
6871 				phi = phi->next;
6872 			}
6873 		}
6874 		if (p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6875 			if ((t->flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
6876 			 && !zend_jit_set_ip(&dasm_state, p->opline)) {
6877 				goto jit_failure;
6878 			}
6879 		}
6880 		t->link = ZEND_JIT_TRACE_NUM;
6881 		if (p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6882 			t->flags |= ZEND_JIT_TRACE_CHECK_INTERRUPT;
6883 		}
6884 		if (!(t->flags & ZEND_JIT_TRACE_LOOP)) {
6885 			const void *timeout_exit_addr = NULL;
6886 
6887 			t->flags |= ZEND_JIT_TRACE_LOOP;
6888 
6889 			if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6890 				if (!(t->flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
6891 				 || (ra
6892 				  && zend_jit_trace_stack_needs_deoptimization(stack, op_array->last_var + op_array->T))) {
6893 					/* Deoptimize to the first instruction of the loop */
6894 					uint32_t exit_point = zend_jit_trace_get_exit_point(trace_buffer[1].opline, ZEND_JIT_EXIT_TO_VM);
6895 
6896 					timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6897 					if (!timeout_exit_addr) {
6898 						goto jit_failure;
6899 					}
6900 				} else {
6901 					timeout_exit_addr = dasm_labels[zend_lbinterrupt_handler];
6902 				}
6903 			}
6904 
6905 			zend_jit_trace_end_loop(&dasm_state, 0, timeout_exit_addr); /* jump back to start of the trace loop */
6906 		}
6907 	} else if (p->stop == ZEND_JIT_TRACE_STOP_LINK
6908 	        || p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
6909 		if (ra
6910 		 && (p-1)->op != ZEND_JIT_TRACE_ENTER
6911 		 && (p-1)->op != ZEND_JIT_TRACE_BACK
6912 		 && opline->opcode != ZEND_DO_UCALL
6913 		 && opline->opcode != ZEND_DO_FCALL
6914 		 && opline->opcode != ZEND_DO_FCALL_BY_NAME
6915 		 && opline->opcode != ZEND_INCLUDE_OR_EVAL) {
6916 			if (!zend_jit_trace_deoptimization(&dasm_state, 0, NULL,
6917 					stack, op_array->last_var + op_array->T, NULL, NULL, NULL, 0)) {
6918 				goto jit_failure;
6919 			}
6920 			for (i = 0; i < op_array->last_var; i++) {
6921 				int8_t reg = STACK_REG(stack, i);
6922 				uint8_t type = STACK_TYPE(stack, i);
6923 
6924 				if (reg == ZREG_NONE
6925 				 && type != IS_UNKNOWN
6926 				 && type != STACK_MEM_TYPE(stack, i)) {
6927 					if (!zend_jit_store_var_type(&dasm_state, i, type)) {
6928 						return 0;
6929 					}
6930 					SET_STACK_TYPE(stack, i, type, 1);
6931 				}
6932 			}
6933 		}
6934 		if (p->stop == ZEND_JIT_TRACE_STOP_LINK) {
6935 			const void *timeout_exit_addr = NULL;
6936 
6937 			t->link = zend_jit_find_trace(p->opline->handler);
6938 			if (t->link == 0) {
6939 				/* this can happen if ZEND_JIT_EXIT_INVALIDATE was handled
6940 				 * by zend_jit_trace_exit() in another thread after this
6941 				 * thread set ZEND_JIT_TRACE_STOP_LINK in zend_jit_trace_execute();
6942 				 * ZEND_JIT_EXIT_INVALIDATE resets the opline handler to one of
6943 				 * the "_counter_handler" functions, and these are not registered
6944 				 * tracer functions */
6945 				goto jit_failure;
6946 			}
6947 			if ((zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
6948 			 && !zend_jit_set_ip(&dasm_state, p->opline)) {
6949 				goto jit_failure;
6950 			}
6951 			if (!parent_trace && zend_jit_trace_uses_initial_ip()) {
6952 				t->flags |= ZEND_JIT_TRACE_USES_INITIAL_IP;
6953 			}
6954 			if (parent_trace
6955 			 && (zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_CHECK_INTERRUPT)
6956 			 && zend_jit_traces[parent_trace].root == t->link) {
6957 				if (!(zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)) {
6958 					uint32_t exit_point;
6959 
6960 					for (i = 0; i < op_array->last_var + op_array->T; i++) {
6961 						SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
6962 					}
6963 					exit_point = zend_jit_trace_get_exit_point(zend_jit_traces[t->link].opline, ZEND_JIT_EXIT_TO_VM);
6964 					timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6965 					if (!timeout_exit_addr) {
6966 						goto jit_failure;
6967 					}
6968 				} else {
6969 					timeout_exit_addr = dasm_labels[zend_lbinterrupt_handler];
6970 				}
6971 			}
6972 			zend_jit_trace_link_to_root(&dasm_state, &zend_jit_traces[t->link], timeout_exit_addr);
6973 		} else {
6974 			zend_jit_trace_return(&dasm_state, 0, NULL);
6975 		}
6976 	} else if (p->stop == ZEND_JIT_TRACE_STOP_RETURN) {
6977 		zend_jit_trace_return(&dasm_state, 0, NULL);
6978 	} else {
6979 		// TODO: not implemented ???
6980 		ZEND_ASSERT(0 && p->stop);
6981 	}
6982 
6983 	if (ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
6984 		goto jit_failure;
6985 	}
6986 
6987 	if (!zend_jit_trace_end(&dasm_state, t)) {
6988 		goto jit_failure;
6989 	}
6990 
6991 	handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, ZSTR_VAL(name), ZEND_JIT_TRACE_NUM,
6992 		parent_trace ? SP_ADJ_JIT : ((zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) ? SP_ADJ_VM : SP_ADJ_RET),
6993 		parent_trace ? SP_ADJ_NONE : SP_ADJ_JIT);
6994 
6995 	if (handler) {
6996 		if (p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
6997 			const zend_op_array *rec_op_array;
6998 
6999 			rec_op_array = op_array = trace_buffer->op_array;
7000 			jit_extension =
7001 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7002 			p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
7003 			for (;;p++) {
7004 				if (p->op == ZEND_JIT_TRACE_VM) {
7005 					opline = p->opline;
7006 				} else if (p->op == ZEND_JIT_TRACE_ENTER) {
7007 					if (p->op_array == rec_op_array) {
7008 						zend_jit_trace_setup_ret_counter(opline, jit_extension->offset);
7009 					}
7010 					op_array = p->op_array;
7011 					jit_extension =
7012 						(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7013 				} else if (p->op == ZEND_JIT_TRACE_BACK) {
7014 					op_array = p->op_array;
7015 					jit_extension =
7016 						(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7017 				} else if (p->op == ZEND_JIT_TRACE_END) {
7018 					break;
7019 				}
7020 			}
7021 		} else if (p->stop == ZEND_JIT_TRACE_STOP_LINK
7022 		        || p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
7023 			if (opline
7024 			 && (opline->opcode == ZEND_DO_UCALL
7025 			  || opline->opcode == ZEND_DO_FCALL
7026 			  || opline->opcode == ZEND_DO_FCALL_BY_NAME
7027 			  || opline->opcode == ZEND_YIELD
7028 			  || opline->opcode == ZEND_YIELD_FROM
7029 			  || opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
7030 				zend_jit_trace_setup_ret_counter(opline, jit_extension->offset);
7031 			}
7032 			if (JIT_G(current_frame)
7033 			 && JIT_G(current_frame)->prev) {
7034 				frame = JIT_G(current_frame)->prev;
7035 				do {
7036 					if (frame->call_opline) {
7037 						op_array = &frame->func->op_array;
7038 						jit_extension =
7039 							(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7040 						zend_jit_trace_setup_ret_counter(frame->call_opline, jit_extension->offset);
7041 					}
7042 					frame = frame->prev;
7043 				} while (frame);
7044 			}
7045 		}
7046 	}
7047 
7048 jit_failure:
7049 	dasm_free(&dasm_state);
7050 
7051 	if (name) {
7052 		zend_string_release(name);
7053 	}
7054 
7055 jit_cleanup:
7056 	/* Clean up used op_arrays */
7057 	while (num_op_arrays > 0) {
7058 		op_array = op_arrays[--num_op_arrays];
7059 		jit_extension =
7060 			(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7061 
7062 	    jit_extension->func_info.num = 0;
7063 		jit_extension->func_info.flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
7064 			| ZEND_FUNC_JIT_ON_PROF_REQUEST
7065 			| ZEND_FUNC_JIT_ON_HOT_COUNTERS
7066 			| ZEND_FUNC_JIT_ON_HOT_TRACE;
7067 		memset(&jit_extension->func_info.ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
7068 	}
7069 
7070 	zend_arena_release(&CG(arena), checkpoint);
7071 
7072 	JIT_G(current_frame) = NULL;
7073 	JIT_G(current_trace) = NULL;
7074 
7075 	return handler;
7076 }
7077 
zend_jit_trace_exit_to_vm(uint32_t trace_num,uint32_t exit_num)7078 static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_num)
7079 {
7080 	const void *handler = NULL;
7081 	dasm_State* dasm_state = NULL;
7082 	void *checkpoint;
7083 	char name[32];
7084 	const zend_op *opline;
7085 	uint32_t stack_size;
7086 	zend_jit_trace_stack *stack;
7087 	bool original_handler = 0;
7088 
7089 	if (!zend_jit_trace_exit_needs_deoptimization(trace_num, exit_num)) {
7090 		return dasm_labels[zend_lbtrace_escape];
7091 	}
7092 
7093 	checkpoint = zend_arena_checkpoint(CG(arena));;
7094 
7095 	sprintf(name, "ESCAPE-%d-%d", trace_num, exit_num);
7096 
7097 	dasm_init(&dasm_state, DASM_MAXSECTION);
7098 	dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
7099 	dasm_setup(&dasm_state, dasm_actions);
7100 
7101 	zend_jit_align_func(&dasm_state);
7102 
7103 	/* Deoptimization */
7104 	stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
7105 	stack = zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset;
7106 
7107 	if (!zend_jit_trace_deoptimization(&dasm_state,
7108 			zend_jit_traces[trace_num].exit_info[exit_num].flags,
7109 			zend_jit_traces[trace_num].exit_info[exit_num].opline,
7110 			stack, stack_size, NULL, NULL, NULL, 0)) {
7111 		goto jit_failure;
7112 	}
7113 
7114 	opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
7115 	if (opline) {
7116 		if (opline == zend_jit_traces[zend_jit_traces[trace_num].root].opline) {
7117 			/* prevent endless loop */
7118 			original_handler = 1;
7119 		}
7120 		zend_jit_set_ip_ex(&dasm_state, opline, original_handler);
7121 	}
7122 
7123 	zend_jit_trace_return(&dasm_state, original_handler, opline);
7124 
7125 	handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, name, ZEND_JIT_TRACE_NUM, SP_ADJ_JIT, SP_ADJ_NONE);
7126 
7127 jit_failure:
7128 	dasm_free(&dasm_state);
7129 	zend_arena_release(&CG(arena), checkpoint);
7130 	return handler;
7131 }
7132 
zend_jit_compile_root_trace(zend_jit_trace_rec * trace_buffer,const zend_op * opline,size_t offset)7133 static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace_buffer, const zend_op *opline, size_t offset)
7134 {
7135 	zend_jit_trace_stop ret;
7136 	const void *handler;
7137 	uint8_t orig_trigger;
7138 	zend_jit_trace_info *t = NULL;
7139 	zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
7140 	bool do_bailout = 0;
7141 
7142 	zend_shared_alloc_lock();
7143 
7144 	/* Checks under lock */
7145 	if ((ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_JITED)) {
7146 		ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
7147 	} else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7148 		ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7149 	} else {
7150 		zend_try {
7151 			SHM_UNPROTECT();
7152 			zend_jit_unprotect();
7153 
7154 			t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
7155 
7156 			t->id = ZEND_JIT_TRACE_NUM;
7157 			t->root = ZEND_JIT_TRACE_NUM;
7158 			t->parent = 0;
7159 			t->link = 0;
7160 			t->exit_count = 0;
7161 			t->child_count = 0;
7162 			t->stack_map_size = 0;
7163 			t->flags = 0;
7164 			t->polymorphism = 0;
7165 			t->jmp_table_size = 0;
7166 			t->op_array = trace_buffer[0].op_array;
7167 			t->opline = trace_buffer[1].opline;
7168 			t->exit_info = exit_info;
7169 			t->stack_map = NULL;
7170 
7171 			orig_trigger = JIT_G(trigger);
7172 			JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
7173 
7174 			handler = zend_jit_trace(trace_buffer, 0, 0);
7175 
7176 			JIT_G(trigger) = orig_trigger;
7177 
7178 			if (handler) {
7179 				zend_jit_trace_exit_info *shared_exit_info = NULL;
7180 
7181 				t->exit_info = NULL;
7182 				if (t->exit_count) {
7183 					/* reallocate exit_info into shared memory */
7184 					shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
7185 						sizeof(zend_jit_trace_exit_info) * t->exit_count);
7186 
7187 					if (!shared_exit_info) {
7188 					    if (t->stack_map) {
7189 							efree(t->stack_map);
7190 							t->stack_map = NULL;
7191 						}
7192 						ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7193 						goto exit;
7194 					}
7195 					memcpy(shared_exit_info, exit_info,
7196 						sizeof(zend_jit_trace_exit_info) * t->exit_count);
7197 					t->exit_info = shared_exit_info;
7198 				}
7199 
7200 			    if (t->stack_map_size) {
7201 					zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
7202 					if (!shared_stack_map) {
7203 						efree(t->stack_map);
7204 						ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7205 						goto exit;
7206 					}
7207 					memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
7208 					efree(t->stack_map);
7209 					t->stack_map = shared_stack_map;
7210 			    }
7211 
7212 				t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
7213 				ZEND_JIT_EXIT_COUNTERS += t->exit_count;
7214 
7215 				((zend_op*)opline)->handler = handler;
7216 
7217 				ZEND_JIT_TRACE_NUM++;
7218 				ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_JITED;
7219 
7220 				ret = ZEND_JIT_TRACE_STOP_COMPILED;
7221 			} else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
7222 			           ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
7223 			    if (t->stack_map) {
7224 					efree(t->stack_map);
7225 					t->stack_map = NULL;
7226 				}
7227 				ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
7228 			} else {
7229 			    if (t->stack_map) {
7230 					efree(t->stack_map);
7231 					t->stack_map = NULL;
7232 				}
7233 				ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
7234 			}
7235 
7236 exit:;
7237 		} zend_catch {
7238 			do_bailout = 1;
7239 		} zend_end_try();
7240 
7241 		zend_jit_protect();
7242 		SHM_PROTECT();
7243 	}
7244 
7245 	zend_shared_alloc_unlock();
7246 
7247 	if (do_bailout) {
7248 		zend_bailout();
7249 	}
7250 
7251 	if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
7252 	 && ret == ZEND_JIT_TRACE_STOP_COMPILED
7253 	 && t->exit_count > 0) {
7254 		zend_jit_dump_exit_info(t);
7255 	}
7256 
7257 	return ret;
7258 }
7259 
7260 /* Set counting handler back to original VM handler. */
zend_jit_stop_hot_trace_counters(zend_op_array * op_array)7261 static void zend_jit_stop_hot_trace_counters(zend_op_array *op_array)
7262 {
7263 	zend_jit_op_array_trace_extension *jit_extension;
7264 	uint32_t i;
7265 
7266 	jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7267 	for (i = 0; i < op_array->last; i++) {
7268 		/* Opline with Jit-ed code handler is skipped. */
7269 		if (jit_extension->trace_info[i].trace_flags &
7270 				(ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED)) {
7271 			continue;
7272 		}
7273 		if (jit_extension->trace_info[i].trace_flags &
7274 				(ZEND_JIT_TRACE_START_LOOP | ZEND_JIT_TRACE_START_ENTER | ZEND_JIT_TRACE_START_RETURN)) {
7275 			op_array->opcodes[i].handler = jit_extension->trace_info[i].orig_handler;
7276 		}
7277 	}
7278 }
7279 
7280 /* Get the tracing op_array. */
zend_jit_stop_persistent_op_array(zend_op_array * op_array)7281 static void zend_jit_stop_persistent_op_array(zend_op_array *op_array)
7282 {
7283 	zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
7284 	if (!func_info) {
7285 		return;
7286 	}
7287 	if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_TRACE) {
7288 		zend_jit_stop_hot_trace_counters(op_array);
7289 	}
7290 }
7291 
7292 /* Get all op_arrays with counter handler. */
zend_jit_stop_persistent_script(zend_persistent_script * script)7293 static void zend_jit_stop_persistent_script(zend_persistent_script *script)
7294 {
7295 	zend_class_entry *ce;
7296 	zend_op_array *op_array;
7297 
7298 	zend_jit_stop_persistent_op_array(&script->script.main_op_array);
7299 
7300 	ZEND_HASH_FOREACH_PTR(&script->script.function_table, op_array) {
7301 		zend_jit_stop_persistent_op_array(op_array);
7302 	} ZEND_HASH_FOREACH_END();
7303 
7304 	ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
7305 		ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
7306 			if (op_array->type == ZEND_USER_FUNCTION) {
7307 				zend_jit_stop_persistent_op_array(op_array);
7308 			}
7309 		} ZEND_HASH_FOREACH_END();
7310 	} ZEND_HASH_FOREACH_END();
7311 }
7312 
7313 /* Get all scripts which are accelerated by JIT */
zend_jit_stop_counter_handlers(void)7314 static void zend_jit_stop_counter_handlers(void)
7315 {
7316 	zend_shared_alloc_lock();
7317 	/* mprotect has an extreme overhead, avoid calls to it for every function. */
7318 	SHM_UNPROTECT();
7319 	for (uint32_t i = 0; i < ZCSG(hash).max_num_entries; i++) {
7320 		zend_accel_hash_entry *cache_entry;
7321 		for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
7322 			zend_persistent_script *script;
7323 			if (cache_entry->indirect) continue;
7324 			script = (zend_persistent_script *)cache_entry->data;
7325 			zend_jit_stop_persistent_script(script);
7326 		}
7327 	}
7328 	SHM_PROTECT();
7329 	zend_shared_alloc_unlock();
7330 }
7331 
zend_jit_blacklist_root_trace(const zend_op * opline,size_t offset)7332 static void zend_jit_blacklist_root_trace(const zend_op *opline, size_t offset)
7333 {
7334 	zend_shared_alloc_lock();
7335 
7336 	if (!(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) {
7337 		SHM_UNPROTECT();
7338 		zend_jit_unprotect();
7339 
7340 		((zend_op*)opline)->handler =
7341 			ZEND_OP_TRACE_INFO(opline, offset)->orig_handler;
7342 
7343 		ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_BLACKLISTED;
7344 
7345 		zend_jit_protect();
7346 		SHM_PROTECT();
7347 	}
7348 
7349 	zend_shared_alloc_unlock();
7350 }
7351 
zend_jit_trace_is_bad_root(const zend_op * opline,zend_jit_trace_stop stop,size_t offset)7352 static bool zend_jit_trace_is_bad_root(const zend_op *opline, zend_jit_trace_stop stop, size_t offset)
7353 {
7354 	const zend_op **cache_opline = JIT_G(bad_root_cache_opline);
7355 	uint8_t *cache_count = JIT_G(bad_root_cache_count);
7356 	uint8_t *cache_stop = JIT_G(bad_root_cache_stop);
7357 	uint32_t cache_slot = JIT_G(bad_root_slot);
7358 	uint32_t i;
7359 
7360 	for (i = 0; i < ZEND_JIT_TRACE_BAD_ROOT_SLOTS; i++) {
7361 		if (cache_opline[i] == opline) {
7362 			if (cache_count[i] >= JIT_G(blacklist_root_trace) - 1) {
7363 				cache_opline[i] = NULL;
7364 				return 1;
7365 			} else {
7366 #if 0
7367 				if (ZEND_OP_TRACE_INFO(opline, offset)->counter) {
7368 					*ZEND_OP_TRACE_INFO(opline, offset)->counter =
7369 						random() % ZEND_JIT_TRACE_COUNTER_MAX;
7370 				}
7371 #endif
7372 				cache_count[i]++;
7373 				cache_stop[i] = stop;
7374 				return 0;
7375 			}
7376 		}
7377 	}
7378 	i = cache_slot;
7379 	cache_opline[i] = opline;
7380 	cache_count[i] = 1;
7381 	cache_stop[i] = stop;
7382 	cache_slot = (i + 1) % ZEND_JIT_TRACE_BAD_ROOT_SLOTS;
7383 	JIT_G(bad_root_slot) = cache_slot;
7384 	return 0;
7385 }
7386 
zend_jit_dump_trace(zend_jit_trace_rec * trace_buffer,zend_ssa * tssa)7387 static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa)
7388 {
7389 	zend_jit_trace_rec *p = trace_buffer;
7390 	const zend_op_array *op_array;
7391 	const zend_op *opline;
7392 	uint32_t level = 1 + trace_buffer[0].level;
7393 	int idx, len, i, v, vars_count, call_level;
7394 
7395 	ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
7396 	op_array = p->op_array;
7397 	p += ZEND_JIT_TRACE_START_REC_SIZE;
7398 	idx = 0;
7399 	call_level = 0;
7400 
7401 	if (tssa && tssa->var_info) {
7402 		if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
7403 			vars_count = op_array->last_var;
7404 		} else {
7405 			vars_count = op_array->last_var + op_array->T;
7406 		}
7407 		for (i = 0; i < vars_count; i++) {
7408 			if (tssa->vars[i].use_chain >= 0 || tssa->vars[i].phi_use_chain) {
7409 				fprintf(stderr, "    %*c;", level, ' ');
7410 				zend_dump_ssa_var(op_array, tssa, i, 0, i, ZEND_DUMP_RC_INFERENCE);
7411 				fprintf(stderr, "\n");
7412 			}
7413 		}
7414 		if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
7415 		 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
7416 		 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7417 			zend_ssa_phi *p = tssa->blocks[1].phis;
7418 
7419 			fprintf(stderr, "LOOP:\n");
7420 
7421 			while (p) {
7422 				fprintf(stderr, "     ;");
7423 				zend_dump_ssa_var(op_array, tssa, p->ssa_var, 0, p->var, ZEND_DUMP_RC_INFERENCE);
7424 				fprintf(stderr, " = Phi(");
7425 				zend_dump_ssa_var(op_array, tssa, p->sources[0], 0, p->var, ZEND_DUMP_RC_INFERENCE);
7426 				fprintf(stderr, ", ");
7427 				zend_dump_ssa_var(op_array, tssa, p->sources[1], 0, p->var, ZEND_DUMP_RC_INFERENCE);
7428 				fprintf(stderr, ")\n");
7429 				p = p->next;
7430 			}
7431 		}
7432 	}
7433 
7434 	while (1) {
7435 		if (p->op == ZEND_JIT_TRACE_VM) {
7436 			uint8_t op1_type, op2_type, op3_type;
7437 
7438 			opline = p->opline;
7439 			fprintf(stderr, "%04d%*c",
7440 				(int)(opline - op_array->opcodes),
7441 				level, ' ');
7442 			zend_dump_op(op_array, NULL, opline, ZEND_DUMP_RC_INFERENCE, tssa, (tssa && tssa->ops) ? tssa->ops + idx : NULL);
7443 
7444 			op1_type = p->op1_type;
7445 			op2_type = p->op2_type;
7446 			op3_type = p->op3_type;
7447 			if (op1_type != IS_UNKNOWN || op2_type != IS_UNKNOWN || op3_type != IS_UNKNOWN) {
7448 				fprintf(stderr, " ;");
7449 				if (op1_type != IS_UNKNOWN) {
7450 					const char *ref = (op1_type & IS_TRACE_INDIRECT) ?
7451 						((op1_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7452 						((op1_type & IS_TRACE_REFERENCE) ? "&" : "");
7453 					if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
7454 						p++;
7455 						fprintf(stderr, " op1(%sobject of class %s)", ref,
7456 							ZSTR_VAL(p->ce->name));
7457 					} else {
7458 						const char *type = ((op1_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
7459 						fprintf(stderr, " op1(%s%s%s)", ref, (op1_type & IS_TRACE_PACKED) ? "packed " : "", type);
7460 					}
7461 				}
7462 				if (op2_type != IS_UNKNOWN) {
7463 					const char *ref = (op2_type & IS_TRACE_INDIRECT) ?
7464 						((op2_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7465 						((op2_type & IS_TRACE_REFERENCE) ? "&" : "");
7466 					if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
7467 						p++;
7468 						fprintf(stderr, " op2(%sobject of class %s)", ref,
7469 							ZSTR_VAL(p->ce->name));
7470 					} else {
7471 						const char *type = ((op2_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT));
7472 						fprintf(stderr, " op2(%s%s)", ref, type);
7473 					}
7474 				}
7475 				if (op3_type != IS_UNKNOWN) {
7476 					const char *ref = (op3_type & IS_TRACE_INDIRECT) ?
7477 						((op3_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7478 						((op3_type & IS_TRACE_REFERENCE) ? "&" : "");
7479 					const char *type = ((op3_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op3_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT));
7480 					fprintf(stderr, " op3(%s%s)", ref, type);
7481 				}
7482 			}
7483 			if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
7484 				uint8_t val_type;
7485 				const char *type;
7486 
7487 				if (op1_type == IS_UNKNOWN && op2_type == IS_UNKNOWN && op3_type == IS_UNKNOWN) {
7488 					fprintf(stderr, " ;");
7489 				}
7490 				p++;
7491 				val_type = p->op1_type;
7492 
7493 				if (val_type == IS_UNDEF) {
7494 					type = "undef";
7495 				} else if (val_type == IS_REFERENCE) {
7496 					type = "ref";
7497 				} else {
7498 					type = zend_get_type_by_const(val_type);
7499 				}
7500 				fprintf(stderr, " val(%s)", type);
7501 			}
7502 			fprintf(stderr, "\n");
7503 			idx++;
7504 
7505 			len = zend_jit_trace_op_len(opline);
7506 			while (len > 1) {
7507 				opline++;
7508 				fprintf(stderr, "%04d%*c;",
7509 					(int)(opline - op_array->opcodes),
7510 					level, ' ');
7511 				zend_dump_op(op_array, NULL, opline, ZEND_DUMP_RC_INFERENCE, tssa, (tssa && tssa->ops) ? tssa->ops + idx : NULL);
7512 				idx++;
7513 				len--;
7514 				fprintf(stderr, "\n");
7515 			}
7516 		} else if (p->op == ZEND_JIT_TRACE_ENTER) {
7517 			op_array = p->op_array;
7518 			fprintf(stderr, "    %*c>enter %s%s%s\n",
7519 				level, ' ',
7520 				op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7521 				op_array->scope ? "::" : "",
7522 				op_array->function_name ?
7523 					ZSTR_VAL(op_array->function_name) :
7524 					ZSTR_VAL(op_array->filename));
7525 			level++;
7526 			if (tssa && tssa->var_info) {
7527 				call_level++;
7528 				v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7529 				vars_count = op_array->last_var;
7530 				for (i = 0; i < vars_count; i++, v++) {
7531 					if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
7532 						fprintf(stderr, "    %*c;", level, ' ');
7533 						zend_dump_ssa_var(op_array, tssa, v, 0, i, ZEND_DUMP_RC_INFERENCE);
7534 						fprintf(stderr, "\n");
7535 					}
7536 				}
7537 			}
7538 		} else if (p->op == ZEND_JIT_TRACE_BACK) {
7539 			op_array = p->op_array;
7540 			level--;
7541 			fprintf(stderr, "    %*c<back %s%s%s\n",
7542 				level, ' ',
7543 				op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7544 				op_array->scope ? "::" : "",
7545 				op_array->function_name ?
7546 					ZSTR_VAL(op_array->function_name) :
7547 					ZSTR_VAL(op_array->filename));
7548 			if (tssa && tssa->var_info) {
7549 				if (call_level == 0) {
7550 					v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7551 					vars_count = op_array->last_var + op_array->T;
7552 					for (i = 0; i < vars_count; i++, v++) {
7553 						if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
7554 							fprintf(stderr, "    %*c;", level, ' ');
7555 							zend_dump_ssa_var(op_array, tssa, v, 0, i, ZEND_DUMP_RC_INFERENCE);
7556 							fprintf(stderr, "\n");
7557 						}
7558 					}
7559 				} else {
7560 					call_level--;
7561 				}
7562 			}
7563 		} else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
7564 			if (p->func != (zend_function*)&zend_pass_function) {
7565 				fprintf(stderr, (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) ? "    %*c>fake_init %s%s%s\n" : "    %*c>init %s%s%s\n",
7566 					level, ' ',
7567 					(p->func && p->func->common.scope) ? ZSTR_VAL(p->func->common.scope->name) : "",
7568 					(p->func && p->func->common.scope) ? "::" : "",
7569 					p->func ? ZSTR_VAL(p->func->common.function_name) : "???");
7570 			} else {
7571 				fprintf(stderr, "    %*c>skip\n",
7572 					level, ' ');
7573 			}
7574 		} else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
7575 			if (p->func != (zend_function*)&zend_pass_function) {
7576 				fprintf(stderr, "    %*c>call %s%s%s\n",
7577 					level, ' ',
7578 					p->func->common.scope ? ZSTR_VAL(p->func->common.scope->name) : "",
7579 					p->func->common.scope ? "::" : "",
7580 					ZSTR_VAL(p->func->common.function_name));
7581 			} else {
7582 				fprintf(stderr, "    %*c>skip\n",
7583 					level, ' ');
7584 			}
7585 		} else if (p->op == ZEND_JIT_TRACE_END) {
7586 			break;
7587 		}
7588 		p++;
7589 	}
7590 }
7591 
zend_jit_dump_exit_info(zend_jit_trace_info * t)7592 static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
7593 {
7594 	int i, j;
7595 
7596 	fprintf(stderr, "---- TRACE %d exit info\n", t->id);
7597 	for (i = 0; i < t->exit_count; i++) {
7598 		const zend_op_array *op_array = t->exit_info[i].op_array;
7599 		uint32_t stack_size = t->exit_info[i].stack_size;
7600 		zend_jit_trace_stack *stack = t->stack_map + t->exit_info[i].stack_offset;
7601 
7602 		fprintf(stderr, "     exit_%d:", i);
7603 		if (t->exit_info[i].opline) {
7604 			fprintf(stderr, " %04d/", (int)(t->exit_info[i].opline - op_array->opcodes));
7605 		} else {
7606 			fprintf(stderr, " ----/");
7607 		}
7608 		if (t->exit_info[i].stack_size) {
7609 			fprintf(stderr, "%04d/%d", t->exit_info[i].stack_offset, t->exit_info[i].stack_size);
7610 		} else {
7611 			fprintf(stderr, "----/0");
7612 		}
7613 		if (t->exit_info[i].flags & ZEND_JIT_EXIT_TO_VM) {
7614 			fprintf(stderr, "/VM");
7615 		}
7616 		if (t->exit_info[i].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7617 			fprintf(stderr, "/CALL");
7618 		}
7619 		if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL)) {
7620 			fprintf(stderr, "/POLY");
7621 		}
7622 		if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) {
7623 			fprintf(stderr, "/FREE_OP1");
7624 		}
7625 		if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP2) {
7626 			fprintf(stderr, "/FREE_OP2");
7627 		}
7628 		for (j = 0; j < stack_size; j++) {
7629 			zend_uchar type = STACK_TYPE(stack, j);
7630 			if (type != IS_UNKNOWN) {
7631 				fprintf(stderr, " ");
7632 				zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
7633 				fprintf(stderr, ":");
7634 				if (type == IS_UNDEF) {
7635 					fprintf(stderr, "undef");
7636 				} else {
7637 					fprintf(stderr, "%s", zend_get_type_by_const(type));
7638 				}
7639 				if (STACK_REG(stack, j) != ZREG_NONE) {
7640 					if (STACK_REG(stack, j) < ZREG_NUM) {
7641 						fprintf(stderr, "(%s)", zend_reg_name[STACK_REG(stack, j)]);
7642 					} else if (STACK_REG(stack, j) == ZREG_THIS) {
7643 						fprintf(stderr, "(this)");
7644 					} else if (STACK_REG(stack, j) == ZREG_ZVAL_TRY_ADDREF) {
7645 						fprintf(stderr, "(zval_try_addref)");
7646 					} else {
7647 						fprintf(stderr, "(const_%d)", STACK_REG(stack, j) - ZREG_NUM);
7648 					}
7649 				}
7650 			} else if (STACK_REG(stack, j) == ZREG_ZVAL_TRY_ADDREF) {
7651 				fprintf(stderr, " ");
7652 				zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
7653 				fprintf(stderr, ":unknown(zval_try_addref)");
7654 			} else if (STACK_REG(stack, j) == ZREG_ZVAL_COPY_GPR0) {
7655 				fprintf(stderr, " ");
7656 				zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
7657 				fprintf(stderr, ":unknown(zval_copy(%s))", zend_reg_name[ZREG_COPY]);
7658 			}
7659 		}
7660 		fprintf(stderr, "\n");
7661 	}
7662 }
7663 
zend_jit_trace_hot_root(zend_execute_data * execute_data,const zend_op * opline)7664 int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline)
7665 {
7666 	const zend_op *orig_opline;
7667 	zend_jit_trace_stop stop;
7668 	int ret = 0;
7669 	zend_op_array *op_array;
7670 	zend_jit_op_array_trace_extension *jit_extension;
7671 	size_t offset;
7672 	uint32_t trace_num;
7673 	zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
7674 
7675 	ZEND_ASSERT(EX(func)->type == ZEND_USER_FUNCTION);
7676 	ZEND_ASSERT(opline >= EX(func)->op_array.opcodes &&
7677 		opline < EX(func)->op_array.opcodes + EX(func)->op_array.last);
7678 
7679 repeat:
7680 	trace_num = ZEND_JIT_TRACE_NUM;
7681 	orig_opline = opline;
7682 	op_array = &EX(func)->op_array;
7683 	jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7684 	offset = jit_extension->offset;
7685 
7686 	EX(opline) = opline;
7687 
7688 	/* Lock-free check if the root trace was already JIT-ed or blacklist-ed in another process */
7689 	if (ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED)) {
7690 		return 0;
7691 	}
7692 
7693 	if (JIT_G(tracing)) {
7694 		++(*ZEND_OP_TRACE_INFO(opline, offset)->counter);
7695 		return 0;
7696 	}
7697 
7698 	if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
7699 		fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
7700 			trace_num,
7701 			zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
7702 			EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
7703 			EX(func)->op_array.scope ? "::" : "",
7704 			EX(func)->op_array.function_name ?
7705 				ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
7706 			ZSTR_VAL(EX(func)->op_array.filename),
7707 			opline->lineno);
7708 	}
7709 
7710 	if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7711 		stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7712 		zend_jit_stop_counter_handlers();
7713 		goto abort;
7714 	}
7715 
7716 	JIT_G(tracing) = 1;
7717 	stop = zend_jit_trace_execute(execute_data, opline, trace_buffer,
7718 		ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_START_MASK, 0);
7719 	JIT_G(tracing) = 0;
7720 
7721 	if (stop & ZEND_JIT_TRACE_HALT) {
7722 		ret = -1;
7723 	}
7724 	stop &= ~ZEND_JIT_TRACE_HALT;
7725 
7726 	if (UNEXPECTED(trace_buffer[1].opline != orig_opline)) {
7727 		orig_opline = trace_buffer[1].opline;
7728 		op_array = (zend_op_array*)trace_buffer[0].op_array;
7729 		jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7730 		offset = jit_extension->offset;
7731 		if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
7732 			const zend_op_array *op_array = trace_buffer[0].op_array;
7733 			const zend_op *opline = trace_buffer[1].opline;
7734 			zend_jit_op_array_trace_extension *jit_extension =
7735 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7736 			size_t offset = jit_extension->offset;
7737 
7738 			fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
7739 				trace_num,
7740 				zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
7741 				op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7742 				op_array->scope ? "::" : "",
7743 				op_array->function_name ?
7744 					ZSTR_VAL(op_array->function_name) : "$main",
7745 				ZSTR_VAL(op_array->filename),
7746 				opline->lineno);
7747 		}
7748 	}
7749 
7750 	if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BYTECODE)) {
7751 		zend_jit_dump_trace(trace_buffer, NULL);
7752 	}
7753 
7754 	if (ZEND_JIT_TRACE_STOP_OK(stop)) {
7755 		if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_STOP) {
7756 			if (stop == ZEND_JIT_TRACE_STOP_LINK) {
7757 				uint32_t idx = trace_buffer[1].last;
7758 				uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
7759 				fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
7760 					trace_num,
7761 					link_to);
7762 			} else {
7763 				fprintf(stderr, "---- TRACE %d stop (%s)\n",
7764 					trace_num,
7765 					zend_jit_trace_stop_description[stop]);
7766 			}
7767 		}
7768 		stop = zend_jit_compile_root_trace(trace_buffer, orig_opline, offset);
7769 		if (EXPECTED(ZEND_JIT_TRACE_STOP_DONE(stop))) {
7770 			if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_COMPILED) {
7771 				fprintf(stderr, "---- TRACE %d %s\n",
7772 					trace_num,
7773 					zend_jit_trace_stop_description[stop]);
7774 			}
7775 		} else {
7776 			goto abort;
7777 		}
7778 	} else {
7779 abort:
7780 		if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_ABORT) {
7781 			fprintf(stderr, "---- TRACE %d abort (%s)\n",
7782 				trace_num,
7783 				zend_jit_trace_stop_description[stop]);
7784 		}
7785 		if (!ZEND_JIT_TRACE_STOP_MAY_RECOVER(stop)
7786 		 || zend_jit_trace_is_bad_root(orig_opline, stop, offset)) {
7787 			if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
7788 				fprintf(stderr, "---- TRACE %d blacklisted\n",
7789 					trace_num);
7790 			}
7791 			zend_jit_blacklist_root_trace(orig_opline, offset);
7792 		}
7793 		if (ZEND_JIT_TRACE_STOP_REPEAT(stop)) {
7794 			execute_data = EG(current_execute_data);
7795 			opline = EX(opline);
7796 			goto repeat;
7797 		}
7798 	}
7799 
7800 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_TRACE_STOP|ZEND_JIT_DEBUG_TRACE_ABORT|ZEND_JIT_DEBUG_TRACE_COMPILED|ZEND_JIT_DEBUG_TRACE_BLACKLIST)) {
7801 		fprintf(stderr, "\n");
7802 	}
7803 
7804 	return ret;
7805 }
7806 
zend_jit_blacklist_trace_exit(uint32_t trace_num,uint32_t exit_num)7807 static void zend_jit_blacklist_trace_exit(uint32_t trace_num, uint32_t exit_num)
7808 {
7809 	const void *handler;
7810 	bool do_bailout = 0;
7811 
7812 	zend_shared_alloc_lock();
7813 
7814 	if (!(zend_jit_traces[trace_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED))) {
7815 		SHM_UNPROTECT();
7816 		zend_jit_unprotect();
7817 
7818 		zend_try {
7819 			handler = zend_jit_trace_exit_to_vm(trace_num, exit_num);
7820 
7821 			if (handler) {
7822 				zend_jit_link_side_trace(
7823 					zend_jit_traces[trace_num].code_start,
7824 					zend_jit_traces[trace_num].code_size,
7825 					zend_jit_traces[trace_num].jmp_table_size,
7826 					exit_num,
7827 					handler);
7828 			}
7829 			zend_jit_traces[trace_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_BLACKLISTED;
7830 		} zend_catch {
7831 			do_bailout = 1;
7832 		} zend_end_try();
7833 
7834 		zend_jit_protect();
7835 		SHM_PROTECT();
7836 	}
7837 
7838 	zend_shared_alloc_unlock();
7839 
7840 	if (do_bailout) {
7841 		zend_bailout();
7842 	}
7843 }
7844 
zend_jit_trace_exit_is_bad(uint32_t trace_num,uint32_t exit_num)7845 static bool zend_jit_trace_exit_is_bad(uint32_t trace_num, uint32_t exit_num)
7846 {
7847 	uint8_t *counter = JIT_G(exit_counters) +
7848 		zend_jit_traces[trace_num].exit_counters + exit_num;
7849 
7850 	if (*counter + 1 >= JIT_G(hot_side_exit) + JIT_G(blacklist_side_trace)) {
7851 		return 1;
7852 	}
7853 	(*counter)++;
7854 	return 0;
7855 }
7856 
zend_jit_trace_exit_is_hot(uint32_t trace_num,uint32_t exit_num)7857 static bool zend_jit_trace_exit_is_hot(uint32_t trace_num, uint32_t exit_num)
7858 {
7859 	uint8_t *counter = JIT_G(exit_counters) +
7860 		zend_jit_traces[trace_num].exit_counters + exit_num;
7861 
7862 	if (*counter + 1 >= JIT_G(hot_side_exit)) {
7863 		return 1;
7864 	}
7865 	(*counter)++;
7866 	return 0;
7867 }
7868 
zend_jit_compile_side_trace(zend_jit_trace_rec * trace_buffer,uint32_t parent_num,uint32_t exit_num,uint32_t polymorphism)7869 static zend_jit_trace_stop zend_jit_compile_side_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_num, uint32_t exit_num, uint32_t polymorphism)
7870 {
7871 	zend_jit_trace_stop ret;
7872 	const void *handler;
7873 	uint8_t orig_trigger;
7874 	zend_jit_trace_info *t;
7875 	zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
7876 	bool do_bailout = 0;
7877 
7878 	zend_shared_alloc_lock();
7879 
7880 	/* Checks under lock */
7881 	if (zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
7882 		ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
7883 	} else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7884 		ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7885 	} else if (zend_jit_traces[zend_jit_traces[parent_num].root].child_count >= JIT_G(max_side_traces)) {
7886 		ret = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
7887 	} else {
7888 		SHM_UNPROTECT();
7889 		zend_jit_unprotect();
7890 
7891 		zend_try {
7892 			t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
7893 
7894 			t->id = ZEND_JIT_TRACE_NUM;
7895 			t->root = zend_jit_traces[parent_num].root;
7896 			t->parent = parent_num;
7897 			t->link = 0;
7898 			t->exit_count = 0;
7899 			t->child_count = 0;
7900 			t->stack_map_size = 0;
7901 			t->flags = 0;
7902 			t->polymorphism = polymorphism;
7903 			t->jmp_table_size = 0;
7904 			t->opline = NULL;
7905 			t->exit_info = exit_info;
7906 			t->stack_map = NULL;
7907 
7908 			orig_trigger = JIT_G(trigger);
7909 			JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
7910 
7911 			handler = zend_jit_trace(trace_buffer, parent_num, exit_num);
7912 
7913 			JIT_G(trigger) = orig_trigger;
7914 
7915 			if (handler) {
7916 				zend_jit_trace_exit_info *shared_exit_info = NULL;
7917 
7918 				t->exit_info = NULL;
7919 				if (t->exit_count) {
7920 					/* reallocate exit_info into shared memory */
7921 					shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
7922 						sizeof(zend_jit_trace_exit_info) * t->exit_count);
7923 
7924 					if (!shared_exit_info) {
7925 						if (t->stack_map) {
7926 							efree(t->stack_map);
7927 							t->stack_map = NULL;
7928 						}
7929 						ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7930 						goto exit;
7931 					}
7932 					memcpy(shared_exit_info, exit_info,
7933 						sizeof(zend_jit_trace_exit_info) * t->exit_count);
7934 					t->exit_info = shared_exit_info;
7935 				}
7936 
7937 				if (t->stack_map_size) {
7938 					zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
7939 					if (!shared_stack_map) {
7940 						efree(t->stack_map);
7941 						ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7942 						goto exit;
7943 					}
7944 					memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
7945 					efree(t->stack_map);
7946 					t->stack_map = shared_stack_map;
7947 			    }
7948 
7949 				zend_jit_link_side_trace(
7950 					zend_jit_traces[parent_num].code_start,
7951 					zend_jit_traces[parent_num].code_size,
7952 					zend_jit_traces[parent_num].jmp_table_size,
7953 					exit_num,
7954 					handler);
7955 
7956 				t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
7957 				ZEND_JIT_EXIT_COUNTERS += t->exit_count;
7958 
7959 				zend_jit_traces[zend_jit_traces[parent_num].root].child_count++;
7960 				ZEND_JIT_TRACE_NUM++;
7961 				zend_jit_traces[parent_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_JITED;
7962 
7963 				ret = ZEND_JIT_TRACE_STOP_COMPILED;
7964 			} else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
7965 			           ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
7966 			    if (t->stack_map) {
7967 					efree(t->stack_map);
7968 					t->stack_map = NULL;
7969 				}
7970 				ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
7971 			} else {
7972 				if (t->stack_map) {
7973 					efree(t->stack_map);
7974 					t->stack_map = NULL;
7975 				}
7976 				ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
7977 			}
7978 
7979 exit:;
7980 		} zend_catch {
7981 			do_bailout = 1;
7982 		}  zend_end_try();
7983 
7984 		zend_jit_protect();
7985 		SHM_PROTECT();
7986 	}
7987 
7988 	zend_shared_alloc_unlock();
7989 
7990 	if (do_bailout) {
7991 		zend_bailout();
7992 	}
7993 
7994 	if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
7995 	 && ret == ZEND_JIT_TRACE_STOP_COMPILED
7996 	 && t->exit_count > 0) {
7997 		zend_jit_dump_exit_info(t);
7998 	}
7999 
8000 	return ret;
8001 }
8002 
zend_jit_trace_hot_side(zend_execute_data * execute_data,uint32_t parent_num,uint32_t exit_num)8003 int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint32_t parent_num, uint32_t exit_num)
8004 {
8005 	zend_jit_trace_stop stop;
8006 	int ret = 0;
8007 	uint32_t trace_num;
8008 	zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
8009 	uint32_t is_megamorphic = 0;
8010 	uint32_t polymorphism = 0;
8011 
8012 	trace_num = ZEND_JIT_TRACE_NUM;
8013 
8014 	/* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
8015 	if (zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
8016 		return 0;
8017 	}
8018 
8019 	if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8020 		fprintf(stderr, "---- TRACE %d start (side trace %d/%d) %s%s%s() %s:%d\n",
8021 			trace_num, parent_num, exit_num,
8022 			EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
8023 			EX(func)->op_array.scope ? "::" : "",
8024 			EX(func)->op_array.function_name ?
8025 				ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
8026 			ZSTR_VAL(EX(func)->op_array.filename),
8027 			EX(opline)->lineno);
8028 	}
8029 
8030 	if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8031 		stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8032 		goto abort;
8033 	}
8034 
8035 	if (zend_jit_traces[zend_jit_traces[parent_num].root].child_count >= JIT_G(max_side_traces)) {
8036 		stop = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
8037 		goto abort;
8038 	}
8039 
8040 	if (JIT_G(max_polymorphic_calls) > 0) {
8041 		if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL))
8042 		 || ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)
8043 		  && EX(call))) {
8044 			if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
8045 				is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
8046 					(ZEND_JIT_EXIT_METHOD_CALL | ZEND_JIT_EXIT_CLOSURE_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
8047 			} else if (!zend_jit_traces[parent_num].polymorphism) {
8048 				polymorphism = 1;
8049 			} else if (exit_num == 0) {
8050 				polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
8051 			}
8052 		}
8053 	}
8054 
8055 	JIT_G(tracing) = 1;
8056 	stop = zend_jit_trace_execute(execute_data, EX(opline), trace_buffer, ZEND_JIT_TRACE_START_SIDE, is_megamorphic);
8057 	JIT_G(tracing) = 0;
8058 
8059 	if (stop & ZEND_JIT_TRACE_HALT) {
8060 		ret = -1;
8061 	}
8062 	stop &= ~ZEND_JIT_TRACE_HALT;
8063 
8064 	if (UNEXPECTED(trace_buffer->start != ZEND_JIT_TRACE_START_SIDE)) {
8065 		if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8066 			const zend_op_array *op_array = trace_buffer[0].op_array;
8067 			const zend_op *opline = trace_buffer[1].opline;
8068 			zend_jit_op_array_trace_extension *jit_extension =
8069 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8070 			size_t offset = jit_extension->offset;
8071 
8072 			fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8073 				trace_num,
8074 				zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
8075 				op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
8076 				op_array->scope ? "::" : "",
8077 				op_array->function_name ?
8078 					ZSTR_VAL(op_array->function_name) : "$main",
8079 				ZSTR_VAL(op_array->filename),
8080 				opline->lineno);
8081 		}
8082 	}
8083 
8084 	if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BYTECODE)) {
8085 		zend_jit_dump_trace(trace_buffer, NULL);
8086 	}
8087 
8088 	if (ZEND_JIT_TRACE_STOP_OK(stop)) {
8089 		if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_STOP) {
8090 			if (stop == ZEND_JIT_TRACE_STOP_LINK) {
8091 				uint32_t idx = trace_buffer[1].last;
8092 				uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);;
8093 				fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
8094 					trace_num,
8095 					link_to);
8096 			} else {
8097 				fprintf(stderr, "---- TRACE %d stop (%s)\n",
8098 					trace_num,
8099 					zend_jit_trace_stop_description[stop]);
8100 			}
8101 		}
8102 		if (EXPECTED(trace_buffer->start == ZEND_JIT_TRACE_START_SIDE)) {
8103 			stop = zend_jit_compile_side_trace(trace_buffer, parent_num, exit_num, polymorphism);
8104 		} else {
8105 			const zend_op_array *op_array = trace_buffer[0].op_array;
8106 			zend_jit_op_array_trace_extension *jit_extension =
8107 				(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8108 			const zend_op *opline = trace_buffer[1].opline;
8109 
8110 			stop = zend_jit_compile_root_trace(trace_buffer, opline, jit_extension->offset);
8111 		}
8112 		if (EXPECTED(ZEND_JIT_TRACE_STOP_DONE(stop))) {
8113 			if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_COMPILED) {
8114 				fprintf(stderr, "---- TRACE %d %s\n",
8115 					trace_num,
8116 					zend_jit_trace_stop_description[stop]);
8117 			}
8118 		} else {
8119 			goto abort;
8120 		}
8121 	} else {
8122 abort:
8123 		if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_ABORT) {
8124 			fprintf(stderr, "---- TRACE %d abort (%s)\n",
8125 				trace_num,
8126 				zend_jit_trace_stop_description[stop]);
8127 		}
8128 		if (!ZEND_JIT_TRACE_STOP_MAY_RECOVER(stop)
8129 		 || zend_jit_trace_exit_is_bad(parent_num, exit_num)) {
8130 			zend_jit_blacklist_trace_exit(parent_num, exit_num);
8131 			if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8132 				fprintf(stderr, "---- EXIT %d/%d blacklisted\n",
8133 					parent_num, exit_num);
8134 			}
8135 		}
8136 		if (ZEND_JIT_TRACE_STOP_REPEAT(stop)) {
8137 			execute_data = EG(current_execute_data);
8138 			return zend_jit_trace_hot_root(execute_data, EX(opline));
8139 		}
8140 	}
8141 
8142 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_TRACE_STOP|ZEND_JIT_DEBUG_TRACE_ABORT|ZEND_JIT_DEBUG_TRACE_COMPILED|ZEND_JIT_DEBUG_TRACE_BLACKLIST)) {
8143 		fprintf(stderr, "\n");
8144 	}
8145 
8146 	return ret;
8147 }
8148 
zend_jit_trace_exit(uint32_t exit_num,zend_jit_registers_buf * regs)8149 int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs)
8150 {
8151 	uint32_t trace_num = EG(jit_trace_num);
8152 	zend_execute_data *execute_data = EG(current_execute_data);
8153 	const zend_op *orig_opline = EX(opline);
8154 	const zend_op *opline;
8155 	zend_jit_trace_info *t = &zend_jit_traces[trace_num];
8156 	int repeat_last_opline = 0;
8157 
8158 	/* Deoptimization of VM stack state */
8159 	uint32_t i;
8160 	uint32_t stack_size = t->exit_info[exit_num].stack_size;
8161 	zend_jit_trace_stack *stack = t->stack_map + t->exit_info[exit_num].stack_offset;
8162 
8163 	if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
8164 		zend_execute_data *call = (zend_execute_data *)regs->gpr[ZREG_RX];
8165 		call->prev_execute_data = EX(call);
8166 		EX(call) = call;
8167 	}
8168 
8169 	for (i = 0; i < stack_size; i++) {
8170 		if (STACK_REG(stack, i) != ZREG_NONE) {
8171 			if (STACK_TYPE(stack, i) == IS_LONG) {
8172 				zend_long val;
8173 
8174 				if (STACK_REG(stack, i) < ZREG_NUM) {
8175 					val = regs->gpr[STACK_REG(stack, i)];
8176 				} else if (STACK_REG(stack, i) == ZREG_LONG_MIN) {
8177 					val = ZEND_LONG_MIN;
8178 				} else if (STACK_REG(stack, i) == ZREG_LONG_MAX) {
8179 					val = ZEND_LONG_MAX;
8180 				} else {
8181 					ZEND_UNREACHABLE();
8182 				}
8183 				ZVAL_LONG(EX_VAR_NUM(i), val);
8184 			} else if (STACK_TYPE(stack, i) == IS_DOUBLE) {
8185 				double val;
8186 
8187 				if (STACK_REG(stack, i) < ZREG_NUM) {
8188 					val = regs->fpr[STACK_REG(stack, i) - ZREG_FIRST_FPR];
8189 				} else if (STACK_REG(stack, i) == ZREG_LONG_MIN_MINUS_1) {
8190 					val = (double)ZEND_LONG_MIN - 1.0;
8191 				} else if (STACK_REG(stack, i) == ZREG_LONG_MAX_PLUS_1) {
8192 					val = (double)ZEND_LONG_MAX + 1.0;
8193 				} else {
8194 					ZEND_UNREACHABLE();
8195 				}
8196 				ZVAL_DOUBLE(EX_VAR_NUM(i), val);
8197 			} else if (STACK_REG(stack, i) == ZREG_THIS) {
8198 				zend_object *obj = Z_OBJ(EX(This));
8199 
8200 				GC_ADDREF(obj);
8201 				ZVAL_OBJ(EX_VAR_NUM(i), obj);
8202 			} else if (STACK_REG(stack, i) == ZREG_NULL) {
8203 				ZVAL_NULL(EX_VAR_NUM(i));
8204 			} else if (STACK_REG(stack, i) == ZREG_ZVAL_TRY_ADDREF) {
8205 				Z_TRY_ADDREF_P(EX_VAR_NUM(i));
8206 			} else if (STACK_REG(stack, i) == ZREG_ZVAL_COPY_GPR0) {
8207 				zval *val = (zval*)regs->gpr[ZREG_COPY];
8208 
8209 				if (UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
8210 					/* Undefined array index or property */
8211 					repeat_last_opline = 1;
8212 				} else {
8213 					ZVAL_COPY(EX_VAR_NUM(i), val);
8214 				}
8215 			} else {
8216 				ZEND_UNREACHABLE();
8217 			}
8218 		}
8219 	}
8220 
8221 	if (repeat_last_opline) {
8222 		EX(opline) = t->exit_info[exit_num].opline - 1;
8223 		if ((EX(opline)->op1_type & (IS_VAR|IS_TMP_VAR))
8224 		 && !(t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1)
8225 		 && EX(opline)->opcode != ZEND_FETCH_LIST_R) {
8226 			Z_TRY_ADDREF_P(EX_VAR(EX(opline)->op1.var));
8227 		}
8228 		return 1;
8229 	}
8230 
8231 	opline = t->exit_info[exit_num].opline;
8232 
8233 	if (opline) {
8234 		if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP2) {
8235 			ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R
8236 					|| (opline-1)->opcode == ZEND_FETCH_DIM_IS
8237 					|| (opline-1)->opcode == ZEND_FETCH_LIST_R
8238 					|| (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG);
8239 			EX(opline) = opline-1;
8240 			zval_ptr_dtor_nogc(EX_VAR((opline-1)->op2.var));
8241 		}
8242 		if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) {
8243 			ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R
8244 					|| (opline-1)->opcode == ZEND_FETCH_DIM_IS
8245 					|| (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG
8246 					|| (opline-1)->opcode == ZEND_FETCH_OBJ_R
8247 					|| (opline-1)->opcode == ZEND_FETCH_OBJ_IS
8248 					|| (opline-1)->opcode == ZEND_FETCH_OBJ_FUNC_ARG);
8249 			EX(opline) = opline-1;
8250 			zval_ptr_dtor_nogc(EX_VAR((opline-1)->op1.var));
8251 		}
8252 		if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) {
8253 			if (EG(exception)) {
8254 				return 1;
8255 			}
8256 		}
8257 		if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
8258 			zend_function *func = (zend_function*)regs->gpr[ZREG_COPY];
8259 
8260 			if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
8261 				zend_string_release_ex(func->common.function_name, 0);
8262 				zend_free_trampoline(func);
8263 				EX(opline) = opline;
8264 				return 1;
8265 			}
8266 		}
8267 
8268 		/* Set VM opline to continue interpretation */
8269 		EX(opline) = opline;
8270 	}
8271 
8272 	if (zend_atomic_bool_load_ex(&EG(vm_interrupt)) || JIT_G(tracing)) {
8273 		return 1;
8274 	/* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
8275 	} else if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
8276 		return 0;
8277 	}
8278 
8279 	ZEND_ASSERT(EX(func)->type == ZEND_USER_FUNCTION);
8280 	ZEND_ASSERT(EX(opline) >= EX(func)->op_array.opcodes &&
8281 		EX(opline) < EX(func)->op_array.opcodes + EX(func)->op_array.last);
8282 
8283 	if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT) {
8284 		fprintf(stderr, "     TRACE %d exit %d %s%s%s() %s:%d\n",
8285 			trace_num,
8286 			exit_num,
8287 			EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
8288 			EX(func)->op_array.scope ? "::" : "",
8289 			EX(func)->op_array.function_name ?
8290 				ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
8291 			ZSTR_VAL(EX(func)->op_array.filename),
8292 			EX(opline)->lineno);
8293 	}
8294 
8295 	if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_INVALIDATE) {
8296 		zend_jit_op_array_trace_extension *jit_extension;
8297 		uint32_t num = trace_num;
8298 
8299 		while (t->root != num) {
8300 			num = t->root;
8301 			t = &zend_jit_traces[num];
8302 		}
8303 
8304 		zend_shared_alloc_lock();
8305 
8306 		jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(t->op_array);
8307 
8308 		/* Checks under lock, just in case something has changed while we were waiting for the lock */
8309 		if (!(ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED))) {
8310 			/* skip: not JIT-ed nor blacklisted */
8311 		} else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8312 			/* too many root traces, blacklist the root trace */
8313 			if (!(ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) {
8314 				SHM_UNPROTECT();
8315 				zend_jit_unprotect();
8316 
8317 				((zend_op*)opline)->handler =
8318 					ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->orig_handler;
8319 
8320 				ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &= ~ZEND_JIT_TRACE_JITED;
8321 				ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags |= ZEND_JIT_TRACE_BLACKLISTED;
8322 
8323 				zend_jit_protect();
8324 				SHM_PROTECT();
8325 			}
8326 		} else {
8327 			SHM_UNPROTECT();
8328 			zend_jit_unprotect();
8329 
8330 			if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_LOOP) {
8331 				((zend_op*)(t->opline))->handler = (const void*)zend_jit_loop_trace_counter_handler;
8332 			} else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_ENTER) {
8333 				((zend_op*)(t->opline))->handler = (const void*)zend_jit_func_trace_counter_handler;
8334 			} else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_RETURN) {
8335 				((zend_op*)(t->opline))->handler = (const void*)zend_jit_ret_trace_counter_handler;
8336 			}
8337 			ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &=
8338 				ZEND_JIT_TRACE_START_LOOP|ZEND_JIT_TRACE_START_ENTER|ZEND_JIT_TRACE_START_RETURN;
8339 
8340 			zend_jit_protect();
8341 			SHM_PROTECT();
8342 		}
8343 
8344 		zend_shared_alloc_unlock();
8345 
8346 		return 0;
8347 	}
8348 
8349 	if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_TO_VM) {
8350 		if (zend_jit_trace_exit_is_bad(trace_num, exit_num)) {
8351 			zend_jit_blacklist_trace_exit(trace_num, exit_num);
8352 			if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8353 				fprintf(stderr, "---- EXIT %d/%d blacklisted\n",
8354 					trace_num, exit_num);
8355 			}
8356 			return 0;
8357 		}
8358 	} else if (JIT_G(hot_side_exit) && zend_jit_trace_exit_is_hot(trace_num, exit_num)) {
8359 		return zend_jit_trace_hot_side(execute_data, trace_num, exit_num);
8360 	}
8361 
8362 	/* Return 1 to call original handler instead of the same JIT-ed trace */
8363 	return (orig_opline == t->opline && EX(opline) == orig_opline);
8364 }
8365 
zend_jit_trace_supported(const zend_op * opline)8366 static zend_always_inline uint8_t zend_jit_trace_supported(const zend_op *opline)
8367 {
8368 	switch (opline->opcode) {
8369 		case ZEND_CATCH:
8370 		case ZEND_FAST_CALL:
8371 		case ZEND_FAST_RET:
8372 			return ZEND_JIT_TRACE_UNSUPPORTED;
8373 		default:
8374 			return ZEND_JIT_TRACE_SUPPORTED;
8375 	}
8376 }
8377 
zend_jit_restart_hot_trace_counters(zend_op_array * op_array)8378 static int zend_jit_restart_hot_trace_counters(zend_op_array *op_array)
8379 {
8380 	zend_jit_op_array_trace_extension *jit_extension;
8381 	uint32_t i;
8382 
8383 	jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8384 	for (i = 0; i < op_array->last; i++) {
8385 		jit_extension->trace_info[i].trace_flags &=
8386 			ZEND_JIT_TRACE_START_LOOP | ZEND_JIT_TRACE_START_ENTER | ZEND_JIT_TRACE_UNSUPPORTED;
8387 		if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_LOOP) {
8388 			op_array->opcodes[i].handler = (const void*)zend_jit_loop_trace_counter_handler;
8389 		} else if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_ENTER) {
8390 			op_array->opcodes[i].handler = (const void*)zend_jit_func_trace_counter_handler;
8391 		} else {
8392 			op_array->opcodes[i].handler = jit_extension->trace_info[i].orig_handler;
8393 		}
8394 	}
8395 	return SUCCESS;
8396 }
8397 
zend_jit_setup_hot_trace_counters(zend_op_array * op_array)8398 static int zend_jit_setup_hot_trace_counters(zend_op_array *op_array)
8399 {
8400 	zend_op *opline;
8401 	zend_jit_op_array_trace_extension *jit_extension;
8402 	uint32_t i;
8403 
8404 	ZEND_ASSERT(sizeof(zend_op_trace_info) == sizeof(zend_op));
8405 
8406 	jit_extension = (zend_jit_op_array_trace_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_trace_extension) + (op_array->last - 1) * sizeof(zend_op_trace_info));
8407 	if (!jit_extension) {
8408 		return FAILURE;
8409 	}
8410 	memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
8411 	jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_HOT_TRACE;
8412 	jit_extension->op_array = op_array;
8413 	jit_extension->offset = (char*)jit_extension->trace_info - (char*)op_array->opcodes;
8414 	for (i = 0; i < op_array->last; i++) {
8415 		jit_extension->trace_info[i].orig_handler = op_array->opcodes[i].handler;
8416 		jit_extension->trace_info[i].call_handler = zend_get_opcode_handler_func(&op_array->opcodes[i]);
8417 		jit_extension->trace_info[i].counter = NULL;
8418 		jit_extension->trace_info[i].trace_flags =
8419 			zend_jit_trace_supported(&op_array->opcodes[i]);
8420 	}
8421 	ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
8422 
8423 	if (JIT_G(hot_loop)) {
8424 		zend_cfg cfg;
8425 
8426 		ZEND_ASSERT(zend_jit_loop_trace_counter_handler != NULL);
8427 
8428 		if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
8429 			return FAILURE;
8430 		}
8431 
8432 		for (i = 0; i < cfg.blocks_count; i++) {
8433 			if (cfg.blocks[i].flags & ZEND_BB_REACHABLE) {
8434 				if (cfg.blocks[i].flags & ZEND_BB_LOOP_HEADER) {
8435 					/* loop header */
8436 					opline = op_array->opcodes + cfg.blocks[i].start;
8437 					if (!(ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_UNSUPPORTED)) {
8438 						opline->handler = (const void*)zend_jit_loop_trace_counter_handler;
8439 						if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter) {
8440 							ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
8441 								&zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
8442 							ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
8443 						}
8444 						ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags |=
8445 							ZEND_JIT_TRACE_START_LOOP;
8446 					}
8447 				}
8448 			}
8449 		}
8450 	}
8451 
8452 	if (JIT_G(hot_func)) {
8453 		ZEND_ASSERT(zend_jit_func_trace_counter_handler != NULL);
8454 		opline = op_array->opcodes;
8455 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
8456 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
8457 				opline++;
8458 			}
8459 		}
8460 
8461 		if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags) {
8462 			/* function entry */
8463 			opline->handler = (const void*)zend_jit_func_trace_counter_handler;
8464 			ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
8465 				&zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
8466 			ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
8467 			ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags |=
8468 				ZEND_JIT_TRACE_START_ENTER;
8469 		}
8470 	}
8471 
8472 	zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
8473 
8474 	return SUCCESS;
8475 }
8476 
zend_jit_trace_init_caches(void)8477 static void zend_jit_trace_init_caches(void)
8478 {
8479 	memset(ZEND_VOIDP(JIT_G(bad_root_cache_opline)), 0, sizeof(JIT_G(bad_root_cache_opline)));
8480 	memset(JIT_G(bad_root_cache_count), 0, sizeof(JIT_G(bad_root_cache_count)));
8481 	memset(JIT_G(bad_root_cache_stop), 0, sizeof(JIT_G(bad_root_cache_count)));
8482 	JIT_G(bad_root_slot) = 0;
8483 
8484 	if (JIT_G(exit_counters)) {
8485 		memset(JIT_G(exit_counters), 0, JIT_G(max_exit_counters));
8486 	}
8487 }
8488 
zend_jit_trace_reset_caches(void)8489 static void zend_jit_trace_reset_caches(void)
8490 {
8491 	JIT_G(tracing) = 0;
8492 #ifdef ZTS
8493 	if (!JIT_G(exit_counters)) {
8494 		JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
8495 	}
8496 #endif
8497 }
8498 
zend_jit_trace_free_caches(zend_jit_globals * jit_globals)8499 static void zend_jit_trace_free_caches(zend_jit_globals *jit_globals)
8500 {
8501 	if (jit_globals->exit_counters) {
8502 		free(jit_globals->exit_counters);
8503 	}
8504 }
8505 
zend_jit_trace_restart(void)8506 static void zend_jit_trace_restart(void)
8507 {
8508 	ZEND_JIT_TRACE_NUM = 1;
8509 	ZEND_JIT_COUNTER_NUM = 0;
8510 	ZEND_JIT_EXIT_NUM = 0;
8511 	ZEND_JIT_EXIT_COUNTERS = 0;
8512 
8513 	zend_jit_trace_init_caches();
8514 }
8515