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