xref: /PHP-8.4/ext/opcache/jit/zend_jit.c (revision bf786d0d)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend JIT                                                             |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | https://www.php.net/license/3_01.txt                                 |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "main/php.h"
20 #include "main/SAPI.h"
21 #include "php_version.h"
22 #include <ZendAccelerator.h>
23 #include "zend_shared_alloc.h"
24 #include "Zend/zend_execute.h"
25 #include "Zend/zend_vm.h"
26 #include "Zend/zend_exceptions.h"
27 #include "Zend/zend_constants.h"
28 #include "Zend/zend_closures.h"
29 #include "Zend/zend_ini.h"
30 #include "Zend/zend_observer.h"
31 #include "zend_smart_str.h"
32 #include "jit/zend_jit.h"
33 
34 #ifdef HAVE_JIT
35 
36 #include "Optimizer/zend_func_info.h"
37 #include "Optimizer/zend_ssa.h"
38 #include "Optimizer/zend_inference.h"
39 #include "Optimizer/zend_call_graph.h"
40 #include "Optimizer/zend_dump.h"
41 #include "Optimizer/zend_worklist.h"
42 
43 #include "jit/zend_jit_internal.h"
44 
45 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
46 #include <pthread.h>
47 #endif
48 
49 #ifdef ZTS
50 int jit_globals_id;
51 #else
52 zend_jit_globals jit_globals;
53 #endif
54 
55 //#define CONTEXT_THREADED_JIT
56 #define ZEND_JIT_USE_RC_INFERENCE
57 
58 #ifdef ZEND_JIT_USE_RC_INFERENCE
59 # define ZEND_SSA_RC_INFERENCE_FLAG ZEND_SSA_RC_INFERENCE
60 # define RC_MAY_BE_1(info)          (((info) & (MAY_BE_RC1|MAY_BE_REF)) != 0)
61 # define RC_MAY_BE_N(info)          (((info) & (MAY_BE_RCN|MAY_BE_REF)) != 0)
62 #else
63 # define ZEND_SSA_RC_INFERENCE_FLAG 0
64 # define RC_MAY_BE_1(info)          1
65 # define RC_MAY_BE_N(info)          1
66 #endif
67 
68 #define JIT_PREFIX      "JIT$"
69 #define JIT_STUB_PREFIX "JIT$$"
70 #define TRACE_PREFIX    "TRACE-"
71 
72 zend_ulong zend_jit_profile_counter = 0;
73 int zend_jit_profile_counter_rid = -1;
74 
75 int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT];
76 
77 const zend_op *zend_jit_halt_op = NULL;
78 static int zend_jit_vm_kind = 0;
79 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
80 static int zend_write_protect = 1;
81 #endif
82 
83 static void *dasm_buf = NULL;
84 static void *dasm_end = NULL;
85 static void **dasm_ptr = NULL;
86 
87 static size_t dasm_size = 0;
88 
89 static zend_long jit_bisect_pos = 0;
90 
91 static const void *zend_jit_runtime_jit_handler = NULL;
92 static const void *zend_jit_profile_jit_handler = NULL;
93 static const void *zend_jit_func_hot_counter_handler = NULL;
94 static const void *zend_jit_loop_hot_counter_handler = NULL;
95 static const void *zend_jit_func_trace_counter_handler = NULL;
96 static const void *zend_jit_ret_trace_counter_handler = NULL;
97 static const void *zend_jit_loop_trace_counter_handler = NULL;
98 
99 static int ZEND_FASTCALL zend_runtime_jit(void);
100 
101 static int zend_jit_trace_op_len(const zend_op *opline);
102 static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline);
103 static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags);
104 static const void *zend_jit_trace_get_exit_addr(uint32_t n);
105 static void zend_jit_trace_add_code(const void *start, uint32_t size);
106 static zend_string *zend_jit_func_name(const zend_op_array *op_array);
107 
108 static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info);
109 static bool zend_jit_supported_binary_op(uint8_t op, uint32_t op1_info, uint32_t op2_info);
110 
dominates(const zend_basic_block * blocks,int a,int b)111 static bool dominates(const zend_basic_block *blocks, int a, int b) {
112 	while (blocks[b].level > blocks[a].level) {
113 		b = blocks[b].idom;
114 	}
115 	return a == b;
116 }
117 
zend_ssa_is_last_use(const zend_op_array * op_array,const zend_ssa * ssa,int var,int use)118 static bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_ssa *ssa, int var, int use)
119 {
120 	int next_use;
121 
122 	if (ssa->vars[var].phi_use_chain) {
123 		zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
124 		do {
125 			if (!ssa->vars[phi->ssa_var].no_val) {
126 				return 0;
127 			}
128 			phi = zend_ssa_next_use_phi(ssa, var, phi);
129 		} while (phi);
130 	}
131 
132 	if (ssa->cfg.blocks[ssa->cfg.map[use]].loop_header > 0
133 	 || (ssa->cfg.blocks[ssa->cfg.map[use]].flags & ZEND_BB_LOOP_HEADER)) {
134 		int b = ssa->cfg.map[use];
135 		int prev_use = ssa->vars[var].use_chain;
136 		int def_block;
137 
138 		if (ssa->vars[var].definition >= 0) {
139 			def_block =ssa->cfg.map[ssa->vars[var].definition];
140 		} else {
141 			ZEND_ASSERT(ssa->vars[var].definition_phi);
142 			def_block = ssa->vars[var].definition_phi->block;
143 		}
144 		if (dominates(ssa->cfg.blocks, def_block,
145 				(ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) ? b : ssa->cfg.blocks[b].loop_header)) {
146 			return 0;
147 		}
148 
149 		while (prev_use >= 0 && prev_use != use) {
150 			if (b != ssa->cfg.map[prev_use]
151 			 && dominates(ssa->cfg.blocks, b, ssa->cfg.map[prev_use])
152 			 && !zend_ssa_is_no_val_use(op_array->opcodes + prev_use, ssa->ops + prev_use, var)) {
153 				return 0;
154 			}
155 			prev_use = zend_ssa_next_use(ssa->ops, var, prev_use);
156 		}
157 	}
158 
159 	next_use = zend_ssa_next_use(ssa->ops, var, use);
160 	if (next_use < 0) {
161 		return 1;
162 	} else if (zend_ssa_is_no_val_use(op_array->opcodes + next_use, ssa->ops + next_use, var)) {
163 		return 1;
164 	}
165 	return 0;
166 }
167 
zend_jit_is_constant_cmp_long_long(const zend_op * opline,zend_ssa_range * op1_range,zend_jit_addr op1_addr,zend_ssa_range * op2_range,zend_jit_addr op2_addr,bool * result)168 static int zend_jit_is_constant_cmp_long_long(const zend_op  *opline,
169                                               zend_ssa_range *op1_range,
170                                               zend_jit_addr   op1_addr,
171                                               zend_ssa_range *op2_range,
172                                               zend_jit_addr   op2_addr,
173                                               bool           *result)
174 {
175 	zend_long op1_min;
176 	zend_long op1_max;
177 	zend_long op2_min;
178 	zend_long op2_max;
179 
180 	if (op1_range) {
181 		op1_min = op1_range->min;
182 		op1_max = op1_range->max;
183 	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
184 		ZEND_ASSERT(Z_TYPE_P(Z_ZV(op1_addr)) == IS_LONG);
185 		op1_min = op1_max = Z_LVAL_P(Z_ZV(op1_addr));
186 	} else {
187 		return 0;
188 	}
189 
190 	if (op2_range) {
191 		op2_min = op2_range->min;
192 		op2_max = op2_range->max;
193 	} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
194 		ZEND_ASSERT(Z_TYPE_P(Z_ZV(op2_addr)) == IS_LONG);
195 		op2_min = op2_max = Z_LVAL_P(Z_ZV(op2_addr));
196 	} else {
197 		return 0;
198 	}
199 
200 	switch (opline->opcode) {
201 		case ZEND_IS_EQUAL:
202 		case ZEND_IS_IDENTICAL:
203 		case ZEND_CASE:
204 		case ZEND_CASE_STRICT:
205 			if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
206 				*result = 1;
207 				return 1;
208 			} else if (op1_max < op2_min || op1_min > op2_max) {
209 				*result = 0;
210 				return 1;
211 			}
212 			return 0;
213 		case ZEND_IS_NOT_EQUAL:
214 		case ZEND_IS_NOT_IDENTICAL:
215 			if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
216 				*result = 0;
217 				return 1;
218 			} else if (op1_max < op2_min || op1_min > op2_max) {
219 				*result = 1;
220 				return 1;
221 			}
222 			return 0;
223 		case ZEND_IS_SMALLER:
224 			if (op1_max < op2_min) {
225 				*result = 1;
226 				return 1;
227 			} else if (op1_min >= op2_max) {
228 				*result = 0;
229 				return 1;
230 			}
231 			return 0;
232 		case ZEND_IS_SMALLER_OR_EQUAL:
233 			if (op1_max <= op2_min) {
234 				*result = 1;
235 				return 1;
236 			} else if (op1_min > op2_max) {
237 				*result = 0;
238 				return 1;
239 			}
240 			return 0;
241 		default:
242 			ZEND_UNREACHABLE();
243 	}
244 	return 0;
245 }
246 
247 #define ADVANCE_SSA_OP(ssa_op, offset) \
248 	do { \
249 		if (ssa_op) ssa_op += offset; \
250 	} while (0)
251 
zend_jit_needs_call_chain(zend_call_info * call_info,uint32_t b,const zend_op_array * op_array,zend_ssa * ssa,const zend_ssa_op * ssa_op,const zend_op * opline,int call_level,zend_jit_trace_rec * trace)252 static int zend_jit_needs_call_chain(zend_call_info *call_info, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, const zend_op *opline, int call_level, zend_jit_trace_rec *trace)
253 {
254 	int skip;
255 
256 	if (trace) {
257 		zend_jit_trace_rec *p = trace;
258 
259 		ADVANCE_SSA_OP(ssa_op, 1);
260 		while (1) {
261 			if (p->op == ZEND_JIT_TRACE_VM) {
262 				switch (p->opline->opcode) {
263 					case ZEND_SEND_ARRAY:
264 					case ZEND_SEND_USER:
265 					case ZEND_SEND_UNPACK:
266 					case ZEND_INIT_FCALL:
267 					case ZEND_INIT_METHOD_CALL:
268 					case ZEND_INIT_STATIC_METHOD_CALL:
269 					case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
270 					case ZEND_INIT_FCALL_BY_NAME:
271 					case ZEND_INIT_NS_FCALL_BY_NAME:
272 					case ZEND_INIT_DYNAMIC_CALL:
273 					case ZEND_NEW:
274 					case ZEND_INIT_USER_CALL:
275 					case ZEND_FAST_CALL:
276 					case ZEND_JMP:
277 					case ZEND_JMPZ:
278 					case ZEND_JMPNZ:
279 					case ZEND_JMPZ_EX:
280 					case ZEND_JMPNZ_EX:
281 					case ZEND_FE_RESET_R:
282 					case ZEND_FE_RESET_RW:
283 					case ZEND_JMP_SET:
284 					case ZEND_COALESCE:
285 					case ZEND_JMP_NULL:
286 					case ZEND_ASSERT_CHECK:
287 					case ZEND_CATCH:
288 					case ZEND_DECLARE_ANON_CLASS:
289 					case ZEND_FE_FETCH_R:
290 					case ZEND_FE_FETCH_RW:
291 					case ZEND_BIND_INIT_STATIC_OR_JMP:
292 					case ZEND_JMP_FRAMELESS:
293 						return 1;
294 					case ZEND_DO_ICALL:
295 					case ZEND_DO_UCALL:
296 					case ZEND_DO_FCALL_BY_NAME:
297 					case ZEND_DO_FCALL:
298 					case ZEND_CALLABLE_CONVERT:
299 						return 0;
300 					case ZEND_SEND_VAL:
301 					case ZEND_SEND_VAR:
302 					case ZEND_SEND_VAL_EX:
303 					case ZEND_SEND_VAR_EX:
304 					case ZEND_SEND_FUNC_ARG:
305 					case ZEND_SEND_REF:
306 					case ZEND_SEND_VAR_NO_REF:
307 					case ZEND_SEND_VAR_NO_REF_EX:
308 						/* skip */
309 						break;
310 					default:
311 						if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
312 							return 1;
313 						}
314 				}
315 				ADVANCE_SSA_OP(ssa_op, zend_jit_trace_op_len(opline));
316 			} else if (p->op == ZEND_JIT_TRACE_ENTER ||
317 			           p->op == ZEND_JIT_TRACE_BACK ||
318 			           p->op == ZEND_JIT_TRACE_END) {
319 				return 1;
320 			}
321 			p++;
322 		}
323 	}
324 
325 	if (!call_info) {
326 		const zend_op *end = op_array->opcodes + op_array->last;
327 
328 		opline++;
329 		ADVANCE_SSA_OP(ssa_op, 1);
330 		skip = (call_level == 1);
331 		while (opline != end) {
332 			if (!skip) {
333 				if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
334 					return 1;
335 				}
336 			}
337 			switch (opline->opcode) {
338 				case ZEND_SEND_VAL:
339 				case ZEND_SEND_VAR:
340 				case ZEND_SEND_VAL_EX:
341 				case ZEND_SEND_VAR_EX:
342 				case ZEND_SEND_FUNC_ARG:
343 				case ZEND_SEND_REF:
344 				case ZEND_SEND_VAR_NO_REF:
345 				case ZEND_SEND_VAR_NO_REF_EX:
346 					skip = 0;
347 					break;
348 				case ZEND_SEND_ARRAY:
349 				case ZEND_SEND_USER:
350 				case ZEND_SEND_UNPACK:
351 				case ZEND_INIT_FCALL:
352 				case ZEND_INIT_METHOD_CALL:
353 				case ZEND_INIT_STATIC_METHOD_CALL:
354 				case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
355 				case ZEND_INIT_FCALL_BY_NAME:
356 				case ZEND_INIT_NS_FCALL_BY_NAME:
357 				case ZEND_INIT_DYNAMIC_CALL:
358 				case ZEND_NEW:
359 				case ZEND_INIT_USER_CALL:
360 				case ZEND_FAST_CALL:
361 				case ZEND_JMP:
362 				case ZEND_JMPZ:
363 				case ZEND_JMPNZ:
364 				case ZEND_JMPZ_EX:
365 				case ZEND_JMPNZ_EX:
366 				case ZEND_FE_RESET_R:
367 				case ZEND_FE_RESET_RW:
368 				case ZEND_JMP_SET:
369 				case ZEND_COALESCE:
370 				case ZEND_JMP_NULL:
371 				case ZEND_ASSERT_CHECK:
372 				case ZEND_CATCH:
373 				case ZEND_DECLARE_ANON_CLASS:
374 				case ZEND_FE_FETCH_R:
375 				case ZEND_FE_FETCH_RW:
376 				case ZEND_BIND_INIT_STATIC_OR_JMP:
377 				case ZEND_JMP_FRAMELESS:
378 					return 1;
379 				case ZEND_DO_ICALL:
380 				case ZEND_DO_UCALL:
381 				case ZEND_DO_FCALL_BY_NAME:
382 				case ZEND_DO_FCALL:
383 				case ZEND_CALLABLE_CONVERT:
384 					end = opline;
385 					if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
386 						/* INIT_FCALL and DO_FCALL in different BasicBlocks */
387 						return 1;
388 					}
389 					return 0;
390 			}
391 			opline++;
392 			ADVANCE_SSA_OP(ssa_op, 1);
393 		}
394 
395 		return 1;
396 	} else {
397 		const zend_op *end = call_info->caller_call_opline;
398 
399 		/* end may be null if an opcode like EXIT is part of the argument list. */
400 		if (!end || end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
401 			/* INIT_FCALL and DO_FCALL in different BasicBlocks */
402 			return 1;
403 		}
404 
405 		opline++;
406 		ADVANCE_SSA_OP(ssa_op, 1);
407 		skip = (call_level == 1);
408 		while (opline != end) {
409 			if (skip) {
410 				switch (opline->opcode) {
411 					case ZEND_SEND_VAL:
412 					case ZEND_SEND_VAR:
413 					case ZEND_SEND_VAL_EX:
414 					case ZEND_SEND_VAR_EX:
415 					case ZEND_SEND_FUNC_ARG:
416 					case ZEND_SEND_REF:
417 					case ZEND_SEND_VAR_NO_REF:
418 					case ZEND_SEND_VAR_NO_REF_EX:
419 						skip = 0;
420 						break;
421 					case ZEND_SEND_ARRAY:
422 					case ZEND_SEND_USER:
423 					case ZEND_SEND_UNPACK:
424 						return 1;
425 				}
426 			} else {
427 				if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
428 					return 1;
429 				}
430 			}
431 			opline++;
432 			ADVANCE_SSA_OP(ssa_op, 1);
433 		}
434 
435 		return 0;
436 	}
437 }
438 
skip_valid_arguments(const zend_op_array * op_array,zend_ssa * ssa,const zend_call_info * call_info)439 static uint32_t skip_valid_arguments(const zend_op_array *op_array, zend_ssa *ssa, const zend_call_info *call_info)
440 {
441 	uint32_t num_args = 0;
442 	zend_function *func = call_info->callee_func;
443 
444 	/* It's okay to handle prototypes here, because they can only increase the accepted arguments.
445 	 * Anything legal for the parent method is also legal for the parent method. */
446 	while (num_args < call_info->num_args) {
447 		zend_arg_info *arg_info = func->op_array.arg_info + num_args;
448 
449 		if (ZEND_TYPE_IS_SET(arg_info->type)) {
450 			if (ZEND_TYPE_IS_ONLY_MASK(arg_info->type)) {
451 				zend_op *opline = call_info->arg_info[num_args].opline;
452 				zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
453 				uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
454 				if ((OP1_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) & ~type_mask) {
455 					break;
456 				}
457 			} else {
458 				break;
459 			}
460 		}
461 		num_args++;
462 	}
463 	return num_args;
464 }
465 
zend_ssa_cv_info(const zend_op_array * op_array,zend_ssa * ssa,uint32_t var)466 static uint32_t zend_ssa_cv_info(const zend_op_array *op_array, zend_ssa *ssa, uint32_t var)
467 {
468 	uint32_t j, info;
469 
470 	if (ssa->vars && ssa->var_info) {
471 		info = ssa->var_info[var].type;
472 		for (j = op_array->last_var; j < ssa->vars_count; j++) {
473 			if (ssa->vars[j].var == var) {
474 				info |= ssa->var_info[j].type;
475 			}
476 		}
477 	} else {
478 		info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_UNDEF |
479 			MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
480 	}
481 
482 #ifdef ZEND_JIT_USE_RC_INFERENCE
483 	/* Refcount may be increased by RETURN opcode */
484 	if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
485 		for (j = 0; j < ssa->cfg.blocks_count; j++) {
486 			if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
487 			    ssa->cfg.blocks[j].len > 0) {
488 				const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;
489 
490 				if (opline->opcode == ZEND_RETURN) {
491 					if (opline->op1_type == IS_CV && opline->op1.var == EX_NUM_TO_VAR(var)) {
492 						info |= MAY_BE_RCN;
493 						break;
494 					}
495 				}
496 			}
497 		}
498 	}
499 #endif
500 
501 	return info;
502 }
503 
zend_jit_may_avoid_refcounting(const zend_op * opline,uint32_t op1_info)504 static bool zend_jit_may_avoid_refcounting(const zend_op *opline, uint32_t op1_info)
505 {
506 	switch (opline->opcode) {
507 		case ZEND_FETCH_OBJ_FUNC_ARG:
508 			if (!JIT_G(current_frame) ||
509 			    !JIT_G(current_frame)->call->func ||
510 			    !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
511 				return 0;
512 			}
513 			/* break missing intentionally */
514 		case ZEND_FETCH_OBJ_R:
515 		case ZEND_FETCH_OBJ_IS:
516 			if ((op1_info & MAY_BE_OBJECT)
517 			 && opline->op2_type == IS_CONST
518 			 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING
519 			 && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') {
520 				return 1;
521 			}
522 			break;
523 		case ZEND_FETCH_DIM_FUNC_ARG:
524 			if (!JIT_G(current_frame) ||
525 			    !JIT_G(current_frame)->call->func ||
526 			    !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
527 				return 0;
528 			}
529 			/* break missing intentionally */
530 		case ZEND_FETCH_DIM_R:
531 		case ZEND_FETCH_DIM_IS:
532 			return 1;
533 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
534 			if (!(opline->extended_value & ZEND_ISEMPTY)) {
535 				return 1;
536 			}
537 			break;
538 	}
539 	return 0;
540 }
541 
zend_jit_is_persistent_constant(zval * key,uint32_t flags)542 static bool zend_jit_is_persistent_constant(zval *key, uint32_t flags)
543 {
544 	zval *zv;
545 	zend_constant *c = NULL;
546 
547 	/* null/true/false are resolved during compilation, so don't check for them here. */
548 	zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
549 	if (zv) {
550 		c = (zend_constant*)Z_PTR_P(zv);
551 	} else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
552 		key++;
553 		zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
554 		if (zv) {
555 			c = (zend_constant*)Z_PTR_P(zv);
556 		}
557 	}
558 	return c && (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT);
559 }
560 
zend_get_known_property_info(const zend_op_array * op_array,zend_class_entry * ce,zend_string * member,bool on_this,zend_string * filename)561 static zend_property_info* zend_get_known_property_info(const zend_op_array *op_array, zend_class_entry *ce, zend_string *member, bool on_this, zend_string *filename)
562 {
563 	zend_property_info *info = NULL;
564 
565 	if ((on_this && (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) ||
566 	    !ce ||
567 	    !(ce->ce_flags & ZEND_ACC_LINKED) ||
568 	    (ce->ce_flags & ZEND_ACC_TRAIT) ||
569 	    ce->create_object) {
570 		return NULL;
571 	}
572 
573 	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
574 		if (ce->info.user.filename != filename) {
575 			/* class declaration might be changed independently */
576 			return NULL;
577 		}
578 
579 		if (ce->parent) {
580 			zend_class_entry *parent = ce->parent;
581 
582 			do {
583 				if (parent->type == ZEND_INTERNAL_CLASS) {
584 					break;
585 				} else if (parent->info.user.filename != filename) {
586 					/* some of parents class declarations might be changed independently */
587 					/* TODO: this check may be not enough, because even
588 					 * in the same it's possible to conditionally define
589 					 * few classes with the same name, and "parent" may
590 					 * change from request to request.
591 					 */
592 					return NULL;
593 				}
594 				parent = parent->parent;
595 			} while (parent);
596 		}
597 	}
598 
599 	// TODO: Treat property hooks more precisely.
600 	info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
601 	if (info == NULL ||
602 	    !IS_VALID_PROPERTY_OFFSET(info->offset) ||
603 	    (info->flags & ZEND_ACC_STATIC) ||
604 	    info->hooks) {
605 		return NULL;
606 	}
607 
608 	if (info->flags & ZEND_ACC_PUBLIC) {
609 		return info;
610 	} else if (on_this) {
611 		if (ce == info->ce) {
612 			if (ce == op_array->scope) {
613 				return info;
614 			} else {
615 				return NULL;
616 			}
617 		} else if ((info->flags & ZEND_ACC_PROTECTED)
618 				&& instanceof_function_slow(ce, info->ce)) {
619 			return info;
620 		}
621 	}
622 
623 	return NULL;
624 }
625 
zend_may_be_dynamic_property(zend_class_entry * ce,zend_string * member,bool on_this,const zend_op_array * op_array)626 static bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *member, bool on_this, const zend_op_array *op_array)
627 {
628 	zend_property_info *info;
629 
630 	if (!ce || (ce->ce_flags & ZEND_ACC_TRAIT) || (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
631 		return 1;
632 	}
633 
634 	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
635 		if (ce->info.user.filename != op_array->filename) {
636 			/* class declaration might be changed independently */
637 			return 1;
638 		}
639 	}
640 
641 	// TODO: Treat property hooks more precisely.
642 	info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
643 	if (info == NULL ||
644 	    !IS_VALID_PROPERTY_OFFSET(info->offset) ||
645 	    (info->flags & ZEND_ACC_STATIC) ||
646 	    info->hooks) {
647 		return 1;
648 	}
649 
650 	if (!(info->flags & ZEND_ACC_PUBLIC) &&
651 	    (!on_this || info->ce != ce)) {
652 		return 1;
653 	}
654 
655 	return 0;
656 }
657 
658 #define OP_RANGE(ssa_op, opN) \
659 	(((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
660 	  ssa->var_info && \
661 	  (ssa_op)->opN##_use >= 0 && \
662 	  ssa->var_info[(ssa_op)->opN##_use].has_range) ? \
663 	 &ssa->var_info[(ssa_op)->opN##_use].range : NULL)
664 
665 #define OP1_RANGE()      OP_RANGE(ssa_op, op1)
666 #define OP2_RANGE()      OP_RANGE(ssa_op, op2)
667 #define OP1_DATA_RANGE() OP_RANGE(ssa_op + 1, op1)
668 
669 #include "jit/zend_jit_helpers.c"
670 #include "Zend/zend_cpuinfo.h"
671 
672 #ifdef HAVE_GCC_GLOBAL_REGS
673 # define GCC_GLOBAL_REGS 1
674 #else
675 # define GCC_GLOBAL_REGS 0
676 #endif
677 
678 /* By default avoid JITing inline handlers if it does not seem profitable due to lack of
679  * type information. Disabling this option allows testing some JIT handlers in the
680  * presence of try/catch blocks, which prevent SSA construction. */
681 #ifndef PROFITABILITY_CHECKS
682 # define PROFITABILITY_CHECKS 1
683 #endif
684 
685 #define BP_JIT_IS 6 /* Used for ISSET_ISEMPTY_DIM_OBJ. see BP_VAR_*defines in Zend/zend_compile.h */
686 
687 /* The generated code may contain tautological comparisons, ignore them. */
688 #if defined(__clang__)
689 # pragma clang diagnostic push
690 # pragma clang diagnostic ignored "-Wtautological-compare"
691 # pragma clang diagnostic ignored "-Wstring-compare"
692 #endif
693 
694 #include "jit/zend_jit_ir.c"
695 
696 #if defined(__clang__)
697 # pragma clang diagnostic pop
698 #endif
699 
700 #ifdef _WIN32
701 # include <Windows.h>
702 #else
703 # include <sys/mman.h>
704 # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
705 #   define MAP_ANONYMOUS MAP_ANON
706 # endif
707 #endif
708 
zend_jit_status(zval * ret)709 ZEND_EXT_API void zend_jit_status(zval *ret)
710 {
711 	zval stats;
712 	array_init(&stats);
713 	add_assoc_bool(&stats, "enabled", JIT_G(enabled));
714 	add_assoc_bool(&stats, "on", JIT_G(on));
715 	add_assoc_long(&stats, "kind", JIT_G(trigger));
716 	add_assoc_long(&stats, "opt_level", JIT_G(opt_level));
717 	add_assoc_long(&stats, "opt_flags", JIT_G(opt_flags));
718 	if (dasm_buf) {
719 		add_assoc_long(&stats, "buffer_size", (char*)dasm_end - (char*)dasm_buf);
720 		add_assoc_long(&stats, "buffer_free", (char*)dasm_end - (char*)*dasm_ptr);
721 	} else {
722 		add_assoc_long(&stats, "buffer_size", 0);
723 		add_assoc_long(&stats, "buffer_free", 0);
724 	}
725 	add_assoc_zval(ret, "jit", &stats);
726 }
727 
zend_jit_func_name(const zend_op_array * op_array)728 static zend_string *zend_jit_func_name(const zend_op_array *op_array)
729 {
730 	smart_str buf = {0};
731 
732 	if (op_array->function_name) {
733 		smart_str_appends(&buf, JIT_PREFIX);
734 		if (op_array->scope) {
735 			smart_str_appendl(&buf, ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name));
736 			smart_str_appends(&buf, "::");
737 		}
738 		smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
739 		if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
740 			smart_str_appends(&buf, ":");
741 			smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
742 			smart_str_appends(&buf, ":");
743 			smart_str_append_long(&buf, op_array->line_start);
744 		}
745 		smart_str_0(&buf);
746 		return buf.s;
747 	} else if (op_array->filename) {
748 		smart_str_appends(&buf, JIT_PREFIX);
749 		smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
750 		smart_str_0(&buf);
751 		return buf.s;
752 	} else {
753 		return NULL;
754 	}
755 }
756 
zend_may_overflow(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,zend_ssa * ssa)757 static int zend_may_overflow(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa)
758 {
759 	int res;
760 	zend_long op1_min, op1_max, op2_min, op2_max;
761 
762 	if (!ssa->ops || !ssa->var_info) {
763 		return 1;
764 	}
765 	switch (opline->opcode) {
766 		case ZEND_PRE_INC:
767 		case ZEND_POST_INC:
768 			res = ssa_op->op1_def;
769 			if (res < 0
770 			 || !ssa->var_info[res].has_range
771 			 || ssa->var_info[res].range.overflow) {
772 				if (!OP1_HAS_RANGE()) {
773 					return 1;
774 				}
775 				op1_max = OP1_MAX_RANGE();
776 				if (op1_max == ZEND_LONG_MAX) {
777 					return 1;
778 				}
779 			}
780 			return 0;
781 		case ZEND_PRE_DEC:
782 		case ZEND_POST_DEC:
783 			res = ssa_op->op1_def;
784 			if (res < 0
785 			 || !ssa->var_info[res].has_range
786 			 || ssa->var_info[res].range.underflow) {
787 				if (!OP1_HAS_RANGE()) {
788 					return 1;
789 				}
790 				op1_min = OP1_MIN_RANGE();
791 				if (op1_min == ZEND_LONG_MIN) {
792 					return 1;
793 				}
794 			}
795 			return 0;
796 		case ZEND_ADD:
797 			res = ssa_op->result_def;
798 			if (res < 0
799 			 || !ssa->var_info[res].has_range
800 			 || ssa->var_info[res].range.underflow) {
801 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
802 					return 1;
803 				}
804 				op1_min = OP1_MIN_RANGE();
805 				op2_min = OP2_MIN_RANGE();
806 				if (zend_add_will_overflow(op1_min, op2_min)) {
807 					return 1;
808 				}
809 			}
810 			if (res < 0
811 			 || !ssa->var_info[res].has_range
812 			 || ssa->var_info[res].range.overflow) {
813 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
814 					return 1;
815 				}
816 				op1_max = OP1_MAX_RANGE();
817 				op2_max = OP2_MAX_RANGE();
818 				if (zend_add_will_overflow(op1_max, op2_max)) {
819 					return 1;
820 				}
821 			}
822 			return 0;
823 		case ZEND_SUB:
824 			res = ssa_op->result_def;
825 			if (res < 0
826 			 || !ssa->var_info[res].has_range
827 			 || ssa->var_info[res].range.underflow) {
828 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
829 					return 1;
830 				}
831 				op1_min = OP1_MIN_RANGE();
832 				op2_max = OP2_MAX_RANGE();
833 				if (zend_sub_will_overflow(op1_min, op2_max)) {
834 					return 1;
835 				}
836 			}
837 			if (res < 0
838 			 || !ssa->var_info[res].has_range
839 			 || ssa->var_info[res].range.overflow) {
840 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
841 					return 1;
842 				}
843 				op1_max = OP1_MAX_RANGE();
844 				op2_min = OP2_MIN_RANGE();
845 				if (zend_sub_will_overflow(op1_max, op2_min)) {
846 					return 1;
847 				}
848 			}
849 			return 0;
850 		case ZEND_MUL:
851 			res = ssa_op->result_def;
852 			return (res < 0 ||
853 				!ssa->var_info[res].has_range ||
854 				ssa->var_info[res].range.underflow ||
855 				ssa->var_info[res].range.overflow);
856 		case ZEND_ASSIGN_OP:
857 			if (opline->extended_value == ZEND_ADD) {
858 				res = ssa_op->op1_def;
859 				if (res < 0
860 				 || !ssa->var_info[res].has_range
861 				 || ssa->var_info[res].range.underflow) {
862 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
863 						return 1;
864 					}
865 					op1_min = OP1_MIN_RANGE();
866 					op2_min = OP2_MIN_RANGE();
867 					if (zend_add_will_overflow(op1_min, op2_min)) {
868 						return 1;
869 					}
870 				}
871 				if (res < 0
872 				 || !ssa->var_info[res].has_range
873 				 || ssa->var_info[res].range.overflow) {
874 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
875 						return 1;
876 					}
877 					op1_max = OP1_MAX_RANGE();
878 					op2_max = OP2_MAX_RANGE();
879 					if (zend_add_will_overflow(op1_max, op2_max)) {
880 						return 1;
881 					}
882 				}
883 				return 0;
884 			} else if (opline->extended_value == ZEND_SUB) {
885 				res = ssa_op->op1_def;
886 				if (res < 0
887 				 || !ssa->var_info[res].has_range
888 				 || ssa->var_info[res].range.underflow) {
889 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
890 						return 1;
891 					}
892 					op1_min = OP1_MIN_RANGE();
893 					op2_max = OP2_MAX_RANGE();
894 					if (zend_sub_will_overflow(op1_min, op2_max)) {
895 						return 1;
896 					}
897 				}
898 				if (res < 0
899 				 || !ssa->var_info[res].has_range
900 				 || ssa->var_info[res].range.overflow) {
901 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
902 						return 1;
903 					}
904 					op1_max = OP1_MAX_RANGE();
905 					op2_min = OP2_MIN_RANGE();
906 					if (zend_sub_will_overflow(op1_max, op2_min)) {
907 						return 1;
908 					}
909 				}
910 				return 0;
911 			} else if (opline->extended_value == ZEND_MUL) {
912 				res = ssa_op->op1_def;
913 				return (res < 0 ||
914 					!ssa->var_info[res].has_range ||
915 					ssa->var_info[res].range.underflow ||
916 					ssa->var_info[res].range.overflow);
917 			}
918 			ZEND_FALLTHROUGH;
919 		default:
920 			return 1;
921 	}
922 }
923 
zend_jit_build_cfg(const zend_op_array * op_array,zend_cfg * cfg)924 static int zend_jit_build_cfg(const zend_op_array *op_array, zend_cfg *cfg)
925 {
926 	uint32_t flags;
927 
928 	flags = ZEND_CFG_STACKLESS | ZEND_CFG_NO_ENTRY_PREDECESSORS | ZEND_SSA_RC_INFERENCE_FLAG | ZEND_SSA_USE_CV_RESULTS | ZEND_CFG_RECV_ENTRY;
929 
930 	zend_build_cfg(&CG(arena), op_array, flags, cfg);
931 
932 	/* Don't JIT huge functions. Apart from likely being detrimental due to the amount of
933 	 * generated code, some of our analysis is recursive and will stack overflow with many
934 	 * blocks. */
935 	if (cfg->blocks_count > 100000) {
936 		return FAILURE;
937 	}
938 
939 	zend_cfg_build_predecessors(&CG(arena), cfg);
940 
941 	/* Compute Dominators Tree */
942 	zend_cfg_compute_dominators_tree(op_array, cfg);
943 
944 	/* Identify reducible and irreducible loops */
945 	zend_cfg_identify_loops(op_array, cfg);
946 
947 	return SUCCESS;
948 }
949 
zend_jit_op_array_analyze1(const zend_op_array * op_array,zend_script * script,zend_ssa * ssa)950 static int zend_jit_op_array_analyze1(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa)
951 {
952 	if (zend_jit_build_cfg(op_array, &ssa->cfg) != SUCCESS) {
953 		return FAILURE;
954 	}
955 
956 #if 0
957 	/* TODO: debugger and profiler supports? */
958 	if ((ssa->cfg.flags & ZEND_FUNC_HAS_EXTENDED_INFO)) {
959 		return FAILURE;
960 	}
961 #endif
962 
963 	/* TODO: move this to zend_cfg.c ? */
964 	if (!op_array->function_name) {
965 		ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
966 	}
967 
968 	if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC)
969 	 && ssa->cfg.blocks
970 	 && op_array->last_try_catch == 0
971 	 && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
972 	 && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
973 		if (zend_build_ssa(&CG(arena), script, op_array, ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS, ssa) != SUCCESS) {
974 			return FAILURE;
975 		}
976 
977 		zend_ssa_compute_use_def_chains(&CG(arena), op_array, ssa);
978 
979 		zend_ssa_find_false_dependencies(op_array, ssa);
980 
981 		zend_ssa_find_sccs(op_array, ssa);
982 	}
983 
984 	return SUCCESS;
985 }
986 
zend_jit_op_array_analyze2(const zend_op_array * op_array,zend_script * script,zend_ssa * ssa,uint32_t optimization_level)987 static int zend_jit_op_array_analyze2(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa, uint32_t optimization_level)
988 {
989 	if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC)
990 	 && ssa->cfg.blocks
991 	 && op_array->last_try_catch == 0
992 	 && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
993 	 && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
994 		if (zend_ssa_inference(&CG(arena), op_array, script, ssa,
995 				optimization_level & ~ZEND_OPTIMIZER_NARROW_TO_DOUBLE) != SUCCESS) {
996 			return FAILURE;
997 		}
998 	}
999 
1000 	return SUCCESS;
1001 }
1002 
zend_jit_allocate_registers(zend_jit_ctx * ctx,const zend_op_array * op_array,zend_ssa * ssa)1003 static void zend_jit_allocate_registers(zend_jit_ctx *ctx, const zend_op_array *op_array, zend_ssa *ssa)
1004 {
1005 	void *checkpoint;
1006 	int candidates_count, i;
1007 	zend_jit_reg_var *ra;
1008 
1009 	checkpoint = zend_arena_checkpoint(CG(arena));
1010 	ra = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_reg_var));
1011 	candidates_count = 0;
1012 	for (i = 0; i < ssa->vars_count; i++) {
1013 		if (zend_jit_may_be_in_reg(op_array, ssa, i)) {
1014 			ra[i].ref = IR_NULL;
1015 			candidates_count++;
1016 		}
1017 	}
1018 	if (!candidates_count) {
1019 		zend_arena_release(&CG(arena), checkpoint);
1020 		return;
1021 	}
1022 
1023 	if (JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) {
1024 		/* Naive SSA resolution */
1025 		for (i = 0; i < ssa->vars_count; i++) {
1026 			if (ssa->vars[i].definition_phi && !ssa->vars[i].no_val) {
1027 				zend_ssa_phi *phi = ssa->vars[i].definition_phi;
1028 				int k, src;
1029 
1030 				if (phi->pi >= 0) {
1031 					src = phi->sources[0];
1032 					if (ra[i].ref) {
1033 						if (!ra[src].ref) {
1034 							ra[i].flags |= ZREG_LOAD;
1035 						} else {
1036 							ra[i].flags |= ZREG_PI;
1037 						}
1038 					} else if (ra[src].ref) {
1039 						ra[src].flags |= ZREG_STORE;
1040 					}
1041 				} else {
1042 					int need_move = 0;
1043 
1044 					for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
1045 						src = phi->sources[k];
1046 						if (src >= 0) {
1047 							if (ssa->vars[src].definition_phi
1048 							 && ssa->vars[src].definition_phi->pi >= 0
1049 							 && phi->block == ssa->vars[src].definition_phi->block) {
1050 								/* Skip zero-length interval for Pi variable */
1051 								src = ssa->vars[src].definition_phi->sources[0];
1052 							}
1053 							if (ra[i].ref) {
1054 								if (!ra[src].ref) {
1055 									need_move = 1;
1056 								}
1057 							} else if (ra[src].ref) {
1058 								need_move = 1;
1059 							}
1060 						}
1061 					}
1062 					if (need_move) {
1063 						if (ra[i].ref) {
1064 							ra[i].flags |= ZREG_LOAD;
1065 						}
1066 						for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
1067 							src = phi->sources[k];
1068 							if (src >= 0) {
1069 								if (ssa->vars[src].definition_phi
1070 								 && ssa->vars[src].definition_phi->pi >= 0
1071 								 && phi->block == ssa->vars[src].definition_phi->block) {
1072 									/* Skip zero-length interval for Pi variable */
1073 									src = ssa->vars[src].definition_phi->sources[0];
1074 								}
1075 								if (ra[src].ref) {
1076 									ra[src].flags |= ZREG_STORE;
1077 								}
1078 							}
1079 						}
1080 					} else {
1081 						ra[i].flags |= ZREG_PHI;
1082 					}
1083 				}
1084 			}
1085 		}
1086 
1087 		/* Remove useless register allocation */
1088 		for (i = 0; i < ssa->vars_count; i++) {
1089 			if (ra[i].ref &&
1090 			    ((ra[i].flags & ZREG_LOAD) ||
1091 			     ((ra[i].flags & ZREG_STORE) && ssa->vars[i].definition >= 0)) &&
1092 			    ssa->vars[i].use_chain < 0) {
1093 			    bool may_remove = 1;
1094 				zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
1095 
1096 				while (phi) {
1097 					if (ra[phi->ssa_var].ref &&
1098 					    !(ra[phi->ssa_var].flags & ZREG_LOAD)) {
1099 						may_remove = 0;
1100 						break;
1101 					}
1102 					phi = zend_ssa_next_use_phi(ssa, i, phi);
1103 				}
1104 				if (may_remove) {
1105 					ra[i].ref = IR_UNUSED;
1106 				}
1107 			}
1108 		}
1109 
1110 		/* Remove intervals used once */
1111 		for (i = 0; i < ssa->vars_count; i++) {
1112 			if (ra[i].ref) {
1113 				if (!(ra[i].flags & (ZREG_LOAD|ZREG_STORE))) {
1114 					uint32_t var_num = ssa->vars[i].var;
1115 					uint32_t op_num = ssa->vars[i].definition;
1116 
1117 					/* Check if a tempoary variable may be freed by exception handler */
1118 					if (op_array->last_live_range
1119 					 && var_num >= op_array->last_var
1120 					 && ssa->vars[i].definition >= 0
1121 					 && ssa->ops[op_num].result_def == i) {
1122 						const zend_live_range *range = op_array->live_range;
1123 						int j;
1124 
1125 						op_num++;
1126 						if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
1127 							op_num++;
1128 						}
1129 						for (j = 0; j < op_array->last_live_range; range++, j++) {
1130 							if (range->start > op_num) {
1131 								/* further blocks will not be relevant... */
1132 								break;
1133 							} else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
1134 								/* check if opcodes in range may throw */
1135 								do {
1136 									if (zend_may_throw(op_array->opcodes + op_num, ssa->ops + op_num, op_array, ssa)) {
1137 										ra[i].flags |= ZREG_STORE;
1138 										break;
1139 									}
1140 									op_num++;
1141 									if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
1142 										op_num++;
1143 									}
1144 								} while (op_num < range->end);
1145 								break;
1146 							}
1147 						}
1148 					}
1149 				}
1150 				if ((ra[i].flags & ZREG_LOAD)
1151 				 && (ra[i].flags & ZREG_STORE)
1152 				 && (ssa->vars[i].use_chain < 0
1153 				  || zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
1154 					bool may_remove = 1;
1155 					zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
1156 
1157 					while (phi) {
1158 						if (ra[phi->ssa_var].ref &&
1159 						    !(ra[phi->ssa_var].flags & ZREG_LOAD)) {
1160 							may_remove = 0;
1161 							break;
1162 						}
1163 						phi = zend_ssa_next_use_phi(ssa, i, phi);
1164 					}
1165 					if (may_remove) {
1166 						ra[i].ref = IR_UNUSED;
1167 					}
1168 				}
1169 			}
1170 		}
1171 	}
1172 
1173 	if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
1174 		fprintf(stderr, "Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
1175 		for (i = 0; i < ssa->vars_count; i++) {
1176 			if (ra[i].ref) {
1177 				fprintf(stderr, "#%d.", i);
1178 				uint32_t var_num = ssa->vars[i].var;
1179 				zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
1180 				if (ra[i].flags & ZREG_LOAD) {
1181 					fprintf(stderr, " load");
1182 				}
1183 				if (ra[i].flags & ZREG_STORE) {
1184 					fprintf(stderr, " store");
1185 				}
1186 				fprintf(stderr, "\n");
1187 			}
1188 		}
1189 		fprintf(stderr, "\n");
1190 	}
1191 
1192 	ctx->ra = ra;
1193 }
1194 
zend_jit_compute_post_order(zend_cfg * cfg,int start,int * post_order)1195 static int zend_jit_compute_post_order(zend_cfg *cfg, int start, int *post_order)
1196 {
1197 	int count = 0;
1198 	int b, n, *p;
1199 	zend_basic_block *bb;
1200 	zend_worklist worklist;
1201 	ALLOCA_FLAG(use_heap)
1202 
1203 	ZEND_WORKLIST_ALLOCA(&worklist, cfg->blocks_count, use_heap);
1204 	zend_worklist_push(&worklist, start);
1205 
1206 	while (zend_worklist_len(&worklist) != 0) {
1207 next:
1208 		b = zend_worklist_peek(&worklist);
1209 		bb = &cfg->blocks[b];
1210 		n = bb->successors_count;
1211 		if (n > 0) {
1212 			p = bb->successors;
1213 			do {
1214 				if (cfg->blocks[*p].flags & (ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END)) {
1215 					/* skip */
1216 				} else if (zend_worklist_push(&worklist, *p)) {
1217 					goto next;
1218 				}
1219 				p++;
1220 				n--;
1221 			} while (n > 0);
1222 		}
1223 		zend_worklist_pop(&worklist);
1224 		post_order[count++] = b;
1225 	}
1226 	ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
1227 	return count;
1228 }
1229 
zend_jit_next_is_send_result(const zend_op * opline)1230 static bool zend_jit_next_is_send_result(const zend_op *opline)
1231 {
1232 	if (opline->result_type == IS_TMP_VAR
1233 	 && (opline+1)->opcode == ZEND_SEND_VAL
1234 	 && (opline+1)->op1_type == IS_TMP_VAR
1235 	 && (opline+1)->op2_type != IS_CONST
1236 	 && (opline+1)->op1.var == opline->result.var) {
1237 		return 1;
1238 	}
1239 	return 0;
1240 }
1241 
zend_jit_supported_binary_op(uint8_t op,uint32_t op1_info,uint32_t op2_info)1242 static bool zend_jit_supported_binary_op(uint8_t op, uint32_t op1_info, uint32_t op2_info)
1243 {
1244 	if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
1245 		return false;
1246 	}
1247 	switch (op) {
1248 		case ZEND_POW:
1249 		case ZEND_DIV:
1250 			// TODO: check for division by zero ???
1251 			return false;
1252 		case ZEND_ADD:
1253 		case ZEND_SUB:
1254 		case ZEND_MUL:
1255 			return (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
1256 				&& (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
1257 		case ZEND_BW_OR:
1258 		case ZEND_BW_AND:
1259 		case ZEND_BW_XOR:
1260 		case ZEND_SL:
1261 		case ZEND_SR:
1262 		case ZEND_MOD:
1263 			return (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG);
1264 		case ZEND_CONCAT:
1265 			return (op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING);
1266 		EMPTY_SWITCH_DEFAULT_CASE()
1267 	}
1268 }
1269 
zend_jit(const zend_op_array * op_array,zend_ssa * ssa,const zend_op * rt_opline)1270 static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_opline)
1271 {
1272 	int b, i, end;
1273 	zend_op *opline;
1274 	zend_jit_ctx ctx;
1275 	zend_jit_ctx *jit = &ctx;
1276 	zend_jit_reg_var *ra = NULL;
1277 	void *handler;
1278 	int call_level = 0;
1279 	void *checkpoint = NULL;
1280 	bool recv_emitted = 0;   /* emitted at least one RECV opcode */
1281 	uint8_t smart_branch_opcode;
1282 	uint32_t target_label, target_label2;
1283 	uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_mem_info;
1284 	zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
1285 	zend_class_entry *ce;
1286 	bool ce_is_instanceof;
1287 	bool on_this;
1288 
1289 	ZEND_ASSERT(!(op_array->fn_flags & ZEND_ACC_CLOSURE) || !(op_array->scope));
1290 
1291 	if (JIT_G(bisect_limit)) {
1292 		jit_bisect_pos++;
1293 		if (jit_bisect_pos >= JIT_G(bisect_limit)) {
1294 			if (jit_bisect_pos == JIT_G(bisect_limit)) {
1295 				fprintf(stderr, "Not JITing %s%s%s in %s:%d and after due to jit_bisect_limit\n",
1296 					op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
1297 					op_array->scope ? "::" : "",
1298 					op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}",
1299 					ZSTR_VAL(op_array->filename), op_array->line_start);
1300 			}
1301 			return FAILURE;
1302 		}
1303 	}
1304 
1305 	if (ssa->cfg.flags & ZEND_FUNC_IRREDUCIBLE) {
1306 		/* We can't order blocks properly */
1307 		return FAILURE;
1308 	}
1309 
1310 	if (rt_opline) {
1311 		/* Set BB_ENTRY flag to limit register usage across the OSR ENTRY point */
1312 		ssa->cfg.blocks[ssa->cfg.map[rt_opline - op_array->opcodes]].flags |= ZEND_BB_ENTRY;
1313 	}
1314 
1315 	zend_jit_start(&ctx, op_array, ssa);
1316 	if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
1317 		checkpoint = zend_arena_checkpoint(CG(arena));
1318 		zend_jit_allocate_registers(&ctx, op_array, ssa);
1319 		ra = ctx.ra;
1320 	}
1321 
1322 	/* Process blocks in Reverse Post Order */
1323 	int *sorted_blocks = alloca(sizeof(int) * ssa->cfg.blocks_count);
1324 	int n = zend_jit_compute_post_order(&ssa->cfg, 0, sorted_blocks);
1325 
1326 	while (n > 0) {
1327 		b = sorted_blocks[--n];
1328 		if ((ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE) == 0) {
1329 			continue;
1330 		}
1331 
1332 		if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) {
1333 			opline = op_array->opcodes + ssa->cfg.blocks[b].start;
1334 			if (ssa->cfg.flags & ZEND_CFG_RECV_ENTRY) {
1335 				if (opline->opcode == ZEND_RECV_INIT) {
1336 					if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1337 						if (opline != op_array->opcodes && (opline-1)->opcode != ZEND_RECV_INIT) {
1338 							zend_jit_recv_entry(&ctx, b);
1339 						}
1340 					} else {
1341 						if (opline != op_array->opcodes && recv_emitted) {
1342 							zend_jit_recv_entry(&ctx, b);
1343 						}
1344 					}
1345 					recv_emitted = 1;
1346 				} else if (opline->opcode == ZEND_RECV) {
1347 					if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
1348 						/* skip */
1349 						zend_jit_bb_start(&ctx, b);
1350 						zend_jit_bb_end(&ctx, b);
1351 						continue;
1352 					} else if (recv_emitted) {
1353 						zend_jit_recv_entry(&ctx, b);
1354 					} else {
1355 						recv_emitted = 1;
1356 					}
1357 				} else {
1358 					if (recv_emitted) {
1359 						zend_jit_recv_entry(&ctx, b);
1360 					} else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
1361 					           ssa->cfg.blocks[b].len == 1 &&
1362 					           (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
1363 						/* don't generate code for BB with single opcode */
1364 						zend_jit_free_ctx(&ctx);
1365 
1366 						if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
1367 							zend_arena_release(&CG(arena), checkpoint);
1368 						}
1369 						return SUCCESS;
1370 					}
1371 				}
1372 			} else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
1373 			           ssa->cfg.blocks[b].len == 1 &&
1374 			           (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
1375 				/* don't generate code for BB with single opcode */
1376 				zend_jit_free_ctx(&ctx);
1377 
1378 				if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
1379 					zend_arena_release(&CG(arena), checkpoint);
1380 				}
1381 				return SUCCESS;
1382 			}
1383 		}
1384 
1385 		zend_jit_bb_start(&ctx, b);
1386 
1387 		if ((JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) && ctx.ra) {
1388 			zend_ssa_phi *phi = ssa->blocks[b].phis;
1389 
1390 			/* First try to insert IR Phi */
1391 			while (phi) {
1392 				zend_jit_reg_var *ival = &ctx.ra[phi->ssa_var];
1393 
1394 				if (ival->ref) {
1395 					if (ival->flags & ZREG_PI) {
1396 						zend_jit_gen_pi(jit, phi);
1397 					} else if (ival->flags & ZREG_PHI) {
1398 						zend_jit_gen_phi(jit, phi);
1399 					}
1400 				}
1401 				phi = phi->next;
1402 			}
1403 		}
1404 
1405 		if (rt_opline
1406 		 && (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) == 0
1407 		 && rt_opline == op_array->opcodes + ssa->cfg.blocks[b].start) {
1408 			zend_jit_osr_entry(&ctx, b); /* OSR (On-Stack-Replacement) Entry-Point */
1409 		}
1410 
1411 		if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1412 			if ((ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW)
1413 			  && ssa->cfg.blocks[b].start != 0
1414 			  && (op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_NOP
1415 			   || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG
1416 			   || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING
1417 			   || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_MATCH)) {
1418 				zend_jit_reset_last_valid_opline(&ctx);
1419 			} else {
1420 				zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start);
1421 			}
1422 		} else if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) {
1423 			zend_jit_reset_last_valid_opline(&ctx);
1424 		} else if (ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY) {
1425 			zend_jit_reset_last_valid_opline(&ctx);
1426 		} else if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY)) {
1427 			zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start);
1428 		}
1429 		if (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) {
1430 			zend_jit_check_timeout(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start, NULL);
1431 		}
1432 		if (!ssa->cfg.blocks[b].len) {
1433 			zend_jit_bb_end(&ctx, b);
1434 			continue;
1435 		}
1436 		if ((JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) && ra) {
1437 			zend_ssa_phi *phi = ssa->blocks[b].phis;
1438 
1439 			while (phi) {
1440 				zend_jit_reg_var *ival = &ra[phi->ssa_var];
1441 
1442 				if (ival->ref) {
1443 					if (ival->flags & ZREG_LOAD) {
1444 						ZEND_ASSERT(ival->ref == IR_NULL);
1445 
1446 						if (!zend_jit_load_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, phi->ssa_var)) {
1447 							goto jit_failure;
1448 						}
1449 					} else if (ival->flags & ZREG_STORE) {
1450 						ZEND_ASSERT(ival->ref != IR_NULL);
1451 
1452 						if (!zend_jit_store_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, phi->ssa_var, 1)) {
1453 							goto jit_failure;
1454 						}
1455 					}
1456 				}
1457 				phi = phi->next;
1458 			}
1459 		}
1460 		end = ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1;
1461 		for (i = ssa->cfg.blocks[b].start; i <= end; i++) {
1462 			zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[i] : NULL;
1463 			opline = op_array->opcodes + i;
1464 			switch (opline->opcode) {
1465 				case ZEND_INIT_FCALL:
1466 				case ZEND_INIT_FCALL_BY_NAME:
1467 				case ZEND_INIT_NS_FCALL_BY_NAME:
1468 				case ZEND_INIT_METHOD_CALL:
1469 				case ZEND_INIT_DYNAMIC_CALL:
1470 				case ZEND_INIT_STATIC_METHOD_CALL:
1471 				case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
1472 				case ZEND_INIT_USER_CALL:
1473 				case ZEND_NEW:
1474 					call_level++;
1475 			}
1476 
1477 			if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
1478 				switch (opline->opcode) {
1479 					case ZEND_PRE_INC:
1480 					case ZEND_PRE_DEC:
1481 					case ZEND_POST_INC:
1482 					case ZEND_POST_DEC:
1483 						if (opline->op1_type != IS_CV) {
1484 							break;
1485 						}
1486 						op1_info = OP1_INFO();
1487 						if (!(op1_info & MAY_BE_LONG)) {
1488 							break;
1489 						}
1490 						if (opline->result_type != IS_UNUSED) {
1491 							res_use_info = -1;
1492 
1493 							if (opline->result_type == IS_CV
1494 							 && ssa->vars
1495 							 && ssa_op->result_use >= 0
1496 							 && !ssa->vars[ssa_op->result_use].no_val) {
1497 								zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
1498 
1499 								if (Z_MODE(res_use_addr) != IS_REG
1500 								 || Z_LOAD(res_use_addr)
1501 								 || Z_STORE(res_use_addr)) {
1502 									res_use_info = RES_USE_INFO();
1503 								}
1504 							}
1505 							res_info = RES_INFO();
1506 							res_addr = RES_REG_ADDR();
1507 						} else {
1508 							res_use_info = -1;
1509 							res_info = -1;
1510 							res_addr = 0;
1511 						}
1512 						op1_def_info = OP1_DEF_INFO();
1513 						if (!zend_jit_inc_dec(&ctx, opline,
1514 								op1_info, OP1_REG_ADDR(),
1515 								op1_def_info, OP1_DEF_REG_ADDR(),
1516 								res_use_info, res_info,
1517 								res_addr,
1518 								(op1_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
1519 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1520 							goto jit_failure;
1521 						}
1522 						goto done;
1523 					case ZEND_BW_OR:
1524 					case ZEND_BW_AND:
1525 					case ZEND_BW_XOR:
1526 					case ZEND_SL:
1527 					case ZEND_SR:
1528 					case ZEND_MOD:
1529 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1530 							break;
1531 						}
1532 						op1_info = OP1_INFO();
1533 						op2_info = OP2_INFO();
1534 						if (!(op1_info & MAY_BE_LONG)
1535 						 || !(op2_info & MAY_BE_LONG)) {
1536 							break;
1537 						}
1538 						res_addr = RES_REG_ADDR();
1539 						if (Z_MODE(res_addr) != IS_REG
1540 						 && (i + 1) <= end
1541 						 && zend_jit_next_is_send_result(opline)) {
1542 							i++;
1543 							res_use_info = -1;
1544 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1545 							if (!zend_jit_reuse_ip(&ctx)) {
1546 								goto jit_failure;
1547 							}
1548 						} else {
1549 							res_use_info = -1;
1550 
1551 							if (opline->result_type == IS_CV
1552 							 && ssa->vars
1553 							 && ssa_op->result_use >= 0
1554 							 && !ssa->vars[ssa_op->result_use].no_val) {
1555 								zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
1556 
1557 								if (Z_MODE(res_use_addr) != IS_REG
1558 								 || Z_LOAD(res_use_addr)
1559 								 || Z_STORE(res_use_addr)) {
1560 									res_use_info = RES_USE_INFO();
1561 								}
1562 							}
1563 						}
1564 						if (!zend_jit_long_math(&ctx, opline,
1565 								op1_info, OP1_RANGE(), OP1_REG_ADDR(),
1566 								op2_info, OP2_RANGE(), OP2_REG_ADDR(),
1567 								res_use_info, RES_INFO(), res_addr,
1568 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1569 							goto jit_failure;
1570 						}
1571 						goto done;
1572 					case ZEND_ADD:
1573 					case ZEND_SUB:
1574 					case ZEND_MUL:
1575 //					case ZEND_DIV: // TODO: check for division by zero ???
1576 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1577 							break;
1578 						}
1579 						op1_info = OP1_INFO();
1580 						op2_info = OP2_INFO();
1581 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
1582 							break;
1583 						}
1584 						if (opline->opcode == ZEND_ADD &&
1585 						    (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
1586 						    (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
1587 							/* pass */
1588 						} else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
1589 						    !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1590 							break;
1591 						}
1592 						res_addr = RES_REG_ADDR();
1593 						if (Z_MODE(res_addr) != IS_REG
1594 						 && (i + 1) <= end
1595 						 && zend_jit_next_is_send_result(opline)) {
1596 							i++;
1597 							res_use_info = -1;
1598 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1599 							if (!zend_jit_reuse_ip(&ctx)) {
1600 								goto jit_failure;
1601 							}
1602 						} else {
1603 							res_use_info = -1;
1604 
1605 							if (opline->result_type == IS_CV
1606 							 && ssa->vars
1607 							 && ssa_op->result_use >= 0
1608 							 && !ssa->vars[ssa_op->result_use].no_val) {
1609 								zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
1610 
1611 								if (Z_MODE(res_use_addr) != IS_REG
1612 								 || Z_LOAD(res_use_addr)
1613 								 || Z_STORE(res_use_addr)) {
1614 									res_use_info = RES_USE_INFO();
1615 								}
1616 							}
1617 						}
1618 						res_info = RES_INFO();
1619 						if (opline->opcode == ZEND_ADD &&
1620 						    (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
1621 						    (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
1622 							if (!zend_jit_add_arrays(&ctx, opline, op1_info, OP1_REG_ADDR(), op2_info, OP2_REG_ADDR(), res_addr)) {
1623 								goto jit_failure;
1624 							}
1625 						} else {
1626 							if (!zend_jit_math(&ctx, opline,
1627 									op1_info, OP1_REG_ADDR(),
1628 									op2_info, OP2_REG_ADDR(),
1629 									res_use_info, res_info, res_addr,
1630 									(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
1631 									zend_may_throw(opline, ssa_op, op_array, ssa))) {
1632 								goto jit_failure;
1633 							}
1634 						}
1635 						goto done;
1636 					case ZEND_CONCAT:
1637 					case ZEND_FAST_CONCAT:
1638 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1639 							break;
1640 						}
1641 						op1_info = OP1_INFO();
1642 						op2_info = OP2_INFO();
1643 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
1644 							break;
1645 						}
1646 						if (!(op1_info & MAY_BE_STRING) ||
1647 						    !(op2_info & MAY_BE_STRING)) {
1648 							break;
1649 						}
1650 						res_addr = RES_REG_ADDR();
1651 						if ((i + 1) <= end
1652 						 && zend_jit_next_is_send_result(opline)) {
1653 							i++;
1654 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1655 							if (!zend_jit_reuse_ip(&ctx)) {
1656 								goto jit_failure;
1657 							}
1658 						}
1659 						if (!zend_jit_concat(&ctx, opline,
1660 								op1_info, op2_info, res_addr,
1661 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1662 							goto jit_failure;
1663 						}
1664 						goto done;
1665 					case ZEND_ASSIGN_OP:
1666 						if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1667 							break;
1668 						}
1669 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1670 							break;
1671 						}
1672 						op1_info = OP1_INFO();
1673 						op2_info = OP2_INFO();
1674 						if (!zend_jit_supported_binary_op(
1675 								opline->extended_value, op1_info, op2_info)) {
1676 							break;
1677 						}
1678 						op1_addr = OP1_REG_ADDR();
1679 						op1_mem_info = -1;
1680 						if (Z_MODE(op1_addr) != IS_REG
1681 						 || Z_LOAD(op1_addr)
1682 						 || Z_STORE(op1_addr)) {
1683 							op1_mem_info = op1_info;
1684 						}
1685 						op1_def_info = OP1_DEF_INFO();
1686 						if (!zend_jit_assign_op(&ctx, opline,
1687 								op1_info, op1_addr, OP1_RANGE(),
1688 								op1_def_info, OP1_DEF_REG_ADDR(), op1_mem_info,
1689 								op2_info, OP2_REG_ADDR(), OP2_RANGE(),
1690 								(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
1691 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1692 							goto jit_failure;
1693 						}
1694 						goto done;
1695 					case ZEND_ASSIGN_DIM_OP:
1696 						if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1697 							break;
1698 						}
1699 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1700 							break;
1701 						}
1702 						if (!zend_jit_supported_binary_op(
1703 								opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
1704 							break;
1705 						}
1706 						if (!zend_jit_assign_dim_op(&ctx, opline,
1707 								OP1_INFO(), OP1_DEF_INFO(), OP1_REG_ADDR(),
1708 								OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
1709 								(opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
1710 								OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(), IS_UNKNOWN,
1711 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1712 							goto jit_failure;
1713 						}
1714 						goto done;
1715 					case ZEND_ASSIGN_DIM:
1716 						if (opline->op1_type != IS_CV) {
1717 							break;
1718 						}
1719 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1720 							break;
1721 						}
1722 						if (!zend_jit_assign_dim(&ctx, opline,
1723 								OP1_INFO(), OP1_REG_ADDR(),
1724 								OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
1725 								(opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
1726 								OP1_DATA_INFO(), OP1_DATA_REG_ADDR(),
1727 								(ctx.ra && (ssa_op+1)->op1_def >= 0) ? OP1_DATA_DEF_REG_ADDR() : 0,
1728 								(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
1729 								IS_UNKNOWN,
1730 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1731 							goto jit_failure;
1732 						}
1733 						goto done;
1734 					case ZEND_PRE_INC_OBJ:
1735 					case ZEND_PRE_DEC_OBJ:
1736 					case ZEND_POST_INC_OBJ:
1737 					case ZEND_POST_DEC_OBJ:
1738 						if (opline->op2_type != IS_CONST
1739 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1740 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1741 							break;
1742 						}
1743 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1744 							break;
1745 						}
1746 						ce = NULL;
1747 						ce_is_instanceof = 0;
1748 						on_this = 0;
1749 						if (opline->op1_type == IS_UNUSED) {
1750 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
1751 							ce = op_array->scope;
1752 							/* scope is NULL for closures. */
1753 							if (ce) {
1754 								ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1755 							}
1756 							op1_addr = 0;
1757 							on_this = 1;
1758 						} else {
1759 							op1_info = OP1_INFO();
1760 							if (!(op1_info & MAY_BE_OBJECT)) {
1761 								break;
1762 							}
1763 							op1_addr = OP1_REG_ADDR();
1764 							if (ssa->var_info && ssa->ops) {
1765 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1766 								if (ssa_op->op1_use >= 0) {
1767 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
1768 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
1769 										ce = op1_ssa->ce;
1770 										ce_is_instanceof = op1_ssa->is_instanceof;
1771 									}
1772 								}
1773 							}
1774 						}
1775 						if (!zend_jit_incdec_obj(&ctx, opline, op_array, ssa, ssa_op,
1776 								op1_info, op1_addr,
1777 								0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
1778 							goto jit_failure;
1779 						}
1780 						goto done;
1781 					case ZEND_ASSIGN_OBJ_OP:
1782 						if (opline->result_type != IS_UNUSED) {
1783 							break;
1784 						}
1785 						if (opline->op2_type != IS_CONST
1786 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1787 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1788 							break;
1789 						}
1790 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1791 							break;
1792 						}
1793 						if (!zend_jit_supported_binary_op(
1794 								opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
1795 							break;
1796 						}
1797 						ce = NULL;
1798 						ce_is_instanceof = 0;
1799 						on_this = 0;
1800 						if (opline->op1_type == IS_UNUSED) {
1801 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
1802 							ce = op_array->scope;
1803 							/* scope is NULL for closures. */
1804 							if (ce) {
1805 								ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1806 							}
1807 							op1_addr = 0;
1808 							on_this = 1;
1809 						} else {
1810 							op1_info = OP1_INFO();
1811 							if (!(op1_info & MAY_BE_OBJECT)) {
1812 								break;
1813 							}
1814 							op1_addr = OP1_REG_ADDR();
1815 							if (ssa->var_info && ssa->ops) {
1816 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1817 								if (ssa_op->op1_use >= 0) {
1818 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
1819 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
1820 										ce = op1_ssa->ce;
1821 										ce_is_instanceof = op1_ssa->is_instanceof;
1822 									}
1823 								}
1824 							}
1825 						}
1826 						if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
1827 								op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
1828 								0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
1829 							goto jit_failure;
1830 						}
1831 						goto done;
1832 					case ZEND_ASSIGN_OBJ:
1833 						if (opline->op2_type != IS_CONST
1834 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1835 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1836 							break;
1837 						}
1838 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1839 							break;
1840 						}
1841 						ce = NULL;
1842 						ce_is_instanceof = 0;
1843 						on_this = 0;
1844 						if (opline->op1_type == IS_UNUSED) {
1845 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
1846 							ce = op_array->scope;
1847 							/* scope is NULL for closures. */
1848 							if (ce) {
1849 								ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1850 							}
1851 							op1_addr = 0;
1852 							on_this = 1;
1853 						} else {
1854 							op1_info = OP1_INFO();
1855 							if (!(op1_info & MAY_BE_OBJECT)) {
1856 								break;
1857 							}
1858 							op1_addr = OP1_REG_ADDR();
1859 							if (ssa->var_info && ssa->ops) {
1860 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1861 								if (ssa_op->op1_use >= 0) {
1862 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
1863 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
1864 										ce = op1_ssa->ce;
1865 										ce_is_instanceof = op1_ssa->is_instanceof;
1866 									}
1867 								}
1868 							}
1869 						}
1870 						if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
1871 								op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
1872 								(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
1873 								0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN,
1874 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1875 							goto jit_failure;
1876 						}
1877 						goto done;
1878 					case ZEND_ASSIGN:
1879 						if (opline->op1_type != IS_CV) {
1880 							break;
1881 						}
1882 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1883 							break;
1884 						}
1885 						op2_addr = OP2_REG_ADDR();
1886 						if (ra
1887 						 && ssa->ops[opline - op_array->opcodes].op2_def >= 0
1888 						 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op2_def].no_val) {
1889 							op2_def_addr = OP2_DEF_REG_ADDR();
1890 						} else {
1891 							op2_def_addr = op2_addr;
1892 						}
1893 						op1_info = OP1_INFO();
1894 						if (ra && ssa->vars[ssa_op->op1_use].no_val) {
1895 							op1_info |= MAY_BE_UNDEF; // requres type assignment
1896 						}
1897 						if (opline->result_type == IS_UNUSED) {
1898 							res_addr = 0;
1899 							res_info = -1;
1900 						} else {
1901 							res_addr = RES_REG_ADDR();
1902 							res_info = RES_INFO();
1903 							if (Z_MODE(res_addr) != IS_REG
1904 							 && (i + 1) <= end
1905 							 && zend_jit_next_is_send_result(opline)
1906 							 && (!(op1_info & MAY_HAVE_DTOR) || !(op1_info & MAY_BE_RC1))) {
1907 								i++;
1908 								res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1909 								if (!zend_jit_reuse_ip(&ctx)) {
1910 									goto jit_failure;
1911 								}
1912 							}
1913 						}
1914 						if (!zend_jit_assign(&ctx, opline,
1915 								op1_info, OP1_REG_ADDR(),
1916 								OP1_DEF_INFO(), OP1_DEF_REG_ADDR(),
1917 								OP2_INFO(), op2_addr, op2_def_addr,
1918 								res_info, res_addr,
1919 								0,
1920 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
1921 							goto jit_failure;
1922 						}
1923 						goto done;
1924 					case ZEND_QM_ASSIGN:
1925 						op1_addr = OP1_REG_ADDR();
1926 						if (ra
1927 						 && ssa->ops[opline - op_array->opcodes].op1_def >= 0
1928 						 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
1929 							op1_def_addr = OP1_DEF_REG_ADDR();
1930 						} else {
1931 							op1_def_addr = op1_addr;
1932 						}
1933 						if (!zend_jit_qm_assign(&ctx, opline,
1934 								OP1_INFO(), op1_addr, op1_def_addr,
1935 								-1, RES_INFO(), RES_REG_ADDR())) {
1936 							goto jit_failure;
1937 						}
1938 						goto done;
1939 					case ZEND_INIT_FCALL:
1940 					case ZEND_INIT_FCALL_BY_NAME:
1941 					case ZEND_INIT_NS_FCALL_BY_NAME:
1942 						if (!zend_jit_init_fcall(&ctx, opline, b, op_array, ssa, ssa_op, call_level, NULL, 0)) {
1943 							goto jit_failure;
1944 						}
1945 						goto done;
1946 					case ZEND_SEND_VAL:
1947 					case ZEND_SEND_VAL_EX:
1948 						if (opline->op2_type == IS_CONST) {
1949 							/* Named parameters not supported in JIT (yet) */
1950 							break;
1951 						}
1952 						if (opline->opcode == ZEND_SEND_VAL_EX
1953 						 && opline->op2.num > MAX_ARG_FLAG_NUM) {
1954 							break;
1955 						}
1956 						if (!zend_jit_send_val(&ctx, opline,
1957 								OP1_INFO(), OP1_REG_ADDR())) {
1958 							goto jit_failure;
1959 						}
1960 						goto done;
1961 					case ZEND_SEND_REF:
1962 						if (opline->op2_type == IS_CONST) {
1963 							/* Named parameters not supported in JIT (yet) */
1964 							break;
1965 						}
1966 						if (!zend_jit_send_ref(&ctx, opline, op_array,
1967 								OP1_INFO(), 0)) {
1968 							goto jit_failure;
1969 						}
1970 						goto done;
1971 					case ZEND_SEND_VAR:
1972 					case ZEND_SEND_VAR_EX:
1973 					case ZEND_SEND_VAR_NO_REF:
1974 					case ZEND_SEND_VAR_NO_REF_EX:
1975 					case ZEND_SEND_FUNC_ARG:
1976 						if (opline->op2_type == IS_CONST) {
1977 							/* Named parameters not supported in JIT (yet) */
1978 							break;
1979 						}
1980 						if ((opline->opcode == ZEND_SEND_VAR_EX
1981 						  || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
1982 						 && opline->op2.num > MAX_ARG_FLAG_NUM) {
1983 							break;
1984 						}
1985 						op1_addr = OP1_REG_ADDR();
1986 						if (ra
1987 						 && ssa->ops[opline - op_array->opcodes].op1_def >= 0
1988 						 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
1989 							op1_def_addr = OP1_DEF_REG_ADDR();
1990 						} else {
1991 							op1_def_addr = op1_addr;
1992 						}
1993 						if (!zend_jit_send_var(&ctx, opline, op_array,
1994 								OP1_INFO(), op1_addr, op1_def_addr)) {
1995 							goto jit_failure;
1996 						}
1997 						goto done;
1998 					case ZEND_CHECK_FUNC_ARG:
1999 						if (opline->op2_type == IS_CONST) {
2000 							/* Named parameters not supported in JIT (yet) */
2001 							break;
2002 						}
2003 						if (opline->op2.num > MAX_ARG_FLAG_NUM) {
2004 							break;
2005 						}
2006 						if (!zend_jit_check_func_arg(&ctx, opline)) {
2007 							goto jit_failure;
2008 						}
2009 						goto done;
2010 					case ZEND_CHECK_UNDEF_ARGS:
2011 						if (!zend_jit_check_undef_args(&ctx, opline)) {
2012 							goto jit_failure;
2013 						}
2014 						goto done;
2015 					case ZEND_DO_UCALL:
2016 						ZEND_FALLTHROUGH;
2017 					case ZEND_DO_ICALL:
2018 					case ZEND_DO_FCALL_BY_NAME:
2019 					case ZEND_DO_FCALL:
2020 						if (!zend_jit_do_fcall(&ctx, opline, op_array, ssa, call_level, b + 1, NULL)) {
2021 							goto jit_failure;
2022 						}
2023 						goto done;
2024 					case ZEND_IS_EQUAL:
2025 					case ZEND_IS_NOT_EQUAL:
2026 					case ZEND_IS_SMALLER:
2027 					case ZEND_IS_SMALLER_OR_EQUAL:
2028 					case ZEND_CASE: {
2029 						res_addr = RES_REG_ADDR();
2030 						if ((opline->result_type & IS_TMP_VAR)
2031 						 && (i + 1) <= end
2032 						 && ((opline+1)->opcode == ZEND_JMPZ
2033 						  || (opline+1)->opcode == ZEND_JMPNZ
2034 						  || (opline+1)->opcode == ZEND_JMPZ_EX
2035 						  || (opline+1)->opcode == ZEND_JMPNZ_EX)
2036 						 && (opline+1)->op1_type == IS_TMP_VAR
2037 						 && (opline+1)->op1.var == opline->result.var) {
2038 							i++;
2039 							smart_branch_opcode = (opline+1)->opcode;
2040 							target_label = ssa->cfg.blocks[b].successors[0];
2041 							target_label2 = ssa->cfg.blocks[b].successors[1];
2042 							/* For EX variant write into the result of EX opcode. */
2043 							if ((opline+1)->opcode == ZEND_JMPZ_EX
2044 									|| (opline+1)->opcode == ZEND_JMPNZ_EX) {
2045 								res_addr = OP_REG_ADDR(opline + 1, ssa_op + 1, result_type, result, result_def);
2046 							}
2047 						} else {
2048 							smart_branch_opcode = 0;
2049 							target_label = target_label2 = (uint32_t)-1;
2050 						}
2051 						if (!zend_jit_cmp(&ctx, opline,
2052 								OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
2053 								OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
2054 								res_addr,
2055 								zend_may_throw(opline, ssa_op, op_array, ssa),
2056 								smart_branch_opcode, target_label, target_label2,
2057 								NULL, 0)) {
2058 							goto jit_failure;
2059 						}
2060 						goto done;
2061 					}
2062 					case ZEND_IS_IDENTICAL:
2063 					case ZEND_IS_NOT_IDENTICAL:
2064 					case ZEND_CASE_STRICT:
2065 						res_addr = RES_REG_ADDR();
2066 						if ((opline->result_type & IS_TMP_VAR)
2067 						 && (i + 1) <= end
2068 						 && ((opline+1)->opcode == ZEND_JMPZ
2069 						  || (opline+1)->opcode == ZEND_JMPZ_EX
2070 						  || (opline+1)->opcode == ZEND_JMPNZ_EX
2071 						  || (opline+1)->opcode == ZEND_JMPNZ)
2072 						 && (opline+1)->op1_type == IS_TMP_VAR
2073 						 && (opline+1)->op1.var == opline->result.var) {
2074 							i++;
2075 							smart_branch_opcode = (opline+1)->opcode;
2076 							target_label = ssa->cfg.blocks[b].successors[0];
2077 							target_label2 = ssa->cfg.blocks[b].successors[1];
2078 							/* For EX variant write into the result of EX opcode. */
2079 							if ((opline+1)->opcode == ZEND_JMPZ_EX
2080 									|| (opline+1)->opcode == ZEND_JMPNZ_EX) {
2081 								res_addr = OP_REG_ADDR(opline + 1, ssa_op + 1, result_type, result, result_def);
2082 							}
2083 						} else {
2084 							smart_branch_opcode = 0;
2085 							target_label = target_label2 = (uint32_t)-1;
2086 						}
2087 						if (!zend_jit_identical(&ctx, opline,
2088 								OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
2089 								OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
2090 								res_addr,
2091 								zend_may_throw(opline, ssa_op, op_array, ssa),
2092 								smart_branch_opcode, target_label, target_label2,
2093 								NULL, 0)) {
2094 							goto jit_failure;
2095 						}
2096 						goto done;
2097 					case ZEND_DEFINED:
2098 						if ((opline->result_type & IS_TMP_VAR)
2099 						 && (i + 1) <= end
2100 						 && ((opline+1)->opcode == ZEND_JMPZ
2101 						  || (opline+1)->opcode == ZEND_JMPNZ)
2102 						 && (opline+1)->op1_type == IS_TMP_VAR
2103 						 && (opline+1)->op1.var == opline->result.var) {
2104 							i++;
2105 							smart_branch_opcode = (opline+1)->opcode;
2106 							target_label = ssa->cfg.blocks[b].successors[0];
2107 							target_label2 = ssa->cfg.blocks[b].successors[1];
2108 						} else {
2109 							smart_branch_opcode = 0;
2110 							target_label = target_label2 = (uint32_t)-1;
2111 						}
2112 						if (!zend_jit_defined(&ctx, opline, smart_branch_opcode, target_label, target_label2, NULL)) {
2113 							goto jit_failure;
2114 						}
2115 						goto done;
2116 					case ZEND_TYPE_CHECK:
2117 						if (opline->extended_value == MAY_BE_RESOURCE) {
2118 							// TODO: support for is_resource() ???
2119 							break;
2120 						}
2121 						if ((opline->result_type & IS_TMP_VAR)
2122 						 && (i + 1) <= end
2123 						 && ((opline+1)->opcode == ZEND_JMPZ
2124 						  || (opline+1)->opcode == ZEND_JMPNZ)
2125 						 && (opline+1)->op1_type == IS_TMP_VAR
2126 						 && (opline+1)->op1.var == opline->result.var) {
2127 							i++;
2128 							smart_branch_opcode = (opline+1)->opcode;
2129 							target_label = ssa->cfg.blocks[b].successors[0];
2130 							target_label2 = ssa->cfg.blocks[b].successors[1];
2131 						} else {
2132 							smart_branch_opcode = 0;
2133 							target_label = target_label2 = (uint32_t)-1;
2134 						}
2135 						if (!zend_jit_type_check(&ctx, opline, OP1_INFO(), smart_branch_opcode, target_label, target_label2, NULL)) {
2136 							goto jit_failure;
2137 						}
2138 						goto done;
2139 					case ZEND_RETURN:
2140 						op1_info = OP1_INFO();
2141 						if ((PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info))
2142 						 || op_array->type == ZEND_EVAL_CODE
2143 						 // TODO: support for top-level code
2144 						 || !op_array->function_name
2145 						 // TODO: support for IS_UNDEF ???
2146 						 || (op1_info & MAY_BE_UNDEF)) {
2147 							if (!zend_jit_tail_handler(&ctx, opline)) {
2148 								goto jit_failure;
2149 							}
2150 						} else {
2151 							if (!zend_jit_return(&ctx, opline, op_array,
2152 									op1_info, OP1_REG_ADDR())) {
2153 								goto jit_failure;
2154 							}
2155 						}
2156 						goto done;
2157 					case ZEND_BOOL:
2158 					case ZEND_BOOL_NOT:
2159 						if (!zend_jit_bool_jmpznz(&ctx, opline,
2160 								OP1_INFO(), OP1_REG_ADDR(), RES_REG_ADDR(),
2161 								-1, -1,
2162 								zend_may_throw(opline, ssa_op, op_array, ssa),
2163 								opline->opcode, NULL)) {
2164 							goto jit_failure;
2165 						}
2166 						goto done;
2167 					case ZEND_JMPZ:
2168 					case ZEND_JMPNZ:
2169 						if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
2170 						    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
2171 							/* smart branch */
2172 							if (!zend_jit_cond_jmp(&ctx, opline + 1, ssa->cfg.blocks[b].successors[0])) {
2173 								goto jit_failure;
2174 							}
2175 							goto done;
2176 						}
2177 						ZEND_FALLTHROUGH;
2178 					case ZEND_JMPZ_EX:
2179 					case ZEND_JMPNZ_EX:
2180 						if (opline->result_type == IS_UNDEF) {
2181 							res_addr = 0;
2182 						} else {
2183 							res_addr = RES_REG_ADDR();
2184 						}
2185 						if (!zend_jit_bool_jmpznz(&ctx, opline,
2186 								OP1_INFO(), OP1_REG_ADDR(), res_addr,
2187 								ssa->cfg.blocks[b].successors[0], ssa->cfg.blocks[b].successors[1],
2188 								zend_may_throw(opline, ssa_op, op_array, ssa),
2189 								opline->opcode, NULL)) {
2190 							goto jit_failure;
2191 						}
2192 						goto done;
2193 					case ZEND_ISSET_ISEMPTY_CV:
2194 						if ((opline->extended_value & ZEND_ISEMPTY)) {
2195 							// TODO: support for empty() ???
2196 							break;
2197 						}
2198 						if ((opline->result_type & IS_TMP_VAR)
2199 						 && (i + 1) <= end
2200 						 && ((opline+1)->opcode == ZEND_JMPZ
2201 						  || (opline+1)->opcode == ZEND_JMPNZ)
2202 						 && (opline+1)->op1_type == IS_TMP_VAR
2203 						 && (opline+1)->op1.var == opline->result.var) {
2204 							i++;
2205 							smart_branch_opcode = (opline+1)->opcode;
2206 							target_label = ssa->cfg.blocks[b].successors[0];
2207 							target_label2 = ssa->cfg.blocks[b].successors[1];
2208 						} else {
2209 							smart_branch_opcode = 0;
2210 							target_label = target_label2 = (uint32_t)-1;
2211 						}
2212 						if (!zend_jit_isset_isempty_cv(&ctx, opline,
2213 								OP1_INFO(), OP1_REG_ADDR(),
2214 								smart_branch_opcode, target_label, target_label2,
2215 								NULL)) {
2216 							goto jit_failure;
2217 						}
2218 						goto done;
2219 					case ZEND_IN_ARRAY:
2220 						if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
2221 							break;
2222 						}
2223 						op1_info = OP1_INFO();
2224 						if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
2225 							break;
2226 						}
2227 						if ((opline->result_type & IS_TMP_VAR)
2228 						 && (i + 1) <= end
2229 						 && ((opline+1)->opcode == ZEND_JMPZ
2230 						  || (opline+1)->opcode == ZEND_JMPNZ)
2231 						 && (opline+1)->op1_type == IS_TMP_VAR
2232 						 && (opline+1)->op1.var == opline->result.var) {
2233 							i++;
2234 							smart_branch_opcode = (opline+1)->opcode;
2235 							target_label = ssa->cfg.blocks[b].successors[0];
2236 							target_label2 = ssa->cfg.blocks[b].successors[1];
2237 						} else {
2238 							smart_branch_opcode = 0;
2239 							target_label = target_label2 = (uint32_t)-1;
2240 						}
2241 						if (!zend_jit_in_array(&ctx, opline,
2242 								op1_info, OP1_REG_ADDR(),
2243 								smart_branch_opcode, target_label, target_label2,
2244 								NULL)) {
2245 							goto jit_failure;
2246 						}
2247 						goto done;
2248 					case ZEND_FETCH_DIM_R:
2249 					case ZEND_FETCH_DIM_IS:
2250 					case ZEND_FETCH_LIST_R:
2251 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2252 							break;
2253 						}
2254 						if (!zend_jit_fetch_dim_read(&ctx, opline, ssa, ssa_op,
2255 								OP1_INFO(), OP1_REG_ADDR(), 0,
2256 								OP2_INFO(), OP2_REG_ADDR(), OP2_RANGE(),
2257 								RES_INFO(), RES_REG_ADDR(), IS_UNKNOWN)) {
2258 							goto jit_failure;
2259 						}
2260 						goto done;
2261 					case ZEND_FETCH_DIM_W:
2262 					case ZEND_FETCH_DIM_RW:
2263 //					case ZEND_FETCH_DIM_UNSET:
2264 					case ZEND_FETCH_LIST_W:
2265 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2266 							break;
2267 						}
2268 						if (opline->op1_type != IS_CV) {
2269 							break;
2270 						}
2271 						if (!zend_jit_fetch_dim(&ctx, opline,
2272 								OP1_INFO(), OP1_REG_ADDR(),
2273 								OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
2274 								(opline->op2_type != IS_UNUSED) ? OP2_RANGE() : 0,
2275 								RES_REG_ADDR(), IS_UNKNOWN)) {
2276 							goto jit_failure;
2277 						}
2278 						goto done;
2279 					case ZEND_ISSET_ISEMPTY_DIM_OBJ:
2280 						if ((opline->extended_value & ZEND_ISEMPTY)) {
2281 							// TODO: support for empty() ???
2282 							break;
2283 						}
2284 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2285 							break;
2286 						}
2287 						if ((opline->result_type & IS_TMP_VAR)
2288 						 && (i + 1) <= end
2289 						 && ((opline+1)->opcode == ZEND_JMPZ
2290 						  || (opline+1)->opcode == ZEND_JMPNZ)
2291 						 && (opline+1)->op1_type == IS_TMP_VAR
2292 						 && (opline+1)->op1.var == opline->result.var) {
2293 							i++;
2294 							smart_branch_opcode = (opline+1)->opcode;
2295 							target_label = ssa->cfg.blocks[b].successors[0];
2296 							target_label2 = ssa->cfg.blocks[b].successors[1];
2297 						} else {
2298 							smart_branch_opcode = 0;
2299 							target_label = target_label2 = (uint32_t)-1;
2300 						}
2301 						if (!zend_jit_isset_isempty_dim(&ctx, opline,
2302 								OP1_INFO(), OP1_REG_ADDR(), 0,
2303 								OP2_INFO(), OP2_REG_ADDR(), OP2_RANGE(), IS_UNKNOWN,
2304 								zend_may_throw(opline, ssa_op, op_array, ssa),
2305 								smart_branch_opcode, target_label, target_label2,
2306 								NULL)) {
2307 							goto jit_failure;
2308 						}
2309 						goto done;
2310 					case ZEND_FETCH_OBJ_R:
2311 					case ZEND_FETCH_OBJ_IS:
2312 					case ZEND_FETCH_OBJ_W:
2313 						if (opline->op2_type != IS_CONST
2314 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
2315 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
2316 							break;
2317 						}
2318 						ce = NULL;
2319 						ce_is_instanceof = 0;
2320 						on_this = 0;
2321 						if (opline->op1_type == IS_UNUSED) {
2322 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
2323 							op1_addr = 0;
2324 							ce = op_array->scope;
2325 							/* scope is NULL for closures. */
2326 							if (ce) {
2327 								ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2328 							}
2329 							on_this = 1;
2330 						} else {
2331 							op1_info = OP1_INFO();
2332 							if (!(op1_info & MAY_BE_OBJECT)) {
2333 								break;
2334 							}
2335 							op1_addr = OP1_REG_ADDR();
2336 							if (ssa->var_info && ssa->ops) {
2337 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
2338 								if (ssa_op->op1_use >= 0) {
2339 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
2340 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
2341 										ce = op1_ssa->ce;
2342 										ce_is_instanceof = op1_ssa->is_instanceof;
2343 									}
2344 								}
2345 							}
2346 						}
2347 						if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
2348 								op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
2349 								RES_REG_ADDR(), IS_UNKNOWN,
2350 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
2351 							goto jit_failure;
2352 						}
2353 						goto done;
2354 					case ZEND_BIND_GLOBAL:
2355 						if (!ssa->ops || !ssa->var_info) {
2356 							op1_info = MAY_BE_ANY|MAY_BE_REF;
2357 						} else {
2358 							op1_info = OP1_INFO();
2359 						}
2360 						if (!zend_jit_bind_global(&ctx, opline, op1_info)) {
2361 							goto jit_failure;
2362 						}
2363 						goto done;
2364 					case ZEND_RECV:
2365 						if (!zend_jit_recv(&ctx, opline, op_array)) {
2366 							goto jit_failure;
2367 						}
2368 						goto done;
2369 					case ZEND_RECV_INIT:
2370 						if (!zend_jit_recv_init(&ctx, opline, op_array,
2371 								(opline + 1)->opcode != ZEND_RECV_INIT,
2372 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
2373 							goto jit_failure;
2374 						}
2375 						goto done;
2376 					case ZEND_FREE:
2377 					case ZEND_FE_FREE:
2378 						if (!zend_jit_free(&ctx, opline, OP1_INFO(),
2379 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
2380 							goto jit_failure;
2381 						}
2382 						goto done;
2383 					case ZEND_ECHO:
2384 						op1_info = OP1_INFO();
2385 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
2386 							break;
2387 						}
2388 						if (!zend_jit_echo(&ctx, opline, op1_info)) {
2389 							goto jit_failure;
2390 						}
2391 						goto done;
2392 					case ZEND_STRLEN:
2393 						op1_info = OP1_INFO();
2394 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
2395 							break;
2396 						}
2397 						if (!zend_jit_strlen(&ctx, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR())) {
2398 							goto jit_failure;
2399 						}
2400 						goto done;
2401 					case ZEND_COUNT:
2402 						op1_info = OP1_INFO();
2403 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
2404 							break;
2405 						}
2406 						if (!zend_jit_count(&ctx, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
2407 							goto jit_failure;
2408 						}
2409 						goto done;
2410 					case ZEND_FETCH_THIS:
2411 						if (!zend_jit_fetch_this(&ctx, opline, op_array, 0)) {
2412 							goto jit_failure;
2413 						}
2414 						goto done;
2415 					case ZEND_SWITCH_LONG:
2416 					case ZEND_SWITCH_STRING:
2417 					case ZEND_MATCH:
2418 						if (!zend_jit_switch(&ctx, opline, op_array, ssa, NULL, NULL)) {
2419 							goto jit_failure;
2420 						}
2421 						goto done;
2422 					case ZEND_VERIFY_RETURN_TYPE:
2423 						if (opline->op1_type == IS_UNUSED) {
2424 							/* Always throws */
2425 							break;
2426 						}
2427 						if (opline->op1_type == IS_CONST) {
2428 							/* TODO Different instruction format, has return value */
2429 							break;
2430 						}
2431 						if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
2432 							/* Not worth bothering with */
2433 							break;
2434 						}
2435 						if (OP1_INFO() & MAY_BE_REF) {
2436 							/* TODO May need reference unwrapping. */
2437 							break;
2438 						}
2439 						if (!zend_jit_verify_return_type(&ctx, opline, op_array, OP1_INFO())) {
2440 							goto jit_failure;
2441 						}
2442 						goto done;
2443 					case ZEND_FE_RESET_R:
2444 						op1_info = OP1_INFO();
2445 						if ((op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) != MAY_BE_ARRAY) {
2446 							break;
2447 						}
2448 						if (!zend_jit_fe_reset(&ctx, opline, op1_info)) {
2449 							goto jit_failure;
2450 						}
2451 						goto done;
2452 					case ZEND_FE_FETCH_R:
2453 						op1_info = OP1_INFO();
2454 						if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
2455 							break;
2456 						}
2457 						if (!zend_jit_fe_fetch(&ctx, opline, op1_info, OP2_INFO(),
2458 								ssa->cfg.blocks[b].successors[0], opline->opcode, NULL)) {
2459 							goto jit_failure;
2460 						}
2461 						goto done;
2462 					case ZEND_FETCH_CONSTANT:
2463 						if (!zend_jit_fetch_constant(&ctx, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
2464 							goto jit_failure;
2465 						}
2466 						goto done;
2467 					case ZEND_INIT_METHOD_CALL:
2468 						if (opline->op2_type != IS_CONST
2469 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
2470 							break;
2471 						}
2472 						ce = NULL;
2473 						ce_is_instanceof = 0;
2474 						on_this = 0;
2475 						if (opline->op1_type == IS_UNUSED) {
2476 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
2477 							op1_addr = 0;
2478 							ce = op_array->scope;
2479 							/* scope is NULL for closures. */
2480 							if (ce) {
2481 								ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2482 							}
2483 							on_this = 1;
2484 						} else {
2485 							op1_info = OP1_INFO();
2486 							if (!(op1_info & MAY_BE_OBJECT)) {
2487 								break;
2488 							}
2489 							op1_addr = OP1_REG_ADDR();
2490 							if (ssa->var_info && ssa->ops) {
2491 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
2492 								if (ssa_op->op1_use >= 0) {
2493 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
2494 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
2495 										ce = op1_ssa->ce;
2496 										ce_is_instanceof = op1_ssa->is_instanceof;
2497 									}
2498 								}
2499 							}
2500 						}
2501 						if (!zend_jit_init_method_call(&ctx, opline, b, op_array, ssa, ssa_op, call_level,
2502 								op1_info, op1_addr, ce, ce_is_instanceof, on_this, 0, NULL,
2503 								NULL, 0,
2504 								-1, -1,
2505 								0)) {
2506 							goto jit_failure;
2507 						}
2508 						goto done;
2509 					case ZEND_ROPE_INIT:
2510 					case ZEND_ROPE_ADD:
2511 					case ZEND_ROPE_END:
2512 						op2_info = OP2_INFO();
2513 						if ((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
2514 							break;
2515 						}
2516 						if (!zend_jit_rope(&ctx, opline, op2_info)) {
2517 							goto jit_failure;
2518 						}
2519 						goto done;
2520 					default:
2521 						break;
2522 				}
2523 			}
2524 
2525 			switch (opline->opcode) {
2526 				case ZEND_RECV_INIT:
2527 				case ZEND_BIND_GLOBAL:
2528 					if (opline == op_array->opcodes ||
2529 					    opline->opcode != op_array->opcodes[i-1].opcode) {
2530 						/* repeatable opcodes */
2531 						if (!zend_jit_handler(&ctx, opline,
2532 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
2533 							goto jit_failure;
2534 						}
2535 					}
2536 					zend_jit_set_last_valid_opline(&ctx, opline+1);
2537 					break;
2538 				case ZEND_NOP:
2539 				case ZEND_OP_DATA:
2540 				case ZEND_SWITCH_LONG:
2541 				case ZEND_SWITCH_STRING:
2542 					break;
2543 				case ZEND_MATCH:
2544 					/* We have to exit to the VM because the MATCH handler performs an N-way jump for
2545 					 * which we can't generate simple (opcache.jit=1201) JIT code. */
2546 					if (!zend_jit_tail_handler(&ctx, opline)) {
2547 						goto jit_failure;
2548 					}
2549 					break;
2550 				case ZEND_JMP:
2551 					if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
2552 						const zend_op *target = OP_JMP_ADDR(opline, opline->op1);
2553 
2554 						if (!zend_jit_set_ip(&ctx, target)) {
2555 							goto jit_failure;
2556 						}
2557 					}
2558 					break;
2559 				case ZEND_CATCH:
2560 				case ZEND_FAST_CALL:
2561 				case ZEND_FAST_RET:
2562 				case ZEND_GENERATOR_CREATE:
2563 				case ZEND_GENERATOR_RETURN:
2564 				case ZEND_RETURN_BY_REF:
2565 				case ZEND_RETURN:
2566 				case ZEND_MATCH_ERROR:
2567 				/* switch through trampoline */
2568 				case ZEND_YIELD:
2569 				case ZEND_YIELD_FROM:
2570 				case ZEND_THROW:
2571 				case ZEND_VERIFY_NEVER_TYPE:
2572 					if (!zend_jit_tail_handler(&ctx, opline)) {
2573 						goto jit_failure;
2574 					}
2575 					/* THROW and EXIT may be used in the middle of BB */
2576 					/* don't generate code for the rest of BB */
2577 					i = end;
2578 					break;
2579 				/* stackless execution */
2580 				case ZEND_INCLUDE_OR_EVAL:
2581 				case ZEND_DO_FCALL:
2582 				case ZEND_DO_UCALL:
2583 				case ZEND_DO_FCALL_BY_NAME:
2584 					if (!zend_jit_call(&ctx, opline, b + 1)) {
2585 						goto jit_failure;
2586 					}
2587 					break;
2588 				case ZEND_JMPZ:
2589 				case ZEND_JMPNZ:
2590 					if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
2591 					    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
2592 						/* smart branch */
2593 						if (!zend_jit_cond_jmp(&ctx, opline + 1, ssa->cfg.blocks[b].successors[0])) {
2594 							goto jit_failure;
2595 						}
2596 						goto done;
2597 					}
2598 					ZEND_FALLTHROUGH;
2599 				case ZEND_JMPZ_EX:
2600 				case ZEND_JMPNZ_EX:
2601 				case ZEND_JMP_SET:
2602 				case ZEND_COALESCE:
2603 				case ZEND_JMP_NULL:
2604 				case ZEND_FE_RESET_R:
2605 				case ZEND_FE_RESET_RW:
2606 				case ZEND_ASSERT_CHECK:
2607 				case ZEND_FE_FETCH_R:
2608 				case ZEND_FE_FETCH_RW:
2609 				case ZEND_BIND_INIT_STATIC_OR_JMP:
2610 					if (!zend_jit_handler(&ctx, opline,
2611 							zend_may_throw(opline, ssa_op, op_array, ssa)) ||
2612 					    !zend_jit_cond_jmp(&ctx, opline + 1, ssa->cfg.blocks[b].successors[0])) {
2613 						goto jit_failure;
2614 					}
2615 					break;
2616 				case ZEND_JMP_FRAMELESS:
2617 					if (!zend_jit_jmp_frameless(&ctx, opline, /* exit_addr */ NULL, /* guard */ 0)) {
2618 						goto jit_failure;
2619 					}
2620 					break;
2621 				case ZEND_NEW:
2622 					if (!zend_jit_handler(&ctx, opline, 1)) {
2623 						return 0;
2624 					}
2625 					if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
2626 						zend_class_entry *ce = NULL;
2627 
2628 						if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) {
2629 							if (ssa->ops && ssa->var_info) {
2630 								zend_ssa_var_info *res_ssa = &ssa->var_info[ssa->ops[opline - op_array->opcodes].result_def];
2631 								if (res_ssa->ce && !res_ssa->is_instanceof) {
2632 									ce = res_ssa->ce;
2633 								}
2634 							}
2635 						} else {
2636 							if (opline->op1_type == IS_CONST) {
2637 								zval *zv = RT_CONSTANT(opline, opline->op1);
2638 								if (Z_TYPE_P(zv) == IS_STRING) {
2639 									zval *lc = zv + 1;
2640 									ce = (zend_class_entry*)zend_hash_find_ptr(EG(class_table), Z_STR_P(lc));
2641 								}
2642 							}
2643 						}
2644 
2645 						i++;
2646 
2647 						if (!ce || !(ce->ce_flags & ZEND_ACC_LINKED) || ce->constructor) {
2648 							const zend_op *next_opline = opline + 1;
2649 
2650 							ZEND_ASSERT(b + 1 == ssa->cfg.blocks[b].successors[0]);
2651 							zend_jit_constructor(&ctx, next_opline, op_array, ssa, call_level, b + 1);
2652 						}
2653 
2654 						/* We skip over the DO_FCALL, so decrement call_level ourselves. */
2655 						call_level--;
2656 					}
2657 					break;
2658 				case ZEND_FRAMELESS_ICALL_0:
2659 					jit_frameless_icall0(jit, opline);
2660 					goto done;
2661 				case ZEND_FRAMELESS_ICALL_1:
2662 					op1_info = OP1_INFO();
2663 					jit_frameless_icall1(jit, opline, op1_info);
2664 					goto done;
2665 				case ZEND_FRAMELESS_ICALL_2:
2666 					op1_info = OP1_INFO();
2667 					op2_info = OP2_INFO();
2668 					jit_frameless_icall2(jit, opline, op1_info, op2_info);
2669 					goto done;
2670 				case ZEND_FRAMELESS_ICALL_3:
2671 					op1_info = OP1_INFO();
2672 					op2_info = OP2_INFO();
2673 					jit_frameless_icall3(jit, opline, op1_info, op2_info, OP1_DATA_INFO());
2674 					goto done;
2675 				default:
2676 					if (!zend_jit_handler(&ctx, opline,
2677 							zend_may_throw(opline, ssa_op, op_array, ssa))) {
2678 						goto jit_failure;
2679 					}
2680 					if (i == end
2681 					 && (opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
2682 						/* smart branch split across basic blocks */
2683 						if (!zend_jit_set_cond(&ctx, opline + 2, opline->result.var)) {
2684 							goto jit_failure;
2685 						}
2686 					}
2687 			}
2688 done:
2689 			switch (opline->opcode) {
2690 				case ZEND_DO_FCALL:
2691 				case ZEND_DO_ICALL:
2692 				case ZEND_DO_UCALL:
2693 				case ZEND_DO_FCALL_BY_NAME:
2694 				case ZEND_CALLABLE_CONVERT:
2695 					call_level--;
2696 			}
2697 		}
2698 		zend_jit_bb_end(&ctx, b);
2699 	}
2700 
2701 	if (jit->return_inputs) {
2702 		zend_jit_common_return(jit);
2703 
2704 		bool left_frame = 0;
2705 		if (op_array->last_var > 100) {
2706 			/* To many CVs to unroll */
2707 			if (!zend_jit_free_cvs(&ctx)) {
2708 				goto jit_failure;
2709 			}
2710 			left_frame = 1;
2711 		}
2712 		if (!left_frame) {
2713 			int j;
2714 
2715 			for (j = 0 ; j < op_array->last_var; j++) {
2716 				uint32_t info = zend_ssa_cv_info(op_array, ssa, j);
2717 
2718 				if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
2719 					if (!left_frame) {
2720 						left_frame = 1;
2721 					    if (!zend_jit_leave_frame(&ctx)) {
2722 							goto jit_failure;
2723 					    }
2724 					}
2725 					if (!zend_jit_free_cv(&ctx, info, j)) {
2726 						goto jit_failure;
2727 					}
2728 				}
2729 			}
2730 		}
2731 		if (!zend_jit_leave_func(&ctx, op_array, NULL, MAY_BE_ANY, left_frame,
2732 				NULL, NULL, (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, 1)) {
2733 			goto jit_failure;
2734 		}
2735 	}
2736 
2737 	handler = zend_jit_finish(&ctx);
2738 	if (!handler) {
2739 		goto jit_failure;
2740 	}
2741 	zend_jit_free_ctx(&ctx);
2742 
2743 	if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
2744 		zend_arena_release(&CG(arena), checkpoint);
2745 	}
2746 	return SUCCESS;
2747 
2748 jit_failure:
2749 	zend_jit_free_ctx(&ctx);
2750 	if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
2751 		zend_arena_release(&CG(arena), checkpoint);
2752 	}
2753 	return FAILURE;
2754 }
2755 
zend_jit_collect_calls(zend_op_array * op_array,zend_script * script)2756 static void zend_jit_collect_calls(zend_op_array *op_array, zend_script *script)
2757 {
2758 	zend_func_info *func_info;
2759 
2760 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
2761 	    JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
2762 	    JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
2763 	    func_info = ZEND_FUNC_INFO(op_array);
2764 	} else {
2765 		func_info = zend_arena_calloc(&CG(arena), 1, sizeof(zend_func_info));
2766 		ZEND_SET_FUNC_INFO(op_array, func_info);
2767 	}
2768 	zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, op_array, func_info);
2769 }
2770 
zend_jit_cleanup_func_info(zend_op_array * op_array)2771 static void zend_jit_cleanup_func_info(zend_op_array *op_array)
2772 {
2773 	zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
2774 	zend_call_info *caller_info, *callee_info;
2775 
2776 	if (func_info) {
2777 		caller_info = func_info->caller_info;
2778 		callee_info = func_info->callee_info;
2779 
2780 		if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
2781 		    JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
2782 		    JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
2783 			func_info->num = 0;
2784 			func_info->flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
2785 				| ZEND_FUNC_JIT_ON_PROF_REQUEST
2786 				| ZEND_FUNC_JIT_ON_HOT_COUNTERS
2787 				| ZEND_FUNC_JIT_ON_HOT_TRACE;
2788 			memset(&func_info->ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
2789 		} else {
2790 			ZEND_SET_FUNC_INFO(op_array, NULL);
2791 		}
2792 
2793 		while (caller_info) {
2794 			if (caller_info->caller_op_array) {
2795 				zend_jit_cleanup_func_info(caller_info->caller_op_array);
2796 			}
2797 			caller_info = caller_info->next_caller;
2798 		}
2799 		while (callee_info) {
2800 			if (callee_info->callee_func && callee_info->callee_func->type == ZEND_USER_FUNCTION) {
2801 				zend_jit_cleanup_func_info(&callee_info->callee_func->op_array);
2802 			}
2803 			callee_info = callee_info->next_callee;
2804 		}
2805 	}
2806 }
2807 
zend_real_jit_func(zend_op_array * op_array,zend_script * script,const zend_op * rt_opline,uint8_t trigger)2808 static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, const zend_op *rt_opline, uint8_t trigger)
2809 {
2810 	zend_ssa ssa;
2811 	void *checkpoint;
2812 	zend_func_info *func_info;
2813 	uint8_t orig_trigger;
2814 
2815 	if (*dasm_ptr == dasm_end) {
2816 		return FAILURE;
2817 	}
2818 
2819 	orig_trigger = JIT_G(trigger);
2820 	JIT_G(trigger) = trigger;
2821 	checkpoint = zend_arena_checkpoint(CG(arena));
2822 
2823 	/* Build SSA */
2824 	memset(&ssa, 0, sizeof(zend_ssa));
2825 
2826 	if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
2827 		if (trigger == ZEND_JIT_ON_FIRST_EXEC) {
2828 			zend_jit_op_array_extension *jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
2829 			op_array = (zend_op_array*) jit_extension->op_array;
2830 		} else if (trigger == ZEND_JIT_ON_HOT_COUNTERS) {
2831 			zend_jit_op_array_hot_extension *jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
2832 			op_array = (zend_op_array*) jit_extension->op_array;
2833 		} else {
2834 			ZEND_ASSERT(!op_array->scope);
2835 		}
2836 	}
2837 
2838 	if (zend_jit_op_array_analyze1(op_array, script, &ssa) != SUCCESS) {
2839 		goto jit_failure;
2840 	}
2841 
2842 	if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNCS) {
2843 		zend_jit_collect_calls(op_array, script);
2844 		func_info = ZEND_FUNC_INFO(op_array);
2845 		func_info->call_map = zend_build_call_map(&CG(arena), func_info, op_array);
2846 		if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
2847 			zend_init_func_return_info(op_array, script, &func_info->return_info);
2848 		}
2849 	}
2850 
2851 	if (zend_jit_op_array_analyze2(op_array, script, &ssa, ZCG(accel_directives).optimization_level) != SUCCESS) {
2852 		goto jit_failure;
2853 	}
2854 
2855 	if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
2856 		zend_dump_op_array(op_array, ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &ssa);
2857 	}
2858 
2859 	if (zend_jit(op_array, &ssa, rt_opline) != SUCCESS) {
2860 		goto jit_failure;
2861 	}
2862 
2863 	zend_jit_cleanup_func_info(op_array);
2864 	zend_arena_release(&CG(arena), checkpoint);
2865 	JIT_G(trigger) = orig_trigger;
2866 	return SUCCESS;
2867 
2868 jit_failure:
2869 	zend_jit_cleanup_func_info(op_array);
2870 	zend_arena_release(&CG(arena), checkpoint);
2871 	JIT_G(trigger) = orig_trigger;
2872 	return FAILURE;
2873 }
2874 
2875 /* Run-time JIT handler */
zend_runtime_jit(void)2876 static int ZEND_FASTCALL zend_runtime_jit(void)
2877 {
2878 	zend_execute_data *execute_data = EG(current_execute_data);
2879 	zend_op_array *op_array = &EX(func)->op_array;
2880 	zend_op *opline = op_array->opcodes;
2881 	zend_jit_op_array_extension *jit_extension;
2882 	bool do_bailout = 0;
2883 
2884 	zend_shared_alloc_lock();
2885 
2886 	if (ZEND_FUNC_INFO(op_array)) {
2887 
2888 		SHM_UNPROTECT();
2889 		zend_jit_unprotect();
2890 
2891 		zend_try {
2892 			/* restore original opcode handlers */
2893 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2894 				while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
2895 					opline++;
2896 				}
2897 			}
2898 			jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
2899 			opline->handler = jit_extension->orig_handler;
2900 
2901 			/* perform real JIT for this function */
2902 			zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_FIRST_EXEC);
2903 		} zend_catch {
2904 			do_bailout = true;
2905 		} zend_end_try();
2906 
2907 		zend_jit_protect();
2908 		SHM_PROTECT();
2909 	}
2910 
2911 	zend_shared_alloc_unlock();
2912 
2913 	if (do_bailout) {
2914 		zend_bailout();
2915 	}
2916 
2917 	/* JIT-ed code is going to be called by VM */
2918 	return 0;
2919 }
2920 
zend_jit_check_funcs(HashTable * function_table,bool is_method)2921 void zend_jit_check_funcs(HashTable *function_table, bool is_method) {
2922 	zend_op *opline;
2923 	zend_function *func;
2924 	zend_op_array *op_array;
2925 	uintptr_t counter;
2926 	zend_jit_op_array_extension *jit_extension;
2927 
2928 	ZEND_HASH_MAP_REVERSE_FOREACH_PTR(function_table, func) {
2929 		if (func->type == ZEND_INTERNAL_FUNCTION) {
2930 			break;
2931 		}
2932 		op_array = &func->op_array;
2933 		opline = op_array->opcodes;
2934 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2935 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
2936 				opline++;
2937 			}
2938 		}
2939 		if (opline->handler == zend_jit_profile_jit_handler) {
2940 			if (!RUN_TIME_CACHE(op_array)) {
2941 				continue;
2942 			}
2943 			counter = (uintptr_t)ZEND_COUNTER_INFO(op_array);
2944 			ZEND_COUNTER_INFO(op_array) = 0;
2945 			jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
2946 			opline->handler = jit_extension->orig_handler;
2947 			if (((double)counter / (double)zend_jit_profile_counter) > JIT_G(prof_threshold)) {
2948 				zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_PROF_REQUEST);
2949 			}
2950 		}
2951 	} ZEND_HASH_FOREACH_END();
2952 }
2953 
zend_jit_hot_func(zend_execute_data * execute_data,const zend_op * opline)2954 void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
2955 {
2956 	zend_op_array *op_array = &EX(func)->op_array;
2957 	zend_jit_op_array_hot_extension *jit_extension;
2958 	uint32_t i;
2959 	bool do_bailout = 0;
2960 
2961 	zend_shared_alloc_lock();
2962 	jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
2963 
2964 	if (jit_extension) {
2965 		SHM_UNPROTECT();
2966 		zend_jit_unprotect();
2967 
2968 		zend_try {
2969 			for (i = 0; i < op_array->last; i++) {
2970 				op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
2971 			}
2972 
2973 			/* perform real JIT for this function */
2974 			zend_real_jit_func(op_array, NULL, opline, ZEND_JIT_ON_HOT_COUNTERS);
2975 		} zend_catch {
2976 			do_bailout = 1;
2977 		} zend_end_try();
2978 
2979 		zend_jit_protect();
2980 		SHM_PROTECT();
2981 	}
2982 
2983 	zend_shared_alloc_unlock();
2984 
2985 	if (do_bailout) {
2986 		zend_bailout();
2987 	}
2988 	/* JIT-ed code is going to be called by VM */
2989 }
2990 
zend_jit_setup_hot_counters_ex(zend_op_array * op_array,zend_cfg * cfg)2991 static void zend_jit_setup_hot_counters_ex(zend_op_array *op_array, zend_cfg *cfg)
2992 {
2993 	if (JIT_G(hot_func)) {
2994 		zend_op *opline = op_array->opcodes;
2995 
2996 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2997 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
2998 				opline++;
2999 			}
3000 		}
3001 
3002 		opline->handler = (const void*)zend_jit_func_hot_counter_handler;
3003 	}
3004 
3005 	if (JIT_G(hot_loop)) {
3006 		uint32_t i;
3007 
3008 		for (i = 0; i < cfg->blocks_count; i++) {
3009 			if ((cfg->blocks[i].flags & ZEND_BB_REACHABLE) &&
3010 			    (cfg->blocks[i].flags & ZEND_BB_LOOP_HEADER)) {
3011 			    op_array->opcodes[cfg->blocks[i].start].handler =
3012 					(const void*)zend_jit_loop_hot_counter_handler;
3013 			}
3014 		}
3015 	}
3016 }
3017 
zend_jit_restart_hot_counters(zend_op_array * op_array)3018 static int zend_jit_restart_hot_counters(zend_op_array *op_array)
3019 {
3020 	zend_jit_op_array_hot_extension *jit_extension;
3021 	zend_cfg cfg;
3022 	uint32_t i;
3023 
3024 	jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
3025 	for (i = 0; i < op_array->last; i++) {
3026 		op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
3027 	}
3028 
3029 	if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
3030 		return FAILURE;
3031 	}
3032 
3033 	zend_jit_setup_hot_counters_ex(op_array, &cfg);
3034 
3035 	return SUCCESS;
3036 }
3037 
zend_jit_setup_hot_counters(zend_op_array * op_array)3038 static int zend_jit_setup_hot_counters(zend_op_array *op_array)
3039 {
3040 	zend_jit_op_array_hot_extension *jit_extension;
3041 	zend_cfg cfg;
3042 	uint32_t i;
3043 
3044 	ZEND_ASSERT(!JIT_G(hot_func) || zend_jit_func_hot_counter_handler != NULL);
3045 	ZEND_ASSERT(!JIT_G(hot_loop) || zend_jit_loop_hot_counter_handler != NULL);
3046 
3047 	if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
3048 		return FAILURE;
3049 	}
3050 
3051 	jit_extension = (zend_jit_op_array_hot_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_hot_extension) + (op_array->last - 1) * sizeof(void*));
3052 	if (!jit_extension) {
3053 		return FAILURE;
3054 	}
3055 	memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
3056 	jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_HOT_COUNTERS;
3057 	jit_extension->op_array = op_array;
3058 	jit_extension->counter = &zend_jit_hot_counters[zend_jit_op_array_hash(op_array) & (ZEND_HOT_COUNTERS_COUNT - 1)];
3059 	for (i = 0; i < op_array->last; i++) {
3060 		jit_extension->orig_handlers[i] = op_array->opcodes[i].handler;
3061 	}
3062 	ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
3063 
3064 	zend_jit_setup_hot_counters_ex(op_array, &cfg);
3065 
3066 	zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
3067 
3068 	return SUCCESS;
3069 }
3070 
3071 #include "jit/zend_jit_trace.c"
3072 
zend_jit_op_array(zend_op_array * op_array,zend_script * script)3073 int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
3074 {
3075 	if (dasm_ptr == NULL) {
3076 		return FAILURE;
3077 	}
3078 
3079 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC) {
3080 		zend_jit_op_array_extension *jit_extension;
3081 		zend_op *opline = op_array->opcodes;
3082 
3083 		if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3084 			ZEND_SET_FUNC_INFO(op_array, NULL);
3085 			zend_error(E_WARNING, "Preloading is incompatible with first-exec and profile triggered JIT");
3086 			return SUCCESS;
3087 		}
3088 
3089 		/* Set run-time JIT handler */
3090 		ZEND_ASSERT(zend_jit_runtime_jit_handler != NULL);
3091 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3092 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3093 				opline++;
3094 			}
3095 		}
3096 		jit_extension = (zend_jit_op_array_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_extension));
3097 		if (!jit_extension) {
3098 			return FAILURE;
3099 		}
3100 		memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
3101 		jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_FIRST_EXEC;
3102 		jit_extension->op_array = op_array;
3103 		jit_extension->orig_handler = (void*)opline->handler;
3104 		ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
3105 		opline->handler = (const void*)zend_jit_runtime_jit_handler;
3106 		zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
3107 
3108 		return SUCCESS;
3109 	} else if (JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST) {
3110 		zend_jit_op_array_extension *jit_extension;
3111 		zend_op *opline = op_array->opcodes;
3112 
3113 		if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3114 			ZEND_SET_FUNC_INFO(op_array, NULL);
3115 			zend_error(E_WARNING, "Preloading is incompatible with first-exec and profile triggered JIT");
3116 			return SUCCESS;
3117 		}
3118 
3119 		ZEND_ASSERT(zend_jit_profile_jit_handler != NULL);
3120 		if (op_array->function_name) {
3121 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3122 				while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3123 					opline++;
3124 				}
3125 			}
3126 			jit_extension = (zend_jit_op_array_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_extension));
3127 			if (!jit_extension) {
3128 				return FAILURE;
3129 			}
3130 			memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
3131 			jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_PROF_REQUEST;
3132 			jit_extension->op_array = op_array;
3133 			jit_extension->orig_handler = (void*)opline->handler;
3134 			ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
3135 			opline->handler = (const void*)zend_jit_profile_jit_handler;
3136 			zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
3137 		}
3138 
3139 		return SUCCESS;
3140 	} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
3141 		return zend_jit_setup_hot_counters(op_array);
3142 	} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3143 		return zend_jit_setup_hot_trace_counters(op_array);
3144 	} else if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
3145 		return zend_real_jit_func(op_array, script, NULL, ZEND_JIT_ON_SCRIPT_LOAD);
3146 	} else {
3147 		ZEND_UNREACHABLE();
3148 	}
3149 	return FAILURE;
3150 }
3151 
zend_jit_script(zend_script * script)3152 int zend_jit_script(zend_script *script)
3153 {
3154 	void *checkpoint;
3155 	zend_call_graph call_graph;
3156 	zend_func_info *info;
3157 	int i;
3158 
3159 	if (dasm_ptr == NULL || *dasm_ptr == dasm_end) {
3160 		return FAILURE;
3161 	}
3162 
3163 	checkpoint = zend_arena_checkpoint(CG(arena));
3164 
3165 	call_graph.op_arrays_count = 0;
3166 	zend_build_call_graph(&CG(arena), script, &call_graph);
3167 
3168 	zend_analyze_call_graph(&CG(arena), script, &call_graph);
3169 
3170 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
3171 	    JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
3172 	    JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS ||
3173 	    JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3174 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3175 			if (zend_jit_op_array(call_graph.op_arrays[i], script) != SUCCESS) {
3176 				goto jit_failure;
3177 			}
3178 		}
3179 	} else if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
3180 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3181 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3182 			if (info) {
3183 				if (zend_jit_op_array_analyze1(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
3184 					goto jit_failure;
3185 				}
3186 				info->ssa.cfg.flags |= info->flags;
3187 				info->flags = info->ssa.cfg.flags;
3188 			}
3189 		}
3190 
3191 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3192 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3193 			if (info) {
3194 				info->call_map = zend_build_call_map(&CG(arena), info, call_graph.op_arrays[i]);
3195 				if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
3196 					zend_init_func_return_info(call_graph.op_arrays[i], script, &info->return_info);
3197 				}
3198 			}
3199 		}
3200 
3201 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3202 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3203 			if (info) {
3204 				if (zend_jit_op_array_analyze2(call_graph.op_arrays[i], script, &info->ssa, ZCG(accel_directives).optimization_level) != SUCCESS) {
3205 					goto jit_failure;
3206 				}
3207 				info->flags = info->ssa.cfg.flags;
3208 			}
3209 		}
3210 
3211 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3212 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3213 			if (info) {
3214 				if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
3215 					zend_dump_op_array(call_graph.op_arrays[i], ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &info->ssa);
3216 				}
3217 				if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) {
3218 					goto jit_failure;
3219 				}
3220 			}
3221 		}
3222 
3223 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3224 			ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
3225 		}
3226 	} else {
3227 		ZEND_UNREACHABLE();
3228 	}
3229 
3230 	zend_arena_release(&CG(arena), checkpoint);
3231 
3232 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC
3233 	 || JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST
3234 	 || JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS
3235 	 || JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3236 		zend_class_entry *ce;
3237 		zend_op_array *op_array;
3238 
3239 		ZEND_HASH_MAP_FOREACH_PTR(&script->class_table, ce) {
3240 			ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
3241 				if (!ZEND_FUNC_INFO(op_array)) {
3242 					void *jit_extension = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
3243 
3244 					if (jit_extension) {
3245 						ZEND_SET_FUNC_INFO(op_array, jit_extension);
3246 					}
3247 				}
3248 			} ZEND_HASH_FOREACH_END();
3249 		} ZEND_HASH_FOREACH_END();
3250 	}
3251 
3252 	return SUCCESS;
3253 
3254 jit_failure:
3255 	if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
3256 		for (i = 0; i < call_graph.op_arrays_count; i++) {
3257 			ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
3258 		}
3259 	}
3260 	zend_arena_release(&CG(arena), checkpoint);
3261 	return FAILURE;
3262 }
3263 
zend_jit_unprotect(void)3264 void zend_jit_unprotect(void)
3265 {
3266 #ifdef HAVE_MPROTECT
3267 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
3268 		int opts = PROT_READ | PROT_WRITE;
3269 #ifdef ZTS
3270 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3271 		if (zend_write_protect) {
3272 			pthread_jit_write_protect_np(0);
3273 		}
3274 #endif
3275 		opts |= PROT_EXEC;
3276 #endif
3277 		if (mprotect(dasm_buf, dasm_size, opts) != 0) {
3278 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3279 		}
3280 	}
3281 #elif defined(_WIN32)
3282 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
3283 		DWORD old, new;
3284 #ifdef ZTS
3285 		new = PAGE_EXECUTE_READWRITE;
3286 #else
3287 		new = PAGE_READWRITE;
3288 #endif
3289 		if (!VirtualProtect(dasm_buf, dasm_size, new, &old)) {
3290 			DWORD err = GetLastError();
3291 			char *msg = php_win32_error_to_msg(err);
3292 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3293 			php_win32_error_msg_free(msg);
3294 		}
3295 	}
3296 #endif
3297 }
3298 
zend_jit_protect(void)3299 void zend_jit_protect(void)
3300 {
3301 #ifdef HAVE_MPROTECT
3302 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
3303 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3304 		if (zend_write_protect) {
3305 			pthread_jit_write_protect_np(1);
3306 		}
3307 #endif
3308 		if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3309 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3310 		}
3311 	}
3312 #elif defined(_WIN32)
3313 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
3314 		DWORD old;
3315 
3316 		if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
3317 			DWORD err = GetLastError();
3318 			char *msg = php_win32_error_to_msg(err);
3319 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3320 			php_win32_error_msg_free(msg);
3321 		}
3322 	}
3323 #endif
3324 }
3325 
zend_jit_init_handlers(void)3326 static void zend_jit_init_handlers(void)
3327 {
3328 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3329 		zend_jit_runtime_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_runtime_jit];
3330 		zend_jit_profile_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_profile_jit];
3331 		zend_jit_func_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_hot_counter];
3332 		zend_jit_loop_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_hot_counter];
3333 		zend_jit_func_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_trace_counter];
3334 		zend_jit_ret_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_ret_trace_counter];
3335 		zend_jit_loop_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_trace_counter];
3336 	} else {
3337 		zend_jit_runtime_jit_handler = (const void*)zend_runtime_jit;
3338 		zend_jit_profile_jit_handler = (const void*)zend_jit_profile_helper;
3339 		zend_jit_func_hot_counter_handler = (const void*)zend_jit_func_counter_helper;
3340 		zend_jit_loop_hot_counter_handler = (const void*)zend_jit_loop_counter_helper;
3341 		zend_jit_func_trace_counter_handler = (const void*)zend_jit_func_trace_helper;
3342 		zend_jit_ret_trace_counter_handler = (const void*)zend_jit_ret_trace_helper;
3343 		zend_jit_loop_trace_counter_handler = (const void*)zend_jit_loop_trace_helper;
3344 	}
3345 }
3346 
zend_jit_globals_ctor(zend_jit_globals * jit_globals)3347 static void zend_jit_globals_ctor(zend_jit_globals *jit_globals)
3348 {
3349 	memset(jit_globals, 0, sizeof(zend_jit_globals));
3350 	zend_jit_trace_init_caches();
3351 }
3352 
3353 #ifdef ZTS
zend_jit_globals_dtor(zend_jit_globals * jit_globals)3354 static void zend_jit_globals_dtor(zend_jit_globals *jit_globals)
3355 {
3356 	zend_jit_trace_free_caches(jit_globals);
3357 }
3358 #endif
3359 
zend_jit_parse_config_num(zend_long jit)3360 static int zend_jit_parse_config_num(zend_long jit)
3361 {
3362 	if (jit == 0) {
3363 		JIT_G(on) = 0;
3364 		return SUCCESS;
3365 	}
3366 
3367 	if (jit < 0) return FAILURE;
3368 
3369 	if (jit % 10 == 0 || jit % 10 > 5) return FAILURE;
3370 	JIT_G(opt_level) = jit % 10;
3371 
3372 	jit /= 10;
3373 	if (jit % 10 > 5 || jit % 10 == 4) return FAILURE;
3374 	JIT_G(trigger) = jit % 10;
3375 
3376 	jit /= 10;
3377 	if (jit % 10 > 2) return FAILURE;
3378 	JIT_G(opt_flags) = jit % 10;
3379 
3380 	jit /= 10;
3381 	if (jit % 10 > 1) return FAILURE;
3382 	JIT_G(opt_flags) |= ((jit % 10) ? ZEND_JIT_CPU_AVX : 0);
3383 
3384 	if (jit / 10 != 0) return FAILURE;
3385 
3386 	JIT_G(on) = 1;
3387 
3388 	return SUCCESS;
3389 }
3390 
zend_jit_config(zend_string * jit,int stage)3391 int zend_jit_config(zend_string *jit, int stage)
3392 {
3393 	if (stage != ZEND_INI_STAGE_STARTUP && !JIT_G(enabled)) {
3394 		if (stage == ZEND_INI_STAGE_RUNTIME) {
3395 			zend_error(E_WARNING, "Cannot change opcache.jit setting at run-time (JIT is disabled)");
3396 		}
3397 		return FAILURE;
3398 	}
3399 
3400 	if (zend_string_equals_literal_ci(jit, "disable")) {
3401 		JIT_G(enabled) = 0;
3402 		JIT_G(on) = 0;
3403 		return SUCCESS;
3404 	} else if (ZSTR_LEN(jit) == 0
3405 			|| zend_string_equals_literal_ci(jit, "0")
3406 			|| zend_string_equals_literal_ci(jit, "off")
3407 			|| zend_string_equals_literal_ci(jit, "no")
3408 			|| zend_string_equals_literal_ci(jit, "false")) {
3409 		JIT_G(enabled) = 1;
3410 		JIT_G(on) = 0;
3411 		return SUCCESS;
3412 	} else if (zend_string_equals_literal_ci(jit, "1")
3413 			|| zend_string_equals_literal_ci(jit, "on")
3414 			|| zend_string_equals_literal_ci(jit, "yes")
3415 			|| zend_string_equals_literal_ci(jit, "true")
3416 			|| zend_string_equals_literal_ci(jit, "tracing")) {
3417 		JIT_G(enabled) = 1;
3418 		JIT_G(on) = 1;
3419 		JIT_G(opt_level) = ZEND_JIT_LEVEL_OPT_FUNCS;
3420 		JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
3421 		JIT_G(opt_flags) = ZEND_JIT_REG_ALLOC_GLOBAL | ZEND_JIT_CPU_AVX;
3422 		return SUCCESS;
3423 	} else if (zend_string_equals_ci(jit, ZSTR_KNOWN(ZEND_STR_FUNCTION))) {
3424 		JIT_G(enabled) = 1;
3425 		JIT_G(on) = 1;
3426 		JIT_G(opt_level) = ZEND_JIT_LEVEL_OPT_SCRIPT;
3427 		JIT_G(trigger) = ZEND_JIT_ON_SCRIPT_LOAD;
3428 		JIT_G(opt_flags) = ZEND_JIT_REG_ALLOC_GLOBAL | ZEND_JIT_CPU_AVX;
3429 		return SUCCESS;
3430 	} else  {
3431 		char *end;
3432 		zend_long num = ZEND_STRTOL(ZSTR_VAL(jit), &end, 10);
3433 		if (end != ZSTR_VAL(jit) + ZSTR_LEN(jit) || zend_jit_parse_config_num(num) != SUCCESS) {
3434 			goto failure;
3435 		}
3436 		JIT_G(enabled) = 1;
3437 		return SUCCESS;
3438 	}
3439 
3440 failure:
3441 	zend_error(E_WARNING, "Invalid \"opcache.jit\" setting. Should be \"disable\", \"on\", \"off\", \"tracing\", \"function\" or 4-digit number");
3442 	JIT_G(enabled) = 0;
3443 	JIT_G(on) = 0;
3444 	return FAILURE;
3445 }
3446 
zend_jit_debug_config(zend_long old_val,zend_long new_val,int stage)3447 int zend_jit_debug_config(zend_long old_val, zend_long new_val, int stage)
3448 {
3449 	if (stage != ZEND_INI_STAGE_STARTUP) {
3450 		if (((old_val ^ new_val) & ZEND_JIT_DEBUG_PERSISTENT) != 0) {
3451 			if (stage == ZEND_INI_STAGE_RUNTIME) {
3452 				zend_error(E_WARNING, "Some opcache.jit_debug bits cannot be changed after startup");
3453 			}
3454 			return FAILURE;
3455 		}
3456 	}
3457 	return SUCCESS;
3458 }
3459 
zend_jit_init(void)3460 void zend_jit_init(void)
3461 {
3462 #ifdef ZTS
3463 	jit_globals_id = ts_allocate_id(&jit_globals_id, sizeof(zend_jit_globals), (ts_allocate_ctor) zend_jit_globals_ctor, (ts_allocate_dtor) zend_jit_globals_dtor);
3464 #else
3465 	zend_jit_globals_ctor(&jit_globals);
3466 #endif
3467 }
3468 
zend_jit_check_support(void)3469 int zend_jit_check_support(void)
3470 {
3471 	int i;
3472 
3473 	zend_jit_vm_kind = zend_vm_kind();
3474 	if (zend_jit_vm_kind != ZEND_VM_KIND_CALL &&
3475 	    zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
3476 		zend_error(E_WARNING, "JIT is compatible only with CALL and HYBRID VM. JIT disabled.");
3477 		JIT_G(enabled) = 0;
3478 		JIT_G(on) = 0;
3479 		return FAILURE;
3480 	}
3481 
3482 	if (zend_execute_ex != execute_ex) {
3483 		if (zend_dtrace_enabled) {
3484 			zend_error(E_WARNING, "JIT is incompatible with DTrace. JIT disabled.");
3485 		} else if (strcmp(sapi_module.name, "phpdbg") != 0) {
3486 			zend_error(E_WARNING, "JIT is incompatible with third party extensions that override zend_execute_ex(). JIT disabled.");
3487 		}
3488 		JIT_G(enabled) = 0;
3489 		JIT_G(on) = 0;
3490 		return FAILURE;
3491 	}
3492 
3493 	for (i = 0; i <= 256; i++) {
3494 		switch (i) {
3495 			/* JIT has no effect on these opcodes */
3496 			case ZEND_BEGIN_SILENCE:
3497 			case ZEND_END_SILENCE:
3498 				break;
3499 			default:
3500 				if (zend_get_user_opcode_handler(i) != NULL) {
3501 					zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
3502 					JIT_G(enabled) = 0;
3503 					JIT_G(on) = 0;
3504 					return FAILURE;
3505 				}
3506 		}
3507 	}
3508 
3509 #if defined(IR_TARGET_AARCH64)
3510 	if (JIT_G(buffer_size) > 128*1024*1024) {
3511 		zend_error(E_WARNING, "JIT on AArch64 doesn't support opcache.jit_buffer_size above 128M.");
3512 		JIT_G(enabled) = 0;
3513 		JIT_G(on) = 0;
3514 		return FAILURE;
3515 	}
3516 #elif defined(IR_TARGET_X64)
3517 	if (JIT_G(buffer_size) > 2 * Z_L(1024*1024*1024)) {
3518 		zend_error(E_WARNING, "JIT on x86_64 doesn't support opcache.jit_buffer_size above 2G.");
3519 		JIT_G(enabled) = 0;
3520 		JIT_G(on) = 0;
3521 		return FAILURE;
3522 	}
3523 #endif
3524 
3525 	return SUCCESS;
3526 }
3527 
zend_jit_startup(void * buf,size_t size,bool reattached)3528 void zend_jit_startup(void *buf, size_t size, bool reattached)
3529 {
3530 	zend_jit_halt_op = zend_get_halt_op();
3531 	zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME);
3532 
3533 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3534 	zend_write_protect = pthread_jit_write_protect_supported_np();
3535 #endif
3536 
3537 	dasm_buf = buf;
3538 	dasm_size = size;
3539 	dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr) * 2);
3540 
3541 #ifdef HAVE_MPROTECT
3542 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3543 	if (zend_write_protect) {
3544 		pthread_jit_write_protect_np(1);
3545 	}
3546 #endif
3547 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
3548 		if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
3549 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3550 		}
3551 	} else {
3552 		if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3553 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3554 		}
3555 	}
3556 #elif defined(_WIN32)
3557 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
3558 		DWORD old;
3559 
3560 		if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READWRITE, &old)) {
3561 			DWORD err = GetLastError();
3562 			char *msg = php_win32_error_to_msg(err);
3563 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3564 			php_win32_error_msg_free(msg);
3565 		}
3566 	} else {
3567 		DWORD old;
3568 
3569 		if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
3570 			DWORD err = GetLastError();
3571 			char *msg = php_win32_error_to_msg(err);
3572 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3573 			php_win32_error_msg_free(msg);
3574 		}
3575 	}
3576 #endif
3577 
3578 	if (!reattached) {
3579 		zend_jit_unprotect();
3580 		*dasm_ptr = dasm_buf;
3581 #if defined(_WIN32)
3582 		zend_jit_stub_handlers = dasm_buf;
3583 		*dasm_ptr = (void**)*dasm_ptr + sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
3584 #elif defined(IR_TARGET_AARCH64)
3585 		zend_jit_stub_handlers = dasm_buf;
3586 		*dasm_ptr = (void**)*dasm_ptr + (sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])) * 2;
3587 		memset(zend_jit_stub_handlers, 0, (sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])) * 2 * sizeof(void*));
3588 #endif
3589 		*dasm_ptr = (void*)ZEND_MM_ALIGNED_SIZE_EX(((size_t)(*dasm_ptr)), 16);
3590 		zend_jit_protect();
3591 	} else {
3592 #if defined(_WIN32) || defined(IR_TARGET_AARCH64)
3593 		zend_jit_stub_handlers = dasm_buf;
3594 		zend_jit_init_handlers();
3595 #endif
3596 	}
3597 
3598 	zend_jit_unprotect();
3599 	zend_jit_setup();
3600 	zend_jit_protect();
3601 	zend_jit_init_handlers();
3602 
3603 	zend_jit_trace_startup(reattached);
3604 
3605 	zend_jit_unprotect();
3606 	/* save JIT buffer pos */
3607 	dasm_ptr[1] = dasm_ptr[0];
3608 	zend_jit_protect();
3609 }
3610 
zend_jit_shutdown(void)3611 void zend_jit_shutdown(void)
3612 {
3613 	if (JIT_G(debug) & ZEND_JIT_DEBUG_SIZE && dasm_ptr != NULL) {
3614 		fprintf(stderr, "\nJIT memory usage: %td\n", (ptrdiff_t)((char*)*dasm_ptr - (char*)dasm_buf));
3615 	}
3616 
3617 	zend_jit_shutdown_ir();
3618 
3619 #ifdef ZTS
3620 	ts_free_id(jit_globals_id);
3621 #else
3622 	zend_jit_trace_free_caches(&jit_globals);
3623 #endif
3624 }
3625 
zend_jit_reset_counters(void)3626 static void zend_jit_reset_counters(void)
3627 {
3628 	int i;
3629 
3630 	for (i = 0; i < ZEND_HOT_COUNTERS_COUNT; i++) {
3631 		zend_jit_hot_counters[i] = ZEND_JIT_COUNTER_INIT;
3632 	}
3633 }
3634 
zend_jit_activate(void)3635 void zend_jit_activate(void)
3636 {
3637 	zend_jit_profile_counter = 0;
3638 	if (JIT_G(on)) {
3639 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
3640 			zend_jit_reset_counters();
3641 		} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3642 			zend_jit_reset_counters();
3643 			zend_jit_trace_reset_caches();
3644 		}
3645 	}
3646 }
3647 
zend_jit_deactivate(void)3648 void zend_jit_deactivate(void)
3649 {
3650 	if (zend_jit_profile_counter && !CG(unclean_shutdown)) {
3651 		zend_class_entry *ce;
3652 
3653 		zend_shared_alloc_lock();
3654 		SHM_UNPROTECT();
3655 		zend_jit_unprotect();
3656 
3657 		zend_jit_check_funcs(EG(function_table), 0);
3658 		ZEND_HASH_MAP_REVERSE_FOREACH_PTR(EG(class_table), ce) {
3659 			if (ce->type == ZEND_INTERNAL_CLASS) {
3660 				break;
3661 			}
3662 			zend_jit_check_funcs(&ce->function_table, 1);
3663 		} ZEND_HASH_FOREACH_END();
3664 
3665 		zend_jit_protect();
3666 		SHM_PROTECT();
3667 		zend_shared_alloc_unlock();
3668 	}
3669 
3670 	zend_jit_profile_counter = 0;
3671 }
3672 
zend_jit_restart_preloaded_op_array(zend_op_array * op_array)3673 static void zend_jit_restart_preloaded_op_array(zend_op_array *op_array)
3674 {
3675 	zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
3676 
3677 	if (!func_info) {
3678 		return;
3679 	}
3680 
3681 	if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_TRACE) {
3682 		zend_jit_restart_hot_trace_counters(op_array);
3683 	} else if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_COUNTERS) {
3684 		zend_jit_restart_hot_counters(op_array);
3685 #if 0
3686 	// TODO: We have to restore handlers for some inner basic-blocks, but we didn't store them ???
3687 	} else if (func_info->flags & (ZEND_FUNC_JIT_ON_FIRST_EXEC|ZEND_FUNC_JIT_ON_PROF_REQUEST)) {
3688 		zend_op *opline = op_array->opcodes;
3689 		zend_jit_op_array_extension *jit_extension =
3690 			(zend_jit_op_array_extension*)func_info;
3691 
3692 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3693 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3694 				opline++;
3695 			}
3696 		}
3697 		if (func_info->flags & ZEND_FUNC_JIT_ON_FIRST_EXEC) {
3698 			opline->handler = (const void*)zend_jit_runtime_jit_handler;
3699 		} else {
3700 			opline->handler = (const void*)zend_jit_profile_jit_handler;
3701 		}
3702 #endif
3703 	}
3704 	if (op_array->num_dynamic_func_defs) {
3705 		for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
3706 			zend_jit_restart_preloaded_op_array(op_array->dynamic_func_defs[i]);
3707 		}
3708 	}
3709 }
3710 
zend_jit_restart_preloaded_script(zend_persistent_script * script)3711 static void zend_jit_restart_preloaded_script(zend_persistent_script *script)
3712 {
3713 	zend_class_entry *ce;
3714 	zend_op_array *op_array;
3715 
3716 	zend_jit_restart_preloaded_op_array(&script->script.main_op_array);
3717 
3718 	ZEND_HASH_MAP_FOREACH_PTR(&script->script.function_table, op_array) {
3719 		zend_jit_restart_preloaded_op_array(op_array);
3720 	} ZEND_HASH_FOREACH_END();
3721 
3722 	ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) {
3723 		ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
3724 			if (op_array->type == ZEND_USER_FUNCTION) {
3725 				zend_jit_restart_preloaded_op_array(op_array);
3726 			}
3727 		} ZEND_HASH_FOREACH_END();
3728 	} ZEND_HASH_FOREACH_END();
3729 }
3730 
zend_jit_restart(void)3731 void zend_jit_restart(void)
3732 {
3733 	if (dasm_buf) {
3734 		zend_jit_unprotect();
3735 
3736 		/* restore JIT buffer pos */
3737 		dasm_ptr[0] = dasm_ptr[1];
3738 
3739 		zend_jit_trace_restart();
3740 
3741 		if (ZCSG(preload_script)) {
3742 			zend_jit_restart_preloaded_script(ZCSG(preload_script));
3743 			if (ZCSG(saved_scripts)) {
3744 				zend_persistent_script **p = ZCSG(saved_scripts);
3745 
3746 				while (*p) {
3747 					zend_jit_restart_preloaded_script(*p);
3748 					p++;
3749 				}
3750 			}
3751 		}
3752 
3753 		zend_jit_protect();
3754 	}
3755 }
3756 
3757 #endif /* HAVE_JIT */
3758