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