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