xref: /PHP-8.2/ext/opcache/jit/zend_jit.c (revision 5cf045d3)
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 
42 #if ZEND_JIT_TARGET_X86
43 # include "jit/zend_jit_x86.h"
44 #elif ZEND_JIT_TARGET_ARM64
45 # include "jit/zend_jit_arm64.h"
46 #endif
47 
48 #include "jit/zend_jit_internal.h"
49 
50 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
51 #include <pthread.h>
52 #endif
53 
54 #ifdef ZTS
55 int jit_globals_id;
56 #else
57 zend_jit_globals jit_globals;
58 #endif
59 
60 //#define CONTEXT_THREADED_JIT
61 #define ZEND_JIT_USE_RC_INFERENCE
62 
63 #ifdef ZEND_JIT_USE_RC_INFERENCE
64 # define ZEND_SSA_RC_INFERENCE_FLAG ZEND_SSA_RC_INFERENCE
65 # define RC_MAY_BE_1(info)          (((info) & (MAY_BE_RC1|MAY_BE_REF)) != 0)
66 # define RC_MAY_BE_N(info)          (((info) & (MAY_BE_RCN|MAY_BE_REF)) != 0)
67 #else
68 # define ZEND_SSA_RC_INFERENCE_FLAG 0
69 # define RC_MAY_BE_1(info)          1
70 # define RC_MAY_BE_N(info)          1
71 #endif
72 
73 #define JIT_PREFIX      "JIT$"
74 #define JIT_STUB_PREFIX "JIT$$"
75 #define TRACE_PREFIX    "TRACE-"
76 
77 #define DASM_M_GROW(ctx, t, p, sz, need) \
78   do { \
79     size_t _sz = (sz), _need = (need); \
80     if (_sz < _need) { \
81       if (_sz < 16) _sz = 16; \
82       while (_sz < _need) _sz += _sz; \
83       (p) = (t *)erealloc((p), _sz); \
84       (sz) = _sz; \
85     } \
86   } while(0)
87 
88 #define DASM_M_FREE(ctx, p, sz) efree(p)
89 
90 #if ZEND_DEBUG
91 # define DASM_CHECKS 1
92 #endif
93 
94 #include "dynasm/dasm_proto.h"
95 
96 typedef struct _zend_jit_stub {
97 	const char *name;
98 	int (*stub)(dasm_State **Dst);
99 	uint32_t offset;
100 	uint32_t adjustment;
101 } zend_jit_stub;
102 
103 #define JIT_STUB(name, offset, adjustment) \
104 	{JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, offset, adjustment}
105 
106 zend_ulong zend_jit_profile_counter = 0;
107 int zend_jit_profile_counter_rid = -1;
108 
109 int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT];
110 
111 const zend_op *zend_jit_halt_op = NULL;
112 static int zend_jit_vm_kind = 0;
113 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
114 static int zend_write_protect = 1;
115 #endif
116 
117 static void *dasm_buf = NULL;
118 static void *dasm_end = NULL;
119 static void **dasm_ptr = NULL;
120 
121 static size_t dasm_size = 0;
122 
123 static zend_long jit_bisect_pos = 0;
124 
125 static const void *zend_jit_runtime_jit_handler = NULL;
126 static const void *zend_jit_profile_jit_handler = NULL;
127 static const void *zend_jit_func_hot_counter_handler = NULL;
128 static const void *zend_jit_loop_hot_counter_handler = NULL;
129 static const void *zend_jit_func_trace_counter_handler = NULL;
130 static const void *zend_jit_ret_trace_counter_handler = NULL;
131 static const void *zend_jit_loop_trace_counter_handler = NULL;
132 
133 static int ZEND_FASTCALL zend_runtime_jit(void);
134 
135 static int zend_jit_trace_op_len(const zend_op *opline);
136 static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline);
137 static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags);
138 static const void *zend_jit_trace_get_exit_addr(uint32_t n);
139 static void zend_jit_trace_add_code(const void *start, uint32_t size);
140 static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info);
141 
142 #if ZEND_JIT_TARGET_ARM64
143 static zend_jit_trace_info *zend_jit_get_current_trace_info(void);
144 static uint32_t zend_jit_trace_find_exit_point(const void* addr);
145 #endif
146 
147 static int zend_jit_assign_to_variable(dasm_State    **Dst,
148                                        const zend_op  *opline,
149                                        zend_jit_addr   var_use_addr,
150                                        zend_jit_addr   var_addr,
151                                        uint32_t        var_info,
152                                        uint32_t        var_def_info,
153                                        zend_uchar      val_type,
154                                        zend_jit_addr   val_addr,
155                                        uint32_t        val_info,
156                                        zend_jit_addr   res_addr,
157                                        bool       check_exception);
158 
dominates(const zend_basic_block * blocks,int a,int b)159 static bool dominates(const zend_basic_block *blocks, int a, int b) {
160 	while (blocks[b].level > blocks[a].level) {
161 		b = blocks[b].idom;
162 	}
163 	return a == b;
164 }
165 
zend_ssa_is_last_use(const zend_op_array * op_array,const zend_ssa * ssa,int var,int use)166 static bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_ssa *ssa, int var, int use)
167 {
168 	int next_use;
169 
170 	if (ssa->vars[var].phi_use_chain) {
171 		zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
172 		do {
173 			if (!ssa->vars[phi->ssa_var].no_val) {
174 				return 0;
175 			}
176 			phi = zend_ssa_next_use_phi(ssa, var, phi);
177 		} while (phi);
178 	}
179 
180 	if (ssa->cfg.blocks[ssa->cfg.map[use]].loop_header > 0
181 	 || (ssa->cfg.blocks[ssa->cfg.map[use]].flags & ZEND_BB_LOOP_HEADER)) {
182 		int b = ssa->cfg.map[use];
183 		int prev_use = ssa->vars[var].use_chain;
184 
185 		while (prev_use >= 0 && prev_use != use) {
186 			if (b != ssa->cfg.map[prev_use]
187 			 && dominates(ssa->cfg.blocks, b, ssa->cfg.map[prev_use])
188 			 && !zend_ssa_is_no_val_use(op_array->opcodes + prev_use, ssa->ops + prev_use, var)) {
189 				return 0;
190 			}
191 			prev_use = zend_ssa_next_use(ssa->ops, var, prev_use);
192 		}
193 	}
194 
195 	next_use = zend_ssa_next_use(ssa->ops, var, use);
196 	if (next_use < 0) {
197 		return 1;
198 	} else if (zend_ssa_is_no_val_use(op_array->opcodes + next_use, ssa->ops + next_use, var)) {
199 		return 1;
200 	}
201 	return 0;
202 }
203 
zend_ival_is_last_use(const zend_lifetime_interval * ival,int use)204 static bool zend_ival_is_last_use(const zend_lifetime_interval *ival, int use)
205 {
206 	if (ival->flags & ZREG_LAST_USE) {
207 		const zend_life_range *range = &ival->range;
208 
209 		while (range->next) {
210 			range = range->next;
211 		}
212 		return range->end == use;
213 	}
214 	return 0;
215 }
216 
zend_is_commutative(zend_uchar opcode)217 static bool zend_is_commutative(zend_uchar opcode)
218 {
219 	return
220 		opcode == ZEND_ADD ||
221 		opcode == ZEND_MUL ||
222 		opcode == ZEND_BW_OR ||
223 		opcode == ZEND_BW_AND ||
224 		opcode == ZEND_BW_XOR;
225 }
226 
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)227 static int zend_jit_is_constant_cmp_long_long(const zend_op  *opline,
228                                               zend_ssa_range *op1_range,
229                                               zend_jit_addr   op1_addr,
230                                               zend_ssa_range *op2_range,
231                                               zend_jit_addr   op2_addr,
232                                               bool           *result)
233 {
234 	zend_long op1_min;
235 	zend_long op1_max;
236 	zend_long op2_min;
237 	zend_long op2_max;
238 
239 	if (op1_range) {
240 		op1_min = op1_range->min;
241 		op1_max = op1_range->max;
242 	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
243 		ZEND_ASSERT(Z_TYPE_P(Z_ZV(op1_addr)) == IS_LONG);
244 		op1_min = op1_max = Z_LVAL_P(Z_ZV(op1_addr));
245 	} else {
246 		return 0;
247 	}
248 
249 	if (op2_range) {
250 		op2_min = op2_range->min;
251 		op2_max = op2_range->max;
252 	} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
253 		ZEND_ASSERT(Z_TYPE_P(Z_ZV(op2_addr)) == IS_LONG);
254 		op2_min = op2_max = Z_LVAL_P(Z_ZV(op2_addr));
255 	} else {
256 		return 0;
257 	}
258 
259 	switch (opline->opcode) {
260 		case ZEND_IS_EQUAL:
261 		case ZEND_IS_IDENTICAL:
262 		case ZEND_CASE:
263 		case ZEND_CASE_STRICT:
264 			if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
265 				*result = 1;
266 				return 1;
267 			} else if (op1_max < op2_min || op1_min > op2_max) {
268 				*result = 0;
269 				return 1;
270 			}
271 			return 0;
272 		case ZEND_IS_NOT_EQUAL:
273 		case ZEND_IS_NOT_IDENTICAL:
274 			if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
275 				*result = 0;
276 				return 1;
277 			} else if (op1_max < op2_min || op1_min > op2_max) {
278 				*result = 1;
279 				return 1;
280 			}
281 			return 0;
282 		case ZEND_IS_SMALLER:
283 			if (op1_max < op2_min) {
284 				*result = 1;
285 				return 1;
286 			} else if (op1_min >= op2_max) {
287 				*result = 0;
288 				return 1;
289 			}
290 			return 0;
291 		case ZEND_IS_SMALLER_OR_EQUAL:
292 			if (op1_max <= op2_min) {
293 				*result = 1;
294 				return 1;
295 			} else if (op1_min > op2_max) {
296 				*result = 0;
297 				return 1;
298 			}
299 			return 0;
300 		default:
301 			ZEND_UNREACHABLE();
302 	}
303 	return 0;
304 }
305 
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)306 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)
307 {
308 	int skip;
309 
310 	if (trace) {
311 		zend_jit_trace_rec *p = trace;
312 
313 		ssa_op++;
314 		while (1) {
315 			if (p->op == ZEND_JIT_TRACE_VM) {
316 				switch (p->opline->opcode) {
317 					case ZEND_SEND_ARRAY:
318 					case ZEND_SEND_USER:
319 					case ZEND_SEND_UNPACK:
320 					case ZEND_INIT_FCALL:
321 					case ZEND_INIT_METHOD_CALL:
322 					case ZEND_INIT_STATIC_METHOD_CALL:
323 					case ZEND_INIT_FCALL_BY_NAME:
324 					case ZEND_INIT_NS_FCALL_BY_NAME:
325 					case ZEND_INIT_DYNAMIC_CALL:
326 					case ZEND_NEW:
327 					case ZEND_INIT_USER_CALL:
328 					case ZEND_FAST_CALL:
329 					case ZEND_JMP:
330 					case ZEND_JMPZ:
331 					case ZEND_JMPNZ:
332 					case ZEND_JMPZ_EX:
333 					case ZEND_JMPNZ_EX:
334 					case ZEND_FE_RESET_R:
335 					case ZEND_FE_RESET_RW:
336 					case ZEND_JMP_SET:
337 					case ZEND_COALESCE:
338 					case ZEND_JMP_NULL:
339 					case ZEND_ASSERT_CHECK:
340 					case ZEND_CATCH:
341 					case ZEND_DECLARE_ANON_CLASS:
342 					case ZEND_FE_FETCH_R:
343 					case ZEND_FE_FETCH_RW:
344 						return 1;
345 					case ZEND_DO_ICALL:
346 					case ZEND_DO_UCALL:
347 					case ZEND_DO_FCALL_BY_NAME:
348 					case ZEND_DO_FCALL:
349 					case ZEND_CALLABLE_CONVERT:
350 						return 0;
351 					case ZEND_SEND_VAL:
352 					case ZEND_SEND_VAR:
353 					case ZEND_SEND_VAL_EX:
354 					case ZEND_SEND_VAR_EX:
355 					case ZEND_SEND_FUNC_ARG:
356 					case ZEND_SEND_REF:
357 					case ZEND_SEND_VAR_NO_REF:
358 					case ZEND_SEND_VAR_NO_REF_EX:
359 						/* skip */
360 						break;
361 					default:
362 						if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
363 							return 1;
364 						}
365 				}
366 				ssa_op += zend_jit_trace_op_len(opline);
367 			} else if (p->op == ZEND_JIT_TRACE_ENTER ||
368 			           p->op == ZEND_JIT_TRACE_BACK ||
369 			           p->op == ZEND_JIT_TRACE_END) {
370 				return 1;
371 			}
372 			p++;
373 		}
374 	}
375 
376 	if (!call_info) {
377 		const zend_op *end = op_array->opcodes + op_array->last;
378 
379 		opline++;
380 		ssa_op++;
381 		skip = (call_level == 1);
382 		while (opline != end) {
383 			if (!skip) {
384 				if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
385 					return 1;
386 				}
387 			}
388 			switch (opline->opcode) {
389 				case ZEND_SEND_VAL:
390 				case ZEND_SEND_VAR:
391 				case ZEND_SEND_VAL_EX:
392 				case ZEND_SEND_VAR_EX:
393 				case ZEND_SEND_FUNC_ARG:
394 				case ZEND_SEND_REF:
395 				case ZEND_SEND_VAR_NO_REF:
396 				case ZEND_SEND_VAR_NO_REF_EX:
397 					skip = 0;
398 					break;
399 				case ZEND_SEND_ARRAY:
400 				case ZEND_SEND_USER:
401 				case ZEND_SEND_UNPACK:
402 				case ZEND_INIT_FCALL:
403 				case ZEND_INIT_METHOD_CALL:
404 				case ZEND_INIT_STATIC_METHOD_CALL:
405 				case ZEND_INIT_FCALL_BY_NAME:
406 				case ZEND_INIT_NS_FCALL_BY_NAME:
407 				case ZEND_INIT_DYNAMIC_CALL:
408 				case ZEND_NEW:
409 				case ZEND_INIT_USER_CALL:
410 				case ZEND_FAST_CALL:
411 				case ZEND_JMP:
412 				case ZEND_JMPZ:
413 				case ZEND_JMPNZ:
414 				case ZEND_JMPZ_EX:
415 				case ZEND_JMPNZ_EX:
416 				case ZEND_FE_RESET_R:
417 				case ZEND_FE_RESET_RW:
418 				case ZEND_JMP_SET:
419 				case ZEND_COALESCE:
420 				case ZEND_JMP_NULL:
421 				case ZEND_ASSERT_CHECK:
422 				case ZEND_CATCH:
423 				case ZEND_DECLARE_ANON_CLASS:
424 				case ZEND_FE_FETCH_R:
425 				case ZEND_FE_FETCH_RW:
426 					return 1;
427 				case ZEND_DO_ICALL:
428 				case ZEND_DO_UCALL:
429 				case ZEND_DO_FCALL_BY_NAME:
430 				case ZEND_DO_FCALL:
431 				case ZEND_CALLABLE_CONVERT:
432 					end = opline;
433 					if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
434 						/* INIT_FCALL and DO_FCALL in different BasicBlocks */
435 						return 1;
436 					}
437 					return 0;
438 			}
439 			opline++;
440 			ssa_op++;
441 		}
442 
443 		return 1;
444 	} else {
445 		const zend_op *end = call_info->caller_call_opline;
446 
447 		/* end may be null if an opcode like EXIT is part of the argument list. */
448 		if (!end || end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
449 			/* INIT_FCALL and DO_FCALL in different BasicBlocks */
450 			return 1;
451 		}
452 
453 		opline++;
454 		ssa_op++;
455 		skip = (call_level == 1);
456 		while (opline != end) {
457 			if (skip) {
458 				switch (opline->opcode) {
459 					case ZEND_SEND_VAL:
460 					case ZEND_SEND_VAR:
461 					case ZEND_SEND_VAL_EX:
462 					case ZEND_SEND_VAR_EX:
463 					case ZEND_SEND_FUNC_ARG:
464 					case ZEND_SEND_REF:
465 					case ZEND_SEND_VAR_NO_REF:
466 					case ZEND_SEND_VAR_NO_REF_EX:
467 						skip = 0;
468 						break;
469 					case ZEND_SEND_ARRAY:
470 					case ZEND_SEND_USER:
471 					case ZEND_SEND_UNPACK:
472 						return 1;
473 				}
474 			} else {
475 				if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
476 					return 1;
477 				}
478 			}
479 			opline++;
480 			ssa_op++;
481 		}
482 
483 		return 0;
484 	}
485 }
486 
skip_valid_arguments(const zend_op_array * op_array,zend_ssa * ssa,const zend_call_info * call_info)487 static uint32_t skip_valid_arguments(const zend_op_array *op_array, zend_ssa *ssa, const zend_call_info *call_info)
488 {
489 	uint32_t num_args = 0;
490 	zend_function *func = call_info->callee_func;
491 
492 	/* It's okay to handle prototypes here, because they can only increase the accepted arguments.
493 	 * Anything legal for the parent method is also legal for the parent method. */
494 	while (num_args < call_info->num_args) {
495 		zend_arg_info *arg_info = func->op_array.arg_info + num_args;
496 
497 		if (ZEND_TYPE_IS_SET(arg_info->type)) {
498 			if (ZEND_TYPE_IS_ONLY_MASK(arg_info->type)) {
499 				zend_op *opline = call_info->arg_info[num_args].opline;
500 				zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
501 				uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
502 				if ((OP1_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) & ~type_mask) {
503 					break;
504 				}
505 			} else {
506 				break;
507 			}
508 		}
509 		num_args++;
510 	}
511 	return num_args;
512 }
513 
zend_ssa_cv_info(const zend_op_array * op_array,zend_ssa * ssa,uint32_t var)514 static uint32_t zend_ssa_cv_info(const zend_op_array *op_array, zend_ssa *ssa, uint32_t var)
515 {
516 	uint32_t j, info;
517 
518 	if (ssa->vars && ssa->var_info) {
519 		info = ssa->var_info[var].type;
520 		for (j = op_array->last_var; j < ssa->vars_count; j++) {
521 			if (ssa->vars[j].var == var) {
522 				info |= ssa->var_info[j].type;
523 			}
524 		}
525 	} else {
526 		info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_UNDEF |
527 			MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
528 	}
529 
530 #ifdef ZEND_JIT_USE_RC_INFERENCE
531 	/* Refcount may be increased by RETURN opcode */
532 	if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
533 		for (j = 0; j < ssa->cfg.blocks_count; j++) {
534 			if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
535 			    ssa->cfg.blocks[j].len > 0) {
536 				const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;
537 
538 				if (opline->opcode == ZEND_RETURN) {
539 					if (opline->op1_type == IS_CV && opline->op1.var == EX_NUM_TO_VAR(var)) {
540 						info |= MAY_BE_RCN;
541 						break;
542 					}
543 				}
544 			}
545 		}
546 	}
547 #endif
548 
549 	return info;
550 }
551 
zend_jit_may_avoid_refcounting(const zend_op * opline,uint32_t op1_info)552 static bool zend_jit_may_avoid_refcounting(const zend_op *opline, uint32_t op1_info)
553 {
554 	switch (opline->opcode) {
555 		case ZEND_FETCH_OBJ_FUNC_ARG:
556 			if (!JIT_G(current_frame) ||
557 			    !JIT_G(current_frame)->call->func ||
558 			    !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
559 				return 0;
560 			}
561 			/* break missing intentionally */
562 		case ZEND_FETCH_OBJ_R:
563 		case ZEND_FETCH_OBJ_IS:
564 			if ((op1_info & MAY_BE_OBJECT)
565 			 && opline->op2_type == IS_CONST
566 			 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING
567 			 && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') {
568 				return 1;
569 			}
570 			break;
571 		case ZEND_FETCH_DIM_FUNC_ARG:
572 			if (!JIT_G(current_frame) ||
573 			    !JIT_G(current_frame)->call->func ||
574 			    !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
575 				return 0;
576 			}
577 			/* break missing intentionally */
578 		case ZEND_FETCH_DIM_R:
579 		case ZEND_FETCH_DIM_IS:
580 			return 1;
581 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
582 			if (!(opline->extended_value & ZEND_ISEMPTY)) {
583 				return 1;
584 			}
585 			break;
586 	}
587 	return 0;
588 }
589 
zend_jit_is_persistent_constant(zval * key,uint32_t flags)590 static bool zend_jit_is_persistent_constant(zval *key, uint32_t flags)
591 {
592 	zval *zv;
593 	zend_constant *c = NULL;
594 
595 	/* null/true/false are resolved during compilation, so don't check for them here. */
596 	zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
597 	if (zv) {
598 		c = (zend_constant*)Z_PTR_P(zv);
599 	} else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
600 		key++;
601 		zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
602 		if (zv) {
603 			c = (zend_constant*)Z_PTR_P(zv);
604 		}
605 	}
606 	return c && (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT);
607 }
608 
zend_get_known_property_info(const zend_op_array * op_array,zend_class_entry * ce,zend_string * member,bool on_this,zend_string * filename)609 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)
610 {
611 	zend_property_info *info = NULL;
612 
613 	if ((on_this && (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) ||
614 	    !ce ||
615 	    !(ce->ce_flags & ZEND_ACC_LINKED) ||
616 	    (ce->ce_flags & ZEND_ACC_TRAIT) ||
617 	    ce->create_object) {
618 		return NULL;
619 	}
620 
621 	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
622 		if (ce->info.user.filename != filename) {
623 			/* class declaration might be changed independently */
624 			return NULL;
625 		}
626 
627 		if (ce->parent) {
628 			zend_class_entry *parent = ce->parent;
629 
630 			do {
631 				if (parent->type == ZEND_INTERNAL_CLASS) {
632 					break;
633 				} else if (parent->info.user.filename != filename) {
634 					/* some of parents class declarations might be changed independently */
635 					/* TODO: this check may be not enough, because even
636 					 * in the same it's possible to conditionally define
637 					 * few classes with the same name, and "parent" may
638 					 * change from request to request.
639 					 */
640 					return NULL;
641 				}
642 				parent = parent->parent;
643 			} while (parent);
644 		}
645 	}
646 
647 	info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
648 	if (info == NULL ||
649 	    !IS_VALID_PROPERTY_OFFSET(info->offset) ||
650 	    (info->flags & ZEND_ACC_STATIC)) {
651 		return NULL;
652 	}
653 
654 	if (info->flags & ZEND_ACC_PUBLIC) {
655 		return info;
656 	} else if (on_this) {
657 		if (ce == info->ce) {
658 			if (ce == op_array->scope) {
659 				return info;
660 			} else {
661 				return NULL;
662 			}
663 		} else if ((info->flags & ZEND_ACC_PROTECTED)
664 				&& instanceof_function_slow(ce, info->ce)) {
665 			return info;
666 		}
667 	}
668 
669 	return NULL;
670 }
671 
zend_may_be_dynamic_property(zend_class_entry * ce,zend_string * member,bool on_this,const zend_op_array * op_array)672 static bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *member, bool on_this, const zend_op_array *op_array)
673 {
674 	zend_property_info *info;
675 
676 	if (!ce || (ce->ce_flags & ZEND_ACC_TRAIT) || (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
677 		return 1;
678 	}
679 
680 	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
681 		if (ce->info.user.filename != op_array->filename) {
682 			/* class declaration might be changed independently */
683 			return 1;
684 		}
685 	}
686 
687 	info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
688 	if (info == NULL ||
689 	    !IS_VALID_PROPERTY_OFFSET(info->offset) ||
690 	    (info->flags & ZEND_ACC_STATIC)) {
691 		return 1;
692 	}
693 
694 	if (!(info->flags & ZEND_ACC_PUBLIC) &&
695 	    (!on_this || info->ce != ce)) {
696 		return 1;
697 	}
698 
699 	return 0;
700 }
701 
702 #define OP_RANGE(ssa_op, opN) \
703 	(((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
704 	  ssa->var_info && \
705 	  (ssa_op)->opN##_use >= 0 && \
706 	  ssa->var_info[(ssa_op)->opN##_use].has_range) ? \
707 	 &ssa->var_info[(ssa_op)->opN##_use].range : NULL)
708 
709 #define OP1_RANGE()      OP_RANGE(ssa_op, op1)
710 #define OP2_RANGE()      OP_RANGE(ssa_op, op2)
711 #define OP1_DATA_RANGE() OP_RANGE(ssa_op + 1, op1)
712 
713 #if ZEND_JIT_TARGET_X86
714 # include "dynasm/dasm_x86.h"
715 #elif ZEND_JIT_TARGET_ARM64
716 static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, uint32_t *cp, ptrdiff_t offset);
717 # define DASM_ADD_VENEER zend_jit_add_veneer
718 # include "dynasm/dasm_arm64.h"
719 #endif
720 
721 #include "jit/zend_jit_helpers.c"
722 #include "jit/zend_jit_disasm.c"
723 #ifndef _WIN32
724 # include "jit/zend_jit_gdb.h"
725 # include "jit/zend_jit_perf_dump.c"
726 #endif
727 #ifdef HAVE_OPROFILE
728 # include "jit/zend_jit_oprofile.c"
729 #endif
730 
731 #include "Zend/zend_cpuinfo.h"
732 
733 #ifdef HAVE_VALGRIND
734 # include <valgrind/valgrind.h>
735 #endif
736 
737 #ifdef HAVE_GCC_GLOBAL_REGS
738 # define GCC_GLOBAL_REGS 1
739 #else
740 # define GCC_GLOBAL_REGS 0
741 #endif
742 
743 /* By default avoid JITing inline handlers if it does not seem profitable due to lack of
744  * type information. Disabling this option allows testing some JIT handlers in the
745  * presence of try/catch blocks, which prevent SSA construction. */
746 #ifndef PROFITABILITY_CHECKS
747 # define PROFITABILITY_CHECKS 1
748 #endif
749 
750 #define BP_JIT_IS 6 /* Used for ISSET_ISEMPTY_DIM_OBJ. see BP_VAR_*defines in Zend/zend_compile.h */
751 
752 typedef enum _sp_adj_kind {
753 	SP_ADJ_NONE,
754 	SP_ADJ_RET,
755 	SP_ADJ_VM,
756 	SP_ADJ_JIT,
757 	SP_ADJ_ASSIGN,
758 	SP_ADJ_LAST
759 } sp_adj_kind;
760 
761 static int sp_adj[SP_ADJ_LAST];
762 
763 /* The generated code may contain tautological comparisons, ignore them. */
764 #if defined(__clang__)
765 # pragma clang diagnostic push
766 # pragma clang diagnostic ignored "-Wtautological-compare"
767 # pragma clang diagnostic ignored "-Wstring-compare"
768 #endif
769 
770 #if ZEND_JIT_TARGET_X86
771 # include "jit/zend_jit_vtune.c"
772 # include "jit/zend_jit_x86.c"
773 #elif ZEND_JIT_TARGET_ARM64
774 # include "jit/zend_jit_arm64.c"
775 #endif
776 
777 #if defined(__clang__)
778 # pragma clang diagnostic pop
779 #endif
780 
781 #if _WIN32
782 # include <Windows.h>
783 #else
784 # include <sys/mman.h>
785 # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
786 #   define MAP_ANONYMOUS MAP_ANON
787 # endif
788 #endif
789 
zend_jit_status(zval * ret)790 ZEND_EXT_API void zend_jit_status(zval *ret)
791 {
792 	zval stats;
793 	array_init(&stats);
794 	add_assoc_bool(&stats, "enabled", JIT_G(enabled));
795 	add_assoc_bool(&stats, "on", JIT_G(on));
796 	add_assoc_long(&stats, "kind", JIT_G(trigger));
797 	add_assoc_long(&stats, "opt_level", JIT_G(opt_level));
798 	add_assoc_long(&stats, "opt_flags", JIT_G(opt_flags));
799 	if (dasm_buf) {
800 		add_assoc_long(&stats, "buffer_size", (char*)dasm_end - (char*)dasm_buf);
801 		add_assoc_long(&stats, "buffer_free", (char*)dasm_end - (char*)*dasm_ptr);
802 	} else {
803 		add_assoc_long(&stats, "buffer_size", 0);
804 		add_assoc_long(&stats, "buffer_free", 0);
805 	}
806 	add_assoc_zval(ret, "jit", &stats);
807 }
808 
zend_jit_func_name(const zend_op_array * op_array)809 static zend_string *zend_jit_func_name(const zend_op_array *op_array)
810 {
811 	smart_str buf = {0};
812 
813 	if (op_array->function_name) {
814 		if (op_array->scope) {
815 			smart_str_appends(&buf, JIT_PREFIX);
816 			smart_str_appendl(&buf, ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name));
817 			smart_str_appends(&buf, "::");
818 			smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
819 			smart_str_0(&buf);
820 			return buf.s;
821 		} else {
822 			smart_str_appends(&buf, JIT_PREFIX);
823 			smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
824 			smart_str_0(&buf);
825 			return buf.s;
826 		}
827 	} else if (op_array->filename) {
828 		smart_str_appends(&buf, JIT_PREFIX);
829 		smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
830 		smart_str_0(&buf);
831 		return buf.s;
832 	} else {
833 		return NULL;
834 	}
835 }
836 
837 #if ZEND_DEBUG
handle_dasm_error(int ret)838 static void handle_dasm_error(int ret) {
839 	switch (ret & 0xff000000u) {
840 		case DASM_S_NOMEM:
841 			fprintf(stderr, "DASM_S_NOMEM\n");
842 			break;
843 		case DASM_S_PHASE:
844 			fprintf(stderr, "DASM_S_PHASE\n");
845 			break;
846 		case DASM_S_MATCH_SEC:
847 			fprintf(stderr, "DASM_S_MATCH_SEC\n");
848 			break;
849 		case DASM_S_RANGE_I:
850 			fprintf(stderr, "DASM_S_RANGE_I\n");
851 			break;
852 		case DASM_S_RANGE_SEC:
853 			fprintf(stderr, "DASM_S_RANGE_SEC\n");
854 			break;
855 		case DASM_S_RANGE_LG:
856 			fprintf(stderr, "DASM_S_RANGE_LG\n");
857 			break;
858 		case DASM_S_RANGE_PC:
859 			fprintf(stderr, "DASM_S_RANGE_PC %d\n", ret & 0xffffffu);
860 			break;
861 #ifdef DASM_S_RANGE_VREG
862 		case DASM_S_RANGE_VREG:
863 			fprintf(stderr, "DASM_S_RANGE_VREG\n");
864 			break;
865 #endif
866 #ifdef DASM_S_UNDEF_L
867 		case DASM_S_UNDEF_L:
868 			fprintf(stderr, "DASM_S_UNDEF_L\n");
869 			break;
870 #endif
871 #ifdef DASM_S_UNDEF_LG
872 		case DASM_S_UNDEF_LG:
873 			fprintf(stderr, "DASM_S_UNDEF_LG\n");
874 			break;
875 #endif
876 #ifdef DASM_S_RANGE_REL
877 		case DASM_S_RANGE_REL:
878 			fprintf(stderr, "DASM_S_RANGE_REL\n");
879 			break;
880 #endif
881 		case DASM_S_UNDEF_PC:
882 			fprintf(stderr, "DASM_S_UNDEF_PC %d\n", ret & 0xffffffu);
883 			break;
884 		default:
885 			fprintf(stderr, "DASM_S_%0x\n", ret & 0xff000000u);
886 			break;
887 	}
888 	ZEND_UNREACHABLE();
889 }
890 #endif
891 
dasm_link_and_encode(dasm_State ** dasm_state,const zend_op_array * op_array,zend_ssa * ssa,const zend_op * rt_opline,zend_lifetime_interval ** ra,const char * name,uint32_t trace_num,uint32_t sp_offset,uint32_t sp_adjustment)892 static void *dasm_link_and_encode(dasm_State             **dasm_state,
893                                   const zend_op_array     *op_array,
894                                   zend_ssa                *ssa,
895                                   const zend_op           *rt_opline,
896                                   zend_lifetime_interval **ra,
897                                   const char              *name,
898                                   uint32_t                 trace_num,
899                                   uint32_t                 sp_offset,
900                                   uint32_t                 sp_adjustment)
901 {
902 	size_t size;
903 	int ret;
904 	void *entry;
905 #if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)
906 	zend_string *str = NULL;
907 #endif
908 
909 	if (rt_opline && ssa && ssa->cfg.map) {
910 		/* Create additional entry point, to switch from interpreter to JIT-ed
911 		 * code at run-time.
912 		 */
913 		int b = ssa->cfg.map[rt_opline - op_array->opcodes];
914 
915 //#ifdef CONTEXT_THREADED_JIT
916 //		if (!(ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY))) {
917 //#else
918 		if (!(ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY))) {
919 //#endif
920 			zend_jit_label(dasm_state, ssa->cfg.blocks_count + b);
921 			zend_jit_prologue(dasm_state);
922 			if (ra) {
923 				int i;
924 				zend_lifetime_interval *ival;
925 				zend_life_range *range;
926 				uint32_t pos = rt_opline - op_array->opcodes;
927 
928 				for (i = 0; i < ssa->vars_count; i++) {
929 					ival = ra[i];
930 
931 					if (ival && ival->reg != ZREG_NONE) {
932 						range = &ival->range;
933 
934 						if (pos >= range->start && pos <= range->end) {
935 							if (!zend_jit_load_var(dasm_state, ssa->var_info[i].type, ssa->vars[i].var, ival->reg)) {
936 								return NULL;
937 							}
938 							break;
939 						}
940 						range = range->next;
941 					}
942 				}
943 			}
944 			zend_jit_jmp(dasm_state, b);
945 		}
946 	}
947 
948 	ret = dasm_link(dasm_state, &size);
949 	if (ret != DASM_S_OK) {
950 #if ZEND_DEBUG
951 		handle_dasm_error(ret);
952 #endif
953 		return NULL;
954 	}
955 
956 	if ((void*)((char*)*dasm_ptr + size) > dasm_end) {
957 		*dasm_ptr = dasm_end; //prevent further try
958 		// TODO: jit_buffer_size overflow ???
959 		return NULL;
960 	}
961 
962 #if ZEND_JIT_TARGET_ARM64
963 	dasm_venners_size = 0;
964 #endif
965 
966 	ret = dasm_encode(dasm_state, *dasm_ptr);
967 	if (ret != DASM_S_OK) {
968 #if ZEND_DEBUG
969 		handle_dasm_error(ret);
970 #endif
971 		return NULL;
972 	}
973 
974 #if ZEND_JIT_TARGET_ARM64
975 	size += dasm_venners_size;
976 #endif
977 
978 	entry = *dasm_ptr;
979 	*dasm_ptr = (void*)((char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(size, DASM_ALIGNMENT));
980 
981 	/* flush the hardware I-cache */
982 	JIT_CACHE_FLUSH(entry, entry + size);
983 
984 	if (trace_num) {
985 		zend_jit_trace_add_code(entry, dasm_getpclabel(dasm_state, 1));
986 	}
987 
988 	if (op_array && ssa) {
989 		int b;
990 
991 		for (b = 0; b < ssa->cfg.blocks_count; b++) {
992 //#ifdef CONTEXT_THREADED_JIT
993 //			if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) {
994 //#else
995 			if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
996 //#endif
997 				zend_op *opline = op_array->opcodes + ssa->cfg.blocks[b].start;
998 				int offset = dasm_getpclabel(dasm_state, ssa->cfg.blocks_count + b);
999 
1000 				if (offset >= 0) {
1001 					opline->handler = (void*)(((char*)entry) + offset);
1002 				}
1003 			}
1004 		}
1005 	    if (rt_opline && ssa && ssa->cfg.map) {
1006 			int b = ssa->cfg.map[rt_opline - op_array->opcodes];
1007 			zend_op *opline = (zend_op*)rt_opline;
1008 			int offset = dasm_getpclabel(dasm_state, ssa->cfg.blocks_count + b);
1009 
1010 			if (offset >= 0) {
1011 				opline->handler = (void*)(((char*)entry) + offset);
1012 			}
1013 		}
1014 	}
1015 
1016 #if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)
1017 	if (!name) {
1018 		if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_OPROFILE|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_VTUNE|ZEND_JIT_DEBUG_PERF_DUMP)) {
1019 			str = zend_jit_func_name(op_array);
1020 			if (str) {
1021 				name = ZSTR_VAL(str);
1022 			}
1023 		}
1024 #ifdef HAVE_DISASM
1025 	    if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
1026 			zend_jit_disasm_add_symbol(name, (uintptr_t)entry, size);
1027 			zend_jit_disasm(
1028 				name,
1029 				(op_array && op_array->filename) ? ZSTR_VAL(op_array->filename) : NULL,
1030 				op_array,
1031 				&ssa->cfg,
1032 				entry,
1033 				size);
1034 		}
1035 	} else {
1036 	    if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM_STUBS|ZEND_JIT_DEBUG_ASM)) {
1037 			zend_jit_disasm_add_symbol(name, (uintptr_t)entry, size);
1038 			if ((JIT_G(debug) & (trace_num ? ZEND_JIT_DEBUG_ASM : ZEND_JIT_DEBUG_ASM_STUBS)) != 0) {
1039 				zend_jit_disasm(
1040 					name,
1041 					(op_array && op_array->filename) ? ZSTR_VAL(op_array->filename) : NULL,
1042 					op_array,
1043 					ssa ? &ssa->cfg : NULL,
1044 					entry,
1045 					size);
1046 			}
1047 		}
1048 # endif
1049 	}
1050 #endif
1051 
1052 #ifdef HAVE_GDB
1053 	if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
1054 		if (name) {
1055 			zend_jit_gdb_register(
1056 					name,
1057 					op_array,
1058 					entry,
1059 					size,
1060 					sp_adj[sp_offset],
1061 					sp_adj[sp_adjustment]);
1062 		}
1063 	}
1064 #endif
1065 
1066 #ifdef HAVE_OPROFILE
1067 	if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) {
1068 		zend_jit_oprofile_register(
1069 			name,
1070 			entry,
1071 			size);
1072 	}
1073 #endif
1074 
1075 #ifdef HAVE_PERFTOOLS
1076 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
1077 		if (name) {
1078 			zend_jit_perf_map_register(
1079 				name,
1080 				entry,
1081 				size);
1082 			if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
1083 				zend_jit_perf_jitdump_register(
1084 					name,
1085 					entry,
1086 					size);
1087 			}
1088 		}
1089 	}
1090 #endif
1091 
1092 #ifdef HAVE_VTUNE
1093 	if (JIT_G(debug) & ZEND_JIT_DEBUG_VTUNE) {
1094 		if (name) {
1095 			zend_jit_vtune_register(
1096 				name,
1097 				entry,
1098 				size);
1099 		}
1100 	}
1101 #endif
1102 
1103 #if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)
1104 	if (str) {
1105 		zend_string_release(str);
1106 	}
1107 #endif
1108 
1109 	return entry;
1110 }
1111 
zend_may_overflow(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,zend_ssa * ssa)1112 static int zend_may_overflow(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa)
1113 {
1114 	int res;
1115 	zend_long op1_min, op1_max, op2_min, op2_max;
1116 
1117 	if (!ssa->ops || !ssa->var_info) {
1118 		return 1;
1119 	}
1120 	switch (opline->opcode) {
1121 		case ZEND_PRE_INC:
1122 		case ZEND_POST_INC:
1123 			res = ssa_op->op1_def;
1124 			if (res < 0
1125 			 || !ssa->var_info[res].has_range
1126 			 || ssa->var_info[res].range.overflow) {
1127 				if (!OP1_HAS_RANGE()) {
1128 					return 1;
1129 				}
1130 				op1_max = OP1_MAX_RANGE();
1131 				if (op1_max == ZEND_LONG_MAX) {
1132 					return 1;
1133 				}
1134 			}
1135 			return 0;
1136 		case ZEND_PRE_DEC:
1137 		case ZEND_POST_DEC:
1138 			res = ssa_op->op1_def;
1139 			if (res < 0
1140 			 || !ssa->var_info[res].has_range
1141 			 || ssa->var_info[res].range.underflow) {
1142 				if (!OP1_HAS_RANGE()) {
1143 					return 1;
1144 				}
1145 				op1_min = OP1_MIN_RANGE();
1146 				if (op1_min == ZEND_LONG_MIN) {
1147 					return 1;
1148 				}
1149 			}
1150 			return 0;
1151 		case ZEND_ADD:
1152 			res = ssa_op->result_def;
1153 			if (res < 0
1154 			 || !ssa->var_info[res].has_range
1155 			 || ssa->var_info[res].range.underflow) {
1156 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1157 					return 1;
1158 				}
1159 				op1_min = OP1_MIN_RANGE();
1160 				op2_min = OP2_MIN_RANGE();
1161 				if (zend_add_will_overflow(op1_min, op2_min)) {
1162 					return 1;
1163 				}
1164 			}
1165 			if (res < 0
1166 			 || !ssa->var_info[res].has_range
1167 			 || ssa->var_info[res].range.overflow) {
1168 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1169 					return 1;
1170 				}
1171 				op1_max = OP1_MAX_RANGE();
1172 				op2_max = OP2_MAX_RANGE();
1173 				if (zend_add_will_overflow(op1_max, op2_max)) {
1174 					return 1;
1175 				}
1176 			}
1177 			return 0;
1178 		case ZEND_SUB:
1179 			res = ssa_op->result_def;
1180 			if (res < 0
1181 			 || !ssa->var_info[res].has_range
1182 			 || ssa->var_info[res].range.underflow) {
1183 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1184 					return 1;
1185 				}
1186 				op1_min = OP1_MIN_RANGE();
1187 				op2_max = OP2_MAX_RANGE();
1188 				if (zend_sub_will_overflow(op1_min, op2_max)) {
1189 					return 1;
1190 				}
1191 			}
1192 			if (res < 0
1193 			 || !ssa->var_info[res].has_range
1194 			 || ssa->var_info[res].range.overflow) {
1195 				if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1196 					return 1;
1197 				}
1198 				op1_max = OP1_MAX_RANGE();
1199 				op2_min = OP2_MIN_RANGE();
1200 				if (zend_sub_will_overflow(op1_max, op2_min)) {
1201 					return 1;
1202 				}
1203 			}
1204 			return 0;
1205 		case ZEND_MUL:
1206 			res = ssa_op->result_def;
1207 			return (res < 0 ||
1208 				!ssa->var_info[res].has_range ||
1209 				ssa->var_info[res].range.underflow ||
1210 				ssa->var_info[res].range.overflow);
1211 		case ZEND_ASSIGN_OP:
1212 			if (opline->extended_value == ZEND_ADD) {
1213 				res = ssa_op->op1_def;
1214 				if (res < 0
1215 				 || !ssa->var_info[res].has_range
1216 				 || ssa->var_info[res].range.underflow) {
1217 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1218 						return 1;
1219 					}
1220 					op1_min = OP1_MIN_RANGE();
1221 					op2_min = OP2_MIN_RANGE();
1222 					if (zend_add_will_overflow(op1_min, op2_min)) {
1223 						return 1;
1224 					}
1225 				}
1226 				if (res < 0
1227 				 || !ssa->var_info[res].has_range
1228 				 || ssa->var_info[res].range.overflow) {
1229 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1230 						return 1;
1231 					}
1232 					op1_max = OP1_MAX_RANGE();
1233 					op2_max = OP2_MAX_RANGE();
1234 					if (zend_add_will_overflow(op1_max, op2_max)) {
1235 						return 1;
1236 					}
1237 				}
1238 				return 0;
1239 			} else if (opline->extended_value == ZEND_SUB) {
1240 				res = ssa_op->op1_def;
1241 				if (res < 0
1242 				 || !ssa->var_info[res].has_range
1243 				 || ssa->var_info[res].range.underflow) {
1244 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1245 						return 1;
1246 					}
1247 					op1_min = OP1_MIN_RANGE();
1248 					op2_max = OP2_MAX_RANGE();
1249 					if (zend_sub_will_overflow(op1_min, op2_max)) {
1250 						return 1;
1251 					}
1252 				}
1253 				if (res < 0
1254 				 || !ssa->var_info[res].has_range
1255 				 || ssa->var_info[res].range.overflow) {
1256 					if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
1257 						return 1;
1258 					}
1259 					op1_max = OP1_MAX_RANGE();
1260 					op2_min = OP2_MIN_RANGE();
1261 					if (zend_sub_will_overflow(op1_max, op2_min)) {
1262 						return 1;
1263 					}
1264 				}
1265 				return 0;
1266 			} else if (opline->extended_value == ZEND_MUL) {
1267 				res = ssa_op->op1_def;
1268 				return (res < 0 ||
1269 					!ssa->var_info[res].has_range ||
1270 					ssa->var_info[res].range.underflow ||
1271 					ssa->var_info[res].range.overflow);
1272 			}
1273 			ZEND_FALLTHROUGH;
1274 		default:
1275 			return 1;
1276 	}
1277 }
1278 
zend_jit_build_cfg(const zend_op_array * op_array,zend_cfg * cfg)1279 static int zend_jit_build_cfg(const zend_op_array *op_array, zend_cfg *cfg)
1280 {
1281 	uint32_t flags;
1282 
1283 	flags = ZEND_CFG_STACKLESS | ZEND_CFG_NO_ENTRY_PREDECESSORS | ZEND_SSA_RC_INFERENCE_FLAG | ZEND_SSA_USE_CV_RESULTS | ZEND_CFG_RECV_ENTRY;
1284 
1285 	zend_build_cfg(&CG(arena), op_array, flags, cfg);
1286 
1287 	/* Don't JIT huge functions. Apart from likely being detrimental due to the amount of
1288 	 * generated code, some of our analysis is recursive and will stack overflow with many
1289 	 * blocks. */
1290 	if (cfg->blocks_count > 100000) {
1291 		return FAILURE;
1292 	}
1293 
1294 	zend_cfg_build_predecessors(&CG(arena), cfg);
1295 
1296 	/* Compute Dominators Tree */
1297 	zend_cfg_compute_dominators_tree(op_array, cfg);
1298 
1299 	/* Identify reducible and irreducible loops */
1300 	zend_cfg_identify_loops(op_array, cfg);
1301 
1302 	return SUCCESS;
1303 }
1304 
zend_jit_op_array_analyze1(const zend_op_array * op_array,zend_script * script,zend_ssa * ssa)1305 static int zend_jit_op_array_analyze1(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa)
1306 {
1307 	if (zend_jit_build_cfg(op_array, &ssa->cfg) != SUCCESS) {
1308 		return FAILURE;
1309 	}
1310 
1311 #if 0
1312 	/* TODO: debugger and profiler supports? */
1313 	if ((ssa->cfg.flags & ZEND_FUNC_HAS_EXTENDED_INFO)) {
1314 		return FAILURE;
1315 	}
1316 #endif
1317 
1318 	/* TODO: move this to zend_cfg.c ? */
1319 	if (!op_array->function_name) {
1320 		ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1321 	}
1322 
1323 	if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC)
1324 	 && ssa->cfg.blocks
1325 	 && op_array->last_try_catch == 0
1326 	 && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
1327 	 && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
1328 		if (zend_build_ssa(&CG(arena), script, op_array, ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS, ssa) != SUCCESS) {
1329 			return FAILURE;
1330 		}
1331 
1332 		zend_ssa_compute_use_def_chains(&CG(arena), op_array, ssa);
1333 
1334 		zend_ssa_find_false_dependencies(op_array, ssa);
1335 
1336 		zend_ssa_find_sccs(op_array, ssa);
1337 	}
1338 
1339 	return SUCCESS;
1340 }
1341 
zend_jit_op_array_analyze2(const zend_op_array * op_array,zend_script * script,zend_ssa * ssa,uint32_t optimization_level)1342 static int zend_jit_op_array_analyze2(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa, uint32_t optimization_level)
1343 {
1344 	if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC)
1345 	 && ssa->cfg.blocks
1346 	 && op_array->last_try_catch == 0
1347 	 && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
1348 	 && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
1349 		if (zend_ssa_inference(&CG(arena), op_array, script, ssa,
1350 				optimization_level & ~ZEND_OPTIMIZER_NARROW_TO_DOUBLE) != SUCCESS) {
1351 			return FAILURE;
1352 		}
1353 	}
1354 
1355 	return SUCCESS;
1356 }
1357 
zend_jit_add_range(zend_lifetime_interval ** intervals,int var,uint32_t from,uint32_t to)1358 static int zend_jit_add_range(zend_lifetime_interval **intervals, int var, uint32_t from, uint32_t to)
1359 {
1360 	zend_lifetime_interval *ival = intervals[var];
1361 
1362 	if (!ival) {
1363 		ival = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval));
1364 		if (!ival) {
1365 			return FAILURE;
1366 		}
1367 		ival->ssa_var = var;
1368 		ival->reg = ZREG_NONE;
1369 		ival->flags = 0;
1370 		ival->range.start = from;
1371 		ival->range.end = to;
1372 		ival->range.next = NULL;
1373 		ival->hint = NULL;
1374 		ival->used_as_hint = NULL;
1375 		intervals[var] = ival;
1376 	} else if (ival->range.start > to + 1) {
1377 		zend_life_range *range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
1378 
1379 		if (!range) {
1380 			return FAILURE;
1381 		}
1382 		range->start = ival->range.start;
1383 		range->end   = ival->range.end;
1384 		range->next  = ival->range.next;
1385 		ival->range.start = from;
1386 		ival->range.end = to;
1387 		ival->range.next = range;
1388 	} else if (ival->range.start == to + 1) {
1389 		ival->range.start = from;
1390 	} else {
1391 		zend_life_range *range = &ival->range;
1392 		zend_life_range *last = NULL;
1393 
1394 		do {
1395 			if (range->start > to + 1) {
1396 				break;
1397 			} else if (range->end + 1 >= from) {
1398 				if (range->start > from) {
1399 					range->start = from;
1400 				}
1401 				last = range;
1402 				range = range->next;
1403 				while (range) {
1404 					if (range->start > to + 1) {
1405 						break;
1406 					}
1407 					last->end = range->end;
1408 					range = range->next;
1409 					last->next = range;
1410 				}
1411 				if (to > last->end) {
1412 					last->end = to;
1413 				}
1414 				return SUCCESS;
1415 			}
1416 			last = range;
1417 			range = range->next;
1418 		} while (range);
1419 
1420 		range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
1421 		if (!range) {
1422 			return FAILURE;
1423 		}
1424 		range->start = from;
1425 		range->end   = to;
1426 		range->next  = last->next;
1427 		last->next = range;
1428 	}
1429 
1430 	return SUCCESS;
1431 }
1432 
zend_jit_begin_range(zend_lifetime_interval ** intervals,int var,uint32_t block_start,uint32_t from)1433 static int zend_jit_begin_range(zend_lifetime_interval **intervals, int var, uint32_t block_start, uint32_t from)
1434 {
1435 	if (block_start != from && intervals[var]) {
1436 		zend_life_range *range = &intervals[var]->range;
1437 
1438 		do {
1439 			if (from >= range->start && from <= range->end) {
1440 				if (range->start == block_start) {
1441 					range->start = from;
1442 				} else {
1443 					zend_life_range *r = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
1444 					if (!r) {
1445 						return FAILURE;
1446 					}
1447 					r->start = from;
1448 					r->end = range->end;
1449 					r->next = range->next;
1450 					range->end = block_start - 1;
1451 					range->next = r;
1452 				}
1453 				return SUCCESS;
1454 			}
1455 			range = range->next;
1456 		} while (range);
1457 	}
1458 
1459 	// dead store
1460 	return zend_jit_add_range(intervals, var, from, from);
1461 }
1462 
zend_jit_insert_interval(zend_lifetime_interval ** list,zend_lifetime_interval * ival)1463 static void zend_jit_insert_interval(zend_lifetime_interval **list, zend_lifetime_interval *ival)
1464 {
1465 	while (1) {
1466 		if (*list == NULL) {
1467 			*list = ival;
1468 			ival->list_next = NULL;
1469 			return;
1470 		} else if (ival->range.start < (*list)->range.start) {
1471 			ival->list_next = *list;
1472 			*list = ival;
1473 			return;
1474 		}
1475 		list = &(*list)->list_next;
1476 	}
1477 }
1478 
zend_jit_split_interval(zend_lifetime_interval * current,uint32_t pos,zend_lifetime_interval ** list,zend_lifetime_interval ** free)1479 static int zend_jit_split_interval(zend_lifetime_interval *current, uint32_t pos, zend_lifetime_interval **list, zend_lifetime_interval **free)
1480 {
1481 	zend_lifetime_interval *ival;
1482 	zend_life_range *range = &current->range;
1483 	zend_life_range *prev = NULL;
1484 
1485 	if (*free) {
1486 		ival = *free;
1487 		*free = ival->list_next;
1488 	} else {
1489 		ival = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval));
1490 
1491 		if (!ival) {
1492 			return FAILURE;
1493 		}
1494 	}
1495 
1496 	current->flags |= ZREG_STORE;
1497 
1498 	ival->ssa_var = current->ssa_var;
1499 	ival->reg     = ZREG_NONE;
1500 	ival->flags  |= ZREG_SPLIT | ZREG_LOAD;
1501 	ival->flags  &= ~ZREG_STORE;
1502 	ival->hint    = NULL;
1503 
1504 	do {
1505 		if (pos >= range->start && pos <= range->end) {
1506 			break;
1507 		}
1508 		prev = range;
1509 		range = range->next;
1510 	} while(range);
1511 
1512 	ZEND_ASSERT(range != NULL);
1513 
1514 	ival->range.start   = pos;
1515 	ival->range.end     = range->end;
1516 	ival->range.next    = range->next;
1517 
1518 	if (pos == range->start) {
1519 		ZEND_ASSERT(prev != NULL);
1520 		prev->next = NULL;
1521 	} else {
1522 		range->end = pos - 1;
1523 	}
1524 
1525 	zend_jit_insert_interval(list, ival);
1526 
1527 	return SUCCESS;
1528 }
1529 
zend_jit_sort_intervals(zend_lifetime_interval ** intervals,int count)1530 static zend_lifetime_interval *zend_jit_sort_intervals(zend_lifetime_interval **intervals, int count)
1531 {
1532 	zend_lifetime_interval *list, *last;
1533 	int i;
1534 
1535 	list = NULL;
1536 	i = 0;
1537 	while (i < count) {
1538 		list = intervals[i];
1539 		i++;
1540 		if (list) {
1541 			last = list;
1542 			last->list_next = NULL;
1543 			break;
1544 		}
1545 	}
1546 
1547 	while (i < count) {
1548 		zend_lifetime_interval *ival = intervals[i];
1549 
1550 		i++;
1551 		if (ival) {
1552 			if ((ival->range.start > last->range.start) ||
1553 			    (ival->range.start == last->range.start &&
1554 			     ((!ival->hint && last->hint && last->hint != ival) ||
1555 			      ival->range.end > last->range.end))) {
1556 				last->list_next = ival;
1557 				last = ival;
1558 				ival->list_next = NULL;
1559 			} else {
1560 				zend_lifetime_interval **p = &list;
1561 
1562 				while (1) {
1563 					if (*p == NULL) {
1564 						*p = last = ival;
1565 						ival->list_next = NULL;
1566 						break;
1567 					} else if ((ival->range.start < (*p)->range.start) ||
1568 					           (ival->range.start == (*p)->range.start &&
1569 					            ((ival->hint && !(*p)->hint && ival->hint != *p) ||
1570 					             ival->range.end < (*p)->range.end))) {
1571 						ival->list_next = *p;
1572 						*p = ival;
1573 						break;
1574 					}
1575 					p = &(*p)->list_next;
1576 				}
1577 			}
1578 		}
1579 	}
1580 
1581 	return list;
1582 }
1583 
zend_jit_print_regset(zend_regset regset)1584 static ZEND_ATTRIBUTE_UNUSED void zend_jit_print_regset(zend_regset regset)
1585 {
1586 	zend_reg reg;
1587 	int first = 1;
1588 
1589 	ZEND_REGSET_FOREACH(regset, reg) {
1590 		if (first) {
1591 			first = 0;
1592 			fprintf(stderr, "%s", zend_reg_name[reg]);
1593 		} else {
1594 			fprintf(stderr, ", %s", zend_reg_name[reg]);
1595 		}
1596 	} ZEND_REGSET_FOREACH_END();
1597 }
1598 
zend_jit_compute_block_order_int(zend_ssa * ssa,int n,int * block_order)1599 static int *zend_jit_compute_block_order_int(zend_ssa *ssa, int n, int *block_order)
1600 {
1601 	zend_basic_block *b = ssa->cfg.blocks + n;
1602 
1603 tail_call:
1604 	*block_order = n;
1605 	block_order++;
1606 
1607 	n = b->children;
1608 	while (n >= 0) {
1609 		b = ssa->cfg.blocks + n;
1610 		if (b->next_child < 0) {
1611 			goto tail_call;
1612 		}
1613 		block_order = zend_jit_compute_block_order_int(ssa, n, block_order);
1614 		n = b->next_child;
1615 	}
1616 
1617 	return block_order;
1618 }
1619 
zend_jit_compute_block_order(zend_ssa * ssa,int * block_order)1620 static int zend_jit_compute_block_order(zend_ssa *ssa, int *block_order)
1621 {
1622 	int *end = zend_jit_compute_block_order_int(ssa, 0, block_order);
1623 
1624 	return end - block_order;
1625 }
1626 
zend_jit_in_loop(zend_ssa * ssa,int header,zend_basic_block * b)1627 static bool zend_jit_in_loop(zend_ssa *ssa, int header, zend_basic_block *b)
1628 {
1629 	while (b->loop_header >= 0) {
1630 		if (b->loop_header == header) {
1631 			return 1;
1632 		}
1633 		b = ssa->cfg.blocks + b->loop_header;
1634 	}
1635 	return 0;
1636 }
1637 
zend_jit_compute_loop_body(zend_ssa * ssa,int header,int n,zend_bitset loop_body)1638 static void zend_jit_compute_loop_body(zend_ssa *ssa, int header, int n, zend_bitset loop_body)
1639 {
1640 	zend_basic_block *b = ssa->cfg.blocks + n;
1641 	uint32_t i;
1642 
1643 tail_call:
1644 	if (b->len) {
1645 		for (i = b->start; i < b->start + b->len; i++) {
1646 			zend_bitset_incl(loop_body, i);
1647 		}
1648 	}
1649 
1650 	n = b->children;
1651 	while (n >= 0) {
1652 		b = ssa->cfg.blocks + n;
1653 		if (zend_jit_in_loop(ssa, header, b)) {
1654 			if (b->next_child < 0) {
1655 				goto tail_call;
1656 			}
1657 			zend_jit_compute_loop_body(ssa, header, n, loop_body);
1658 		}
1659 		n = b->next_child;
1660 	}
1661 }
1662 
zend_jit_add_hint(zend_lifetime_interval ** intervals,int dst,int src)1663 static void zend_jit_add_hint(zend_lifetime_interval **intervals, int dst, int src)
1664 {
1665 	if (intervals[dst]->range.start < intervals[src]->range.start) {
1666 		int tmp = src;
1667 		src = dst;
1668 		dst = tmp;
1669 	}
1670 	while (dst != src && intervals[dst]->hint) {
1671 		if (intervals[dst]->hint->range.start < intervals[src]->range.start) {
1672 			int tmp = src;
1673 			src = intervals[dst]->hint->ssa_var;
1674 			dst = tmp;
1675 		} else {
1676 			dst = intervals[dst]->hint->ssa_var;
1677 		}
1678 	}
1679 	if (dst != src) {
1680 		intervals[dst]->hint = intervals[src];
1681 	}
1682 }
1683 
1684 /* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
1685    Michael Franz, CGO'10 (2010), Figure 4. */
zend_jit_compute_liveness(const zend_op_array * op_array,zend_ssa * ssa,zend_bitset candidates,zend_lifetime_interval ** list)1686 static int zend_jit_compute_liveness(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset candidates, zend_lifetime_interval **list)
1687 {
1688 	int set_size, i, j, k, l;
1689 	uint32_t n;
1690 	zend_bitset live, live_in, pi_vars, loop_body;
1691 	int *block_order;
1692 	zend_ssa_phi *phi;
1693 	zend_lifetime_interval **intervals;
1694 	size_t mem_size;
1695 	ALLOCA_FLAG(use_heap);
1696 
1697 	set_size = zend_bitset_len(ssa->vars_count);
1698 	mem_size =
1699 		ZEND_MM_ALIGNED_SIZE(ssa->vars_count * sizeof(zend_lifetime_interval*)) +
1700 		ZEND_MM_ALIGNED_SIZE((set_size * ssa->cfg.blocks_count) * ZEND_BITSET_ELM_SIZE) +
1701 		ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE) +
1702 		ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE) +
1703 		ZEND_MM_ALIGNED_SIZE(zend_bitset_len(op_array->last) * ZEND_BITSET_ELM_SIZE) +
1704 		ZEND_MM_ALIGNED_SIZE(ssa->cfg.blocks_count * sizeof(int));
1705 	intervals = do_alloca(mem_size, use_heap);
1706 	if (!intervals) {
1707 		*list = NULL;
1708 		return FAILURE;
1709 	}
1710 
1711 	live_in = (zend_bitset)((char*)intervals + ZEND_MM_ALIGNED_SIZE(ssa->vars_count * sizeof(zend_lifetime_interval*)));
1712 	live = (zend_bitset)((char*)live_in + ZEND_MM_ALIGNED_SIZE((set_size * ssa->cfg.blocks_count) * ZEND_BITSET_ELM_SIZE));
1713 	pi_vars = (zend_bitset)((char*)live + ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE));
1714 	loop_body = (zend_bitset)((char*)pi_vars + ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE));
1715 	block_order = (int*)((char*)loop_body + ZEND_MM_ALIGNED_SIZE(zend_bitset_len(op_array->last) * ZEND_BITSET_ELM_SIZE));
1716 
1717 	memset(intervals, 0, ssa->vars_count * sizeof(zend_lifetime_interval*));
1718 	zend_bitset_clear(live_in, set_size * ssa->cfg.blocks_count);
1719 
1720 	/* TODO: Provide a linear block order where all dominators of a block
1721 	 * are before this block, and where all blocks belonging to the same loop
1722 	 * are contiguous ???
1723 	 */
1724 	for (l = zend_jit_compute_block_order(ssa, block_order) - 1; l >= 0; l--) {
1725 		zend_basic_block *b;
1726 
1727 		i = block_order[l];
1728 		b = ssa->cfg.blocks + i;
1729 
1730 		/* live = UNION of successor.liveIn for each successor of b */
1731 		/* live.add(phi.inputOf(b)) for each phi of successors of b */
1732 		zend_bitset_clear(live, set_size);
1733 		for (j = 0; j < b->successors_count; j++) {
1734 			int succ = b->successors[j];
1735 
1736 			zend_bitset_union(live, live_in + set_size * succ, set_size);
1737 			zend_bitset_clear(pi_vars, set_size);
1738 			for (phi = ssa->blocks[succ].phis; phi; phi = phi->next) {
1739 				if (ssa->vars[phi->ssa_var].no_val) {
1740 					/* skip */
1741 				} else if (phi->pi >= 0) {
1742 					if (phi->pi == i && phi->sources[0] >= 0) {
1743 						if (zend_bitset_in(candidates, phi->sources[0])) {
1744 							zend_bitset_incl(live, phi->sources[0]);
1745 						}
1746 						zend_bitset_incl(pi_vars, phi->var);
1747 					}
1748 				} else if (!zend_bitset_in(pi_vars, phi->var)) {
1749 					for (k = 0; k < ssa->cfg.blocks[succ].predecessors_count; k++) {
1750 						if (ssa->cfg.predecessors[ssa->cfg.blocks[succ].predecessor_offset + k] == i) {
1751 							if (phi->sources[k] >= 0 && zend_bitset_in(candidates, phi->sources[k])) {
1752 								zend_bitset_incl(live, phi->sources[k]);
1753 							}
1754 							break;
1755 						}
1756 					}
1757 				}
1758 			}
1759 		}
1760 
1761 		/* addRange(var, b.from, b.to) for each var in live */
1762 		ZEND_BITSET_FOREACH(live, set_size, j) {
1763 			if (zend_bitset_in(candidates, j)) {
1764 				if (zend_jit_add_range(intervals, j, b->start, b->start + b->len - 1) != SUCCESS) {
1765 					goto failure;
1766 				}
1767 			}
1768 		} ZEND_BITSET_FOREACH_END();
1769 
1770 		/* for each operation op of b in reverse order */
1771 		for (n = b->start + b->len; n > b->start;) {
1772 			zend_ssa_op *op;
1773 			const zend_op *opline;
1774 			uint32_t num;
1775 
1776 			n--;
1777 			op = ssa->ops + n;
1778 			opline = op_array->opcodes + n;
1779 
1780 			if (UNEXPECTED(opline->opcode == ZEND_OP_DATA)) {
1781 				num = n - 1;
1782 			} else {
1783 				num = n;
1784 			}
1785 
1786 			/* for each output operand opd of op do */
1787 			/*   setFrom(opd, op)                   */
1788 			/*   live.remove(opd)                   */
1789 			if (op->op1_def >= 0 && zend_bitset_in(candidates, op->op1_def)) {
1790 				if (zend_jit_begin_range(intervals, op->op1_def, b->start, num) != SUCCESS) {
1791 					goto failure;
1792 				}
1793 				zend_bitset_excl(live, op->op1_def);
1794 			}
1795 			if (op->op2_def >= 0 && zend_bitset_in(candidates, op->op2_def)) {
1796 				if (zend_jit_begin_range(intervals, op->op2_def, b->start, num) != SUCCESS) {
1797 					goto failure;
1798 				}
1799 				zend_bitset_excl(live, op->op2_def);
1800 			}
1801 			if (op->result_def >= 0 && zend_bitset_in(candidates, op->result_def)) {
1802 				if (zend_jit_begin_range(intervals, op->result_def, b->start, num) != SUCCESS) {
1803 					goto failure;
1804 				}
1805 				zend_bitset_excl(live, op->result_def);
1806 			}
1807 
1808 			/* for each input operand opd of op do */
1809 			/*   live.add(opd)                     */
1810 			/*   addRange(opd, b.from, op)         */
1811 			if (op->op1_use >= 0
1812 			 && zend_bitset_in(candidates, op->op1_use)
1813 			 && !zend_ssa_is_no_val_use(opline, op, op->op1_use)) {
1814 				zend_bitset_incl(live, op->op1_use);
1815 				if (zend_jit_add_range(intervals, op->op1_use, b->start, num) != SUCCESS) {
1816 					goto failure;
1817 				}
1818 			}
1819 			if (op->op2_use >= 0
1820 			 && zend_bitset_in(candidates, op->op2_use)
1821 			 && !zend_ssa_is_no_val_use(opline, op, op->op2_use)) {
1822 				zend_bitset_incl(live, op->op2_use);
1823 				if (zend_jit_add_range(intervals, op->op2_use, b->start, num) != SUCCESS) {
1824 					goto failure;
1825 				}
1826 			}
1827 			if (op->result_use >= 0
1828 			 && zend_bitset_in(candidates, op->result_use)
1829 			 && !zend_ssa_is_no_val_use(opline, op, op->result_use)) {
1830 				zend_bitset_incl(live, op->result_use);
1831 				if (zend_jit_add_range(intervals, op->result_use, b->start, num) != SUCCESS) {
1832 					goto failure;
1833 				}
1834 			}
1835 		}
1836 
1837 		/* live.remove(phi.output) for each phi of b */
1838 		for (phi = ssa->blocks[i].phis; phi; phi = phi->next) {
1839 			zend_bitset_excl(live, phi->ssa_var);
1840 		}
1841 
1842 		/* b.liveIn = live */
1843 		zend_bitset_copy(live_in + set_size * i, live, set_size);
1844 	}
1845 
1846 	for (i = ssa->cfg.blocks_count - 1; i >= 0; i--) {
1847 		zend_basic_block *b = ssa->cfg.blocks + i;
1848 
1849 		/* if b is loop header */
1850 		if ((b->flags & ZEND_BB_LOOP_HEADER)) {
1851 			live = live_in + set_size * i;
1852 
1853 			if (!zend_bitset_empty(live, set_size)) {
1854 				uint32_t set_size2 = zend_bitset_len(op_array->last);
1855 
1856 				zend_bitset_clear(loop_body, set_size2);
1857 				zend_jit_compute_loop_body(ssa, i, i, loop_body);
1858 				while (!zend_bitset_empty(loop_body, set_size2)) {
1859 					uint32_t from = zend_bitset_first(loop_body, set_size2);
1860 					uint32_t to = from;
1861 
1862 					do {
1863 						zend_bitset_excl(loop_body, to);
1864 						to++;
1865 					} while (zend_bitset_in(loop_body, to));
1866 					to--;
1867 
1868 					ZEND_BITSET_FOREACH(live, set_size, j) {
1869 						if (zend_jit_add_range(intervals, j, from, to) != SUCCESS) {
1870 							goto failure;
1871 						}
1872 					} ZEND_BITSET_FOREACH_END();
1873 				}
1874 			}
1875 		}
1876 
1877 	}
1878 
1879 	if (JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) {
1880 		/* Register hinting (a cheap way for register coalescing) */
1881 		for (i = 0; i < ssa->vars_count; i++) {
1882 			if (intervals[i]) {
1883 				int src;
1884 
1885 				if (ssa->vars[i].definition_phi) {
1886 					zend_ssa_phi *phi = ssa->vars[i].definition_phi;
1887 
1888 					if (phi->pi >= 0) {
1889 						src = phi->sources[0];
1890 						if (intervals[src]) {
1891 							zend_jit_add_hint(intervals, i, src);
1892 						}
1893 					} else {
1894 						for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
1895 							src = phi->sources[k];
1896 							if (src >= 0) {
1897 								if (ssa->vars[src].definition_phi
1898 								 && ssa->vars[src].definition_phi->pi >= 0
1899 								 && phi->block == ssa->vars[src].definition_phi->block) {
1900 									/* Skip zero-length interval for Pi variable */
1901 									src = ssa->vars[src].definition_phi->sources[0];
1902 								}
1903 								if (intervals[src]) {
1904 									zend_jit_add_hint(intervals, i, src);
1905 								}
1906 							}
1907 						}
1908 					}
1909 				}
1910 			}
1911 		}
1912 		for (i = 0; i < ssa->vars_count; i++) {
1913 			if (intervals[i] && !intervals[i]->hint) {
1914 
1915 				if (ssa->vars[i].definition >= 0) {
1916 					uint32_t line = ssa->vars[i].definition;
1917 					const zend_op *opline = op_array->opcodes + line;
1918 
1919 					switch (opline->opcode) {
1920 						case ZEND_QM_ASSIGN:
1921 						case ZEND_POST_INC:
1922 						case ZEND_POST_DEC:
1923 							if (ssa->ops[line].op1_use >= 0 &&
1924 							    intervals[ssa->ops[line].op1_use] &&
1925 							    (i == ssa->ops[line].op1_def ||
1926 							     (i == ssa->ops[line].result_def &&
1927 							      (ssa->ops[line].op1_def < 0 ||
1928 							       !intervals[ssa->ops[line].op1_def])))) {
1929 								zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
1930 							}
1931 							break;
1932 						case ZEND_SEND_VAR:
1933 						case ZEND_PRE_INC:
1934 						case ZEND_PRE_DEC:
1935 							if (i == ssa->ops[line].op1_def &&
1936 							    ssa->ops[line].op1_use >= 0 &&
1937 							    intervals[ssa->ops[line].op1_use]) {
1938 								zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
1939 							}
1940 							break;
1941 						case ZEND_ASSIGN:
1942 							if (ssa->ops[line].op2_use >= 0 &&
1943 							    intervals[ssa->ops[line].op2_use] &&
1944 							    (i == ssa->ops[line].op2_def ||
1945 								 (i == ssa->ops[line].op1_def &&
1946 							      (ssa->ops[line].op2_def < 0 ||
1947 							       !intervals[ssa->ops[line].op2_def])) ||
1948 								 (i == ssa->ops[line].result_def &&
1949 							      (ssa->ops[line].op2_def < 0 ||
1950 							       !intervals[ssa->ops[line].op2_def]) &&
1951 							      (ssa->ops[line].op1_def < 0 ||
1952 							       !intervals[ssa->ops[line].op1_def])))) {
1953 								zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
1954 							}
1955 							break;
1956 						case ZEND_SUB:
1957 						case ZEND_ADD:
1958 						case ZEND_MUL:
1959 						case ZEND_BW_OR:
1960 						case ZEND_BW_AND:
1961 						case ZEND_BW_XOR:
1962 							if (i == ssa->ops[line].result_def) {
1963 								if (ssa->ops[line].op1_use >= 0 &&
1964 								    intervals[ssa->ops[line].op1_use] &&
1965 								    ssa->ops[line].op1_use_chain < 0 &&
1966 								    !ssa->vars[ssa->ops[line].op1_use].phi_use_chain &&
1967 								    (ssa->var_info[i].type & MAY_BE_ANY) ==
1968 								        (ssa->var_info[ssa->ops[line].op1_use].type & MAY_BE_ANY)) {
1969 									zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
1970 								} else if (opline->opcode != ZEND_SUB &&
1971 								    ssa->ops[line].op2_use >= 0 &&
1972 								    intervals[ssa->ops[line].op2_use] &&
1973 								    ssa->ops[line].op2_use_chain < 0 &&
1974 								    !ssa->vars[ssa->ops[line].op2_use].phi_use_chain &&
1975 								    (ssa->var_info[i].type & MAY_BE_ANY) ==
1976 								        (ssa->var_info[ssa->ops[line].op2_use].type & MAY_BE_ANY)) {
1977 									zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
1978 								}
1979 							}
1980 							break;
1981 					}
1982 				}
1983 			}
1984 		}
1985 	}
1986 
1987 	*list = zend_jit_sort_intervals(intervals, ssa->vars_count);
1988 
1989 	if (*list) {
1990 		zend_lifetime_interval *ival = *list;
1991 		while (ival) {
1992 			if (ival->hint) {
1993 				ival->hint->used_as_hint = ival;
1994 			}
1995 			ival = ival->list_next;
1996 		}
1997 	}
1998 
1999 	free_alloca(intervals, use_heap);
2000 	return SUCCESS;
2001 
2002 failure:
2003 	*list = NULL;
2004 	free_alloca(intervals, use_heap);
2005 	return FAILURE;
2006 }
2007 
zend_interval_end(zend_lifetime_interval * ival)2008 static uint32_t zend_interval_end(zend_lifetime_interval *ival)
2009 {
2010 	zend_life_range *range = &ival->range;
2011 
2012 	while (range->next) {
2013 		range = range->next;
2014 	}
2015 	return range->end;
2016 }
2017 
zend_interval_covers(zend_lifetime_interval * ival,uint32_t position)2018 static bool zend_interval_covers(zend_lifetime_interval *ival, uint32_t position)
2019 {
2020 	zend_life_range *range = &ival->range;
2021 
2022 	do {
2023 		if (position >= range->start && position <= range->end) {
2024 			return 1;
2025 		}
2026 		range = range->next;
2027 	} while (range);
2028 
2029 	return 0;
2030 }
2031 
zend_interval_intersection(zend_lifetime_interval * ival1,zend_lifetime_interval * ival2)2032 static uint32_t zend_interval_intersection(zend_lifetime_interval *ival1, zend_lifetime_interval *ival2)
2033 {
2034 	zend_life_range *r1 = &ival1->range;
2035 	zend_life_range *r2 = &ival2->range;
2036 
2037 	do {
2038 		if (r1->start <= r2->end) {
2039 			if (r2->start <= r1->end) {
2040 				return MAX(r1->start, r2->start);
2041 			} else {
2042 				r2 = r2->next;
2043 			}
2044 		} else {
2045 			r1 = r1->next;
2046 		}
2047 	} while (r1 && r2);
2048 
2049 	return 0xffffffff;
2050 }
2051 
2052 /* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
2053    Christian Wimmer VEE'05 (2005), Figure 4. Allocation without spilling */
zend_jit_try_allocate_free_reg(const zend_op_array * op_array,const zend_op ** ssa_opcodes,zend_ssa * ssa,zend_lifetime_interval * current,zend_regset available,zend_regset * hints,zend_lifetime_interval * active,zend_lifetime_interval * inactive,zend_lifetime_interval ** list,zend_lifetime_interval ** free)2054 static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, const zend_op **ssa_opcodes, zend_ssa *ssa, zend_lifetime_interval *current, zend_regset available, zend_regset *hints, zend_lifetime_interval *active, zend_lifetime_interval *inactive, zend_lifetime_interval **list, zend_lifetime_interval **free)
2055 {
2056 	zend_lifetime_interval *it;
2057 	uint32_t freeUntilPos[ZREG_NUM];
2058 	uint32_t pos, pos2;
2059 	zend_reg i, reg, reg2;
2060 	zend_reg hint = ZREG_NONE;
2061 	zend_regset low_priority_regs;
2062 	zend_life_range *range;
2063 
2064 	if ((ssa->var_info[current->ssa_var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
2065 		available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_FP);
2066 	} else {
2067 		available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_GP);
2068 	}
2069 
2070 	/* TODO: Allow usage of preserved registers ???
2071 	 * Their values have to be stored in prologue and restored in epilogue
2072 	 */
2073 	available = ZEND_REGSET_DIFFERENCE(available, ZEND_REGSET_PRESERVED);
2074 
2075 	/* Set freeUntilPos of all physical registers to maxInt */
2076 	for (i = 0; i < ZREG_NUM; i++) {
2077 		freeUntilPos[i] = 0xffffffff;
2078 	}
2079 
2080 	/* for each interval it in active do */
2081 	/*   freeUntilPos[it.reg] = 0        */
2082 	it = active;
2083 	if (ssa->vars[current->ssa_var].definition == current->range.start) {
2084 		while (it) {
2085 			if (current->range.start != zend_interval_end(it)) {
2086 				freeUntilPos[it->reg] = 0;
2087 			} else if (zend_jit_may_reuse_reg(
2088 					ssa_opcodes ? ssa_opcodes[current->range.start] : op_array->opcodes + current->range.start,
2089 					ssa->ops + current->range.start, ssa, current->ssa_var, it->ssa_var)) {
2090 				if (!ZEND_REGSET_IN(*hints, it->reg) &&
2091 				    /* TODO: Avoid most often scratch registers. Find a better way ??? */
2092 				    (!current->used_as_hint ||
2093 				     !ZEND_REGSET_IN(ZEND_REGSET_LOW_PRIORITY, it->reg))) {
2094 					hint = it->reg;
2095 				}
2096 			} else {
2097 				freeUntilPos[it->reg] = 0;
2098 			}
2099 			it = it->list_next;
2100 		}
2101 	} else {
2102 		while (it) {
2103 			freeUntilPos[it->reg] = 0;
2104 			it = it->list_next;
2105 		}
2106 	}
2107 	if (current->hint) {
2108 		hint = current->hint->reg;
2109 		if (hint != ZREG_NONE && current->hint->used_as_hint == current) {
2110 			ZEND_REGSET_EXCL(*hints, hint);
2111 		}
2112 	}
2113 
2114 	if (hint == ZREG_NONE && ZEND_REGSET_IS_EMPTY(available)) {
2115 		return 0;
2116 	}
2117 
2118 	/* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
2119 	   Michael Franz, CGO'10 (2010), Figure 6. */
2120 	if (current->flags & ZREG_SPLIT) {
2121 		/* for each interval it in inactive intersecting with current do */
2122 		/*   freeUntilPos[it.reg] = next intersection of it with current */
2123 		it = inactive;
2124 		while (it) {
2125 			uint32_t next = zend_interval_intersection(current, it);
2126 
2127 			//ZEND_ASSERT(next != 0xffffffff && !current->split);
2128 			if (next < freeUntilPos[it->reg]) {
2129 				freeUntilPos[it->reg] = next;
2130 			}
2131 			it = it->list_next;
2132 		}
2133 	}
2134 
2135 	/* Handle Scratch Registers */
2136 	/* TODO: Optimize ??? */
2137 	range = &current->range;
2138 	do {
2139 		uint32_t line = range->start;
2140 		uint32_t last_use_line = (uint32_t)-1;
2141 		zend_regset regset;
2142 		zend_reg reg;
2143 
2144 		if ((current->flags & ZREG_LAST_USE) && !range->next) {
2145 			last_use_line = range->end;
2146 		}
2147 		if (ssa->ops[line].op1_def == current->ssa_var ||
2148 		    ssa->ops[line].op2_def == current->ssa_var ||
2149 		    ssa->ops[line].result_def == current->ssa_var) {
2150 			regset = zend_jit_get_def_scratch_regset(
2151 				ssa_opcodes ? ssa_opcodes[line] : op_array->opcodes + line,
2152 				ssa->ops + line,
2153 				op_array, ssa, current->ssa_var, line == last_use_line);
2154 			ZEND_REGSET_FOREACH(regset, reg) {
2155 				if (line < freeUntilPos[reg]) {
2156 					freeUntilPos[reg] = line;
2157 				}
2158 			} ZEND_REGSET_FOREACH_END();
2159 			line++;
2160 		}
2161 		while (line <= range->end) {
2162 			regset = zend_jit_get_scratch_regset(
2163 				ssa_opcodes ? ssa_opcodes[line] : op_array->opcodes + line,
2164 				ssa->ops + line,
2165 				op_array, ssa, current->ssa_var, line == last_use_line);
2166 			ZEND_REGSET_FOREACH(regset, reg) {
2167 				if (line < freeUntilPos[reg]) {
2168 					freeUntilPos[reg] = line;
2169 				}
2170 			} ZEND_REGSET_FOREACH_END();
2171 			line++;
2172 		}
2173 		range = range->next;
2174 	} while (range);
2175 
2176 #if 0
2177 	/* Coalescing */
2178 	if (ssa->vars[current->ssa_var].definition == current->start) {
2179 		zend_op *opline = op_array->opcodes + current->start;
2180 		int hint = -1;
2181 
2182 		switch (opline->opcode) {
2183 			case ZEND_ASSIGN:
2184 				hint = ssa->ops[current->start].op2_use;
2185 			case ZEND_QM_ASSIGN:
2186 				hint = ssa->ops[current->start].op1_use;
2187 				break;
2188 			case ZEND_ADD:
2189 			case ZEND_SUB:
2190 			case ZEND_MUL:
2191 				hint = ssa->ops[current->start].op1_use;
2192 				break;
2193 			case ZEND_ASSIGN_OP:
2194 				if (opline->extended_value == ZEND_ADD
2195 				 || opline->extended_value == ZEND_SUB
2196 				 || opline->extended_value == ZEND_MUL) {
2197 					hint = ssa->ops[current->start].op1_use;
2198 				}
2199 				break;
2200 		}
2201 		if (hint >= 0) {
2202 		}
2203 	}
2204 #endif
2205 
2206 	if (hint != ZREG_NONE && freeUntilPos[hint] > zend_interval_end(current)) {
2207 		current->reg = hint;
2208 		if (current->used_as_hint) {
2209 			ZEND_REGSET_INCL(*hints, hint);
2210 		}
2211 		return 1;
2212 	}
2213 
2214 	if (ZEND_REGSET_IS_EMPTY(available)) {
2215 		return 0;
2216 	}
2217 
2218 	pos = 0; reg = ZREG_NONE;
2219 	pos2 = 0; reg2 = ZREG_NONE;
2220 	low_priority_regs = *hints;
2221 	if (current->used_as_hint) {
2222 		/* TODO: Avoid most often scratch registers. Find a better way ??? */
2223 		low_priority_regs = ZEND_REGSET_UNION(low_priority_regs, ZEND_REGSET_LOW_PRIORITY);
2224 	}
2225 
2226 	ZEND_REGSET_FOREACH(available, i) {
2227 		if (ZEND_REGSET_IN(low_priority_regs, i)) {
2228 			if (freeUntilPos[i] > pos2) {
2229 				reg2 = i;
2230 				pos2 = freeUntilPos[i];
2231 			}
2232 		} else if (freeUntilPos[i] > pos) {
2233 			reg = i;
2234 			pos = freeUntilPos[i];
2235 		}
2236 	} ZEND_REGSET_FOREACH_END();
2237 
2238 	if (reg == ZREG_NONE) {
2239 		if (reg2 != ZREG_NONE) {
2240 			reg = reg2;
2241 			pos = pos2;
2242 			reg2 = ZREG_NONE;
2243 		}
2244 	}
2245 
2246 	if (reg == ZREG_NONE) {
2247 		/* no register available without spilling */
2248 		return 0;
2249 	} else if (zend_interval_end(current) < pos) {
2250 		/* register available for the whole interval */
2251 		current->reg = reg;
2252 		if (current->used_as_hint) {
2253 			ZEND_REGSET_INCL(*hints, reg);
2254 		}
2255 		return 1;
2256 #if 0
2257 	// TODO: allow low priority register usage
2258 	} else if (reg2 != ZREG_NONE && zend_interval_end(current) < pos2) {
2259 		/* register available for the whole interval */
2260 		current->reg = reg2;
2261 		if (current->used_as_hint) {
2262 			ZEND_REGSET_INCL(*hints, reg2);
2263 		}
2264 		return 1;
2265 #endif
2266 	} else {
2267 		/* TODO: enable interval splitting ??? */
2268 		/* register available for the first part of the interval */
2269 		if (1 || zend_jit_split_interval(current, pos, list, free) != SUCCESS) {
2270 			return 0;
2271 		}
2272 		current->reg = reg;
2273 		if (current->used_as_hint) {
2274 			ZEND_REGSET_INCL(*hints, reg);
2275 		}
2276 		return 1;
2277 	}
2278 }
2279 
2280 /* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
2281    Christian Wimmer VEE'05 (2005), Figure 5. Allocation with spilling.
2282    and "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
2283    Michael Franz, CGO'10 (2010), Figure 6. */
zend_jit_allocate_blocked_reg(void)2284 static int zend_jit_allocate_blocked_reg(void)
2285 {
2286 	/* TODO: ??? */
2287 	return 0;
2288 }
2289 
2290 /* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
2291    Christian Wimmer VEE'10 (2005), Figure 2. */
zend_jit_linear_scan(const zend_op_array * op_array,const zend_op ** ssa_opcodes,zend_ssa * ssa,zend_lifetime_interval * list)2292 static zend_lifetime_interval* zend_jit_linear_scan(const zend_op_array *op_array, const zend_op **ssa_opcodes, zend_ssa *ssa, zend_lifetime_interval *list)
2293 {
2294 	zend_lifetime_interval *unhandled, *active, *inactive, *handled, *free;
2295 	zend_lifetime_interval *current, **p, *q;
2296 	uint32_t position;
2297 	zend_regset available = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
2298 	zend_regset hints = ZEND_REGSET_EMPTY;
2299 
2300 	unhandled = list;
2301 	/* active = inactive = handled = free = {} */
2302 	active = inactive = handled = free = NULL;
2303 	while (unhandled != NULL) {
2304 		current = unhandled;
2305 		unhandled = unhandled->list_next;
2306 		position = current->range.start;
2307 
2308 		p = &active;
2309 		while (*p) {
2310 			uint32_t end = zend_interval_end(*p);
2311 
2312 			q = *p;
2313 			if (end < position) {
2314 				/* move ival from active to handled */
2315 				ZEND_REGSET_INCL(available, q->reg);
2316 				*p = q->list_next;
2317 				q->list_next = handled;
2318 				handled = q;
2319 			} else if (!zend_interval_covers(q, position)) {
2320 				/* move ival from active to inactive */
2321 				ZEND_REGSET_INCL(available, q->reg);
2322 				*p = q->list_next;
2323 				q->list_next = inactive;
2324 				inactive = q;
2325 			} else {
2326 				p = &q->list_next;
2327 			}
2328 		}
2329 
2330 		p = &inactive;
2331 		while (*p) {
2332 			uint32_t end = zend_interval_end(*p);
2333 
2334 			q = *p;
2335 			if (end < position) {
2336 				/* move ival from inactive to handled */
2337 				*p = q->list_next;
2338 				q->list_next = handled;
2339 				handled = q;
2340 			} else if (zend_interval_covers(q, position)) {
2341 				/* move ival from inactive to active */
2342 				ZEND_REGSET_EXCL(available, q->reg);
2343 				*p = q->list_next;
2344 				q->list_next = active;
2345 				active = q;
2346 			} else {
2347 				p = &q->list_next;
2348 			}
2349 		}
2350 
2351 		if (zend_jit_try_allocate_free_reg(op_array, ssa_opcodes, ssa, current, available, &hints, active, inactive, &unhandled, &free) ||
2352 		    zend_jit_allocate_blocked_reg()) {
2353 			ZEND_REGSET_EXCL(available, current->reg);
2354 			current->list_next = active;
2355 			active = current;
2356 		} else {
2357 			current->list_next = free;
2358 			free = current;
2359 		}
2360 	}
2361 
2362 	/* move active to handled */
2363 	while (active) {
2364 		current = active;
2365 		active = active->list_next;
2366 		current->list_next = handled;
2367 		handled = current;
2368 	}
2369 
2370 	/* move inactive to handled */
2371 	while (inactive) {
2372 		current = inactive;
2373 		inactive = inactive->list_next;
2374 		current->list_next = handled;
2375 		handled = current;
2376 	}
2377 
2378 	return handled;
2379 }
2380 
zend_jit_dump_lifetime_interval(const zend_op_array * op_array,const zend_ssa * ssa,const zend_lifetime_interval * ival)2381 static void zend_jit_dump_lifetime_interval(const zend_op_array *op_array, const zend_ssa *ssa, const zend_lifetime_interval *ival)
2382 {
2383 	zend_life_range *range;
2384 	int var_num = ssa->vars[ival->ssa_var].var;
2385 
2386 	fprintf(stderr, "#%d.", ival->ssa_var);
2387 	zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
2388 	fprintf(stderr, ": %u-%u", ival->range.start, ival->range.end);
2389 	range = ival->range.next;
2390 	while (range) {
2391 		fprintf(stderr, ", %u-%u", range->start, range->end);
2392 		range = range->next;
2393 	}
2394 	if (ival->reg != ZREG_NONE) {
2395 		fprintf(stderr, " (%s)", zend_reg_name[ival->reg]);
2396 	}
2397 	if (ival->flags & ZREG_LAST_USE) {
2398 		fprintf(stderr, " last_use");
2399 	}
2400 	if (ival->flags & ZREG_LOAD) {
2401 		fprintf(stderr, " load");
2402 	}
2403 	if (ival->flags & ZREG_STORE) {
2404 		fprintf(stderr, " store");
2405 	}
2406 	if (ival->hint) {
2407 		fprintf(stderr, " hint");
2408 		if (ival->hint->ssa_var >= 0) {
2409 			var_num = ssa->vars[ival->hint->ssa_var].var;
2410 			fprintf(stderr, "=#%d.", ival->hint->ssa_var);
2411 			zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
2412 		}
2413 		if (ival->hint->reg != ZREG_NONE) {
2414 			fprintf(stderr, " (%s)", zend_reg_name[ival->hint->reg]);
2415 		}
2416 	}
2417 	fprintf(stderr, "\n");
2418 }
2419 
zend_jit_allocate_registers(const zend_op_array * op_array,zend_ssa * ssa)2420 static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array *op_array, zend_ssa *ssa)
2421 {
2422 	void *checkpoint;
2423 	int set_size, candidates_count, i;
2424 	zend_bitset candidates = NULL;
2425 	zend_lifetime_interval *list, *ival;
2426 	zend_lifetime_interval **intervals;
2427 	ALLOCA_FLAG(use_heap);
2428 
2429 	if (!ssa->var_info) {
2430 		return NULL;
2431 	}
2432 
2433 	/* Identify SSA variables suitable for register allocation */
2434 	set_size = zend_bitset_len(ssa->vars_count);
2435 	candidates = ZEND_BITSET_ALLOCA(set_size, use_heap);
2436 	if (!candidates) {
2437 		return NULL;
2438 	}
2439 	candidates_count = 0;
2440 	zend_bitset_clear(candidates, set_size);
2441 	for (i = 0; i < ssa->vars_count; i++) {
2442 		if (zend_jit_may_be_in_reg(op_array, ssa, i)) {
2443 			zend_bitset_incl(candidates, i);
2444 			candidates_count++;
2445 		}
2446 	}
2447 	if (!candidates_count) {
2448 		free_alloca(candidates, use_heap);
2449 		return NULL;
2450 	}
2451 
2452 	checkpoint = zend_arena_checkpoint(CG(arena));
2453 
2454 	/* Find life-time intervals */
2455 	if (zend_jit_compute_liveness(op_array, ssa, candidates, &list) != SUCCESS) {
2456 		goto failure;
2457 	}
2458 
2459 	if (list) {
2460 		/* Set ZREG_LAST_USE flags */
2461 		ival = list;
2462 		while (ival) {
2463 			zend_life_range *range = &ival->range;
2464 
2465 			while (range->next) {
2466 				range = range->next;
2467 			}
2468 			if (zend_ssa_is_last_use(op_array, ssa, ival->ssa_var, range->end)) {
2469 				ival->flags |= ZREG_LAST_USE;
2470 			}
2471 			ival = ival->list_next;
2472 		}
2473 	}
2474 
2475 	if (list) {
2476 		if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
2477 			fprintf(stderr, "Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
2478 			ival = list;
2479 			while (ival) {
2480 				zend_jit_dump_lifetime_interval(op_array, ssa, ival);
2481 				ival = ival->list_next;
2482 			}
2483 			fprintf(stderr, "\n");
2484 		}
2485 
2486 		/* Linear Scan Register Allocation */
2487 		list = zend_jit_linear_scan(op_array, NULL, ssa, list);
2488 
2489 		if (list) {
2490 			intervals = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_lifetime_interval*));
2491 			if (!intervals) {
2492 				goto failure;
2493 			}
2494 
2495 			ival = list;
2496 			while (ival != NULL) {
2497 				zend_lifetime_interval *next = ival->list_next;
2498 
2499 				ival->list_next = intervals[ival->ssa_var];
2500 				intervals[ival->ssa_var] = ival;
2501 				ival = next;
2502 			}
2503 
2504 			if (JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) {
2505 				/* Naive SSA resolution */
2506 				for (i = 0; i < ssa->vars_count; i++) {
2507 					if (ssa->vars[i].definition_phi && !ssa->vars[i].no_val) {
2508 						zend_ssa_phi *phi = ssa->vars[i].definition_phi;
2509 						int k, src;
2510 
2511 						if (phi->pi >= 0) {
2512 							if (!ssa->vars[i].phi_use_chain
2513 							 || ssa->vars[i].phi_use_chain->block != phi->block) {
2514 								src = phi->sources[0];
2515 								if (intervals[i]) {
2516 									if (!intervals[src]) {
2517 										intervals[i]->flags |= ZREG_LOAD;
2518 									} else if (intervals[i]->reg != intervals[src]->reg) {
2519 										intervals[i]->flags |= ZREG_LOAD;
2520 										intervals[src]->flags |= ZREG_STORE;
2521 									}
2522 								} else if (intervals[src]) {
2523 									intervals[src]->flags |= ZREG_STORE;
2524 								}
2525 							}
2526 						} else {
2527 							int need_move = 0;
2528 
2529 							for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
2530 								src = phi->sources[k];
2531 								if (src >= 0) {
2532 									if (ssa->vars[src].definition_phi
2533 									 && ssa->vars[src].definition_phi->pi >= 0
2534 									 && phi->block == ssa->vars[src].definition_phi->block) {
2535 										/* Skip zero-length interval for Pi variable */
2536 										src = ssa->vars[src].definition_phi->sources[0];
2537 									}
2538 									if (intervals[i]) {
2539 										if (!intervals[src]) {
2540 											need_move = 1;
2541 										} else if (intervals[i]->reg != intervals[src]->reg) {
2542 											need_move = 1;
2543 										}
2544 									} else if (intervals[src]) {
2545 										need_move = 1;
2546 									}
2547 								}
2548 							}
2549 							if (need_move) {
2550 								if (intervals[i]) {
2551 									intervals[i]->flags |= ZREG_LOAD;
2552 								}
2553 								for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
2554 									src = phi->sources[k];
2555 									if (src >= 0) {
2556 										if (ssa->vars[src].definition_phi
2557 										 && ssa->vars[src].definition_phi->pi >= 0
2558 										 && phi->block == ssa->vars[src].definition_phi->block) {
2559 											/* Skip zero-length interval for Pi variable */
2560 											src = ssa->vars[src].definition_phi->sources[0];
2561 										}
2562 										if (intervals[src]) {
2563 											intervals[src]->flags |= ZREG_STORE;
2564 										}
2565 									}
2566 								}
2567 							}
2568 						}
2569 					}
2570 				}
2571 				/* Remove useless register allocation */
2572 				for (i = 0; i < ssa->vars_count; i++) {
2573 					if (intervals[i] &&
2574 					    ((intervals[i]->flags & ZREG_LOAD) ||
2575 					     ((intervals[i]->flags & ZREG_STORE) && ssa->vars[i].definition >= 0)) &&
2576 					    ssa->vars[i].use_chain < 0) {
2577 					    bool may_remove = 1;
2578 						zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
2579 
2580 						while (phi) {
2581 							if (intervals[phi->ssa_var] &&
2582 							    !(intervals[phi->ssa_var]->flags & ZREG_LOAD)) {
2583 								may_remove = 0;
2584 								break;
2585 							}
2586 							phi = zend_ssa_next_use_phi(ssa, i, phi);
2587 						}
2588 						if (may_remove) {
2589 							intervals[i] = NULL;
2590 						}
2591 					}
2592 				}
2593 				/* Remove intervals used once */
2594 				for (i = 0; i < ssa->vars_count; i++) {
2595 					if (intervals[i] &&
2596 					    (intervals[i]->flags & ZREG_LOAD) &&
2597 					    (intervals[i]->flags & ZREG_STORE) &&
2598 					    (ssa->vars[i].use_chain < 0 ||
2599 					     zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
2600 						bool may_remove = 1;
2601 						zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
2602 
2603 						while (phi) {
2604 							if (intervals[phi->ssa_var] &&
2605 							    !(intervals[phi->ssa_var]->flags & ZREG_LOAD)) {
2606 								may_remove = 0;
2607 								break;
2608 							}
2609 							phi = zend_ssa_next_use_phi(ssa, i, phi);
2610 						}
2611 						if (may_remove) {
2612 							intervals[i] = NULL;
2613 						}
2614 					}
2615 				}
2616 			}
2617 
2618 			if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
2619 				fprintf(stderr, "Allocated Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
2620 				for (i = 0; i < ssa->vars_count; i++) {
2621 					ival = intervals[i];
2622 					while (ival) {
2623 						zend_jit_dump_lifetime_interval(op_array, ssa, ival);
2624 						ival = ival->list_next;
2625 					}
2626 				}
2627 				fprintf(stderr, "\n");
2628 			}
2629 
2630 			free_alloca(candidates, use_heap);
2631 			return intervals;
2632 		}
2633 	}
2634 
2635 failure:
2636 	zend_arena_release(&CG(arena), checkpoint);
2637 	free_alloca(candidates, use_heap);
2638 	return NULL;
2639 }
2640 
zend_jit_next_is_send_result(const zend_op * opline)2641 static bool zend_jit_next_is_send_result(const zend_op *opline)
2642 {
2643 	if (opline->result_type == IS_TMP_VAR
2644 	 && (opline+1)->opcode == ZEND_SEND_VAL
2645 	 && (opline+1)->op1_type == IS_TMP_VAR
2646 	 && (opline+1)->op2_type != IS_CONST
2647 	 && (opline+1)->op1.var == opline->result.var) {
2648 		return 1;
2649 	}
2650 	return 0;
2651 }
2652 
zend_jit_supported_binary_op(zend_uchar op,uint32_t op1_info,uint32_t op2_info)2653 static bool zend_jit_supported_binary_op(zend_uchar op, uint32_t op1_info, uint32_t op2_info)
2654 {
2655 	if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
2656 		return false;
2657 	}
2658 	switch (op) {
2659 		case ZEND_POW:
2660 		case ZEND_DIV:
2661 			// TODO: check for division by zero ???
2662 			return false;
2663 		case ZEND_ADD:
2664 		case ZEND_SUB:
2665 		case ZEND_MUL:
2666 			return (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
2667 				&& (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
2668 		case ZEND_BW_OR:
2669 		case ZEND_BW_AND:
2670 		case ZEND_BW_XOR:
2671 		case ZEND_SL:
2672 		case ZEND_SR:
2673 		case ZEND_MOD:
2674 			return (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG);
2675 		case ZEND_CONCAT:
2676 			return (op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING);
2677 		EMPTY_SWITCH_DEFAULT_CASE()
2678 	}
2679 }
2680 
zend_jit(const zend_op_array * op_array,zend_ssa * ssa,const zend_op * rt_opline)2681 static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_opline)
2682 {
2683 	int b, i, end;
2684 	zend_op *opline;
2685 	dasm_State* dasm_state = NULL;
2686 	void *handler;
2687 	int call_level = 0;
2688 	void *checkpoint = NULL;
2689 	zend_lifetime_interval **ra = NULL;
2690 	bool is_terminated = 1; /* previous basic block is terminated by jump */
2691 	bool recv_emitted = 0;   /* emitted at least one RECV opcode */
2692 	zend_uchar smart_branch_opcode;
2693 	uint32_t target_label, target_label2;
2694 	uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info;
2695 	zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
2696 	zend_class_entry *ce;
2697 	bool ce_is_instanceof;
2698 	bool on_this;
2699 
2700 	if (JIT_G(bisect_limit)) {
2701 		jit_bisect_pos++;
2702 		if (jit_bisect_pos >= JIT_G(bisect_limit)) {
2703 			if (jit_bisect_pos == JIT_G(bisect_limit)) {
2704 				fprintf(stderr, "Not JITing %s%s%s in %s:%d and after due to jit_bisect_limit\n",
2705 					op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
2706 					op_array->scope ? "::" : "",
2707 					op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}",
2708 					ZSTR_VAL(op_array->filename), op_array->line_start);
2709 			}
2710 			return FAILURE;
2711 		}
2712 	}
2713 
2714 	if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
2715 		checkpoint = zend_arena_checkpoint(CG(arena));
2716 		ra = zend_jit_allocate_registers(op_array, ssa);
2717 	}
2718 
2719 	/* mark hidden branch targets */
2720 	for (b = 0; b < ssa->cfg.blocks_count; b++) {
2721 		if (ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE &&
2722 		    ssa->cfg.blocks[b].len > 1) {
2723 
2724 			opline = op_array->opcodes + ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1;
2725 			if (opline->opcode == ZEND_DO_FCALL &&
2726 			    (opline-1)->opcode == ZEND_NEW) {
2727 				ssa->cfg.blocks[ssa->cfg.blocks[b].successors[0]].flags |= ZEND_BB_TARGET;
2728 			}
2729 		}
2730 	}
2731 
2732 	dasm_init(&dasm_state, DASM_MAXSECTION);
2733 	dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
2734 	dasm_setup(&dasm_state, dasm_actions);
2735 
2736 	dasm_growpc(&dasm_state, ssa->cfg.blocks_count * 2 + 1);
2737 
2738 	zend_jit_align_func(&dasm_state);
2739 	for (b = 0; b < ssa->cfg.blocks_count; b++) {
2740 		if ((ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE) == 0) {
2741 			continue;
2742 		}
2743 //#ifndef CONTEXT_THREADED_JIT
2744 		if (ssa->cfg.blocks[b].flags & ZEND_BB_ENTRY) {
2745 			if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) {
2746 				/* pass */
2747 			} else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
2748 			           ssa->cfg.blocks[b].len == 1 &&
2749 			           (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT) &&
2750 			           op_array->opcodes[ssa->cfg.blocks[b].start].opcode != ZEND_JMP) {
2751 				/* don't generate code for BB with single opcode */
2752 				continue;
2753 			}
2754 			if (ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW) {
2755 				if (!is_terminated) {
2756 					zend_jit_jmp(&dasm_state, b);
2757 				}
2758 			}
2759 			zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
2760 			zend_jit_prologue(&dasm_state);
2761 		} else
2762 //#endif
2763 		if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) {
2764 			opline = op_array->opcodes + ssa->cfg.blocks[b].start;
2765 			if (ssa->cfg.flags & ZEND_CFG_RECV_ENTRY) {
2766 				if (opline->opcode == ZEND_RECV_INIT) {
2767 					if (opline == op_array->opcodes ||
2768 					    (opline-1)->opcode != ZEND_RECV_INIT) {
2769 						if (recv_emitted) {
2770 							zend_jit_jmp(&dasm_state, b);
2771 						}
2772 						zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
2773 						for (i = 1; (opline+i)->opcode == ZEND_RECV_INIT; i++) {
2774 							zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b + i);
2775 						}
2776 						zend_jit_prologue(&dasm_state);
2777 					}
2778 					recv_emitted = 1;
2779 				} else if (opline->opcode == ZEND_RECV) {
2780 					if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2781 						/* skip */
2782 						continue;
2783 					} else if (recv_emitted) {
2784 						zend_jit_jmp(&dasm_state, b);
2785 						zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
2786 						zend_jit_prologue(&dasm_state);
2787 					} else {
2788 						zend_arg_info *arg_info;
2789 
2790 						if (opline->op1.num <= op_array->num_args) {
2791 							arg_info = &op_array->arg_info[opline->op1.num - 1];
2792 						} else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
2793 							arg_info = &op_array->arg_info[op_array->num_args];
2794 						} else {
2795 							/* skip */
2796 							continue;
2797 						}
2798 						if (!ZEND_TYPE_IS_SET(arg_info->type)) {
2799 							/* skip */
2800 							continue;
2801 						}
2802 						zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
2803 						zend_jit_prologue(&dasm_state);
2804 						recv_emitted = 1;
2805 					}
2806 				} else {
2807 					if (recv_emitted) {
2808 						zend_jit_jmp(&dasm_state, b);
2809 					} else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
2810 					           ssa->cfg.blocks[b].len == 1 &&
2811 					           (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
2812 						/* don't generate code for BB with single opcode */
2813 						dasm_free(&dasm_state);
2814 
2815 						if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
2816 							zend_arena_release(&CG(arena), checkpoint);
2817 						}
2818 						return SUCCESS;
2819 					}
2820 					zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
2821 					zend_jit_prologue(&dasm_state);
2822 					recv_emitted = 1;
2823 				}
2824 			} else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
2825 			           ssa->cfg.blocks[b].len == 1 &&
2826 			           (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
2827 				/* don't generate code for BB with single opcode */
2828 				dasm_free(&dasm_state);
2829 
2830 				if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
2831 					zend_arena_release(&CG(arena), checkpoint);
2832 				}
2833 				return SUCCESS;
2834 			} else {
2835 				zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
2836 				zend_jit_prologue(&dasm_state);
2837 			}
2838 		}
2839 
2840 		is_terminated = 0;
2841 
2842 		zend_jit_label(&dasm_state, b);
2843 		if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
2844 			if ((ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW)
2845 			  && ssa->cfg.blocks[b].start != 0
2846 			  && (op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_NOP
2847 			   || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG
2848 			   || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING
2849 			   || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_MATCH)) {
2850 				zend_jit_reset_last_valid_opline();
2851 				if (!zend_jit_set_ip(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) {
2852 					goto jit_failure;
2853 				}
2854 			} else {
2855 				zend_jit_set_last_valid_opline(op_array->opcodes + ssa->cfg.blocks[b].start);
2856 			}
2857 		} else if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) {
2858 			zend_jit_reset_last_valid_opline();
2859 		} else if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY|ZEND_BB_ENTRY)) {
2860 			zend_jit_set_last_valid_opline(op_array->opcodes + ssa->cfg.blocks[b].start);
2861 		}
2862 		if (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) {
2863 			if (!zend_jit_check_timeout(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start, NULL)) {
2864 				goto jit_failure;
2865 			}
2866 		}
2867 		if (!ssa->cfg.blocks[b].len) {
2868 			continue;
2869 		}
2870 		if ((JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) && ra) {
2871 			zend_ssa_phi *phi = ssa->blocks[b].phis;
2872 
2873 			while (phi) {
2874 				zend_lifetime_interval *ival = ra[phi->ssa_var];
2875 
2876 				if (ival) {
2877 					if (ival->flags & ZREG_LOAD) {
2878 						ZEND_ASSERT(ival->reg != ZREG_NONE);
2879 
2880 						if (!zend_jit_load_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg)) {
2881 							goto jit_failure;
2882 						}
2883 					} else if (ival->flags & ZREG_STORE) {
2884 						ZEND_ASSERT(ival->reg != ZREG_NONE);
2885 
2886 						if (!zend_jit_store_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg, 1)) {
2887 							goto jit_failure;
2888 						}
2889 					}
2890 				}
2891 				phi = phi->next;
2892 			}
2893 		}
2894 		end = ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1;
2895 		for (i = ssa->cfg.blocks[b].start; i <= end; i++) {
2896 			zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[i] : NULL;
2897 			opline = op_array->opcodes + i;
2898 			switch (opline->opcode) {
2899 				case ZEND_INIT_FCALL:
2900 				case ZEND_INIT_FCALL_BY_NAME:
2901 				case ZEND_INIT_NS_FCALL_BY_NAME:
2902 				case ZEND_INIT_METHOD_CALL:
2903 				case ZEND_INIT_DYNAMIC_CALL:
2904 				case ZEND_INIT_STATIC_METHOD_CALL:
2905 				case ZEND_INIT_USER_CALL:
2906 				case ZEND_NEW:
2907 					call_level++;
2908 			}
2909 
2910 			if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
2911 				switch (opline->opcode) {
2912 					case ZEND_PRE_INC:
2913 					case ZEND_PRE_DEC:
2914 					case ZEND_POST_INC:
2915 					case ZEND_POST_DEC:
2916 						if (opline->op1_type != IS_CV) {
2917 							break;
2918 						}
2919 						op1_info = OP1_INFO();
2920 						if (!(op1_info & MAY_BE_LONG)) {
2921 							break;
2922 						}
2923 						if (opline->result_type != IS_UNUSED) {
2924 							res_use_info = -1;
2925 
2926 							if (opline->result_type == IS_CV
2927 							 && ssa->vars
2928 							 && ssa_op->result_use >= 0
2929 							 && !ssa->vars[ssa_op->result_use].no_val) {
2930 								zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
2931 
2932 								if (Z_MODE(res_use_addr) != IS_REG
2933 								 || Z_LOAD(res_use_addr)
2934 								 || Z_STORE(res_use_addr)) {
2935 									res_use_info = RES_USE_INFO();
2936 								}
2937 							}
2938 							res_info = RES_INFO();
2939 							res_addr = RES_REG_ADDR();
2940 						} else {
2941 							res_use_info = -1;
2942 							res_info = -1;
2943 							res_addr = 0;
2944 						}
2945 						op1_def_info = OP1_DEF_INFO();
2946 						if (!zend_jit_inc_dec(&dasm_state, opline,
2947 								op1_info, OP1_REG_ADDR(),
2948 								op1_def_info, OP1_DEF_REG_ADDR(),
2949 								res_use_info, res_info,
2950 								res_addr,
2951 								(op1_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
2952 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
2953 							goto jit_failure;
2954 						}
2955 						goto done;
2956 					case ZEND_BW_OR:
2957 					case ZEND_BW_AND:
2958 					case ZEND_BW_XOR:
2959 					case ZEND_SL:
2960 					case ZEND_SR:
2961 					case ZEND_MOD:
2962 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2963 							break;
2964 						}
2965 						op1_info = OP1_INFO();
2966 						op2_info = OP2_INFO();
2967 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
2968 							break;
2969 						}
2970 						if (!(op1_info & MAY_BE_LONG)
2971 						 || !(op2_info & MAY_BE_LONG)) {
2972 							break;
2973 						}
2974 						res_addr = RES_REG_ADDR();
2975 						if (Z_MODE(res_addr) != IS_REG
2976 						 && (i + 1) <= end
2977 						 && zend_jit_next_is_send_result(opline)) {
2978 							i++;
2979 							res_use_info = -1;
2980 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
2981 							if (!zend_jit_reuse_ip(&dasm_state)) {
2982 								goto jit_failure;
2983 							}
2984 						} else {
2985 							res_use_info = -1;
2986 
2987 							if (opline->result_type == IS_CV
2988 							 && ssa->vars
2989 							 && ssa_op->result_use >= 0
2990 							 && !ssa->vars[ssa_op->result_use].no_val) {
2991 								zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
2992 
2993 								if (Z_MODE(res_use_addr) != IS_REG
2994 								 || Z_LOAD(res_use_addr)
2995 								 || Z_STORE(res_use_addr)) {
2996 									res_use_info = RES_USE_INFO();
2997 								}
2998 							}
2999 						}
3000 						if (!zend_jit_long_math(&dasm_state, opline,
3001 								op1_info, OP1_RANGE(), OP1_REG_ADDR(),
3002 								op2_info, OP2_RANGE(), OP2_REG_ADDR(),
3003 								res_use_info, RES_INFO(), res_addr,
3004 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3005 							goto jit_failure;
3006 						}
3007 						goto done;
3008 					case ZEND_ADD:
3009 					case ZEND_SUB:
3010 					case ZEND_MUL:
3011 //					case ZEND_DIV: // TODO: check for division by zero ???
3012 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3013 							break;
3014 						}
3015 						op1_info = OP1_INFO();
3016 						op2_info = OP2_INFO();
3017 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
3018 							break;
3019 						}
3020 						if (opline->opcode == ZEND_ADD &&
3021 						    (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
3022 						    (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
3023 							/* pass */
3024 						} else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
3025 						    !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
3026 							break;
3027 						}
3028 						res_addr = RES_REG_ADDR();
3029 						if (Z_MODE(res_addr) != IS_REG
3030 						 && (i + 1) <= end
3031 						 && zend_jit_next_is_send_result(opline)) {
3032 							i++;
3033 							res_use_info = -1;
3034 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
3035 							if (!zend_jit_reuse_ip(&dasm_state)) {
3036 								goto jit_failure;
3037 							}
3038 						} else {
3039 							res_use_info = -1;
3040 
3041 							if (opline->result_type == IS_CV
3042 							 && ssa->vars
3043 							 && ssa_op->result_use >= 0
3044 							 && !ssa->vars[ssa_op->result_use].no_val) {
3045 								zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
3046 
3047 								if (Z_MODE(res_use_addr) != IS_REG
3048 								 || Z_LOAD(res_use_addr)
3049 								 || Z_STORE(res_use_addr)) {
3050 									res_use_info = RES_USE_INFO();
3051 								}
3052 							}
3053 						}
3054 						res_info = RES_INFO();
3055 						if (opline->opcode == ZEND_ADD &&
3056 						    (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
3057 						    (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
3058 							if (!zend_jit_add_arrays(&dasm_state, opline, op1_info, OP1_REG_ADDR(), op2_info, OP2_REG_ADDR(), res_addr)) {
3059 								goto jit_failure;
3060 							}
3061 						} else {
3062 							if (!zend_jit_math(&dasm_state, opline,
3063 									op1_info, OP1_REG_ADDR(),
3064 									op2_info, OP2_REG_ADDR(),
3065 									res_use_info, res_info, res_addr,
3066 									(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
3067 									zend_may_throw(opline, ssa_op, op_array, ssa))) {
3068 								goto jit_failure;
3069 							}
3070 						}
3071 						goto done;
3072 					case ZEND_CONCAT:
3073 					case ZEND_FAST_CONCAT:
3074 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3075 							break;
3076 						}
3077 						op1_info = OP1_INFO();
3078 						op2_info = OP2_INFO();
3079 						if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
3080 							break;
3081 						}
3082 						if (!(op1_info & MAY_BE_STRING) ||
3083 						    !(op2_info & MAY_BE_STRING)) {
3084 							break;
3085 						}
3086 						res_addr = RES_REG_ADDR();
3087 						if ((i + 1) <= end
3088 						 && zend_jit_next_is_send_result(opline)) {
3089 							i++;
3090 							res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
3091 							if (!zend_jit_reuse_ip(&dasm_state)) {
3092 								goto jit_failure;
3093 							}
3094 						}
3095 						if (!zend_jit_concat(&dasm_state, opline,
3096 								op1_info, op2_info, res_addr,
3097 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3098 							goto jit_failure;
3099 						}
3100 						goto done;
3101 					case ZEND_ASSIGN_OP:
3102 						if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
3103 							break;
3104 						}
3105 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3106 							break;
3107 						}
3108 						op1_info = OP1_INFO();
3109 						op2_info = OP2_INFO();
3110 						if (!zend_jit_supported_binary_op(
3111 								opline->extended_value, op1_info, op2_info)) {
3112 							break;
3113 						}
3114 						op1_def_info = OP1_DEF_INFO();
3115 						if (!zend_jit_assign_op(&dasm_state, opline,
3116 								op1_info, op1_def_info, OP1_RANGE(),
3117 								op2_info, OP2_RANGE(),
3118 								(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),
3119 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3120 							goto jit_failure;
3121 						}
3122 						goto done;
3123 					case ZEND_ASSIGN_DIM_OP:
3124 						if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
3125 							break;
3126 						}
3127 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3128 							break;
3129 						}
3130 						if (!zend_jit_supported_binary_op(
3131 								opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
3132 							break;
3133 						}
3134 						if (!zend_jit_assign_dim_op(&dasm_state, opline,
3135 								OP1_INFO(), OP1_DEF_INFO(), OP1_REG_ADDR(), OP2_INFO(),
3136 								OP1_DATA_INFO(), OP1_DATA_RANGE(), IS_UNKNOWN,
3137 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3138 							goto jit_failure;
3139 						}
3140 						goto done;
3141 					case ZEND_ASSIGN_DIM:
3142 						if (opline->op1_type != IS_CV) {
3143 							break;
3144 						}
3145 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3146 							break;
3147 						}
3148 						if (!zend_jit_assign_dim(&dasm_state, opline,
3149 								OP1_INFO(), OP1_REG_ADDR(), OP2_INFO(), OP1_DATA_INFO(), IS_UNKNOWN,
3150 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3151 							goto jit_failure;
3152 						}
3153 						goto done;
3154 					case ZEND_PRE_INC_OBJ:
3155 					case ZEND_PRE_DEC_OBJ:
3156 					case ZEND_POST_INC_OBJ:
3157 					case ZEND_POST_DEC_OBJ:
3158 						if (opline->op2_type != IS_CONST
3159 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3160 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3161 							break;
3162 						}
3163 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3164 							break;
3165 						}
3166 						ce = NULL;
3167 						ce_is_instanceof = 0;
3168 						on_this = 0;
3169 						if (opline->op1_type == IS_UNUSED) {
3170 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
3171 							ce = op_array->scope;
3172 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
3173 							op1_addr = 0;
3174 							on_this = 1;
3175 						} else {
3176 							op1_info = OP1_INFO();
3177 							if (!(op1_info & MAY_BE_OBJECT)) {
3178 								break;
3179 							}
3180 							op1_addr = OP1_REG_ADDR();
3181 							if (ssa->var_info && ssa->ops) {
3182 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
3183 								if (ssa_op->op1_use >= 0) {
3184 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
3185 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
3186 										ce = op1_ssa->ce;
3187 										ce_is_instanceof = op1_ssa->is_instanceof;
3188 									}
3189 								}
3190 							}
3191 						}
3192 						if (!zend_jit_incdec_obj(&dasm_state, opline, op_array, ssa, ssa_op,
3193 								op1_info, op1_addr,
3194 								0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
3195 							goto jit_failure;
3196 						}
3197 						goto done;
3198 					case ZEND_ASSIGN_OBJ_OP:
3199 						if (opline->result_type != IS_UNUSED) {
3200 							break;
3201 						}
3202 						if (opline->op2_type != IS_CONST
3203 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3204 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3205 							break;
3206 						}
3207 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3208 							break;
3209 						}
3210 						if (!zend_jit_supported_binary_op(
3211 								opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
3212 							break;
3213 						}
3214 						ce = NULL;
3215 						ce_is_instanceof = 0;
3216 						on_this = 0;
3217 						if (opline->op1_type == IS_UNUSED) {
3218 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
3219 							ce = op_array->scope;
3220 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
3221 							op1_addr = 0;
3222 							on_this = 1;
3223 						} else {
3224 							op1_info = OP1_INFO();
3225 							if (!(op1_info & MAY_BE_OBJECT)) {
3226 								break;
3227 							}
3228 							op1_addr = OP1_REG_ADDR();
3229 							if (ssa->var_info && ssa->ops) {
3230 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
3231 								if (ssa_op->op1_use >= 0) {
3232 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
3233 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
3234 										ce = op1_ssa->ce;
3235 										ce_is_instanceof = op1_ssa->is_instanceof;
3236 									}
3237 								}
3238 							}
3239 						}
3240 						if (!zend_jit_assign_obj_op(&dasm_state, opline, op_array, ssa, ssa_op,
3241 								op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_RANGE(),
3242 								0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
3243 							goto jit_failure;
3244 						}
3245 						goto done;
3246 					case ZEND_ASSIGN_OBJ:
3247 						if (opline->op2_type != IS_CONST
3248 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3249 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3250 							break;
3251 						}
3252 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3253 							break;
3254 						}
3255 						ce = NULL;
3256 						ce_is_instanceof = 0;
3257 						on_this = 0;
3258 						if (opline->op1_type == IS_UNUSED) {
3259 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
3260 							ce = op_array->scope;
3261 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
3262 							op1_addr = 0;
3263 							on_this = 1;
3264 						} else {
3265 							op1_info = OP1_INFO();
3266 							if (!(op1_info & MAY_BE_OBJECT)) {
3267 								break;
3268 							}
3269 							op1_addr = OP1_REG_ADDR();
3270 							if (ssa->var_info && ssa->ops) {
3271 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
3272 								if (ssa_op->op1_use >= 0) {
3273 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
3274 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
3275 										ce = op1_ssa->ce;
3276 										ce_is_instanceof = op1_ssa->is_instanceof;
3277 									}
3278 								}
3279 							}
3280 						}
3281 						if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
3282 								op1_info, op1_addr, OP1_DATA_INFO(),
3283 								0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN,
3284 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3285 							goto jit_failure;
3286 						}
3287 						goto done;
3288 					case ZEND_ASSIGN:
3289 						if (opline->op1_type != IS_CV) {
3290 							break;
3291 						}
3292 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3293 							break;
3294 						}
3295 						op2_addr = OP2_REG_ADDR();
3296 						if (ra
3297 						 && ssa->ops[opline - op_array->opcodes].op2_def >= 0
3298 						 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op2_def].no_val) {
3299 							op2_def_addr = OP2_DEF_REG_ADDR();
3300 						} else {
3301 							op2_def_addr = op2_addr;
3302 						}
3303 						op1_info = OP1_INFO();
3304 						if (ra && ssa->vars[ssa_op->op1_use].no_val) {
3305 							op1_info |= MAY_BE_UNDEF; // requres type assignment
3306 						}
3307 						if (opline->result_type == IS_UNUSED) {
3308 							res_addr = 0;
3309 							res_info = -1;
3310 						} else {
3311 							res_addr = RES_REG_ADDR();
3312 							res_info = RES_INFO();
3313 							if (Z_MODE(res_addr) != IS_REG
3314 							 && (i + 1) <= end
3315 							 && zend_jit_next_is_send_result(opline)
3316 							 && (!(op1_info & MAY_HAVE_DTOR) || !(op1_info & MAY_BE_RC1))) {
3317 								i++;
3318 								res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
3319 								if (!zend_jit_reuse_ip(&dasm_state)) {
3320 									goto jit_failure;
3321 								}
3322 							}
3323 						}
3324 						if (!zend_jit_assign(&dasm_state, opline,
3325 								op1_info, OP1_REG_ADDR(),
3326 								OP1_DEF_INFO(), OP1_DEF_REG_ADDR(),
3327 								OP2_INFO(), op2_addr, op2_def_addr,
3328 								res_info, res_addr,
3329 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3330 							goto jit_failure;
3331 						}
3332 						goto done;
3333 					case ZEND_QM_ASSIGN:
3334 						op1_addr = OP1_REG_ADDR();
3335 						if (ra
3336 						 && ssa->ops[opline - op_array->opcodes].op1_def >= 0
3337 						 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
3338 							op1_def_addr = OP1_DEF_REG_ADDR();
3339 						} else {
3340 							op1_def_addr = op1_addr;
3341 						}
3342 						if (!zend_jit_qm_assign(&dasm_state, opline,
3343 								OP1_INFO(), op1_addr, op1_def_addr,
3344 								-1, RES_INFO(), RES_REG_ADDR())) {
3345 							goto jit_failure;
3346 						}
3347 						goto done;
3348 					case ZEND_INIT_FCALL:
3349 					case ZEND_INIT_FCALL_BY_NAME:
3350 					case ZEND_INIT_NS_FCALL_BY_NAME:
3351 						if (!zend_jit_init_fcall(&dasm_state, opline, b, op_array, ssa, ssa_op, call_level, NULL, 0)) {
3352 							goto jit_failure;
3353 						}
3354 						goto done;
3355 					case ZEND_SEND_VAL:
3356 					case ZEND_SEND_VAL_EX:
3357 						if (opline->op2_type == IS_CONST) {
3358 							/* Named parameters not supported in JIT (yet) */
3359 							break;
3360 						}
3361 						if (opline->opcode == ZEND_SEND_VAL_EX
3362 						 && opline->op2.num > MAX_ARG_FLAG_NUM) {
3363 							break;
3364 						}
3365 						if (!zend_jit_send_val(&dasm_state, opline,
3366 								OP1_INFO(), OP1_REG_ADDR())) {
3367 							goto jit_failure;
3368 						}
3369 						goto done;
3370 					case ZEND_SEND_REF:
3371 						if (opline->op2_type == IS_CONST) {
3372 							/* Named parameters not supported in JIT (yet) */
3373 							break;
3374 						}
3375 						if (!zend_jit_send_ref(&dasm_state, opline, op_array,
3376 								OP1_INFO(), 0)) {
3377 							goto jit_failure;
3378 						}
3379 						goto done;
3380 					case ZEND_SEND_VAR:
3381 					case ZEND_SEND_VAR_EX:
3382 					case ZEND_SEND_VAR_NO_REF:
3383 					case ZEND_SEND_VAR_NO_REF_EX:
3384 					case ZEND_SEND_FUNC_ARG:
3385 						if (opline->op2_type == IS_CONST) {
3386 							/* Named parameters not supported in JIT (yet) */
3387 							break;
3388 						}
3389 						if ((opline->opcode == ZEND_SEND_VAR_EX
3390 						  || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
3391 						 && opline->op2.num > MAX_ARG_FLAG_NUM) {
3392 							break;
3393 						}
3394 						op1_addr = OP1_REG_ADDR();
3395 						if (ra
3396 						 && ssa->ops[opline - op_array->opcodes].op1_def >= 0
3397 						 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
3398 							op1_def_addr = OP1_DEF_REG_ADDR();
3399 						} else {
3400 							op1_def_addr = op1_addr;
3401 						}
3402 						if (!zend_jit_send_var(&dasm_state, opline, op_array,
3403 								OP1_INFO(), op1_addr, op1_def_addr)) {
3404 							goto jit_failure;
3405 						}
3406 						goto done;
3407 					case ZEND_CHECK_FUNC_ARG:
3408 						if (opline->op2_type == IS_CONST) {
3409 							/* Named parameters not supported in JIT (yet) */
3410 							break;
3411 						}
3412 						if (opline->op2.num > MAX_ARG_FLAG_NUM) {
3413 							break;
3414 						}
3415 						if (!zend_jit_check_func_arg(&dasm_state, opline)) {
3416 							goto jit_failure;
3417 						}
3418 						goto done;
3419 					case ZEND_CHECK_UNDEF_ARGS:
3420 						if (!zend_jit_check_undef_args(&dasm_state, opline)) {
3421 							goto jit_failure;
3422 						}
3423 						goto done;
3424 					case ZEND_DO_UCALL:
3425 						is_terminated = 1;
3426 						ZEND_FALLTHROUGH;
3427 					case ZEND_DO_ICALL:
3428 					case ZEND_DO_FCALL_BY_NAME:
3429 					case ZEND_DO_FCALL:
3430 						if (!zend_jit_do_fcall(&dasm_state, opline, op_array, ssa, call_level, b + 1, NULL)) {
3431 							goto jit_failure;
3432 						}
3433 						goto done;
3434 					case ZEND_IS_EQUAL:
3435 					case ZEND_IS_NOT_EQUAL:
3436 					case ZEND_IS_SMALLER:
3437 					case ZEND_IS_SMALLER_OR_EQUAL:
3438 					case ZEND_CASE: {
3439 						res_addr = RES_REG_ADDR();
3440 						if ((opline->result_type & IS_TMP_VAR)
3441 						 && (i + 1) <= end
3442 						 && ((opline+1)->opcode == ZEND_JMPZ
3443 						  || (opline+1)->opcode == ZEND_JMPNZ
3444 						  || (opline+1)->opcode == ZEND_JMPZ_EX
3445 						  || (opline+1)->opcode == ZEND_JMPNZ_EX)
3446 						 && (opline+1)->op1_type == IS_TMP_VAR
3447 						 && (opline+1)->op1.var == opline->result.var) {
3448 							i++;
3449 							smart_branch_opcode = (opline+1)->opcode;
3450 							target_label = ssa->cfg.blocks[b].successors[0];
3451 							target_label2 = ssa->cfg.blocks[b].successors[1];
3452 							/* For EX variant write into the result of EX opcode. */
3453 							if ((opline+1)->opcode == ZEND_JMPZ_EX
3454 									|| (opline+1)->opcode == ZEND_JMPNZ_EX) {
3455 								res_addr = OP_REG_ADDR(opline + 1, result_type, result, result_def);
3456 							}
3457 						} else {
3458 							smart_branch_opcode = 0;
3459 							target_label = target_label2 = (uint32_t)-1;
3460 						}
3461 						if (!zend_jit_cmp(&dasm_state, opline,
3462 								OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
3463 								OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
3464 								res_addr,
3465 								zend_may_throw(opline, ssa_op, op_array, ssa),
3466 								smart_branch_opcode, target_label, target_label2,
3467 								NULL, 0)) {
3468 							goto jit_failure;
3469 						}
3470 						goto done;
3471 					}
3472 					case ZEND_IS_IDENTICAL:
3473 					case ZEND_IS_NOT_IDENTICAL:
3474 					case ZEND_CASE_STRICT:
3475 						if ((opline->result_type & IS_TMP_VAR)
3476 						 && (i + 1) <= end
3477 						 && ((opline+1)->opcode == ZEND_JMPZ
3478 						  || (opline+1)->opcode == ZEND_JMPNZ)
3479 						 && (opline+1)->op1_type == IS_TMP_VAR
3480 						 && (opline+1)->op1.var == opline->result.var) {
3481 							i++;
3482 							smart_branch_opcode = (opline+1)->opcode;
3483 							target_label = ssa->cfg.blocks[b].successors[0];
3484 							target_label2 = ssa->cfg.blocks[b].successors[1];
3485 						} else {
3486 							smart_branch_opcode = 0;
3487 							target_label = target_label2 = (uint32_t)-1;
3488 						}
3489 						if (!zend_jit_identical(&dasm_state, opline,
3490 								OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
3491 								OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
3492 								RES_REG_ADDR(),
3493 								zend_may_throw(opline, ssa_op, op_array, ssa),
3494 								smart_branch_opcode, target_label, target_label2,
3495 								NULL, 0)) {
3496 							goto jit_failure;
3497 						}
3498 						goto done;
3499 					case ZEND_DEFINED:
3500 						if ((opline->result_type & IS_TMP_VAR)
3501 						 && (i + 1) <= end
3502 						 && ((opline+1)->opcode == ZEND_JMPZ
3503 						  || (opline+1)->opcode == ZEND_JMPNZ)
3504 						 && (opline+1)->op1_type == IS_TMP_VAR
3505 						 && (opline+1)->op1.var == opline->result.var) {
3506 							i++;
3507 							smart_branch_opcode = (opline+1)->opcode;
3508 							target_label = ssa->cfg.blocks[b].successors[0];
3509 							target_label2 = ssa->cfg.blocks[b].successors[1];
3510 						} else {
3511 							smart_branch_opcode = 0;
3512 							target_label = target_label2 = (uint32_t)-1;
3513 						}
3514 						if (!zend_jit_defined(&dasm_state, opline, smart_branch_opcode, target_label, target_label2, NULL)) {
3515 							goto jit_failure;
3516 						}
3517 						goto done;
3518 					case ZEND_TYPE_CHECK:
3519 						if (opline->extended_value == MAY_BE_RESOURCE) {
3520 							// TODO: support for is_resource() ???
3521 							break;
3522 						}
3523 						if ((opline->result_type & IS_TMP_VAR)
3524 						 && (i + 1) <= end
3525 						 && ((opline+1)->opcode == ZEND_JMPZ
3526 						  || (opline+1)->opcode == ZEND_JMPNZ)
3527 						 && (opline+1)->op1_type == IS_TMP_VAR
3528 						 && (opline+1)->op1.var == opline->result.var) {
3529 							i++;
3530 							smart_branch_opcode = (opline+1)->opcode;
3531 							target_label = ssa->cfg.blocks[b].successors[0];
3532 							target_label2 = ssa->cfg.blocks[b].successors[1];
3533 						} else {
3534 							smart_branch_opcode = 0;
3535 							target_label = target_label2 = (uint32_t)-1;
3536 						}
3537 						if (!zend_jit_type_check(&dasm_state, opline, OP1_INFO(), smart_branch_opcode, target_label, target_label2, NULL)) {
3538 							goto jit_failure;
3539 						}
3540 						goto done;
3541 					case ZEND_RETURN:
3542 						op1_info = OP1_INFO();
3543 						if ((PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info))
3544 						 || op_array->type == ZEND_EVAL_CODE
3545 						 // TODO: support for top-level code
3546 						 || !op_array->function_name
3547 						 // TODO: support for IS_UNDEF ???
3548 						 || (op1_info & MAY_BE_UNDEF)) {
3549 							if (!zend_jit_tail_handler(&dasm_state, opline)) {
3550 								goto jit_failure;
3551 							}
3552 						} else {
3553 							int j;
3554 							bool left_frame = 0;
3555 
3556 							if (!zend_jit_return(&dasm_state, opline, op_array,
3557 									op1_info, OP1_REG_ADDR())) {
3558 								goto jit_failure;
3559 							}
3560 							if (jit_return_label >= 0) {
3561 								if (!zend_jit_jmp(&dasm_state, jit_return_label)) {
3562 									goto jit_failure;
3563 								}
3564 								goto done;
3565 							}
3566 							jit_return_label = ssa->cfg.blocks_count * 2;
3567 							if (!zend_jit_label(&dasm_state, jit_return_label)) {
3568 								goto jit_failure;
3569 							}
3570 							if (op_array->last_var > 100) {
3571 								/* To many CVs to unroll */
3572 								if (!zend_jit_free_cvs(&dasm_state)) {
3573 									goto jit_failure;
3574 								}
3575 								left_frame = 1;
3576 							}
3577 							if (!left_frame) {
3578 								for (j = 0 ; j < op_array->last_var; j++) {
3579 									uint32_t info = zend_ssa_cv_info(op_array, ssa, j);
3580 
3581 									if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
3582 										if (!left_frame) {
3583 											left_frame = 1;
3584 										    if (!zend_jit_leave_frame(&dasm_state)) {
3585 												goto jit_failure;
3586 										    }
3587 										}
3588 										if (!zend_jit_free_cv(&dasm_state, info, j)) {
3589 											goto jit_failure;
3590 										}
3591 									}
3592 								}
3593 							}
3594 							if (!zend_jit_leave_func(&dasm_state, op_array, opline, op1_info, left_frame,
3595 									NULL, NULL, (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, 1)) {
3596 								goto jit_failure;
3597 							}
3598 						}
3599 						goto done;
3600 					case ZEND_BOOL:
3601 					case ZEND_BOOL_NOT:
3602 						if (!zend_jit_bool_jmpznz(&dasm_state, opline,
3603 								OP1_INFO(), OP1_REG_ADDR(), RES_REG_ADDR(),
3604 								-1, -1,
3605 								zend_may_throw(opline, ssa_op, op_array, ssa),
3606 								opline->opcode, NULL)) {
3607 							goto jit_failure;
3608 						}
3609 						goto done;
3610 					case ZEND_JMPZ:
3611 					case ZEND_JMPNZ:
3612 						if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
3613 						    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
3614 							/* smart branch */
3615 							if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
3616 								goto jit_failure;
3617 							}
3618 							goto done;
3619 						}
3620 						ZEND_FALLTHROUGH;
3621 					case ZEND_JMPZ_EX:
3622 					case ZEND_JMPNZ_EX:
3623 						if (opline->result_type == IS_UNDEF) {
3624 							res_addr = 0;
3625 						} else {
3626 							res_addr = RES_REG_ADDR();
3627 						}
3628 						if (!zend_jit_bool_jmpznz(&dasm_state, opline,
3629 								OP1_INFO(), OP1_REG_ADDR(), res_addr,
3630 								ssa->cfg.blocks[b].successors[0], ssa->cfg.blocks[b].successors[1],
3631 								zend_may_throw(opline, ssa_op, op_array, ssa),
3632 								opline->opcode, NULL)) {
3633 							goto jit_failure;
3634 						}
3635 						goto done;
3636 					case ZEND_ISSET_ISEMPTY_CV:
3637 						if ((opline->extended_value & ZEND_ISEMPTY)) {
3638 							// TODO: support for empty() ???
3639 							break;
3640 						}
3641 						if ((opline->result_type & IS_TMP_VAR)
3642 						 && (i + 1) <= end
3643 						 && ((opline+1)->opcode == ZEND_JMPZ
3644 						  || (opline+1)->opcode == ZEND_JMPNZ)
3645 						 && (opline+1)->op1_type == IS_TMP_VAR
3646 						 && (opline+1)->op1.var == opline->result.var) {
3647 							i++;
3648 							smart_branch_opcode = (opline+1)->opcode;
3649 							target_label = ssa->cfg.blocks[b].successors[0];
3650 							target_label2 = ssa->cfg.blocks[b].successors[1];
3651 						} else {
3652 							smart_branch_opcode = 0;
3653 							target_label = target_label2 = (uint32_t)-1;
3654 						}
3655 						if (!zend_jit_isset_isempty_cv(&dasm_state, opline,
3656 								OP1_INFO(), OP1_REG_ADDR(),
3657 								smart_branch_opcode, target_label, target_label2,
3658 								NULL)) {
3659 							goto jit_failure;
3660 						}
3661 						goto done;
3662 					case ZEND_IN_ARRAY:
3663 						if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
3664 							break;
3665 						}
3666 						op1_info = OP1_INFO();
3667 						if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
3668 							break;
3669 						}
3670 						if ((opline->result_type & IS_TMP_VAR)
3671 						 && (i + 1) <= end
3672 						 && ((opline+1)->opcode == ZEND_JMPZ
3673 						  || (opline+1)->opcode == ZEND_JMPNZ)
3674 						 && (opline+1)->op1_type == IS_TMP_VAR
3675 						 && (opline+1)->op1.var == opline->result.var) {
3676 							i++;
3677 							smart_branch_opcode = (opline+1)->opcode;
3678 							target_label = ssa->cfg.blocks[b].successors[0];
3679 							target_label2 = ssa->cfg.blocks[b].successors[1];
3680 						} else {
3681 							smart_branch_opcode = 0;
3682 							target_label = target_label2 = (uint32_t)-1;
3683 						}
3684 						if (!zend_jit_in_array(&dasm_state, opline,
3685 								op1_info, OP1_REG_ADDR(),
3686 								smart_branch_opcode, target_label, target_label2,
3687 								NULL)) {
3688 							goto jit_failure;
3689 						}
3690 						goto done;
3691 					case ZEND_FETCH_DIM_R:
3692 					case ZEND_FETCH_DIM_IS:
3693 					case ZEND_FETCH_LIST_R:
3694 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3695 							break;
3696 						}
3697 						if (!zend_jit_fetch_dim_read(&dasm_state, opline, ssa, ssa_op,
3698 								OP1_INFO(), OP1_REG_ADDR(), 0,
3699 								OP2_INFO(), RES_INFO(), RES_REG_ADDR(), IS_UNKNOWN)) {
3700 							goto jit_failure;
3701 						}
3702 						goto done;
3703 					case ZEND_FETCH_DIM_W:
3704 					case ZEND_FETCH_DIM_RW:
3705 //					case ZEND_FETCH_DIM_UNSET:
3706 					case ZEND_FETCH_LIST_W:
3707 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3708 							break;
3709 						}
3710 						if (opline->op1_type != IS_CV) {
3711 							break;
3712 						}
3713 						if (!zend_jit_fetch_dim(&dasm_state, opline,
3714 								OP1_INFO(), OP1_REG_ADDR(), OP2_INFO(), RES_REG_ADDR(), IS_UNKNOWN)) {
3715 							goto jit_failure;
3716 						}
3717 						goto done;
3718 					case ZEND_ISSET_ISEMPTY_DIM_OBJ:
3719 						if ((opline->extended_value & ZEND_ISEMPTY)) {
3720 							// TODO: support for empty() ???
3721 							break;
3722 						}
3723 						if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
3724 							break;
3725 						}
3726 						if ((opline->result_type & IS_TMP_VAR)
3727 						 && (i + 1) <= end
3728 						 && ((opline+1)->opcode == ZEND_JMPZ
3729 						  || (opline+1)->opcode == ZEND_JMPNZ)
3730 						 && (opline+1)->op1_type == IS_TMP_VAR
3731 						 && (opline+1)->op1.var == opline->result.var) {
3732 							i++;
3733 							smart_branch_opcode = (opline+1)->opcode;
3734 							target_label = ssa->cfg.blocks[b].successors[0];
3735 							target_label2 = ssa->cfg.blocks[b].successors[1];
3736 						} else {
3737 							smart_branch_opcode = 0;
3738 							target_label = target_label2 = (uint32_t)-1;
3739 						}
3740 						if (!zend_jit_isset_isempty_dim(&dasm_state, opline,
3741 								OP1_INFO(), OP1_REG_ADDR(), 0,
3742 								OP2_INFO(), IS_UNKNOWN,
3743 								zend_may_throw(opline, ssa_op, op_array, ssa),
3744 								smart_branch_opcode, target_label, target_label2,
3745 								NULL)) {
3746 							goto jit_failure;
3747 						}
3748 						goto done;
3749 					case ZEND_FETCH_OBJ_R:
3750 					case ZEND_FETCH_OBJ_IS:
3751 					case ZEND_FETCH_OBJ_W:
3752 						if (opline->op2_type != IS_CONST
3753 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3754 						 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3755 							break;
3756 						}
3757 						ce = NULL;
3758 						ce_is_instanceof = 0;
3759 						on_this = 0;
3760 						if (opline->op1_type == IS_UNUSED) {
3761 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
3762 							op1_addr = 0;
3763 							ce = op_array->scope;
3764 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
3765 							on_this = 1;
3766 						} else {
3767 							op1_info = OP1_INFO();
3768 							if (!(op1_info & MAY_BE_OBJECT)) {
3769 								break;
3770 							}
3771 							op1_addr = OP1_REG_ADDR();
3772 							if (ssa->var_info && ssa->ops) {
3773 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
3774 								if (ssa_op->op1_use >= 0) {
3775 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
3776 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
3777 										ce = op1_ssa->ce;
3778 										ce_is_instanceof = op1_ssa->is_instanceof;
3779 									}
3780 								}
3781 							}
3782 						}
3783 						if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, ssa, ssa_op,
3784 								op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
3785 								IS_UNKNOWN,
3786 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3787 							goto jit_failure;
3788 						}
3789 						goto done;
3790 					case ZEND_BIND_GLOBAL:
3791 						if (!ssa->ops || !ssa->var_info) {
3792 							op1_info = MAY_BE_ANY|MAY_BE_REF;
3793 						} else {
3794 							op1_info = OP1_INFO();
3795 						}
3796 						if (!zend_jit_bind_global(&dasm_state, opline, op1_info)) {
3797 							goto jit_failure;
3798 						}
3799 						goto done;
3800 					case ZEND_RECV:
3801 						if (!zend_jit_recv(&dasm_state, opline, op_array)) {
3802 							goto jit_failure;
3803 						}
3804 						goto done;
3805 					case ZEND_RECV_INIT:
3806 						if (!zend_jit_recv_init(&dasm_state, opline, op_array,
3807 								(opline + 1)->opcode != ZEND_RECV_INIT,
3808 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3809 							goto jit_failure;
3810 						}
3811 						goto done;
3812 					case ZEND_FREE:
3813 					case ZEND_FE_FREE:
3814 						if (!zend_jit_free(&dasm_state, opline, OP1_INFO(),
3815 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3816 							goto jit_failure;
3817 						}
3818 						goto done;
3819 					case ZEND_ECHO:
3820 						op1_info = OP1_INFO();
3821 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
3822 							break;
3823 						}
3824 						if (!zend_jit_echo(&dasm_state, opline, op1_info)) {
3825 							goto jit_failure;
3826 						}
3827 						goto done;
3828 					case ZEND_STRLEN:
3829 						op1_info = OP1_INFO();
3830 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
3831 							break;
3832 						}
3833 						if (!zend_jit_strlen(&dasm_state, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR())) {
3834 							goto jit_failure;
3835 						}
3836 						goto done;
3837 					case ZEND_COUNT:
3838 						op1_info = OP1_INFO();
3839 						if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
3840 							break;
3841 						}
3842 						if (!zend_jit_count(&dasm_state, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
3843 							goto jit_failure;
3844 						}
3845 						goto done;
3846 					case ZEND_FETCH_THIS:
3847 						if (!zend_jit_fetch_this(&dasm_state, opline, op_array, 0)) {
3848 							goto jit_failure;
3849 						}
3850 						goto done;
3851 					case ZEND_SWITCH_LONG:
3852 					case ZEND_SWITCH_STRING:
3853 					case ZEND_MATCH:
3854 						if (!zend_jit_switch(&dasm_state, opline, op_array, ssa, NULL, NULL)) {
3855 							goto jit_failure;
3856 						}
3857 						goto done;
3858 					case ZEND_VERIFY_RETURN_TYPE:
3859 						if (opline->op1_type == IS_UNUSED) {
3860 							/* Always throws */
3861 							break;
3862 						}
3863 						if (opline->op1_type == IS_CONST) {
3864 							/* TODO Different instruction format, has return value */
3865 							break;
3866 						}
3867 						if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
3868 							/* Not worth bothering with */
3869 							break;
3870 						}
3871 						if (OP1_INFO() & MAY_BE_REF) {
3872 							/* TODO May need reference unwrapping. */
3873 							break;
3874 						}
3875 						if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, OP1_INFO())) {
3876 							goto jit_failure;
3877 						}
3878 						goto done;
3879 					case ZEND_FE_RESET_R:
3880 						op1_info = OP1_INFO();
3881 						if ((op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) != MAY_BE_ARRAY) {
3882 							break;
3883 						}
3884 						if (!zend_jit_fe_reset(&dasm_state, opline, op1_info)) {
3885 							goto jit_failure;
3886 						}
3887 						goto done;
3888 					case ZEND_FE_FETCH_R:
3889 						op1_info = OP1_INFO();
3890 						if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
3891 							break;
3892 						}
3893 						if (!zend_jit_fe_fetch(&dasm_state, opline, op1_info, OP2_INFO(),
3894 								ssa->cfg.blocks[b].successors[0], opline->opcode, NULL)) {
3895 							goto jit_failure;
3896 						}
3897 						goto done;
3898 					case ZEND_FETCH_CONSTANT:
3899 						if (!zend_jit_fetch_constant(&dasm_state, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
3900 							goto jit_failure;
3901 						}
3902 						goto done;
3903 					case ZEND_INIT_METHOD_CALL:
3904 						if (opline->op2_type != IS_CONST
3905 						 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
3906 							break;
3907 						}
3908 						ce = NULL;
3909 						ce_is_instanceof = 0;
3910 						on_this = 0;
3911 						if (opline->op1_type == IS_UNUSED) {
3912 							op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
3913 							op1_addr = 0;
3914 							ce = op_array->scope;
3915 							ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
3916 							on_this = 1;
3917 						} else {
3918 							op1_info = OP1_INFO();
3919 							if (!(op1_info & MAY_BE_OBJECT)) {
3920 								break;
3921 							}
3922 							op1_addr = OP1_REG_ADDR();
3923 							if (ssa->var_info && ssa->ops) {
3924 								zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
3925 								if (ssa_op->op1_use >= 0) {
3926 									zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
3927 									if (op1_ssa->ce && !op1_ssa->ce->create_object) {
3928 										ce = op1_ssa->ce;
3929 										ce_is_instanceof = op1_ssa->is_instanceof;
3930 									}
3931 								}
3932 							}
3933 						}
3934 						if (!zend_jit_init_method_call(&dasm_state, opline, b, op_array, ssa, ssa_op, call_level,
3935 								op1_info, op1_addr, ce, ce_is_instanceof, on_this, 0, NULL,
3936 								NULL, 0, 0)) {
3937 							goto jit_failure;
3938 						}
3939 						goto done;
3940 					case ZEND_ROPE_INIT:
3941 					case ZEND_ROPE_ADD:
3942 					case ZEND_ROPE_END:
3943 						op2_info = OP2_INFO();
3944 						if ((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
3945 							break;
3946 						}
3947 						if (!zend_jit_rope(&dasm_state, opline, op2_info)) {
3948 							goto jit_failure;
3949 						}
3950 						goto done;
3951 					default:
3952 						break;
3953 				}
3954 			}
3955 
3956 			switch (opline->opcode) {
3957 				case ZEND_RECV_INIT:
3958 				case ZEND_BIND_GLOBAL:
3959 					if (opline == op_array->opcodes ||
3960 					    opline->opcode != op_array->opcodes[i-1].opcode) {
3961 						/* repeatable opcodes */
3962 						if (!zend_jit_handler(&dasm_state, opline,
3963 								zend_may_throw(opline, ssa_op, op_array, ssa))) {
3964 							goto jit_failure;
3965 						}
3966 					}
3967 					zend_jit_set_last_valid_opline(opline+1);
3968 					break;
3969 				case ZEND_NOP:
3970 				case ZEND_OP_DATA:
3971 				case ZEND_SWITCH_LONG:
3972 				case ZEND_SWITCH_STRING:
3973 					break;
3974 				case ZEND_MATCH:
3975 					/* We have to exit to the VM because the MATCH handler performs an N-way jump for
3976 					 * which we can't generate simple (opcache.jit=1201) JIT code. */
3977 					if (!zend_jit_tail_handler(&dasm_state, opline)) {
3978 						goto jit_failure;
3979 					}
3980 					break;
3981 				case ZEND_JMP:
3982 					if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
3983 						const zend_op *target = OP_JMP_ADDR(opline, opline->op1);
3984 
3985 						if (!zend_jit_set_ip(&dasm_state, target)) {
3986 							goto jit_failure;
3987 						}
3988 					}
3989 					if (!zend_jit_jmp(&dasm_state, ssa->cfg.blocks[b].successors[0])) {
3990 						goto jit_failure;
3991 					}
3992 					is_terminated = 1;
3993 					break;
3994 				case ZEND_CATCH:
3995 				case ZEND_FAST_CALL:
3996 				case ZEND_FAST_RET:
3997 				case ZEND_GENERATOR_CREATE:
3998 				case ZEND_GENERATOR_RETURN:
3999 				case ZEND_RETURN_BY_REF:
4000 				case ZEND_RETURN:
4001 				case ZEND_EXIT:
4002 				case ZEND_MATCH_ERROR:
4003 				/* switch through trampoline */
4004 				case ZEND_YIELD:
4005 				case ZEND_YIELD_FROM:
4006 					if (!zend_jit_tail_handler(&dasm_state, opline)) {
4007 						goto jit_failure;
4008 					}
4009 					is_terminated = 1;
4010 					break;
4011 				/* stackless execution */
4012 				case ZEND_INCLUDE_OR_EVAL:
4013 				case ZEND_DO_FCALL:
4014 				case ZEND_DO_UCALL:
4015 				case ZEND_DO_FCALL_BY_NAME:
4016 					if (!zend_jit_call(&dasm_state, opline, b + 1)) {
4017 						goto jit_failure;
4018 					}
4019 					is_terminated = 1;
4020 					break;
4021 				case ZEND_JMPZ:
4022 				case ZEND_JMPNZ:
4023 					if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
4024 					    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
4025 						/* smart branch */
4026 						if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
4027 							goto jit_failure;
4028 						}
4029 						goto done;
4030 					}
4031 					ZEND_FALLTHROUGH;
4032 				case ZEND_JMPZ_EX:
4033 				case ZEND_JMPNZ_EX:
4034 				case ZEND_JMP_SET:
4035 				case ZEND_COALESCE:
4036 				case ZEND_JMP_NULL:
4037 				case ZEND_FE_RESET_R:
4038 				case ZEND_FE_RESET_RW:
4039 				case ZEND_ASSERT_CHECK:
4040 				case ZEND_FE_FETCH_R:
4041 				case ZEND_FE_FETCH_RW:
4042 					if (!zend_jit_handler(&dasm_state, opline,
4043 							zend_may_throw(opline, ssa_op, op_array, ssa)) ||
4044 					    !zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
4045 						goto jit_failure;
4046 					}
4047 					break;
4048 				case ZEND_NEW:
4049 					if (!zend_jit_handler(&dasm_state, opline, 1)) {
4050 						return 0;
4051 					}
4052 					if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
4053 						zend_class_entry *ce = NULL;
4054 
4055 						if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) {
4056 							if (ssa->ops && ssa->var_info) {
4057 								zend_ssa_var_info *res_ssa = &ssa->var_info[ssa->ops[opline - op_array->opcodes].result_def];
4058 								if (res_ssa->ce && !res_ssa->is_instanceof) {
4059 									ce = res_ssa->ce;
4060 								}
4061 							}
4062 						} else {
4063 							if (opline->op1_type == IS_CONST) {
4064 								zval *zv = RT_CONSTANT(opline, opline->op1);
4065 								if (Z_TYPE_P(zv) == IS_STRING) {
4066 									zval *lc = zv + 1;
4067 									ce = (zend_class_entry*)zend_hash_find_ptr(EG(class_table), Z_STR_P(lc));
4068 								}
4069 							}
4070 						}
4071 
4072 						i++;
4073 
4074 						if (!ce || !(ce->ce_flags & ZEND_ACC_LINKED) || ce->constructor) {
4075 							const zend_op *next_opline = opline + 1;
4076 
4077 							zend_jit_cond_jmp(&dasm_state, next_opline, ssa->cfg.blocks[b].successors[0]);
4078 							if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
4079 								zend_jit_call(&dasm_state, next_opline, b + 1);
4080 								is_terminated = 1;
4081 							} else {
4082 								zend_jit_do_fcall(&dasm_state, next_opline, op_array, ssa, call_level, b + 1, NULL);
4083 							}
4084 						}
4085 
4086 						/* We skip over the DO_FCALL, so decrement call_level ourselves. */
4087 						call_level--;
4088 					}
4089 					break;
4090 				default:
4091 					if (!zend_jit_handler(&dasm_state, opline,
4092 							zend_may_throw(opline, ssa_op, op_array, ssa))) {
4093 						goto jit_failure;
4094 					}
4095 					if (i == end
4096 					 && (opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
4097 						/* smart branch split across basic blocks */
4098 						if (!zend_jit_cond_jmp(&dasm_state, opline + 2, ssa->cfg.blocks[b+1].successors[0])) {
4099 							goto jit_failure;
4100 						}
4101 						if (!zend_jit_jmp(&dasm_state, ssa->cfg.blocks[b+1].successors[1])) {
4102 							goto jit_failure;
4103 						}
4104 						is_terminated = 1;
4105 					}
4106 			}
4107 done:
4108 			switch (opline->opcode) {
4109 				case ZEND_DO_FCALL:
4110 				case ZEND_DO_ICALL:
4111 				case ZEND_DO_UCALL:
4112 				case ZEND_DO_FCALL_BY_NAME:
4113 				case ZEND_CALLABLE_CONVERT:
4114 					call_level--;
4115 			}
4116 		}
4117 	}
4118 
4119 	handler = dasm_link_and_encode(&dasm_state, op_array, ssa, rt_opline, ra, NULL, 0,
4120 		(zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) ? SP_ADJ_VM : SP_ADJ_RET, SP_ADJ_JIT);
4121 	if (!handler) {
4122 		goto jit_failure;
4123 	}
4124 	dasm_free(&dasm_state);
4125 
4126 	if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
4127 		zend_arena_release(&CG(arena), checkpoint);
4128 	}
4129 	return SUCCESS;
4130 
4131 jit_failure:
4132 	if (dasm_state) {
4133 		dasm_free(&dasm_state);
4134 	}
4135 	if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) {
4136 		zend_arena_release(&CG(arena), checkpoint);
4137 	}
4138 	return FAILURE;
4139 }
4140 
zend_jit_collect_calls(zend_op_array * op_array,zend_script * script)4141 static void zend_jit_collect_calls(zend_op_array *op_array, zend_script *script)
4142 {
4143 	zend_func_info *func_info;
4144 
4145 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
4146 	    JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
4147 	    JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
4148 	    func_info = ZEND_FUNC_INFO(op_array);
4149 	} else {
4150 		func_info = zend_arena_calloc(&CG(arena), 1, sizeof(zend_func_info));
4151 		ZEND_SET_FUNC_INFO(op_array, func_info);
4152 	}
4153 	zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, op_array, func_info);
4154 }
4155 
zend_jit_cleanup_func_info(zend_op_array * op_array)4156 static void zend_jit_cleanup_func_info(zend_op_array *op_array)
4157 {
4158 	zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
4159 	zend_call_info *caller_info, *callee_info;
4160 
4161 	if (func_info) {
4162 		caller_info = func_info->caller_info;
4163 		callee_info = func_info->callee_info;
4164 
4165 		if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
4166 		    JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
4167 		    JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
4168 			func_info->num = 0;
4169 			func_info->flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
4170 				| ZEND_FUNC_JIT_ON_PROF_REQUEST
4171 				| ZEND_FUNC_JIT_ON_HOT_COUNTERS
4172 				| ZEND_FUNC_JIT_ON_HOT_TRACE;
4173 			memset(&func_info->ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
4174 		} else {
4175 			ZEND_SET_FUNC_INFO(op_array, NULL);
4176 		}
4177 
4178 		while (caller_info) {
4179 			if (caller_info->caller_op_array) {
4180 				zend_jit_cleanup_func_info(caller_info->caller_op_array);
4181 			}
4182 			caller_info = caller_info->next_caller;
4183 		}
4184 		while (callee_info) {
4185 			if (callee_info->callee_func && callee_info->callee_func->type == ZEND_USER_FUNCTION) {
4186 				zend_jit_cleanup_func_info(&callee_info->callee_func->op_array);
4187 			}
4188 			callee_info = callee_info->next_callee;
4189 		}
4190 	}
4191 }
4192 
zend_real_jit_func(zend_op_array * op_array,zend_script * script,const zend_op * rt_opline)4193 static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, const zend_op *rt_opline)
4194 {
4195 	zend_ssa ssa;
4196 	void *checkpoint;
4197 	zend_func_info *func_info;
4198 
4199 	if (*dasm_ptr == dasm_end) {
4200 		return FAILURE;
4201 	}
4202 
4203 	checkpoint = zend_arena_checkpoint(CG(arena));
4204 
4205 	/* Build SSA */
4206 	memset(&ssa, 0, sizeof(zend_ssa));
4207 
4208 	if (zend_jit_op_array_analyze1(op_array, script, &ssa) != SUCCESS) {
4209 		goto jit_failure;
4210 	}
4211 
4212 	if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNCS) {
4213 		zend_jit_collect_calls(op_array, script);
4214 		func_info = ZEND_FUNC_INFO(op_array);
4215 		func_info->call_map = zend_build_call_map(&CG(arena), func_info, op_array);
4216 		if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
4217 			zend_init_func_return_info(op_array, script, &func_info->return_info);
4218 		}
4219 	}
4220 
4221 	if (zend_jit_op_array_analyze2(op_array, script, &ssa, ZCG(accel_directives).optimization_level) != SUCCESS) {
4222 		goto jit_failure;
4223 	}
4224 
4225 	if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
4226 		zend_dump_op_array(op_array, ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &ssa);
4227 	}
4228 
4229 	if (zend_jit(op_array, &ssa, rt_opline) != SUCCESS) {
4230 		goto jit_failure;
4231 	}
4232 
4233 	zend_jit_cleanup_func_info(op_array);
4234 	zend_arena_release(&CG(arena), checkpoint);
4235 	return SUCCESS;
4236 
4237 jit_failure:
4238 	zend_jit_cleanup_func_info(op_array);
4239 	zend_arena_release(&CG(arena), checkpoint);
4240 	return FAILURE;
4241 }
4242 
4243 /* Run-time JIT handler */
zend_runtime_jit(void)4244 static int ZEND_FASTCALL zend_runtime_jit(void)
4245 {
4246 	zend_execute_data *execute_data = EG(current_execute_data);
4247 	zend_op_array *op_array = &EX(func)->op_array;
4248 	zend_op *opline = op_array->opcodes;
4249 	zend_jit_op_array_extension *jit_extension;
4250 	bool do_bailout = 0;
4251 
4252 	zend_shared_alloc_lock();
4253 
4254 	if (ZEND_FUNC_INFO(op_array)) {
4255 
4256 		SHM_UNPROTECT();
4257 		zend_jit_unprotect();
4258 
4259 		zend_try {
4260 			/* restore original opcode handlers */
4261 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
4262 				while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
4263 					opline++;
4264 				}
4265 			}
4266 			jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
4267 			opline->handler = jit_extension->orig_handler;
4268 
4269 			/* perform real JIT for this function */
4270 			zend_real_jit_func(op_array, NULL, NULL);
4271 		} zend_catch {
4272 			do_bailout = true;
4273 		} zend_end_try();
4274 
4275 		zend_jit_protect();
4276 		SHM_PROTECT();
4277 	}
4278 
4279 	zend_shared_alloc_unlock();
4280 
4281 	if (do_bailout) {
4282 		zend_bailout();
4283 	}
4284 
4285 	/* JIT-ed code is going to be called by VM */
4286 	return 0;
4287 }
4288 
zend_jit_check_funcs(HashTable * function_table,bool is_method)4289 void zend_jit_check_funcs(HashTable *function_table, bool is_method) {
4290 	zend_op *opline;
4291 	zend_function *func;
4292 	zend_op_array *op_array;
4293 	uintptr_t counter;
4294 	zend_jit_op_array_extension *jit_extension;
4295 
4296 	ZEND_HASH_MAP_REVERSE_FOREACH_PTR(function_table, func) {
4297 		if (func->type == ZEND_INTERNAL_FUNCTION) {
4298 			break;
4299 		}
4300 		op_array = &func->op_array;
4301 		opline = op_array->opcodes;
4302 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
4303 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
4304 				opline++;
4305 			}
4306 		}
4307 		if (opline->handler == zend_jit_profile_jit_handler) {
4308 			if (!RUN_TIME_CACHE(op_array)) {
4309 				continue;
4310 			}
4311 			counter = (uintptr_t)ZEND_COUNTER_INFO(op_array);
4312 			ZEND_COUNTER_INFO(op_array) = 0;
4313 			jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
4314 			opline->handler = jit_extension->orig_handler;
4315 			if (((double)counter / (double)zend_jit_profile_counter) > JIT_G(prof_threshold)) {
4316 				zend_real_jit_func(op_array, NULL, NULL);
4317 			}
4318 		}
4319 	} ZEND_HASH_FOREACH_END();
4320 }
4321 
zend_jit_hot_func(zend_execute_data * execute_data,const zend_op * opline)4322 void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
4323 {
4324 	zend_op_array *op_array = &EX(func)->op_array;
4325 	zend_jit_op_array_hot_extension *jit_extension;
4326 	uint32_t i;
4327 	bool do_bailout = 0;
4328 
4329 	zend_shared_alloc_lock();
4330 	jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
4331 
4332 	if (jit_extension) {
4333 		SHM_UNPROTECT();
4334 		zend_jit_unprotect();
4335 
4336 		zend_try {
4337 			for (i = 0; i < op_array->last; i++) {
4338 				op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
4339 			}
4340 
4341 			/* perform real JIT for this function */
4342 			zend_real_jit_func(op_array, NULL, opline);
4343 		} zend_catch {
4344 			do_bailout = 1;
4345 		} zend_end_try();
4346 
4347 		zend_jit_protect();
4348 		SHM_PROTECT();
4349 	}
4350 
4351 	zend_shared_alloc_unlock();
4352 
4353 	if (do_bailout) {
4354 		zend_bailout();
4355 	}
4356 	/* JIT-ed code is going to be called by VM */
4357 }
4358 
zend_jit_setup_hot_counters_ex(zend_op_array * op_array,zend_cfg * cfg)4359 static void zend_jit_setup_hot_counters_ex(zend_op_array *op_array, zend_cfg *cfg)
4360 {
4361 	if (JIT_G(hot_func)) {
4362 		zend_op *opline = op_array->opcodes;
4363 
4364 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
4365 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
4366 				opline++;
4367 			}
4368 		}
4369 
4370 		opline->handler = (const void*)zend_jit_func_hot_counter_handler;
4371 	}
4372 
4373 	if (JIT_G(hot_loop)) {
4374 		uint32_t i;
4375 
4376 		for (i = 0; i < cfg->blocks_count; i++) {
4377 			if ((cfg->blocks[i].flags & ZEND_BB_REACHABLE) &&
4378 			    (cfg->blocks[i].flags & ZEND_BB_LOOP_HEADER)) {
4379 			    op_array->opcodes[cfg->blocks[i].start].handler =
4380 					(const void*)zend_jit_loop_hot_counter_handler;
4381 			}
4382 		}
4383 	}
4384 }
4385 
zend_jit_restart_hot_counters(zend_op_array * op_array)4386 static int zend_jit_restart_hot_counters(zend_op_array *op_array)
4387 {
4388 	zend_jit_op_array_hot_extension *jit_extension;
4389 	zend_cfg cfg;
4390 	uint32_t i;
4391 
4392 	jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
4393 	for (i = 0; i < op_array->last; i++) {
4394 		op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
4395 	}
4396 
4397 	if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
4398 		return FAILURE;
4399 	}
4400 
4401 	zend_jit_setup_hot_counters_ex(op_array, &cfg);
4402 
4403 	return SUCCESS;
4404 }
4405 
zend_jit_setup_hot_counters(zend_op_array * op_array)4406 static int zend_jit_setup_hot_counters(zend_op_array *op_array)
4407 {
4408 	zend_jit_op_array_hot_extension *jit_extension;
4409 	zend_cfg cfg;
4410 	uint32_t i;
4411 
4412 	ZEND_ASSERT(zend_jit_func_hot_counter_handler != NULL);
4413 	ZEND_ASSERT(zend_jit_loop_hot_counter_handler != NULL);
4414 
4415 	if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
4416 		return FAILURE;
4417 	}
4418 
4419 	jit_extension = (zend_jit_op_array_hot_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_hot_extension) + (op_array->last - 1) * sizeof(void*));
4420 	if (!jit_extension) {
4421 		return FAILURE;
4422 	}
4423 	memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
4424 	jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_HOT_COUNTERS;
4425 	jit_extension->counter = &zend_jit_hot_counters[zend_jit_op_array_hash(op_array) & (ZEND_HOT_COUNTERS_COUNT - 1)];
4426 	for (i = 0; i < op_array->last; i++) {
4427 		jit_extension->orig_handlers[i] = op_array->opcodes[i].handler;
4428 	}
4429 	ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
4430 
4431 	zend_jit_setup_hot_counters_ex(op_array, &cfg);
4432 
4433 	zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
4434 
4435 	return SUCCESS;
4436 }
4437 
4438 #include "jit/zend_jit_trace.c"
4439 
zend_jit_op_array(zend_op_array * op_array,zend_script * script)4440 ZEND_EXT_API int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
4441 {
4442 	if (dasm_ptr == NULL) {
4443 		return FAILURE;
4444 	}
4445 
4446 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC) {
4447 		zend_jit_op_array_extension *jit_extension;
4448 		zend_op *opline = op_array->opcodes;
4449 
4450 		if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
4451 			ZEND_SET_FUNC_INFO(op_array, NULL);
4452 			zend_error(E_WARNING, "Preloading is incompatible with first-exec and profile triggered JIT");
4453 			return SUCCESS;
4454 		}
4455 
4456 		/* Set run-time JIT handler */
4457 		ZEND_ASSERT(zend_jit_runtime_jit_handler != NULL);
4458 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
4459 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
4460 				opline++;
4461 			}
4462 		}
4463 		jit_extension = (zend_jit_op_array_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_extension));
4464 		if (!jit_extension) {
4465 			return FAILURE;
4466 		}
4467 		memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
4468 		jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_FIRST_EXEC;
4469 		jit_extension->orig_handler = (void*)opline->handler;
4470 		ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
4471 		opline->handler = (const void*)zend_jit_runtime_jit_handler;
4472 		zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
4473 
4474 		return SUCCESS;
4475 	} else if (JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST) {
4476 		zend_jit_op_array_extension *jit_extension;
4477 		zend_op *opline = op_array->opcodes;
4478 
4479 		if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
4480 			ZEND_SET_FUNC_INFO(op_array, NULL);
4481 			zend_error(E_WARNING, "Preloading is incompatible with first-exec and profile triggered JIT");
4482 			return SUCCESS;
4483 		}
4484 
4485 		ZEND_ASSERT(zend_jit_profile_jit_handler != NULL);
4486 		if (op_array->function_name) {
4487 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
4488 				while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
4489 					opline++;
4490 				}
4491 			}
4492 			jit_extension = (zend_jit_op_array_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_extension));
4493 			if (!jit_extension) {
4494 				return FAILURE;
4495 			}
4496 			memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
4497 			jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_PROF_REQUEST;
4498 			jit_extension->orig_handler = (void*)opline->handler;
4499 			ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
4500 			opline->handler = (const void*)zend_jit_profile_jit_handler;
4501 			zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
4502 		}
4503 
4504 		return SUCCESS;
4505 	} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
4506 		return zend_jit_setup_hot_counters(op_array);
4507 	} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
4508 		return zend_jit_setup_hot_trace_counters(op_array);
4509 	} else if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
4510 		return zend_real_jit_func(op_array, script, NULL);
4511 	} else {
4512 		ZEND_UNREACHABLE();
4513 	}
4514 }
4515 
zend_jit_script(zend_script * script)4516 ZEND_EXT_API int zend_jit_script(zend_script *script)
4517 {
4518 	void *checkpoint;
4519 	zend_call_graph call_graph;
4520 	zend_func_info *info;
4521 	int i;
4522 
4523 	if (dasm_ptr == NULL || *dasm_ptr == dasm_end) {
4524 		return FAILURE;
4525 	}
4526 
4527 	checkpoint = zend_arena_checkpoint(CG(arena));
4528 
4529 	call_graph.op_arrays_count = 0;
4530 	zend_build_call_graph(&CG(arena), script, &call_graph);
4531 
4532 	zend_analyze_call_graph(&CG(arena), script, &call_graph);
4533 
4534 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
4535 	    JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
4536 	    JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS ||
4537 	    JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
4538 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4539 			if (zend_jit_op_array(call_graph.op_arrays[i], script) != SUCCESS) {
4540 				goto jit_failure;
4541 			}
4542 		}
4543 	} else if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
4544 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4545 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
4546 			if (info) {
4547 				if (zend_jit_op_array_analyze1(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
4548 					goto jit_failure;
4549 				}
4550 				info->flags = info->ssa.cfg.flags;
4551 			}
4552 		}
4553 
4554 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4555 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
4556 			if (info) {
4557 				info->call_map = zend_build_call_map(&CG(arena), info, call_graph.op_arrays[i]);
4558 				if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
4559 					zend_init_func_return_info(call_graph.op_arrays[i], script, &info->return_info);
4560 				}
4561 			}
4562 		}
4563 
4564 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4565 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
4566 			if (info) {
4567 				if (zend_jit_op_array_analyze2(call_graph.op_arrays[i], script, &info->ssa, ZCG(accel_directives).optimization_level) != SUCCESS) {
4568 					goto jit_failure;
4569 				}
4570 				info->flags = info->ssa.cfg.flags;
4571 			}
4572 		}
4573 
4574 		if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
4575 			for (i = 0; i < call_graph.op_arrays_count; i++) {
4576 				info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
4577 				if (info) {
4578 					zend_dump_op_array(call_graph.op_arrays[i], ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &info->ssa);
4579 				}
4580 			}
4581 		}
4582 
4583 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4584 			info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
4585 			if (info) {
4586 				if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) {
4587 					goto jit_failure;
4588 				}
4589 			}
4590 		}
4591 
4592 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4593 			ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
4594 		}
4595 	} else {
4596 		ZEND_UNREACHABLE();
4597 	}
4598 
4599 	zend_arena_release(&CG(arena), checkpoint);
4600 
4601 	if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC
4602 	 || JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST
4603 	 || JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS
4604 	 || JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
4605 		zend_class_entry *ce;
4606 		zend_op_array *op_array;
4607 
4608 		ZEND_HASH_MAP_FOREACH_PTR(&script->class_table, ce) {
4609 			ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
4610 				if (!ZEND_FUNC_INFO(op_array)) {
4611 					void *jit_extension = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
4612 
4613 					if (jit_extension) {
4614 						ZEND_SET_FUNC_INFO(op_array, jit_extension);
4615 					}
4616 				}
4617 			} ZEND_HASH_FOREACH_END();
4618 		} ZEND_HASH_FOREACH_END();
4619 	}
4620 
4621 	return SUCCESS;
4622 
4623 jit_failure:
4624 	if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
4625 		for (i = 0; i < call_graph.op_arrays_count; i++) {
4626 			ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
4627 		}
4628 	}
4629 	zend_arena_release(&CG(arena), checkpoint);
4630 	return FAILURE;
4631 }
4632 
zend_jit_unprotect(void)4633 ZEND_EXT_API void zend_jit_unprotect(void)
4634 {
4635 #ifdef HAVE_MPROTECT
4636 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
4637 		int opts = PROT_READ | PROT_WRITE;
4638 #ifdef ZTS
4639 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
4640 		if (zend_write_protect) {
4641 			pthread_jit_write_protect_np(0);
4642 		}
4643 #endif
4644 		opts |= PROT_EXEC;
4645 #endif
4646 		if (mprotect(dasm_buf, dasm_size, opts) != 0) {
4647 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
4648 		}
4649 	}
4650 #elif _WIN32
4651 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
4652 		DWORD old, new;
4653 #ifdef ZTS
4654 		new = PAGE_EXECUTE_READWRITE;
4655 #else
4656 		new = PAGE_READWRITE;
4657 #endif
4658 		if (!VirtualProtect(dasm_buf, dasm_size, new, &old)) {
4659 			DWORD err = GetLastError();
4660 			char *msg = php_win32_error_to_msg(err);
4661 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
4662 			php_win32_error_msg_free(msg);
4663 		}
4664 	}
4665 #endif
4666 }
4667 
zend_jit_protect(void)4668 ZEND_EXT_API void zend_jit_protect(void)
4669 {
4670 #ifdef HAVE_MPROTECT
4671 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
4672 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
4673 		if (zend_write_protect) {
4674 			pthread_jit_write_protect_np(1);
4675 		}
4676 #endif
4677 		if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
4678 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
4679 		}
4680 	}
4681 #elif _WIN32
4682 	if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
4683 		DWORD old;
4684 
4685 		if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
4686 			DWORD err = GetLastError();
4687 			char *msg = php_win32_error_to_msg(err);
4688 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
4689 			php_win32_error_msg_free(msg);
4690 		}
4691 	}
4692 #endif
4693 }
4694 
zend_jit_init_handlers(void)4695 static void zend_jit_init_handlers(void)
4696 {
4697 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4698 		zend_jit_runtime_jit_handler = dasm_labels[zend_lbhybrid_runtime_jit];
4699 		zend_jit_profile_jit_handler = dasm_labels[zend_lbhybrid_profile_jit];
4700 		zend_jit_func_hot_counter_handler = dasm_labels[zend_lbhybrid_func_hot_counter];
4701 		zend_jit_loop_hot_counter_handler = dasm_labels[zend_lbhybrid_loop_hot_counter];
4702 		zend_jit_func_trace_counter_handler = dasm_labels[zend_lbhybrid_func_trace_counter];
4703 		zend_jit_ret_trace_counter_handler = dasm_labels[zend_lbhybrid_ret_trace_counter];
4704 		zend_jit_loop_trace_counter_handler = dasm_labels[zend_lbhybrid_loop_trace_counter];
4705 	} else {
4706 		zend_jit_runtime_jit_handler = (const void*)zend_runtime_jit;
4707 		zend_jit_profile_jit_handler = (const void*)zend_jit_profile_helper;
4708 		zend_jit_func_hot_counter_handler = (const void*)zend_jit_func_counter_helper;
4709 		zend_jit_loop_hot_counter_handler = (const void*)zend_jit_loop_counter_helper;
4710 		zend_jit_func_trace_counter_handler = (const void*)zend_jit_func_trace_helper;
4711 		zend_jit_ret_trace_counter_handler = (const void*)zend_jit_ret_trace_helper;
4712 		zend_jit_loop_trace_counter_handler = (const void*)zend_jit_loop_trace_helper;
4713 	}
4714 }
4715 
zend_jit_make_stubs(void)4716 static int zend_jit_make_stubs(void)
4717 {
4718 	dasm_State* dasm_state = NULL;
4719 	uint32_t i;
4720 
4721 	dasm_init(&dasm_state, DASM_MAXSECTION);
4722 	dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
4723 
4724 	for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
4725 		dasm_setup(&dasm_state, dasm_actions);
4726 		if (!zend_jit_stubs[i].stub(&dasm_state)) {
4727 			return 0;
4728 		}
4729 		if (!dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, zend_jit_stubs[i].name, 0,
4730 				zend_jit_stubs[i].offset, zend_jit_stubs[i].adjustment)) {
4731 			return 0;
4732 		}
4733 	}
4734 
4735 	zend_jit_init_handlers();
4736 
4737 	dasm_free(&dasm_state);
4738 	return 1;
4739 }
4740 
zend_jit_globals_ctor(zend_jit_globals * jit_globals)4741 static void zend_jit_globals_ctor(zend_jit_globals *jit_globals)
4742 {
4743 	memset(jit_globals, 0, sizeof(zend_jit_globals));
4744 	zend_jit_trace_init_caches();
4745 }
4746 
4747 #ifdef ZTS
zend_jit_globals_dtor(zend_jit_globals * jit_globals)4748 static void zend_jit_globals_dtor(zend_jit_globals *jit_globals)
4749 {
4750 	zend_jit_trace_free_caches(jit_globals);
4751 }
4752 #endif
4753 
zend_jit_parse_config_num(zend_long jit)4754 static int zend_jit_parse_config_num(zend_long jit)
4755 {
4756 	if (jit == 0) {
4757 		JIT_G(on) = 0;
4758 		return SUCCESS;
4759 	}
4760 
4761 	if (jit < 0) return FAILURE;
4762 
4763 	if (jit % 10 == 0 || jit % 10 > 5) return FAILURE;
4764 	JIT_G(opt_level) = jit % 10;
4765 
4766 	jit /= 10;
4767 	if (jit % 10 > 5 || jit % 10 == 4) return FAILURE;
4768 	JIT_G(trigger) = jit % 10;
4769 
4770 	jit /= 10;
4771 	if (jit % 10 > 2) return FAILURE;
4772 	JIT_G(opt_flags) = jit % 10;
4773 
4774 	jit /= 10;
4775 	if (jit % 10 > 1) return FAILURE;
4776 	JIT_G(opt_flags) |= ((jit % 10) ? ZEND_JIT_CPU_AVX : 0);
4777 
4778 	if (jit / 10 != 0) return FAILURE;
4779 
4780 	JIT_G(on) = 1;
4781 
4782 	return SUCCESS;
4783 }
4784 
zend_jit_config(zend_string * jit,int stage)4785 ZEND_EXT_API int zend_jit_config(zend_string *jit, int stage)
4786 {
4787 	if (stage != ZEND_INI_STAGE_STARTUP && !JIT_G(enabled)) {
4788 		if (stage == ZEND_INI_STAGE_RUNTIME) {
4789 			zend_error(E_WARNING, "Cannot change opcache.jit setting at run-time (JIT is disabled)");
4790 		}
4791 		return FAILURE;
4792 	}
4793 
4794 	if (zend_string_equals_literal_ci(jit, "disable")) {
4795 		JIT_G(enabled) = 0;
4796 		JIT_G(on) = 0;
4797 		return SUCCESS;
4798 	} else if (ZSTR_LEN(jit) == 0
4799 			|| zend_string_equals_literal_ci(jit, "0")
4800 			|| zend_string_equals_literal_ci(jit, "off")
4801 			|| zend_string_equals_literal_ci(jit, "no")
4802 			|| zend_string_equals_literal_ci(jit, "false")) {
4803 		JIT_G(enabled) = 1;
4804 		JIT_G(on) = 0;
4805 		return SUCCESS;
4806 	} else if (zend_string_equals_literal_ci(jit, "1")
4807 			|| zend_string_equals_literal_ci(jit, "on")
4808 			|| zend_string_equals_literal_ci(jit, "yes")
4809 			|| zend_string_equals_literal_ci(jit, "true")
4810 			|| zend_string_equals_literal_ci(jit, "tracing")) {
4811 		JIT_G(enabled) = 1;
4812 		JIT_G(on) = 1;
4813 		JIT_G(opt_level) = ZEND_JIT_LEVEL_OPT_FUNCS;
4814 		JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
4815 		JIT_G(opt_flags) = ZEND_JIT_REG_ALLOC_GLOBAL | ZEND_JIT_CPU_AVX;
4816 		return SUCCESS;
4817 	} else if (zend_string_equals_literal_ci(jit, "function")) {
4818 		JIT_G(enabled) = 1;
4819 		JIT_G(on) = 1;
4820 		JIT_G(opt_level) = ZEND_JIT_LEVEL_OPT_SCRIPT;
4821 		JIT_G(trigger) = ZEND_JIT_ON_SCRIPT_LOAD;
4822 		JIT_G(opt_flags) = ZEND_JIT_REG_ALLOC_GLOBAL | ZEND_JIT_CPU_AVX;
4823 		return SUCCESS;
4824 	} else  {
4825 		char *end;
4826 		zend_long num = ZEND_STRTOL(ZSTR_VAL(jit), &end, 10);
4827 		if (end != ZSTR_VAL(jit) + ZSTR_LEN(jit) || zend_jit_parse_config_num(num) != SUCCESS) {
4828 			goto failure;
4829 		}
4830 		JIT_G(enabled) = 1;
4831 		return SUCCESS;
4832 	}
4833 
4834 failure:
4835 	zend_error(E_WARNING, "Invalid \"opcache.jit\" setting. Should be \"disable\", \"on\", \"off\", \"tracing\", \"function\" or 4-digit number");
4836 	JIT_G(enabled) = 0;
4837 	JIT_G(on) = 0;
4838 	return FAILURE;
4839 }
4840 
zend_jit_debug_config(zend_long old_val,zend_long new_val,int stage)4841 ZEND_EXT_API int zend_jit_debug_config(zend_long old_val, zend_long new_val, int stage)
4842 {
4843 	if (stage != ZEND_INI_STAGE_STARTUP) {
4844 		if (((old_val ^ new_val) & ZEND_JIT_DEBUG_PERSISTENT) != 0) {
4845 			if (stage == ZEND_INI_STAGE_RUNTIME) {
4846 				zend_error(E_WARNING, "Some opcache.jit_debug bits cannot be changed after startup");
4847 			}
4848 			return FAILURE;
4849 		}
4850 #ifdef HAVE_DISASM
4851 		if (new_val & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
4852 			if (JIT_G(enabled) && !JIT_G(symbols) && !zend_jit_disasm_init()) {
4853 				// TODO: error reporting and cleanup ???
4854 				return FAILURE;
4855 			}
4856 			// TODO: symbols for JIT-ed code compiled before are missing ???
4857 		}
4858 #endif
4859 	}
4860 	return SUCCESS;
4861 }
4862 
zend_jit_init(void)4863 ZEND_EXT_API void zend_jit_init(void)
4864 {
4865 #ifdef ZTS
4866 	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);
4867 #else
4868 	zend_jit_globals_ctor(&jit_globals);
4869 #endif
4870 }
4871 
zend_jit_check_support(void)4872 ZEND_EXT_API int zend_jit_check_support(void)
4873 {
4874 	int i;
4875 
4876 	zend_jit_vm_kind = zend_vm_kind();
4877 	if (zend_jit_vm_kind != ZEND_VM_KIND_CALL &&
4878 	    zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
4879 		zend_error(E_WARNING, "JIT is compatible only with CALL and HYBRID VM. JIT disabled.");
4880 		JIT_G(enabled) = 0;
4881 		JIT_G(on) = 0;
4882 		return FAILURE;
4883 	}
4884 
4885 	if (zend_execute_ex != execute_ex) {
4886 		if (zend_dtrace_enabled) {
4887 			zend_error(E_WARNING, "JIT is incompatible with DTrace. JIT disabled.");
4888 		} else if (strcmp(sapi_module.name, "phpdbg") != 0) {
4889 			zend_error(E_WARNING, "JIT is incompatible with third party extensions that override zend_execute_ex(). JIT disabled.");
4890 		}
4891 		JIT_G(enabled) = 0;
4892 		JIT_G(on) = 0;
4893 		return FAILURE;
4894 	}
4895 
4896 	for (i = 0; i <= 256; i++) {
4897 		switch (i) {
4898 			/* JIT has no effect on these opcodes */
4899 			case ZEND_BEGIN_SILENCE:
4900 			case ZEND_END_SILENCE:
4901 			case ZEND_EXIT:
4902 				break;
4903 			default:
4904 				if (zend_get_user_opcode_handler(i) != NULL) {
4905 					zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
4906 					JIT_G(enabled) = 0;
4907 					JIT_G(on) = 0;
4908 					return FAILURE;
4909 				}
4910 		}
4911 	}
4912 
4913 	return SUCCESS;
4914 }
4915 
zend_jit_startup(void * buf,size_t size,bool reattached)4916 ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached)
4917 {
4918 	int ret;
4919 
4920 	zend_jit_halt_op = zend_get_halt_op();
4921 
4922 	if (zend_jit_setup() != SUCCESS) {
4923 		// TODO: error reporting and cleanup ???
4924 		return FAILURE;
4925 	}
4926 
4927 	zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME);
4928 
4929 #ifdef HAVE_GDB
4930 	zend_jit_gdb_init();
4931 #endif
4932 
4933 #ifdef HAVE_OPROFILE
4934 	if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) {
4935 		if (!zend_jit_oprofile_startup()) {
4936 			// TODO: error reporting and cleanup ???
4937 			return FAILURE;
4938 		}
4939 	}
4940 #endif
4941 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
4942 	zend_write_protect = pthread_jit_write_protect_supported_np();
4943 #endif
4944 
4945 	dasm_buf = buf;
4946 	dasm_size = size;
4947 
4948 #ifdef HAVE_MPROTECT
4949 #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
4950 	if (zend_write_protect) {
4951 		pthread_jit_write_protect_np(1);
4952 	}
4953 #endif
4954 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
4955 		if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
4956 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
4957 		}
4958 	} else {
4959 		if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
4960 			fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
4961 		}
4962 	}
4963 #elif _WIN32
4964 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
4965 		DWORD old;
4966 
4967 		if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READWRITE, &old)) {
4968 			DWORD err = GetLastError();
4969 			char *msg = php_win32_error_to_msg(err);
4970 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
4971 			php_win32_error_msg_free(msg);
4972 		}
4973 	} else {
4974 		DWORD old;
4975 
4976 		if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
4977 			DWORD err = GetLastError();
4978 			char *msg = php_win32_error_to_msg(err);
4979 			fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
4980 			php_win32_error_msg_free(msg);
4981 		}
4982 	}
4983 #endif
4984 
4985 	dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr) * 2);
4986 	if (!reattached) {
4987 		zend_jit_unprotect();
4988 		*dasm_ptr = dasm_buf;
4989 #if _WIN32
4990 		/* reserve space for global labels */
4991 		*dasm_ptr = (void**)*dasm_ptr + zend_lb_MAX;
4992 #endif
4993 		zend_jit_protect();
4994 	}
4995 
4996 #ifdef HAVE_DISASM
4997 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
4998 		if (!zend_jit_disasm_init()) {
4999 			// TODO: error reporting and cleanup ???
5000 			return FAILURE;
5001 		}
5002 	}
5003 #endif
5004 
5005 #ifdef HAVE_PERFTOOLS
5006 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
5007 		zend_jit_perf_jitdump_open();
5008 	}
5009 #endif
5010 
5011 	if (!reattached) {
5012 		zend_jit_unprotect();
5013 		ret = zend_jit_make_stubs();
5014 #if _WIN32
5015 		/* save global labels */
5016 		memcpy(dasm_buf, dasm_labels, sizeof(void*) * zend_lb_MAX);
5017 #endif
5018 		zend_jit_protect();
5019 		if (!ret) {
5020 			// TODO: error reporting and cleanup ???
5021 			return FAILURE;
5022 		}
5023 	} else {
5024 #if _WIN32
5025 		/* restore global labels */
5026 		memcpy(dasm_labels, dasm_buf, sizeof(void*) * zend_lb_MAX);
5027 		zend_jit_init_handlers();
5028 #endif
5029 	}
5030 
5031 	if (zend_jit_trace_startup(reattached) != SUCCESS) {
5032 		return FAILURE;
5033 	}
5034 
5035 	zend_jit_unprotect();
5036 #if ZEND_JIT_TARGET_ARM64
5037 	/* reserve space for global labels veneers */
5038 	dasm_labels_veneers = *dasm_ptr;
5039 	*dasm_ptr = (void**)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(zend_lb_MAX, DASM_ALIGNMENT);
5040 	memset(dasm_labels_veneers, 0, sizeof(void*) * ZEND_MM_ALIGNED_SIZE_EX(zend_lb_MAX, DASM_ALIGNMENT));
5041 #endif
5042 	/* save JIT buffer pos */
5043 	dasm_ptr[1] = dasm_ptr[0];
5044 	zend_jit_protect();
5045 
5046 	return SUCCESS;
5047 }
5048 
zend_jit_shutdown(void)5049 ZEND_EXT_API void zend_jit_shutdown(void)
5050 {
5051 	if (JIT_G(debug) & ZEND_JIT_DEBUG_SIZE && dasm_ptr != NULL) {
5052 		fprintf(stderr, "\nJIT memory usage: %td\n", (ptrdiff_t)((char*)*dasm_ptr - (char*)dasm_buf));
5053 	}
5054 
5055 #ifdef HAVE_OPROFILE
5056 	if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) {
5057 		zend_jit_oprofile_shutdown();
5058 	}
5059 #endif
5060 
5061 #ifdef HAVE_GDB
5062 	if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
5063 		zend_jit_gdb_unregister();
5064 	}
5065 #endif
5066 
5067 #ifdef HAVE_DISASM
5068 	zend_jit_disasm_shutdown();
5069 #endif
5070 
5071 #ifdef HAVE_PERFTOOLS
5072 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
5073 		zend_jit_perf_jitdump_close();
5074 	}
5075 #endif
5076 #ifdef ZTS
5077 	ts_free_id(jit_globals_id);
5078 #else
5079 	zend_jit_trace_free_caches(&jit_globals);
5080 #endif
5081 }
5082 
zend_jit_reset_counters(void)5083 static void zend_jit_reset_counters(void)
5084 {
5085 	int i;
5086 
5087 	for (i = 0; i < ZEND_HOT_COUNTERS_COUNT; i++) {
5088 		zend_jit_hot_counters[i] = ZEND_JIT_COUNTER_INIT;
5089 	}
5090 }
5091 
zend_jit_activate(void)5092 ZEND_EXT_API void zend_jit_activate(void)
5093 {
5094 	zend_jit_profile_counter = 0;
5095 	if (JIT_G(on)) {
5096 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
5097 			zend_jit_reset_counters();
5098 		} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
5099 			zend_jit_reset_counters();
5100 			zend_jit_trace_reset_caches();
5101 		}
5102 	}
5103 }
5104 
zend_jit_deactivate(void)5105 ZEND_EXT_API void zend_jit_deactivate(void)
5106 {
5107 	if (zend_jit_profile_counter && !CG(unclean_shutdown)) {
5108 		zend_class_entry *ce;
5109 
5110 		zend_shared_alloc_lock();
5111 		SHM_UNPROTECT();
5112 		zend_jit_unprotect();
5113 
5114 		zend_jit_check_funcs(EG(function_table), 0);
5115 		ZEND_HASH_MAP_REVERSE_FOREACH_PTR(EG(class_table), ce) {
5116 			if (ce->type == ZEND_INTERNAL_CLASS) {
5117 				break;
5118 			}
5119 			zend_jit_check_funcs(&ce->function_table, 1);
5120 		} ZEND_HASH_FOREACH_END();
5121 
5122 		zend_jit_protect();
5123 		SHM_PROTECT();
5124 		zend_shared_alloc_unlock();
5125 	}
5126 
5127 	zend_jit_profile_counter = 0;
5128 }
5129 
zend_jit_restart_preloaded_op_array(zend_op_array * op_array)5130 static void zend_jit_restart_preloaded_op_array(zend_op_array *op_array)
5131 {
5132 	zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
5133 
5134 	if (!func_info) {
5135 		return;
5136 	}
5137 
5138 	if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_TRACE) {
5139 		zend_jit_restart_hot_trace_counters(op_array);
5140 	} else if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_COUNTERS) {
5141 		zend_jit_restart_hot_counters(op_array);
5142 #if 0
5143 	// TODO: We have to restore handlers for some inner basic-blocks, but we didn't store them ???
5144 	} else if (func_info->flags & (ZEND_FUNC_JIT_ON_FIRST_EXEC|ZEND_FUNC_JIT_ON_PROF_REQUEST)) {
5145 		zend_op *opline = op_array->opcodes;
5146 		zend_jit_op_array_extension *jit_extension =
5147 			(zend_jit_op_array_extension*)func_info;
5148 
5149 		if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
5150 			while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
5151 				opline++;
5152 			}
5153 		}
5154 		if (func_info->flags & ZEND_FUNC_JIT_ON_FIRST_EXEC) {
5155 			opline->handler = (const void*)zend_jit_runtime_jit_handler;
5156 		} else {
5157 			opline->handler = (const void*)zend_jit_profile_jit_handler;
5158 		}
5159 #endif
5160 	}
5161 	if (op_array->num_dynamic_func_defs) {
5162 		for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
5163 			zend_jit_restart_preloaded_op_array(op_array->dynamic_func_defs[i]);
5164 		}
5165 	}
5166 }
5167 
zend_jit_restart_preloaded_script(zend_persistent_script * script)5168 static void zend_jit_restart_preloaded_script(zend_persistent_script *script)
5169 {
5170 	zend_class_entry *ce;
5171 	zend_op_array *op_array;
5172 
5173 	zend_jit_restart_preloaded_op_array(&script->script.main_op_array);
5174 
5175 	ZEND_HASH_MAP_FOREACH_PTR(&script->script.function_table, op_array) {
5176 		zend_jit_restart_preloaded_op_array(op_array);
5177 	} ZEND_HASH_FOREACH_END();
5178 
5179 	ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) {
5180 		ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
5181 			if (op_array->type == ZEND_USER_FUNCTION) {
5182 				zend_jit_restart_preloaded_op_array(op_array);
5183 			}
5184 		} ZEND_HASH_FOREACH_END();
5185 	} ZEND_HASH_FOREACH_END();
5186 }
5187 
zend_jit_restart(void)5188 ZEND_EXT_API void zend_jit_restart(void)
5189 {
5190 	if (dasm_buf) {
5191 		zend_jit_unprotect();
5192 
5193 #if ZEND_JIT_TARGET_ARM64
5194 		memset(dasm_labels_veneers, 0, sizeof(void*) * ZEND_MM_ALIGNED_SIZE_EX(zend_lb_MAX, DASM_ALIGNMENT));
5195 #endif
5196 
5197 		/* restore JIT buffer pos */
5198 		dasm_ptr[0] = dasm_ptr[1];
5199 
5200 		zend_jit_trace_restart();
5201 
5202 		if (ZCSG(preload_script)) {
5203 			zend_jit_restart_preloaded_script(ZCSG(preload_script));
5204 			if (ZCSG(saved_scripts)) {
5205 				zend_persistent_script **p = ZCSG(saved_scripts);
5206 
5207 				while (*p) {
5208 					zend_jit_restart_preloaded_script(*p);
5209 					p++;
5210 				}
5211 			}
5212 		}
5213 
5214 		zend_jit_protect();
5215 
5216 #ifdef HAVE_DISASM
5217 		if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
5218 			zend_jit_disasm_shutdown();
5219 			zend_jit_disasm_init();
5220 		}
5221 #endif
5222 	}
5223 }
5224 
5225 #endif /* HAVE_JIT */
5226