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