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