xref: /php-src/ext/opcache/jit/zend_jit_ir.c (revision f4f6c138)
1 /*
2  *  +----------------------------------------------------------------------+
3  *  | Zend JIT                                                             |
4  *  +----------------------------------------------------------------------+
5  *  | Copyright (c) The PHP Group                                          |
6  *  +----------------------------------------------------------------------+
7  *  | This source file is subject to version 3.01 of the PHP license,      |
8  *  | that is bundled with this package in the file LICENSE, and is        |
9  *  | available through the world-wide-web at the following url:           |
10  *  | https://www.php.net/license/3_01.txt                                 |
11  *  | If you did not receive a copy of the PHP license and are unable to   |
12  *  | obtain it through the world-wide-web, please send a note to          |
13  *  | license@php.net so we can mail you a copy immediately.               |
14  *  +----------------------------------------------------------------------+
15  *  | Authors: Dmitry Stogov <dmitry@php.net>                              |
16  *  +----------------------------------------------------------------------+
17  */
18 
19 #include "jit/ir/ir.h"
20 #include "jit/ir/ir_builder.h"
21 
22 #if defined(IR_TARGET_X86)
23 # define IR_REG_SP            4 /* IR_REG_RSP */
24 # define IR_REG_FP            5 /* IR_REG_RBP */
25 # define ZREG_FP              6 /* IR_REG_RSI */
26 # define ZREG_IP              7 /* IR_REG_RDI */
27 # define ZREG_FIRST_FPR       8
28 # define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7)) /* all preserved registers */
29 #elif defined(IR_TARGET_X64)
30 # define IR_REG_SP            4 /* IR_REG_RSP */
31 # define IR_REG_FP            5 /* IR_REG_RBP */
32 # define ZREG_FP             14 /* IR_REG_R14 */
33 # define ZREG_IP             15 /* IR_REG_R15 */
34 # define ZREG_FIRST_FPR      16
35 # if defined(_WIN64)
36 #  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7) | (1<<12) | (1<<13) | (1<<14) | (1<<15))
37 /*
38 #  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7) | (1<<12) | (1<<13) | (1<<14) | (1<<15) | \
39                                (1<<(16+6)) | (1<<(16+7)) | (1<<(16+8)) | (1<<(16+9)) | (1<<(16+10)) | \
40                                (1<<(16+11)) | (1<<(16+12)) | (1<<(16+13)) | (1<<(16+14)) | (1<<(16+15)))
41 */
42 # else
43 #  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<12) | (1<<13) | (1<<14) | (1<<15)) /* all preserved registers */
44 # endif
45 #elif defined(IR_TARGET_AARCH64)
46 # define IR_REG_SP           31 /* IR_REG_RSP */
47 # define IR_REG_FP           29 /* IR_REG_X29 */
48 # define ZREG_FP             27 /* IR_REG_X27 */
49 # define ZREG_IP             28 /* IR_REG_X28 */
50 # define ZREG_FIRST_FPR      32
51 # define IR_REGSET_PRESERVED ((1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23) | \
52                               (1<<24) | (1<<25) | (1<<26) | (1<<27) | (1<<28)) /* all preserved registers */
53 #else
54 # error "Unknown IR target"
55 #endif
56 
57 #define ZREG_RX ZREG_IP
58 
59 #define OPTIMIZE_FOR_SIZE 0
60 
61 /* IR builder defines */
62 #undef  _ir_CTX
63 #define _ir_CTX                 (&jit->ctx)
64 
65 #undef  ir_CONST_ADDR
66 #define ir_CONST_ADDR(_addr)    jit_CONST_ADDR(jit, (uintptr_t)(_addr))
67 #define ir_CONST_FUNC(_addr)    jit_CONST_FUNC(jit, (uintptr_t)(_addr), 0)
68 #define ir_CONST_FC_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), IR_FASTCALL_FUNC)
69 #define ir_CAST_FC_FUNC(_addr)  ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
70 	ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_I32))
71 
72 #define ir_CONST_FUNC_PROTO(_addr, _proto) \
73 	jit_CONST_FUNC_PROTO(jit, (uintptr_t)(_addr), (_proto))
74 
75 #undef  ir_ADD_OFFSET
76 #define ir_ADD_OFFSET(_addr, _offset) \
77 	jit_ADD_OFFSET(jit, _addr, _offset)
78 
79 #ifdef ZEND_ENABLE_ZVAL_LONG64
80 # define IR_LONG           IR_I64
81 # define ir_CONST_LONG     ir_CONST_I64
82 # define ir_UNARY_OP_L     ir_UNARY_OP_I64
83 # define ir_BINARY_OP_L    ir_BINARY_OP_I64
84 # define ir_ADD_L          ir_ADD_I64
85 # define ir_SUB_L          ir_SUB_I64
86 # define ir_MUL_L          ir_MUL_I64
87 # define ir_DIV_L          ir_DIV_I64
88 # define ir_MOD_L          ir_MOD_I64
89 # define ir_NEG_L          ir_NEG_I64
90 # define ir_ABS_L          ir_ABS_I64
91 # define ir_SEXT_L         ir_SEXT_I64
92 # define ir_ZEXT_L         ir_ZEXT_I64
93 # define ir_TRUNC_L        ir_TRUNC_I64
94 # define ir_BITCAST_L      ir_BITCAST_I64
95 # define ir_FP2L           ir_FP2I64
96 # define ir_ADD_OV_L       ir_ADD_OV_I64
97 # define ir_SUB_OV_L       ir_SUB_OV_I64
98 # define ir_MUL_OV_L       ir_MUL_OV_I64
99 # define ir_NOT_L          ir_NOT_I64
100 # define ir_OR_L           ir_OR_I64
101 # define ir_AND_L          ir_AND_I64
102 # define ir_XOR_L          ir_XOR_I64
103 # define ir_SHL_L          ir_SHL_I64
104 # define ir_SHR_L          ir_SHR_I64
105 # define ir_SAR_L          ir_SAR_I64
106 # define ir_ROL_L          ir_ROL_I64
107 # define ir_ROR_L          ir_ROR_I64
108 # define ir_MIN_L          ir_MIN_I64
109 # define ir_MAX_L          ir_MAX_I64
110 # define ir_LOAD_L         ir_LOAD_I64
111 #else
112 # define IR_LONG           IR_I32
113 # define ir_CONST_LONG     ir_CONST_I32
114 # define ir_UNARY_OP_L     ir_UNARY_OP_I32
115 # define ir_BINARY_OP_L    ir_BINARY_OP_I32
116 # define ir_ADD_L          ir_ADD_I32
117 # define ir_SUB_L          ir_SUB_I32
118 # define ir_MUL_L          ir_MUL_I32
119 # define ir_DIV_L          ir_DIV_I32
120 # define ir_MOD_L          ir_MOD_I32
121 # define ir_NEG_L          ir_NEG_I32
122 # define ir_ABS_L          ir_ABS_I32
123 # define ir_SEXT_L         ir_SEXT_I32
124 # define ir_ZEXT_L         ir_ZEXT_I32
125 # define ir_TRUNC_L        ir_TRUNC_I32
126 # define ir_BITCAST_L      ir_BITCAST_I32
127 # define ir_FP2L           ir_FP2I32
128 # define ir_ADD_OV_L       ir_ADD_OV_I32
129 # define ir_SUB_OV_L       ir_SUB_OV_I32
130 # define ir_MUL_OV_L       ir_MUL_OV_I32
131 # define ir_NOT_L          ir_NOT_I32
132 # define ir_OR_L           ir_OR_I32
133 # define ir_AND_L          ir_AND_I32
134 # define ir_XOR_L          ir_XOR_I32
135 # define ir_SHL_L          ir_SHL_I32
136 # define ir_SHR_L          ir_SHR_I32
137 # define ir_SAR_L          ir_SAR_I32
138 # define ir_ROL_L          ir_ROL_I32
139 # define ir_ROR_L          ir_ROR_I32
140 # define ir_MIN_L          ir_MIN_I32
141 # define ir_MAX_L          ir_MAX_I32
142 # define ir_LOAD_L         ir_LOAD_I32
143 #endif
144 
145 /* A helper structure to collect IT rers for the following use in (MERGE/PHI)_N */
146 typedef struct _ir_refs {
147   uint32_t count;
148   uint32_t limit;
149   ir_ref   refs[] ZEND_ELEMENT_COUNT(count);
150 } ir_refs;
151 
152 #define ir_refs_size(_n)          (offsetof(ir_refs, refs) + sizeof(ir_ref) * (_n))
153 #define ir_refs_init(_name, _n)   _name = alloca(ir_refs_size(_n)); \
154                                   do {_name->count = 0; _name->limit = (_n);} while (0)
155 
ir_refs_add(ir_refs * refs,ir_ref ref)156 static void ir_refs_add(ir_refs *refs, ir_ref ref)
157 {
158 	ir_ref *ptr;
159 
160 	ZEND_ASSERT(refs->count < refs->limit);
161 	ptr = refs->refs;
162 	ptr[refs->count++] = ref;
163 }
164 
165 static size_t zend_jit_trace_prologue_size = (size_t)-1;
166 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
167 static uint32_t allowed_opt_flags = 0;
168 static uint32_t default_mflags = 0;
169 #endif
170 static bool delayed_call_chain = 0; // TODO: remove this var (use jit->delayed_call_level) ???
171 
172 #ifdef ZTS
173 # ifdef _WIN32
174 extern uint32_t _tls_index;
175 extern char *_tls_start;
176 extern char *_tls_end;
177 # endif
178 
179 static size_t tsrm_ls_cache_tcb_offset = 0;
180 static size_t tsrm_tls_index = 0;
181 static size_t tsrm_tls_offset = 0;
182 
183 # define EG_TLS_OFFSET(field) \
184 	(executor_globals_offset + offsetof(zend_executor_globals, field))
185 
186 # define CG_TLS_OFFSET(field) \
187 	(compiler_globals_offset + offsetof(zend_compiler_globals, field))
188 
189 # define jit_EG(_field) \
190 	ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
191 
192 # define jit_CG(_field) \
193 	ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
194 
195 #else
196 
197 # define jit_EG(_field) \
198 	ir_CONST_ADDR(&EG(_field))
199 
200 # define jit_CG(_field) \
201 	ir_CONST_ADDR(&CG(_field))
202 
203 #endif
204 
205 #define jit_CALL(_call, _field) \
206 	ir_ADD_OFFSET(_call, offsetof(zend_execute_data, _field))
207 
208 #define jit_EX(_field) \
209 	jit_CALL(jit_FP(jit), _field)
210 
211 #define jit_RX(_field) \
212 	jit_CALL(jit_IP(jit), _field)
213 
214 #define JIT_STUBS(_) \
215 	_(exception_handler,              IR_SKIP_PROLOGUE) \
216 	_(exception_handler_undef,        IR_SKIP_PROLOGUE) \
217 	_(exception_handler_free_op2,     IR_SKIP_PROLOGUE) \
218 	_(exception_handler_free_op1_op2, IR_SKIP_PROLOGUE) \
219 	_(interrupt_handler,              IR_SKIP_PROLOGUE) \
220 	_(leave_function_handler,         IR_SKIP_PROLOGUE) \
221 	_(negative_shift,                 IR_SKIP_PROLOGUE) \
222 	_(mod_by_zero,                    IR_SKIP_PROLOGUE) \
223 	_(invalid_this,                   IR_SKIP_PROLOGUE) \
224 	_(undefined_function,             IR_SKIP_PROLOGUE) \
225 	_(throw_cannot_pass_by_ref,       IR_SKIP_PROLOGUE) \
226 	_(icall_throw,                    IR_SKIP_PROLOGUE) \
227 	_(leave_throw,                    IR_SKIP_PROLOGUE) \
228 	_(hybrid_runtime_jit,             IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
229 	_(hybrid_profile_jit,             IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
230 	_(hybrid_func_hot_counter,        IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
231 	_(hybrid_loop_hot_counter,        IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
232 	_(hybrid_func_trace_counter,      IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
233 	_(hybrid_ret_trace_counter,       IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
234 	_(hybrid_loop_trace_counter,      IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
235 	_(trace_halt,                     IR_SKIP_PROLOGUE) \
236 	_(trace_escape,                   IR_SKIP_PROLOGUE) \
237 	_(trace_exit,                     IR_SKIP_PROLOGUE) \
238 	_(undefined_offset,               IR_FUNCTION | IR_FASTCALL_FUNC) \
239 	_(undefined_key,                  IR_FUNCTION | IR_FASTCALL_FUNC) \
240 	_(cannot_add_element,             IR_FUNCTION | IR_FASTCALL_FUNC) \
241 	_(assign_const,                   IR_FUNCTION | IR_FASTCALL_FUNC) \
242 	_(assign_tmp,                     IR_FUNCTION | IR_FASTCALL_FUNC) \
243 	_(assign_var,                     IR_FUNCTION | IR_FASTCALL_FUNC) \
244 	_(assign_cv_noref,                IR_FUNCTION | IR_FASTCALL_FUNC) \
245 	_(assign_cv,                      IR_FUNCTION | IR_FASTCALL_FUNC) \
246 	_(new_array,                      IR_FUNCTION | IR_FASTCALL_FUNC) \
247 
248 #define JIT_STUB_ID(name, flags) \
249 	jit_stub_ ## name,
250 
251 #define JIT_STUB_FORWARD(name, flags) \
252 	static int zend_jit_ ## name ## _stub(zend_jit_ctx *jit);
253 
254 #define JIT_STUB(name, flags) \
255 	{JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, flags},
256 
257 typedef enum _jit_stub_id {
258 	JIT_STUBS(JIT_STUB_ID)
259 	jit_last_stub
260 } jit_stub_id;
261 
262 typedef struct _zend_jit_reg_var {
263 	ir_ref   ref;
264 	uint32_t flags;
265 } zend_jit_reg_var;
266 
267 typedef struct _zend_jit_ctx {
268 	ir_ctx               ctx;
269 	const zend_op       *last_valid_opline;
270 	bool                 use_last_valid_opline;
271 	bool                 track_last_valid_opline;
272 	bool                 reuse_ip;
273 	uint32_t             delayed_call_level;
274 	int                  b;           /* current basic block number or -1 */
275 #ifdef ZTS
276 	ir_ref               tls;
277 #endif
278 	ir_ref               fp;
279 	ir_ref               trace_loop_ref;
280 	ir_ref               return_inputs;
281 	const zend_op_array *op_array;
282 	const zend_op_array *current_op_array;
283 	zend_ssa            *ssa;
284 	zend_string         *name;
285 	ir_ref              *bb_start_ref;      /* PHP BB -> IR ref mapping */
286 	ir_ref              *bb_predecessors;   /* PHP BB -> index in bb_edges -> IR refs of predessors */
287 	ir_ref              *bb_edges;
288 	zend_jit_trace_info *trace;
289 	zend_jit_reg_var    *ra;
290 	int                  delay_var;
291 	ir_refs             *delay_refs;
292 	ir_ref               eg_exception_addr;
293 	HashTable            addr_hash;
294 	ir_ref               stub_addr[jit_last_stub];
295 } zend_jit_ctx;
296 
297 typedef int8_t zend_reg;
298 
299 typedef struct _zend_jit_registers_buf {
300 #if defined(IR_TARGET_X64)
301 	uint64_t gpr[16]; /* general purpose integer register */
302 	double   fpr[16]; /* floating point registers */
303 #elif defined(IR_TARGET_X86)
304 	uint32_t gpr[8]; /* general purpose integer register */
305 	double   fpr[8]; /* floating point registers */
306 #elif defined (IR_TARGET_AARCH64)
307 	uint64_t gpr[32]; /* general purpose integer register */
308 	double   fpr[32]; /* floating point registers */
309 #else
310 # error "Unknown IR target"
311 #endif
312 } zend_jit_registers_buf;
313 
314 /* Keep 32 exit points in a single code block */
315 #define ZEND_JIT_EXIT_POINTS_SPACING   4  // push byte + short jmp = bytes
316 #define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
317 
318 static uint32_t zend_jit_exit_point_by_addr(const void *addr);
319 int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
320 
321 static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
322                                        const zend_op  *opline,
323                                        zend_jit_addr   var_use_addr,
324                                        zend_jit_addr   var_addr,
325                                        uint32_t        var_info,
326                                        uint32_t        var_def_info,
327                                        uint8_t         val_type,
328                                        zend_jit_addr   val_addr,
329                                        uint32_t        val_info,
330                                        zend_jit_addr   res_addr,
331                                        zend_jit_addr   ref_addr,
332                                        bool       check_exception);
333 
334 typedef struct _zend_jit_stub {
335 	const char *name;
336 	int (*stub)(zend_jit_ctx *jit);
337 	uint32_t flags;
338 } zend_jit_stub;
339 
340 JIT_STUBS(JIT_STUB_FORWARD)
341 
342 static const zend_jit_stub zend_jit_stubs[] = {
343 	JIT_STUBS(JIT_STUB)
344 };
345 
346 #if defined(_WIN32) || defined(IR_TARGET_AARCH64)
347 /* We keep addresses in SHM to share them between sepaeate processes (on Windows) or to support veneers (on AArch64) */
348 static void** zend_jit_stub_handlers = NULL;
349 #else
350 static void* zend_jit_stub_handlers[sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])];
351 #endif
352 
353 #if defined(IR_TARGET_AARCH64)
354 
355 # ifdef __FreeBSD__
356 /* https://github.com/freebsd/freebsd-src/blob/c52ca7dd09066648b1cc40f758289404d68ab886/libexec/rtld-elf/aarch64/reloc.c#L180-L184 */
357 typedef struct TLSDescriptor {
358 	void*   thunk;
359 	int     index;
360 	size_t  offset;
361 } TLSDescriptor;
362 # endif
363 
364 #define IR_HAS_VENEERS (1U<<31) /* IR_RESERVED_FLAG_1 */
365 
zend_jit_get_veneer(ir_ctx * ctx,const void * addr)366 static const void *zend_jit_get_veneer(ir_ctx *ctx, const void *addr)
367 {
368 	int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
369 
370 	for (i = 0; i < count; i++) {
371 		if (zend_jit_stub_handlers[i] == addr) {
372 			return zend_jit_stub_handlers[count + i];
373 		}
374 	}
375 
376 	if (((zend_jit_ctx*)ctx)->trace
377 	 && (void*)addr >= dasm_buf && (void*)addr < dasm_end) {
378 		uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
379 
380 		if (exit_point != (uint32_t)-1) {
381 			zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
382 
383 			ZEND_ASSERT(exit_point < t->exit_count);
384 			return (const void*)((char*)ctx->deoptimization_exits_base + (exit_point * 4));
385 		}
386 	}
387 
388 	return NULL;
389 }
390 
zend_jit_set_veneer(ir_ctx * ctx,const void * addr,const void * veneer)391 static bool zend_jit_set_veneer(ir_ctx *ctx, const void *addr, const void *veneer)
392 {
393 	int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
394 	uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
395 
396 	if (exit_point != (uint32_t)-1) {
397 		return 1;
398 	}
399 	for (i = 0; i < count; i++) {
400 		if (zend_jit_stub_handlers[i] == addr) {
401 			const void **ptr = (const void**)&zend_jit_stub_handlers[count + i];
402 			*ptr = veneer;
403 			ctx->flags2 |= IR_HAS_VENEERS;
404 #ifdef HAVE_CAPSTONE
405 			int64_t offset;
406 		    if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
407 				const char *name = ir_disasm_find_symbol((uint64_t)(uintptr_t)addr, &offset);
408 
409 				if (name && !offset) {
410 					if (strstr(name, "@veneer") == NULL) {
411 						char *new_name;
412 
413 						zend_spprintf(&new_name, 0, "%s@veneer", name);
414 						ir_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
415 						efree(new_name);
416 					} else {
417 						ir_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
418 					}
419 				}
420 			}
421 #endif
422 			return 1;
423 		}
424 	}
425 
426 	return 0;
427 }
428 
zend_jit_commit_veneers(void)429 static void zend_jit_commit_veneers(void)
430 {
431 	int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
432 
433 	for (i = 0; i < count; i++) {
434 		if (zend_jit_stub_handlers[count + i]) {
435 			zend_jit_stub_handlers[i] = zend_jit_stub_handlers[count + i];
436 			zend_jit_stub_handlers[count + i] = NULL;
437 		}
438 	}
439 }
440 #endif
441 
zend_jit_prefer_const_addr_load(zend_jit_ctx * jit,uintptr_t addr)442 static bool zend_jit_prefer_const_addr_load(zend_jit_ctx *jit, uintptr_t addr)
443 {
444 #if defined(IR_TARGET_X86)
445 	return 0; /* always use immediate value */
446 #elif defined(IR_TARGET_X64)
447 	return addr > 0xffffffff; /* prefer loading long constant from memery */
448 #elif defined(IR_TARGET_AARCH64)
449 	return addr > 0xffff;
450 #else
451 # error "Unknown IR target"
452 #endif
453 }
454 
zend_reg_name(int8_t reg)455 static const char* zend_reg_name(int8_t reg)
456 {
457 	return ir_reg_name(reg, ir_reg_is_int(reg) ? IR_LONG : IR_DOUBLE);
458 }
459 
460 /* IR helpers */
461 
462 #ifdef ZTS
jit_TLS(zend_jit_ctx * jit)463 static ir_ref jit_TLS(zend_jit_ctx *jit)
464 {
465 	ZEND_ASSERT(jit->ctx.control);
466 	if (jit->tls) {
467 		/* Emit "TLS" once for basic block */
468 		ir_insn *insn;
469 		ir_ref ref = jit->ctx.control;
470 
471 		while (1) {
472 			if (ref == jit->tls) {
473 				return jit->tls;
474 			}
475 			insn = &jit->ctx.ir_base[ref];
476 			if (insn->op >= IR_START || insn->op == IR_CALL) {
477 				break;
478 			}
479 			ref = insn->op1;
480 		}
481 	}
482 	jit->tls = ir_TLS(
483 		tsrm_ls_cache_tcb_offset ? tsrm_ls_cache_tcb_offset : tsrm_tls_index,
484 		tsrm_ls_cache_tcb_offset ? IR_NULL : tsrm_tls_offset);
485 	return jit->tls;
486 }
487 #endif
488 
jit_CONST_ADDR(zend_jit_ctx * jit,uintptr_t addr)489 static ir_ref jit_CONST_ADDR(zend_jit_ctx *jit, uintptr_t addr)
490 {
491 	ir_ref ref;
492 	zval *zv;
493 
494 	if (addr == 0) {
495 		return IR_NULL;
496 	}
497 	zv = zend_hash_index_lookup(&jit->addr_hash, addr);
498 	if (Z_TYPE_P(zv) == IS_LONG) {
499 		ref = Z_LVAL_P(zv);
500 		ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_ADDR, IR_ADDR));
501 	} else {
502 		ref = ir_unique_const_addr(&jit->ctx, addr);
503 		ZVAL_LONG(zv, ref);
504 	}
505 	return ref;
506 }
507 
jit_CONST_FUNC_PROTO(zend_jit_ctx * jit,uintptr_t addr,ir_ref proto)508 static ir_ref jit_CONST_FUNC_PROTO(zend_jit_ctx *jit, uintptr_t addr, ir_ref proto)
509 {
510 	ir_ref ref;
511 	ir_insn *insn;
512 	zval *zv;
513 
514 	ZEND_ASSERT(addr != 0);
515 	zv = zend_hash_index_lookup(&jit->addr_hash, addr);
516 	if (Z_TYPE_P(zv) == IS_LONG) {
517 		ref = Z_LVAL_P(zv);
518 		ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_FUNC_ADDR, IR_ADDR) && jit->ctx.ir_base[ref].proto == proto);
519 	} else {
520 		ref = ir_unique_const_addr(&jit->ctx, addr);
521 		insn = &jit->ctx.ir_base[ref];
522 		insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
523 		insn->proto = proto;
524 		ZVAL_LONG(zv, ref);
525 	}
526 	return ref;
527 }
528 
jit_CONST_FUNC(zend_jit_ctx * jit,uintptr_t addr,uint16_t flags)529 static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags)
530 {
531 #if defined(IR_TARGET_X86)
532 	/* TODO: dummy prototype (only flags matter) ??? */
533 	ir_ref proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
534 #else
535 	ir_ref proto = 0;
536 #endif
537 
538 	return jit_CONST_FUNC_PROTO(jit, addr, proto);
539 }
540 
jit_ADD_OFFSET(zend_jit_ctx * jit,ir_ref addr,uintptr_t offset)541 static ir_ref jit_ADD_OFFSET(zend_jit_ctx *jit, ir_ref addr, uintptr_t offset)
542 {
543 	if (offset) {
544 		addr = ir_ADD_A(addr, ir_CONST_ADDR(offset));
545 	}
546 	return addr;
547 }
548 
jit_EG_exception(zend_jit_ctx * jit)549 static ir_ref jit_EG_exception(zend_jit_ctx *jit)
550 {
551 #ifdef ZTS
552 	return jit_EG(exception);
553 #else
554 	ir_ref ref = jit->eg_exception_addr;
555 
556 	if (UNEXPECTED(!ref)) {
557 		ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)&EG(exception));
558 		jit->eg_exception_addr = ref;
559 	}
560 	return ref;
561 #endif
562 }
563 
jit_STUB_ADDR(zend_jit_ctx * jit,jit_stub_id id)564 static ir_ref jit_STUB_ADDR(zend_jit_ctx *jit, jit_stub_id id)
565 {
566 	ir_ref ref = jit->stub_addr[id];
567 
568 	if (UNEXPECTED(!ref)) {
569 		ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
570 		jit->stub_addr[id] = ref;
571 	}
572 	return ref;
573 }
574 
jit_STUB_FUNC_ADDR(zend_jit_ctx * jit,jit_stub_id id,uint16_t flags)575 static ir_ref jit_STUB_FUNC_ADDR(zend_jit_ctx *jit, jit_stub_id id, uint16_t flags)
576 {
577 	ir_ref ref = jit->stub_addr[id];
578 	ir_insn *insn;
579 
580 	if (UNEXPECTED(!ref)) {
581 		ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
582 		insn = &jit->ctx.ir_base[ref];
583 		insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
584 #if defined(IR_TARGET_X86)
585 		/* TODO: dummy prototype (only flags matter) ??? */
586 		insn->proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
587 #else
588 		insn->proto = 0;
589 #endif
590 		jit->stub_addr[id] = ref;
591 	}
592 	return ref;
593 }
594 
jit_SNAPSHOT(zend_jit_ctx * jit,ir_ref addr)595 static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
596 {
597 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
598 		const void *ptr = (const void*)jit->ctx.ir_base[addr].val.addr;
599 		const zend_op_array *op_array = &JIT_G(current_frame)->func->op_array;
600 		uint32_t stack_size = op_array->last_var + op_array->T;
601 
602 		if (ptr == zend_jit_stub_handlers[jit_stub_exception_handler]
603 	     || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_undef]
604 	     || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op1_op2]
605 	     || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op2]
606 	     || ptr == zend_jit_stub_handlers[jit_stub_interrupt_handler]
607 	     || ptr == zend_jit_stub_handlers[jit_stub_leave_function_handler]
608 	     || ptr == zend_jit_stub_handlers[jit_stub_negative_shift]
609 	     || ptr == zend_jit_stub_handlers[jit_stub_mod_by_zero]
610 	     || ptr == zend_jit_stub_handlers[jit_stub_invalid_this]
611 	     || ptr == zend_jit_stub_handlers[jit_stub_undefined_function]
612 	     || ptr == zend_jit_stub_handlers[jit_stub_throw_cannot_pass_by_ref]
613 	     || ptr == zend_jit_stub_handlers[jit_stub_icall_throw]
614 	     || ptr == zend_jit_stub_handlers[jit_stub_leave_throw]
615 	     || ptr == zend_jit_stub_handlers[jit_stub_trace_halt]
616 	     || ptr == zend_jit_stub_handlers[jit_stub_trace_escape]) {
617 			/* This is a GUARD that trigger exit through a stub code (without deoptimization) */
618 			return;
619 		}
620 
621 		/* Check if we need snapshot entries for polymorphic method call */
622 		zend_jit_trace_info *t = jit->trace;
623 		uint32_t exit_point = 0, n = 0;
624 
625 		if (addr < 0) {
626 			if (t->exit_count > 0
627 			 && jit->ctx.ir_base[addr].val.u64 == (uintptr_t)zend_jit_trace_get_exit_addr(t->exit_count - 1)) {
628 				exit_point = t->exit_count - 1;
629 				if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
630 					n = 2;
631 				}
632 			}
633 		}
634 
635 		if (stack_size || n) {
636 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
637 			uint32_t snapshot_size, i;
638 
639 			snapshot_size = stack_size;
640 			while (snapshot_size > 0) {
641 				ir_ref ref = STACK_REF(stack, snapshot_size - 1);
642 
643 				if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, snapshot_size - 1) & (/*ZREG_LOAD|*/ZREG_STORE))) {
644 					snapshot_size--;
645 				} else {
646 					break;
647 				}
648 			}
649 			if (snapshot_size || n) {
650 				ir_ref snapshot;
651 
652 				snapshot = ir_SNAPSHOT(snapshot_size + n);
653 				for (i = 0; i < snapshot_size; i++) {
654 					ir_ref ref = STACK_REF(stack, i);
655 
656 					if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, i) & (/*ZREG_LOAD|*/ZREG_STORE))) {
657 						ref = IR_UNUSED;
658 					}
659 					ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
660 				}
661 				if (n) {
662 					ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func_ref);
663 					ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this_ref);
664 				}
665 			}
666 		}
667 	}
668 }
669 
_add_trace_const(zend_jit_trace_info * t,int64_t val)670 static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
671 {
672 	int32_t i;
673 
674 	for (i = 0; i < t->consts_count; i++) {
675 		if (t->constants[i].i == val) {
676 			return i;
677 		}
678 	}
679 	ZEND_ASSERT(i < 0x7fffffff);
680 	t->consts_count = i + 1;
681 	t->constants = erealloc(t->constants, (i + 1) * sizeof(zend_jit_exit_const));
682 	t->constants[i].i = val;
683 	return i;
684 }
685 
zend_jit_duplicate_exit_point(ir_ctx * ctx,zend_jit_trace_info * t,uint32_t exit_point,ir_ref snapshot_ref)686 uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
687 {
688 	uint32_t stack_size, stack_offset;
689 	uint32_t new_exit_point = t->exit_count;
690 
691 	if (new_exit_point >= ZEND_JIT_TRACE_MAX_EXITS) {
692 		ctx->status = -ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
693 		return exit_point;
694 	}
695 
696 	t->exit_count++;
697 	memcpy(&t->exit_info[new_exit_point], &t->exit_info[exit_point], sizeof(zend_jit_trace_exit_info));
698 	stack_size = t->exit_info[new_exit_point].stack_size;
699 	if (stack_size != 0) {
700 		stack_offset = t->stack_map_size;
701 		t->stack_map_size += stack_size;
702 		// TODO: reduce number of reallocations ???
703 		t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
704 		memcpy(t->stack_map + stack_offset, t->stack_map + t->exit_info[new_exit_point].stack_offset, stack_size * sizeof(zend_jit_trace_stack));
705 		t->exit_info[new_exit_point].stack_offset = stack_offset;
706 	}
707 	t->exit_info[new_exit_point].flags &= ~ZEND_JIT_EXIT_FIXED;
708 
709 	return new_exit_point;
710 }
711 
zend_jit_snapshot_handler(ir_ctx * ctx,ir_ref snapshot_ref,ir_insn * snapshot,void * addr)712 void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
713 {
714 	zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
715 	uint32_t exit_point, exit_flags;
716 	ir_ref n = snapshot->inputs_count;
717 	ir_ref i;
718 
719 	exit_point = zend_jit_exit_point_by_addr(addr);
720 	ZEND_ASSERT(exit_point < t->exit_count);
721 	exit_flags = t->exit_info[exit_point].flags;
722 
723 	if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
724 		int8_t *reg_ops = ctx->regs[snapshot_ref];
725 
726 		ZEND_ASSERT(reg_ops[n - 1] != -1 && reg_ops[n] != -1);
727 		if ((exit_flags & ZEND_JIT_EXIT_FIXED)
728 		 && (t->exit_info[exit_point].poly_func_reg != reg_ops[n - 1]
729 		  || t->exit_info[exit_point].poly_this_reg != reg_ops[n])) {
730 			exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
731 			addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
732 			exit_flags &= ~ZEND_JIT_EXIT_FIXED;
733 		}
734 		t->exit_info[exit_point].poly_func_reg = reg_ops[n - 1];
735 		t->exit_info[exit_point].poly_this_reg = reg_ops[n];
736 		n -= 2;
737 	}
738 
739 	for (i = 2; i <= n; i++) {
740 		ir_ref ref = ir_insn_op(snapshot, i);
741 
742 		if (ref) {
743 			int8_t *reg_ops = ctx->regs[snapshot_ref];
744 			int8_t reg = reg_ops[i];
745 			ir_ref var = i - 2;
746 
747 			ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
748 			if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
749 				ZEND_ASSERT(reg != ZREG_NONE);
750 				if ((exit_flags & ZEND_JIT_EXIT_FIXED)
751 				 && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
752 					exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
753 					addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
754 					exit_flags &= ~ZEND_JIT_EXIT_FIXED;
755 				}
756 				t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
757 			} else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
758 				ZEND_ASSERT(t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_LONG ||
759 					t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_DOUBLE);
760 
761 				if (ref > 0) {
762 					if (reg != ZREG_NONE) {
763 						if (reg & IR_REG_SPILL_LOAD) {
764 							ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
765 							/* spill slot on a CPU stack */
766 							if ((exit_flags & ZEND_JIT_EXIT_FIXED)
767 							 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].ref != ref
768 							  || t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
769 							  || !(t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ZREG_SPILL_SLOT))) {
770 								exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
771 								addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
772 								exit_flags &= ~ZEND_JIT_EXIT_FIXED;
773 							}
774 							t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
775 							t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
776 							t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
777 						} else if (reg & IR_REG_SPILL_SPECIAL) {
778 							/* spill slot on a VM stack */
779 							if ((exit_flags & ZEND_JIT_EXIT_FIXED)
780 							 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
781 							 || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
782 								exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
783 								addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
784 								exit_flags &= ~ZEND_JIT_EXIT_FIXED;
785 							}
786 							t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
787 							t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
788 						} else {
789 							if ((exit_flags & ZEND_JIT_EXIT_FIXED)
790 							 && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
791 								exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
792 								addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
793 								exit_flags &= ~ZEND_JIT_EXIT_FIXED;
794 							}
795 							t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
796 						}
797 					} else {
798 						if ((exit_flags & ZEND_JIT_EXIT_FIXED)
799 						 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
800 						 || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
801 							exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
802 							addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
803 							exit_flags &= ~ZEND_JIT_EXIT_FIXED;
804 						}
805 						t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
806 					}
807 				} else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
808 					int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
809 					t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
810 					t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
811 				}
812 			}
813 		}
814 	}
815 	t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
816 	return addr;
817 }
818 
jit_SIDE_EXIT(zend_jit_ctx * jit,ir_ref addr)819 static void jit_SIDE_EXIT(zend_jit_ctx *jit, ir_ref addr)
820 {
821 	jit_SNAPSHOT(jit, addr);
822 	ir_IJMP(addr);
823 }
824 
825 /* PHP JIT helpers */
826 
jit_EMALLOC(zend_jit_ctx * jit,size_t size,const zend_op_array * op_array,const zend_op * opline)827 static ir_ref jit_EMALLOC(zend_jit_ctx *jit, size_t size, const zend_op_array *op_array, const zend_op *opline)
828 {
829 #if ZEND_DEBUG
830 	return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_emalloc),
831 		ir_CONST_ADDR(size),
832 		op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
833 		ir_CONST_U32(opline ? opline->lineno : 0),
834 		IR_NULL,
835 		ir_CONST_U32(0));
836 #elif defined(HAVE_BUILTIN_CONSTANT_P)
837 	if (size > 24 && size <= 32) {
838 		return ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_emalloc_32));
839 	} else {
840 		return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
841 	}
842 #else
843 	return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
844 #endif
845 }
846 
jit_EFREE(zend_jit_ctx * jit,ir_ref ptr,size_t size,const zend_op_array * op_array,const zend_op * opline)847 static ir_ref jit_EFREE(zend_jit_ctx *jit, ir_ref ptr, size_t size, const zend_op_array *op_array, const zend_op *opline)
848 {
849 #if ZEND_DEBUG
850 	return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_efree),
851 		ptr,
852 		op_array && op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
853 		ir_CONST_U32(opline ? opline->lineno : 0),
854 		IR_NULL,
855 		ir_CONST_U32(0));
856 #elif defined(HAVE_BUILTIN_CONSTANT_P)
857 	if (size > 24 && size <= 32) {
858 		return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree_32), ptr);
859 	} else {
860 		return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
861 	}
862 #else
863 	return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
864 #endif
865 }
866 
jit_FP(zend_jit_ctx * jit)867 static ir_ref jit_FP(zend_jit_ctx *jit)
868 {
869 	ZEND_ASSERT(jit->ctx.control);
870 	if (jit->fp == IR_UNUSED) {
871 		/* Emit "RLOAD FP" once for basic block */
872 		jit->fp = ir_RLOAD_A(ZREG_FP);
873 	} else {
874 		ir_insn *insn;
875 		ir_ref ref = jit->ctx.control;
876 
877 		while (1) {
878 			if (ref == jit->fp) {
879 				break;
880 			}
881 			insn = &jit->ctx.ir_base[ref];
882 			if (insn->op >= IR_START || insn->op == IR_CALL) {
883 				jit->fp = ir_RLOAD_A(ZREG_FP);
884 				break;
885 			}
886 			ref = insn->op1;
887 		}
888 	}
889 	return jit->fp;
890 }
891 
jit_STORE_FP(zend_jit_ctx * jit,ir_ref ref)892 static void jit_STORE_FP(zend_jit_ctx *jit, ir_ref ref)
893 {
894 	ir_RSTORE(ZREG_FP, ref);
895 	jit->fp = IR_UNUSED;
896 }
897 
jit_IP(zend_jit_ctx * jit)898 static ir_ref jit_IP(zend_jit_ctx *jit)
899 {
900 	return ir_RLOAD_A(ZREG_IP);
901 }
902 
jit_STORE_IP(zend_jit_ctx * jit,ir_ref ref)903 static void jit_STORE_IP(zend_jit_ctx *jit, ir_ref ref)
904 {
905 	ir_RSTORE(ZREG_IP, ref);
906 }
907 
jit_IP32(zend_jit_ctx * jit)908 static ir_ref jit_IP32(zend_jit_ctx *jit)
909 {
910 	return ir_RLOAD_U32(ZREG_IP);
911 }
912 
jit_LOAD_IP(zend_jit_ctx * jit,ir_ref ref)913 static void jit_LOAD_IP(zend_jit_ctx *jit, ir_ref ref)
914 {
915 	if (GCC_GLOBAL_REGS) {
916 		jit_STORE_IP(jit, ref);
917 	} else {
918 		ir_STORE(jit_EX(opline), ref);
919 	}
920 }
921 
jit_LOAD_IP_ADDR(zend_jit_ctx * jit,const zend_op * target)922 static void jit_LOAD_IP_ADDR(zend_jit_ctx *jit, const zend_op *target)
923 {
924 	jit_LOAD_IP(jit, ir_CONST_ADDR(target));
925 }
926 
zend_jit_track_last_valid_opline(zend_jit_ctx * jit)927 static void zend_jit_track_last_valid_opline(zend_jit_ctx *jit)
928 {
929 	jit->use_last_valid_opline = 0;
930 	jit->track_last_valid_opline = 1;
931 }
932 
zend_jit_use_last_valid_opline(zend_jit_ctx * jit)933 static void zend_jit_use_last_valid_opline(zend_jit_ctx *jit)
934 {
935 	if (jit->track_last_valid_opline) {
936 		jit->use_last_valid_opline = 1;
937 		jit->track_last_valid_opline = 0;
938 	}
939 }
940 
zend_jit_trace_uses_initial_ip(zend_jit_ctx * jit)941 static bool zend_jit_trace_uses_initial_ip(zend_jit_ctx *jit)
942 {
943 	return jit->use_last_valid_opline;
944 }
945 
zend_jit_set_last_valid_opline(zend_jit_ctx * jit,const zend_op * opline)946 static void zend_jit_set_last_valid_opline(zend_jit_ctx *jit, const zend_op *opline)
947 {
948 	if (!jit->reuse_ip) {
949 		jit->track_last_valid_opline = 1;
950 		jit->last_valid_opline = opline;
951 	}
952 }
953 
zend_jit_reset_last_valid_opline(zend_jit_ctx * jit)954 static void zend_jit_reset_last_valid_opline(zend_jit_ctx *jit)
955 {
956 	jit->track_last_valid_opline = 0;
957 	jit->last_valid_opline = NULL;
958 }
959 
zend_jit_start_reuse_ip(zend_jit_ctx * jit)960 static void zend_jit_start_reuse_ip(zend_jit_ctx *jit)
961 {
962 	zend_jit_reset_last_valid_opline(jit);
963 	jit->reuse_ip = 1;
964 }
965 
zend_jit_reuse_ip(zend_jit_ctx * jit)966 static int zend_jit_reuse_ip(zend_jit_ctx *jit)
967 {
968 	if (!jit->reuse_ip) {
969 		zend_jit_start_reuse_ip(jit);
970 		// RX = EX(call);
971 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
972 	}
973 	return 1;
974 }
975 
zend_jit_stop_reuse_ip(zend_jit_ctx * jit)976 static void zend_jit_stop_reuse_ip(zend_jit_ctx *jit)
977 {
978 	jit->reuse_ip = 0;
979 }
980 
zend_jit_save_call_chain(zend_jit_ctx * jit,uint32_t call_level)981 static int zend_jit_save_call_chain(zend_jit_ctx *jit, uint32_t call_level)
982 {
983 	ir_ref rx, call;
984 
985 	if (call_level == 1) {
986 		// JIT: call = NULL;
987 		call = IR_NULL;
988 	} else {
989 		// JIT: call = EX(call);
990 		call = ir_LOAD_A(jit_EX(call));
991 	}
992 
993 	rx = jit_IP(jit);
994 
995 	// JIT: call->prev_execute_data = call;
996 	ir_STORE(jit_CALL(rx, prev_execute_data), call);
997 
998 	// JIT: EX(call) = call;
999 	ir_STORE(jit_EX(call), rx);
1000 
1001 	jit->delayed_call_level = 0;
1002 	delayed_call_chain = 0;
1003 
1004 	return 1;
1005 }
1006 
zend_jit_set_ip(zend_jit_ctx * jit,const zend_op * target)1007 static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target)
1008 {
1009 	ir_ref ref;
1010 	ir_ref addr = IR_UNUSED;
1011 
1012 	if (jit->delayed_call_level) {
1013 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
1014 			return 0;
1015 		}
1016 	}
1017 
1018 	if (jit->last_valid_opline) {
1019 		zend_jit_use_last_valid_opline(jit);
1020 		if (jit->last_valid_opline != target) {
1021 			if (GCC_GLOBAL_REGS) {
1022 				ref = jit_IP(jit);
1023 			} else {
1024 				addr = jit_EX(opline);
1025 				ref = ir_LOAD_A(addr);
1026 			}
1027 			if (target > jit->last_valid_opline) {
1028 				ref = ir_ADD_OFFSET(ref, (uintptr_t)target - (uintptr_t)jit->last_valid_opline);
1029 			} else {
1030 				ref = ir_SUB_A(ref, ir_CONST_ADDR((uintptr_t)jit->last_valid_opline - (uintptr_t)target));
1031 			}
1032 			if (GCC_GLOBAL_REGS) {
1033 				jit_STORE_IP(jit, ref);
1034 			} else {
1035 				ir_STORE(addr, ref);
1036 			}
1037 		}
1038 	} else {
1039 		if (GCC_GLOBAL_REGS) {
1040 			jit_STORE_IP(jit, ir_CONST_ADDR(target));
1041 		} else {
1042 			ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1043 		}
1044 	}
1045 	jit->reuse_ip = 0;
1046 	zend_jit_set_last_valid_opline(jit, target);
1047 	return 1;
1048 }
1049 
zend_jit_set_ip_ex(zend_jit_ctx * jit,const zend_op * target,bool set_ip_reg)1050 static int zend_jit_set_ip_ex(zend_jit_ctx *jit, const zend_op *target, bool set_ip_reg)
1051 {
1052 	if (!GCC_GLOBAL_REGS && set_ip_reg && !jit->last_valid_opline) {
1053 		/* Optimization to avoid duplicate constant load */
1054 		ir_STORE(jit_EX(opline), ir_HARD_COPY_A(ir_CONST_ADDR(target)));
1055 		return 1;
1056 	}
1057 	return zend_jit_set_ip(jit, target);
1058 }
1059 
jit_SET_EX_OPLINE(zend_jit_ctx * jit,const zend_op * target)1060 static void jit_SET_EX_OPLINE(zend_jit_ctx *jit, const zend_op *target)
1061 {
1062 	if (jit->last_valid_opline == target) {
1063 		zend_jit_use_last_valid_opline(jit);
1064 		if (GCC_GLOBAL_REGS) {
1065 			// EX(opline) = opline
1066 			ir_STORE(jit_EX(opline), jit_IP(jit));
1067 		}
1068 	} else {
1069 		ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1070 		if (!GCC_GLOBAL_REGS) {
1071 			zend_jit_reset_last_valid_opline(jit);
1072 		}
1073 	}
1074 }
1075 
jit_ZVAL_ADDR(zend_jit_ctx * jit,zend_jit_addr addr)1076 static ir_ref jit_ZVAL_ADDR(zend_jit_ctx *jit, zend_jit_addr addr)
1077 {
1078 	if (Z_MODE(addr) == IS_MEM_ZVAL) {
1079 		ir_ref reg;
1080 
1081 		if (Z_REG(addr) == ZREG_FP) {
1082 			reg = jit_FP(jit);
1083 		} else if (Z_REG(addr) == ZREG_RX) {
1084 			reg = jit_IP(jit);
1085 		} else {
1086 			ZEND_UNREACHABLE();
1087 		}
1088 		return ir_ADD_OFFSET(reg, Z_OFFSET(addr));
1089 	} else if (Z_MODE(addr) == IS_REF_ZVAL) {
1090 		return Z_IR_REF(addr);
1091 	} else {
1092 		ZEND_ASSERT(Z_MODE(addr) == IS_CONST_ZVAL);
1093 		return ir_CONST_ADDR(Z_ZV(addr));
1094 	}
1095 }
1096 
jit_Z_TYPE_ref(zend_jit_ctx * jit,ir_ref ref)1097 static ir_ref jit_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref)
1098 {
1099 	return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type)));
1100 }
1101 
jit_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr)1102 static ir_ref jit_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr)
1103 {
1104 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1105 		return ir_CONST_U8(Z_TYPE_P(Z_ZV(addr)));
1106 	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1107 		ir_ref reg;
1108 
1109 		ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1110 		if (Z_REG(addr) == ZREG_FP) {
1111 			reg = jit_FP(jit);
1112 		} else if (Z_REG(addr) == ZREG_RX) {
1113 			reg = jit_IP(jit);
1114 		} else {
1115 			ZEND_UNREACHABLE();
1116 		}
1117 		return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type)));
1118 	} else {
1119 		return jit_Z_TYPE_ref(jit, jit_ZVAL_ADDR(jit, addr));
1120 	}
1121 }
1122 
jit_Z_TYPE_FLAGS_ref(zend_jit_ctx * jit,ir_ref ref)1123 static ir_ref jit_Z_TYPE_FLAGS_ref(zend_jit_ctx *jit, ir_ref ref)
1124 {
1125 	return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type_flags)));
1126 }
1127 
jit_Z_TYPE_FLAGS(zend_jit_ctx * jit,zend_jit_addr addr)1128 static ir_ref jit_Z_TYPE_FLAGS(zend_jit_ctx *jit, zend_jit_addr addr)
1129 {
1130 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1131 		return ir_CONST_U8(Z_TYPE_FLAGS_P(Z_ZV(addr)));
1132 	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1133 		ir_ref reg;
1134 
1135 		ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1136 		if (Z_REG(addr) == ZREG_FP) {
1137 			reg = jit_FP(jit);
1138 		} else if (Z_REG(addr) == ZREG_RX) {
1139 			reg = jit_IP(jit);
1140 		} else {
1141 			ZEND_UNREACHABLE();
1142 		}
1143 		return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type_flags)));
1144 	} else {
1145 		return jit_Z_TYPE_FLAGS_ref(jit, jit_ZVAL_ADDR(jit, addr));
1146 	}
1147 }
1148 
jit_Z_TYPE_INFO_ref(zend_jit_ctx * jit,ir_ref ref)1149 static ir_ref jit_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref)
1150 {
1151 	return ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)));
1152 }
1153 
jit_Z_TYPE_INFO(zend_jit_ctx * jit,zend_jit_addr addr)1154 static ir_ref jit_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr)
1155 {
1156 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1157 		return ir_CONST_U32(Z_TYPE_INFO_P(Z_ZV(addr)));
1158 	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1159 		ir_ref reg;
1160 
1161 		ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1162 		if (Z_REG(addr) == ZREG_FP) {
1163 			reg = jit_FP(jit);
1164 		} else if (Z_REG(addr) == ZREG_RX) {
1165 			reg = jit_IP(jit);
1166 		} else {
1167 			ZEND_UNREACHABLE();
1168 		}
1169 		return ir_LOAD_U32(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)));
1170 	} else {
1171 		return jit_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr));
1172 	}
1173 }
1174 
jit_set_Z_TYPE_INFO_ref(zend_jit_ctx * jit,ir_ref ref,ir_ref type_info)1175 static void jit_set_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type_info)
1176 {
1177 	ir_STORE(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)), type_info);
1178 }
1179 
jit_set_Z_TYPE_INFO_ex(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref type_info)1180 static void jit_set_Z_TYPE_INFO_ex(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref type_info)
1181 {
1182 	if (Z_MODE(addr) == IS_MEM_ZVAL) {
1183 		ir_ref reg;
1184 
1185 		ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1186 		if (Z_REG(addr) == ZREG_FP) {
1187 			reg = jit_FP(jit);
1188 		} else if (Z_REG(addr) == ZREG_RX) {
1189 			reg = jit_IP(jit);
1190 		} else {
1191 			ZEND_UNREACHABLE();
1192 		}
1193 		ir_STORE(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)), type_info);
1194 	} else {
1195 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr), type_info);
1196 	}
1197 }
1198 
jit_set_Z_TYPE_INFO(zend_jit_ctx * jit,zend_jit_addr addr,uint32_t type_info)1199 static void jit_set_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr, uint32_t type_info)
1200 {
1201 	if (type_info < IS_STRING
1202 	 && Z_MODE(addr) == IS_MEM_ZVAL
1203 	 && Z_REG(addr) == ZREG_FP
1204 	 && JIT_G(current_frame)
1205 	 && STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(addr))) == type_info) {
1206 		/* type is already set */
1207 		return;
1208 	}
1209 	jit_set_Z_TYPE_INFO_ex(jit, addr, ir_CONST_U32(type_info));
1210 }
1211 
jit_if_Z_TYPE_ref(zend_jit_ctx * jit,ir_ref ref,ir_ref type)1212 static ir_ref jit_if_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type)
1213 {
1214 	return ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), type));
1215 }
1216 
jit_if_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type)1217 static ir_ref jit_if_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1218 {
1219 	ZEND_ASSERT(type != IS_UNDEF);
1220 	return ir_IF(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)));
1221 }
1222 
jit_if_not_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type)1223 static ir_ref jit_if_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1224 {
1225 	ir_ref ref = jit_Z_TYPE(jit, addr);
1226 
1227 	if (type != IS_UNDEF) {
1228 		ref = ir_NE(ref, ir_CONST_U8(type));
1229 	}
1230 	return ir_IF(ref);
1231 }
1232 
jit_guard_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type,const void * exit_addr)1233 static void jit_guard_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1234 {
1235 	ir_ref ref = jit_Z_TYPE(jit, addr);
1236 
1237 	if (type != IS_UNDEF) {
1238 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
1239 	} else {
1240 		ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1241 	}
1242 }
1243 
jit_guard_not_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type,const void * exit_addr)1244 static void jit_guard_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1245 {
1246 	ir_ref ref = jit_Z_TYPE(jit, addr);
1247 
1248 	if (type != IS_UNDEF) {
1249 		ref = ir_NE(ref, ir_CONST_U8(type));
1250 	}
1251 	ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
1252 }
1253 
jit_if_REFCOUNTED(zend_jit_ctx * jit,zend_jit_addr addr)1254 static ir_ref jit_if_REFCOUNTED(zend_jit_ctx *jit, zend_jit_addr addr)
1255 {
1256 	return ir_IF(jit_Z_TYPE_FLAGS(jit, addr));
1257 }
1258 
jit_if_COLLECTABLE_ref(zend_jit_ctx * jit,ir_ref addr_ref)1259 static ir_ref jit_if_COLLECTABLE_ref(zend_jit_ctx *jit, ir_ref addr_ref)
1260 {
1261 	return ir_IF(ir_AND_U8(jit_Z_TYPE_FLAGS_ref(jit, addr_ref), ir_CONST_U8(IS_TYPE_COLLECTABLE)));
1262 }
1263 
jit_Z_LVAL_ref(zend_jit_ctx * jit,ir_ref ref)1264 static ir_ref jit_Z_LVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1265 {
1266 	return ir_LOAD_L(ref);
1267 }
1268 
jit_Z_DVAL_ref(zend_jit_ctx * jit,ir_ref ref)1269 static ir_ref jit_Z_DVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1270 {
1271 	return ir_LOAD_D(ref);
1272 }
1273 
zend_jit_spilling_may_cause_conflict(zend_jit_ctx * jit,int var,ir_ref val)1274 static bool zend_jit_spilling_may_cause_conflict(zend_jit_ctx *jit, int var, ir_ref val)
1275 {
1276 	if (jit->ctx.ir_base[val].op == IR_RLOAD) {
1277 		/* Deoptimization */
1278 		return 0;
1279 	}
1280 //	if (jit->ctx.ir_base[val].op == IR_LOAD
1281 //	 && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1282 //	 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1283 //	 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1284 //	 && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1285 //	 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr == (uintptr_t)EX_NUM_TO_VAR(jit->ssa->vars[var].var)) {
1286 //		/* LOAD from the same location (the LOAD is pinned) */
1287 //		// TODO: should be anti-dependent with the following stores ???
1288 //		return 0;
1289 //	}
1290 	if (jit->ssa->vars[var].var < jit->current_op_array->last_var) {
1291 		/* IS_CV */
1292 		if (jit->ctx.ir_base[val].op == IR_LOAD
1293 		 && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1294 		 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1295 		 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1296 		 && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1297 		 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr != (uintptr_t)EX_NUM_TO_VAR(jit->ssa->vars[var].var)
1298 		 && EX_VAR_TO_NUM(jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr) < jit->current_op_array->last_var) {
1299 			/* binding between different CVs may cause spill conflict */
1300 			return 1;
1301 		} else if (jit->ssa->vars[var].definition >= 0
1302 		 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1303 		 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1304 		 && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].no_val
1305 		 && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi
1306 		 && (jit->ssa->cfg.blocks[jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi->block].flags & ZEND_BB_LOOP_HEADER)) {
1307 			/* Avoid moving spill store out of loop */
1308 			return 1;
1309 		}
1310 		return 0;
1311 	}
1312 	return 1;
1313 }
1314 
zend_jit_def_reg(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref val)1315 static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
1316 {
1317 	int var;
1318 
1319 	ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1320 	var = Z_SSA_VAR(addr);
1321 	if (var == jit->delay_var) {
1322 		ir_refs_add(jit->delay_refs, val);
1323 		return;
1324 	}
1325 	ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
1326 
1327 	/* Negative "var" has special meaning for IR */
1328 	if (val > 0 && !zend_jit_spilling_may_cause_conflict(jit, var, val)) {
1329 		val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
1330 	}
1331 	jit->ra[var].ref = val;
1332 
1333 	if (jit->ra[var].flags & ZREG_FORWARD) {
1334 		zend_ssa_phi *phi = jit->ssa->vars[var].phi_use_chain;
1335 		zend_basic_block *bb;
1336 		int n, j, *p;
1337 		ir_ref *q;
1338 
1339 		jit->ra[var].flags &= ~ZREG_FORWARD;
1340 		while (phi != NULL) {
1341 			zend_ssa_phi *dst_phi = phi;
1342 			int src_var = var;
1343 
1344 			if (dst_phi->pi >= 0) {
1345 				jit->ra[src_var].ref = val;
1346 				src_var = dst_phi->ssa_var;
1347 				if (!(jit->ra[src_var].flags & ZREG_FORWARD)) {
1348 					phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1349 					continue;
1350 				}
1351 				dst_phi = jit->ssa->vars[src_var].phi_use_chain;
1352 				ZEND_ASSERT(dst_phi != NULL && "reg forwarding");
1353 				ZEND_ASSERT(!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding");
1354 				jit->ra[src_var].flags &= ~ZREG_FORWARD;
1355 			}
1356 
1357 			if (jit->ra[dst_phi->ssa_var].ref > 0) {
1358 				ir_insn *phi_insn = &jit->ctx.ir_base[jit->ra[dst_phi->ssa_var].ref];
1359 				if (phi_insn->op == IR_PHI) {
1360 //					ZEND_ASSERT(ir_operands_count(ctx, phi_insn) == n + 1);
1361 					bb = &jit->ssa->cfg.blocks[dst_phi->block];
1362 					n = bb->predecessors_count;
1363 					for (j = 0, p = &dst_phi->sources[0], q = phi_insn->ops + 2; j < n; j++, p++, q++) {
1364 						if (*p == src_var) {
1365 							*q = val;
1366 						}
1367 					}
1368 				}
1369 			}
1370 
1371 			phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1372 		}
1373 	}
1374 }
1375 
zend_jit_use_reg(zend_jit_ctx * jit,zend_jit_addr addr)1376 static ir_ref zend_jit_use_reg(zend_jit_ctx *jit, zend_jit_addr addr)
1377 {
1378 	int var = Z_SSA_VAR(addr);
1379 
1380 	ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1381 	ZEND_ASSERT(jit->ra && jit->ra[var].ref);
1382 	if (jit->ra[var].ref == IR_NULL) {
1383 		zend_jit_addr mem_addr;
1384 		ir_ref ref;
1385 
1386 		ZEND_ASSERT(jit->ra[var].flags & ZREG_LOAD);
1387 		mem_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(jit->ssa->vars[var].var));
1388 		if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_LONG) {
1389 			ref = jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1390 		} else if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1391 			ref = jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1392 		} else {
1393 			ZEND_UNREACHABLE();
1394 		}
1395 		zend_jit_def_reg(jit, addr, ref);
1396 		return ref;
1397 	}
1398 	return jit->ra[Z_SSA_VAR(addr)].ref;
1399 }
1400 
zend_jit_gen_pi(zend_jit_ctx * jit,zend_ssa_phi * phi)1401 static void zend_jit_gen_pi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1402 {
1403 	int src_var = phi->sources[0];
1404 	int dst_var = phi->ssa_var;
1405 
1406 	ZEND_ASSERT(phi->pi >= 0);
1407 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1408 	ZEND_ASSERT(jit->ra[src_var].ref);
1409 
1410 	if (jit->ra[src_var].ref == IR_NULL) {
1411 		/* Not defined yet */
1412 		if (jit->ssa->vars[dst_var].use_chain < 0
1413 		 && jit->ssa->vars[dst_var].phi_use_chain) {
1414 			zend_ssa_phi *phi = jit->ssa->vars[dst_var].phi_use_chain;
1415 			if (!zend_ssa_next_use_phi(jit->ssa, dst_var, phi)) {
1416 				/* This is a Pi forwarded to Phi */
1417 				jit->ra[src_var].flags |= ZREG_FORWARD;
1418 				return;
1419 			}
1420 		}
1421 		ZEND_ASSERT(0 && "Not defined Pi source");
1422 	}
1423 	/* Reuse register */
1424 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var),
1425 		zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)));
1426 }
1427 
zend_jit_gen_phi(zend_jit_ctx * jit,zend_ssa_phi * phi)1428 static void zend_jit_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1429 {
1430 	int dst_var = phi->ssa_var;
1431 	zend_basic_block *bb = &jit->ssa->cfg.blocks[phi->block];
1432 	int n = bb->predecessors_count;
1433 	int i;
1434 	ir_type type = (jit->ssa->var_info[phi->ssa_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE;
1435 	ir_ref merge = jit->bb_start_ref[phi->block];
1436 	ir_ref ref;
1437 	ir_ref old_insns_count = jit->ctx.insns_count;
1438 	ir_ref same_src_ref = IR_UNUSED;
1439 	bool phi_inputs_are_the_same = 1;
1440 
1441 	ZEND_ASSERT(phi->pi < 0);
1442 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1443 	ZEND_ASSERT(merge);
1444 	ZEND_ASSERT(jit->ctx.ir_base[merge].op == IR_MERGE || jit->ctx.ir_base[merge].op == IR_LOOP_BEGIN);
1445 	ZEND_ASSERT(n == jit->ctx.ir_base[merge].inputs_count);
1446 
1447 	ref = ir_emit_N(&jit->ctx, IR_OPT(IR_PHI, type), n + 1);
1448 	ir_set_op(&jit->ctx, ref, 1, merge);
1449 
1450 	for (i = 0; i < n; i++) {
1451 		int src_var = phi->sources[i];
1452 
1453 		ZEND_ASSERT(jit->ra[src_var].ref);
1454 		if (jit->ra[src_var].ref == IR_NULL) {
1455 			jit->ra[src_var].flags |= ZREG_FORWARD;
1456 			phi_inputs_are_the_same = 0;
1457 		} else {
1458 			ir_ref src_ref = zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var));
1459 			if (i == 0) {
1460 				same_src_ref = src_ref;
1461 			} else if (same_src_ref != src_ref) {
1462 				phi_inputs_are_the_same = 0;
1463 			}
1464 			ir_set_op(&jit->ctx, ref, i + 2, src_ref);
1465 		}
1466 	}
1467 	if (phi_inputs_are_the_same) {
1468 		ref = same_src_ref;
1469 		jit->ctx.insns_count = old_insns_count;
1470 	}
1471 
1472 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
1473 }
1474 
jit_Z_LVAL(zend_jit_ctx * jit,zend_jit_addr addr)1475 static ir_ref jit_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1476 {
1477 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1478 		return ir_CONST_LONG(Z_LVAL_P(Z_ZV(addr)));
1479 	} else if (Z_MODE(addr) == IS_REG) {
1480 		return zend_jit_use_reg(jit, addr);
1481 	} else {
1482 		return jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1483 	}
1484 }
1485 
jit_set_Z_LVAL(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref lval)1486 static void jit_set_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1487 {
1488 	if (Z_MODE(addr) == IS_REG) {
1489 		zend_jit_def_reg(jit, addr, lval);
1490 	} else {
1491 		ir_STORE(jit_ZVAL_ADDR(jit, addr), lval);
1492 	}
1493 }
1494 
1495 #if SIZEOF_ZEND_LONG == 4
jit_Z_W2(zend_jit_ctx * jit,zend_jit_addr addr)1496 static ir_ref jit_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr)
1497 {
1498 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1499 		return ir_CONST_U32((Z_ZV(addr))->value.ww.w2);
1500 	} else {
1501 		return ir_LOAD_L(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)));
1502 	}
1503 }
1504 
jit_set_Z_W2(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref lval)1505 static void jit_set_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1506 {
1507 	ir_STORE(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)), lval);
1508 }
1509 #endif
1510 
jit_Z_DVAL(zend_jit_ctx * jit,zend_jit_addr addr)1511 static ir_ref jit_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1512 {
1513 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1514 		return ir_CONST_DOUBLE(Z_DVAL_P(Z_ZV(addr)));
1515 	} else if (Z_MODE(addr) == IS_REG) {
1516 		return zend_jit_use_reg(jit, addr);
1517 	} else {
1518 		return jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1519 	}
1520 }
1521 
jit_set_Z_DVAL(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref dval)1522 static void jit_set_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref dval)
1523 {
1524 	if (Z_MODE(addr) == IS_REG) {
1525 		zend_jit_def_reg(jit, addr, dval);
1526 	} else {
1527 		ir_STORE(jit_ZVAL_ADDR(jit, addr), dval);
1528 	}
1529 }
1530 
jit_Z_PTR_ref(zend_jit_ctx * jit,ir_ref ref)1531 static ir_ref jit_Z_PTR_ref(zend_jit_ctx *jit, ir_ref ref)
1532 {
1533 	return ir_LOAD_A(ref);
1534 }
1535 
jit_Z_PTR(zend_jit_ctx * jit,zend_jit_addr addr)1536 static ir_ref jit_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr)
1537 {
1538 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1539 		return ir_CONST_ADDR(Z_PTR_P(Z_ZV(addr)));
1540 	} else {
1541 		return jit_Z_PTR_ref(jit, jit_ZVAL_ADDR(jit, addr));
1542 	}
1543 }
1544 
jit_set_Z_PTR(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref ptr)1545 static void jit_set_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref ptr)
1546 {
1547 	ir_STORE(jit_ZVAL_ADDR(jit, addr), ptr);
1548 }
1549 
jit_GC_REFCOUNT(zend_jit_ctx * jit,ir_ref ref)1550 static ir_ref jit_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref)
1551 {
1552 	return ir_LOAD_U32(ref);
1553 }
1554 
jit_set_GC_REFCOUNT(zend_jit_ctx * jit,ir_ref ref,uint32_t refcount)1555 static void jit_set_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref, uint32_t refcount)
1556 {
1557 	ir_STORE(ref, ir_CONST_U32(refcount));
1558 }
1559 
jit_GC_ADDREF(zend_jit_ctx * jit,ir_ref ref)1560 static void jit_GC_ADDREF(zend_jit_ctx *jit, ir_ref ref)
1561 {
1562 	ir_STORE(ref, ir_ADD_U32(ir_LOAD_U32(ref), ir_CONST_U32(1)));
1563 }
1564 
jit_GC_ADDREF2(zend_jit_ctx * jit,ir_ref ref)1565 static void jit_GC_ADDREF2(zend_jit_ctx *jit, ir_ref ref)
1566 {
1567 	ir_ref counter = ir_LOAD_U32(ref);
1568 	ir_STORE(ref, ir_ADD_U32(counter, ir_CONST_U32(2)));
1569 }
1570 
jit_GC_DELREF(zend_jit_ctx * jit,ir_ref ref)1571 static ir_ref jit_GC_DELREF(zend_jit_ctx *jit, ir_ref ref)
1572 {
1573 	ir_ref counter = ir_LOAD_U32(ref);
1574 	counter = ir_SUB_U32(counter, ir_CONST_U32(1));
1575 	ir_STORE(ref, counter);
1576 	return counter;
1577 }
1578 
jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx * jit,ir_ref ref)1579 static ir_ref jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx *jit, ir_ref ref)
1580 {
1581 	return ir_IF(
1582 		ir_AND_U32(
1583 			ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_refcounted, gc.u.type_info))),
1584 			ir_CONST_U32(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))));
1585 }
1586 
jit_ZVAL_COPY_CONST(zend_jit_ctx * jit,zend_jit_addr dst,uint32_t dst_info,uint32_t dst_def_info,zval * zv,bool addref)1587 static void jit_ZVAL_COPY_CONST(zend_jit_ctx *jit, zend_jit_addr dst, uint32_t dst_info, uint32_t dst_def_info, zval *zv, bool addref)
1588 {
1589 	ir_ref ref = IR_UNUSED;
1590 
1591 	if (Z_TYPE_P(zv) > IS_TRUE) {
1592 		if (Z_TYPE_P(zv) == IS_DOUBLE) {
1593 			jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE(Z_DVAL_P(zv)));
1594 		} else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
1595 			jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE((double)Z_LVAL_P(zv)));
1596 		} else if (Z_TYPE_P(zv) == IS_LONG) {
1597 			jit_set_Z_LVAL(jit, dst, ir_CONST_LONG(Z_LVAL_P(zv)));
1598 		} else {
1599 			ref = ir_CONST_ADDR(Z_PTR_P(zv));
1600 			jit_set_Z_PTR(jit, dst, ref);
1601 			if (addref && Z_REFCOUNTED_P(zv)) {
1602 				jit_GC_ADDREF(jit, ref);
1603 			}
1604 		}
1605 	}
1606 	if (Z_MODE(dst) != IS_REG) {
1607 		if (dst_def_info == MAY_BE_DOUBLE) {
1608 			if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1609 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
1610 			}
1611 		} else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
1612 			jit_set_Z_TYPE_INFO(jit, dst, Z_TYPE_INFO_P(zv));
1613 		}
1614 	}
1615 }
1616 
jit_if_TYPED_REF(zend_jit_ctx * jit,ir_ref ref)1617 static ir_ref jit_if_TYPED_REF(zend_jit_ctx *jit, ir_ref ref)
1618 {
1619 	return ir_IF(ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr))));
1620 }
1621 
jit_ZVAL_COPY(zend_jit_ctx * jit,zend_jit_addr dst,uint32_t dst_info,zend_jit_addr src,uint32_t src_info,bool addref)1622 static void jit_ZVAL_COPY(zend_jit_ctx *jit, zend_jit_addr dst, uint32_t dst_info, zend_jit_addr src, uint32_t src_info, bool addref)
1623 {
1624 	ir_ref ref = IR_UNUSED;
1625 
1626 	if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1627 		if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1628 			jit_set_Z_LVAL(jit, dst, jit_Z_LVAL(jit, src));
1629 		} else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1630 			jit_set_Z_DVAL(jit, dst, jit_Z_DVAL(jit, src));
1631 		} else {
1632 #if SIZEOF_ZEND_LONG == 4
1633 			if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1634 				jit_set_Z_W2(jit, dst, jit_Z_W2(jit, src));
1635 			}
1636 #endif
1637 			ref = jit_Z_PTR(jit, src);
1638 			jit_set_Z_PTR(jit, dst, ref);
1639 		}
1640 	}
1641 	if (has_concrete_type(src_info & MAY_BE_ANY)
1642 	 && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1643      && !(src_info & MAY_BE_GUARD)) {
1644 		if (Z_MODE(dst) != IS_REG
1645 		 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1646 			uint8_t type = concrete_type(src_info);
1647 			jit_set_Z_TYPE_INFO(jit, dst, type);
1648 		}
1649 	} else {
1650 		ir_ref type = jit_Z_TYPE_INFO(jit, src);
1651 		jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1652 		if (addref) {
1653 			if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1654 				ir_ref if_refcounted = IR_UNUSED;
1655 
1656 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1657 					if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1658 					ir_IF_TRUE(if_refcounted);
1659 				}
1660 
1661 				jit_GC_ADDREF(jit, ref);
1662 
1663 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1664 					ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1665 				}
1666 			}
1667 		}
1668 	}
1669 }
1670 
jit_ZVAL_COPY_2(zend_jit_ctx * jit,zend_jit_addr dst2,zend_jit_addr dst,uint32_t dst_info,zend_jit_addr src,uint32_t src_info,int addref)1671 static void jit_ZVAL_COPY_2(zend_jit_ctx *jit, zend_jit_addr dst2, zend_jit_addr dst, uint32_t dst_info, zend_jit_addr src, uint32_t src_info, int addref)
1672 {
1673 	ir_ref ref = IR_UNUSED;
1674 
1675 	if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1676 		if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1677 			ref = jit_Z_LVAL(jit, src);
1678 			jit_set_Z_LVAL(jit, dst, ref);
1679 			jit_set_Z_LVAL(jit, dst2, ref);
1680 		} else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1681 			ref = jit_Z_DVAL(jit, src);
1682 			jit_set_Z_DVAL(jit, dst, ref);
1683 			jit_set_Z_DVAL(jit, dst2, ref);
1684 		} else {
1685 #if SIZEOF_ZEND_LONG == 4
1686 			if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1687 				ref = jit_Z_W2(jit, src);
1688 				jit_set_Z_W2(jit, dst, ref);
1689 				jit_set_Z_W2(jit, dst2, ref);
1690 			}
1691 #endif
1692 			ref = jit_Z_PTR(jit, src);
1693 			jit_set_Z_PTR(jit, dst, ref);
1694 			jit_set_Z_PTR(jit, dst2, ref);
1695 		}
1696 	}
1697 	if (has_concrete_type(src_info & MAY_BE_ANY)
1698 	 && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1699      && !(src_info & MAY_BE_GUARD)) {
1700 		uint8_t type = concrete_type(src_info);
1701 		ir_ref type_ref = ir_CONST_U32(type);
1702 
1703 		if (Z_MODE(dst) != IS_REG
1704 		 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1705 			jit_set_Z_TYPE_INFO_ex(jit, dst, type_ref);
1706 		}
1707 		if (Z_MODE(dst2) != IS_REG) {
1708 			jit_set_Z_TYPE_INFO_ex(jit, dst2, type_ref);
1709 		}
1710 	} else {
1711 		ir_ref type = jit_Z_TYPE_INFO(jit, src);
1712 		jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1713 		jit_set_Z_TYPE_INFO_ex(jit, dst2, type);
1714 		if (addref) {
1715 			if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1716 				ir_ref if_refcounted = IR_UNUSED;
1717 
1718 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1719 					if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1720 					ir_IF_TRUE(if_refcounted);
1721 				}
1722 
1723 				if (addref == 2) {
1724 					jit_GC_ADDREF2(jit, ref);
1725 				} else {
1726 					jit_GC_ADDREF(jit, ref);
1727 				}
1728 
1729 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1730 					ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1731 				}
1732 			}
1733 		}
1734 	}
1735 }
1736 
jit_ZVAL_DTOR(zend_jit_ctx * jit,ir_ref ref,uint32_t op_info,const zend_op * opline)1737 static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const zend_op *opline)
1738 {
1739 	if (!((op_info) & MAY_BE_GUARD)
1740 	 && has_concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1741 		uint8_t type = concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1742 		if (type == IS_STRING && !ZEND_DEBUG) {
1743 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(_efree), ref);
1744 				return;
1745 		} else if (type == IS_ARRAY) {
1746 			if ((op_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) {
1747 				if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1748 					jit_SET_EX_OPLINE(jit, opline);
1749 				}
1750 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_array_destroy), ref);
1751 			} else {
1752 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_array_free), ref);
1753 			}
1754 			return;
1755 		} else if (type == IS_OBJECT) {
1756 			if (opline) {
1757 				jit_SET_EX_OPLINE(jit, opline);
1758 			}
1759 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1760 			return;
1761 		}
1762 	}
1763 	if (opline) {
1764 		jit_SET_EX_OPLINE(jit, opline);
1765 	}
1766 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(rc_dtor_func), ref);
1767 }
1768 
jit_ZVAL_PTR_DTOR(zend_jit_ctx * jit,zend_jit_addr addr,uint32_t op_info,bool gc,const zend_op * opline)1769 static void jit_ZVAL_PTR_DTOR(zend_jit_ctx  *jit,
1770                               zend_jit_addr  addr,
1771                               uint32_t       op_info,
1772                               bool           gc,
1773                               const zend_op *opline)
1774 {
1775     ir_ref ref, ref2;
1776 	ir_ref if_refcounted = IR_UNUSED;
1777 	ir_ref if_not_zero = IR_UNUSED;
1778 	ir_ref end_inputs = IR_UNUSED;
1779 
1780 	if (op_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
1781 		if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1782 			if_refcounted = jit_if_REFCOUNTED(jit, addr);
1783 			ir_IF_FALSE(if_refcounted);
1784 			ir_END_list(end_inputs);
1785 			ir_IF_TRUE(if_refcounted);
1786 		}
1787 		ref = jit_Z_PTR(jit, addr);
1788 		ref2 = jit_GC_DELREF(jit, ref);
1789 
1790 		if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1791 			if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1792 				if_not_zero = ir_IF(ref2);
1793 				ir_IF_FALSE(if_not_zero);
1794 			}
1795 			// zval_dtor_func(r);
1796 			jit_ZVAL_DTOR(jit, ref, op_info, opline);
1797 			if (if_not_zero) {
1798 				ir_END_list(end_inputs);
1799 				ir_IF_TRUE(if_not_zero);
1800 			}
1801 		}
1802 		if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
1803 			ir_ref if_may_not_leak;
1804 
1805 			if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1806 				ir_ref if_ref, if_collectable;
1807 
1808 				if_ref = jit_if_Z_TYPE(jit, addr, IS_REFERENCE);
1809 				ir_IF_TRUE(if_ref);
1810 
1811 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
1812 
1813 				if_collectable = jit_if_COLLECTABLE_ref(jit, ref2);
1814 				ir_IF_FALSE(if_collectable);
1815 				ir_END_list(end_inputs);
1816 				ir_IF_TRUE(if_collectable);
1817 
1818 				ref2 = jit_Z_PTR_ref(jit, ref2);
1819 
1820 				ir_MERGE_WITH_EMPTY_FALSE(if_ref);
1821 				ref = ir_PHI_2(IR_ADDR, ref2, ref);
1822 			}
1823 
1824 			if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1825 			ir_IF_TRUE(if_may_not_leak);
1826 			ir_END_list(end_inputs);
1827 			ir_IF_FALSE(if_may_not_leak);
1828 
1829 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1830 		}
1831 
1832 		if (end_inputs) {
1833 			ir_END_list(end_inputs);
1834 			ir_MERGE_list(end_inputs);
1835 		}
1836 	}
1837 }
1838 
jit_FREE_OP(zend_jit_ctx * jit,uint8_t op_type,znode_op op,uint32_t op_info,const zend_op * opline)1839 static void jit_FREE_OP(zend_jit_ctx  *jit,
1840                         uint8_t        op_type,
1841                         znode_op       op,
1842                         uint32_t       op_info,
1843                         const zend_op *opline)
1844 {
1845 	if (op_type & (IS_VAR|IS_TMP_VAR)) {
1846 		jit_ZVAL_PTR_DTOR(jit,
1847 			ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var),
1848 			op_info, 0, opline);
1849 	}
1850 }
1851 
jit_OBJ_RELEASE(zend_jit_ctx * jit,ir_ref ref)1852 static void jit_OBJ_RELEASE(zend_jit_ctx  *jit, ir_ref ref)
1853 {
1854 	ir_ref end_inputs = IR_UNUSED;
1855     ir_ref if_not_zero, if_may_not_leak;
1856 
1857 	// JIT: if (GC_DELREF(obj) == 0) {
1858 	if_not_zero = ir_IF(jit_GC_DELREF(jit, ref));
1859 	ir_IF_FALSE(if_not_zero);
1860 
1861 	// JIT: zend_objects_store_del(obj)
1862 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1863 	ir_END_list(end_inputs);
1864 
1865 	ir_IF_TRUE(if_not_zero);
1866 	if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1867 
1868 	ir_IF_TRUE(if_may_not_leak);
1869 	ir_END_list(end_inputs);
1870 
1871 	ir_IF_FALSE(if_may_not_leak);
1872 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1873 	ir_END_list(end_inputs);
1874 
1875 	ir_MERGE_list(end_inputs);
1876 }
1877 
zend_jit_check_timeout(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr)1878 static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
1879 {
1880 	ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
1881 
1882 	if (exit_addr) {
1883 		ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1884 	} else if (!opline || jit->last_valid_opline == opline) {
1885 		ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1886 	} else {
1887 		ir_ref if_timeout = ir_IF(ref);
1888 
1889 		ir_IF_TRUE_cold(if_timeout);
1890 		jit_LOAD_IP_ADDR(jit, opline);
1891 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1892 		ir_IF_FALSE(if_timeout);
1893 	}
1894 }
1895 
1896 /* stubs */
1897 
zend_jit_exception_handler_stub(zend_jit_ctx * jit)1898 static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
1899 {
1900 	const void *handler;
1901 
1902 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1903 		handler = zend_get_opcode_handler_func(EG(exception_op));
1904 
1905 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
1906 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
1907 	} else {
1908 		handler = EG(exception_op)->handler;
1909 
1910 		if (GCC_GLOBAL_REGS) {
1911 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
1912 		} else {
1913 			ir_ref ref, if_negative;
1914 
1915 			ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), jit_FP(jit));
1916 			if_negative = ir_IF(ir_LT(ref, ir_CONST_U32(0)));
1917 			ir_IF_TRUE(if_negative);
1918 			ir_MERGE_WITH_EMPTY_FALSE(if_negative);
1919 			ref = ir_PHI_2(IR_I32, ref, ir_CONST_I32(1));
1920 			ir_RETURN(ref);
1921 		}
1922 	}
1923 	return 1;
1924 }
1925 
zend_jit_exception_handler_undef_stub(zend_jit_ctx * jit)1926 static int zend_jit_exception_handler_undef_stub(zend_jit_ctx *jit)
1927 {
1928 	ir_ref ref, result_type, if_result_used;
1929 
1930 	ref = jit_EG(opline_before_exception);
1931 	result_type = ir_LOAD_U8(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result_type)));
1932 
1933 	if_result_used = ir_IF(ir_AND_U8(result_type, ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1934 	ir_IF_TRUE(if_result_used);
1935 
1936 	ref = ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result.var)));
1937 	if (sizeof(void*) == 8) {
1938 		ref = ir_ZEXT_A(ref);
1939 	}
1940 	ir_STORE(ir_ADD_OFFSET(ir_ADD_A(jit_FP(jit), ref), offsetof(zval, u1.type_info)), ir_CONST_U32(IS_UNDEF));
1941 	ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
1942 
1943 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
1944 
1945 	return 1;
1946 }
1947 
zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx * jit)1948 static int zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx *jit)
1949 {
1950 	ir_ref ref, if_dtor;
1951 	zend_jit_addr var_addr;
1952 
1953 	ref = ir_LOAD_A(jit_EG(opline_before_exception));
1954 	if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op1_type))),
1955 		ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1956 	ir_IF_TRUE(if_dtor);
1957 	ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op1.var)));
1958 	if (sizeof(void*) == 8) {
1959 		ref = ir_ZEXT_A(ref);
1960 	}
1961 	ref = ir_ADD_A(jit_FP(jit), ref);
1962 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
1963 	jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
1964 	ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
1965 
1966 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
1967 
1968 	return 1;
1969 }
1970 
zend_jit_exception_handler_free_op2_stub(zend_jit_ctx * jit)1971 static int zend_jit_exception_handler_free_op2_stub(zend_jit_ctx *jit)
1972 {
1973 	ir_ref ref, if_dtor;
1974 	zend_jit_addr var_addr;
1975 
1976 	ref = ir_LOAD_A(jit_EG(opline_before_exception));
1977 	if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op2_type))),
1978 		ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1979 	ir_IF_TRUE(if_dtor);
1980 	ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.var)));
1981 	if (sizeof(void*) == 8) {
1982 		ref = ir_ZEXT_A(ref);
1983 	}
1984 	ref = ir_ADD_A(jit_FP(jit), ref);
1985 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
1986 	jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
1987 	ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
1988 
1989 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
1990 
1991 	return 1;
1992 }
1993 
zend_jit_interrupt_handler_stub(zend_jit_ctx * jit)1994 static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit)
1995 {
1996 	ir_ref if_timeout, if_exception;
1997 
1998 	if (GCC_GLOBAL_REGS) {
1999 		// EX(opline) = opline
2000 		ir_STORE(jit_EX(opline), jit_IP(jit));
2001 	}
2002 
2003 	ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0));
2004 	if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0)));
2005 	ir_IF_FALSE(if_timeout);
2006 	ir_CALL(IR_VOID, ir_CONST_FUNC(zend_timeout));
2007 	ir_MERGE_WITH_EMPTY_TRUE(if_timeout);
2008 
2009 	if (zend_interrupt_function) {
2010 		ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_interrupt_function), jit_FP(jit));
2011 		if_exception = ir_IF(ir_LOAD_A(jit_EG(exception)));
2012 		ir_IF_TRUE(if_exception);
2013 		ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper));
2014 		ir_MERGE_WITH_EMPTY_FALSE(if_exception);
2015 
2016 		jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
2017 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2018 	}
2019 
2020 	if (GCC_GLOBAL_REGS) {
2021 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2022 	} else {
2023 		ir_RETURN(ir_CONST_I32(1));
2024 	}
2025 	return 1;
2026 }
2027 
zend_jit_leave_function_handler_stub(zend_jit_ctx * jit)2028 static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit)
2029 {
2030 	ir_ref call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
2031 	ir_ref if_top = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_TOP)));
2032 
2033 	ir_IF_FALSE(if_top);
2034 
2035 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2036 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2037 		jit_STORE_IP(jit,
2038 			ir_LOAD_A(jit_EX(opline)));
2039 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2040 	} else if (GCC_GLOBAL_REGS) {
2041 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2042 	} else {
2043 		ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info, jit_FP(jit));
2044 	}
2045 
2046 	ir_IF_TRUE(if_top);
2047 
2048 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2049 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2050 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2051 	} else if (GCC_GLOBAL_REGS) {
2052 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2053 	} else {
2054 		ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info, jit_FP(jit));
2055 	}
2056 
2057 	return 1;
2058 }
2059 
zend_jit_negative_shift_stub(zend_jit_ctx * jit)2060 static int zend_jit_negative_shift_stub(zend_jit_ctx *jit)
2061 {
2062 	ir_CALL_2(IR_VOID,
2063 		ir_CONST_FUNC_PROTO(zend_throw_error,
2064 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2065 		ir_CONST_ADDR(zend_ce_arithmetic_error),
2066 		ir_CONST_ADDR("Bit shift by negative number"));
2067 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2068 	return 1;
2069 }
2070 
zend_jit_mod_by_zero_stub(zend_jit_ctx * jit)2071 static int zend_jit_mod_by_zero_stub(zend_jit_ctx *jit)
2072 {
2073 	ir_CALL_2(IR_VOID,
2074 		ir_CONST_FUNC_PROTO(zend_throw_error,
2075 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2076 		ir_CONST_ADDR(zend_ce_division_by_zero_error),
2077 		ir_CONST_ADDR("Modulo by zero"));
2078 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2079 	return 1;
2080 }
2081 
zend_jit_invalid_this_stub(zend_jit_ctx * jit)2082 static int zend_jit_invalid_this_stub(zend_jit_ctx *jit)
2083 {
2084 	ir_CALL_2(IR_VOID,
2085 		ir_CONST_FUNC_PROTO(zend_throw_error,
2086 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2087 		IR_NULL,
2088 		ir_CONST_ADDR("Using $this when not in object context"));
2089 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2090 	return 1;
2091 }
2092 
zend_jit_undefined_function_stub(zend_jit_ctx * jit)2093 static int zend_jit_undefined_function_stub(zend_jit_ctx *jit)
2094 {
2095 	// JIT: load EX(opline)
2096 	ir_ref ref = ir_LOAD_A(jit_FP(jit));
2097 	ir_ref arg3 = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.constant)));
2098 
2099 	if (sizeof(void*) == 8) {
2100 		arg3 = ir_LOAD_A(ir_ADD_A(ref, ir_SEXT_A(arg3)));
2101 	} else {
2102 		arg3 = ir_LOAD_A(arg3);
2103 	}
2104 	arg3 = ir_ADD_OFFSET(arg3, offsetof(zend_string, val));
2105 
2106 	ir_CALL_3(IR_VOID,
2107 		ir_CONST_FUNC_PROTO(zend_throw_error,
2108 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2109 		IR_NULL,
2110 		ir_CONST_ADDR("Call to undefined function %s()"),
2111 		arg3);
2112 
2113 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2114 
2115 	return 1;
2116 }
2117 
zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx * jit)2118 static int zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx *jit)
2119 {
2120 	ir_ref opline, ref, rx, if_eq, if_tmp;
2121 
2122 	// JIT: opline = EX(opline)
2123 	opline = ir_LOAD_A(jit_FP(jit));
2124 
2125 	// JIT: ZVAL_UNDEF(ZEND_CALL_VAR(RX, opline->result.var))
2126 	ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2127 	if (sizeof(void*) == 8) {
2128 		ref = ir_ZEXT_A(ref);
2129 	}
2130 	rx = jit_IP(jit);
2131 	jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(rx, ref), ir_CONST_U32(IS_UNDEF));
2132 
2133 	// last EX(call) frame may be delayed
2134 	// JIT: if (EX(call) == RX)
2135 	ref = ir_LOAD_A(jit_EX(call));
2136 	if_eq = ir_IF(ir_EQ(rx, ref));
2137 	ir_IF_FALSE(if_eq);
2138 
2139 	// JIT: RX->prev_execute_data == EX(call)
2140 	ir_STORE(jit_CALL(rx, prev_execute_data), ref);
2141 
2142 	// JIT: EX(call) = RX
2143 	ir_STORE(jit_EX(call), rx);
2144 	ir_MERGE_WITH_EMPTY_TRUE(if_eq);
2145 
2146 	// JIT: IP = opline
2147 	jit_STORE_IP(jit, opline);
2148 
2149 	// JIT: zend_cannot_pass_by_reference(opline->op2.num)
2150 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_cannot_pass_by_reference),
2151 		ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.num))));
2152 
2153 	// JIT: if (IP->op1_type == IS_TMP_VAR)
2154 	ref = ir_LOAD_U8(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1_type)));
2155 	if_tmp = ir_IF(ir_EQ(ref, ir_CONST_U8(IS_TMP_VAR)));
2156 	ir_IF_TRUE(if_tmp);
2157 
2158 	// JIT: zval_ptr_dtor(EX_VAR(IP->op1.var))
2159 	ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1.var)));
2160 	if (sizeof(void*) == 8) {
2161 		ref = ir_ZEXT_A(ref);
2162 	}
2163 	ref = ir_ADD_A(jit_FP(jit), ref);
2164 	jit_ZVAL_PTR_DTOR(jit,
2165 		ZEND_ADDR_REF_ZVAL(ref),
2166 		MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
2167 	ir_MERGE_WITH_EMPTY_FALSE(if_tmp);
2168 
2169 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2170 
2171 	return 1;
2172 }
2173 
zend_jit_icall_throw_stub(zend_jit_ctx * jit)2174 static int zend_jit_icall_throw_stub(zend_jit_ctx *jit)
2175 {
2176 	ir_ref ip, if_set;
2177 
2178 	// JIT: zend_rethrow_exception(zend_execute_data *execute_data)
2179 	// JIT: if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
2180 	jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2181 	ip = jit_IP(jit);
2182 	if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2183 		ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2184 	ir_IF_FALSE(if_set);
2185 
2186 	// JIT: EG(opline_before_exception) = opline;
2187 	ir_STORE(jit_EG(opline_before_exception), ip);
2188 	ir_MERGE_WITH_EMPTY_TRUE(if_set);
2189 
2190 	// JIT: opline = EG(exception_op);
2191 	jit_STORE_IP(jit, jit_EG(exception_op));
2192 
2193 	if (GCC_GLOBAL_REGS) {
2194 		ir_STORE(jit_EX(opline), jit_IP(jit));
2195 	}
2196 
2197 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2198 
2199 	return 1;
2200 }
2201 
zend_jit_leave_throw_stub(zend_jit_ctx * jit)2202 static int zend_jit_leave_throw_stub(zend_jit_ctx *jit)
2203 {
2204 	ir_ref ip, if_set;
2205 
2206 	// JIT: if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
2207 	jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2208 	ip = jit_IP(jit);
2209 	if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2210 		ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2211 	ir_IF_FALSE(if_set);
2212 
2213 	// JIT: EG(opline_before_exception) = opline;
2214 	ir_STORE(jit_EG(opline_before_exception), ip);
2215 	ir_MERGE_WITH_EMPTY_TRUE(if_set);
2216 
2217 	// JIT: opline = EG(exception_op);
2218 	jit_LOAD_IP(jit, jit_EG(exception_op));
2219 
2220 	if (GCC_GLOBAL_REGS) {
2221 		ir_STORE(jit_EX(opline), jit_IP(jit));
2222 
2223 		// JIT: HANDLE_EXCEPTION()
2224 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2225 	} else {
2226 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
2227 	}
2228 
2229 	return 1;
2230 }
2231 
zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx * jit)2232 static int zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx *jit)
2233 {
2234 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2235 		return 0;
2236 	}
2237 
2238 	ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_runtime_jit));
2239 	ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2240 	return 1;
2241 }
2242 
zend_jit_hybrid_profile_jit_stub(zend_jit_ctx * jit)2243 static int zend_jit_hybrid_profile_jit_stub(zend_jit_ctx *jit)
2244 {
2245 	ir_ref addr, func, run_time_cache, jit_extension;
2246 
2247 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2248 		return 0;
2249 	}
2250 
2251 	addr = ir_CONST_ADDR(&zend_jit_profile_counter),
2252 	ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2253 
2254 	func = ir_LOAD_A(jit_EX(func));
2255 	run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
2256 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2257 
2258 	if (zend_jit_profile_counter_rid) {
2259 		addr = ir_ADD_OFFSET(run_time_cache, zend_jit_profile_counter_rid * sizeof(void*));
2260 	} else {
2261 		addr = run_time_cache;
2262 	}
2263 	ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2264 
2265 	addr = ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_extension, orig_handler));
2266 	ir_IJMP(ir_LOAD_A(addr));
2267 
2268 	return 1;
2269 }
2270 
_zend_jit_hybrid_hot_counter_stub(zend_jit_ctx * jit,uint32_t cost)2271 static int _zend_jit_hybrid_hot_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2272 {
2273 	ir_ref func, jit_extension, addr, ref, if_overflow;
2274 
2275 	func = ir_LOAD_A(jit_EX(func));
2276 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2277 	addr = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, counter)));
2278 	ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2279 	ir_STORE(addr, ref);
2280 	if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2281 
2282 	ir_IF_TRUE_cold(if_overflow);
2283 	ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2284 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_hot_func),
2285 		jit_FP(jit),
2286 		jit_IP(jit));
2287 	ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2288 
2289 	ir_IF_FALSE(if_overflow);
2290 	ref = ir_SUB_A(jit_IP(jit),
2291 		ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, opcodes))));
2292 	ref = ir_DIV_A(ref, ir_CONST_ADDR(sizeof(zend_op) / sizeof(void*)));
2293 
2294 	addr = ir_ADD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, orig_handlers)),
2295 		ref);
2296 	ir_IJMP(ir_LOAD_A(addr));
2297 
2298 	return 1;
2299 }
2300 
zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx * jit)2301 static int zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx *jit)
2302 {
2303 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2304 		return 0;
2305 	}
2306 
2307 	return _zend_jit_hybrid_hot_counter_stub(jit,
2308 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2309 }
2310 
zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx * jit)2311 static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit)
2312 {
2313 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2314 		return 0;
2315 	}
2316 
2317 	return _zend_jit_hybrid_hot_counter_stub(jit,
2318 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2319 }
2320 
_zend_jit_orig_opline_handler(zend_jit_ctx * jit,ir_ref offset)2321 static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset)
2322 {
2323 	ir_ref addr;
2324 
2325 	if (GCC_GLOBAL_REGS) {
2326 		addr = ir_ADD_A(offset, jit_IP(jit));
2327 	} else {
2328 		addr = ir_ADD_A(offset, ir_LOAD_A(jit_EX(opline)));
2329 	}
2330 
2331 	return ir_LOAD_A(addr);
2332 }
2333 
zend_jit_orig_opline_handler(zend_jit_ctx * jit)2334 static ir_ref zend_jit_orig_opline_handler(zend_jit_ctx *jit)
2335 {
2336 	ir_ref func, jit_extension, offset;
2337 
2338 	func = ir_LOAD_A(jit_EX(func));
2339 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2340 	offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2341 	return _zend_jit_orig_opline_handler(jit, offset);
2342 }
2343 
_zend_jit_hybrid_trace_counter_stub(zend_jit_ctx * jit,uint32_t cost)2344 static int _zend_jit_hybrid_trace_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2345 {
2346 	ir_ref func, jit_extension, offset, addr, ref, if_overflow, ret, if_halt;
2347 
2348 	func = ir_LOAD_A(jit_EX(func));
2349 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2350 	offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2351 	addr = ir_LOAD_A(ir_ADD_OFFSET(ir_ADD_A(offset, jit_IP(jit)), offsetof(zend_op_trace_info, counter)));
2352 	ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2353 	ir_STORE(addr, ref);
2354 	if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2355 
2356 	ir_IF_TRUE_cold(if_overflow);
2357 	ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2358 	ret = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_trace_hot_root),
2359 		jit_FP(jit),
2360 		jit_IP(jit));
2361 	if_halt = ir_IF(ir_LT(ret, ir_CONST_I32(0)));
2362 	ir_IF_FALSE(if_halt);
2363 
2364 	ref = jit_EG(current_execute_data);
2365 	jit_STORE_FP(jit, ir_LOAD_A(ref));
2366 	ref = ir_LOAD_A(jit_EX(opline));
2367 	jit_STORE_IP(jit, ref);
2368 	ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2369 
2370 	ir_IF_FALSE(if_overflow);
2371 	ir_IJMP(_zend_jit_orig_opline_handler(jit, offset));
2372 
2373 	ir_IF_TRUE(if_halt);
2374 	ir_IJMP(ir_CONST_FC_FUNC(zend_jit_halt_op->handler));
2375 
2376 	return 1;
2377 }
2378 
zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx * jit)2379 static int zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx *jit)
2380 {
2381 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2382 		return 0;
2383 	}
2384 
2385 	return _zend_jit_hybrid_trace_counter_stub(jit,
2386 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2387 }
2388 
zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx * jit)2389 static int zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx *jit)
2390 {
2391 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2392 		return 0;
2393 	}
2394 
2395 	return _zend_jit_hybrid_trace_counter_stub(jit,
2396 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2397 }
2398 
zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx * jit)2399 static int zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx *jit)
2400 {
2401 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2402 		return 0;
2403 	}
2404 
2405 	return _zend_jit_hybrid_trace_counter_stub(jit,
2406 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2407 }
2408 
zend_jit_trace_halt_stub(zend_jit_ctx * jit)2409 static int zend_jit_trace_halt_stub(zend_jit_ctx *jit)
2410 {
2411 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2412 		ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_halt_op->handler));
2413 	} else if (GCC_GLOBAL_REGS) {
2414 		jit_STORE_IP(jit, IR_NULL);
2415 		ir_RETURN(IR_VOID);
2416 	} else {
2417 		ir_RETURN(ir_CONST_I32(-1)); // ZEND_VM_RETURN
2418 	}
2419 	return 1;
2420 }
2421 
zend_jit_trace_escape_stub(zend_jit_ctx * jit)2422 static int zend_jit_trace_escape_stub(zend_jit_ctx *jit)
2423 {
2424 	if (GCC_GLOBAL_REGS) {
2425 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2426 	} else {
2427 		ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2428 	}
2429 
2430 	return 1;
2431 }
2432 
zend_jit_trace_exit_stub(zend_jit_ctx * jit)2433 static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
2434 {
2435 	ir_ref ref, ret, if_zero, addr;
2436 
2437 	if (GCC_GLOBAL_REGS) {
2438 		// EX(opline) = opline
2439 		ir_STORE(jit_EX(opline), jit_IP(jit));
2440 	}
2441 
2442 	ret = ir_EXITCALL(ir_CONST_FC_FUNC(zend_jit_trace_exit));
2443 
2444 	if_zero = ir_IF(ir_EQ(ret, ir_CONST_I32(0)));
2445 
2446 	ir_IF_TRUE(if_zero);
2447 
2448 	if (GCC_GLOBAL_REGS) {
2449 		ref = jit_EG(current_execute_data);
2450 		jit_STORE_FP(jit, ir_LOAD_A(ref));
2451 		ref = ir_LOAD_A(jit_EX(opline));
2452 		jit_STORE_IP(jit, ref);
2453 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2454 	} else {
2455 		ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2456 	}
2457 
2458 	ir_IF_FALSE(if_zero);
2459 
2460 	ir_GUARD(ir_GE(ret, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2461 
2462 	ref = jit_EG(current_execute_data);
2463 	jit_STORE_FP(jit, ir_LOAD_A(ref));
2464 
2465 	if (GCC_GLOBAL_REGS) {
2466 		ref = ir_LOAD_A(jit_EX(opline));
2467 		jit_STORE_IP(jit, ref);
2468 	}
2469 
2470 	// check for interrupt (try to avoid this ???)
2471 	zend_jit_check_timeout(jit, NULL, NULL);
2472 
2473 	addr = zend_jit_orig_opline_handler(jit);
2474 	if (GCC_GLOBAL_REGS) {
2475 		ir_TAILCALL(IR_VOID, addr);
2476 	} else {
2477 #if defined(IR_TARGET_X86)
2478 		addr = ir_CAST_FC_FUNC(addr);
2479 #endif
2480 		ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
2481 		ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2482 		ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2483 	}
2484 
2485 	return 1;
2486 }
2487 
zend_jit_undefined_offset_stub(zend_jit_ctx * jit)2488 static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit)
2489 {
2490 	if (GCC_GLOBAL_REGS) {
2491 		ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key));
2492 	} else {
2493 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit));
2494 	}
2495 
2496 	return 1;
2497 }
2498 
zend_jit_undefined_key_stub(zend_jit_ctx * jit)2499 static int zend_jit_undefined_key_stub(zend_jit_ctx *jit)
2500 {
2501 	if (GCC_GLOBAL_REGS) {
2502 		ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key));
2503 	} else {
2504 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit));
2505 	}
2506 
2507 	return 1;
2508 }
2509 
zend_jit_cannot_add_element_stub(zend_jit_ctx * jit)2510 static int zend_jit_cannot_add_element_stub(zend_jit_ctx *jit)
2511 {
2512 	ir_ref opline = ir_LOAD_A(jit_EX(opline));
2513 	ir_ref ref, if_result_used;
2514 
2515 	if_result_used = ir_IF(ir_AND_U8(
2516 		ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, result_type))),
2517 		ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2518 	ir_IF_TRUE(if_result_used);
2519 
2520 	ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2521 	if (sizeof(void*) == 8) {
2522 		ref = ir_ZEXT_A(ref);
2523 	}
2524 	jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_UNDEF));
2525 	ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2526 
2527 	ir_CALL_2(IR_VOID,
2528 		ir_CONST_FUNC_PROTO(zend_throw_error,
2529 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2530 		IR_NULL,
2531 		ir_CONST_ADDR("Cannot add element to the array as the next element is already occupied"));
2532 	ir_RETURN(IR_VOID);
2533 
2534 	return 1;
2535 }
2536 
zend_jit_assign_const_stub(zend_jit_ctx * jit)2537 static int zend_jit_assign_const_stub(zend_jit_ctx *jit)
2538 {
2539 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2540 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2541 
2542 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2543 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2544 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2545 
2546 	if (!zend_jit_assign_to_variable(
2547 			jit, NULL,
2548 			var_addr, var_addr, -1, -1,
2549 			IS_CONST, val_addr, val_info,
2550 			0, 0, 0)) {
2551 		return 0;
2552 	}
2553 	ir_RETURN(IR_VOID);
2554 	return 1;
2555 }
2556 
zend_jit_assign_tmp_stub(zend_jit_ctx * jit)2557 static int zend_jit_assign_tmp_stub(zend_jit_ctx *jit)
2558 {
2559 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2560 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2561 
2562 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2563 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2564 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2565 
2566 	if (!zend_jit_assign_to_variable(
2567 			jit, NULL,
2568 			var_addr, var_addr, -1, -1,
2569 			IS_TMP_VAR, val_addr, val_info,
2570 			0, 0, 0)) {
2571 		return 0;
2572 	}
2573 	ir_RETURN(IR_VOID);
2574 	return 1;
2575 }
2576 
zend_jit_assign_var_stub(zend_jit_ctx * jit)2577 static int zend_jit_assign_var_stub(zend_jit_ctx *jit)
2578 {
2579 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2580 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2581 
2582 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2583 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2584 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2585 
2586 	if (!zend_jit_assign_to_variable(
2587 			jit, NULL,
2588 			var_addr, var_addr, -1, -1,
2589 			IS_VAR, val_addr, val_info,
2590 			0, 0, 0)) {
2591 		return 0;
2592 	}
2593 	ir_RETURN(IR_VOID);
2594 	return 1;
2595 }
2596 
zend_jit_assign_cv_noref_stub(zend_jit_ctx * jit)2597 static int zend_jit_assign_cv_noref_stub(zend_jit_ctx *jit)
2598 {
2599 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2600 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2601 
2602 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2603 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2604 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2605 
2606 	if (!zend_jit_assign_to_variable(
2607 			jit, NULL,
2608 			var_addr, var_addr, -1, -1,
2609 			IS_CV, val_addr, val_info,
2610 			0, 0, 0)) {
2611 		return 0;
2612 	}
2613 	ir_RETURN(IR_VOID);
2614 	return 1;
2615 }
2616 
zend_jit_new_array_stub(zend_jit_ctx * jit)2617 static int zend_jit_new_array_stub(zend_jit_ctx *jit)
2618 {
2619 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2620 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2621 	ir_ref ref = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_zend_new_array_0));
2622 
2623 	jit_set_Z_PTR(jit, var_addr, ref);
2624 	jit_set_Z_TYPE_INFO(jit, var_addr, IS_ARRAY_EX);
2625 	ir_RETURN(ref);
2626 	return 1;
2627 }
2628 
zend_jit_assign_cv_stub(zend_jit_ctx * jit)2629 static int zend_jit_assign_cv_stub(zend_jit_ctx *jit)
2630 {
2631 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2632 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2633 
2634 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2635 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2636 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2637 
2638 	if (!zend_jit_assign_to_variable(
2639 			jit, NULL,
2640 			var_addr, var_addr, -1, -1,
2641 			IS_CV, val_addr, val_info,
2642 			0, 0, 0)) {
2643 		return 0;
2644 	}
2645 	ir_RETURN(IR_VOID);
2646 	return 1;
2647 }
2648 
zend_jit_init_ctx(zend_jit_ctx * jit,uint32_t flags)2649 static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2650 {
2651 #if defined (__CET__) && (__CET__ & 1) != 0
2652 	flags |= IR_GEN_ENDBR;
2653 #endif
2654 	flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
2655 
2656 	ir_init(&jit->ctx, flags, 256, 1024);
2657 	jit->ctx.ret_type = -1;
2658 
2659 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2660 	jit->ctx.mflags |= default_mflags;
2661 	if (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX) {
2662 		jit->ctx.mflags |= IR_X86_AVX;
2663 	}
2664 #elif defined(IR_TARGET_AARCH64)
2665 	jit->ctx.get_veneer = zend_jit_get_veneer;
2666 	jit->ctx.set_veneer = zend_jit_set_veneer;
2667 #endif
2668 
2669 	jit->ctx.fixed_regset = (1<<ZREG_FP) | (1<<ZREG_IP);
2670 	if (!(flags & IR_FUNCTION)) {
2671 		jit->ctx.flags |= IR_NO_STACK_COMBINE;
2672 		if (zend_jit_vm_kind == ZEND_VM_KIND_CALL) {
2673 			jit->ctx.flags |= IR_FUNCTION;
2674 			/* Stack must be 16 byte aligned */
2675 			/* TODO: select stack size ??? */
2676 #if defined(IR_TARGET_AARCH64)
2677 			jit->ctx.flags |= IR_USE_FRAME_POINTER;
2678 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 16; /* 10 saved registers and 6 spill slots (8 bytes) */
2679 #elif defined(_WIN64)
2680 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 8 saved registers and 3 spill slots (8 bytes) */
2681 #elif defined(IR_TARGET_X86_64)
2682 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 9;  /* 6 saved registers and 3 spill slots (8 bytes) */
2683 #else /* IR_TARGET_x86 */
2684 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */
2685 #endif
2686 			if (GCC_GLOBAL_REGS) {
2687 				jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<<ZREG_FP) | (1<<ZREG_IP));
2688 			} else {
2689 				jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED;
2690 //#ifdef _WIN64
2691 //				jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
2692 //#endif
2693 			}
2694 			jit->ctx.fixed_call_stack_size = 16;
2695 		} else {
2696 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2697 			jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
2698 			if (jit->ctx.fixed_stack_red_zone > 16) {
2699 				jit->ctx.fixed_stack_frame_size = jit->ctx.fixed_stack_red_zone - 16;
2700 				jit->ctx.fixed_call_stack_size = 16;
2701 			}
2702 			jit->ctx.flags |= IR_MERGE_EMPTY_ENTRIES;
2703 #else
2704 			jit->ctx.fixed_stack_red_zone = 0;
2705 			jit->ctx.fixed_stack_frame_size = 32; /* 4 spill slots (8 bytes) or 8 spill slots (4 bytes) */
2706 			jit->ctx.fixed_call_stack_size = 16;
2707 #endif
2708 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2709 			jit->ctx.fixed_regset |= (1<<IR_REG_FP); /* prevent %rbp (%r5) usage */
2710 #endif
2711 		}
2712 	}
2713 
2714 	jit->ctx.snapshot_create = (ir_snapshot_create_t)jit_SNAPSHOT;
2715 
2716 	jit->op_array = NULL;
2717 	jit->current_op_array = NULL;
2718 	jit->ssa = NULL;
2719 	jit->name = NULL;
2720 	jit->last_valid_opline = NULL;
2721 	jit->use_last_valid_opline = 0;
2722 	jit->track_last_valid_opline = 0;
2723 	jit->reuse_ip = 0;
2724 	jit->delayed_call_level = 0;
2725 	delayed_call_chain = 0;
2726 	jit->b = -1;
2727 #ifdef ZTS
2728 	jit->tls = IR_UNUSED;
2729 #endif
2730 	jit->fp = IR_UNUSED;
2731 	jit->trace_loop_ref = IR_UNUSED;
2732 	jit->return_inputs = IR_UNUSED;
2733 	jit->bb_start_ref = NULL;
2734 	jit->bb_predecessors = NULL;
2735 	jit->bb_edges = NULL;
2736 	jit->trace = NULL;
2737 	jit->ra = NULL;
2738 	jit->delay_var = -1;
2739 	jit->delay_refs = NULL;
2740 	jit->eg_exception_addr = 0;
2741 	zend_hash_init(&jit->addr_hash, 64, NULL, NULL, 0);
2742 	memset(jit->stub_addr, 0, sizeof(jit->stub_addr));
2743 
2744 	ir_START();
2745 }
2746 
zend_jit_free_ctx(zend_jit_ctx * jit)2747 static int zend_jit_free_ctx(zend_jit_ctx *jit)
2748 {
2749 	if (jit->name) {
2750 		zend_string_release(jit->name);
2751 	}
2752 	zend_hash_destroy(&jit->addr_hash);
2753 	ir_free(&jit->ctx);
2754 	return 1;
2755 }
2756 
zend_jit_ir_compile(ir_ctx * ctx,size_t * size,const char * name)2757 static void *zend_jit_ir_compile(ir_ctx *ctx, size_t *size, const char *name)
2758 {
2759 	void *entry;
2760 	ir_code_buffer code_buffer;
2761 
2762 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_SRC) {
2763 		if (name) fprintf(stderr, "%s: ; after folding\n", name);
2764 		ir_save(ctx, 0, stderr);
2765 	}
2766 
2767 #if ZEND_DEBUG
2768 	ir_check(ctx);
2769 #endif
2770 
2771 	ir_build_def_use_lists(ctx);
2772 
2773 #if ZEND_DEBUG
2774 	ir_check(ctx);
2775 #endif
2776 
2777 #if 1
2778 	ir_sccp(ctx);
2779 #endif
2780 
2781 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCCP) {
2782 		if (name) fprintf(stderr, "%s: ; after SCCP\n", name);
2783 		ir_save(ctx, 0, stderr);
2784 	}
2785 
2786 	ir_build_cfg(ctx);
2787 	ir_build_dominators_tree(ctx);
2788 	ir_find_loops(ctx);
2789 
2790 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_CFG) {
2791 		if (name) fprintf(stderr, "%s: ; after CFG\n", name);
2792 		ir_save(ctx, IR_SAVE_CFG, stderr);
2793 	}
2794 
2795 	ir_gcm(ctx);
2796 
2797 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_GCM) {
2798 		if (name) fprintf(stderr, "%s: ; after GCM\n", name);
2799 		ir_save(ctx, IR_SAVE_CFG|IR_SAVE_CFG_MAP, stderr);
2800 	}
2801 
2802 	ir_schedule(ctx);
2803 
2804 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE) {
2805 		if (name) fprintf(stderr, "%s: ; after schedule\n", name);
2806 		ir_save(ctx, IR_SAVE_CFG, stderr);
2807 	}
2808 
2809 	ir_match(ctx);
2810 #if !defined(IR_TARGET_AARCH64)
2811 	ctx->flags &= ~IR_USE_FRAME_POINTER; /* don't use FRAME_POINTER even with ALLOCA, TODO: cleanup this ??? */
2812 #endif
2813 	ir_assign_virtual_registers(ctx);
2814 	ir_compute_live_ranges(ctx);
2815 	ir_coalesce(ctx);
2816 	ir_reg_alloc(ctx);
2817 
2818 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_REGS) {
2819 		if (name) fprintf(stderr, "%s: ; after register allocation\n", name);
2820 		ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2821 		ir_dump_live_ranges(ctx, stderr);
2822 	}
2823 
2824 	ir_schedule_blocks(ctx);
2825 
2826 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
2827 		if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_CODEGEN) {
2828 			if (name) fprintf(stderr, "%s: ; codegen\n", name);
2829 			ir_dump_codegen(ctx, stderr);
2830 		} else {
2831 			if (name) fprintf(stderr, "%s: ; final\n", name);
2832 			ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2833 		}
2834 	}
2835 
2836 #if ZEND_DEBUG
2837 	ir_check(ctx);
2838 #endif
2839 
2840 	code_buffer.start = dasm_buf;
2841 	code_buffer.end = dasm_end;
2842 	code_buffer.pos = *dasm_ptr;
2843 	ctx->code_buffer = &code_buffer;
2844 
2845 	entry = ir_emit_code(ctx, size);
2846 
2847 	*dasm_ptr = code_buffer.pos;
2848 
2849 #if defined(IR_TARGET_AARCH64)
2850 	if (ctx->flags2 & IR_HAS_VENEERS) {
2851 		zend_jit_commit_veneers();
2852 	}
2853 #endif
2854 
2855 	return entry;
2856 }
2857 
zend_jit_setup_stubs(void)2858 static void zend_jit_setup_stubs(void)
2859 {
2860 	zend_jit_ctx jit;
2861 	void *entry;
2862 	size_t size;
2863 	uint32_t i;
2864 
2865 	for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
2866 		zend_jit_init_ctx(&jit, zend_jit_stubs[i].flags);
2867 
2868 		if (!zend_jit_stubs[i].stub(&jit)) {
2869 			zend_jit_free_ctx(&jit);
2870 			zend_jit_stub_handlers[i] = NULL;
2871 			continue;
2872 		}
2873 
2874 		entry = zend_jit_ir_compile(&jit.ctx, &size, zend_jit_stubs[i].name);
2875 		if (!entry) {
2876 			zend_jit_free_ctx(&jit);
2877 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile stub");
2878 		}
2879 
2880 		zend_jit_stub_handlers[i] = entry;
2881 
2882 		if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2883 #ifdef HAVE_CAPSTONE
2884 			if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
2885 				ir_disasm_add_symbol(zend_jit_stubs[i].name, (uintptr_t)entry, size);
2886 			}
2887 			if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_STUBS) {
2888 				ir_disasm(zend_jit_stubs[i].name,
2889 					entry, size, (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0, &jit.ctx, stderr);
2890 			}
2891 #endif
2892 #ifndef _WIN32
2893 			if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
2894 //				ir_mem_unprotect(entry, size);
2895 				ir_gdb_register(zend_jit_stubs[i].name, entry, size, 0, 0);
2896 //				ir_mem_protect(entry, size);
2897 			}
2898 
2899 			if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2900 				ir_perf_map_register(zend_jit_stubs[i].name, entry, size);
2901 				if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
2902 					ir_perf_jitdump_register(zend_jit_stubs[i].name, entry, size);
2903 				}
2904 			}
2905 #endif
2906 		}
2907 		zend_jit_free_ctx(&jit);
2908 	}
2909 }
2910 
2911 #define REGISTER_HELPER(n)  \
2912 	ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)n, sizeof(void*));
2913 #define REGISTER_DATA(n)  \
2914 	ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)&n, sizeof(n));
2915 
zend_jit_setup_disasm(void)2916 static void zend_jit_setup_disasm(void)
2917 {
2918 #ifdef HAVE_CAPSTONE
2919 	ir_disasm_init();
2920 
2921 	if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
2922 		zend_op opline;
2923 
2924 		memset(&opline, 0, sizeof(opline));
2925 
2926 		opline.opcode = ZEND_DO_UCALL;
2927 		opline.result_type = IS_UNUSED;
2928 		zend_vm_set_opcode_handler(&opline);
2929 		ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2930 
2931 		opline.opcode = ZEND_DO_UCALL;
2932 		opline.result_type = IS_VAR;
2933 		zend_vm_set_opcode_handler(&opline);
2934 		ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2935 
2936 		opline.opcode = ZEND_DO_FCALL_BY_NAME;
2937 		opline.result_type = IS_UNUSED;
2938 		zend_vm_set_opcode_handler(&opline);
2939 		ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2940 
2941 		opline.opcode = ZEND_DO_FCALL_BY_NAME;
2942 		opline.result_type = IS_VAR;
2943 		zend_vm_set_opcode_handler(&opline);
2944 		ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2945 
2946 		opline.opcode = ZEND_DO_FCALL;
2947 		opline.result_type = IS_UNUSED;
2948 		zend_vm_set_opcode_handler(&opline);
2949 		ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2950 
2951 		opline.opcode = ZEND_DO_FCALL;
2952 		opline.result_type = IS_VAR;
2953 		zend_vm_set_opcode_handler(&opline);
2954 		ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2955 
2956 		opline.opcode = ZEND_RETURN;
2957 		opline.op1_type = IS_CONST;
2958 		zend_vm_set_opcode_handler(&opline);
2959 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2960 
2961 		opline.opcode = ZEND_RETURN;
2962 		opline.op1_type = IS_TMP_VAR;
2963 		zend_vm_set_opcode_handler(&opline);
2964 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2965 
2966 		opline.opcode = ZEND_RETURN;
2967 		opline.op1_type = IS_VAR;
2968 		zend_vm_set_opcode_handler(&opline);
2969 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2970 
2971 		opline.opcode = ZEND_RETURN;
2972 		opline.op1_type = IS_CV;
2973 		zend_vm_set_opcode_handler(&opline);
2974 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2975 
2976 		ir_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
2977 	}
2978 
2979 	REGISTER_DATA(zend_jit_profile_counter);
2980 
2981 	REGISTER_HELPER(zend_runtime_jit);
2982 	REGISTER_HELPER(zend_jit_hot_func);
2983 	REGISTER_HELPER(zend_jit_trace_hot_root);
2984 	REGISTER_HELPER(zend_jit_trace_exit);
2985 
2986 	REGISTER_HELPER(zend_jit_array_free);
2987 	REGISTER_HELPER(zend_jit_undefined_op_helper);
2988 	REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
2989 	REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
2990 	REGISTER_HELPER(zend_jit_post_inc_typed_ref);
2991 	REGISTER_HELPER(zend_jit_post_dec_typed_ref);
2992 	REGISTER_HELPER(zend_jit_pre_inc);
2993 	REGISTER_HELPER(zend_jit_pre_dec);
2994 	REGISTER_HELPER(zend_jit_add_arrays_helper);
2995 	REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
2996 	REGISTER_HELPER(zend_jit_fast_concat_helper);
2997 	REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
2998 	REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
2999 	REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
3000 	REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
3001 	REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
3002 	REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
3003 	REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
3004 	REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
3005 	REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
3006 	REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
3007 	REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
3008 	REGISTER_HELPER(zend_jit_check_constant);
3009 	REGISTER_HELPER(zend_jit_get_constant);
3010 	REGISTER_HELPER(zend_jit_int_extend_stack_helper);
3011 	REGISTER_HELPER(zend_jit_extend_stack_helper);
3012 	REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
3013 	REGISTER_HELPER(zend_jit_find_func_helper);
3014 	REGISTER_HELPER(zend_jit_find_ns_func_helper);
3015 	REGISTER_HELPER(zend_jit_jmp_frameless_helper);
3016 	REGISTER_HELPER(zend_jit_unref_helper);
3017 	REGISTER_HELPER(zend_jit_invalid_method_call);
3018 	REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
3019 	REGISTER_HELPER(zend_jit_find_method_helper);
3020 	REGISTER_HELPER(zend_jit_find_method_tmp_helper);
3021 	REGISTER_HELPER(zend_jit_push_static_method_call_frame);
3022 	REGISTER_HELPER(zend_jit_push_static_method_call_frame_tmp);
3023 	REGISTER_HELPER(zend_jit_find_class_helper);
3024 	REGISTER_HELPER(zend_jit_find_static_method_helper);
3025 	REGISTER_HELPER(zend_jit_push_this_method_call_frame);
3026 	REGISTER_HELPER(zend_jit_free_trampoline_helper);
3027 	REGISTER_HELPER(zend_jit_verify_return_slow);
3028 	REGISTER_HELPER(zend_jit_deprecated_helper);
3029 	REGISTER_HELPER(zend_jit_undefined_long_key);
3030 	REGISTER_HELPER(zend_jit_undefined_long_key_ex);
3031 	REGISTER_HELPER(zend_jit_undefined_string_key);
3032 	REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3033 	REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3034 	REGISTER_HELPER(zend_free_extra_named_params);
3035 	REGISTER_HELPER(zend_jit_free_call_frame);
3036 	REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3037 	REGISTER_HELPER(zend_jit_verify_arg_slow);
3038 	REGISTER_HELPER(zend_missing_arg_error);
3039 	REGISTER_HELPER(zend_jit_only_vars_by_reference);
3040 	REGISTER_HELPER(zend_jit_leave_func_helper);
3041 	REGISTER_HELPER(zend_jit_leave_nested_func_helper);
3042 	REGISTER_HELPER(zend_jit_leave_top_func_helper);
3043 	REGISTER_HELPER(zend_jit_fetch_global_helper);
3044 	REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3045 	REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3046 	REGISTER_HELPER(zend_jit_hash_lookup_rw);
3047 	REGISTER_HELPER(zend_jit_symtable_find);
3048 	REGISTER_HELPER(zend_jit_symtable_lookup_w);
3049 	REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3050 	REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3051 	REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3052 	REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3053 	REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3054 	REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3055 	REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3056 	REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3057 	REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3058 	REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3059 	REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3060 	REGISTER_HELPER(zend_jit_invalid_array_access);
3061 	REGISTER_HELPER(zend_jit_zval_array_dup);
3062 	REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3063 	REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3064 	REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3065 	REGISTER_HELPER(zend_jit_isset_dim_helper);
3066 	REGISTER_HELPER(zend_jit_assign_dim_helper);
3067 	REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3068 	REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3069 	REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3070 	REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3071 	REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3072 	REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3073 	REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3074 	REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3075 	REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3076 	REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3077 	REGISTER_HELPER(zend_jit_check_array_promotion);
3078 	REGISTER_HELPER(zend_jit_create_typed_ref);
3079 	REGISTER_HELPER(zend_jit_invalid_property_write);
3080 	REGISTER_HELPER(zend_jit_invalid_property_read);
3081 	REGISTER_HELPER(zend_jit_extract_helper);
3082 	REGISTER_HELPER(zend_jit_invalid_property_assign);
3083 	REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3084 	REGISTER_HELPER(zend_jit_assign_obj_helper);
3085 	REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3086 	REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3087 	REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3088 	REGISTER_HELPER(zend_jit_invalid_property_incdec);
3089 	REGISTER_HELPER(zend_jit_inc_typed_prop);
3090 	REGISTER_HELPER(zend_jit_dec_typed_prop);
3091 	REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3092 	REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3093 	REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3094 	REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3095 	REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3096 	REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3097 	REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3098 	REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3099 	REGISTER_HELPER(zend_jit_uninit_static_prop);
3100 	REGISTER_HELPER(zend_jit_rope_end);
3101 	REGISTER_HELPER(zend_fcall_interrupt);
3102 
3103 #ifndef ZTS
3104 	REGISTER_DATA(EG(current_execute_data));
3105 	REGISTER_DATA(EG(exception));
3106 	REGISTER_DATA(EG(opline_before_exception));
3107 	REGISTER_DATA(EG(vm_interrupt));
3108 	REGISTER_DATA(EG(timed_out));
3109 	REGISTER_DATA(EG(uninitialized_zval));
3110 	REGISTER_DATA(EG(zend_constants));
3111 	REGISTER_DATA(EG(jit_trace_num));
3112 	REGISTER_DATA(EG(vm_stack_top));
3113 	REGISTER_DATA(EG(vm_stack_end));
3114 	REGISTER_DATA(EG(exception_op));
3115 	REGISTER_DATA(EG(symbol_table));
3116 
3117 	REGISTER_DATA(CG(map_ptr_base));
3118 #endif
3119 #endif
3120 }
3121 
zend_jit_calc_trace_prologue_size(void)3122 static void zend_jit_calc_trace_prologue_size(void)
3123 {
3124 	zend_jit_ctx jit_ctx;
3125 	zend_jit_ctx *jit = &jit_ctx;
3126 	void *entry;
3127 	size_t size;
3128 
3129 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
3130 
3131 	if (!GCC_GLOBAL_REGS) {
3132 		ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3133 		jit_STORE_FP(jit, ref);
3134 		jit->ctx.flags |= IR_FASTCALL_FUNC;
3135 	}
3136 
3137 	ir_UNREACHABLE();
3138 
3139 	entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3140 	zend_jit_free_ctx(jit);
3141 
3142 	if (!entry) {
3143 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3144 	}
3145 
3146 	zend_jit_trace_prologue_size = size;
3147 }
3148 
3149 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3150 static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3151 
3152 typedef struct _Unwind_Context _Unwind_Context;
3153 typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3154 extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
3155 extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
3156 
3157 typedef struct _zend_jit_unwind_arg {
3158 	int cnt;
3159 	uintptr_t cfa[3];
3160 } zend_jit_unwind_arg;
3161 
zend_jit_unwind_cb(_Unwind_Context * ctx,void * a)3162 static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3163 {
3164 	zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
3165 	arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3166 	arg->cnt++;
3167 	if (arg->cnt == 3) {
3168 		return 5; // _URC_END_OF_STACK
3169 	}
3170 	return 0; // _URC_NO_REASON;
3171 }
3172 
zend_jit_touch_vm_stack_data(void * vm_stack_data)3173 static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3174 {
3175 	zend_jit_unwind_arg arg;
3176 
3177 	memset(&arg, 0, sizeof(arg));
3178 	_Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3179 	if (arg.cnt == 3) {
3180 		zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3181 	}
3182 }
3183 
3184 extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3185 
zend_jit_set_sp_adj_vm(void)3186 static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3187 {
3188 	void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3189 
3190 	orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3191 	zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3192 	execute_ex(NULL);                                        // set sp_adj[SP_ADJ_VM]
3193 	zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3194 }
3195 #endif
3196 
zend_jit_setup(void)3197 static void zend_jit_setup(void)
3198 {
3199 #if defined(IR_TARGET_X86)
3200 	if (!zend_cpu_supports_sse2()) {
3201 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3202 	}
3203 #endif
3204 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3205 	allowed_opt_flags = 0;
3206 	if (zend_cpu_supports_avx()) {
3207 		allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3208 	}
3209 # if defined(PHP_HAVE_BUILTIN_CPU_SUPPORTS) && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
3210 	if (zend_cpu_supports_cldemote()) {
3211 		default_mflags |= IR_X86_CLDEMOTE;
3212 	}
3213 # endif
3214 #endif
3215 #ifdef ZTS
3216 #if defined(IR_TARGET_AARCH64)
3217 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3218 
3219 # ifdef __FreeBSD__
3220 	if (tsrm_ls_cache_tcb_offset == 0) {
3221 		TLSDescriptor **where;
3222 
3223 		__asm__(
3224 			"adrp %0, :tlsdesc:_tsrm_ls_cache\n"
3225 			"add %0, %0, :tlsdesc_lo12:_tsrm_ls_cache\n"
3226 			: "=r" (where));
3227 		/* See https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst
3228 		 * section "Relocations for thread-local storage".
3229 		 * The first entry holds a pointer to the variable's TLS descriptor resolver function and the second entry holds
3230 		 * a platform-specific offset or pointer. */
3231 		TLSDescriptor *tlsdesc = where[1];
3232 
3233 		tsrm_tls_offset = tlsdesc->offset;
3234 		/* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/22ca6db50f4e6bd75a141f57cf953d8de6531a06/lib/libc/gen/tls.c#L88) */
3235 		tsrm_tls_index = (tlsdesc->index + 1) * 8;
3236 	}
3237 # else
3238 	ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0);
3239 # endif
3240 # elif defined(_WIN64)
3241 	tsrm_tls_index  = _tls_index * sizeof(void*);
3242 
3243 	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3244 	/* Probably, it might be better solution */
3245 	do {
3246 		void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
3247 		void *val = _tsrm_ls_cache;
3248 		size_t offset = 0;
3249 		size_t size = (char*)&_tls_end - (char*)&_tls_start;
3250 
3251 		while (offset < size) {
3252 			if (*tls_mem == val) {
3253 				tsrm_tls_offset = offset;
3254 				break;
3255 			}
3256 			tls_mem++;
3257 			offset += sizeof(void*);
3258 		}
3259 		if (offset >= size) {
3260 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3261 		}
3262 	} while(0);
3263 # elif defined(ZEND_WIN32)
3264 	tsrm_tls_index  = _tls_index * sizeof(void*);
3265 
3266 	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3267 	/* Probably, it might be better solution */
3268 	do {
3269 		void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
3270 		void *val = _tsrm_ls_cache;
3271 		size_t offset = 0;
3272 		size_t size = (char*)&_tls_end - (char*)&_tls_start;
3273 
3274 		while (offset < size) {
3275 			if (*tls_mem == val) {
3276 				tsrm_tls_offset = offset;
3277 				break;
3278 			}
3279 			tls_mem++;
3280 			offset += sizeof(void*);
3281 		}
3282 		if (offset >= size) {
3283 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3284 		}
3285 	} while(0);
3286 # elif defined(__APPLE__) && defined(__x86_64__)
3287 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3288 	if (tsrm_ls_cache_tcb_offset == 0) {
3289 		size_t *ti;
3290 		__asm__(
3291 			"leaq __tsrm_ls_cache(%%rip),%0"
3292 			: "=r" (ti));
3293 		tsrm_tls_offset = ti[2];
3294 		tsrm_tls_index = ti[1] * 8;
3295 	}
3296 # elif defined(__GNUC__) && defined(__x86_64__)
3297 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3298 	if (tsrm_ls_cache_tcb_offset == 0) {
3299 #if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && \
3300 	!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3301 		size_t ret;
3302 
3303 		asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
3304 			: "=r" (ret));
3305 		tsrm_ls_cache_tcb_offset = ret;
3306 #elif defined(__MUSL__)
3307 		size_t *ti;
3308 
3309 		__asm__(
3310 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3311 			: "=a" (ti));
3312 		tsrm_tls_offset = ti[1];
3313 		tsrm_tls_index = ti[0] * 8;
3314 #elif defined(__FreeBSD__)
3315 		size_t *ti;
3316 
3317 		__asm__(
3318 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3319 			: "=a" (ti));
3320 		tsrm_tls_offset = ti[1];
3321 		/* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/bf56e8b9c8639ac4447d223b83cdc128107cc3cd/libexec/rtld-elf/rtld.c#L5260) */
3322 		tsrm_tls_index = (ti[0] + 1) * 8;
3323 #else
3324 		size_t *ti;
3325 
3326 		__asm__(
3327 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3328 			: "=a" (ti));
3329 		tsrm_tls_offset = ti[1];
3330 		tsrm_tls_index = ti[0] * 16;
3331 #endif
3332 	}
3333 # elif defined(__GNUC__) && defined(__i386__)
3334 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3335 	if (tsrm_ls_cache_tcb_offset == 0) {
3336 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3337 		size_t ret;
3338 
3339 		asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
3340 			: "=a" (ret));
3341 		tsrm_ls_cache_tcb_offset = ret;
3342 #else
3343 		size_t *ti, _ebx, _ecx, _edx;
3344 
3345 		__asm__(
3346 			"call 1f\n"
3347 			".subsection 1\n"
3348 			"1:\tmovl (%%esp), %%ebx\n\t"
3349 			"ret\n"
3350 			".previous\n\t"
3351 			"addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
3352 			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
3353 			"call ___tls_get_addr@plt\n\t"
3354 			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
3355 			: "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
3356 		tsrm_tls_offset = ti[1];
3357 		tsrm_tls_index = ti[0] * 8;
3358 #endif
3359 	}
3360 # endif
3361 #endif
3362 
3363 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3364 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3365 		zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3366 	}
3367 #endif
3368 
3369 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3370 		zend_jit_setup_disasm();
3371 	}
3372 
3373 #ifndef _WIN32
3374 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3375 		ir_perf_jitdump_open();
3376 	}
3377 
3378 #endif
3379 	zend_long debug = JIT_G(debug);
3380 	if (!(debug & ZEND_JIT_DEBUG_ASM_STUBS)) {
3381 		JIT_G(debug) &= ~(ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_FINAL|
3382 			ZEND_JIT_DEBUG_IR_CODEGEN|
3383 			ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_CFG|ZEND_JIT_DEBUG_IR_AFTER_GCM|
3384 			ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS);
3385 	}
3386 
3387 	zend_jit_calc_trace_prologue_size();
3388 	zend_jit_setup_stubs();
3389 	JIT_G(debug) = debug;
3390 }
3391 
zend_jit_shutdown_ir(void)3392 static void zend_jit_shutdown_ir(void)
3393 {
3394 #ifndef _WIN32
3395 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3396 		ir_perf_jitdump_close();
3397 	}
3398 	if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
3399 		ir_gdb_unregister_all();
3400 	}
3401 #endif
3402 #ifdef HAVE_CAPSTONE
3403 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3404 		ir_disasm_free();
3405 	}
3406 #endif
3407 }
3408 
3409 /* PHP control flow reconstruction helpers */
jit_IF_ex(zend_jit_ctx * jit,ir_ref condition,ir_ref true_block)3410 static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3411 {
3412 	ir_ref ref = ir_IF(condition);
3413 	/* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3414 	 *
3415 	 * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3416 	 * to start target block
3417 	 */
3418 	ir_set_op(&jit->ctx, ref, 3, true_block);
3419 	return ref;
3420 }
3421 
jit_IF_TRUE_FALSE_ex(zend_jit_ctx * jit,ir_ref if_ref,ir_ref true_block)3422 static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3423 {
3424 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3425 	ZEND_ASSERT(if_ref);
3426 	ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3427 	ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3428 	if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3429 		ir_IF_TRUE(if_ref);
3430 	} else {
3431 		ir_IF_FALSE(if_ref);
3432 	}
3433 }
3434 
_zend_jit_add_predecessor_ref(zend_jit_ctx * jit,int b,int pred,ir_ref ref)3435 static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3436 {
3437 	int i, *p;
3438 	zend_basic_block *bb;
3439 	ir_ref *r, header;
3440 
3441 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3442 	bb = &jit->ssa->cfg.blocks[b];
3443 	p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3444 	r = &jit->bb_edges[jit->bb_predecessors[b]];
3445 	for (i = 0; i < bb->predecessors_count; i++, p++, r++) {
3446 		if (*p == pred) {
3447 			ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3448 			header = jit->bb_start_ref[b];
3449 			if (header) {
3450 				/* this is back edge */
3451 				ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3452 				if (jit->ctx.ir_base[ref].op == IR_END) {
3453 					jit->ctx.ir_base[ref].op = IR_LOOP_END;
3454 				} else if (jit->ctx.ir_base[ref].op == IR_IF) {
3455 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3456 					ref = ir_LOOP_END();
3457 				} else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3458 					ir_BEGIN(ref);
3459 					ref = ir_LOOP_END();
3460 				} else {
3461 					ZEND_UNREACHABLE();
3462 				}
3463 				ir_MERGE_SET_OP(header, i + 1, ref);
3464 			}
3465 			*r = ref;
3466 			return;
3467 		}
3468 	}
3469 	ZEND_UNREACHABLE();
3470 }
3471 
_zend_jit_merge_smart_branch_inputs(zend_jit_ctx * jit,uint32_t true_label,uint32_t false_label,ir_ref true_inputs,ir_ref false_inputs)3472 static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3473                                                 uint32_t      true_label,
3474                                                 uint32_t      false_label,
3475                                                 ir_ref        true_inputs,
3476                                                 ir_ref        false_inputs)
3477 {
3478 	ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3479 
3480 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3481 	if (true_inputs) {
3482 		ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3483 		if (!jit->ctx.ir_base[true_inputs].op2) {
3484 			true_path = true_inputs;
3485 		} else {
3486 			ir_MERGE_list(true_inputs);
3487 			true_path = ir_END();
3488 		}
3489 	}
3490 	if (false_inputs) {
3491 		ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3492 		if (!jit->ctx.ir_base[false_inputs].op2) {
3493 			false_path = false_inputs;
3494 		} else {
3495 			ir_MERGE_list(false_inputs);
3496 			false_path = ir_END();
3497 		}
3498 	}
3499 
3500 	if (true_label == false_label && true_path && false_path) {
3501 		ir_MERGE_2(true_path, false_path);
3502 		_zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3503 	} else if (!true_path && !false_path) {
3504 		/* dead code */
3505 		true_path = ir_END();
3506 		_zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3507 	} else {
3508 		if (true_path) {
3509 			_zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3510 		}
3511 		if (false_path) {
3512 			_zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3513 		}
3514 	}
3515 
3516 	jit->b = -1;
3517 }
3518 
_zend_jit_fix_merges(zend_jit_ctx * jit)3519 static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3520 {
3521 	int i, count;
3522 	ir_ref j, k, n, *p, *q, *r;
3523 	ir_ref ref;
3524 	ir_insn *insn, *phi;
3525 
3526 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3527 	count = jit->ssa->cfg.blocks_count;
3528 	for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3529 		ref = *p;
3530 		if (ref) {
3531 			insn = &jit->ctx.ir_base[ref];
3532 			if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3533 				n = insn->inputs_count;
3534 				/* Remove IS_UNUSED inputs */
3535 				for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3536 					if (*q) {
3537 						if (q != r) {
3538 							*r = *q;
3539 							phi = insn + 1 + (n >> 2);
3540 							while (phi->op == IR_PI) {
3541 								phi++;
3542 							}
3543 							while (phi->op == IR_PHI) {
3544 								ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3545 								phi += 1 + ((n + 1) >> 2);
3546 							}
3547 						}
3548 						k++;
3549 						r++;
3550 					}
3551 				}
3552 				if (k != n) {
3553 					ir_ref n2, k2;
3554 
3555 					if (k <= 1) {
3556 						insn->op = IR_BEGIN;
3557 						insn->inputs_count = 0;
3558 					} else {
3559 						insn->inputs_count = k;
3560 					}
3561 					n2 = 1 + (n >> 2);
3562 					k2 = 1 + (k >> 2);
3563 					while (k2 != n2) {
3564 						(insn+k2)->optx = IR_NOP;
3565 						k2++;
3566 					}
3567 					phi = insn + 1 + (n >> 2);
3568 					while (phi->op == IR_PI) {
3569 						phi++;
3570 					}
3571 					while (phi->op == IR_PHI) {
3572 						if (k <= 1) {
3573 							phi->op = IR_COPY;
3574 							phi->op1 = phi->op2;
3575 							phi->op2 = 1;
3576 							phi->inputs_count = 0;
3577 						} else {
3578 							phi->inputs_count = k + 1;
3579 						}
3580 						n2 = 1 + ((n + 1) >> 2);
3581 						k2 = 1 + ((k + 1) >> 2);
3582 						while (k2 != n2) {
3583 							(phi+k2)->optx = IR_NOP;
3584 							k2++;
3585 						}
3586 						phi += 1 + ((n + 1) >> 2);
3587 					}
3588 				}
3589 			}
3590 		}
3591 	}
3592 }
3593 
zend_jit_case_start(zend_jit_ctx * jit,int switch_b,int case_b,ir_ref switch_ref)3594 static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3595 {
3596 	zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3597 	const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3598 
3599 	if (opline->opcode == ZEND_SWITCH_LONG
3600 	 || opline->opcode == ZEND_SWITCH_STRING
3601 	 || opline->opcode == ZEND_MATCH) {
3602 		HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3603 		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3604 		int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3605 		zval *zv;
3606 		ir_ref list = IR_UNUSED, idx;
3607 		bool first = 1;
3608 
3609 		ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3610 			const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3611 			int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3612 
3613 			if (b == case_b) {
3614 				if (!first) {
3615 					ir_END_list(list);
3616 				}
3617 				if (HT_IS_PACKED(jumptable)) {
3618 					idx = ir_CONST_LONG(zv - jumptable->arPacked);
3619 				} else {
3620 					idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3621 				}
3622 				ir_CASE_VAL(switch_ref, idx);
3623 				first = 0;
3624 			}
3625 		} ZEND_HASH_FOREACH_END();
3626 		if (default_b == case_b) {
3627 			if (!first) {
3628 				ir_END_list(list);
3629 			}
3630 			if (jit->ctx.ir_base[switch_ref].op3) {
3631 				/* op3 may contain a list of additional "default" path inputs for MATCH */
3632 				ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3633 				jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3634 				ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3635 				ir_ref end = ref;
3636 				while (jit->ctx.ir_base[end].op2) {
3637 					ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3638 					end = jit->ctx.ir_base[end].op2;
3639 				}
3640 				jit->ctx.ir_base[end].op2 = list;
3641 				list = ref;
3642 			}
3643 			ir_CASE_DEFAULT(switch_ref);
3644 		}
3645 		if (list) {
3646 			ir_END_list(list);
3647 			ir_MERGE_list(list);
3648 		}
3649 	} else {
3650 		ZEND_UNREACHABLE();
3651 	}
3652 }
3653 
zend_jit_bb_start(zend_jit_ctx * jit,int b)3654 static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3655 {
3656 	zend_basic_block *bb;
3657 	int i, n, *p, pred;
3658 	ir_ref ref, bb_start;
3659 
3660 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3661 	ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3662 	bb = &jit->ssa->cfg.blocks[b];
3663 	ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3664 	n = bb->predecessors_count;
3665 
3666 	if (n == 0) {
3667 		/* pass */
3668 		ZEND_ASSERT(jit->ctx.control);
3669 #if ZEND_DEBUG
3670 		ref = jit->ctx.control;
3671 		ir_insn *insn = &jit->ctx.ir_base[ref];
3672 		while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3673 			ref = insn->op1;
3674 			insn = &jit->ctx.ir_base[ref];
3675 		}
3676 		ZEND_ASSERT(insn->op == IR_START);
3677 		ZEND_ASSERT(ref == 1);
3678 #endif
3679 		bb_start = 1;
3680 		if (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
3681 			/* prvent END/BEGIN merging */
3682 			jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3683 			bb_start = jit->ctx.control;
3684 		}
3685 	} else if (n == 1) {
3686 		ZEND_ASSERT(!jit->ctx.control);
3687 		pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3688 		ref = jit->bb_edges[jit->bb_predecessors[b]];
3689 		if (ref == IR_UNUSED) {
3690 			if (!jit->ctx.control) {
3691 				ir_BEGIN(IR_UNUSED); /* unreachable block */
3692 			}
3693 		} else {
3694 			ir_op op = jit->ctx.ir_base[ref].op;
3695 
3696 			if (op == IR_IF) {
3697 				if (!jit->ctx.control) {
3698 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3699 				} else {
3700 					ir_ref entry_path = ir_END();
3701 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3702 					ir_MERGE_WITH(entry_path);
3703 				}
3704 			} else if (op == IR_SWITCH) {
3705 				zend_jit_case_start(jit, pred, b, ref);
3706 			} else {
3707 				if (!jit->ctx.control) {
3708 					ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3709 					if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3710 					 && (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)) {
3711 						/* prvent END/BEGIN merging */
3712 						jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3713 					} else {
3714 						ir_BEGIN(ref);
3715 					}
3716 				} else {
3717 					ir_MERGE_WITH(ref);
3718 				}
3719 			}
3720 		}
3721 		bb_start = jit->ctx.control;
3722 	} else {
3723 		int forward_edges_count = 0;
3724 		int back_edges_count = 0;
3725 		ir_ref *pred_refs;
3726 		ir_ref entry_path = IR_UNUSED;
3727 		ALLOCA_FLAG(use_heap);
3728 
3729 		ZEND_ASSERT(!jit->ctx.control);
3730 		if (jit->ctx.control) {
3731 			entry_path = ir_END();
3732 		}
3733 		pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3734 		for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3735 			pred = *p;
3736 			if (jit->bb_start_ref[pred]) {
3737 				/* forward edge */
3738 				forward_edges_count++;
3739 				ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3740 				if (ref == IR_UNUSED) {
3741 					/* dead edge */
3742 					pred_refs[i] = IR_UNUSED;
3743 				} else {
3744 					ir_op op = jit->ctx.ir_base[ref].op;
3745 
3746 					if (op == IR_IF) {
3747 						jit_IF_TRUE_FALSE_ex(jit, ref, b);
3748 						pred_refs[i] = ir_END();
3749 					} else if (op == IR_SWITCH) {
3750 						zend_jit_case_start(jit, pred, b, ref);
3751 						pred_refs[i] = ir_END();
3752 					} else {
3753 						ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3754 						pred_refs[i] = ref;
3755 					}
3756 				}
3757 			} else {
3758 				/* backward edge */
3759 				back_edges_count++;
3760 				pred_refs[i] = IR_UNUSED;
3761 			}
3762 		}
3763 
3764 		if (bb->flags & ZEND_BB_LOOP_HEADER) {
3765 			ZEND_ASSERT(back_edges_count != 0);
3766 			ZEND_ASSERT(forward_edges_count != 0);
3767 			ir_MERGE_N(n, pred_refs);
3768 			jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3769 			bb_start = jit->ctx.control;
3770 			if (entry_path) {
3771 				ir_MERGE_WITH(entry_path);
3772 			}
3773 		} else {
3774 //			ZEND_ASSERT(back_edges_count != 0);
3775 			/* edges from exceptional blocks may be counted as back edges */
3776 			ir_MERGE_N(n, pred_refs);
3777 			bb_start = jit->ctx.control;
3778 			if (entry_path) {
3779 				ir_MERGE_WITH(entry_path);
3780 			}
3781 		}
3782 		free_alloca(pred_refs, use_heap);
3783 	}
3784 	jit->b = b;
3785 	jit->bb_start_ref[b] = bb_start;
3786 
3787 	if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3788 		jit->ctx.fold_cse_limit = bb_start;
3789 	}
3790 
3791 	return 1;
3792 }
3793 
zend_jit_bb_end(zend_jit_ctx * jit,int b)3794 static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3795 {
3796 	int succ;
3797 	zend_basic_block *bb;
3798 
3799 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3800 	if (jit->b != b) {
3801 		return 1;
3802 	}
3803 
3804 	bb = &jit->ssa->cfg.blocks[b];
3805 	ZEND_ASSERT(bb->successors_count != 0);
3806 	if (bb->successors_count == 1) {
3807 		succ = bb->successors[0];
3808 	} else {
3809 		const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3810 
3811 		/* Use only the following successor of SWITCH and FE_RESET_R */
3812 		ZEND_ASSERT(opline->opcode == ZEND_SWITCH_LONG
3813 		 || opline->opcode == ZEND_SWITCH_STRING
3814 		 || opline->opcode == ZEND_MATCH
3815 		 || opline->opcode == ZEND_FE_RESET_R);
3816 		succ = b + 1;
3817 	}
3818 	_zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3819 	jit->b = -1;
3820 	return 1;
3821 }
3822 
jit_CMP_IP(zend_jit_ctx * jit,ir_op op,const zend_op * next_opline)3823 static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3824 {
3825 	ir_ref ref;
3826 
3827 #if 1
3828 	if (GCC_GLOBAL_REGS) {
3829 		ref = jit_IP32(jit);
3830 	} else {
3831 		ref = ir_LOAD_U32(jit_EX(opline));
3832 	}
3833 	ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3834 #else
3835 	if (GCC_GLOBAL_REGS) {
3836 		ref = jit_IP(jit);
3837 	} else {
3838 		ref = ir_LOAD_A(jit_EX(opline));
3839 	}
3840 	ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
3841 #endif
3842 	return ref;
3843 }
3844 
zend_jit_jmp_frameless(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr,zend_jmp_fl_result guard)3845 static int zend_jit_jmp_frameless(
3846 	zend_jit_ctx *jit,
3847 	const zend_op *opline,
3848 	const void *exit_addr,
3849 	zend_jmp_fl_result guard
3850 ) {
3851 	ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
3852 	zend_basic_block *bb;
3853 
3854 	// JIT: CACHED_PTR(opline->extended_value)
3855 	cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
3856 	cache_result = ir_LOAD_L(cache_slot_ref);
3857 
3858 	// JIT: if (UNEXPECTED(!result))
3859 	if_ref = ir_IF(cache_result);
3860 	ir_IF_FALSE_cold(if_ref);
3861 	zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3862 	function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3863 		ir_CONST_ADDR(func_name_zv),
3864 		cache_slot_ref);
3865 	ir_MERGE_WITH_EMPTY_TRUE(if_ref);
3866 
3867 	phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
3868 
3869 	if (exit_addr) {
3870 		ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3871 	} else {
3872 		ZEND_ASSERT(jit->b >= 0);
3873 		bb = &jit->ssa->cfg.blocks[jit->b];
3874 		// JIT: if (result == ZEND_JMP_FL_HIT)
3875 		ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3876 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3877 		_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3878 		jit->b = -1;
3879 	}
3880 
3881 	return 1;
3882 }
3883 
zend_jit_cond_jmp(zend_jit_ctx * jit,const zend_op * next_opline,int target_block)3884 static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
3885 {
3886 	ir_ref ref;
3887 	zend_basic_block *bb;
3888 
3889 	ZEND_ASSERT(jit->b >= 0);
3890 	bb = &jit->ssa->cfg.blocks[jit->b];
3891 
3892 	ZEND_ASSERT(bb->successors_count == 2);
3893 	if (bb->successors[0] == bb->successors[1]) {
3894 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
3895 		jit->b = -1;
3896 		zend_jit_set_last_valid_opline(jit, next_opline);
3897 		return 1;
3898 	}
3899 
3900 	ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
3901 
3902 	_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3903 	_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3904 
3905 	jit->b = -1;
3906 	zend_jit_set_last_valid_opline(jit, next_opline);
3907 
3908 	return 1;
3909 }
3910 
zend_jit_set_cond(zend_jit_ctx * jit,const zend_op * next_opline,uint32_t var)3911 static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *next_opline, uint32_t var)
3912 {
3913 	ir_ref ref;
3914 
3915 	ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, IR_EQ, next_opline)), ir_CONST_U32(IS_FALSE));
3916 
3917 	// EX_VAR(var) = ...
3918 	ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
3919 
3920 	zend_jit_reset_last_valid_opline(jit);
3921 	return zend_jit_set_ip(jit, next_opline - 1);
3922 }
3923 
3924 /* PHP JIT handlers */
zend_jit_check_exception(zend_jit_ctx * jit)3925 static void zend_jit_check_exception(zend_jit_ctx *jit)
3926 {
3927 	ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3928 		jit_STUB_ADDR(jit, jit_stub_exception_handler));
3929 }
3930 
zend_jit_check_exception_undef_result(zend_jit_ctx * jit,const zend_op * opline)3931 static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
3932 {
3933 	ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3934 		jit_STUB_ADDR(jit,
3935 			(opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
3936 }
3937 
zend_jit_type_check_undef(zend_jit_ctx * jit,ir_ref type,uint32_t var,const zend_op * opline,bool check_exception,bool in_cold_path,bool undef_result)3938 static void zend_jit_type_check_undef(zend_jit_ctx  *jit,
3939                                       ir_ref         type,
3940                                       uint32_t       var,
3941                                       const zend_op *opline,
3942                                       bool           check_exception,
3943                                       bool           in_cold_path,
3944                                       bool           undef_result)
3945 {
3946 	ir_ref if_def = ir_IF(type);
3947 
3948 	if (!in_cold_path) {
3949 		ir_IF_FALSE_cold(if_def);
3950 	} else {
3951 		ir_IF_FALSE(if_def);
3952 	}
3953 	if (opline) {
3954 		jit_SET_EX_OPLINE(jit, opline);
3955 	}
3956 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3957 	if (check_exception) {
3958 		if (undef_result) {
3959 			zend_jit_check_exception_undef_result(jit, opline);
3960 		} else {
3961 			zend_jit_check_exception(jit);
3962 		}
3963 	}
3964 	ir_MERGE_WITH_EMPTY_TRUE(if_def);
3965 }
3966 
zend_jit_zval_check_undef(zend_jit_ctx * jit,ir_ref ref,uint32_t var,const zend_op * opline,bool check_exception)3967 static ir_ref zend_jit_zval_check_undef(zend_jit_ctx  *jit,
3968                                         ir_ref         ref,
3969                                         uint32_t       var,
3970                                         const zend_op *opline,
3971                                         bool           check_exception)
3972 {
3973 	ir_ref if_def, ref2;
3974 
3975 	if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
3976 	ir_IF_FALSE_cold(if_def);
3977 
3978 	if (opline) {
3979 		jit_SET_EX_OPLINE(jit, opline);
3980 	}
3981 
3982 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3983 
3984 	if (check_exception) {
3985 		zend_jit_check_exception(jit);
3986 	}
3987 
3988 	ref2 = jit_EG(uninitialized_zval);
3989 
3990 	ir_MERGE_WITH_EMPTY_TRUE(if_def);
3991 
3992 	return ir_PHI_2(IR_ADDR, ref2, ref);
3993 }
3994 
zend_jit_recv_entry(zend_jit_ctx * jit,int b)3995 static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
3996 {
3997 	zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
3998 	int pred;
3999 	ir_ref ref;
4000 
4001 	ZEND_ASSERT(bb->predecessors_count > 0);
4002 
4003 	pred = jit->bb_predecessors[b];
4004 	ref = jit->bb_edges[pred];
4005 
4006 	ZEND_ASSERT(ref);
4007 	ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
4008 
4009 	/* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4010 	ir_ENTRY(ref, bb->start);
4011 	if (!GCC_GLOBAL_REGS) {
4012 		/* 2 is hardcoded reference to IR_PARAM */
4013 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4014 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4015 		jit_STORE_FP(jit, 2);
4016 	}
4017 
4018 	ir_MERGE_WITH(ref);
4019 	jit->bb_edges[pred] = ir_END();
4020 }
4021 
zend_jit_osr_entry(zend_jit_ctx * jit,int b)4022 static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4023 {
4024 	zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4025 	ir_ref ref = ir_END();
4026 
4027 	/* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4028 	ir_ENTRY(ref, bb->start);
4029 	if (!GCC_GLOBAL_REGS) {
4030 		/* 2 is hardcoded reference to IR_PARAM */
4031 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4032 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4033 		jit_STORE_FP(jit, 2);
4034 	}
4035 
4036 	ir_MERGE_WITH(ref);
4037 }
4038 
zend_jit_continue_entry(zend_jit_ctx * jit,ir_ref src,unsigned int label)4039 static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4040 {
4041 	ir_ENTRY(src, label);
4042 	if (!GCC_GLOBAL_REGS) {
4043 		/* 2 is hardcoded reference to IR_PARAM */
4044 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4045 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4046 		jit_STORE_FP(jit, 2);
4047 	}
4048 	return ir_END();
4049 }
4050 
zend_jit_handler(zend_jit_ctx * jit,const zend_op * opline,int may_throw)4051 static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4052 {
4053 	ir_ref ref;
4054 	const void *handler;
4055 
4056 	zend_jit_set_ip(jit, opline);
4057 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4058 		handler = zend_get_opcode_handler_func(opline);
4059 	} else {
4060 		handler = opline->handler;
4061 	}
4062 	if (GCC_GLOBAL_REGS) {
4063 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4064 	} else {
4065 		ref = jit_FP(jit);
4066 		ref = ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(handler), ref);
4067 	}
4068 	if (may_throw) {
4069 		zend_jit_check_exception(jit);
4070 	}
4071 	/* Skip the following OP_DATA */
4072 	switch (opline->opcode) {
4073 		case ZEND_ASSIGN_DIM:
4074 		case ZEND_ASSIGN_OBJ:
4075 		case ZEND_ASSIGN_STATIC_PROP:
4076 		case ZEND_ASSIGN_DIM_OP:
4077 		case ZEND_ASSIGN_OBJ_OP:
4078 		case ZEND_ASSIGN_STATIC_PROP_OP:
4079 		case ZEND_ASSIGN_STATIC_PROP_REF:
4080 		case ZEND_ASSIGN_OBJ_REF:
4081 			zend_jit_set_last_valid_opline(jit, opline + 2);
4082 			break;
4083 		default:
4084 			zend_jit_set_last_valid_opline(jit, opline + 1);
4085 			break;
4086 	}
4087 	return 1;
4088 }
4089 
zend_jit_tail_handler(zend_jit_ctx * jit,const zend_op * opline)4090 static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4091 {
4092 	const void *handler;
4093 	ir_ref ref;
4094 	zend_basic_block *bb;
4095 
4096 	zend_jit_set_ip(jit, opline);
4097 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4098 		if (opline->opcode == ZEND_DO_UCALL ||
4099 		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4100 		    opline->opcode == ZEND_DO_FCALL ||
4101 		    opline->opcode == ZEND_RETURN) {
4102 
4103 			/* Use inlined HYBRID VM handler */
4104 			handler = opline->handler;
4105 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4106 		} else {
4107 			handler = zend_get_opcode_handler_func(opline);
4108 			ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4109 			ref = ir_LOAD_A(jit_IP(jit));
4110 			ir_TAILCALL(IR_VOID, ref);
4111 		}
4112 	} else {
4113 		handler = opline->handler;
4114 		if (GCC_GLOBAL_REGS) {
4115 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4116 		} else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4117 		 && (opline->opcode == ZEND_CATCH
4118 		  || opline->opcode == ZEND_FAST_CALL
4119 		  || opline->opcode == ZEND_FAST_RET
4120 		  || opline->opcode == ZEND_MATCH_ERROR
4121 		  || opline->opcode == ZEND_THROW
4122 		  || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4123 			ref = jit_FP(jit);
4124 			ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4125 			ir_RETURN(ir_CONST_I32(1));
4126 		} else {
4127 			ref = jit_FP(jit);
4128 			ir_TAILCALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4129 		}
4130 	}
4131 	if (jit->b >= 0) {
4132 		bb = &jit->ssa->cfg.blocks[jit->b];
4133 		if (bb->successors_count > 0
4134 		 && (opline->opcode == ZEND_DO_FCALL
4135 		  || opline->opcode == ZEND_DO_UCALL
4136 		  || opline->opcode == ZEND_DO_FCALL_BY_NAME
4137 		  || opline->opcode == ZEND_INCLUDE_OR_EVAL
4138 		  || opline->opcode == ZEND_GENERATOR_CREATE
4139 		  || opline->opcode == ZEND_YIELD
4140 		  || opline->opcode == ZEND_YIELD_FROM
4141 		  || opline->opcode == ZEND_FAST_CALL)) {
4142 			/* Add a fake control edge from UNREACHABLE to the following ENTRY */
4143 			int succ;
4144 
4145 			if (bb->successors_count == 1) {
4146 				succ = bb->successors[0];
4147 				ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
4148 			} else {
4149 				/* Use only the following successor of FAST_CALL */
4150 				ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4151 				succ = jit->b + 1;
4152 				/* we need an entry */
4153 				jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4154 			}
4155 			ref = jit->ctx.insns_count - 1;
4156 			ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4157 			ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4158 			_zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4159 		}
4160 		jit->b = -1;
4161 		zend_jit_reset_last_valid_opline(jit);
4162 	}
4163 	return 1;
4164 }
4165 
zend_jit_call(zend_jit_ctx * jit,const zend_op * opline,unsigned int next_block)4166 static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4167 {
4168 	return zend_jit_tail_handler(jit, opline);
4169 }
4170 
zend_jit_spill_store(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info,bool set_type)4171 static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4172 {
4173 	ZEND_ASSERT(Z_MODE(src) == IS_REG);
4174 	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4175 
4176 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4177 		jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4178 		if (set_type &&
4179 		    (Z_REG(dst) != ZREG_FP ||
4180 		     !JIT_G(current_frame) ||
4181 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4182 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4183 		}
4184 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4185 		jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4186 		if (set_type &&
4187 		    (Z_REG(dst) != ZREG_FP ||
4188 		     !JIT_G(current_frame) ||
4189 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4190 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4191 		}
4192 	} else {
4193 		ZEND_UNREACHABLE();
4194 	}
4195 	return 1;
4196 }
4197 
zend_jit_spill_store_inv(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4198 static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4199 {
4200 	ZEND_ASSERT(Z_MODE(src) == IS_REG);
4201 	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4202 
4203 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4204 		jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4205 		if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4206 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4207 		} else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4208 			/* invalidate memory type */
4209 			STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4210 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4211 		}
4212 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4213 		jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4214 		if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4215 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4216 		} else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4217 			/* invalidate memory type */
4218 			STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4219 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4220 		}
4221 	} else {
4222 		ZEND_UNREACHABLE();
4223 	}
4224 	return 1;
4225 }
4226 
zend_jit_load_reg(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4227 static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4228 {
4229 	ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
4230 	ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4231 
4232 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4233 		zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4234 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4235 		zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4236 	} else {
4237 		ZEND_UNREACHABLE();
4238 	}
4239 	return 1;
4240 }
4241 
zend_jit_store_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var,bool set_type)4242 static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4243 {
4244 	zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4245 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4246 
4247 	return zend_jit_spill_store(jit, src, dst, info, set_type);
4248 }
4249 
zend_jit_store_ref(zend_jit_ctx * jit,uint32_t info,int var,int32_t src,bool set_type)4250 static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4251 {
4252 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4253 
4254 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4255 		jit_set_Z_LVAL(jit, dst, src);
4256 		if (set_type &&
4257 		    (Z_REG(dst) != ZREG_FP ||
4258 		     !JIT_G(current_frame) ||
4259 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4260 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4261 		}
4262 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4263 		jit_set_Z_DVAL(jit, dst, src);
4264 		if (set_type &&
4265 		    (Z_REG(dst) != ZREG_FP ||
4266 		     !JIT_G(current_frame) ||
4267 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4268 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4269 		}
4270 	} else {
4271 		ZEND_UNREACHABLE();
4272 	}
4273 	return 1;
4274 }
4275 
zend_jit_deopt_rload(zend_jit_ctx * jit,ir_type type,int32_t reg)4276 static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4277 {
4278 	ir_ref ref = jit->ctx.control;
4279 	ir_insn *insn;
4280 
4281 	while (1) {
4282 		insn = &jit->ctx.ir_base[ref];
4283 		if (insn->op == IR_RLOAD && insn->op2 == reg) {
4284 			ZEND_ASSERT(insn->type == type);
4285 			return ref;
4286 		} else if (insn->op == IR_START) {
4287 			break;
4288 		}
4289 		ref = insn->op1;
4290 	}
4291 	return ir_RLOAD(type, reg);
4292 }
4293 
zend_jit_store_const_long(zend_jit_ctx * jit,int var,zend_long val)4294 static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4295 {
4296 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4297 	ir_ref src = ir_CONST_LONG(val);
4298 
4299 	if (jit->ra && jit->ra[var].ref == IR_NULL) {
4300 		zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4301 	}
4302 	jit_set_Z_LVAL(jit, dst, src);
4303 	jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4304 	return 1;
4305 }
4306 
zend_jit_store_const_double(zend_jit_ctx * jit,int var,double val)4307 static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4308 {
4309 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4310 	ir_ref src = ir_CONST_DOUBLE(val);
4311 
4312 	if (jit->ra && jit->ra[var].ref == IR_NULL) {
4313 		zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4314 	}
4315 	jit_set_Z_DVAL(jit, dst, src);
4316 	jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4317 	return 1;
4318 }
4319 
zend_jit_store_type(zend_jit_ctx * jit,int var,uint8_t type)4320 static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4321 {
4322 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4323 
4324 	ZEND_ASSERT(type <= IS_DOUBLE);
4325 	jit_set_Z_TYPE_INFO(jit, dst, type);
4326 	return 1;
4327 }
4328 
zend_jit_store_reg(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,bool in_mem,bool set_type)4329 static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4330 {
4331 	zend_jit_addr src;
4332 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4333 	ir_type type;
4334 
4335 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4336 		type = IR_LONG;
4337 		src = zend_jit_deopt_rload(jit, type, reg);
4338 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4339 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4340 		} else if (!in_mem) {
4341 			jit_set_Z_LVAL(jit, dst, src);
4342 			if (set_type &&
4343 			    (Z_REG(dst) != ZREG_FP ||
4344 			     !JIT_G(current_frame) ||
4345 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4346 				jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4347 			}
4348 		}
4349 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4350 		type = IR_DOUBLE;
4351 		src = zend_jit_deopt_rload(jit, type, reg);
4352 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4353 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4354 		} else if (!in_mem) {
4355 			jit_set_Z_DVAL(jit, dst, src);
4356 			if (set_type &&
4357 			    (Z_REG(dst) != ZREG_FP ||
4358 			     !JIT_G(current_frame) ||
4359 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4360 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4361 			}
4362 		}
4363 	} else {
4364 		ZEND_UNREACHABLE();
4365 	}
4366 	return 1;
4367 }
4368 
zend_jit_store_spill_slot(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,int32_t offset,bool set_type)4369 static int zend_jit_store_spill_slot(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, int32_t offset, bool set_type)
4370 {
4371 	zend_jit_addr src;
4372 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4373 
4374 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4375 		src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4376 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4377 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4378 		} else {
4379 			jit_set_Z_LVAL(jit, dst, src);
4380 			if (set_type &&
4381 			    (Z_REG(dst) != ZREG_FP ||
4382 			     !JIT_G(current_frame) ||
4383 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4384 				jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4385 			}
4386 		}
4387 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4388 		src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4389 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4390 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4391 		} else {
4392 			jit_set_Z_DVAL(jit, dst, src);
4393 			if (set_type &&
4394 			    (Z_REG(dst) != ZREG_FP ||
4395 			     !JIT_G(current_frame) ||
4396 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4397 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4398 			}
4399 		}
4400 	} else {
4401 		ZEND_UNREACHABLE();
4402 	}
4403 	return 1;
4404 }
4405 
zend_jit_store_var_type(zend_jit_ctx * jit,int var,uint32_t type)4406 static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4407 {
4408 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4409 
4410 	jit_set_Z_TYPE_INFO(jit, dst, type);
4411 	return 1;
4412 }
4413 
zend_jit_zval_try_addref(zend_jit_ctx * jit,zend_jit_addr var_addr)4414 static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4415 {
4416 	ir_ref if_refcounted, end1;
4417 
4418 	if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4419 	ir_IF_FALSE(if_refcounted);
4420 	end1 = ir_END();
4421 	ir_IF_TRUE(if_refcounted);
4422 	jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4423 	ir_MERGE_WITH(end1);
4424 	return 1;
4425 }
4426 
zend_jit_store_var_if_necessary(zend_jit_ctx * jit,int var,zend_jit_addr src,uint32_t info)4427 static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4428 {
4429 	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4430 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4431 		return zend_jit_spill_store(jit, src, dst, info, 1);
4432 	}
4433 	return 1;
4434 }
4435 
zend_jit_store_var_if_necessary_ex(zend_jit_ctx * jit,int var,zend_jit_addr src,uint32_t info,zend_jit_addr old,uint32_t old_info)4436 static int zend_jit_store_var_if_necessary_ex(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info)
4437 {
4438 	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4439 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4440 		bool set_type = 1;
4441 
4442 		if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4443 		    (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4444 			if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4445 				if (JIT_G(current_frame)) {
4446 					uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4447 
4448 					if (mem_type != IS_UNKNOWN
4449 					 && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4450 						set_type = 0;
4451 					}
4452 				} else {
4453 					set_type = 0;
4454 				}
4455 			}
4456 		}
4457 		return zend_jit_spill_store(jit, src, dst, info, set_type);
4458 	}
4459 	return 1;
4460 }
4461 
zend_jit_load_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var)4462 static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4463 {
4464 	zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4465 	zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4466 
4467 	return zend_jit_load_reg(jit, src, dst, info);
4468 }
4469 
zend_jit_invalidate_var_if_necessary(zend_jit_ctx * jit,uint8_t op_type,zend_jit_addr addr,znode_op op)4470 static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4471 {
4472 	if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4473 		/* Invalidate operand type to prevent incorrect destuction by exception_handler_free_op1_op2() */
4474 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4475 		jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4476 	}
4477 	return 1;
4478 }
4479 
zend_jit_update_regs(zend_jit_ctx * jit,uint32_t var,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4480 static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4481 {
4482 	if (!zend_jit_same_addr(src, dst)) {
4483 		if (Z_MODE(src) == IS_REG) {
4484 			if (Z_MODE(dst) == IS_REG) {
4485 				zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4486 				if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4487 					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4488 
4489 					if (!zend_jit_spill_store(jit, dst, var_addr, info,
4490 							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4491 							JIT_G(current_frame) == NULL ||
4492 							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4493 							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4494 					)) {
4495 						return 0;
4496 					}
4497 				}
4498 			} else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4499 				if (!Z_LOAD(src) && !Z_STORE(src)) {
4500 					if (!zend_jit_spill_store(jit, src, dst, info,
4501 							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4502 							JIT_G(current_frame) == NULL ||
4503 							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4504 							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4505 					)) {
4506 						return 0;
4507 					}
4508 				}
4509 			} else {
4510 				ZEND_UNREACHABLE();
4511 			}
4512 		} else if (Z_MODE(src) == IS_MEM_ZVAL) {
4513 			if (Z_MODE(dst) == IS_REG) {
4514 				if (!zend_jit_load_reg(jit, src, dst, info)) {
4515 					return 0;
4516 				}
4517 			} else {
4518 				ZEND_UNREACHABLE();
4519 			}
4520 		} else {
4521 			ZEND_UNREACHABLE();
4522 		}
4523 	} else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4524 		dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4525 		if (!zend_jit_spill_store(jit, src, dst, info,
4526 				JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4527 				JIT_G(current_frame) == NULL ||
4528 				STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4529 				(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4530 		)) {
4531 			return 0;
4532 		}
4533 	}
4534 	return 1;
4535 }
4536 
4537 struct jit_observer_fcall_is_unobserved_data {
4538 	ir_ref if_unobserved;
4539 	ir_ref ir_end_inputs;
4540 };
4541 
jit_observer_fcall_is_unobserved_start(zend_jit_ctx * jit,const zend_function * func,ir_ref * observer_handler,ir_ref rx,ir_ref func_ref)4542 static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobserved_start(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4543 	ir_ref run_time_cache;
4544 	struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4545 	if (func) {
4546 		ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4547 	} else {
4548 		// JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4549 		ZEND_ASSERT(rx != IR_UNUSED);
4550 		ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4551 			ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4552 			ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4553 		ir_IF_TRUE(if_trampoline_or_generator);
4554 		ir_END_list(data.ir_end_inputs);
4555 		ir_IF_FALSE(if_trampoline_or_generator);
4556 	}
4557 	if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4558 		// JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4559 		run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)), (uintptr_t)ZEND_MAP_PTR(func->common.run_time_cache)));
4560 #ifndef ZTS
4561 	} else if (func && rx == IS_UNUSED) { // happens for internal functions only
4562 		ZEND_ASSERT(!ZEND_USER_CODE(func->type));
4563 		run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4564 #endif
4565 	} else {
4566 		// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4567 		if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4568 			run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4569 		} else {
4570 			// JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4571 			run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4572 			ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4573 			ir_IF_TRUE(if_odd);
4574 
4575 			ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4576 
4577 			ir_ref if_odd_end = ir_END();
4578 			ir_IF_FALSE(if_odd);
4579 
4580 			// JIT: if (func->common.runtime_cache != NULL) {
4581 			ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4582 			ir_IF_TRUE(if_rt_cache);
4583 			ir_END_list(data.ir_end_inputs);
4584 			ir_IF_FALSE(if_rt_cache);
4585 
4586 			ir_MERGE_WITH(if_odd_end);
4587 			run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4588 		}
4589 	}
4590 	// JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4591 	if (func) {
4592 		*observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4593 	} else {
4594 		// JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4595 		ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4596 		ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4597 		ir_IF_TRUE(if_internal_func);
4598 
4599 		ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4600 
4601 		ir_ref if_internal_func_end = ir_END();
4602 		ir_IF_FALSE(if_internal_func);
4603 
4604 		ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4605 
4606 		ir_MERGE_WITH(if_internal_func_end);
4607 		*observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
4608 	}
4609 
4610 	// JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4611 	data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4612 	ir_IF_FALSE(data.if_unobserved);
4613 	return data;
4614 }
4615 
4616 /* For frameless the true branch of if_unobserved is used and this function not called. */
jit_observer_fcall_is_unobserved_end(zend_jit_ctx * jit,struct jit_observer_fcall_is_unobserved_data * data)4617 static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4618 	ir_END_list(data->ir_end_inputs);
4619 	ir_IF_TRUE(data->if_unobserved);
4620 	ir_END_list(data->ir_end_inputs);
4621 	ir_MERGE_list(data->ir_end_inputs);
4622 }
4623 
jit_observer_fcall_begin(zend_jit_ctx * jit,ir_ref rx,ir_ref observer_handler)4624 static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4625 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4626 }
4627 
jit_observer_fcall_end(zend_jit_ctx * jit,ir_ref rx,ir_ref res_ref)4628 static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4629 	// JIT: if (execute_data == EG(current_observed_frame)) {
4630 	ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4631 	ir_IF_TRUE(has_end_observer);
4632 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4633 		rx, res_ref);
4634 	ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4635 }
4636 
zend_jit_inc_dec(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint32_t op1_def_info,zend_jit_addr op1_def_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr,int may_overflow,int may_throw)4637 static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
4638 {
4639 	ir_ref if_long = IR_UNUSED;
4640 	ir_ref op1_lval_ref = IR_UNUSED;
4641 	ir_ref ref;
4642 	ir_op op;
4643 
4644 	if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4645 		if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4646 		ir_IF_TRUE(if_long);
4647 	}
4648 	if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4649 		op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4650 		jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4651 		if (Z_MODE(res_addr) != IS_REG) {
4652 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4653 		}
4654 	}
4655 	if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4656 	 && Z_MODE(op1_addr) == IS_REG
4657 	 && !Z_LOAD(op1_addr)
4658 	 && !Z_STORE(op1_addr)) {
4659 		jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4660 	}
4661 	if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4662 		op = may_overflow ? IR_ADD_OV : IR_ADD;
4663 	} else {
4664 		op = may_overflow ? IR_SUB_OV : IR_SUB;
4665 	}
4666 	if (!op1_lval_ref) {
4667 		op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4668 	}
4669 	ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4670 	if (op1_def_info & MAY_BE_LONG) {
4671 		jit_set_Z_LVAL(jit, op1_def_addr, ref);
4672 	}
4673 	if (may_overflow &&
4674 	    (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4675 	     ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4676 		int32_t exit_point;
4677 		const void *exit_addr;
4678 		zend_jit_trace_stack *stack;
4679 		uint32_t old_op1_info, old_res_info = 0;
4680 
4681 		stack = JIT_G(current_frame)->stack;
4682 		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4683 		SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4684 		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4685 			SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4686 		} else {
4687 			SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4688 		}
4689 		if (opline->result_type != IS_UNUSED) {
4690 			old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4691 			if (opline->opcode == ZEND_PRE_INC) {
4692 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4693 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4694 			} else if (opline->opcode == ZEND_PRE_DEC) {
4695 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4696 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4697 			} else if (opline->opcode == ZEND_POST_INC) {
4698 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4699 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MAX));
4700 			} else if (opline->opcode == ZEND_POST_DEC) {
4701 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4702 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MIN));
4703 			}
4704 		}
4705 
4706 		exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4707 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4708 		ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4709 
4710 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4711 		    opline->result_type != IS_UNUSED) {
4712 			jit_set_Z_LVAL(jit, res_addr, ref);
4713 			if (Z_MODE(res_addr) != IS_REG) {
4714 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4715 			}
4716 		}
4717 
4718 		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4719 		if (opline->result_type != IS_UNUSED) {
4720 			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4721 		}
4722 	} else if (may_overflow) {
4723 		ir_ref if_overflow;
4724 		ir_ref merge_inputs = IR_UNUSED;
4725 
4726 		if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4727 		 || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) ==  (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4728 			int32_t exit_point;
4729 			const void *exit_addr;
4730 			zend_jit_trace_stack *stack;
4731 			uint32_t old_res_info = 0;
4732 
4733 			stack = JIT_G(current_frame)->stack;
4734 			if (opline->result_type != IS_UNUSED) {
4735 				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4736 				if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4737 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4738 				}
4739 			}
4740 			exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4741 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4742 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4743 			    opline->result_type != IS_UNUSED) {
4744 				if_overflow = ir_IF(ir_OVERFLOW(ref));
4745 				ir_IF_FALSE_cold(if_overflow);
4746 				jit_set_Z_LVAL(jit, res_addr, ref);
4747 				if (Z_MODE(res_addr) != IS_REG) {
4748 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4749 				}
4750 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
4751 				ir_IF_TRUE(if_overflow);
4752 			} else {
4753 				ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4754 			}
4755 			if (opline->result_type != IS_UNUSED) {
4756 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4757 			}
4758 		} else {
4759 			if_overflow = ir_IF(ir_OVERFLOW(ref));
4760 			ir_IF_FALSE(if_overflow);
4761 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4762 			    opline->result_type != IS_UNUSED) {
4763 				jit_set_Z_LVAL(jit, res_addr, ref);
4764 				if (Z_MODE(res_addr) != IS_REG) {
4765 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4766 				}
4767 			}
4768 			ir_END_list(merge_inputs);
4769 
4770 			/* overflow => cold path */
4771 			ir_IF_TRUE_cold(if_overflow);
4772 		}
4773 
4774 		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4775 			if (Z_MODE(op1_def_addr) == IS_REG) {
4776 				jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4777 			} else {
4778 #if SIZEOF_ZEND_LONG == 4
4779 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0));
4780 				jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0x41e00000));
4781 #else
4782 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4783 #endif
4784 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4785 			}
4786 		} else {
4787 			if (Z_MODE(op1_def_addr) == IS_REG) {
4788 				jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4789 			} else {
4790 #if SIZEOF_ZEND_LONG == 4
4791 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x00200000));
4792 				jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0xc1e00000));
4793 #else
4794 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4795 #endif
4796 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4797 			}
4798 		}
4799 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4800 		    opline->result_type != IS_UNUSED) {
4801 			if (opline->opcode == ZEND_PRE_INC) {
4802 				if (Z_MODE(res_addr) == IS_REG) {
4803 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4804 				} else {
4805 #if SIZEOF_ZEND_LONG == 4
4806 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
4807 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
4808 #else
4809 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4810 #endif
4811 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4812 				}
4813 			} else {
4814 				if (Z_MODE(res_addr) == IS_REG) {
4815 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4816 				} else {
4817 #if SIZEOF_ZEND_LONG == 4
4818 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
4819 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
4820 #else
4821 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
4822 #endif
4823 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4824 				}
4825 			}
4826 		}
4827 
4828 		if (merge_inputs) {
4829 			ir_END_list(merge_inputs);
4830 			ir_MERGE_list(merge_inputs);
4831 		}
4832 	} else {
4833 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4834 		    opline->result_type != IS_UNUSED) {
4835 			jit_set_Z_LVAL(jit, res_addr, ref);
4836 			if (Z_MODE(res_addr) != IS_REG) {
4837 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4838 			}
4839 		}
4840 	}
4841 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4842 		ir_ref merge_inputs = ir_END();
4843 
4844 		/* !is_long => cold path */
4845 		ir_IF_FALSE_cold(if_long);
4846 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4847 			jit_SET_EX_OPLINE(jit, opline);
4848 			if (op1_info & MAY_BE_UNDEF) {
4849 				ir_ref if_def;
4850 
4851 				if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
4852 				ir_IF_FALSE_cold(if_def);
4853 
4854 				// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
4855 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
4856 
4857 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
4858 				ir_MERGE_WITH_EMPTY_TRUE(if_def);
4859 
4860 				op1_info |= MAY_BE_NULL;
4861 			}
4862 
4863 			ref = jit_ZVAL_ADDR(jit, op1_addr);
4864 
4865 			if (op1_info & MAY_BE_REF) {
4866 				ir_ref if_ref, if_typed, func, ref2, arg2;
4867 
4868 				if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
4869 				ir_IF_TRUE(if_ref);
4870 				ref2 = jit_Z_PTR_ref(jit, ref);
4871 
4872 				if_typed = jit_if_TYPED_REF(jit, ref2);
4873 				ir_IF_TRUE(if_typed);
4874 
4875 				if (RETURN_VALUE_USED(opline)) {
4876 					ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
4877 					arg2 = jit_ZVAL_ADDR(jit, res_addr);
4878 				} else {
4879 					arg2 = IR_NULL;
4880 				}
4881 				if (opline->opcode == ZEND_PRE_INC) {
4882 					func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
4883 				} else if (opline->opcode == ZEND_PRE_DEC) {
4884 					func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
4885 				} else if (opline->opcode == ZEND_POST_INC) {
4886 					func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
4887 				} else if (opline->opcode == ZEND_POST_DEC) {
4888 					func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
4889 				} else {
4890 					ZEND_UNREACHABLE();
4891 				}
4892 
4893 				ir_CALL_2(IR_VOID, func, ref2, arg2);
4894 				zend_jit_check_exception(jit);
4895 				ir_END_list(merge_inputs);
4896 
4897 				ir_IF_FALSE(if_typed);
4898 				ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
4899 				ir_MERGE_WITH_EMPTY_FALSE(if_ref);
4900 				ref = ir_PHI_2(IR_ADDR, ref2, ref);
4901 			}
4902 
4903 			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4904 				jit_ZVAL_COPY(jit,
4905 					res_addr,
4906 					res_use_info,
4907 					ZEND_ADDR_REF_ZVAL(ref), op1_info, 1);
4908 			}
4909 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4910 				if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
4911 					ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4912 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
4913 				} else {
4914 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function), ref);
4915 				}
4916 			} else {
4917 				if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
4918 					ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4919 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec), ref, arg2);
4920 				} else {
4921 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function), ref);
4922 				}
4923 			}
4924 			if (may_throw) {
4925 				zend_jit_check_exception(jit);
4926 			}
4927 		} else {
4928 			ref = jit_Z_DVAL(jit, op1_addr);
4929 			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4930 				jit_set_Z_DVAL(jit, res_addr, ref);
4931 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4932 			}
4933 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4934 				op = IR_ADD;
4935 			} else {
4936 				op = IR_SUB;
4937 			}
4938 			ref = ir_BINARY_OP_D(op, ref, ir_CONST_DOUBLE(1.0));
4939 			jit_set_Z_DVAL(jit, op1_def_addr, ref);
4940 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4941 			    opline->result_type != IS_UNUSED) {
4942 				jit_set_Z_DVAL(jit, res_addr, ref);
4943 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4944 			}
4945 		}
4946 		ir_END_list(merge_inputs);
4947 		ir_MERGE_list(merge_inputs);
4948 	}
4949 	if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
4950 		return 0;
4951 	}
4952 	if (opline->result_type != IS_UNUSED) {
4953 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
4954 			return 0;
4955 		}
4956 	}
4957 	return 1;
4958 }
4959 
zend_jit_math_long_long(zend_jit_ctx * jit,const zend_op * opline,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_info,uint32_t res_use_info,int may_overflow)4960 static int zend_jit_math_long_long(zend_jit_ctx   *jit,
4961                                    const zend_op  *opline,
4962                                    uint8_t         opcode,
4963                                    zend_jit_addr   op1_addr,
4964                                    zend_jit_addr   op2_addr,
4965                                    zend_jit_addr   res_addr,
4966                                    uint32_t        res_info,
4967                                    uint32_t        res_use_info,
4968                                    int             may_overflow)
4969 {
4970 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4971 	ir_op op;
4972 	ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
4973 
4974 	if (opcode == ZEND_ADD) {
4975 		op = may_overflow ? IR_ADD_OV : IR_ADD;
4976 	} else if (opcode == ZEND_SUB) {
4977 		op = may_overflow ? IR_SUB_OV : IR_SUB;
4978 	} else if (opcode == ZEND_MUL) {
4979 		op = may_overflow ? IR_MUL_OV : IR_MUL;
4980 	} else {
4981 		ZEND_UNREACHABLE();
4982 	}
4983 	op1 = jit_Z_LVAL(jit, op1_addr);
4984 	op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
4985 	ref = ir_BINARY_OP_L(op, op1, op2);
4986 
4987 	if (may_overflow) {
4988 		if (res_info & MAY_BE_GUARD) {
4989 			if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
4990 				zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
4991 				uint32_t old_res_info;
4992 				int32_t exit_point;
4993 				const void *exit_addr;
4994 
4995 				if (opline->opcode == ZEND_ADD
4996 				 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
4997 					old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4998 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4999 					SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5000 					exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5001 					SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5002 				} else if (opline->opcode == ZEND_SUB
5003 				 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5004 					old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5005 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5006 					SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5007 					exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5008 					SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5009 				} else {
5010 					exit_point = zend_jit_trace_get_exit_point(opline, 0);
5011 				}
5012 
5013 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5014 				if (!exit_addr) {
5015 					return 0;
5016 				}
5017 				ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5018 				may_overflow = 0;
5019 			} else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
5020 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
5021 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5022 
5023 				if (!exit_addr) {
5024 					return 0;
5025 				}
5026 				ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5027 			} else {
5028 				ZEND_UNREACHABLE();
5029 			}
5030 		} else {
5031 			if_overflow = ir_IF(ir_OVERFLOW(ref));
5032 			ir_IF_FALSE(if_overflow);
5033 		}
5034 	}
5035 
5036 	if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5037 		jit_set_Z_LVAL(jit, res_addr, ref);
5038 
5039 		if (Z_MODE(res_addr) != IS_REG) {
5040 			if (!zend_jit_same_addr(op1_addr, res_addr)) {
5041 				if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5042 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5043 				}
5044 			}
5045 		}
5046 	}
5047 
5048 	if (may_overflow) {
5049 		ir_ref fast_path = IR_UNUSED;
5050 
5051 		if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5052 			fast_path = ir_END();
5053 			ir_IF_TRUE_cold(if_overflow);
5054 		}
5055 		if (opcode == ZEND_ADD) {
5056 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5057 				if (Z_MODE(res_addr) == IS_REG) {
5058 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5059 				} else {
5060 #if SIZEOF_ZEND_LONG == 4
5061 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
5062 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
5063 #else
5064 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5065 #endif
5066 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5067 				}
5068 				if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5069 					ir_MERGE_WITH(fast_path);
5070 				}
5071 				return 1;
5072 			}
5073 			op = IR_ADD;
5074 		} else if (opcode == ZEND_SUB) {
5075 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5076 				if (Z_MODE(res_addr) == IS_REG) {
5077 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5078 				} else {
5079 #if SIZEOF_ZEND_LONG == 4
5080 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
5081 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
5082 #else
5083 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
5084 #endif
5085 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5086 				}
5087 				if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5088 					ir_MERGE_WITH(fast_path);
5089 				}
5090 				return 1;
5091 			}
5092 			op = IR_SUB;
5093 		} else if (opcode == ZEND_MUL) {
5094 			op = IR_MUL;
5095 		} else {
5096 			ZEND_UNREACHABLE();
5097 		}
5098 #if 1
5099 		/* reload */
5100 		op1 = jit_Z_LVAL(jit, op1_addr);
5101 		op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5102 #endif
5103 #if 1
5104 		/* disable CSE */
5105 		ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5106 		jit->ctx.fold_cse_limit = 0x7fffffff;
5107 #endif
5108 		op1 = ir_INT2D(op1);
5109 		op2 = ir_INT2D(op2);
5110 #if 1
5111 		jit->ctx.fold_cse_limit = old_cse_limit;
5112 #endif
5113 		ref = ir_BINARY_OP_D(op, op1, op2);
5114 		jit_set_Z_DVAL(jit, res_addr, ref);
5115 		if (Z_MODE(res_addr) != IS_REG) {
5116 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5117 		}
5118 		if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5119 			ir_MERGE_WITH(fast_path);
5120 		}
5121 	}
5122 
5123 	return 1;
5124 }
5125 
zend_jit_math_long_double(zend_jit_ctx * jit,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_use_info)5126 static int zend_jit_math_long_double(zend_jit_ctx   *jit,
5127                                      uint8_t         opcode,
5128                                      zend_jit_addr   op1_addr,
5129                                      zend_jit_addr   op2_addr,
5130                                      zend_jit_addr   res_addr,
5131                                      uint32_t        res_use_info)
5132 {
5133 	ir_op op;
5134 	ir_ref op1, op2, ref;
5135 
5136 	if (opcode == ZEND_ADD) {
5137 		op = IR_ADD;
5138 	} else if (opcode == ZEND_SUB) {
5139 		op = IR_SUB;
5140 	} else if (opcode == ZEND_MUL) {
5141 		op = IR_MUL;
5142 	} else if (opcode == ZEND_DIV) {
5143 		op = IR_DIV;
5144 	} else {
5145 		ZEND_UNREACHABLE();
5146 	}
5147 	op1 = jit_Z_LVAL(jit, op1_addr);
5148 	op2 = jit_Z_DVAL(jit, op2_addr);
5149 	ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5150 	jit_set_Z_DVAL(jit, res_addr, ref);
5151 
5152 	if (Z_MODE(res_addr) != IS_REG) {
5153 		if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5154 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5155 		}
5156 	}
5157 	return 1;
5158 }
5159 
zend_jit_math_double_long(zend_jit_ctx * jit,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_use_info)5160 static int zend_jit_math_double_long(zend_jit_ctx   *jit,
5161                                      uint8_t         opcode,
5162                                      zend_jit_addr   op1_addr,
5163                                      zend_jit_addr   op2_addr,
5164                                      zend_jit_addr   res_addr,
5165                                      uint32_t        res_use_info)
5166 {
5167 	ir_op op;
5168 	ir_ref op1, op2, ref;
5169 
5170 	if (opcode == ZEND_ADD) {
5171 		op = IR_ADD;
5172 	} else if (opcode == ZEND_SUB) {
5173 		op = IR_SUB;
5174 	} else if (opcode == ZEND_MUL) {
5175 		op = IR_MUL;
5176 	} else if (opcode == ZEND_DIV) {
5177 		op = IR_DIV;
5178 	} else {
5179 		ZEND_UNREACHABLE();
5180 	}
5181 	op1 = jit_Z_DVAL(jit, op1_addr);
5182 	op2 = jit_Z_LVAL(jit, op2_addr);
5183 	ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5184 	jit_set_Z_DVAL(jit, res_addr, ref);
5185 
5186 	if (Z_MODE(res_addr) != IS_REG) {
5187 		if (!zend_jit_same_addr(op1_addr, res_addr)) {
5188 			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5189 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5190 			}
5191 		}
5192 	}
5193 	return 1;
5194 }
5195 
zend_jit_math_double_double(zend_jit_ctx * jit,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_use_info)5196 static int zend_jit_math_double_double(zend_jit_ctx   *jit,
5197                                        uint8_t         opcode,
5198                                        zend_jit_addr   op1_addr,
5199                                        zend_jit_addr   op2_addr,
5200                                        zend_jit_addr   res_addr,
5201                                        uint32_t        res_use_info)
5202 {
5203 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5204 	ir_op op;
5205 	ir_ref op1, op2, ref;
5206 
5207 	if (opcode == ZEND_ADD) {
5208 		op = IR_ADD;
5209 	} else if (opcode == ZEND_SUB) {
5210 		op = IR_SUB;
5211 	} else if (opcode == ZEND_MUL) {
5212 		op = IR_MUL;
5213 	} else if (opcode == ZEND_DIV) {
5214 		op = IR_DIV;
5215 	} else {
5216 		ZEND_UNREACHABLE();
5217 	}
5218 	op1 = jit_Z_DVAL(jit, op1_addr);
5219 	op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5220 	ref = ir_BINARY_OP_D(op, op1, op2);
5221 	jit_set_Z_DVAL(jit, res_addr, ref);
5222 
5223 	if (Z_MODE(res_addr) != IS_REG) {
5224 		if (!zend_jit_same_addr(op1_addr, res_addr)) {
5225 			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5226 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5227 			}
5228 		}
5229 	}
5230 	return 1;
5231 }
5232 
zend_jit_math_helper(zend_jit_ctx * jit,const zend_op * opline,uint8_t opcode,uint8_t op1_type,znode_op op1,zend_jit_addr op1_addr,uint32_t op1_info,uint8_t op2_type,znode_op op2,zend_jit_addr op2_addr,uint32_t op2_info,uint32_t res_var,zend_jit_addr res_addr,uint32_t res_info,uint32_t res_use_info,int may_overflow,int may_throw)5233 static int zend_jit_math_helper(zend_jit_ctx   *jit,
5234                                 const zend_op  *opline,
5235                                 uint8_t         opcode,
5236                                 uint8_t         op1_type,
5237                                 znode_op        op1,
5238                                 zend_jit_addr   op1_addr,
5239                                 uint32_t        op1_info,
5240                                 uint8_t         op2_type,
5241                                 znode_op        op2,
5242                                 zend_jit_addr   op2_addr,
5243                                 uint32_t        op2_info,
5244                                 uint32_t        res_var,
5245                                 zend_jit_addr   res_addr,
5246                                 uint32_t        res_info,
5247                                 uint32_t        res_use_info,
5248                                 int             may_overflow,
5249                                 int             may_throw)
5250 {
5251 	ir_ref if_op1_long = IR_UNUSED;
5252 	ir_ref if_op1_double = IR_UNUSED;
5253 	ir_ref if_op2_double = IR_UNUSED;
5254 	ir_ref if_op1_long_op2_long = IR_UNUSED;
5255 	ir_ref if_op1_long_op2_double = IR_UNUSED;
5256 	ir_ref if_op1_double_op2_double = IR_UNUSED;
5257 	ir_ref if_op1_double_op2_long = IR_UNUSED;
5258 	ir_ref slow_inputs = IR_UNUSED;
5259 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5260 	ir_refs *end_inputs;
5261 	ir_refs *res_inputs;
5262 
5263 	ir_refs_init(end_inputs, 6);
5264 	ir_refs_init(res_inputs, 6);
5265 
5266 	if (Z_MODE(op1_addr) == IS_REG) {
5267 		if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5268 			/* Force load */
5269 			zend_jit_use_reg(jit, op1_addr);
5270 		}
5271 	} else if (Z_MODE(op2_addr) == IS_REG) {
5272 		if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5273 			/* Force load */
5274 			zend_jit_use_reg(jit, op2_addr);
5275 		}
5276 	}
5277 
5278 	if (Z_MODE(res_addr) == IS_REG) {
5279 		jit->delay_var = Z_SSA_VAR(res_addr);
5280 		jit->delay_refs = res_inputs;
5281 	}
5282 
5283 	if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5284 		if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5285 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5286 			ir_IF_TRUE(if_op1_long);
5287 		}
5288 		if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5289 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5290 			ir_IF_TRUE(if_op1_long_op2_long);
5291 		}
5292 		if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5293 			return 0;
5294 		}
5295 		ir_refs_add(end_inputs, ir_END());
5296 		if (if_op1_long) {
5297 			ir_IF_FALSE_cold(if_op1_long);
5298 			ir_END_list(slow_inputs);
5299 		}
5300 		if (if_op1_long_op2_long) {
5301 			ir_IF_FALSE_cold(if_op1_long_op2_long);
5302 			ir_END_list(slow_inputs);
5303 		}
5304 	} else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
5305 		if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5306 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5307 			ir_IF_TRUE(if_op1_long);
5308 		}
5309 		if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5310 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5311 			ir_IF_FALSE_cold(if_op1_long_op2_long);
5312 			if (op2_info & MAY_BE_DOUBLE) {
5313 				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5314 					if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5315 					ir_IF_FALSE_cold(if_op1_long_op2_double);
5316 					ir_END_list(slow_inputs);
5317 					ir_IF_TRUE(if_op1_long_op2_double);
5318 				}
5319 				if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5320 					return 0;
5321 				}
5322 				ir_refs_add(end_inputs, ir_END());
5323 			} else {
5324 				ir_END_list(slow_inputs);
5325 			}
5326 			ir_IF_TRUE(if_op1_long_op2_long);
5327 		}
5328 		if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5329 			return 0;
5330 		}
5331 		ir_refs_add(end_inputs, ir_END());
5332 
5333 		if (if_op1_long) {
5334 			ir_IF_FALSE_cold(if_op1_long);
5335 		}
5336 
5337 		if (op1_info & MAY_BE_DOUBLE) {
5338 			if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5339 				if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5340 				ir_IF_FALSE_cold(if_op1_double);
5341 				ir_END_list(slow_inputs);
5342 				ir_IF_TRUE(if_op1_double);
5343 			}
5344 			if (op2_info & MAY_BE_DOUBLE) {
5345 				if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5346 					if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5347 					ir_IF_TRUE(if_op1_double_op2_double);
5348 				}
5349 				if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5350 					return 0;
5351 				}
5352 				ir_refs_add(end_inputs, ir_END());
5353 				if (if_op1_double_op2_double) {
5354 					ir_IF_FALSE_cold(if_op1_double_op2_double);
5355 				}
5356 			}
5357 			if (!same_ops) {
5358 				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5359 					if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5360 					ir_IF_FALSE_cold(if_op1_double_op2_long);
5361 					ir_END_list(slow_inputs);
5362 					ir_IF_TRUE(if_op1_double_op2_long);
5363 				}
5364 				if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5365 					return 0;
5366 				}
5367 				ir_refs_add(end_inputs, ir_END());
5368 			} else if (if_op1_double_op2_double) {
5369 				ir_END_list(slow_inputs);
5370 			}
5371 		} else if (if_op1_long) {
5372 			ir_END_list(slow_inputs);
5373 		}
5374 	} else if ((op1_info & MAY_BE_DOUBLE) &&
5375 	           !(op1_info & MAY_BE_LONG) &&
5376 	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5377 	           (res_info & MAY_BE_DOUBLE)) {
5378 		if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5379 			if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5380 			ir_IF_FALSE_cold(if_op1_double);
5381 			ir_END_list(slow_inputs);
5382 			ir_IF_TRUE(if_op1_double);
5383 		}
5384 		if (op2_info & MAY_BE_DOUBLE) {
5385 			if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5386 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5387 				ir_IF_TRUE(if_op1_double_op2_double);
5388 			}
5389 			if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5390 				return 0;
5391 			}
5392 			ir_refs_add(end_inputs, ir_END());
5393 			if (if_op1_double_op2_double) {
5394 				ir_IF_FALSE_cold(if_op1_double_op2_double);
5395 			}
5396 		}
5397 		if (!same_ops && (op2_info & MAY_BE_LONG)) {
5398 			if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5399 				if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5400 				ir_IF_FALSE_cold(if_op1_double_op2_long);
5401 				ir_END_list(slow_inputs);
5402 				ir_IF_TRUE(if_op1_double_op2_long);
5403 			}
5404 			if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5405 				return 0;
5406 			}
5407 			ir_refs_add(end_inputs, ir_END());
5408 		} else if (if_op1_double_op2_double) {
5409 			ir_END_list(slow_inputs);
5410 		}
5411 	} else if ((op2_info & MAY_BE_DOUBLE) &&
5412 	           !(op2_info & MAY_BE_LONG) &&
5413 	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5414 	           (res_info & MAY_BE_DOUBLE)) {
5415 		if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5416 			if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5417 			ir_IF_FALSE_cold(if_op2_double);
5418 			ir_END_list(slow_inputs);
5419 			ir_IF_TRUE(if_op2_double);
5420 		}
5421 		if (op1_info & MAY_BE_DOUBLE) {
5422 			if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5423 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5424 				ir_IF_TRUE(if_op1_double_op2_double);
5425 			}
5426 			if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5427 				return 0;
5428 			}
5429 			ir_refs_add(end_inputs, ir_END());
5430 			if (if_op1_double_op2_double) {
5431 				ir_IF_FALSE_cold(if_op1_double_op2_double);
5432 			}
5433 		}
5434 		if (!same_ops && (op1_info & MAY_BE_LONG)) {
5435 			if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5436 				if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5437 				ir_IF_FALSE_cold(if_op1_long_op2_double);
5438 				ir_END_list(slow_inputs);
5439 				ir_IF_TRUE(if_op1_long_op2_double);
5440 			}
5441 			if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5442 				return 0;
5443 			}
5444 			ir_refs_add(end_inputs, ir_END());
5445 		} else if (if_op1_double_op2_double) {
5446 			ir_END_list(slow_inputs);
5447 		}
5448 	}
5449 
5450 	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5451 		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5452 		ir_ref func, arg1, arg2, arg3;
5453 
5454 		if (slow_inputs) {
5455 			ir_MERGE_list(slow_inputs);
5456 		}
5457 
5458 		if (Z_MODE(op1_addr) == IS_REG) {
5459 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5460 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5461 				return 0;
5462 			}
5463 			op1_addr = real_addr;
5464 		}
5465 		if (Z_MODE(op2_addr) == IS_REG) {
5466 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5467 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5468 				return 0;
5469 			}
5470 			op2_addr = real_addr;
5471 		}
5472 		if (Z_MODE(res_addr) == IS_REG) {
5473 			arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5474 		} else {
5475 			arg1 = jit_ZVAL_ADDR(jit, res_addr);
5476 		}
5477 		arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5478 		arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5479 		jit_SET_EX_OPLINE(jit, opline);
5480 		if (opcode == ZEND_ADD) {
5481 			func = ir_CONST_FC_FUNC(add_function);
5482 		} else if (opcode == ZEND_SUB) {
5483 			func = ir_CONST_FC_FUNC(sub_function);
5484 		} else if (opcode == ZEND_MUL) {
5485 			func = ir_CONST_FC_FUNC(mul_function);
5486 		} else if (opcode == ZEND_DIV) {
5487 			func = ir_CONST_FC_FUNC(div_function);
5488 		} else {
5489 			ZEND_UNREACHABLE();
5490 		}
5491 		ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5492 
5493 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5494 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5495 
5496 		if (may_throw) {
5497 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5498 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5499 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5500 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5501 				zend_jit_check_exception_undef_result(jit, opline);
5502 			} else {
5503 				zend_jit_check_exception(jit);
5504 			}
5505 		}
5506 		if (Z_MODE(res_addr) == IS_REG) {
5507 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5508 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5509 				return 0;
5510 			}
5511 		}
5512 		ir_refs_add(end_inputs, ir_END());
5513 	}
5514 
5515 	if (end_inputs->count) {
5516 		ir_MERGE_N(end_inputs->count, end_inputs->refs);
5517 	}
5518 
5519 	if (Z_MODE(res_addr) == IS_REG) {
5520 		ZEND_ASSERT(jit->delay_refs == res_inputs);
5521 		ZEND_ASSERT(end_inputs->count == res_inputs->count);
5522 		jit->delay_var = -1;
5523 		jit->delay_refs = NULL;
5524 		if (res_inputs->count == 1) {
5525 			zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5526 		} else {
5527 			ir_ref phi = ir_PHI_N((res_info & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE, res_inputs->count, res_inputs->refs);
5528 			zend_jit_def_reg(jit, res_addr, phi);
5529 		}
5530 	}
5531 
5532 	return 1;
5533 }
5534 
zend_jit_math(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint32_t op2_info,zend_jit_addr op2_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr,int may_overflow,int may_throw)5535 static int zend_jit_math(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
5536 {
5537 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5538 
5539 	if (!zend_jit_math_helper(jit, opline, opline->opcode, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->result.var, res_addr, res_info, res_use_info, may_overflow, may_throw)) {
5540 		return 0;
5541 	}
5542 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5543 		return 0;
5544 	}
5545 	return 1;
5546 }
5547 
zend_jit_add_arrays(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint32_t op2_info,zend_jit_addr op2_addr,zend_jit_addr res_addr)5548 static int zend_jit_add_arrays(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr)
5549 {
5550 	ir_ref ref;
5551 	ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5552 	ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5553 
5554 	ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5555 	jit_set_Z_PTR(jit, res_addr, ref);
5556 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5557 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5558 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5559 	return 1;
5560 }
5561 
zend_jit_long_math_helper(zend_jit_ctx * jit,const zend_op * opline,uint8_t opcode,uint8_t op1_type,znode_op op1,zend_jit_addr op1_addr,uint32_t op1_info,zend_ssa_range * op1_range,uint8_t op2_type,znode_op op2,zend_jit_addr op2_addr,uint32_t op2_info,zend_ssa_range * op2_range,uint32_t res_var,zend_jit_addr res_addr,uint32_t res_info,uint32_t res_use_info,int may_throw)5562 static int zend_jit_long_math_helper(zend_jit_ctx   *jit,
5563                                      const zend_op  *opline,
5564                                      uint8_t         opcode,
5565                                      uint8_t         op1_type,
5566                                      znode_op        op1,
5567                                      zend_jit_addr   op1_addr,
5568                                      uint32_t        op1_info,
5569                                      zend_ssa_range *op1_range,
5570                                      uint8_t         op2_type,
5571                                      znode_op        op2,
5572                                      zend_jit_addr   op2_addr,
5573                                      uint32_t        op2_info,
5574                                      zend_ssa_range *op2_range,
5575                                      uint32_t        res_var,
5576                                      zend_jit_addr   res_addr,
5577                                      uint32_t        res_info,
5578                                      uint32_t        res_use_info,
5579                                      int             may_throw)
5580 {
5581 	ir_ref ref = IR_UNUSED;
5582 	ir_ref if_long1 = IR_UNUSED;
5583 	ir_ref if_long2 = IR_UNUSED;
5584 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5585 	ir_refs *res_inputs;
5586 
5587 	ir_refs_init(res_inputs, 2);
5588 
5589 	if (Z_MODE(op1_addr) == IS_REG
5590 	 && Z_LOAD(op1_addr)
5591 	 && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5592 		/* Force load */
5593 		zend_jit_use_reg(jit, op1_addr);
5594 	}
5595 	if (Z_MODE(op2_addr) == IS_REG
5596 	 && Z_LOAD(op2_addr)
5597 	 && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5598 		/* Force load */
5599 		zend_jit_use_reg(jit, op2_addr);
5600 	}
5601 
5602 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5603 		if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5604 		ir_IF_TRUE(if_long1);
5605 	}
5606 	if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5607 		if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5608 		ir_IF_TRUE(if_long2);
5609 	}
5610 
5611 	if (opcode == ZEND_SL) {
5612 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5613 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5614 
5615 			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5616 				if (EXPECTED(op2_lval > 0)) {
5617 					ref = ir_CONST_LONG(0);
5618 				} else {
5619 					zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5620 					zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5621 					jit_SET_EX_OPLINE(jit, opline);
5622 					ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5623 					if (Z_MODE(res_addr) == IS_REG) {
5624 						ref = ir_CONST_LONG(0); // dead code
5625 					}
5626 				}
5627 			} else {
5628 				ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5629 			}
5630 		} else {
5631 			ref = jit_Z_LVAL(jit, op2_addr);
5632 			if (!op2_range ||
5633 			     op2_range->min < 0 ||
5634 			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5635 
5636 				ir_ref if_wrong, cold_path, ref2, if_ok;
5637 				ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5638 
5639 				if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5640 				ir_IF_TRUE_cold(if_wrong);
5641 				if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5642 				ir_IF_FALSE(if_ok);
5643 				jit_SET_EX_OPLINE(jit, opline);
5644 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5645 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5646 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5647 				ir_IF_TRUE(if_ok);
5648 				ref2 = ir_CONST_LONG(0);
5649 				cold_path = ir_END();
5650 				ir_IF_FALSE(if_wrong);
5651 				ref = ir_SHL_L(op1_ref, ref);
5652 				ir_MERGE_WITH(cold_path);
5653 				ref = ir_PHI_2(IR_LONG, ref, ref2);
5654 			} else {
5655 				ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5656 			}
5657 		}
5658 	} else if (opcode == ZEND_SR) {
5659 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5660 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5661 
5662 			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5663 				if (EXPECTED(op2_lval > 0)) {
5664 					ref = ir_SAR_L(
5665 						jit_Z_LVAL(jit, op1_addr),
5666 						ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5667 				} else {
5668 					zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5669 					zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5670 					jit_SET_EX_OPLINE(jit, opline);
5671 					ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5672 					if (Z_MODE(res_addr) == IS_REG) {
5673 						ref = ir_CONST_LONG(0); // dead code
5674 					}
5675 				}
5676 			} else {
5677 				ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5678 			}
5679 		} else {
5680 			ref = jit_Z_LVAL(jit, op2_addr);
5681 			if (!op2_range ||
5682 			     op2_range->min < 0 ||
5683 			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5684 
5685 				ir_ref if_wrong, cold_path, ref2, if_ok;
5686 
5687 				if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5688 				ir_IF_TRUE_cold(if_wrong);
5689 				if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5690 				ir_IF_FALSE(if_ok);
5691 				jit_SET_EX_OPLINE(jit, opline);
5692 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5693 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5694 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5695 				ir_IF_TRUE(if_ok);
5696 				ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5697 				cold_path = ir_END();
5698 				ir_IF_FALSE(if_wrong);
5699 				ir_MERGE_WITH(cold_path);
5700 				ref = ir_PHI_2(IR_LONG, ref, ref2);
5701 			}
5702 			ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5703 		}
5704 	} else if (opcode == ZEND_MOD) {
5705 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5706 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5707 
5708 			if (op2_lval == 0) {
5709 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5710 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5711 				jit_SET_EX_OPLINE(jit, opline);
5712 				ir_GUARD(IR_FALSE,	jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5713 				if (Z_MODE(res_addr) == IS_REG) {
5714 					ref = ir_CONST_LONG(0); // dead code
5715 				}
5716 			} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5717 				ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5718 			} else {
5719 				ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5720 			}
5721 		} else {
5722 			ir_ref zero_path = 0;
5723 			ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5724 
5725 			ref = jit_Z_LVAL(jit, op2_addr);
5726 			if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5727 				ir_ref if_ok = ir_IF(ref);
5728 				ir_IF_FALSE(if_ok);
5729 				jit_SET_EX_OPLINE(jit, opline);
5730 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5731 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5732 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5733 				ir_IF_TRUE(if_ok);
5734 			}
5735 
5736 			/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5737 			if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5738 				ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5739 				ir_IF_TRUE_cold(if_minus_one);
5740 				zero_path = ir_END();
5741 				ir_IF_FALSE(if_minus_one);
5742 			}
5743 			ref = ir_MOD_L(op1_ref, ref);
5744 
5745 			if (zero_path) {
5746 				ir_MERGE_WITH(zero_path);
5747 				ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5748 			}
5749 		}
5750 	} else {
5751 		ir_op op;
5752 		ir_ref op1, op2;
5753 
5754 		if (opcode == ZEND_BW_OR) {
5755 			op = IR_OR;
5756 		} else if (opcode == ZEND_BW_AND) {
5757 			op = IR_AND;
5758 		} else if (opcode == ZEND_BW_XOR) {
5759 			op = IR_XOR;
5760 		} else {
5761 			ZEND_UNREACHABLE();
5762 		}
5763 		op1 = jit_Z_LVAL(jit, op1_addr);
5764 		op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5765 		ref = ir_BINARY_OP_L(op, op1, op2);
5766 	}
5767 
5768 	if (ref) {
5769 		if (Z_MODE(res_addr) == IS_REG
5770 		 && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5771 		  || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5772 			jit->delay_var = Z_SSA_VAR(res_addr);
5773 			jit->delay_refs = res_inputs;
5774 		}
5775 		jit_set_Z_LVAL(jit, res_addr, ref);
5776 		if (Z_MODE(res_addr) != IS_REG) {
5777 			if (!zend_jit_same_addr(op1_addr, res_addr)) {
5778 				if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5779 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5780 				}
5781 			}
5782 		}
5783 	}
5784 
5785 	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5786 		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5787 		ir_ref fast_path = ir_END();
5788 		ir_ref func, arg1, arg2, arg3;
5789 
5790 		if (if_long2 && if_long1) {
5791 			ir_ref ref;
5792 			ir_IF_FALSE_cold(if_long2);
5793 			ref = ir_END();
5794 			ir_IF_FALSE_cold(if_long1);
5795 			ir_MERGE_2(ref, ir_END());
5796 		} else if (if_long1) {
5797 			ir_IF_FALSE_cold(if_long1);
5798 		} else if (if_long2) {
5799 			ir_IF_FALSE_cold(if_long2);
5800 		}
5801 
5802 		if (op1_info & MAY_BE_UNDEF) {
5803 			ir_ref if_def, ref, ref2;
5804 
5805 			ref = jit_ZVAL_ADDR(jit, op1_addr);
5806 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5807 			ir_IF_FALSE_cold(if_def);
5808 
5809 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5810 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5811 
5812 			ref2 = jit_EG(uninitialized_zval);
5813 			ir_MERGE_WITH_EMPTY_TRUE(if_def);
5814 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
5815 			op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5816 		}
5817 
5818 		if (op2_info & MAY_BE_UNDEF) {
5819 			ir_ref if_def, ref, ref2;
5820 
5821 			ref = jit_ZVAL_ADDR(jit, op2_addr);
5822 			if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5823 			ir_IF_FALSE_cold(if_def);
5824 
5825 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
5826 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
5827 
5828 			ref2 = jit_EG(uninitialized_zval);
5829 			ir_MERGE_WITH_EMPTY_TRUE(if_def);
5830 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
5831 			op2_addr = ZEND_ADDR_REF_ZVAL(ref);
5832 		}
5833 
5834 		if (Z_MODE(op1_addr) == IS_REG) {
5835 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5836 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5837 				return 0;
5838 			}
5839 			op1_addr = real_addr;
5840 		}
5841 		if (Z_MODE(op2_addr) == IS_REG) {
5842 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5843 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5844 				return 0;
5845 			}
5846 			op2_addr = real_addr;
5847 		}
5848 		if (Z_MODE(res_addr) == IS_REG) {
5849 			arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5850 		} else {
5851 			arg1 = jit_ZVAL_ADDR(jit, res_addr);
5852 		}
5853 		arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5854 		arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5855 		jit_SET_EX_OPLINE(jit, opline);
5856 		if (opcode == ZEND_BW_OR) {
5857 			func = ir_CONST_FC_FUNC(bitwise_or_function);
5858 		} else if (opcode == ZEND_BW_AND) {
5859 			func = ir_CONST_FC_FUNC(bitwise_and_function);
5860 		} else if (opcode == ZEND_BW_XOR) {
5861 			func = ir_CONST_FC_FUNC(bitwise_xor_function);
5862 		} else if (opcode == ZEND_SL) {
5863 			func = ir_CONST_FC_FUNC(shift_left_function);
5864 		} else if (opcode == ZEND_SR) {
5865 			func = ir_CONST_FC_FUNC(shift_right_function);
5866 		} else if (opcode == ZEND_MOD) {
5867 			func = ir_CONST_FC_FUNC(mod_function);
5868 		} else {
5869 			ZEND_UNREACHABLE();
5870 		}
5871 		ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5872 
5873 		if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5874 			/* compound assignment may decrement "op2" refcount */
5875 			op2_info |= MAY_BE_RC1;
5876 		}
5877 
5878 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5879 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5880 
5881 		if (may_throw) {
5882 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5883 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5884 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5885 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5886 				zend_jit_check_exception_undef_result(jit, opline);
5887 			} else {
5888 				zend_jit_check_exception(jit);
5889 			}
5890 		}
5891 
5892 		if (Z_MODE(res_addr) == IS_REG) {
5893 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5894 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5895 				return 0;
5896 			}
5897 		}
5898 
5899 		ir_MERGE_2(fast_path, ir_END());
5900 
5901 		if (Z_MODE(res_addr) == IS_REG) {
5902 			ZEND_ASSERT(jit->delay_refs == res_inputs);
5903 			ZEND_ASSERT(res_inputs->count == 2);
5904 			jit->delay_var = -1;
5905 			jit->delay_refs = NULL;
5906 			if (res_inputs->count == 1) {
5907 				zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5908 			} else {
5909 				ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
5910 				zend_jit_def_reg(jit, res_addr, phi);
5911 			}
5912 		}
5913 	}
5914 
5915 	return 1;
5916 }
5917 
zend_jit_long_math(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_ssa_range * op1_range,zend_jit_addr op1_addr,uint32_t op2_info,zend_ssa_range * op2_range,zend_jit_addr op2_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr,int may_throw)5918 static int zend_jit_long_math(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
5919 {
5920 	ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
5921 
5922 	if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
5923 			opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
5924 			opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
5925 			opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
5926 		return 0;
5927 	}
5928 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5929 		return 0;
5930 	}
5931 	return 1;
5932 }
5933 
zend_jit_concat_helper(zend_jit_ctx * jit,const zend_op * opline,uint8_t op1_type,znode_op op1,zend_jit_addr op1_addr,uint32_t op1_info,uint8_t op2_type,znode_op op2,zend_jit_addr op2_addr,uint32_t op2_info,zend_jit_addr res_addr,int may_throw)5934 static int zend_jit_concat_helper(zend_jit_ctx   *jit,
5935                                   const zend_op  *opline,
5936                                   uint8_t         op1_type,
5937                                   znode_op        op1,
5938                                   zend_jit_addr   op1_addr,
5939                                   uint32_t        op1_info,
5940                                   uint8_t         op2_type,
5941                                   znode_op        op2,
5942                                   zend_jit_addr   op2_addr,
5943                                   uint32_t        op2_info,
5944                                   zend_jit_addr   res_addr,
5945                                   int             may_throw)
5946 {
5947 	ir_ref if_op1_string = IR_UNUSED;
5948 	ir_ref if_op2_string = IR_UNUSED;
5949 	ir_ref fast_path = IR_UNUSED;
5950 
5951 	if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5952 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5953 			if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
5954 			ir_IF_TRUE(if_op1_string);
5955 		}
5956 		if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5957 			if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
5958 			ir_IF_TRUE(if_op2_string);
5959 		}
5960 		if (zend_jit_same_addr(op1_addr, res_addr)) {
5961 			ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5962 			ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
5963 
5964 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
5965 			/* concatenation with itself may reduce refcount */
5966 			op2_info |= MAY_BE_RC1;
5967 		} else {
5968 			ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5969 			ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5970 			ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5971 
5972 			if (op1_type == IS_CV || op1_type == IS_CONST) {
5973 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
5974 			} else {
5975 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
5976 			}
5977 		}
5978 		/* concatenation with empty string may increase refcount */
5979 		op2_info |= MAY_BE_RCN;
5980 		jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
5981 		if (if_op1_string || if_op2_string) {
5982 			fast_path = ir_END();
5983 		}
5984 	}
5985 	if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
5986 	    (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
5987 		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5988 			if (if_op1_string && if_op2_string) {
5989 				ir_IF_FALSE(if_op1_string);
5990 				ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
5991 			} else if (if_op1_string) {
5992 				ir_IF_FALSE_cold(if_op1_string);
5993 			} else if (if_op2_string) {
5994 				ir_IF_FALSE_cold(if_op2_string);
5995 			}
5996 		}
5997 		ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5998 		ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5999 		ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6000 
6001 		jit_SET_EX_OPLINE(jit, opline);
6002 		ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(concat_function), arg1, arg2, arg3);
6003 		/* concatenation with empty string may increase refcount */
6004 		op1_info |= MAY_BE_RCN;
6005 		op2_info |= MAY_BE_RCN;
6006 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6007 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6008 		if (may_throw) {
6009 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6010 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6011 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6012 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6013 				zend_jit_check_exception_undef_result(jit, opline);
6014 			} else {
6015 				zend_jit_check_exception(jit);
6016 			}
6017 		}
6018 		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6019 			ir_MERGE_WITH(fast_path);
6020 		}
6021 	}
6022 	return 1;
6023 }
6024 
zend_jit_concat(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,uint32_t op2_info,zend_jit_addr res_addr,int may_throw)6025 static int zend_jit_concat(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr, int may_throw)
6026 {
6027 	zend_jit_addr op1_addr, op2_addr;
6028 
6029 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6030 	ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
6031 
6032 	op1_addr = OP1_ADDR();
6033 	op2_addr = OP2_ADDR();
6034 
6035 	return zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, may_throw);
6036 }
6037 
zend_jit_assign_op(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,zend_ssa_range * op1_range,uint32_t op1_def_info,zend_jit_addr op1_def_addr,uint32_t op1_mem_info,uint32_t op2_info,zend_jit_addr op2_addr,zend_ssa_range * op2_range,int may_overflow,int may_throw)6038 static int zend_jit_assign_op(zend_jit_ctx   *jit,
6039                               const zend_op  *opline,
6040                               uint32_t        op1_info,
6041                               zend_jit_addr   op1_addr,
6042                               zend_ssa_range *op1_range,
6043                               uint32_t        op1_def_info,
6044                               zend_jit_addr   op1_def_addr,
6045                               uint32_t        op1_mem_info,
6046                               uint32_t        op2_info,
6047                               zend_jit_addr   op2_addr,
6048                               zend_ssa_range *op2_range,
6049                               int             may_overflow,
6050                               int             may_throw)
6051 {
6052 	int result = 1;
6053 	ir_ref slow_path = IR_UNUSED;
6054 
6055 	ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6056 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6057 
6058 	if (op1_info & MAY_BE_REF) {
6059 		ir_ref ref, ref2, arg2, op1_noref_path;
6060 		ir_ref if_op1_ref = IR_UNUSED;
6061 		ir_ref if_op1_typed = IR_UNUSED;
6062 		binary_op_type binary_op = get_binary_op(opline->extended_value);
6063 
6064 		ref = jit_ZVAL_ADDR(jit, op1_addr);
6065 		if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6066 		ir_IF_FALSE(if_op1_ref);
6067 		op1_noref_path = ir_END();
6068 		ir_IF_TRUE(if_op1_ref);
6069 		ref2 = jit_Z_PTR_ref(jit, ref);
6070 
6071 		if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6072 		ir_IF_TRUE_cold(if_op1_typed);
6073 
6074 		if (Z_MODE(op2_addr) == IS_REG) {
6075 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6076 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6077 				return 0;
6078 			}
6079 			arg2 = jit_ZVAL_ADDR(jit, real_addr);
6080 		} else {
6081 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6082 		}
6083 		jit_SET_EX_OPLINE(jit, opline);
6084 		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6085 		 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6086 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6087 				ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6088 		} else {
6089 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6090 				ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6091 		}
6092 		zend_jit_check_exception(jit);
6093 		slow_path = ir_END();
6094 
6095 		ir_IF_FALSE(if_op1_typed);
6096 		ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6097 
6098 		ir_MERGE_WITH(op1_noref_path);
6099 		ref = ir_PHI_2(IR_ADDR, ref2, ref);
6100 		ZEND_ASSERT(op1_addr == op1_def_addr);
6101 		op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6102 	}
6103 
6104 	switch (opline->extended_value) {
6105 		case ZEND_ADD:
6106 		case ZEND_SUB:
6107 		case ZEND_MUL:
6108 		case ZEND_DIV:
6109 			result = zend_jit_math_helper(jit, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_overflow, may_throw);
6110 			break;
6111 		case ZEND_BW_OR:
6112 		case ZEND_BW_AND:
6113 		case ZEND_BW_XOR:
6114 		case ZEND_SL:
6115 		case ZEND_SR:
6116 		case ZEND_MOD:
6117 			result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6118 				opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6119 				opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6120 				opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6121 			break;
6122 		case ZEND_CONCAT:
6123 			result = zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_def_addr, may_throw);
6124 			break;
6125 		default:
6126 			ZEND_UNREACHABLE();
6127 	}
6128 
6129 	if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
6130 		return 0;
6131 	}
6132 
6133 	if (op1_info & MAY_BE_REF) {
6134 		ir_MERGE_WITH(slow_path);
6135 	}
6136 
6137 	return result;
6138 }
6139 
jit_ZVAL_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6140 static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6141 {
6142 	ir_ref if_ref, ref2;
6143 
6144 	if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6145 	ir_IF_TRUE(if_ref);
6146 	ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6147 	ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6148 	return ir_PHI_2(IR_ADDR, ref2, ref);
6149 }
6150 
jit_ZVAL_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6151 static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6152 {
6153 	ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6154 	ref = jit_ZVAL_DEREF_ref(jit, ref);
6155 	return ZEND_ADDR_REF_ZVAL(ref);
6156 }
6157 
jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6158 static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6159 {
6160 	ir_ref if_ref, ref2;
6161 
6162 	if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6163 	ir_IF_TRUE(if_ref);
6164 	ref2 = jit_Z_PTR_ref(jit, ref);
6165 	ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6166 	return ir_PHI_2(IR_ADDR, ref2, ref);
6167 }
6168 
jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6169 static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6170 {
6171 	ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6172 	ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6173 	return ZEND_ADDR_REF_ZVAL(ref);
6174 }
6175 
zend_jit_simple_assign(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr var_addr,uint32_t var_info,uint32_t var_def_info,uint8_t val_type,zend_jit_addr val_addr,uint32_t val_info,zend_jit_addr res_addr,bool check_exception)6176 static int zend_jit_simple_assign(zend_jit_ctx   *jit,
6177                                   const zend_op  *opline,
6178                                   zend_jit_addr   var_addr,
6179                                   uint32_t        var_info,
6180                                   uint32_t        var_def_info,
6181                                   uint8_t         val_type,
6182                                   zend_jit_addr   val_addr,
6183                                   uint32_t        val_info,
6184                                   zend_jit_addr   res_addr,
6185                                   bool            check_exception)
6186 {
6187 	ir_ref end_inputs = IR_UNUSED;
6188 
6189 	if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6190 		zval *zv = Z_ZV(val_addr);
6191 
6192 		if (!res_addr) {
6193 			jit_ZVAL_COPY_CONST(jit,
6194 				var_addr,
6195 				var_info, var_def_info,
6196 				zv, 1);
6197 		} else {
6198 			jit_ZVAL_COPY_CONST(jit,
6199 				var_addr,
6200 				var_info, var_def_info,
6201 				zv, 1);
6202 			jit_ZVAL_COPY_CONST(jit,
6203 				res_addr,
6204 				-1, var_def_info,
6205 				zv, 1);
6206 		}
6207 	} else {
6208 		if (val_info & MAY_BE_UNDEF) {
6209 			ir_ref if_def, ret;
6210 
6211 			if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6212 			ir_IF_FALSE_cold(if_def);
6213 
6214 			jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6215 			if (res_addr) {
6216 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6217 			}
6218 			jit_SET_EX_OPLINE(jit, opline);
6219 
6220 			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6221 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6222 			ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6223 
6224 			if (check_exception) {
6225 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6226 			}
6227 
6228 			ir_END_list(end_inputs);
6229 			ir_IF_TRUE(if_def);
6230 		}
6231 		if (val_info & MAY_BE_REF) {
6232 			if (val_type == IS_CV) {
6233 				ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6234 				ref = jit_ZVAL_DEREF_ref(jit, ref);
6235 				val_addr = ZEND_ADDR_REF_ZVAL(ref);
6236 			} else {
6237 				ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6238 
6239 				ref = jit_ZVAL_ADDR(jit, val_addr);
6240 				type = jit_Z_TYPE_ref(jit, ref);
6241 				if_ref = ir_IF(ir_EQ(type, ir_CONST_U8(IS_REFERENCE)));
6242 
6243 				ir_IF_TRUE_cold(if_ref);
6244 				ref = jit_Z_PTR_ref(jit, ref);
6245 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
6246 				if (!res_addr) {
6247 					jit_ZVAL_COPY(jit,
6248 						var_addr,
6249 						var_info,
6250 						ZEND_ADDR_REF_ZVAL(ref2), val_info, 1);
6251 				} else {
6252 					jit_ZVAL_COPY_2(jit,
6253 						res_addr,
6254 						var_addr,
6255 						var_info,
6256 						ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6257 				}
6258 
6259 				refcount = jit_GC_DELREF(jit, ref);
6260 				if_not_zero = ir_IF(refcount);
6261 				ir_IF_FALSE(if_not_zero);
6262 				// TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6263 				// This is related to GH-10168 (keep this before GH-10168 is completely closed)
6264 				// jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6265 				jit_ZVAL_DTOR(jit, ref, val_info, opline);
6266 				ir_END_list(end_inputs);
6267 				ir_IF_TRUE(if_not_zero);
6268 				ir_END_list(end_inputs);
6269 
6270 				ir_IF_FALSE(if_ref);
6271 			}
6272 		}
6273 
6274 		if (!res_addr) {
6275 			jit_ZVAL_COPY(jit,
6276 				var_addr,
6277 				var_info,
6278 				val_addr, val_info, val_type == IS_CV);
6279 		} else {
6280 			jit_ZVAL_COPY_2(jit,
6281 				res_addr,
6282 				var_addr,
6283 				var_info,
6284 				val_addr, val_info, val_type == IS_CV ? 2 : 1);
6285 		}
6286 	}
6287 
6288 	if (end_inputs) {
6289 		ir_END_list(end_inputs);
6290 		ir_MERGE_list(end_inputs);
6291 	}
6292 
6293 	return 1;
6294 }
6295 
zend_jit_assign_to_variable_call(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr __var_use_addr,zend_jit_addr var_addr,uint32_t __var_info,uint32_t __var_def_info,uint8_t val_type,zend_jit_addr val_addr,uint32_t val_info,zend_jit_addr __res_addr,bool __check_exception)6296 static int zend_jit_assign_to_variable_call(zend_jit_ctx   *jit,
6297                                             const zend_op  *opline,
6298                                             zend_jit_addr   __var_use_addr,
6299                                             zend_jit_addr   var_addr,
6300                                             uint32_t        __var_info,
6301                                             uint32_t        __var_def_info,
6302                                             uint8_t         val_type,
6303                                             zend_jit_addr   val_addr,
6304                                             uint32_t        val_info,
6305                                             zend_jit_addr   __res_addr,
6306                                             bool       __check_exception)
6307 {
6308 	jit_stub_id func;
6309 	ir_ref undef_path = IR_UNUSED;
6310 
6311 	if (val_info & MAY_BE_UNDEF) {
6312 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6313 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6314 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6315 
6316 			if (!exit_addr) {
6317 				return 0;
6318 			}
6319 
6320 			jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6321 		} else {
6322 			ir_ref if_def;
6323 
6324 			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6325 			if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6326 			ir_IF_FALSE_cold(if_def);
6327 			jit_SET_EX_OPLINE(jit, opline);
6328 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6329 
6330 			ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6331 				jit_ZVAL_ADDR(jit, var_addr),
6332 				jit_EG(uninitialized_zval));
6333 
6334 			undef_path = ir_END();
6335 			ir_IF_TRUE(if_def);
6336 		}
6337 	}
6338 
6339 	if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6340 		func = jit_stub_assign_tmp;
6341 	} else if (val_type == IS_CONST) {
6342 		func = jit_stub_assign_const;
6343 	} else if (val_type == IS_TMP_VAR) {
6344 		func = jit_stub_assign_tmp;
6345 	} else if (val_type == IS_VAR) {
6346 		if (!(val_info & MAY_BE_REF)) {
6347 			func = jit_stub_assign_tmp;
6348 		} else {
6349 			func = jit_stub_assign_var;
6350 		}
6351 	} else if (val_type == IS_CV) {
6352 		if (!(val_info & MAY_BE_REF)) {
6353 			func = jit_stub_assign_cv_noref;
6354 		} else {
6355 			func = jit_stub_assign_cv;
6356 		}
6357 	} else {
6358 		ZEND_UNREACHABLE();
6359 	}
6360 
6361 	if (opline) {
6362 		jit_SET_EX_OPLINE(jit, opline);
6363 	}
6364 
6365 	ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6366 		jit_ZVAL_ADDR(jit, var_addr),
6367 		jit_ZVAL_ADDR(jit, val_addr));
6368 
6369 	if (undef_path) {
6370 		ir_MERGE_WITH(undef_path);
6371 	}
6372 
6373 	return 1;
6374 }
6375 
zend_jit_assign_to_variable(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr var_use_addr,zend_jit_addr var_addr,uint32_t var_info,uint32_t var_def_info,uint8_t val_type,zend_jit_addr val_addr,uint32_t val_info,zend_jit_addr res_addr,zend_jit_addr ref_addr,bool check_exception)6376 static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
6377                                        const zend_op  *opline,
6378                                        zend_jit_addr   var_use_addr,
6379                                        zend_jit_addr   var_addr,
6380                                        uint32_t        var_info,
6381                                        uint32_t        var_def_info,
6382                                        uint8_t         val_type,
6383                                        zend_jit_addr   val_addr,
6384                                        uint32_t        val_info,
6385                                        zend_jit_addr   res_addr,
6386                                        zend_jit_addr   ref_addr,
6387                                        bool       check_exception)
6388 {
6389 	ir_ref if_refcounted = IR_UNUSED;
6390 	ir_ref simple_inputs = IR_UNUSED;
6391 	bool done = 0;
6392 	zend_jit_addr real_res_addr = 0;
6393 	ir_refs *end_inputs;
6394 	ir_refs *res_inputs;
6395 
6396 	ir_refs_init(end_inputs, 6);
6397 	ir_refs_init(res_inputs, 6);
6398 
6399 	if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6400 		/* Force load */
6401 		zend_jit_use_reg(jit, val_addr);
6402 	}
6403 
6404 	if (Z_MODE(var_addr) == IS_REG) {
6405 		jit->delay_var = Z_SSA_VAR(var_addr);
6406 		jit->delay_refs = res_inputs;
6407 		if (Z_MODE(res_addr) == IS_REG) {
6408 			real_res_addr = res_addr;
6409 			res_addr = 0;
6410 		}
6411 	} else if (Z_MODE(res_addr) == IS_REG) {
6412 		jit->delay_var = Z_SSA_VAR(res_addr);
6413 		jit->delay_refs = res_inputs;
6414 	}
6415 
6416 	if ((var_info & MAY_BE_REF) || ref_addr) {
6417 		ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6418 		uintptr_t func;
6419 
6420 		if (!ref_addr) {
6421 			ref = jit_ZVAL_ADDR(jit, var_use_addr);
6422 			if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6423 			ir_IF_TRUE(if_ref);
6424 			ref2 = jit_Z_PTR_ref(jit, ref);
6425 		} else {
6426 			ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6427 		}
6428 		if_typed = jit_if_TYPED_REF(jit, ref2);
6429 		ir_IF_TRUE_cold(if_typed);
6430 		jit_SET_EX_OPLINE(jit, opline);
6431 		if (Z_MODE(val_addr) == IS_REG) {
6432 			zend_jit_addr real_addr;
6433 
6434 			if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6435 				real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6436 			} else {
6437 				ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6438 				real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6439 			}
6440 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6441 				return 0;
6442 			}
6443 			arg2 = jit_ZVAL_ADDR(jit, real_addr);
6444 		} else {
6445 			arg2 = jit_ZVAL_ADDR(jit, val_addr);
6446 		}
6447 		if (!res_addr) {
6448 			if (val_type == IS_CONST) {
6449 				func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6450 			} else if (val_type == IS_TMP_VAR) {
6451 				func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6452 			} else if (val_type == IS_VAR) {
6453 				func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6454 			} else if (val_type == IS_CV) {
6455 				func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6456 			} else {
6457 				ZEND_UNREACHABLE();
6458 			}
6459 			ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6460 		} else {
6461 			if (val_type == IS_CONST) {
6462 				func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6463 			} else if (val_type == IS_TMP_VAR) {
6464 				func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6465 			} else if (val_type == IS_VAR) {
6466 				func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6467 			} else if (val_type == IS_CV) {
6468 				func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6469 			} else {
6470 				ZEND_UNREACHABLE();
6471 			}
6472 			ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6473 		}
6474 		if (check_exception) {
6475 			zend_jit_check_exception(jit);
6476 		}
6477 		ir_refs_add(end_inputs, ir_END());
6478 
6479 		if (!ref_addr) {
6480 			ir_IF_FALSE(if_ref);
6481 			non_ref_path = ir_END();
6482 			ir_IF_FALSE(if_typed);
6483 			ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6484 			ir_MERGE_WITH(non_ref_path);
6485 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
6486 			var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6487 		} else {
6488 			ir_IF_FALSE(if_typed);
6489 		}
6490 	}
6491 
6492 	if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6493 		ir_ref ref, counter, if_not_zero;
6494 
6495 		if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6496 			if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6497 			ir_IF_FALSE(if_refcounted);
6498 			ir_END_list(simple_inputs);
6499 			ir_IF_TRUE_cold(if_refcounted);
6500 		} else if (RC_MAY_BE_1(var_info)) {
6501 			done = 1;
6502 		}
6503 		ref = jit_Z_PTR(jit, var_use_addr);
6504 		if (RC_MAY_BE_1(var_info)) {
6505 			if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0)) {
6506 				return 0;
6507 			}
6508 			counter = jit_GC_DELREF(jit, ref);
6509 
6510 			if_not_zero = ir_IF(counter);
6511 			ir_IF_FALSE(if_not_zero);
6512 			jit_ZVAL_DTOR(jit, ref, var_info, opline);
6513 			if (check_exception) {
6514 				zend_jit_check_exception(jit);
6515 			}
6516 			ir_refs_add(end_inputs, ir_END());
6517 			ir_IF_TRUE(if_not_zero);
6518 			if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6519 				ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6520 				ir_IF_FALSE(if_may_leak);
6521 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6522 
6523 				if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6524 					ZEND_ASSERT(jit->delay_refs == res_inputs);
6525 					ZEND_ASSERT(res_inputs->count > 0);
6526 					ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6527 				}
6528 				if (check_exception && (val_info & MAY_BE_UNDEF)) {
6529 					zend_jit_check_exception(jit);
6530 				}
6531 				ir_refs_add(end_inputs, ir_END());
6532 				ir_IF_TRUE(if_may_leak);
6533 			}
6534 			if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6535 				ZEND_ASSERT(jit->delay_refs == res_inputs);
6536 				ZEND_ASSERT(res_inputs->count > 0);
6537 				ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6538 			}
6539 			if (check_exception && (val_info & MAY_BE_UNDEF)) {
6540 				zend_jit_check_exception(jit);
6541 			}
6542 			ir_refs_add(end_inputs, ir_END());
6543 		} else /* if (RC_MAY_BE_N(var_info)) */ {
6544 			jit_GC_DELREF(jit, ref);
6545 			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6546 				ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6547 				ir_IF_FALSE(if_may_leak);
6548 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6549 				ir_END_list(simple_inputs);
6550 				ir_IF_TRUE(if_may_leak);
6551 			}
6552 			ir_END_list(simple_inputs);
6553 		}
6554 	}
6555 
6556 	if (simple_inputs) {
6557 		ir_MERGE_list(simple_inputs);
6558 	}
6559 
6560 	if (!done) {
6561 		if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6562 			return 0;
6563 		}
6564 		if (end_inputs->count) {
6565 			ir_refs_add(end_inputs, ir_END());
6566 		}
6567 	}
6568 
6569 	if (end_inputs->count) {
6570 		ir_MERGE_N(end_inputs->count, end_inputs->refs);
6571 	}
6572 
6573 	if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6574 		ir_ref phi;
6575 
6576 		ZEND_ASSERT(jit->delay_refs == res_inputs);
6577 		ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6578 		jit->delay_var = -1;
6579 		jit->delay_refs = NULL;
6580 		if (res_inputs->count == 1) {
6581 			phi = res_inputs->refs[0];
6582 		} else {
6583 			phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6584 				res_inputs->count, res_inputs->refs);
6585 		}
6586 		if (Z_MODE(var_addr) == IS_REG) {
6587 			if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6588 				phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6589 			}
6590 			zend_jit_def_reg(jit, var_addr, phi);
6591 			if (real_res_addr) {
6592 				if (var_def_info & MAY_BE_LONG) {
6593 					jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6594 				} else {
6595 					jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6596 				}
6597 			}
6598 		} else {
6599 			zend_jit_def_reg(jit, res_addr, phi);
6600 		}
6601 	}
6602 
6603 	return 1;
6604 }
6605 
zend_jit_qm_assign(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,zend_jit_addr op1_def_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr)6606 static int zend_jit_qm_assign(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr)
6607 {
6608 	if (op1_addr != op1_def_addr) {
6609 		if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6610 			return 0;
6611 		}
6612 		if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6613 			op1_addr = op1_def_addr;
6614 		}
6615 	}
6616 
6617 	if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 1)) {
6618 		return 0;
6619 	}
6620 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6621 		return 0;
6622 	}
6623 	return 1;
6624 }
6625 
zend_jit_assign(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_use_addr,uint32_t op1_def_info,zend_jit_addr op1_addr,uint32_t op2_info,zend_jit_addr op2_addr,zend_jit_addr op2_def_addr,uint32_t res_info,zend_jit_addr res_addr,zend_jit_addr ref_addr,int may_throw)6626 static int zend_jit_assign(zend_jit_ctx  *jit,
6627                            const zend_op *opline,
6628                            uint32_t       op1_info,
6629                            zend_jit_addr  op1_use_addr,
6630                            uint32_t       op1_def_info,
6631                            zend_jit_addr  op1_addr,
6632                            uint32_t       op2_info,
6633                            zend_jit_addr  op2_addr,
6634                            zend_jit_addr  op2_def_addr,
6635                            uint32_t       res_info,
6636                            zend_jit_addr  res_addr,
6637                            zend_jit_addr  ref_addr,
6638                            int            may_throw)
6639 {
6640 	ZEND_ASSERT(opline->op1_type == IS_CV);
6641 
6642 	if (op2_addr != op2_def_addr) {
6643 		if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6644 			return 0;
6645 		}
6646 		if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6647 			op2_addr = op2_def_addr;
6648 		}
6649 	}
6650 
6651 	if (Z_MODE(op1_addr) != IS_REG
6652 	 && Z_MODE(op1_use_addr) == IS_REG
6653 	 && !Z_LOAD(op1_use_addr)
6654 	 && !Z_STORE(op1_use_addr)) {
6655 		/* Force type update */
6656 		op1_info |= MAY_BE_UNDEF;
6657 	}
6658 	if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6659 			opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6660 		return 0;
6661 	}
6662 	if (Z_MODE(op1_addr) == IS_REG) {
6663 		if (Z_STORE(op1_addr)) {
6664 			if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6665 				return 0;
6666 			}
6667 		} else if ((op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
6668 			&& Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6669 			&& Z_REG(op1_use_addr) == ZREG_FP
6670 			&& EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6671 			/* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6672 			if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6673 				jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6674 				if (JIT_G(current_frame)) {
6675 					SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6676 				}
6677 			} else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6678 				jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6679 				if (JIT_G(current_frame)) {
6680 					SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6681 				}
6682 			} else {
6683 				ZEND_UNREACHABLE();
6684 			}
6685 		}
6686 	}
6687 	if (opline->result_type != IS_UNUSED) {
6688 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6689 			return 0;
6690 		}
6691 	}
6692 
6693 	return 1;
6694 }
6695 
zend_jit_cmp_op(const zend_op * opline)6696 static ir_op zend_jit_cmp_op(const zend_op *opline)
6697 {
6698 	ir_op op;
6699 
6700 	switch (opline->opcode) {
6701 		case ZEND_IS_EQUAL:
6702 		case ZEND_IS_IDENTICAL:
6703 		case ZEND_CASE:
6704 		case ZEND_CASE_STRICT:
6705 			op = IR_EQ;
6706 			break;
6707 		case ZEND_IS_NOT_EQUAL:
6708 		case ZEND_IS_NOT_IDENTICAL:
6709 			op = IR_NE;
6710 			break;
6711 		case ZEND_IS_SMALLER:
6712 			op = IR_LT;
6713 			break;
6714 		case ZEND_IS_SMALLER_OR_EQUAL:
6715 			op = IR_LE;
6716 			break;
6717 		default:
6718 			ZEND_UNREACHABLE();
6719 	}
6720 	return op;
6721 }
6722 
zend_jit_cmp_long_long(zend_jit_ctx * jit,const zend_op * opline,zend_ssa_range * op1_range,zend_jit_addr op1_addr,zend_ssa_range * op2_range,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr,bool skip_comparison)6723 static ir_ref zend_jit_cmp_long_long(zend_jit_ctx   *jit,
6724                                      const zend_op  *opline,
6725                                      zend_ssa_range *op1_range,
6726                                      zend_jit_addr   op1_addr,
6727                                      zend_ssa_range *op2_range,
6728                                      zend_jit_addr   op2_addr,
6729                                      zend_jit_addr   res_addr,
6730                                      uint8_t         smart_branch_opcode,
6731                                      uint32_t        target_label,
6732                                      uint32_t        target_label2,
6733                                      const void     *exit_addr,
6734                                      bool       skip_comparison)
6735 {
6736 	ir_ref ref;
6737 	bool result;
6738 
6739 	if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6740 		if (!smart_branch_opcode ||
6741 		    smart_branch_opcode == ZEND_JMPZ_EX ||
6742 		    smart_branch_opcode == ZEND_JMPNZ_EX) {
6743 			jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6744 		}
6745 		if (smart_branch_opcode && !exit_addr) {
6746 			if (smart_branch_opcode == ZEND_JMPZ ||
6747 			    smart_branch_opcode == ZEND_JMPZ_EX) {
6748 				return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6749 			} else if (smart_branch_opcode == ZEND_JMPNZ ||
6750 			           smart_branch_opcode == ZEND_JMPNZ_EX) {
6751 				return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6752 			} else {
6753 				ZEND_UNREACHABLE();
6754 			}
6755 		}
6756 		if (opline->opcode != ZEND_IS_IDENTICAL
6757 		 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6758 		 && opline->opcode != ZEND_CASE_STRICT) {
6759 			return ir_END();
6760 		} else {
6761 			return IR_NULL; /* success */
6762 		}
6763 	}
6764 
6765 	ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6766 
6767 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6768 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6769 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6770 	}
6771 	if (exit_addr) {
6772 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6773 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6774 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6775 			} else {
6776 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6777 			}
6778 		} else {
6779 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6780 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6781 			} else {
6782 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6783 			}
6784 		}
6785 	} else if (smart_branch_opcode) {
6786 		return jit_IF_ex(jit, ref,
6787 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6788 	}
6789 
6790 	if (opline->opcode != ZEND_IS_IDENTICAL
6791 	 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6792 	 && opline->opcode != ZEND_CASE_STRICT) {
6793 		return ir_END();
6794 	} else {
6795 		return IR_NULL; /* success */
6796 	}
6797 }
6798 
zend_jit_cmp_long_double(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6799 static ir_ref zend_jit_cmp_long_double(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6800 {
6801 	ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), ir_INT2D(jit_Z_LVAL(jit, op1_addr)), jit_Z_DVAL(jit, op2_addr));
6802 
6803 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6804 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6805 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6806 	}
6807 	if (exit_addr) {
6808 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6809 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6810 		} else {
6811 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6812 		}
6813 	} else if (smart_branch_opcode) {
6814 		return jit_IF_ex(jit, ref,
6815 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6816 	}
6817 	return ir_END();
6818 }
6819 
zend_jit_cmp_double_long(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6820 static ir_ref zend_jit_cmp_double_long(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6821 {
6822 	ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), ir_INT2D(jit_Z_LVAL(jit, op2_addr)));
6823 
6824 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6825 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6826 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6827 	}
6828 	if (exit_addr) {
6829 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6830 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6831 		} else {
6832 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6833 		}
6834 	} else if (smart_branch_opcode) {
6835 		return jit_IF_ex(jit, ref,
6836 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6837 	}
6838 	return ir_END();
6839 }
6840 
zend_jit_cmp_double_double(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6841 static ir_ref zend_jit_cmp_double_double(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6842 {
6843 	ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
6844 
6845 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6846 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6847 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6848 	}
6849 	if (exit_addr) {
6850 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6851 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6852 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6853 			} else {
6854 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6855 			}
6856 		} else {
6857 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6858 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6859 			} else {
6860 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6861 			}
6862 		}
6863 	} else if (smart_branch_opcode) {
6864 		return jit_IF_ex(jit, ref,
6865 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6866 	}
6867 	if (opline->opcode != ZEND_IS_IDENTICAL
6868 	 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6869 	 && opline->opcode != ZEND_CASE_STRICT) {
6870 		return ir_END();
6871 	} else {
6872 		return IR_NULL; /* success */
6873 	}
6874 }
6875 
zend_jit_cmp_slow(zend_jit_ctx * jit,ir_ref ref,const zend_op * opline,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6876 static ir_ref zend_jit_cmp_slow(zend_jit_ctx *jit, ir_ref ref, const zend_op *opline, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6877 {
6878 	ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
6879 
6880 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6881 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6882 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6883 	}
6884 	if (exit_addr) {
6885 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6886 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6887 		} else {
6888 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6889 		}
6890 	} else if (smart_branch_opcode) {
6891 		return jit_IF_ex(jit, ref,
6892 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6893 	}
6894 
6895 	return ir_END();
6896 }
6897 
zend_jit_cmp(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_ssa_range * op1_range,zend_jit_addr op1_addr,uint32_t op2_info,zend_ssa_range * op2_range,zend_jit_addr op2_addr,zend_jit_addr res_addr,int may_throw,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr,bool skip_comparison)6898 static int zend_jit_cmp(zend_jit_ctx   *jit,
6899                         const zend_op  *opline,
6900                         uint32_t        op1_info,
6901                         zend_ssa_range *op1_range,
6902                         zend_jit_addr   op1_addr,
6903                         uint32_t        op2_info,
6904                         zend_ssa_range *op2_range,
6905                         zend_jit_addr   op2_addr,
6906                         zend_jit_addr   res_addr,
6907                         int             may_throw,
6908                         uint8_t         smart_branch_opcode,
6909                         uint32_t        target_label,
6910                         uint32_t        target_label2,
6911                         const void     *exit_addr,
6912                         bool       skip_comparison)
6913 {
6914 	ir_ref ref = IR_UNUSED;
6915 	ir_ref if_op1_long = IR_UNUSED;
6916 	ir_ref if_op1_double = IR_UNUSED;
6917 	ir_ref if_op2_double = IR_UNUSED;
6918 	ir_ref if_op1_long_op2_long = IR_UNUSED;
6919 	ir_ref if_op1_long_op2_double = IR_UNUSED;
6920 	ir_ref if_op1_double_op2_double = IR_UNUSED;
6921 	ir_ref if_op1_double_op2_long = IR_UNUSED;
6922 	ir_ref slow_inputs = IR_UNUSED;
6923 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
6924 	bool has_slow =
6925 		(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6926 		(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6927 		((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
6928 		 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
6929 	ir_refs *end_inputs;
6930 
6931 	ir_refs_init(end_inputs, 8);
6932 
6933 	if (Z_MODE(op1_addr) == IS_REG) {
6934 		if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
6935 			/* Force load */
6936 			zend_jit_use_reg(jit, op1_addr);
6937 		}
6938 	} else if (Z_MODE(op2_addr) == IS_REG) {
6939 		if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
6940 			/* Force load */
6941 			zend_jit_use_reg(jit, op2_addr);
6942 		}
6943 	}
6944 
6945 	if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
6946 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
6947 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
6948 			ir_IF_TRUE(if_op1_long);
6949 		}
6950 		if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
6951 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
6952 			ir_IF_FALSE_cold(if_op1_long_op2_long);
6953 			if (op2_info & MAY_BE_DOUBLE) {
6954 				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6955 					if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6956 					ir_IF_FALSE_cold(if_op1_long_op2_double);
6957 					ir_END_list(slow_inputs);
6958 					ir_IF_TRUE(if_op1_long_op2_double);
6959 				}
6960 				ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6961 				if (!ref) {
6962 					return 0;
6963 				}
6964 				ir_refs_add(end_inputs, ref);
6965 			} else {
6966 				ir_END_list(slow_inputs);
6967 			}
6968 			ir_IF_TRUE(if_op1_long_op2_long);
6969 		}
6970 		ref = zend_jit_cmp_long_long(jit, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison);
6971 		if (!ref) {
6972 			return 0;
6973 		}
6974 		ir_refs_add(end_inputs, ref);
6975 
6976 		if (if_op1_long) {
6977 			ir_IF_FALSE_cold(if_op1_long);
6978 		}
6979 		if (op1_info & MAY_BE_DOUBLE) {
6980 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6981 				if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
6982 				ir_IF_FALSE_cold(if_op1_double);
6983 				ir_END_list(slow_inputs);
6984 				ir_IF_TRUE(if_op1_double);
6985 			}
6986 			if (op2_info & MAY_BE_DOUBLE) {
6987 				if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
6988 					if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6989 					ir_IF_TRUE(if_op1_double_op2_double);
6990 				}
6991 				ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6992 				if (!ref) {
6993 					return 0;
6994 				}
6995 				ir_refs_add(end_inputs, ref);
6996 				if (if_op1_double_op2_double) {
6997 					ir_IF_FALSE_cold(if_op1_double_op2_double);
6998 				}
6999 			}
7000 			if (!same_ops) {
7001 				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7002 					if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7003 					ir_IF_FALSE_cold(if_op1_double_op2_long);
7004 					ir_END_list(slow_inputs);
7005 					ir_IF_TRUE(if_op1_double_op2_long);
7006 				}
7007 				ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7008 				if (!ref) {
7009 					return 0;
7010 				}
7011 				ir_refs_add(end_inputs, ref);
7012 			} else if (if_op1_double_op2_double) {
7013 				ir_END_list(slow_inputs);
7014 			}
7015 		} else if (if_op1_long) {
7016 			ir_END_list(slow_inputs);
7017 		}
7018 	} else if ((op1_info & MAY_BE_DOUBLE) &&
7019 	           !(op1_info & MAY_BE_LONG) &&
7020 	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7021 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7022 			if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7023 			ir_IF_FALSE_cold(if_op1_double);
7024 			ir_END_list(slow_inputs);
7025 			ir_IF_TRUE(if_op1_double);
7026 		}
7027 		if (op2_info & MAY_BE_DOUBLE) {
7028 			if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7029 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7030 				ir_IF_TRUE(if_op1_double_op2_double);
7031 			}
7032 			ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7033 			if (!ref) {
7034 				return 0;
7035 			}
7036 			ir_refs_add(end_inputs, ref);
7037 			if (if_op1_double_op2_double) {
7038 				ir_IF_FALSE_cold(if_op1_double_op2_double);
7039 			}
7040 		}
7041 		if (!same_ops && (op2_info & MAY_BE_LONG)) {
7042 			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7043 				if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7044 				ir_IF_FALSE_cold(if_op1_double_op2_long);
7045 				ir_END_list(slow_inputs);
7046 				ir_IF_TRUE(if_op1_double_op2_long);
7047 			}
7048 			ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7049 			if (!ref) {
7050 				return 0;
7051 			}
7052 			ir_refs_add(end_inputs, ref);
7053 		} else if (if_op1_double_op2_double) {
7054 			ir_END_list(slow_inputs);
7055 		}
7056 	} else if ((op2_info & MAY_BE_DOUBLE) &&
7057 	           !(op2_info & MAY_BE_LONG) &&
7058 	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7059 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7060 			if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7061 			ir_IF_FALSE_cold(if_op2_double);
7062 			ir_END_list(slow_inputs);
7063 			ir_IF_TRUE(if_op2_double);
7064 		}
7065 		if (op1_info & MAY_BE_DOUBLE) {
7066 			if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7067 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7068 				ir_IF_TRUE(if_op1_double_op2_double);
7069 			}
7070 			ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7071 			if (!ref) {
7072 				return 0;
7073 			}
7074 			ir_refs_add(end_inputs, ref);
7075 			if (if_op1_double_op2_double) {
7076 				ir_IF_FALSE_cold(if_op1_double_op2_double);
7077 			}
7078 		}
7079 		if (!same_ops && (op1_info & MAY_BE_LONG)) {
7080 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7081 				if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7082 				ir_IF_FALSE_cold(if_op1_long_op2_double);
7083 				ir_END_list(slow_inputs);
7084 				ir_IF_TRUE(if_op1_long_op2_double);
7085 			}
7086 			ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7087 			if (!ref) {
7088 				return 0;
7089 			}
7090 			ir_refs_add(end_inputs, ref);
7091 		} else if (if_op1_double_op2_double) {
7092 			ir_END_list(slow_inputs);
7093 		}
7094 	}
7095 
7096 	if (has_slow ||
7097 	    (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7098 	    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7099 	    ir_ref op1, op2, ref;
7100 
7101 		if (slow_inputs) {
7102 			ir_MERGE_list(slow_inputs);
7103 		}
7104 		jit_SET_EX_OPLINE(jit, opline);
7105 
7106 		if (Z_MODE(op1_addr) == IS_REG) {
7107 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7108 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7109 				return 0;
7110 			}
7111 			op1_addr = real_addr;
7112 		}
7113 		if (Z_MODE(op2_addr) == IS_REG) {
7114 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7115 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7116 				return 0;
7117 			}
7118 			op2_addr = real_addr;
7119 		}
7120 
7121 		op1 = jit_ZVAL_ADDR(jit, op1_addr);
7122 		if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7123 			op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, 0);
7124 		}
7125 		op2 = jit_ZVAL_ADDR(jit, op2_addr);
7126 		if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7127 			op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, 0);
7128 		}
7129 		ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7130 		if (opline->opcode != ZEND_CASE) {
7131 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7132 		}
7133 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7134 		if (may_throw) {
7135 			zend_jit_check_exception_undef_result(jit, opline);
7136 		}
7137 
7138 		ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7139 		if (!ref) {
7140 			return 0;
7141 		}
7142 		ir_refs_add(end_inputs, ref);
7143 	}
7144 
7145 	if (end_inputs->count) {
7146 		uint32_t n = end_inputs->count;
7147 
7148 		if (smart_branch_opcode && !exit_addr) {
7149 			zend_basic_block *bb;
7150 			ir_ref ref;
7151 			uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7152 				target_label2 : target_label;
7153 			uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7154 				target_label : target_label2;
7155 
7156 			ZEND_ASSERT(jit->b >= 0);
7157 			bb = &jit->ssa->cfg.blocks[jit->b];
7158 			ZEND_ASSERT(bb->successors_count == 2);
7159 
7160 			if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7161 				ir_ref merge_inputs = IR_UNUSED;
7162 
7163 				while (n) {
7164 					n--;
7165 					ir_IF_TRUE(end_inputs->refs[n]);
7166 					ir_END_list(merge_inputs);
7167 					ir_IF_FALSE(end_inputs->refs[n]);
7168 					ir_END_list(merge_inputs);
7169 				}
7170 				ir_MERGE_list(merge_inputs);
7171 				_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7172 			} else if (n == 1) {
7173 				ref = end_inputs->refs[0];
7174 				_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7175 				_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7176 			} else {
7177 				ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7178 
7179 				while (n) {
7180 					n--;
7181 					ir_IF_TRUE(end_inputs->refs[n]);
7182 					ir_END_list(true_inputs);
7183 					ir_IF_FALSE(end_inputs->refs[n]);
7184 					ir_END_list(false_inputs);
7185 				}
7186 				ir_MERGE_list(true_inputs);
7187 				_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7188 				ir_MERGE_list(false_inputs);
7189 				_zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7190 			}
7191 			jit->b = -1;
7192 		} else {
7193 			ir_MERGE_N(n, end_inputs->refs);
7194 		}
7195 	} else if (smart_branch_opcode && !exit_addr) {
7196 		/* dead code */
7197 		_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7198 		jit->b = -1;
7199 	}
7200 
7201 	return 1;
7202 }
7203 
zend_jit_identical(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_ssa_range * op1_range,zend_jit_addr op1_addr,uint32_t op2_info,zend_ssa_range * op2_range,zend_jit_addr op2_addr,zend_jit_addr res_addr,int may_throw,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr,bool skip_comparison)7204 static int zend_jit_identical(zend_jit_ctx   *jit,
7205                               const zend_op  *opline,
7206                               uint32_t        op1_info,
7207                               zend_ssa_range *op1_range,
7208                               zend_jit_addr   op1_addr,
7209                               uint32_t        op2_info,
7210                               zend_ssa_range *op2_range,
7211                               zend_jit_addr   op2_addr,
7212                               zend_jit_addr   res_addr,
7213                               int             may_throw,
7214                               uint8_t         smart_branch_opcode,
7215                               uint32_t        target_label,
7216                               uint32_t        target_label2,
7217                               const void     *exit_addr,
7218                               bool       skip_comparison)
7219 {
7220 	bool always_false = 0, always_true = 0;
7221 	ir_ref ref = IR_UNUSED;
7222 
7223 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7224 		ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7225 		op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, 0);
7226 		op1_info |= MAY_BE_NULL;
7227 		op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7228 	}
7229 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7230 		ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7231 		op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, 0);
7232 		op2_info |= MAY_BE_NULL;
7233 		op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7234 	}
7235 
7236 	if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7237 		always_false = 1;
7238 	} else if (has_concrete_type(op1_info)
7239 	 && has_concrete_type(op2_info)
7240 	 && concrete_type(op1_info) == concrete_type(op2_info)
7241 	 && concrete_type(op1_info) <= IS_TRUE) {
7242 		always_true = 1;
7243 	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7244 		if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7245 			always_true = 1;
7246 		} else {
7247 			always_false = 1;
7248 		}
7249 	}
7250 
7251 	if (always_true) {
7252 		if (opline->opcode != ZEND_CASE_STRICT) {
7253 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7254 		}
7255 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7256 		if (!smart_branch_opcode
7257 		 || smart_branch_opcode == ZEND_JMPZ_EX
7258 		 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7259 			jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7260 		}
7261 		if (may_throw) {
7262 			zend_jit_check_exception(jit);
7263 		}
7264 		if (exit_addr) {
7265 			if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7266 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7267 			}
7268 		} else if (smart_branch_opcode) {
7269 			uint32_t label;
7270 
7271 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7272 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7273 					target_label : target_label2;
7274 			} else {
7275 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7276 					target_label2 : target_label;
7277 			}
7278 			_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7279 			jit->b = -1;
7280 		}
7281 		return 1;
7282 	} else if (always_false) {
7283 		if (opline->opcode != ZEND_CASE_STRICT) {
7284 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7285 		}
7286 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7287 		if (!smart_branch_opcode
7288 		 || smart_branch_opcode == ZEND_JMPZ_EX
7289 		 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7290 			jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7291 		}
7292 		if (may_throw) {
7293 			zend_jit_check_exception(jit);
7294 		}
7295 		if (exit_addr) {
7296 			if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7297 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7298 			}
7299 		} else if (smart_branch_opcode) {
7300 			uint32_t label;
7301 
7302 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7303 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7304 					target_label2 : target_label;
7305 			} else {
7306 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7307 					target_label : target_label2;
7308 			}
7309 			_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7310 			jit->b = -1;
7311 		}
7312 		return 1;
7313 	}
7314 
7315 	if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7316 		ref = jit_ZVAL_ADDR(jit, op1_addr);
7317 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7318 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7319 	}
7320 	if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7321 		ref = jit_ZVAL_ADDR(jit, op2_addr);
7322 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7323 		op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7324 	}
7325 
7326 	if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7327 	    (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7328 		ref = zend_jit_cmp_long_long(jit, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison);
7329 		if (!ref) {
7330 			return 0;
7331 		}
7332 	} else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7333 	           (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7334 		ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7335 		if (!ref) {
7336 			return 0;
7337 		}
7338 	} else {
7339 		if (opline->op1_type != IS_CONST) {
7340 			if (Z_MODE(op1_addr) == IS_REG) {
7341 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7342 				if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7343 					return 0;
7344 				}
7345 				op1_addr = real_addr;
7346 			}
7347 		}
7348 		if (opline->op2_type != IS_CONST) {
7349 			if (Z_MODE(op2_addr) == IS_REG) {
7350 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7351 				if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7352 					return 0;
7353 				}
7354 			}
7355 		}
7356 
7357 		if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7358 			zval *val = Z_ZV(op1_addr);
7359 
7360 			ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7361 		} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7362 			zval *val = Z_ZV(op2_addr);
7363 
7364 			ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7365 		} else {
7366 			if (Z_MODE(op1_addr) == IS_REG) {
7367 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7368 				if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7369 					return 0;
7370 				}
7371 				op1_addr = real_addr;
7372 			}
7373 			if (Z_MODE(op2_addr) == IS_REG) {
7374 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7375 				if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7376 					return 0;
7377 				}
7378 				op2_addr = real_addr;
7379 			}
7380 			if (may_throw) {
7381 				jit_SET_EX_OPLINE(jit, opline);
7382 			}
7383 
7384 			ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_is_identical),
7385 				jit_ZVAL_ADDR(jit, op1_addr),
7386 				jit_ZVAL_ADDR(jit, op2_addr));
7387 		}
7388 
7389 		if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7390 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7391 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7392 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7393 			} else {
7394 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7395 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7396 			}
7397 		}
7398 		if (opline->opcode != ZEND_CASE_STRICT) {
7399 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7400 		}
7401 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7402 		if (may_throw) {
7403 			zend_jit_check_exception_undef_result(jit, opline);
7404 		}
7405 		if (exit_addr) {
7406 			if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7407 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7408 			} else {
7409 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7410 			}
7411 		} else if (smart_branch_opcode) {
7412 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7413 				/* swap labels */
7414 				uint32_t tmp = target_label;
7415 				target_label = target_label2;
7416 				target_label2 = tmp;
7417 			}
7418 			ref = jit_IF_ex(jit, ref,
7419 				(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7420 		}
7421 	}
7422 
7423 	if (smart_branch_opcode && !exit_addr) {
7424 		zend_basic_block *bb;
7425 
7426 		ZEND_ASSERT(jit->b >= 0);
7427 		bb = &jit->ssa->cfg.blocks[jit->b];
7428 		ZEND_ASSERT(bb->successors_count == 2);
7429 
7430 		if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7431 			ir_IF_TRUE(ref);
7432 			ir_MERGE_WITH_EMPTY_FALSE(ref);
7433 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7434 		} else {
7435 			ZEND_ASSERT(bb->successors_count == 2);
7436 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7437 			_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7438 		}
7439 		jit->b = -1;
7440 	}
7441 
7442 	return 1;
7443 }
7444 
zend_jit_bool_jmpznz(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,zend_jit_addr res_addr,uint32_t target_label,uint32_t target_label2,int may_throw,uint8_t branch_opcode,const void * exit_addr)7445 static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr)
7446 {
7447 	uint32_t true_label = -1;
7448 	uint32_t false_label = -1;
7449 	bool set_bool = 0;
7450 	bool set_bool_not = 0;
7451 	bool always_true = 0, always_false = 0;
7452 	ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7453 	ir_type type = IR_UNUSED;
7454 
7455 	if (branch_opcode == ZEND_BOOL) {
7456 		set_bool = 1;
7457 	} else if (branch_opcode == ZEND_BOOL_NOT) {
7458 		set_bool = 1;
7459 		set_bool_not = 1;
7460 	} else if (branch_opcode == ZEND_JMPZ) {
7461 		true_label = target_label2;
7462 		false_label = target_label;
7463 	} else if (branch_opcode == ZEND_JMPNZ) {
7464 		true_label = target_label;
7465 		false_label = target_label2;
7466 	} else if (branch_opcode == ZEND_JMPZ_EX) {
7467 		set_bool = 1;
7468 		true_label = target_label2;
7469 		false_label = target_label;
7470 	} else if (branch_opcode == ZEND_JMPNZ_EX) {
7471 		set_bool = 1;
7472 		true_label = target_label;
7473 		false_label = target_label2;
7474 	} else {
7475 		ZEND_UNREACHABLE();
7476 	}
7477 
7478 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7479 		ref = jit_ZVAL_ADDR(jit, op1_addr);
7480 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7481 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7482 	}
7483 
7484 	if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
7485 		if (zend_is_true(Z_ZV(op1_addr))) {
7486 			always_true = 1;
7487 		} else {
7488 			always_false = 1;
7489 		}
7490 	} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7491 		if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7492 			always_true = 1;
7493 		} else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7494 			if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7495 				ref = jit_ZVAL_ADDR(jit, op1_addr);
7496 				zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, 0);
7497 			}
7498 			always_false = 1;
7499 		}
7500 	}
7501 
7502 	if (always_true) {
7503 		if (set_bool) {
7504 			jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7505 		}
7506 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7507 		if (may_throw) {
7508 			zend_jit_check_exception(jit);
7509 		}
7510 		if (true_label != (uint32_t)-1) {
7511 			ZEND_ASSERT(exit_addr == NULL);
7512 			_zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7513 			jit->b = -1;
7514 		}
7515 		return 1;
7516 	} else if (always_false) {
7517 		if (set_bool) {
7518 			jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7519 		}
7520 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7521 		if (may_throw) {
7522 			zend_jit_check_exception(jit);
7523 		}
7524 		if (false_label != (uint32_t)-1) {
7525 			ZEND_ASSERT(exit_addr == NULL);
7526 			_zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7527 			jit->b = -1;
7528 		}
7529 		return 1;
7530 	}
7531 
7532 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7533 		type = jit_Z_TYPE(jit, op1_addr);
7534 		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7535 			ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7536 
7537 			ir_IF_TRUE_cold(if_type);
7538 
7539 			if (op1_info & MAY_BE_UNDEF) {
7540 				zend_jit_type_check_undef(jit,
7541 					type,
7542 					opline->op1.var,
7543 					opline, 1, 0, 1);
7544 			}
7545 			if (set_bool) {
7546 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7547 			}
7548 			if (exit_addr) {
7549 				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
7550 					ir_END_list(end_inputs);
7551 				} else {
7552 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7553 				}
7554 			} else if (false_label != (uint32_t)-1) {
7555 				ir_END_list(false_inputs);
7556 			} else {
7557 				ir_END_list(end_inputs);
7558 			}
7559 			ir_IF_FALSE(if_type);
7560 		}
7561 
7562 		if (op1_info & MAY_BE_TRUE) {
7563 			ir_ref if_type = IR_UNUSED;
7564 
7565 			if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7566 				if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7567 
7568 				ir_IF_TRUE(if_type);
7569 			}
7570 			if (set_bool) {
7571 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7572 			}
7573 			if (exit_addr) {
7574 				if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7575 					ir_END_list(end_inputs);
7576 				} else {
7577 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7578 				}
7579 			} else if (true_label != (uint32_t)-1) {
7580 				ir_END_list(true_inputs);
7581 			} else {
7582 				ir_END_list(end_inputs);
7583 			}
7584 			if (if_type) {
7585 				ir_IF_FALSE(if_type);
7586 			}
7587 		}
7588 	}
7589 
7590 	if (op1_info & MAY_BE_LONG) {
7591 		ir_ref if_long = IR_UNUSED;
7592 		ir_ref ref;
7593 
7594 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
7595 			if (!type) {
7596 				type = jit_Z_TYPE(jit, op1_addr);
7597 			}
7598 			if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7599 			ir_IF_TRUE(if_long);
7600 		}
7601 		ref = jit_Z_LVAL(jit, op1_addr);
7602 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7603 			ref = ir_NE(ref, ir_CONST_LONG(0));
7604 			if (set_bool_not) {
7605 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7606 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7607 			} else {
7608 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7609 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7610 			}
7611 			ir_END_list(end_inputs);
7612 		} else if (exit_addr) {
7613 			if (set_bool) {
7614 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7615 					ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, ir_CONST_LONG(0))), ir_CONST_U32(IS_FALSE)));
7616 			}
7617 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7618 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7619 			} else {
7620 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7621 			}
7622 			ir_END_list(end_inputs);
7623 		} else {
7624 			ir_ref if_val = ir_IF(ref);
7625 			ir_IF_TRUE(if_val);
7626 			if (set_bool) {
7627 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7628 			}
7629 			ir_END_list(true_inputs);
7630 			ir_IF_FALSE(if_val);
7631 			if (set_bool) {
7632 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7633 			}
7634 			ir_END_list(false_inputs);
7635 		}
7636 		if (if_long) {
7637 			ir_IF_FALSE(if_long);
7638 		}
7639 	}
7640 
7641 	if (op1_info & MAY_BE_DOUBLE) {
7642 		ir_ref if_double = IR_UNUSED;
7643 		ir_ref ref;
7644 
7645 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7646 			if (!type) {
7647 				type = jit_Z_TYPE(jit, op1_addr);
7648 			}
7649 			if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7650 			ir_IF_TRUE(if_double);
7651 		}
7652 		ref = ir_NE(jit_Z_DVAL(jit, op1_addr), ir_CONST_DOUBLE(0.0));
7653 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7654 			if (set_bool_not) {
7655 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7656 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7657 			} else {
7658 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7659 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7660 			}
7661 			ir_END_list(end_inputs);
7662 		} else if (exit_addr) {
7663 		    if (set_bool) {
7664 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7665 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7666 		    }
7667 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7668 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7669 			} else {
7670 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7671 			}
7672 			ir_END_list(end_inputs);
7673 		} else {
7674 			ir_ref if_val = ir_IF(ref);
7675 			ir_IF_TRUE(if_val);
7676 			if (set_bool) {
7677 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7678 			}
7679 			ir_END_list(true_inputs);
7680 			ir_IF_FALSE(if_val);
7681 			if (set_bool) {
7682 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7683 			}
7684 			ir_END_list(false_inputs);
7685 		}
7686 		if (if_double) {
7687 			ir_IF_FALSE(if_double);
7688 		}
7689 	}
7690 
7691 	if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7692 		jit_SET_EX_OPLINE(jit, opline);
7693 		ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7694 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7695 		if (may_throw) {
7696 			zend_jit_check_exception_undef_result(jit, opline);
7697 		}
7698 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7699 			if (set_bool_not) {
7700 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7701 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7702 			} else {
7703 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7704 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7705 			}
7706 			if (end_inputs) {
7707 				ir_END_list(end_inputs);
7708 			}
7709 		} else if (exit_addr) {
7710 			if (set_bool) {
7711 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7712 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7713 			}
7714 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7715 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7716 			} else {
7717 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7718 			}
7719 			if (end_inputs) {
7720 				ir_END_list(end_inputs);
7721 			}
7722 		} else {
7723 			ir_ref if_val = ir_IF(ref);
7724 			ir_IF_TRUE(if_val);
7725 			if (set_bool) {
7726 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7727 			}
7728 			ir_END_list(true_inputs);
7729 			ir_IF_FALSE(if_val);
7730 			if (set_bool) {
7731 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7732 			}
7733 			ir_END_list(false_inputs);
7734 		}
7735 	}
7736 
7737 	if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7738 		if (end_inputs) {
7739 			ir_MERGE_list(end_inputs);
7740 		}
7741 	} else {
7742 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7743 	}
7744 
7745 	return 1;
7746 }
7747 
zend_jit_defined(zend_jit_ctx * jit,const zend_op * opline,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)7748 static int zend_jit_defined(zend_jit_ctx *jit, const zend_op *opline, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7749 {
7750 	uint32_t defined_label = (uint32_t)-1;
7751 	uint32_t undefined_label = (uint32_t)-1;
7752 	zval *zv = RT_CONSTANT(opline, opline->op1);
7753 	zend_jit_addr res_addr = 0;
7754 	ir_ref ref, ref2, if_set, if_zero, if_set2;
7755 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7756 
7757 	if (smart_branch_opcode && !exit_addr) {
7758 		if (smart_branch_opcode == ZEND_JMPZ) {
7759 			defined_label = target_label2;
7760 			undefined_label = target_label;
7761 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
7762 			defined_label = target_label;
7763 			undefined_label = target_label2;
7764 		} else {
7765 			ZEND_UNREACHABLE();
7766 		}
7767 	} else {
7768 		res_addr = RES_ADDR();
7769 	}
7770 
7771 	// if (CACHED_PTR(opline->extended_value)) {
7772 	ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7773 
7774 	if_set = ir_IF(ref);
7775 
7776 	ir_IF_FALSE_cold(if_set);
7777 	if_zero = ir_END();
7778 
7779 	ir_IF_TRUE(if_set);
7780 	if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7781 	ir_IF_FALSE(if_set2);
7782 
7783 	if (exit_addr) {
7784 		if (smart_branch_opcode == ZEND_JMPNZ) {
7785 			jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7786 		} else {
7787 			ir_END_list(end_inputs);
7788 		}
7789 	} else if (smart_branch_opcode) {
7790 		ir_END_list(true_inputs);
7791 	} else {
7792 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7793 		ir_END_list(end_inputs);
7794 	}
7795 
7796 	ir_IF_TRUE_cold(if_set2);
7797 
7798 	ref2 = jit_EG(zend_constants);
7799 	ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7800 	if (sizeof(void*) == 8) {
7801 		ref = ir_TRUNC_U32(ref);
7802 	}
7803 	ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7804 	ref2 = ir_IF(ref2);
7805 	ir_IF_TRUE(ref2);
7806 
7807 	if (exit_addr) {
7808 		if (smart_branch_opcode == ZEND_JMPZ) {
7809 			jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7810 		} else {
7811 			ir_END_list(end_inputs);
7812 		}
7813 	} else if (smart_branch_opcode) {
7814 		ir_END_list(false_inputs);
7815 	} else {
7816 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7817 		ir_END_list(end_inputs);
7818 	}
7819 
7820 	ir_IF_FALSE(ref2);
7821 	ir_MERGE_2(if_zero, ir_END());
7822 
7823 	jit_SET_EX_OPLINE(jit, opline);
7824 	ref2 = ir_NE(ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_check_constant), ir_CONST_ADDR(zv)), IR_NULL);
7825 	if (exit_addr) {
7826 		if (smart_branch_opcode == ZEND_JMPZ) {
7827 			ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
7828 		} else {
7829 			ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
7830 		}
7831 		ir_END_list(end_inputs);
7832 	} else if (smart_branch_opcode) {
7833 		ref2 = ir_IF(ref2);
7834 		ir_IF_TRUE(ref2);
7835 		ir_END_list(true_inputs);
7836 		ir_IF_FALSE(ref2);
7837 		ir_END_list(false_inputs);
7838 	} else {
7839 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7840 			ir_ADD_U32(ir_ZEXT_U32(ref2), ir_CONST_U32(IS_FALSE)));
7841 		ir_END_list(end_inputs);
7842 	}
7843 
7844 	if (!smart_branch_opcode || exit_addr) {
7845 		if (end_inputs) {
7846 			ir_MERGE_list(end_inputs);
7847 		}
7848 	} else {
7849 		_zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
7850 	}
7851 
7852 	return 1;
7853 }
7854 
zend_jit_escape_if_undef(zend_jit_ctx * jit,int var,uint32_t flags,const zend_op * opline,int8_t reg)7855 static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
7856 {
7857 	zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7858 	ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
7859 
7860 	ir_IF_FALSE_cold(if_def);
7861 
7862 	if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7863 		if (!zend_jit_save_call_chain(jit, -1)) {
7864 			return 0;
7865 		}
7866 	}
7867 
7868 	if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
7869 	 && (opline-1)->opcode != ZEND_FETCH_LIST_R
7870 	 && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
7871 	 && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
7872 		zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
7873 
7874 		zend_jit_zval_try_addref(jit, val_addr);
7875 	}
7876 
7877 	jit_LOAD_IP_ADDR(jit, opline - 1);
7878 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
7879 
7880 	ir_IF_TRUE(if_def);
7881 
7882 	return 1;
7883 }
7884 
zend_jit_restore_zval(zend_jit_ctx * jit,int var,int8_t reg)7885 static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
7886 {
7887 	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
7888 	zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7889 
7890 	// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
7891 	jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, 1);
7892 	return 1;
7893 }
7894 
zend_jit_guard_fetch_result_type(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr val_addr,uint8_t type,bool deref,uint32_t flags,bool op1_avoid_refcounting)7895 static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx         *jit,
7896                                                       const zend_op        *opline,
7897                                                       zend_jit_addr         val_addr,
7898                                                       uint8_t               type,
7899                                                       bool                  deref,
7900                                                       uint32_t              flags,
7901                                                       bool                  op1_avoid_refcounting)
7902 {
7903 	zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
7904 	int32_t exit_point;
7905 	const void *res_exit_addr = NULL;
7906 	ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
7907 	ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
7908 	uint32_t old_op1_info = 0;
7909 	uint32_t old_info;
7910 	ir_ref old_ref;
7911 
7912 
7913 	if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7914 		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
7915 		if (op1_avoid_refcounting
7916 		 || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
7917 		  && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
7918 			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
7919 		}
7920 	}
7921 	old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
7922 	old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7923 	CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7924 	SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
7925 
7926 	if (deref) {
7927 		ir_ref if_type;
7928 
7929 		if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7930 			if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
7931 		} else {
7932 			if_type = jit_if_Z_TYPE(jit, val_addr, type);
7933 		}
7934 		ir_IF_TRUE(if_type);
7935 		end1 = ir_END();
7936 		ref1 = ref;
7937 		ir_IF_FALSE_cold(if_type);
7938 
7939 		SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7940 		exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7941 		res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7942 		if (!res_exit_addr) {
7943 			return 0;
7944 		}
7945 
7946 		jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
7947 		ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
7948 		val_addr = ZEND_ADDR_REF_ZVAL(ref);
7949 	}
7950 
7951 	SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7952 	exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7953 	res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7954 	if (!res_exit_addr) {
7955 		return 0;
7956 	}
7957 
7958 	if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7959 		ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
7960 	} else {
7961 		jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
7962 	}
7963 
7964 	if (deref) {
7965 		ir_MERGE_WITH(end1);
7966 		ref = ir_PHI_2(IR_ADDR, ref, ref1);
7967 	}
7968 
7969 	val_addr = ZEND_ADDR_REF_ZVAL(ref);
7970 
7971 	SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
7972 	SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
7973 	if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7974 		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
7975 	}
7976 
7977 	return val_addr;
7978 }
7979 
zend_jit_fetch_constant(zend_jit_ctx * jit,const zend_op * opline,const zend_op_array * op_array,zend_ssa * ssa,const zend_ssa_op * ssa_op,zend_jit_addr res_addr)7980 static int zend_jit_fetch_constant(zend_jit_ctx         *jit,
7981                                    const zend_op        *opline,
7982                                    const zend_op_array  *op_array,
7983                                    zend_ssa             *ssa,
7984                                    const zend_ssa_op    *ssa_op,
7985                                    zend_jit_addr         res_addr)
7986 {
7987 	zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
7988 	uint32_t res_info = RES_INFO();
7989 	ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
7990 
7991 	// JIT: c = CACHED_PTR(opline->extended_value);
7992 	ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7993 
7994 	// JIT: if (c != NULL)
7995 	if_set = ir_IF(ref);
7996 
7997 	if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
7998 		// JIT: if (!IS_SPECIAL_CACHE_VAL(c))
7999 		ir_IF_FALSE_cold(if_set);
8000 		not_set_path = ir_END();
8001 		ir_IF_TRUE(if_set);
8002 		if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
8003 		ir_IF_TRUE_cold(if_special);
8004 		special_path = ir_END();
8005 		ir_IF_FALSE(if_special);
8006 		fast_path = ir_END();
8007 		ir_MERGE_2(not_set_path, special_path);
8008 	} else {
8009 		ir_IF_TRUE(if_set);
8010 		fast_path = ir_END();
8011 		ir_IF_FALSE_cold(if_set);
8012 	}
8013 
8014 	// JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
8015 	jit_SET_EX_OPLINE(jit, opline);
8016 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_constant),
8017 		ir_CONST_ADDR(zv),
8018 		ir_CONST_U32(opline->op1.num));
8019 	ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8020 
8021 	ir_MERGE_WITH(fast_path);
8022 	ref = ir_PHI_2(IR_ADDR, ref2, ref);
8023 
8024 	if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
8025 		uint8_t type = concrete_type(res_info);
8026 		zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
8027 
8028 		const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, 0, 0, 0);
8029 		if (!const_addr) {
8030 			return 0;
8031 		}
8032 
8033 		res_info &= ~MAY_BE_GUARD;
8034 		ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
8035 
8036 		// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8037 		jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, 1);
8038 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
8039 			return 0;
8040 		}
8041 	} else {
8042 		ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
8043 
8044 		// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8045 		jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, 1);
8046 	}
8047 
8048 
8049 	return 1;
8050 }
8051 
zend_jit_type_check(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)8052 static int zend_jit_type_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
8053 {
8054 	uint32_t  mask;
8055 	zend_jit_addr op1_addr = OP1_ADDR();
8056 	zend_jit_addr res_addr = 0;
8057 	uint32_t true_label = -1, false_label = -1;
8058 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8059 
8060 	// TODO: support for is_resource() ???
8061 	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8062 
8063 	if (smart_branch_opcode && !exit_addr) {
8064 		if (smart_branch_opcode == ZEND_JMPZ) {
8065 			true_label = target_label2;
8066 			false_label = target_label;
8067 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
8068 			true_label = target_label;
8069 			false_label = target_label2;
8070 		} else {
8071 			ZEND_UNREACHABLE();
8072 		}
8073 	} else {
8074 		res_addr = RES_ADDR();
8075 	}
8076 
8077 	if (op1_info & MAY_BE_UNDEF) {
8078 		ir_ref if_def = IR_UNUSED;
8079 
8080 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8081 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8082 			ir_IF_FALSE_cold(if_def);
8083 		}
8084 
8085 		jit_SET_EX_OPLINE(jit, opline);
8086 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8087 		zend_jit_check_exception_undef_result(jit, opline);
8088 		if (opline->extended_value & MAY_BE_NULL) {
8089 			if (exit_addr) {
8090 				if (smart_branch_opcode == ZEND_JMPNZ) {
8091 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8092 				} else {
8093 					ir_END_list(end_inputs);
8094 				}
8095 			} else if (smart_branch_opcode) {
8096 				ir_END_list(true_inputs);
8097 			} else {
8098 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8099 				ir_END_list(end_inputs);
8100 			}
8101 		} else {
8102 			if (exit_addr) {
8103 				if (smart_branch_opcode == ZEND_JMPZ) {
8104 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8105 				} else {
8106 					ir_END_list(end_inputs);
8107 				}
8108 			} else if (smart_branch_opcode) {
8109 				ir_END_list(false_inputs);
8110 			} else {
8111 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8112 				if (if_def) {
8113 					ir_END_list(end_inputs);
8114 				}
8115 			}
8116 		}
8117 
8118 		if (if_def) {
8119 			ir_IF_TRUE(if_def);
8120 			op1_info |= MAY_BE_NULL;
8121 		}
8122 	}
8123 
8124 	if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8125 		mask = opline->extended_value;
8126 		if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8127 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8128 			if (exit_addr) {
8129 				if (smart_branch_opcode == ZEND_JMPNZ) {
8130 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8131 				} else if (end_inputs) {
8132 					ir_END_list(end_inputs);
8133 				}
8134 			} else if (smart_branch_opcode) {
8135 				ir_END_list(true_inputs);
8136 			} else {
8137 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8138 				ir_END_list(end_inputs);
8139 			}
8140 	    } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8141 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8142 			if (exit_addr) {
8143 				if (smart_branch_opcode == ZEND_JMPZ) {
8144 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8145 				} else if (end_inputs) {
8146 					ir_END_list(end_inputs);
8147 				}
8148 			} else if (smart_branch_opcode) {
8149 				ir_END_list(false_inputs);
8150 			} else {
8151 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8152 				ir_END_list(end_inputs);
8153 			}
8154 		} else {
8155 			ir_ref ref;
8156 			bool invert = 0;
8157 			uint8_t type;
8158 
8159 			switch (mask) {
8160 				case MAY_BE_NULL:   type = IS_NULL;   break;
8161 				case MAY_BE_FALSE:  type = IS_FALSE;  break;
8162 				case MAY_BE_TRUE:   type = IS_TRUE;   break;
8163 				case MAY_BE_LONG:   type = IS_LONG;   break;
8164 				case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8165 				case MAY_BE_STRING: type = IS_STRING; break;
8166 				case MAY_BE_ARRAY:  type = IS_ARRAY;  break;
8167 				case MAY_BE_OBJECT: type = IS_OBJECT; break;
8168 				case MAY_BE_ANY - MAY_BE_NULL:     type = IS_NULL;   invert = 1; break;
8169 				case MAY_BE_ANY - MAY_BE_FALSE:    type = IS_FALSE;  invert = 1; break;
8170 				case MAY_BE_ANY - MAY_BE_TRUE:     type = IS_TRUE;   invert = 1; break;
8171 				case MAY_BE_ANY - MAY_BE_LONG:     type = IS_LONG;   invert = 1; break;
8172 				case MAY_BE_ANY - MAY_BE_DOUBLE:   type = IS_DOUBLE; invert = 1; break;
8173 				case MAY_BE_ANY - MAY_BE_STRING:   type = IS_STRING; invert = 1; break;
8174 				case MAY_BE_ANY - MAY_BE_ARRAY:    type = IS_ARRAY;  invert = 1; break;
8175 				case MAY_BE_ANY - MAY_BE_OBJECT:   type = IS_OBJECT; invert = 1; break;
8176 				case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break;
8177 				default:
8178 					type = 0;
8179 			}
8180 
8181 			if (op1_info & MAY_BE_REF) {
8182 				ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8183 				ref = jit_ZVAL_DEREF_ref(jit, ref);
8184 				op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8185 			}
8186 			if (type == 0) {
8187 				ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8188 				if (!smart_branch_opcode) {
8189 					ref = ir_NE(ref, ir_CONST_U32(0));
8190 				}
8191 			} else if (invert) {
8192 				ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8193 			} else {
8194 				ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8195 			}
8196 
8197 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8198 
8199 			if (exit_addr) {
8200 				if (smart_branch_opcode == ZEND_JMPZ) {
8201 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8202 				} else {
8203 					ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8204 				}
8205 				if (end_inputs) {
8206 					ir_END_list(end_inputs);
8207 				}
8208 			} else if (smart_branch_opcode) {
8209 				ir_ref if_val = ir_IF(ref);
8210 				ir_IF_TRUE(if_val);
8211 				ir_END_list(true_inputs);
8212 				ir_IF_FALSE(if_val);
8213 				ir_END_list(false_inputs);
8214 			} else {
8215 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8216 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8217 				ir_END_list(end_inputs);
8218 			}
8219 	    }
8220 	}
8221 
8222 	if (!smart_branch_opcode || exit_addr) {
8223 		if (end_inputs) {
8224 			ir_MERGE_list(end_inputs);
8225 		} else if (exit_addr && !jit->ctx.control) {
8226 			ir_BEGIN(IR_UNUSED); /* unreachable block */
8227 		}
8228 	} else {
8229 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8230 	}
8231 
8232 	return 1;
8233 }
8234 
zend_jit_isset_isempty_cv(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)8235 static int zend_jit_isset_isempty_cv(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
8236 {
8237 	zend_jit_addr res_addr = RES_ADDR();
8238 	uint32_t true_label = -1, false_label = -1;
8239 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8240 
8241 	// TODO: support for empty() ???
8242 	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8243 
8244 	if (smart_branch_opcode && !exit_addr) {
8245 		if (smart_branch_opcode == ZEND_JMPZ) {
8246 			true_label = target_label2;
8247 			false_label = target_label;
8248 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
8249 			true_label = target_label;
8250 			false_label = target_label2;
8251 		} else {
8252 			ZEND_UNREACHABLE();
8253 		}
8254 	} else {
8255 		res_addr = RES_ADDR();
8256 	}
8257 
8258 	if (op1_info & MAY_BE_REF) {
8259 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8260 		ref = jit_ZVAL_DEREF_ref(jit, ref);
8261 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8262 	}
8263 
8264 	if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8265 		if (exit_addr) {
8266 			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8267 		} else if (smart_branch_opcode) {
8268 			ir_END_list(true_inputs);
8269 		} else {
8270 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8271 			ir_END_list(end_inputs);
8272 		}
8273 	} else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8274 		if (exit_addr) {
8275 			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8276 		} else if (smart_branch_opcode) {
8277 			ir_END_list(false_inputs);
8278 		} else {
8279 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8280 			ir_END_list(end_inputs);
8281 		}
8282 	} else {
8283 		ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8284 		if (exit_addr) {
8285 			if (smart_branch_opcode == ZEND_JMPNZ) {
8286 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8287 			} else {
8288 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8289 			}
8290 		} else if (smart_branch_opcode) {
8291 			ir_ref if_val = ir_IF(ref);
8292 			ir_IF_TRUE(if_val);
8293 			ir_END_list(true_inputs);
8294 			ir_IF_FALSE(if_val);
8295 			ir_END_list(false_inputs);
8296 		} else {
8297 			jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8298 				ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8299 			ir_END_list(end_inputs);
8300 		}
8301 	}
8302 
8303 	if (!smart_branch_opcode || exit_addr) {
8304 		if (end_inputs) {
8305 			ir_MERGE_list(end_inputs);
8306 		}
8307 	} else {
8308 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8309 	}
8310 
8311 	return 1;
8312 }
8313 
8314 /* copy of hidden zend_closure */
8315 typedef struct _zend_closure {
8316 	zend_object       std;
8317 	zend_function     func;
8318 	zval              this_ptr;
8319 	zend_class_entry *called_scope;
8320 	zif_handler       orig_internal_handler;
8321 } zend_closure;
8322 
zend_jit_stack_check(zend_jit_ctx * jit,const zend_op * opline,uint32_t used_stack)8323 static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8324 {
8325 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8326 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8327 
8328 	if (!exit_addr) {
8329 		return 0;
8330 	}
8331 
8332 	// JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8333 	ir_GUARD(
8334 		ir_UGE(
8335 			ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8336 			ir_CONST_ADDR(used_stack)),
8337 		ir_CONST_ADDR(exit_addr));
8338 
8339 	return 1;
8340 }
8341 
zend_jit_free_trampoline(zend_jit_ctx * jit,int8_t func_reg)8342 static int zend_jit_free_trampoline(zend_jit_ctx *jit, int8_t func_reg)
8343 {
8344 	// JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8345 	ir_ref func = ir_RLOAD_A(func_reg);
8346 	ir_ref if_trampoline = ir_IF(ir_AND_U32(
8347 		ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8348 		ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
8349 
8350 	ir_IF_TRUE(if_trampoline);
8351 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8352 	ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8353 
8354 	return 1;
8355 }
8356 
zend_jit_push_call_frame(zend_jit_ctx * jit,const zend_op * opline,const zend_op_array * op_array,zend_function * func,bool is_closure,bool delayed_fetch_this,int checked_stack,ir_ref func_ref,ir_ref this_ref)8357 static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool delayed_fetch_this, int checked_stack, ir_ref func_ref, ir_ref this_ref)
8358 {
8359 	uint32_t used_stack;
8360 	ir_ref used_stack_ref = IR_UNUSED;
8361 	bool stack_check = 1;
8362 	ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8363 
8364 	ZEND_ASSERT(func_ref != IR_NULL);
8365 	if (func) {
8366 		used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8367 		if ((int)used_stack <= checked_stack) {
8368 			stack_check = 0;
8369 		}
8370 		used_stack_ref = ir_CONST_ADDR(used_stack);
8371 	} else {
8372 		ir_ref num_args_ref;
8373 		ir_ref if_internal_func = IR_UNUSED;
8374 
8375 		used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8376 		used_stack_ref = ir_CONST_ADDR(used_stack);
8377 
8378 		if (!is_closure) {
8379 			used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8380 
8381 			// JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8382 			ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
8383 			if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8384 			ir_IF_FALSE(if_internal_func);
8385 		}
8386 
8387 		// JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8388 		num_args_ref = ir_CONST_U32(opline->extended_value);
8389 		if (!is_closure) {
8390 			ref = ir_SUB_U32(
8391 				ir_SUB_U32(
8392 					ir_MIN_U32(
8393 						num_args_ref,
8394 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.num_args)))),
8395 					ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.last_var)))),
8396 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8397 		} else {
8398 			ref = ir_SUB_U32(
8399 				ir_SUB_U32(
8400 					ir_MIN_U32(
8401 						num_args_ref,
8402 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8403 					ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8404 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8405 		}
8406 		ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8407 		if (sizeof(void*) == 8) {
8408 			ref = ir_SEXT_A(ref);
8409 		}
8410 		ref = ir_SUB_A(used_stack_ref, ref);
8411 
8412 		if (is_closure) {
8413 			used_stack_ref = ref;
8414 		} else {
8415 			ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8416 			used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8417 		}
8418 	}
8419 
8420 	zend_jit_start_reuse_ip(jit);
8421 
8422 	// JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8423 	jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8424 
8425 	if (stack_check) {
8426 		// JIT: Check Stack Overflow
8427 		ref = ir_UGE(
8428 			ir_SUB_A(
8429 				ir_LOAD_A(jit_EG(vm_stack_end)),
8430 				jit_IP(jit)),
8431 			used_stack_ref);
8432 
8433 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8434 			bool may_be_trampoline = !func && (opline->opcode == ZEND_INIT_METHOD_CALL);
8435 			int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8436 				may_be_trampoline ?
8437 					(ZEND_JIT_EXIT_TO_VM | ZEND_JIT_EXIT_METHOD_CALL) : ZEND_JIT_EXIT_TO_VM);
8438 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8439 
8440 			if (!exit_addr) {
8441 				return 0;
8442 			}
8443 
8444 			if (may_be_trampoline) {
8445 				jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
8446 				jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
8447 			}
8448 
8449 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8450 		} else {
8451 			if_enough_stack = ir_IF(ref);
8452 			ir_IF_FALSE_cold(if_enough_stack);
8453 
8454 #ifdef _WIN32
8455 			if (0) {
8456 #else
8457 			if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8458 #endif
8459 				jit_SET_EX_OPLINE(jit, opline);
8460 				ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8461 			} else {
8462 				if (!is_closure) {
8463 					ref = func_ref;
8464 				} else {
8465 					ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8466 				}
8467 				jit_SET_EX_OPLINE(jit, opline);
8468 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8469 					used_stack_ref, ref);
8470 			}
8471 			jit_STORE_IP(jit, ref);
8472 
8473 			cold_path = ir_END();
8474 			ir_IF_TRUE(if_enough_stack);
8475 		}
8476 	}
8477 
8478 	ref = jit_EG(vm_stack_top);
8479 	rx = jit_IP(jit);
8480 #if !OPTIMIZE_FOR_SIZE
8481 	/* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8482 	 * This vesions is longer but faster
8483 	 *    mov EG(vm_stack_top), %CALL
8484 	 *    lea size(%call), %tmp
8485 	 *    mov %tmp, EG(vm_stack_top)
8486 	 */
8487 	top = rx;
8488 #else
8489 	/* JIT: EG(vm_stack_top) += used_stack;
8490 	 * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8491 	 *    mov EG(vm_stack_top), %CALL
8492 	 *    add $size, EG(vm_stack_top)
8493 	 */
8494 	top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8495 #endif
8496 	ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8497 
8498 	// JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8499 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8500 		// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8501 		ir_STORE(jit_CALL(rx, This.u1.type_info), ir_CONST_U32(IS_UNDEF | ZEND_CALL_NESTED_FUNCTION));
8502 	}
8503 #ifdef _WIN32
8504 	if (0) {
8505 #else
8506 	if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8507 #endif
8508 		if (cold_path) {
8509 			ir_MERGE_WITH(cold_path);
8510 			rx = jit_IP(jit);
8511 		}
8512 
8513 		// JIT: call->func = func;
8514 		ir_STORE(jit_CALL(rx, func), func_ref);
8515 	} else {
8516 		if (!is_closure) {
8517 			// JIT: call->func = func;
8518 			ir_STORE(jit_CALL(rx, func), func_ref);
8519 		} else {
8520 			// JIT: call->func = &closure->func;
8521 			ir_STORE(jit_CALL(rx, func), ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8522 		}
8523 		if (cold_path) {
8524 			ir_MERGE_WITH(cold_path);
8525 			rx = jit_IP(jit);
8526 		}
8527 	}
8528 	if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8529 		// JIT: Z_PTR(call->This) = obj;
8530 		ZEND_ASSERT(this_ref != IR_NULL);
8531 		ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8532 	    if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8533 			// JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8534 			ref = jit_CALL(rx, This.u1.type_info);
8535 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8536 				ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS));
8537 			} else {
8538 				ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_HAS_THIS)));
8539 			}
8540 	    } else {
8541 			if (opline->op1_type == IS_CV) {
8542 				// JIT: GC_ADDREF(obj);
8543 				jit_GC_ADDREF(jit, this_ref);
8544 			}
8545 
8546 			// JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8547 			ref = jit_CALL(rx, This.u1.type_info);
8548 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8549 				ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS));
8550 			} else {
8551 				ir_STORE(ref,
8552 					ir_OR_U32(ir_LOAD_U32(ref),
8553 						ir_CONST_U32(ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)));
8554 			}
8555 	    }
8556 	} else if (opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
8557 		// JIT: Z_CE(call->This) = called_scope;
8558 		ir_STORE(jit_CALL(rx, This), this_ref);
8559 	} else if (!is_closure) {
8560 		// JIT: Z_CE(call->This) = called_scope;
8561 		ir_STORE(jit_CALL(rx, This), IR_NULL);
8562 	} else {
8563 		ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8564 
8565 		if (opline->op2_type == IS_CV) {
8566 			// JIT: GC_ADDREF(closure);
8567 			jit_GC_ADDREF(jit, func_ref);
8568 		}
8569 
8570 		// JIT: RX(object_or_called_scope) = closure->called_scope;
8571 		object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8572 
8573 		// JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8574 		//      (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8575 		call_info = ir_OR_U32(
8576 			ir_AND_U32(
8577 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8578 				ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
8579 			ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
8580 		// JIT: if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
8581 		if_cond = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.u1.v.type))));
8582 		ir_IF_TRUE(if_cond);
8583 
8584 		// JIT: call_info |= ZEND_CALL_HAS_THIS;
8585 		call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
8586 
8587 		// JIT: object_or_called_scope = Z_OBJ(closure->this_ptr);
8588 		object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.value.ptr)));
8589 
8590 		ir_MERGE_WITH_EMPTY_FALSE(if_cond);
8591 		call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8592 		object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8593 
8594 		// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8595 		ref = jit_CALL(rx, This.u1.type_info);
8596 		ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), call_info));
8597 
8598 		// JIT: Z_PTR(call->This) = object_or_called_scope;
8599 		ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8600 
8601 		// JIT: if (closure->func.op_array.run_time_cache__ptr)
8602 		if_cond = ir_IF(ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.run_time_cache__ptr))));
8603 		ir_IF_FALSE(if_cond);
8604 
8605 		// JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8606 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8607 			ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8608 
8609 		ir_MERGE_WITH_EMPTY_TRUE(if_cond);
8610 	}
8611 
8612 	// JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8613 	ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8614 
8615 	return 1;
8616 }
8617 
8618 static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8619 {
8620 	int32_t exit_point;
8621 	const void *exit_addr;
8622 	ir_ref call;
8623 
8624 	if (func->type == ZEND_INTERNAL_FUNCTION) {
8625 #ifdef ZEND_WIN32
8626 		// TODO: ASLR may cause different addresses in different workers ???
8627 		return 0;
8628 #endif
8629 	} else if (func->type == ZEND_USER_FUNCTION) {
8630 		if (!zend_accel_in_shm(func->op_array.opcodes)) {
8631 			/* op_array and op_array->opcodes are not persistent. We can't link. */
8632 			return 0;
8633 		}
8634 	} else {
8635 		ZEND_UNREACHABLE();
8636 		return 0;
8637 	}
8638 
8639 	exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8640 	exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8641 	if (!exit_addr) {
8642 		return 0;
8643 	}
8644 
8645 	// call = EX(call);
8646 	call = ir_LOAD_A(jit_EX(call));
8647 	while (level > 0) {
8648 		// call = call->prev_execute_data
8649 		call = ir_LOAD_A(jit_CALL(call, prev_execute_data));
8650 		level--;
8651 	}
8652 
8653 	if (func->type == ZEND_USER_FUNCTION &&
8654 	    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8655 	     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8656 	     !func->common.function_name)) {
8657 		const zend_op *opcodes = func->op_array.opcodes;
8658 
8659 		// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8660 		ir_GUARD(
8661 			ir_EQ(
8662 				ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(call, func)), offsetof(zend_op_array, opcodes))),
8663 				ir_CONST_ADDR(opcodes)),
8664 			ir_CONST_ADDR(exit_addr));
8665 	} else {
8666 		// JIT: if (call->func != func) goto exit_addr;
8667 		ir_GUARD(ir_EQ(ir_LOAD_A(jit_CALL(call, func)), ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8668 	}
8669 
8670 	return 1;
8671 }
8672 
8673 static int zend_jit_init_fcall(zend_jit_ctx *jit, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack)
8674 {
8675 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
8676 	zend_call_info *call_info = NULL;
8677 	zend_function *func = NULL;
8678 	ir_ref func_ref = IR_UNUSED;
8679 
8680 	if (jit->delayed_call_level) {
8681 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8682 			return 0;
8683 		}
8684 	}
8685 
8686 	if (info) {
8687 		call_info = info->callee_info;
8688 		while (call_info && call_info->caller_init_opline != opline) {
8689 			call_info = call_info->next_callee;
8690 		}
8691 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
8692 			func = call_info->callee_func;
8693 		}
8694 	}
8695 
8696 	if (!func
8697 	 && trace
8698 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8699 #ifdef _WIN32
8700 		/* ASLR */
8701 		if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8702 			func = (zend_function*)trace->func;
8703 		}
8704 #else
8705 		func = (zend_function*)trace->func;
8706 #endif
8707 	}
8708 
8709 #ifdef _WIN32
8710 	if (0) {
8711 #else
8712 	if (opline->opcode == ZEND_INIT_FCALL
8713 	 && func
8714 	 && func->type == ZEND_INTERNAL_FUNCTION) {
8715 #endif
8716 		/* load constant address later */
8717 		func_ref = ir_CONST_ADDR(func);
8718 	} else if (func && op_array == &func->op_array) {
8719 		/* recursive call */
8720 		if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8721 		 || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8722 			func_ref = ir_LOAD_A(jit_EX(func));
8723 		} else {
8724 			func_ref = ir_CONST_ADDR(func);
8725 		}
8726 	} else {
8727 		ir_ref if_func, cache_slot_ref, ref;
8728 
8729 		// JIT: if (CACHED_PTR(opline->result.num))
8730 		cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8731 		func_ref = ir_LOAD_A(cache_slot_ref);
8732 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8733 		 && func
8734 		 && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8735 		 && opline->opcode != ZEND_INIT_FCALL) {
8736 			/* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8737 			if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8738 		} else {
8739 			if_func = ir_IF(func_ref);
8740 		}
8741 		ir_IF_FALSE_cold(if_func);
8742 		if (opline->opcode == ZEND_INIT_FCALL
8743 		 && func
8744 		 && func->type == ZEND_USER_FUNCTION
8745 		 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8746 			ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8747 		    ir_STORE(cache_slot_ref, ref);
8748 			ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8749 		} else {
8750 			zval *zv = RT_CONSTANT(opline, opline->op2);
8751 
8752 			if (opline->opcode == ZEND_INIT_FCALL) {
8753 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8754 					ir_CONST_ADDR(Z_STR_P(zv)),
8755 					cache_slot_ref);
8756 			} else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8757 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8758 					ir_CONST_ADDR(Z_STR_P(zv + 1)),
8759 					cache_slot_ref);
8760 			} else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8761 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8762 					ir_CONST_ADDR(zv),
8763 					cache_slot_ref);
8764 			} else {
8765 				ZEND_UNREACHABLE();
8766 			}
8767 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8768 				int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8769 					func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8770 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8771 
8772 				if (!exit_addr) {
8773 					return 0;
8774 				}
8775 				if (!func || opline->opcode == ZEND_INIT_FCALL) {
8776 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8777 				} else if (func->type == ZEND_USER_FUNCTION
8778 					 && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
8779 					const zend_op *opcodes = func->op_array.opcodes;
8780 
8781 					ir_GUARD(
8782 						ir_EQ(
8783 							ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_op_array, opcodes))),
8784 							ir_CONST_ADDR(opcodes)),
8785 						ir_CONST_ADDR(exit_addr));
8786 				} else {
8787 					ir_GUARD(ir_EQ(ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8788 				}
8789 			} else {
8790 jit_SET_EX_OPLINE(jit, opline);
8791 				ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8792 			}
8793 		}
8794 		ir_MERGE_WITH_EMPTY_TRUE(if_func);
8795 		func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8796 	}
8797 
8798 	if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, IR_UNUSED)) {
8799 		return 0;
8800 	}
8801 
8802 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8803 		if (!zend_jit_save_call_chain(jit, call_level)) {
8804 			return 0;
8805 		}
8806 	} else {
8807 		ZEND_ASSERT(call_level > 0);
8808 		jit->delayed_call_level = call_level;
8809 		delayed_call_chain = 1;
8810 	}
8811 
8812 	if (trace
8813 	 && trace->op == ZEND_JIT_TRACE_END
8814 	 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
8815 		if (!zend_jit_set_ip(jit, opline + 1)) {
8816 			return 0;
8817 		}
8818 	}
8819 
8820 	return 1;
8821 }
8822 
8823 static int zend_jit_init_method_call(zend_jit_ctx         *jit,
8824                                      const zend_op        *opline,
8825                                      uint32_t              b,
8826                                      const zend_op_array  *op_array,
8827                                      zend_ssa             *ssa,
8828                                      const zend_ssa_op    *ssa_op,
8829                                      int                   call_level,
8830                                      uint32_t              op1_info,
8831                                      zend_jit_addr         op1_addr,
8832                                      zend_class_entry     *ce,
8833                                      bool                  ce_is_instanceof,
8834                                      bool                  on_this,
8835                                      bool                  delayed_fetch_this,
8836                                      zend_class_entry     *trace_ce,
8837                                      zend_jit_trace_rec   *trace,
8838                                      int                   checked_stack,
8839                                      int8_t                func_reg,
8840                                      int8_t                this_reg,
8841                                      bool                  polymorphic_side_trace)
8842 {
8843 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
8844 	zend_call_info *call_info = NULL;
8845 	zend_function *func = NULL;
8846 	zval *function_name;
8847 	ir_ref if_static = IR_UNUSED, cold_path, this_ref = IR_NULL, func_ref = IR_NULL;
8848 
8849 	ZEND_ASSERT(opline->op2_type == IS_CONST);
8850 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
8851 
8852 	function_name = RT_CONSTANT(opline, opline->op2);
8853 
8854 	if (info) {
8855 		call_info = info->callee_info;
8856 		while (call_info && call_info->caller_init_opline != opline) {
8857 			call_info = call_info->next_callee;
8858 		}
8859 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
8860 			func = call_info->callee_func;
8861 		}
8862 	}
8863 
8864 	if (polymorphic_side_trace) {
8865 		/* function is passed in r0 from parent_trace */
8866 		ZEND_ASSERT(func_reg >= 0 && this_reg >= 0);
8867 		func_ref = zend_jit_deopt_rload(jit, IR_ADDR, func_reg);
8868 		this_ref = zend_jit_deopt_rload(jit, IR_ADDR, this_reg);
8869 	} else {
8870 		ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
8871 
8872 		if (on_this) {
8873 			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
8874 			this_ref = jit_Z_PTR(jit, this_addr);
8875 		} else {
8876 		    if (op1_info & MAY_BE_REF) {
8877 				if (opline->op1_type == IS_CV) {
8878 					// JIT: ZVAL_DEREF(op1)
8879 					ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8880 					ref = jit_ZVAL_DEREF_ref(jit, ref);
8881 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8882 				} else {
8883 					ir_ref if_ref;
8884 
8885 					/* Hack: Convert reference to regular value to simplify JIT code */
8886 					ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
8887 
8888 					if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
8889 					ir_IF_TRUE(if_ref);
8890 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
8891 
8892 					ir_MERGE_WITH_EMPTY_FALSE(if_ref);
8893 				}
8894 			}
8895 			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
8896 				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8897 					int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8898 					const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8899 
8900 					if (!exit_addr) {
8901 						return 0;
8902 					}
8903 					ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
8904 						ir_CONST_ADDR(exit_addr));
8905 				} else {
8906 					ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
8907 
8908 					ir_IF_FALSE_cold(if_object);
8909 
8910 					jit_SET_EX_OPLINE(jit, opline);
8911 					if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8912 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
8913 							jit_ZVAL_ADDR(jit, op1_addr));
8914 					} else {
8915 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
8916 							jit_ZVAL_ADDR(jit, op1_addr));
8917 					}
8918 					ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
8919 					ir_IF_TRUE(if_object);
8920 				}
8921 			}
8922 
8923 			this_ref = jit_Z_PTR(jit, op1_addr);
8924 		}
8925 
8926 		if (jit->delayed_call_level) {
8927 			if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8928 				return 0;
8929 			}
8930 		}
8931 
8932 		if (func) {
8933 			// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8934 			ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
8935 
8936 			if_found = ir_IF(ref);
8937 			ir_IF_TRUE(if_found);
8938 			fast_path = ir_END();
8939 		} else {
8940 			// JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
8941 			run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
8942 			ref = ir_EQ(
8943 				ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
8944 				ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
8945 			if_found = ir_IF(ref);
8946 			ir_IF_TRUE(if_found);
8947 
8948 			// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8949 			ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
8950 			fast_path = ir_END();
8951 
8952 		}
8953 
8954 		ir_IF_FALSE_cold(if_found);
8955 		jit_SET_EX_OPLINE(jit, opline);
8956 
8957 		if (!jit->ctx.fixed_call_stack_size) {
8958 			// JIT: alloca(sizeof(void*));
8959 			this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
8960 		} else {
8961 			this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
8962 		}
8963 		ir_STORE(this_ref2, this_ref);
8964 
8965 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8966 			ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
8967 					this_ref,
8968 					ir_CONST_ADDR(function_name),
8969 					this_ref2);
8970 		} else {
8971 			ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
8972 					this_ref,
8973 					ir_CONST_ADDR(function_name),
8974 					this_ref2);
8975 		}
8976 
8977 		this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
8978 		if (!jit->ctx.fixed_call_stack_size) {
8979 			// JIT: revert alloca
8980 			ir_AFREE(ir_CONST_ADDR(0x10));
8981 		}
8982 
8983 		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8984 
8985 		ir_MERGE_WITH(fast_path);
8986 		func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
8987 		this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
8988 	}
8989 
8990 	if ((!func || zend_jit_may_be_modified(func, op_array))
8991 	 && trace
8992 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
8993 	 && trace->func
8994 #ifdef _WIN32
8995 	 && trace->func->type != ZEND_INTERNAL_FUNCTION
8996 #endif
8997 	) {
8998 		int32_t exit_point;
8999 		const void *exit_addr;
9000 
9001 		exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
9002 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9003 		if (!exit_addr) {
9004 			return 0;
9005 		}
9006 
9007 		jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9008 		jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
9009 
9010 		func = (zend_function*)trace->func;
9011 
9012 		if (func->type == ZEND_USER_FUNCTION &&
9013 		    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9014 		     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9015 		     !func->common.function_name)) {
9016 			const zend_op *opcodes = func->op_array.opcodes;
9017 
9018 			ir_GUARD(
9019 				ir_EQ(
9020 					ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9021 					ir_CONST_ADDR(opcodes)),
9022 				ir_CONST_ADDR(exit_addr));
9023 		} else {
9024 			ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9025 		}
9026 	}
9027 
9028 	if (!func) {
9029 		// JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9030 		if_static = ir_IF(ir_AND_U32(
9031 			ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9032 			ir_CONST_U32(ZEND_ACC_STATIC)));
9033 		ir_IF_TRUE_cold(if_static);
9034 	}
9035 
9036 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9037 		ir_ref ret;
9038 
9039 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9040 			ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame_tmp),
9041 					this_ref,
9042 					func_ref,
9043 					ir_CONST_U32(opline->extended_value));
9044 		} else {
9045 			ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame),
9046 					this_ref,
9047 					func_ref,
9048 					ir_CONST_U32(opline->extended_value));
9049 		}
9050 
9051 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
9052 			ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9053 		}
9054 		jit_STORE_IP(jit, ret);
9055 	}
9056 
9057 	if (!func) {
9058 		cold_path = ir_END();
9059 		ir_IF_FALSE(if_static);
9060 	}
9061 
9062 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9063 		if (!zend_jit_push_call_frame(jit, opline, NULL, func, 0, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
9064 			return 0;
9065 		}
9066 	}
9067 
9068 	if (!func) {
9069 		ir_MERGE_WITH(cold_path);
9070 	}
9071 	zend_jit_start_reuse_ip(jit);
9072 
9073 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9074 		if (!zend_jit_save_call_chain(jit, call_level)) {
9075 			return 0;
9076 		}
9077 	} else {
9078 		ZEND_ASSERT(call_level > 0);
9079 		delayed_call_chain = 1;
9080 		jit->delayed_call_level = call_level;
9081 	}
9082 
9083 	if (trace
9084 	 && trace->op == ZEND_JIT_TRACE_END
9085 	 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9086 		if (!zend_jit_set_ip(jit, opline + 1)) {
9087 			return 0;
9088 		}
9089 	}
9090 
9091 	return 1;
9092 }
9093 
9094 static int zend_jit_init_static_method_call(zend_jit_ctx         *jit,
9095                                             const zend_op        *opline,
9096                                             uint32_t              b,
9097                                             const zend_op_array  *op_array,
9098                                             zend_ssa             *ssa,
9099                                             const zend_ssa_op    *ssa_op,
9100                                             int                   call_level,
9101                                             zend_jit_trace_rec   *trace,
9102                                             int                   checked_stack)
9103 {
9104 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
9105 	zend_call_info *call_info = NULL;
9106 	zend_class_entry *ce;
9107 	zend_function *func = NULL;
9108 	ir_ref func_ref, func_ref2, scope_ref, scope_ref2, if_cached, cold_path, ref;
9109 	ir_ref if_static = IR_UNUSED;
9110 
9111 	if (info) {
9112 		call_info = info->callee_info;
9113 		while (call_info && call_info->caller_init_opline != opline) {
9114 			call_info = call_info->next_callee;
9115 		}
9116 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
9117 			func = call_info->callee_func;
9118 		}
9119 	}
9120 
9121 	ce = zend_get_known_class(op_array, opline, opline->op1_type, opline->op1);
9122 	if (!func && ce) {
9123 		zval *zv = RT_CONSTANT(opline, opline->op2);
9124 		zend_string *method_name;
9125 
9126 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
9127 		method_name = Z_STR_P(zv);
9128 		zv = zend_hash_find(&ce->function_table, method_name);
9129 		if (zv) {
9130 			zend_function *fn = Z_PTR_P(zv);
9131 
9132 			if (fn->common.scope == op_array->scope
9133 			 || (fn->common.fn_flags & ZEND_ACC_PUBLIC)
9134 			 || ((fn->common.fn_flags & ZEND_ACC_PROTECTED)
9135 			  && op_array->scope
9136 			  && instanceof_function_slow(op_array->scope, fn->common.scope))) {
9137 				func = fn;
9138 			}
9139 		}
9140 	}
9141 
9142 	if (jit->delayed_call_level) {
9143 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9144 			return 0;
9145 		}
9146 	}
9147 
9148 	// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9149 	func_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9150 
9151 	// JIT: if (fbc)
9152 	if_cached = ir_IF(func_ref);
9153 	ir_IF_FALSE_cold(if_cached);
9154 
9155 	jit_SET_EX_OPLINE(jit, opline);
9156 	scope_ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_class_helper), jit_FP(jit));
9157 	ir_GUARD(scope_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9158 
9159 	func_ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_static_method_helper), jit_FP(jit), scope_ref2);
9160 	ir_GUARD(func_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9161 
9162 	cold_path = ir_END();
9163 
9164 	ir_IF_TRUE(if_cached);
9165 	if (ce && (ce->ce_flags & ZEND_ACC_IMMUTABLE) && (ce->ce_flags & ZEND_ACC_LINKED)) {
9166 		scope_ref = ir_CONST_ADDR(ce);
9167 	} else {
9168 		scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num));
9169 	}
9170 
9171 	ir_MERGE_2(cold_path, ir_END());
9172 	func_ref = ir_PHI_2(IR_ADDR, func_ref2, func_ref);
9173 	scope_ref = ir_PHI_2(IR_ADDR, scope_ref2, scope_ref);
9174 
9175 	if ((!func || zend_jit_may_be_modified(func, op_array))
9176 	 && trace
9177 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9178 	 && trace->func
9179 #ifdef _WIN32
9180 	 && trace->func->type != ZEND_INTERNAL_FUNCTION
9181 #endif
9182 	) {
9183 		int32_t exit_point;
9184 		const void *exit_addr;
9185 
9186 		exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : 0);
9187 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9188 		if (!exit_addr) {
9189 			return 0;
9190 		}
9191 
9192 //		jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9193 //		jit->trace->exit_info[exit_point].poly_this_ref = scope_ref;
9194 
9195 		func = (zend_function*)trace->func;
9196 
9197 		if (func->type == ZEND_USER_FUNCTION &&
9198 		    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9199 		     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9200 		     !func->common.function_name)) {
9201 			const zend_op *opcodes = func->op_array.opcodes;
9202 
9203 			ir_GUARD(
9204 				ir_EQ(
9205 					ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9206 					ir_CONST_ADDR(opcodes)),
9207 				ir_CONST_ADDR(exit_addr));
9208 		} else {
9209 			ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9210 		}
9211 	}
9212 
9213 	if (!func || !(func->common.fn_flags & ZEND_ACC_STATIC)) {
9214 		if (!func) {
9215 			// JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9216 			if_static = ir_IF(ir_AND_U32(
9217 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9218 				ir_CONST_U32(ZEND_ACC_STATIC)));
9219 			ir_IF_FALSE_cold(if_static);
9220 		}
9221 
9222 		ref = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_this_method_call_frame),
9223 				scope_ref,
9224 				func_ref,
9225 				ir_CONST_U32(opline->extended_value));
9226 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9227 		jit_STORE_IP(jit, ref);
9228 
9229 		if (!func) {
9230 			cold_path = ir_END();
9231 			ir_IF_TRUE(if_static);
9232 		}
9233 	}
9234 
9235 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC)) {
9236 		if (opline->op1_type == IS_UNUSED
9237 		 && ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
9238 		     (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) {
9239 			if (op_array->fn_flags & ZEND_ACC_STATIC) {
9240 				scope_ref = ir_LOAD_A(jit_EX(This.value.ref));
9241 			} else {
9242 				scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce)));
9243 			}
9244 		}
9245 		if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, scope_ref)) {
9246 			return 0;
9247 		}
9248 
9249 		if (!func) {
9250 			ir_MERGE_2(cold_path, ir_END());
9251 		}
9252 	}
9253 
9254 	zend_jit_start_reuse_ip(jit);
9255 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9256 		if (!zend_jit_save_call_chain(jit, call_level)) {
9257 			return 0;
9258 		}
9259 	} else {
9260 		ZEND_ASSERT(call_level > 0);
9261 		jit->delayed_call_level = call_level;
9262 		delayed_call_chain = 1;
9263 	}
9264 
9265 	if (trace
9266 	 && trace->op == ZEND_JIT_TRACE_END
9267 	 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9268 		if (!zend_jit_set_ip(jit, opline + 1)) {
9269 			return 0;
9270 		}
9271 	}
9272 
9273 	return 1;
9274 }
9275 
9276 static int zend_jit_init_closure_call(zend_jit_ctx         *jit,
9277                                       const zend_op        *opline,
9278                                       uint32_t              b,
9279                                       const zend_op_array  *op_array,
9280                                       zend_ssa             *ssa,
9281                                       const zend_ssa_op    *ssa_op,
9282                                       int                   call_level,
9283                                       zend_jit_trace_rec   *trace,
9284                                       int                   checked_stack)
9285 {
9286 	zend_function *func = NULL;
9287 	zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9288 	ir_ref ref;
9289 
9290 	ref = jit_Z_PTR(jit, op2_addr);
9291 
9292 	if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9293 	 && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9294 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9295 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9296 
9297 		if (!exit_addr) {
9298 			return 0;
9299 		}
9300 
9301 		ir_GUARD(
9302 			ir_EQ(
9303 				ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_object, ce))),
9304 				ir_CONST_ADDR(zend_ce_closure)),
9305 			ir_CONST_ADDR(exit_addr));
9306 
9307 		if (ssa->var_info && ssa_op->op2_use >= 0) {
9308 			ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9309 			ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9310 			ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9311 		}
9312 	}
9313 
9314 	if (trace
9315 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9316 	 && trace->func
9317 	 && trace->func->type == ZEND_USER_FUNCTION) {
9318 		const zend_op *opcodes;
9319 		int32_t exit_point;
9320 		const void *exit_addr;
9321 
9322 		func = (zend_function*)trace->func;
9323 		opcodes = func->op_array.opcodes;
9324 		exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9325 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9326 		if (!exit_addr) {
9327 			return 0;
9328 		}
9329 
9330 		ir_GUARD(
9331 			ir_EQ(
9332 				ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9333 				ir_CONST_ADDR(opcodes)),
9334 			ir_CONST_ADDR(exit_addr));
9335 	}
9336 
9337 	if (jit->delayed_call_level) {
9338 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9339 			return 0;
9340 		}
9341 	}
9342 
9343 	if (!zend_jit_push_call_frame(jit, opline, NULL, func, 1, 0, checked_stack, ref, IR_UNUSED)) {
9344 		return 0;
9345 	}
9346 
9347 	if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9348 		if (!zend_jit_save_call_chain(jit, call_level)) {
9349 			return 0;
9350 		}
9351 	} else {
9352 		ZEND_ASSERT(call_level > 0);
9353 		delayed_call_chain = 1;
9354 		jit->delayed_call_level = call_level;
9355 	}
9356 
9357 	if (trace
9358 	 && trace->op == ZEND_JIT_TRACE_END
9359 	 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9360 		if (!zend_jit_set_ip(jit, opline + 1)) {
9361 			return 0;
9362 		}
9363 	}
9364 
9365 	return 1;
9366 }
9367 
9368 static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9369 {
9370 	uint32_t arg_num = opline->op2.num;
9371 	zend_jit_addr arg_addr;
9372 
9373 	ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
9374 
9375 	if (!zend_jit_reuse_ip(jit)) {
9376 		return 0;
9377 	}
9378 
9379 	if (opline->opcode == ZEND_SEND_VAL_EX) {
9380 		uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9381 
9382 		ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
9383 
9384 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9385 		 && JIT_G(current_frame)
9386 		 && JIT_G(current_frame)->call
9387 		 && JIT_G(current_frame)->call->func) {
9388 			if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9389 				/* Don't generate code that always throws exception */
9390 				return 0;
9391 			}
9392 		} else {
9393 			ir_ref cond = ir_AND_U32(
9394 				ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9395 				ir_CONST_U32(mask));
9396 
9397 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9398 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9399 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9400 				if (!exit_addr) {
9401 					return 0;
9402 				}
9403 				ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9404 			} else {
9405 				ir_ref if_pass_by_ref;
9406 
9407 				if_pass_by_ref = ir_IF(cond);
9408 
9409 				ir_IF_TRUE_cold(if_pass_by_ref);
9410 				if (Z_MODE(op1_addr) == IS_REG) {
9411 					/* set type to avoid zval_ptr_dtor() on uninitialized value */
9412 					zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9413 					jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9414 				}
9415 				jit_SET_EX_OPLINE(jit, opline);
9416 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9417 
9418 				ir_IF_FALSE(if_pass_by_ref);
9419 			}
9420 		}
9421 	}
9422 
9423 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9424 
9425 	if (opline->op1_type == IS_CONST) {
9426 		zval *zv = RT_CONSTANT(opline, opline->op1);
9427 
9428 		jit_ZVAL_COPY_CONST(jit,
9429 			arg_addr,
9430 			MAY_BE_ANY, MAY_BE_ANY,
9431 			zv, 1);
9432 	} else {
9433 		jit_ZVAL_COPY(jit,
9434 			arg_addr,
9435 			MAY_BE_ANY,
9436 			op1_addr, op1_info, 0);
9437 	}
9438 
9439 	return 1;
9440 }
9441 
9442 static int zend_jit_send_ref(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold)
9443 {
9444 	zend_jit_addr op1_addr, arg_addr, ref_addr;
9445 	ir_ref ref_path = IR_UNUSED;
9446 
9447 	op1_addr = OP1_ADDR();
9448 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9449 
9450 	if (!zend_jit_reuse_ip(jit)) {
9451 		return 0;
9452 	}
9453 
9454 	if (opline->op1_type == IS_VAR) {
9455 		if (op1_info & MAY_BE_INDIRECT) {
9456 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9457 		}
9458 	} else if (opline->op1_type == IS_CV) {
9459 		if (op1_info & MAY_BE_UNDEF) {
9460 			if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9461 				// JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9462 				ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9463 				ir_IF_FALSE(if_def);
9464 				// JIT: ZVAL_NULL(op1)
9465 				jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9466 				ir_MERGE_WITH_EMPTY_TRUE(if_def);
9467 			}
9468 			op1_info &= ~MAY_BE_UNDEF;
9469 			op1_info |= MAY_BE_NULL;
9470 		}
9471 	} else {
9472 		ZEND_UNREACHABLE();
9473 	}
9474 
9475 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9476 		ir_ref ref, ref2;
9477 
9478 		if (op1_info & MAY_BE_REF) {
9479 			ir_ref if_ref;
9480 
9481 			// JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9482 			if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9483 			ir_IF_TRUE(if_ref);
9484 			// JIT: ref = Z_PTR_P(op1)
9485 			ref = jit_Z_PTR(jit, op1_addr);
9486 			// JIT: GC_ADDREF(ref)
9487 			jit_GC_ADDREF(jit, ref);
9488 			// JIT: ZVAL_REFERENCE(arg, ref)
9489 			jit_set_Z_PTR(jit, arg_addr, ref);
9490 			jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9491 			ref_path = ir_END();
9492 			ir_IF_FALSE(if_ref);
9493 		}
9494 
9495 		// JIT: ZVAL_NEW_REF(arg, varptr);
9496 		// JIT: ref = emalloc(sizeof(zend_reference));
9497 		ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9498 		// JIT: GC_REFCOUNT(ref) = 2
9499 		jit_set_GC_REFCOUNT(jit, ref, 2);
9500 		// JIT: GC_TYPE(ref) = GC_REFERENCE
9501 		ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, gc.u.type_info)), ir_CONST_U32(GC_REFERENCE));
9502 		ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr)), IR_NULL);
9503 		ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9504 		ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9505 
9506         // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9507 		jit_ZVAL_COPY(jit,
9508 			ref_addr,
9509 			MAY_BE_ANY,
9510 			op1_addr, op1_info, 0);
9511 
9512 		// JIT: ZVAL_REFERENCE(arg, ref)
9513 		jit_set_Z_PTR(jit, op1_addr, ref);
9514 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9515 
9516 		// JIT: ZVAL_REFERENCE(arg, ref)
9517 		jit_set_Z_PTR(jit, arg_addr, ref);
9518 		jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9519 	}
9520 
9521 	if (ref_path) {
9522 		ir_MERGE_WITH(ref_path);
9523 	}
9524 
9525 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9526 
9527 	return 1;
9528 }
9529 
9530 static int zend_jit_send_var(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr)
9531 {
9532 	uint32_t arg_num = opline->op2.num;
9533 	zend_jit_addr arg_addr;
9534 	ir_ref end_inputs = IR_UNUSED;
9535 
9536 	ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9537 	     opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9538 	    arg_num <= MAX_ARG_FLAG_NUM);
9539 
9540 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9541 
9542 	if (!zend_jit_reuse_ip(jit)) {
9543 		return 0;
9544 	}
9545 
9546 	if (opline->opcode == ZEND_SEND_VAR_EX) {
9547 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9548 		 && JIT_G(current_frame)
9549 		 && JIT_G(current_frame)->call
9550 		 && JIT_G(current_frame)->call->func) {
9551 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9552 				if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9553 					return 0;
9554 				}
9555 				return 1;
9556 			}
9557 		} else {
9558 			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9559 
9560 			// JIT: if (RX->func->quick_arg_flags & mask)
9561 			ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9562 				ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9563 				ir_CONST_U32(mask)));
9564 			ir_IF_TRUE_cold(if_send_by_ref);
9565 
9566 			if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9567 				return 0;
9568 			}
9569 
9570 			ir_END_list(end_inputs);
9571 			ir_IF_FALSE(if_send_by_ref);
9572 		}
9573 	} else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9574 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9575 		 && JIT_G(current_frame)
9576 		 && JIT_G(current_frame)->call
9577 		 && JIT_G(current_frame)->call->func) {
9578 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9579 
9580 		        // JIT: ZVAL_COPY_VALUE(arg, op1)
9581 				jit_ZVAL_COPY(jit,
9582 					arg_addr,
9583 					MAY_BE_ANY,
9584 					op1_addr, op1_info, 0);
9585 
9586 				if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9587 					if (!(op1_info & MAY_BE_REF)) {
9588 						/* Don't generate code that always throws exception */
9589 						return 0;
9590 					} else {
9591 						int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9592 						const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9593 						if (!exit_addr) {
9594 							return 0;
9595 						}
9596 
9597 						// JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9598 						ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9599 							ir_CONST_ADDR(exit_addr));
9600 					}
9601 				}
9602 				return 1;
9603 			}
9604 		} else {
9605 			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9606 			ir_ref func, if_send_by_ref, if_prefer_ref;
9607 
9608 			// JIT: if (RX->func->quick_arg_flags & mask)
9609 			func = ir_LOAD_A(jit_RX(func));
9610 			if_send_by_ref = ir_IF(ir_AND_U32(
9611 				ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9612 				ir_CONST_U32(mask)));
9613 			ir_IF_TRUE_cold(if_send_by_ref);
9614 
9615 			mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9616 
9617 	        // JIT: ZVAL_COPY_VALUE(arg, op1)
9618 			jit_ZVAL_COPY(jit,
9619 				arg_addr,
9620 				MAY_BE_ANY,
9621 				op1_addr, op1_info, 0);
9622 
9623 			if (op1_info & MAY_BE_REF) {
9624 				ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9625 				ir_IF_TRUE(if_ref);
9626 				ir_END_list(end_inputs);
9627 				ir_IF_FALSE(if_ref);
9628 			}
9629 
9630 			// JIT: if (RX->func->quick_arg_flags & mask)
9631 			if_prefer_ref = ir_IF(ir_AND_U32(
9632 				ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9633 				ir_CONST_U32(mask)));
9634 			ir_IF_TRUE(if_prefer_ref);
9635 			ir_END_list(end_inputs);
9636 			ir_IF_FALSE(if_prefer_ref);
9637 
9638 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9639 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9640 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9641 				if (!exit_addr) {
9642 					return 0;
9643 				}
9644 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9645 			} else {
9646 				jit_SET_EX_OPLINE(jit, opline);
9647 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9648 					jit_ZVAL_ADDR(jit, arg_addr));
9649 				zend_jit_check_exception(jit);
9650 				ir_END_list(end_inputs);
9651 			}
9652 
9653 			ir_IF_FALSE(if_send_by_ref);
9654 		}
9655 	} else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9656 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9657 		 && JIT_G(current_frame)
9658 		 && JIT_G(current_frame)->call
9659 		 && JIT_G(current_frame)->call->func) {
9660 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9661 				if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9662 					return 0;
9663 				}
9664 				return 1;
9665 			}
9666 		} else {
9667 			// JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9668 			ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9669 				ir_LOAD_U32(jit_RX(This.u1.type_info)),
9670 				ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9671 			ir_IF_TRUE_cold(if_send_by_ref);
9672 
9673 			if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9674 				return 0;
9675 			}
9676 
9677 			ir_END_list(end_inputs);
9678 			ir_IF_FALSE(if_send_by_ref);
9679 		}
9680 	}
9681 
9682 	if (op1_info & MAY_BE_UNDEF) {
9683 		ir_ref ref, if_def = IR_UNUSED;
9684 
9685 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9686 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9687 			ir_IF_FALSE_cold(if_def);
9688 		}
9689 
9690 		// JIT: zend_jit_undefined_op_helper(opline->op1.var)
9691 		jit_SET_EX_OPLINE(jit, opline);
9692 		ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9693 			ir_CONST_U32(opline->op1.var));
9694 
9695 		// JIT: ZVAL_NULL(arg)
9696 		jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9697 
9698 		// JIT: check_exception
9699 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9700 
9701 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9702 			ir_END_list(end_inputs);
9703 			ir_IF_TRUE(if_def);
9704 		} else {
9705 			if (end_inputs) {
9706 				ir_END_list(end_inputs);
9707 				ir_MERGE_list(end_inputs);
9708 			}
9709 			return 1;
9710 		}
9711 	}
9712 
9713 	if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9714         // JIT: ZVAL_COPY_VALUE(arg, op1)
9715 		jit_ZVAL_COPY(jit,
9716 			arg_addr,
9717 			MAY_BE_ANY,
9718 			op1_addr, op1_info, 0);
9719 		if (op1_info & MAY_BE_REF) {
9720 				// JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9721 				ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9722 				ir_IF_TRUE(if_ref);
9723 				ir_END_list(end_inputs);
9724 				ir_IF_FALSE(if_ref);
9725 		}
9726 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9727 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9728 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9729 			if (!exit_addr) {
9730 				return 0;
9731 			}
9732 			ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9733 		} else {
9734 			jit_SET_EX_OPLINE(jit, opline);
9735 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9736 				jit_ZVAL_ADDR(jit, arg_addr));
9737 			zend_jit_check_exception(jit);
9738 		}
9739 	} else {
9740 		if (op1_info & MAY_BE_REF) {
9741 			if (opline->op1_type == IS_CV) {
9742 				ir_ref ref;
9743 
9744 				// JIT: ZVAL_DEREF(op1)
9745 				ref = jit_ZVAL_ADDR(jit, op1_addr);
9746 				ref = jit_ZVAL_DEREF_ref(jit, ref);
9747 				op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9748 
9749 		        // JIT: ZVAL_COPY(arg, op1)
9750 				jit_ZVAL_COPY(jit,
9751 					arg_addr,
9752 					MAY_BE_ANY,
9753 					op1_addr, op1_info, 1);
9754 			} else {
9755 				ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9756 				zend_jit_addr ref_addr;
9757 
9758 				// JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9759 				if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9760 				ir_IF_TRUE_cold(if_ref);
9761 
9762 				// JIT: ref = Z_COUNTED_P(op1);
9763 				ref = jit_Z_PTR(jit, op1_addr);
9764 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9765 				ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9766 
9767 				// JIT: ZVAL_COPY_VALUE(arg, op1);
9768 				jit_ZVAL_COPY(jit,
9769 					arg_addr,
9770 					MAY_BE_ANY,
9771 					ref_addr, op1_info, 0);
9772 
9773 				// JIT: if (GC_DELREF(ref) != 0)
9774 				refcount = jit_GC_DELREF(jit, ref);
9775 				if_not_zero = ir_IF(refcount);
9776 				ir_IF_TRUE(if_not_zero);
9777 
9778                 // JIT: if (Z_REFCOUNTED_P(arg)
9779 				if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9780 				ir_IF_TRUE(if_refcounted);
9781 				// JIT: Z_ADDREF_P(arg)
9782 				jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9783 				ir_END_list(end_inputs);
9784 				ir_IF_FALSE(if_refcounted);
9785 				ir_END_list(end_inputs);
9786 
9787 				ir_IF_FALSE(if_not_zero);
9788 
9789 				// JIT: efree(ref)
9790 				jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9791 				ir_END_list(end_inputs);
9792 
9793 				ir_IF_FALSE(if_ref);
9794 
9795 				// JIT: ZVAL_COPY_VALUE(arg, op1);
9796 				jit_ZVAL_COPY(jit,
9797 					arg_addr,
9798 					MAY_BE_ANY,
9799 					op1_addr, op1_info, 0);
9800 			}
9801 		} else {
9802 			if (op1_addr != op1_def_addr) {
9803 				if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9804 					return 0;
9805 				}
9806 				if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9807 					op1_addr = op1_def_addr;
9808 				}
9809 			}
9810 
9811 	        // JIT: ZVAL_COPY_VALUE(arg, op1)
9812 			jit_ZVAL_COPY(jit,
9813 				arg_addr,
9814 				MAY_BE_ANY,
9815 				op1_addr, op1_info, opline->op1_type == IS_CV);
9816 		}
9817 	}
9818 
9819 	if (end_inputs) {
9820 		ir_END_list(end_inputs);
9821 		ir_MERGE_list(end_inputs);
9822 	}
9823 
9824 	return 1;
9825 }
9826 
9827 static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
9828 {
9829 	uint32_t arg_num = opline->op2.num;
9830 	ir_ref ref;
9831 
9832 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9833 	 && JIT_G(current_frame)
9834 	 && JIT_G(current_frame)->call
9835 	 && JIT_G(current_frame)->call->func) {
9836 		if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9837 			if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
9838 				TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
9839 				// JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9840 				if (jit->reuse_ip) {
9841 					ref = jit_IP(jit);
9842 				} else {
9843 					ref = ir_LOAD_A(jit_EX(call));
9844 				}
9845 				ref = jit_CALL(ref, This.u1.type_info);
9846 				ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9847 			}
9848 		} else {
9849 			if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
9850 				TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
9851 				// JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9852 				if (jit->reuse_ip) {
9853 					ref = jit_IP(jit);
9854 				} else {
9855 					ref = ir_LOAD_A(jit_EX(call));
9856 				}
9857 				ref = jit_CALL(ref, This.u1.type_info);
9858 				ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9859 			}
9860 		}
9861 	} else {
9862 		// JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
9863 		uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9864 		ir_ref rx, if_ref, cold_path;
9865 
9866 		if (!zend_jit_reuse_ip(jit)) {
9867 			return 0;
9868 		}
9869 
9870 		rx = jit_IP(jit);
9871 
9872 		ref = ir_AND_U32(
9873 			ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_function, quick_arg_flags))),
9874 			ir_CONST_U32(mask));
9875 		if_ref = ir_IF(ref);
9876 		ir_IF_TRUE_cold(if_ref);
9877 
9878 		// JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9879 		ref = jit_CALL(rx, This.u1.type_info);
9880 		ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9881 
9882 		cold_path = ir_END();
9883 		ir_IF_FALSE(if_ref);
9884 
9885 		// JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9886 		ref = jit_CALL(rx, This.u1.type_info);
9887 		ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9888 
9889 		ir_MERGE_WITH(cold_path);
9890 	}
9891 
9892 	return 1;
9893 }
9894 
9895 static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
9896 {
9897 	ir_ref call, if_may_have_undef, ret;
9898 
9899 	if (jit->reuse_ip) {
9900 		call = jit_IP(jit);
9901 	} else {
9902 		call = ir_LOAD_A(jit_EX(call));
9903 	}
9904 
9905 	if_may_have_undef = ir_IF(ir_AND_U8(
9906 		ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
9907 		ir_CONST_U8(ZEND_CALL_MAY_HAVE_UNDEF >> 24)));
9908 
9909 	ir_IF_TRUE_cold(if_may_have_undef);
9910 	jit_SET_EX_OPLINE(jit, opline);
9911 	ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_handle_undef_args), call);
9912 	ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9913 	ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
9914 
9915 	return 1;
9916 }
9917 
9918 static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block, zend_jit_trace_rec *trace)
9919 {
9920 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
9921 	zend_call_info *call_info = NULL;
9922 	const zend_function *func = NULL;
9923 	uint32_t i;
9924 	uint32_t call_num_args = 0;
9925 	bool unknown_num_args = 0;
9926 	const void *exit_addr = NULL;
9927 	const zend_op *prev_opline;
9928 	ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
9929 
9930 	prev_opline = opline - 1;
9931 	while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
9932 		prev_opline--;
9933 	}
9934 	if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
9935 			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
9936 		unknown_num_args = 1;
9937 	}
9938 
9939 	if (info) {
9940 		call_info = info->callee_info;
9941 		while (call_info && call_info->caller_call_opline != opline) {
9942 			call_info = call_info->next_callee;
9943 		}
9944 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
9945 			func = call_info->callee_func;
9946 		}
9947 		if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
9948 		 && JIT_G(current_frame)
9949 		 && JIT_G(current_frame)->call
9950 		 && !JIT_G(current_frame)->call->func) {
9951 			call_info = NULL; func = NULL; /* megamorphic call from trait */
9952 		}
9953 	}
9954 	if (!func) {
9955 		/* resolve function at run time */
9956 	} else if (func->type == ZEND_USER_FUNCTION) {
9957 		ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
9958 		call_num_args = call_info->num_args;
9959 	} else if (func->type == ZEND_INTERNAL_FUNCTION) {
9960 		ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
9961 		call_num_args = call_info->num_args;
9962 	} else {
9963 		ZEND_UNREACHABLE();
9964 	}
9965 
9966 	if (trace && !func) {
9967 		if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
9968 			ZEND_ASSERT(!trace->func || trace->func->type == ZEND_INTERNAL_FUNCTION);
9969 #ifndef ZEND_WIN32
9970 			// TODO: ASLR may cause different addresses in different workers ???
9971 			func = trace->func;
9972 			if (JIT_G(current_frame) &&
9973 			    JIT_G(current_frame)->call &&
9974 			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9975 				call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9976 			} else {
9977 				unknown_num_args = 1;
9978 			}
9979 #endif
9980 		} else if (trace->op == ZEND_JIT_TRACE_ENTER) {
9981 			ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
9982 			if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
9983 				func = trace->func;
9984 				if (JIT_G(current_frame) &&
9985 				    JIT_G(current_frame)->call &&
9986 				    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9987 					call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9988 				} else {
9989 					unknown_num_args = 1;
9990 				}
9991 			}
9992 		}
9993 	}
9994 
9995 	bool may_have_extra_named_params =
9996 		opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS &&
9997 		(!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
9998 
9999 	if (!jit->reuse_ip) {
10000 		zend_jit_start_reuse_ip(jit);
10001 		// JIT: call = EX(call);
10002 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
10003 	}
10004 	rx = jit_IP(jit);
10005 	zend_jit_stop_reuse_ip(jit);
10006 
10007 	jit_SET_EX_OPLINE(jit, opline);
10008 
10009 	if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10010 		if (!func) {
10011 			if (trace) {
10012 				uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10013 
10014 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10015 				if (!exit_addr) {
10016 					return 0;
10017 				}
10018 
10019 				func_ref = ir_LOAD_A(jit_CALL(rx, func));
10020 				ir_GUARD_NOT(
10021 					ir_AND_U32(
10022 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10023 						ir_CONST_U32(ZEND_ACC_DEPRECATED)),
10024 					ir_CONST_ADDR(exit_addr));
10025 			}
10026 		}
10027 	}
10028 
10029 	if (!jit->delayed_call_level) {
10030 		// JIT: EX(call) = call->prev_execute_data;
10031 		ir_STORE(jit_EX(call),
10032 			(call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
10033 	}
10034 	delayed_call_chain = 0;
10035 	jit->delayed_call_level = 0;
10036 
10037 	// JIT: call->prev_execute_data = execute_data;
10038 	ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
10039 
10040 	if (!func) {
10041 		if (!func_ref) {
10042 			func_ref = ir_LOAD_A(jit_CALL(rx, func));
10043 		}
10044 	}
10045 
10046 	if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10047 		if (!func) {
10048 			if (!trace) {
10049 				ir_ref if_deprecated, ret;
10050 
10051 				if_deprecated = ir_IF(ir_AND_U32(
10052 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10053 						ir_CONST_U32(ZEND_ACC_DEPRECATED)));
10054 				ir_IF_TRUE_cold(if_deprecated);
10055 
10056 				if (GCC_GLOBAL_REGS) {
10057 					ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10058 				} else {
10059 					ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10060 				}
10061 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10062 				ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
10063 			}
10064 		} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10065 			ir_ref ret;
10066 
10067 			if (GCC_GLOBAL_REGS) {
10068 				ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10069 			} else {
10070 				ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10071 			}
10072 			ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10073 		}
10074 	}
10075 
10076 	if (!func
10077 	 && opline->opcode != ZEND_DO_UCALL
10078 	 && opline->opcode != ZEND_DO_ICALL) {
10079 		ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
10080 		if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
10081 		ir_IF_TRUE(if_user);
10082 	}
10083 
10084 	if ((!func || func->type == ZEND_USER_FUNCTION)
10085 	 && opline->opcode != ZEND_DO_ICALL) {
10086 		bool recursive_call_through_jmp = 0;
10087 		uint32_t num_args = 0;
10088 
10089 		// JIT: EX(call) = NULL;
10090 		ir_STORE(jit_CALL(rx, call), IR_NULL);
10091 
10092 		// JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
10093 		ir_STORE(jit_CALL(rx, return_value),
10094 			RETURN_VALUE_USED(opline) ?
10095 				jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
10096 				IR_NULL);
10097 
10098 		// JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
10099 		if (!func || func->op_array.cache_size) {
10100 			ir_ref run_time_cache;
10101 
10102 			if (func && op_array == &func->op_array) {
10103 				/* recursive call */
10104 				run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
10105 			} else if (func
10106 			 && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
10107 			 && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
10108 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
10109 					(uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
10110 			} else if ((func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) ||
10111 					(JIT_G(current_frame) &&
10112 					 JIT_G(current_frame)->call &&
10113 					 TRACE_FRAME_IS_CLOSURE_CALL(JIT_G(current_frame)->call))) {
10114 				/* Closures always use direct pointers */
10115 				ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10116 
10117 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10118 			} else {
10119 				ir_ref if_odd, run_time_cache2;
10120 				ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10121 
10122 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10123 				if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
10124 				ir_IF_TRUE(if_odd);
10125 
10126 				run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
10127 
10128 				ir_MERGE_WITH_EMPTY_FALSE(if_odd);
10129 				run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
10130 			}
10131 
10132 			ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
10133 		}
10134 
10135 		// JIT: EG(current_execute_data) = execute_data = call;
10136 		ir_STORE(jit_EG(current_execute_data), rx);
10137 		jit_STORE_FP(jit, rx);
10138 
10139 		// JIT: opline = op_array->opcodes;
10140 		if (func && !unknown_num_args) {
10141 
10142 			for (i = call_num_args; i < func->op_array.last_var; i++) {
10143 				uint32_t n = EX_NUM_TO_VAR(i);
10144 				zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
10145 
10146 				jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
10147 			}
10148 
10149 			if (call_num_args <= func->op_array.num_args) {
10150 				if (!trace || (trace->op == ZEND_JIT_TRACE_END
10151 				 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10152 					if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
10153 						if (trace) {
10154 							num_args = 0;
10155 						} else if (call_info) {
10156 							num_args = skip_valid_arguments(op_array, ssa, call_info);
10157 						} else {
10158 							num_args = call_num_args;
10159 						}
10160 					} else {
10161 						num_args = call_num_args;
10162 					}
10163 					if (zend_accel_in_shm(func->op_array.opcodes)) {
10164 						jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
10165 					} else {
10166 						if (!func_ref) {
10167 							func_ref = ir_LOAD_A(jit_CALL(rx, func));
10168 						}
10169 						ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10170 						if (num_args) {
10171 							ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
10172 						}
10173 						jit_LOAD_IP(jit, ip);
10174 					}
10175 
10176 					if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
10177 						/* recursive call */
10178 						recursive_call_through_jmp = 1;
10179 					}
10180 				}
10181 			} else {
10182 				if (!trace || (trace->op == ZEND_JIT_TRACE_END
10183 				 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10184 					ir_ref ip;
10185 
10186 					if (zend_accel_in_shm(func->op_array.opcodes)) {
10187 						ip = ir_CONST_ADDR(func->op_array.opcodes);
10188 					} else {
10189 						if (!func_ref) {
10190 							func_ref = ir_LOAD_A(jit_CALL(rx, func));
10191 						}
10192 						ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10193 					}
10194 					jit_LOAD_IP(jit, ip);
10195 				}
10196 				if (GCC_GLOBAL_REGS) {
10197 					ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10198 				} else {
10199 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
10200 				}
10201 			}
10202 		} else {
10203 			ir_ref ip;
10204 			ir_ref merge_inputs = IR_UNUSED;
10205 
10206 			// JIT: opline = op_array->opcodes
10207 			if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10208 				ip = ir_CONST_ADDR(func->op_array.opcodes);
10209 			} else {
10210 				if (!func_ref) {
10211 					func_ref = ir_LOAD_A(jit_CALL(rx, func));
10212 				}
10213 				ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10214 			}
10215 			jit_LOAD_IP(jit, ip);
10216 
10217 			// JIT: num_args = EX_NUM_ARGS();
10218 			ir_ref num_args, first_extra_arg;
10219 
10220 			num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
10221 			if (func) {
10222 				first_extra_arg = ir_CONST_U32(func->op_array.num_args);
10223 			} else {
10224 				// JIT: first_extra_arg = op_array->num_args;
10225 				ZEND_ASSERT(func_ref);
10226 				first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
10227 			}
10228 
10229 			// JIT: if (UNEXPECTED(num_args > first_extra_arg))
10230 			ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
10231 			ir_IF_TRUE_cold(if_extra_args);
10232 			if (GCC_GLOBAL_REGS) {
10233 				ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10234 			} else {
10235 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
10236 			}
10237 			ir_END_list(merge_inputs);
10238 			ir_IF_FALSE(if_extra_args);
10239 			if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10240 				if (!func) {
10241 					// JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10242 					ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
10243 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10244 						ir_CONST_U32(ZEND_ACC_HAS_TYPE_HINTS)));
10245 					ir_IF_TRUE(if_has_type_hints);
10246 					ir_END_list(merge_inputs);
10247 					ir_IF_FALSE(if_has_type_hints);
10248 				}
10249 				// JIT: opline += num_args;
10250 
10251 				ir_ref ref = ir_MUL_U32(num_args, ir_CONST_U32(sizeof(zend_op)));
10252 
10253 				if (sizeof(void*) == 8) {
10254 					ref = ir_ZEXT_A(ref);
10255 				}
10256 
10257 				if (GCC_GLOBAL_REGS) {
10258 					jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10259 				} else {
10260 					ir_ref addr = jit_EX(opline);
10261 
10262 					ir_STORE(addr, ir_ADD_A(ir_LOAD_A(addr), ref));
10263 				}
10264 			}
10265 
10266 			ir_END_list(merge_inputs);
10267 			ir_MERGE_list(merge_inputs);
10268 
10269 			// JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10270 			ir_ref last_var;
10271 
10272 			if (func) {
10273 				last_var = ir_CONST_U32(func->op_array.last_var);
10274 			} else {
10275 				ZEND_ASSERT(func_ref);
10276 				last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10277 			}
10278 
10279 			ir_ref idx = ir_SUB_U32(last_var, num_args);
10280 			ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10281 			ir_IF_TRUE(if_need);
10282 
10283 			// JIT: zval *var = EX_VAR_NUM(num_args);
10284 			if (sizeof(void*) == 8) {
10285 				num_args = ir_ZEXT_A(num_args);
10286 			}
10287 			ir_ref var_ref = ir_ADD_OFFSET(
10288 				ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10289 				(ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10290 
10291 			ir_ref loop = ir_LOOP_BEGIN(ir_END());
10292 			var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10293 			idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10294 			ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10295 			ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10296 			ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10297 			ir_PHI_SET_OP(idx, 2, idx2);
10298 			ir_ref if_not_zero = ir_IF(idx2);
10299 			ir_IF_TRUE(if_not_zero);
10300 			ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10301 			ir_IF_FALSE(if_not_zero);
10302 			ir_MERGE_WITH_EMPTY_FALSE(if_need);
10303 		}
10304 
10305 		if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10306 			ir_ref observer_handler;
10307 			ir_ref rx = jit_FP(jit);
10308 			struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10309 			if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10310 				ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10311 				jit_SET_EX_OPLINE(jit, trace[1].opline);
10312 			} else if (GCC_GLOBAL_REGS) {
10313 				// EX(opline) = opline
10314 				ir_STORE(jit_EX(opline), jit_IP(jit));
10315 			}
10316 			jit_observer_fcall_begin(jit, rx, observer_handler);
10317 
10318 			if (trace) {
10319 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10320 
10321 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10322 				if (!exit_addr) {
10323 					return 0;
10324 				}
10325 			} else {
10326 				exit_addr = NULL;
10327 			}
10328 
10329 			zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr);
10330 
10331 			jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10332 		}
10333 
10334 		if (trace) {
10335 			if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10336 				user_path = ir_END();
10337 			}
10338 		} else {
10339 			zend_basic_block *bb;
10340 
10341 			do {
10342 				if (recursive_call_through_jmp) {
10343 					ir_ref begin, end;
10344 					ir_insn *insn;
10345 
10346 					/* attempt to convert direct recursive call into loop */
10347 					begin = jit->bb_start_ref[num_args];
10348 					ZEND_ASSERT(begin != IR_UNUSED);
10349 					insn = &jit->ctx.ir_base[begin];
10350 					if (insn->op == IR_BEGIN) {
10351 						end = ir_LOOP_END();
10352 						insn = &jit->ctx.ir_base[begin];
10353 						insn->op = IR_LOOP_BEGIN;
10354 						insn->inputs_count = 2;
10355 						insn->op2 = end;
10356 						break;
10357 					} else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10358 							&& insn->inputs_count == 2) {
10359 						end = ir_LOOP_END();
10360 						insn = &jit->ctx.ir_base[begin];
10361 						insn->op = IR_LOOP_BEGIN;
10362 						insn->inputs_count = 3;
10363 						insn->op3 = end;
10364 						break;
10365 					} else if (insn->op == IR_LOOP_BEGIN && insn->inputs_count == 3) {
10366 						ZEND_ASSERT(jit->ctx.ir_base[insn->op3].op == IR_LOOP_END);
10367 						jit->ctx.ir_base[insn->op3].op = IR_END;
10368 						ir_MERGE_2(insn->op3, ir_END());
10369 						end = ir_LOOP_END();
10370 						insn = &jit->ctx.ir_base[begin];
10371 						insn->op3 = end;
10372 						break;
10373 					}
10374 				}
10375 				/* fallback to indirect JMP or RETURN */
10376 				if (GCC_GLOBAL_REGS) {
10377 					ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10378 				} else {
10379 					ir_RETURN(ir_CONST_I32(1));
10380 				}
10381 			} while (0);
10382 
10383 			bb = &jit->ssa->cfg.blocks[jit->b];
10384 			if (bb->successors_count > 0) {
10385 				int succ;
10386 				ir_ref ref;
10387 
10388 				ZEND_ASSERT(bb->successors_count == 1);
10389 				succ = bb->successors[0];
10390 				/* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10391 				ref = jit->ctx.insns_count - 1;
10392 				ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10393 					|| jit->ctx.ir_base[ref].op == IR_RETURN
10394 					|| jit->ctx.ir_base[ref].op == IR_LOOP_END);
10395 				ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
10396 				ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10397 				if (func || (opline->opcode == ZEND_DO_UCALL)) {
10398 					_zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10399 					jit->b = -1;
10400 				} else {
10401 					user_path = ref;
10402 				}
10403 			}
10404 		}
10405 	}
10406 
10407 	if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10408 	 && (opline->opcode != ZEND_DO_UCALL)) {
10409 		if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10410 			ir_IF_FALSE(if_user);
10411 		}
10412 
10413 		// JIT: EG(current_execute_data) = execute_data;
10414 		ir_STORE(jit_EG(current_execute_data), rx);
10415 
10416 		bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10417 		if (may_have_observer) {
10418 			ir_ref observer_handler;
10419 			struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
10420 			jit_observer_fcall_begin(jit, rx, observer_handler);
10421 			jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10422 		}
10423 
10424 		// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10425 		ir_ref res_addr = IR_UNUSED, func_ptr;
10426 
10427 		if (RETURN_VALUE_USED(opline)) {
10428 			res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10429 		} else {
10430 			/* CPU stack allocated temporary zval */
10431 			ir_ref ptr;
10432 
10433 			if (!jit->ctx.fixed_call_stack_size) {
10434 				// JIT: alloca(sizeof(void*));
10435 				ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10436 			} else {
10437 				ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10438 			}
10439 			res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10440 		}
10441 
10442 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10443 
10444 		zend_jit_reset_last_valid_opline(jit);
10445 
10446 		// JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10447 		ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10448 		if (zend_execute_internal) {
10449 			ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
10450 		} else {
10451 			if (func) {
10452 				func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10453 			} else {
10454 				func_ptr = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler)));
10455 #if defined(IR_TARGET_X86)
10456 				func_ptr = ir_CAST_FC_FUNC(func_ptr);
10457 #endif
10458 			}
10459 			ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10460 		}
10461 
10462 		if (may_have_observer) {
10463 			jit_observer_fcall_end(jit, rx, res_ref);
10464 		}
10465 
10466 		/* When zend_interrupt_function is set, it gets called while
10467 		 * the frame is still on top. This is less efficient than
10468 		 * doing it later once it's popped off. There is code further
10469 		 * down that handles when there isn't an interrupt function.
10470 		 */
10471 		if (zend_interrupt_function) {
10472 			// JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
10473 			ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
10474 			ir_IF_TRUE_cold(if_interrupt);
10475 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), rx);
10476 			ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
10477 		}
10478 
10479 		// JIT: EG(current_execute_data) = execute_data;
10480 		ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10481 
10482 		// JIT: zend_vm_stack_free_args(call);
10483 		if (func && !unknown_num_args) {
10484 			for (i = 0; i < call_num_args; i++ ) {
10485 				if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10486 					uint32_t offset = EX_NUM_TO_VAR(i);
10487 					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
10488 
10489 					jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, opline);
10490 				}
10491 			}
10492 		} else {
10493 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10494 		}
10495 
10496 		if (may_have_extra_named_params) {
10497 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10498 			ir_ref if_has_named = ir_IF(ir_AND_U8(
10499 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10500 				ir_CONST_U8(ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)));
10501 			ir_IF_TRUE_cold(if_has_named);
10502 
10503 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_extra_named_params),
10504 				ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10505 
10506 			ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10507 		}
10508 
10509 		if (opline->opcode == ZEND_DO_FCALL) {
10510 			// TODO: optimize ???
10511 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10512 			ir_ref if_release_this = ir_IF(ir_AND_U8(
10513 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10514 				ir_CONST_U8(ZEND_CALL_RELEASE_THIS >> 16)));
10515 			ir_IF_TRUE_cold(if_release_this);
10516 
10517 			// JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10518 			jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10519 
10520 			ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10521 		}
10522 
10523 
10524 		ir_ref allocated_path = IR_UNUSED;
10525 
10526 		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10527 		    !JIT_G(current_frame) ||
10528 		    !JIT_G(current_frame)->call ||
10529 		    !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10530 		    prev_opline->opcode == ZEND_SEND_UNPACK ||
10531 		    prev_opline->opcode == ZEND_SEND_ARRAY ||
10532 			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10533 
10534 			// JIT: zend_vm_stack_free_call_frame(call);
10535 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10536 			ir_ref if_allocated = ir_IF(ir_AND_U8(
10537 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10538 				ir_CONST_U8(ZEND_CALL_ALLOCATED >> 16)));
10539 			ir_IF_TRUE_cold(if_allocated);
10540 
10541 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10542 
10543 			allocated_path = ir_END();
10544 			ir_IF_FALSE(if_allocated);
10545 		}
10546 
10547 		ir_STORE(jit_EG(vm_stack_top), rx);
10548 
10549 		if (allocated_path) {
10550 			ir_MERGE_WITH(allocated_path);
10551 		}
10552 
10553 		if (!RETURN_VALUE_USED(opline)) {
10554 			zend_class_entry *ce;
10555 			bool ce_is_instanceof;
10556 			uint32_t func_info = call_info ?
10557 				zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10558 				(MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10559 
10560 			/* If an exception is thrown, the return_value may stay at the
10561 			 * original value of null. */
10562 			func_info |= MAY_BE_NULL;
10563 
10564 			if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10565 				ir_ref sp = ir_RLOAD_A(IR_REG_SP);
10566 				res_addr = ZEND_ADDR_REF_ZVAL(sp);
10567 				jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
10568 			}
10569 			if (!jit->ctx.fixed_call_stack_size) {
10570 				// JIT: revert alloca
10571 				ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10572 			}
10573 		}
10574 
10575 		// JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10576 		ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10577 			jit_STUB_ADDR(jit, jit_stub_icall_throw));
10578 
10579 		/* If there isn't a zend_interrupt_function, the timeout is
10580 		 * handled here because it's more efficient.
10581 		 */
10582 		if (!zend_interrupt_function) {
10583 			// TODO: Can we avoid checking for interrupts after each call ???
10584 			if (trace && jit->last_valid_opline != opline) {
10585 				int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10586 
10587 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10588 				if (!exit_addr) {
10589 					return 0;
10590 				}
10591 			} else {
10592 				exit_addr = NULL;
10593 			}
10594 
10595 			zend_jit_check_timeout(jit, opline + 1, exit_addr);
10596 		}
10597 
10598 		if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10599 			jit_LOAD_IP_ADDR(jit, opline + 1);
10600 		} else if (trace
10601 		 && trace->op == ZEND_JIT_TRACE_END
10602 		 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
10603 			jit_LOAD_IP_ADDR(jit, opline + 1);
10604 		}
10605 	}
10606 
10607 	if (user_path) {
10608 		ir_MERGE_WITH(user_path);
10609 	}
10610 
10611 	return 1;
10612 }
10613 
10614 static int zend_jit_constructor(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, int next_block)
10615 {
10616 	ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10617 
10618 	ir_IF_FALSE(if_skip_constructor);
10619 
10620 	if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10621 		if (!zend_jit_tail_handler(jit, opline)) {
10622 			return 0;
10623 		}
10624 	} else {
10625 		if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10626 			return 0;
10627 		}
10628 	}
10629 
10630 	/* override predecessors of the next block */
10631 	ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10632 	if (!jit->ctx.control) {
10633 		ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10634 		ir_IF_TRUE(if_skip_constructor);
10635 		ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10636 		jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10637 	} else {
10638 		ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10639 		/* merge current control path with the true branch of constructor skip condition */
10640 		ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10641 		jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10642 
10643 		jit->b = -1;
10644 	}
10645 
10646 	return 1;
10647 }
10648 
10649 static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
10650 {
10651 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10652 	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10653 	ir_ref ref, fast_path = IR_UNUSED;
10654 
10655 	ref = jit_ZVAL_ADDR(jit, res_addr);
10656 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10657 	 && JIT_G(current_frame)
10658 	 && JIT_G(current_frame)->prev) {
10659 		zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10660 		uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10661 
10662 		if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10663 			return 1;
10664 		}
10665 	}
10666 
10667 	if (ZEND_ARG_SEND_MODE(arg_info)) {
10668 		if (opline->opcode == ZEND_RECV_INIT) {
10669 			ref = jit_ZVAL_DEREF_ref(jit, ref);
10670 		} else {
10671 			ref = jit_Z_PTR_ref(jit, ref);
10672 			ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
10673 		}
10674 	}
10675 
10676 	if (type_mask != 0) {
10677 		if (is_power_of_two(type_mask)) {
10678 			uint32_t type_code = concrete_type(type_mask);
10679 			ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10680 			ir_IF_TRUE(if_ok);
10681 			fast_path = ir_END();
10682 			ir_IF_FALSE_cold(if_ok);
10683 		} else {
10684 			ir_ref if_ok = ir_IF(ir_AND_U32(
10685 				ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10686 				ir_CONST_U32(type_mask)));
10687 			ir_IF_TRUE(if_ok);
10688 			fast_path = ir_END();
10689 			ir_IF_FALSE_cold(if_ok);
10690 		}
10691 	}
10692 
10693 	jit_SET_EX_OPLINE(jit, opline);
10694 	ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10695 		ref, ir_CONST_ADDR(arg_info));
10696 
10697 	if (check_exception) {
10698 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10699 	}
10700 
10701 	if (fast_path) {
10702 		ir_MERGE_WITH(fast_path);
10703 	}
10704 
10705 	return 1;
10706 }
10707 
10708 static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
10709 {
10710 	uint32_t arg_num = opline->op1.num;
10711 	zend_arg_info *arg_info = NULL;
10712 
10713 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10714 		if (EXPECTED(arg_num <= op_array->num_args)) {
10715 			arg_info = &op_array->arg_info[arg_num-1];
10716 		} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10717 			arg_info = &op_array->arg_info[op_array->num_args];
10718 		}
10719 		if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10720 			arg_info = NULL;
10721 		}
10722 	}
10723 
10724 	if (arg_info || (opline+1)->opcode != ZEND_RECV) {
10725 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10726 			if (!JIT_G(current_frame) ||
10727 			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
10728 			    arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10729 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10730 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10731 
10732 				if (!exit_addr) {
10733 					return 0;
10734 				}
10735 				ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
10736 					ir_CONST_ADDR(exit_addr));
10737 			}
10738 		} else {
10739 			ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10740 			ir_IF_FALSE_cold(if_ok);
10741 
10742 			jit_SET_EX_OPLINE(jit, opline);
10743 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_missing_arg_error), jit_FP(jit));
10744 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10745 			ir_IF_TRUE(if_ok);
10746 		}
10747 	}
10748 
10749 	if (arg_info) {
10750 		if (!zend_jit_verify_arg_type(jit, opline, arg_info, 1)) {
10751 			return 0;
10752 		}
10753 	}
10754 
10755 	return 1;
10756 }
10757 
10758 static int zend_jit_recv_init(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool is_last, int may_throw)
10759 {
10760 	uint32_t arg_num = opline->op1.num;
10761 	zval *zv = RT_CONSTANT(opline, opline->op2);
10762 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10763 	ir_ref ref, if_fail, skip_path = IR_UNUSED;
10764 
10765 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10766 	 && JIT_G(current_frame)
10767 	 && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
10768 		if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10769 			jit_ZVAL_COPY_CONST(jit,
10770 				res_addr,
10771 				-1, -1,
10772 				zv, 1);
10773 		}
10774 	} else {
10775 		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10776 		    (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
10777 			ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10778 			ir_IF_TRUE(if_skip);
10779 			skip_path = ir_END();
10780 			ir_IF_FALSE(if_skip);
10781 		}
10782 		jit_ZVAL_COPY_CONST(jit,
10783 			res_addr,
10784 			-1, -1,
10785 			zv, 1);
10786 	}
10787 
10788 	if (Z_CONSTANT_P(zv)) {
10789 		jit_SET_EX_OPLINE(jit, opline);
10790 		ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zval_update_constant_ex),
10791 			jit_ZVAL_ADDR(jit, res_addr),
10792 			ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), offsetof(zend_op_array, scope))));
10793 
10794 		if_fail = ir_IF(ref);
10795 		ir_IF_TRUE_cold(if_fail);
10796 		jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, opline);
10797 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10798 		ir_IF_FALSE(if_fail);
10799 	}
10800 
10801 	if (skip_path) {
10802 		ir_MERGE_WITH(skip_path);
10803 	}
10804 
10805 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10806 		do {
10807 			zend_arg_info *arg_info;
10808 
10809 			if (arg_num <= op_array->num_args) {
10810 				arg_info = &op_array->arg_info[arg_num-1];
10811 			} else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
10812 				arg_info = &op_array->arg_info[op_array->num_args];
10813 			} else {
10814 				break;
10815 			}
10816 			if (!ZEND_TYPE_IS_SET(arg_info->type)) {
10817 				break;
10818 			}
10819 			if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw)) {
10820 				return 0;
10821 			}
10822 		} while (0);
10823 	}
10824 
10825 	return 1;
10826 }
10827 
10828 static bool zend_jit_verify_return_type(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
10829 {
10830 	zend_arg_info *arg_info = &op_array->arg_info[-1];
10831 	ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
10832 	zend_jit_addr op1_addr = OP1_ADDR();
10833 	bool needs_slow_check = 1;
10834 	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10835 	ir_ref fast_path = IR_UNUSED;
10836 
10837 	if (type_mask != 0) {
10838 		if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
10839 			/* pass */
10840 		} else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
10841 			needs_slow_check = 0;
10842 		} else if (is_power_of_two(type_mask)) {
10843 			uint32_t type_code = concrete_type(type_mask);
10844 			ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
10845 
10846 			ir_IF_TRUE(if_ok);
10847 			fast_path = ir_END();
10848 			ir_IF_FALSE_cold(if_ok);
10849 		} else {
10850 			ir_ref if_ok = ir_IF(ir_AND_U32(
10851 				ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
10852 				ir_CONST_U32(type_mask)));
10853 
10854 			ir_IF_TRUE(if_ok);
10855 			fast_path = ir_END();
10856 			ir_IF_FALSE_cold(if_ok);
10857 		}
10858 	}
10859 	if (needs_slow_check) {
10860 		ir_ref ref;
10861 
10862 		jit_SET_EX_OPLINE(jit, opline);
10863 		ref = jit_ZVAL_ADDR(jit, op1_addr);
10864 		if (op1_info & MAY_BE_UNDEF) {
10865 			ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1);
10866 		}
10867 
10868 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
10869 			ref,
10870 			ir_LOAD_A(jit_EX(func)),
10871 			ir_CONST_ADDR(arg_info),
10872 			ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num));
10873 
10874 		zend_jit_check_exception(jit);
10875 
10876 		if (fast_path) {
10877 			ir_MERGE_WITH(fast_path);
10878 		}
10879 	}
10880 
10881 	return 1;
10882 }
10883 
10884 static int zend_jit_leave_frame(zend_jit_ctx *jit)
10885 {
10886 	// JIT: EG(current_execute_data) = EX(prev_execute_data);
10887 	ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10888 	return 1;
10889 }
10890 
10891 static int zend_jit_free_cvs(zend_jit_ctx *jit)
10892 {
10893 	// JIT: EG(current_execute_data) = EX(prev_execute_data);
10894 	ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10895 
10896 	// JIT: zend_free_compiled_variables(execute_data);
10897 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_compiled_variables), jit_FP(jit));
10898 	return 1;
10899 }
10900 
10901 static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
10902 {
10903 	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10904 		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
10905 
10906 		jit_ZVAL_PTR_DTOR(jit, var_addr, info, 1, NULL);
10907 	}
10908 	return 1;
10909 }
10910 
10911 static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
10912 {
10913 	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10914 		jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, opline);
10915 	}
10916 	return 1;
10917 }
10918 
10919 static int zend_jit_leave_func(zend_jit_ctx         *jit,
10920                                const zend_op_array  *op_array,
10921                                const zend_op        *opline,
10922                                uint32_t              op1_info,
10923                                bool             left_frame,
10924                                zend_jit_trace_rec   *trace,
10925                                zend_jit_trace_info  *trace_info,
10926                                int                   indirect_var_access,
10927                                int                   may_throw)
10928 {
10929 	bool may_be_top_frame =
10930 		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10931 		!JIT_G(current_frame) ||
10932 		!TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
10933 	bool may_need_call_helper =
10934 		indirect_var_access || /* may have symbol table */
10935 		!op_array->function_name || /* may have symbol table */
10936 		may_be_top_frame ||
10937 		(op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
10938 		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10939 		!JIT_G(current_frame) ||
10940 		TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
10941 		(uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
10942 	bool may_need_release_this =
10943 		!(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
10944 		op_array->scope &&
10945 		!(op_array->fn_flags & ZEND_ACC_STATIC) &&
10946 		(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10947 		 !JIT_G(current_frame) ||
10948 		 !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
10949 	ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
10950 
10951 	if (may_need_call_helper) {
10952 		if (!left_frame) {
10953 			left_frame = 1;
10954 		    if (!zend_jit_leave_frame(jit)) {
10955 				return 0;
10956 		    }
10957 		}
10958 		/* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
10959 		call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10960 		ref = ir_AND_U32(call_info,
10961 			ir_CONST_U32(ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE));
10962 		if (trace && trace->op != ZEND_JIT_TRACE_END) {
10963 			ir_ref if_slow = ir_IF(ref);
10964 
10965 			ir_IF_TRUE_cold(if_slow);
10966 			if (!GCC_GLOBAL_REGS) {
10967 				ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit));
10968 			} else {
10969 				ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper));
10970 			}
10971 
10972 			if (may_be_top_frame) {
10973 				// TODO: try to avoid this check ???
10974 				if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
10975 #if 0
10976 					/* this check should be handled by the following OPLINE guard */
10977 					|	cmp IP, zend_jit_halt_op
10978 					|	je ->trace_halt
10979 #endif
10980 				} else if (GCC_GLOBAL_REGS) {
10981 					ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10982 				} else {
10983 					ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10984 				}
10985 			}
10986 
10987 			if (!GCC_GLOBAL_REGS) {
10988 				// execute_data = EG(current_execute_data)
10989 				jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
10990 			}
10991 			cold_path = ir_END();
10992 			ir_IF_FALSE(if_slow);
10993 		} else {
10994 			ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
10995 		}
10996 	}
10997 
10998 	if ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
10999 		if (!left_frame) {
11000 			left_frame = 1;
11001 		    if (!zend_jit_leave_frame(jit)) {
11002 				return 0;
11003 		    }
11004 		}
11005 		// JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
11006 		jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
11007 	} else if (may_need_release_this) {
11008 		ir_ref if_release, fast_path = IR_UNUSED;
11009 
11010 		if (!left_frame) {
11011 			left_frame = 1;
11012 		    if (!zend_jit_leave_frame(jit)) {
11013 				return 0;
11014 		    }
11015 		}
11016 		if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
11017 			// JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
11018 			if (!call_info) {
11019 				call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11020 			}
11021 			if_release = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_RELEASE_THIS)));
11022 			ir_IF_FALSE(if_release);
11023 			fast_path = ir_END();
11024 			ir_IF_TRUE(if_release);
11025 		}
11026 		// JIT: OBJ_RELEASE(execute_data->This))
11027 		jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
11028 		if (fast_path) {
11029 			ir_MERGE_WITH(fast_path);
11030 		}
11031 		// TODO: avoid EG(excption) check for $this->foo() calls
11032 		may_throw = 1;
11033 	}
11034 
11035 	// JIT: EG(vm_stack_top) = (zval*)execute_data
11036 	ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
11037 
11038 	// JITL execute_data = EX(prev_execute_data)
11039 	jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
11040 
11041 	if (!left_frame) {
11042 		// JIT: EG(current_execute_data) = execute_data
11043 		ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
11044 	}
11045 
11046 	if (trace) {
11047 		if (trace->op != ZEND_JIT_TRACE_END
11048 		 && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11049 			zend_jit_reset_last_valid_opline(jit);
11050 		} else {
11051 			if (GCC_GLOBAL_REGS) {
11052 				/* We add extra RLOAD and RSTORE to make fusion for persistent register
11053 				 *     mov (%FP), %IP
11054 				 *     add $0x1c, %IP
11055 				 * The naive (commented) code leads to extra register allocation and move.
11056 				 *     mov (%FP), %tmp
11057 				 *     add $0x1c, %tmp
11058 				 *     mov %tmp, %FP
11059 				 */
11060 #if 0
11061 				jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
11062 #else
11063 				jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11064 				jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11065 #endif
11066 			} else {
11067 				ir_ref ref = jit_EX(opline);
11068 
11069 				ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
11070 			}
11071 		}
11072 
11073 		if (cold_path) {
11074 			ir_MERGE_WITH(cold_path);
11075 		}
11076 
11077 		if (trace->op == ZEND_JIT_TRACE_BACK
11078 		 && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11079 			const zend_op *next_opline = trace->opline;
11080 
11081 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11082 			 && (op1_info & MAY_BE_RC1)
11083 			 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
11084 				/* exception might be thrown during destruction of unused return value */
11085 				// JIT: if (EG(exception))
11086 				ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11087 			}
11088 			do {
11089 				trace++;
11090 			} while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
11091 			ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11092 			next_opline = trace->opline;
11093 			ZEND_ASSERT(next_opline != NULL);
11094 
11095 			if (trace->op == ZEND_JIT_TRACE_END
11096 			 && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
11097 				trace_info->flags |= ZEND_JIT_TRACE_LOOP;
11098 
11099 				ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
11100 
11101 				ir_IF_TRUE(if_eq);
11102 				ZEND_ASSERT(jit->trace_loop_ref);
11103 				ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
11104 				ir_MERGE_SET_OP(jit->trace_loop_ref, 2, ir_END());
11105 				ir_IF_FALSE(if_eq);
11106 
11107 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
11108 				ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11109 #else
11110 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
11111 #endif
11112 			} else {
11113 				ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
11114 			}
11115 
11116 			zend_jit_set_last_valid_opline(jit, trace->opline);
11117 
11118 			return 1;
11119 		} else if (may_throw ||
11120 				(((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11121 				  && (op1_info & MAY_BE_RC1)
11122 				  && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
11123 				 && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
11124 			// JIT: if (EG(exception))
11125 			ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11126 		}
11127 
11128 		return 1;
11129 	} else {
11130 		// JIT: if (EG(exception))
11131 		ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11132 		// JIT: opline = EX(opline) + 1
11133 		if (GCC_GLOBAL_REGS) {
11134 			jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11135 			jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11136 		} else {
11137 			ir_ref ref = jit_EX(opline);
11138 
11139 			ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
11140 		}
11141 	}
11142 
11143 	if (GCC_GLOBAL_REGS) {
11144 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11145 	} else {
11146 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
11147 	}
11148 
11149 	jit->b = -1;
11150 
11151 	return 1;
11152 }
11153 
11154 static void zend_jit_common_return(zend_jit_ctx *jit)
11155 {
11156 	ZEND_ASSERT(jit->return_inputs);
11157 	ir_MERGE_list(jit->return_inputs);
11158 }
11159 
11160 static int zend_jit_return(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr)
11161 {
11162 	zend_jit_addr ret_addr;
11163 	int8_t return_value_used = -1;
11164 	ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
11165 
11166 	ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
11167 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
11168 
11169 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11170 		jit->return_inputs = IR_UNUSED;
11171 		if (JIT_G(current_frame)) {
11172 			if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
11173 				return_value_used = 1;
11174 			} else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
11175 				return_value_used = 0;
11176 			} else {
11177 				return_value_used = -1;
11178 			}
11179 		}
11180 	}
11181 
11182 	if (ZEND_OBSERVER_ENABLED) {
11183 		if (Z_MODE(op1_addr) == IS_REG) {
11184 			zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
11185 
11186 			if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
11187 				return 0;
11188 			}
11189 			op1_addr = dst;
11190 		}
11191 		jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
11192 	}
11193 
11194 	// JIT: if (!EX(return_value))
11195 	return_value = ir_LOAD_A(jit_EX(return_value));
11196 	ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
11197 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11198 	    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11199 		if (return_value_used == -1) {
11200 			if_return_value_used = ir_IF(return_value);
11201 			ir_IF_FALSE_cold(if_return_value_used);
11202 		}
11203 		if (return_value_used != 1) {
11204 			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11205 				ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11206 				ir_IF_FALSE(if_refcounted);
11207 				ir_END_list(jit->return_inputs);
11208 				ir_IF_TRUE(if_refcounted);
11209 			}
11210 			ref = jit_Z_PTR(jit, op1_addr);
11211 			refcount = jit_GC_DELREF(jit, ref);
11212 
11213 			if (RC_MAY_BE_1(op1_info)) {
11214 				if (RC_MAY_BE_N(op1_info)) {
11215 					ir_ref if_non_zero = ir_IF(refcount);
11216 					ir_IF_TRUE(if_non_zero);
11217 					ir_END_list(jit->return_inputs);
11218 					ir_IF_FALSE(if_non_zero);
11219 				}
11220 				jit_ZVAL_DTOR(jit, ref, op1_info, opline);
11221 			}
11222 			if (return_value_used == -1) {
11223 				ir_END_list(jit->return_inputs);
11224 			}
11225 		}
11226 	} else if (return_value_used == -1) {
11227 		if_return_value_used = ir_IF(return_value);
11228 		ir_IF_FALSE_cold(if_return_value_used);
11229 		ir_END_list(jit->return_inputs);
11230 	}
11231 
11232 	if (if_return_value_used) {
11233 		ir_IF_TRUE(if_return_value_used);
11234 	}
11235 
11236 	if (return_value_used == 0) {
11237 		if (jit->return_inputs) {
11238 			ZEND_ASSERT(JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE);
11239 			ir_END_list(jit->return_inputs);
11240 			ir_MERGE_list(jit->return_inputs);
11241 			jit->return_inputs = IR_UNUSED;
11242 		}
11243 		return 1;
11244 	}
11245 
11246 	if (opline->op1_type == IS_CONST) {
11247 		zval *zv = RT_CONSTANT(opline, opline->op1);
11248 
11249 		jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
11250 	} else if (opline->op1_type == IS_TMP_VAR) {
11251 		jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11252 	} else if (opline->op1_type == IS_CV) {
11253 		if (op1_info & MAY_BE_REF) {
11254 			ref = jit_ZVAL_ADDR(jit, op1_addr);
11255 			ref = jit_ZVAL_DEREF_ref(jit, ref);
11256 			op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11257 		}
11258 
11259 		if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11260 			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11261 			    (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11262 			    !op_array->function_name) {
11263 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 1);
11264 			} else if (return_value_used != 1) {
11265 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11266 				// JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11267 				jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11268 			} else {
11269 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11270 			}
11271 		} else {
11272 			jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11273 		}
11274 	} else {
11275 		if (op1_info & MAY_BE_REF) {
11276 			ir_ref if_ref, ref2, if_non_zero;
11277 			zend_jit_addr ref_addr;
11278 
11279 			if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11280 			ir_IF_TRUE_cold(if_ref);
11281 
11282 			// JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11283 			ref = jit_Z_PTR(jit, op1_addr);
11284 
11285 			// JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11286 			ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
11287 			ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11288 			jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, 0);
11289 			ref2 = jit_GC_DELREF(jit, ref);
11290 			if_non_zero = ir_IF(ref2);
11291 			ir_IF_TRUE(if_non_zero);
11292 
11293 			// JIT: if (IS_REFCOUNTED())
11294 			ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11295 			ir_IF_FALSE(if_refcounted);
11296 			ir_END_list(jit->return_inputs);
11297 			ir_IF_TRUE(if_refcounted);
11298 
11299 			// JIT: ADDREF
11300 			ref2 = jit_Z_PTR(jit, ret_addr);
11301 			jit_GC_ADDREF(jit, ref2);
11302 			ir_END_list(jit->return_inputs);
11303 
11304 			ir_IF_FALSE(if_non_zero);
11305 
11306 			jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11307 			ir_END_list(jit->return_inputs);
11308 
11309 			ir_IF_FALSE(if_ref);
11310 		}
11311 		jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11312 	}
11313 
11314 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11315 		if (jit->return_inputs) {
11316 			ir_END_list(jit->return_inputs);
11317 			ir_MERGE_list(jit->return_inputs);
11318 			jit->return_inputs = IR_UNUSED;
11319 		}
11320 	} else {
11321 		ir_END_list(jit->return_inputs);
11322 		jit->b = -1;
11323 	}
11324 
11325 	return 1;
11326 }
11327 
11328 static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11329 {
11330 	zend_jit_addr op1_addr = OP1_ADDR();
11331 	zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11332 	ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11333 	ir_ref if_fit, if_reference, if_same_key, fast_path;
11334 	ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11335 
11336 	// JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11337 	cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11338 	idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11339 
11340 	// JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11341 	num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11342 		ir_CONST_U32(sizeof(Bucket)));
11343 	if (sizeof(void*) == 8) {
11344 		num_used_ref = ir_ZEXT_A(num_used_ref);
11345 	}
11346 	if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11347 	ir_IF_FALSE_cold(if_fit);
11348 	ir_END_list(slow_inputs);
11349 	ir_IF_TRUE(if_fit);
11350 
11351 	// JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11352 	bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11353 	if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11354 	ir_IF_FALSE_cold(if_reference);
11355 	ir_END_list(slow_inputs);
11356 	ir_IF_TRUE(if_reference);
11357 
11358 	// JIT: (EXPECTED(p->key == varname))
11359 	if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11360 	ir_IF_FALSE_cold(if_same_key);
11361 	ir_END_list(slow_inputs);
11362 	ir_IF_TRUE(if_same_key);
11363 
11364 	// JIT: GC_ADDREF(Z_PTR(p->val))
11365 	ref = jit_Z_PTR_ref(jit, bucket_ref);
11366 	jit_GC_ADDREF(jit, ref);
11367 
11368 	fast_path = ir_END();
11369 	ir_MERGE_list(slow_inputs);
11370 
11371 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11372 		ir_CONST_ADDR(varname),
11373 		cache_slot_ref);
11374 
11375 	ir_MERGE_WITH(fast_path);
11376 	ref = ir_PHI_2(IR_ADDR, ref2, ref);
11377 
11378 	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11379 		ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11380 
11381 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11382 			// JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11383 			if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11384 			ir_IF_TRUE_cold(if_refcounted);
11385 		}
11386 
11387 		// JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11388 		ref2 = jit_Z_PTR(jit, op1_addr);
11389 
11390 		// JIT: ZVAL_REF(variable_ptr, ref)
11391 		jit_set_Z_PTR(jit, op1_addr, ref);
11392 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11393 
11394 		// JIT: if (GC_DELREF(garbage) == 0)
11395 		refcount = jit_GC_DELREF(jit, ref2);
11396 		if_non_zero = ir_IF(refcount);
11397 		if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11398 			ir_IF_TRUE(if_non_zero);
11399 			ir_END_list(end_inputs);
11400 		}
11401 		ir_IF_FALSE(if_non_zero);
11402 
11403 		jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11404 		if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11405 			ir_END_list(end_inputs);
11406 			ir_IF_TRUE(if_non_zero);
11407 
11408 			// JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11409 			if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11410 			ir_IF_TRUE(if_may_not_leak);
11411 			ir_END_list(end_inputs);
11412 			ir_IF_FALSE(if_may_not_leak);
11413 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref2);
11414 		}
11415 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11416 			ir_END_list(end_inputs);
11417 			ir_IF_FALSE(if_refcounted);
11418 		}
11419 	}
11420 
11421 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11422 		// JIT: ZVAL_REF(variable_ptr, ref)
11423 		jit_set_Z_PTR(jit, op1_addr, ref);
11424 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11425 	}
11426 
11427 	if (end_inputs) {
11428 		ir_END_list(end_inputs);
11429 		ir_MERGE_list(end_inputs);
11430 	}
11431 
11432 	return 1;
11433 }
11434 
11435 static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11436 {
11437 	zend_jit_addr op1_addr = OP1_ADDR();
11438 
11439 	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11440 		if (may_throw) {
11441 			jit_SET_EX_OPLINE(jit, opline);
11442 		}
11443 		if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11444 			ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11445 
11446 			if (op1_info & MAY_BE_ARRAY) {
11447 				if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11448 				ir_IF_TRUE(if_array);
11449 				ir_END_list(end_inputs);
11450 				ir_IF_FALSE(if_array);
11451 			}
11452 			ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11453 			if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11454 			ir_IF_TRUE(if_exists);
11455 			ir_END_list(end_inputs);
11456 			ir_IF_FALSE(if_exists);
11457 
11458 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_hash_iterator_del), ref);
11459 
11460 			ir_END_list(end_inputs);
11461 			ir_MERGE_list(end_inputs);
11462 		}
11463 
11464 		jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11465 
11466 		if (may_throw) {
11467 			zend_jit_check_exception(jit);
11468 		}
11469 	}
11470 
11471 	return 1;
11472 }
11473 
11474 static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11475 {
11476 	if (opline->op1_type == IS_CONST) {
11477 		zval *zv;
11478 		size_t len;
11479 
11480 		zv = RT_CONSTANT(opline, opline->op1);
11481 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11482 		len = Z_STRLEN_P(zv);
11483 
11484 		if (len > 0) {
11485 			const char *str = Z_STRVAL_P(zv);
11486 
11487 			jit_SET_EX_OPLINE(jit, opline);
11488 			ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11489 				ir_CONST_ADDR(str), ir_CONST_ADDR(len));
11490 
11491 			zend_jit_check_exception(jit);
11492 		}
11493 	} else {
11494 		zend_jit_addr op1_addr = OP1_ADDR();
11495 		ir_ref ref;
11496 
11497 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11498 
11499 		jit_SET_EX_OPLINE(jit, opline);
11500 
11501 		ref = jit_Z_PTR(jit, op1_addr);
11502 		ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11503 			ir_ADD_OFFSET(ref, offsetof(zend_string, val)),
11504 			ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_string, len))));
11505 
11506 		if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11507 			jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11508 		}
11509 
11510 		zend_jit_check_exception(jit);
11511 	}
11512 	return 1;
11513 }
11514 
11515 static int zend_jit_strlen(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr)
11516 {
11517 	if (opline->op1_type == IS_CONST) {
11518 		zval *zv;
11519 		size_t len;
11520 
11521 		zv = RT_CONSTANT(opline, opline->op1);
11522 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11523 		len = Z_STRLEN_P(zv);
11524 
11525 		jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11526 		if (Z_MODE(res_addr) != IS_REG) {
11527 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11528 		} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11529 			return 0;
11530 		}
11531 	} else {
11532 		ir_ref ref;
11533 
11534 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11535 
11536 		ref = jit_Z_PTR(jit, op1_addr);
11537 		ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(zend_string, len)));
11538 		jit_set_Z_LVAL(jit, res_addr, ref);
11539 
11540 		if (Z_MODE(res_addr) == IS_REG) {
11541 			if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11542 				return 0;
11543 			}
11544 		} else {
11545 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11546 		}
11547 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11548 	}
11549 	return 1;
11550 }
11551 
11552 static int zend_jit_count(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw)
11553 {
11554 	if (opline->op1_type == IS_CONST) {
11555 		zval *zv;
11556 		zend_long count;
11557 
11558 		zv = RT_CONSTANT(opline, opline->op1);
11559 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
11560 		count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11561 
11562 		jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11563 		if (Z_MODE(res_addr) != IS_REG) {
11564 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11565 		} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11566 			return 0;
11567 		}
11568 	} else {
11569 		ir_ref ref;
11570 
11571 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
11572 		// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11573 
11574 		ref = jit_Z_PTR(jit, op1_addr);
11575 		if (sizeof(void*) == 8) {
11576 			ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11577 			ref = ir_ZEXT_L(ref);
11578 		} else {
11579 			ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11580 		}
11581 		jit_set_Z_LVAL(jit, res_addr, ref);
11582 
11583 		if (Z_MODE(res_addr) == IS_REG) {
11584 			if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11585 				return 0;
11586 			}
11587 		} else {
11588 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11589 		}
11590 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11591 	}
11592 
11593 	if (may_throw) {
11594 		zend_jit_check_exception(jit);
11595 	}
11596 	return 1;
11597 }
11598 
11599 static int zend_jit_in_array(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
11600 {
11601 	HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11602 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11603 	ir_ref ref;
11604 
11605 	ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11606 	ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
11607 
11608 	// JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11609 	if (opline->op1_type != IS_CONST) {
11610 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find),
11611 			ir_CONST_ADDR(ht),
11612 			jit_Z_PTR(jit, op1_addr));
11613 	} else {
11614 		zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11615 
11616 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash),
11617 			ir_CONST_ADDR(ht), ir_CONST_ADDR(str));
11618 	}
11619 
11620 	if (exit_addr) {
11621 		if (smart_branch_opcode == ZEND_JMPZ) {
11622 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11623 		} else {
11624 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11625 		}
11626 	} else if (smart_branch_opcode) {
11627 		zend_basic_block *bb;
11628 
11629 		ZEND_ASSERT(jit->b >= 0);
11630 		bb = &jit->ssa->cfg.blocks[jit->b];
11631 		ZEND_ASSERT(bb->successors_count == 2);
11632 		ref = jit_IF_ex(jit, ref,
11633 			(smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11634 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11635 		_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11636 		jit->b = -1;
11637 	} else {
11638 		jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11639 			ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, IR_NULL)), ir_CONST_U32(IS_FALSE)));
11640 	}
11641 
11642 	return 1;
11643 }
11644 
11645 static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11646 {
11647 	uint32_t offset;
11648 
11649 	offset = (opline->opcode == ZEND_ROPE_INIT) ?
11650 		opline->result.var :
11651 		opline->op1.var + opline->extended_value * sizeof(zend_string*);
11652 
11653 	if (opline->op2_type == IS_CONST) {
11654 		zval *zv = RT_CONSTANT(opline, opline->op2);
11655 		zend_string *str;
11656 
11657 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11658 		str = Z_STR_P(zv);
11659 
11660 		ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11661 	} else {
11662 		zend_jit_addr op2_addr = OP2_ADDR();
11663 		ir_ref ref;
11664 
11665 		ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11666 
11667 		ref = jit_Z_PTR(jit, op2_addr);
11668 		ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11669 		if (opline->op2_type == IS_CV) {
11670 			ir_ref if_refcounted, long_path;
11671 
11672 			if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11673 			ir_IF_TRUE(if_refcounted);
11674 			jit_GC_ADDREF(jit, ref);
11675 			long_path = ir_END();
11676 
11677 			ir_IF_FALSE(if_refcounted);
11678 			ir_MERGE_WITH(long_path);
11679 		}
11680 	}
11681 
11682 	if (opline->opcode == ZEND_ROPE_END) {
11683 		zend_jit_addr res_addr = RES_ADDR();
11684 		ir_ref ref;
11685 
11686 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11687 			ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11688 			ir_CONST_U32(opline->extended_value));
11689 
11690 		jit_set_Z_PTR(jit, res_addr, ref);
11691 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11692 	}
11693 
11694 	return 1;
11695 }
11696 
11697 static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
11698 {
11699 	ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
11700 	ir_refs *merge_inputs, *types, *ptrs;
11701 #if SIZEOF_ZEND_LONG == 4
11702 	ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
11703 	ir_refs *values; /* we need this only for zval.w2 copy */
11704 #endif
11705 
11706 	ir_refs_init(merge_inputs, 4);
11707 	ir_refs_init(types, 4);
11708 	ir_refs_init(ptrs, 4);
11709 #if SIZEOF_ZEND_LONG == 4
11710 	ir_refs_init(values, 4);
11711 #endif
11712 
11713 	// JIT: ptr = Z_PTR_P(val);
11714 	ptr = jit_Z_PTR(jit, val_addr);
11715 
11716 	// JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11717 	if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11718 	ir_IF_FALSE_cold(if_refcounted);
11719 	ir_refs_add(merge_inputs, ir_END());
11720 	ir_refs_add(types, type);
11721 	ir_refs_add(ptrs, ptr);
11722 #if SIZEOF_ZEND_LONG == 4
11723 	ir_refs_add(values, val);
11724 #endif
11725 
11726 	ir_IF_TRUE(if_refcounted);
11727 
11728 	// JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
11729 	if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
11730 //	if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
11731 	ir_IF_TRUE(if_reference);
11732 
11733 	// JIT:	val = Z_REFVAL_P(val);
11734 	val2 = ir_ADD_OFFSET(ptr, offsetof(zend_reference, val));
11735 	type2 = jit_Z_TYPE_INFO_ref(jit, val2);
11736 	ptr2 = jit_Z_PTR_ref(jit, val2);
11737 
11738 	// JIT:	if (Z_OPT_REFCOUNTED_P(val)) {
11739 	if_refcounted2 = ir_IF(ir_AND_U32(type2, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11740 	ir_IF_FALSE_cold(if_refcounted2);
11741 	ir_refs_add(merge_inputs, ir_END());
11742 	ir_refs_add(types, type2);
11743 	ir_refs_add(ptrs, ptr2);
11744 #if SIZEOF_ZEND_LONG == 4
11745 	ir_refs_add(values, val2);
11746 #endif
11747 
11748 	ir_IF_TRUE(if_refcounted2);
11749 	ir_MERGE_WITH_EMPTY_FALSE(if_reference);
11750 	type = ir_PHI_2(IR_U32, type2, type);
11751 	ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
11752 #if SIZEOF_ZEND_LONG == 4
11753 	val = ir_PHI_2(IR_ADDR, val2, val);
11754 #endif
11755 
11756 	// JIT:	Z_ADDREF_P(val);
11757 	jit_GC_ADDREF(jit, ptr);
11758 	ir_refs_add(merge_inputs, ir_END());
11759 	ir_refs_add(types, type);
11760 	ir_refs_add(ptrs, ptr);
11761 #if SIZEOF_ZEND_LONG == 4
11762 	ir_refs_add(values, val);
11763 #endif
11764 
11765 	ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
11766 	type = ir_PHI_N(IR_U32, types->count, types->refs);
11767 	ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
11768 #if SIZEOF_ZEND_LONG == 4
11769 	val = ir_PHI_N(IR_ADDR, values->count, values->refs);
11770 	val_addr = ZEND_ADDR_REF_ZVAL(val);
11771 #endif
11772 
11773 	// JIT: Z_PTR_P(res) = ptr;
11774 	jit_set_Z_PTR(jit, res_addr, ptr);
11775 #if SIZEOF_ZEND_LONG == 4
11776 	jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
11777 #endif
11778 	jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
11779 
11780 	return 1;
11781 }
11782 
11783 static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx  *jit,
11784                                                   const zend_op *opline,
11785                                                   uint32_t       type,
11786                                                   uint32_t       op1_info,
11787                                                   uint32_t       op2_info,
11788                                                   zend_jit_addr  op2_addr,
11789                                                   zend_ssa_range *op2_range,
11790                                                   uint8_t        dim_type,
11791                                                   const void    *found_exit_addr,
11792                                                   const void    *not_found_exit_addr,
11793                                                   const void    *exit_addr,
11794                                                   bool           result_type_guard,
11795                                                   ir_ref         ht_ref,
11796                                                   ir_refs       *found_inputs,
11797                                                   ir_refs       *found_vals,
11798                                                   ir_ref        *end_inputs,
11799                                                   ir_ref        *not_found_inputs)
11800 {
11801 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11802 	ir_ref ref = IR_UNUSED, cond, if_found;
11803 	ir_ref if_type = IS_UNUSED;
11804 	ir_refs *test_zval_inputs, *test_zval_values;
11805 
11806 	ir_refs_init(test_zval_inputs, 4);
11807 	ir_refs_init(test_zval_values, 4);
11808 
11809 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11810 	 && type == BP_VAR_R
11811 	 && !exit_addr) {
11812 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11813 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11814 		if (!exit_addr) {
11815 			return 0;
11816 		}
11817 	}
11818 
11819 	if (op2_info & MAY_BE_LONG) {
11820 		bool op2_loaded = 0;
11821 		bool packed_loaded = 0;
11822 		bool bad_packed_key = 0;
11823 		ir_ref if_packed = IS_UNDEF;
11824 		ir_ref h = IR_UNUSED;
11825 		ir_ref idx_not_found_inputs = IR_UNUSED;
11826 
11827 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
11828 			// JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
11829 			if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
11830 			ir_IF_TRUE(if_type);
11831 		}
11832 		if (op1_info & MAY_BE_PACKED_GUARD) {
11833 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
11834 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11835 
11836 			if (!exit_addr) {
11837 				return 0;
11838 			}
11839 			cond = ir_AND_U32(
11840 				ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11841 				ir_CONST_U32(HASH_FLAG_PACKED));
11842 			if (op1_info & MAY_BE_ARRAY_PACKED) {
11843 				ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11844 			} else {
11845 				ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
11846 			}
11847 		}
11848 		if (type == BP_VAR_W) {
11849 			// JIT: hval = Z_LVAL_P(dim);
11850 			h = jit_Z_LVAL(jit, op2_addr);
11851 			op2_loaded = 1;
11852 		}
11853 		if (op1_info & MAY_BE_ARRAY_PACKED) {
11854 			zend_long val = -1;
11855 
11856 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
11857 				val = Z_LVAL_P(Z_ZV(op2_addr));
11858 				if (val >= 0 && val < HT_MAX_SIZE) {
11859 					packed_loaded = 1;
11860 				} else {
11861 					bad_packed_key = 1;
11862 				}
11863 				h = ir_CONST_LONG(val);
11864 			} else {
11865 				if (!op2_loaded) {
11866 					// JIT: hval = Z_LVAL_P(dim);
11867 					h = jit_Z_LVAL(jit, op2_addr);
11868 					op2_loaded = 1;
11869 				}
11870 				packed_loaded = 1;
11871 			}
11872 
11873 			if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
11874 				/* don't generate "fast" code for packed array */
11875 				packed_loaded = 0;
11876 			}
11877 
11878 			if (packed_loaded) {
11879 				// JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
11880 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11881 					if_packed = ir_IF(
11882 						ir_AND_U32(
11883 							ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11884 							ir_CONST_U32(HASH_FLAG_PACKED)));
11885 					ir_IF_TRUE(if_packed);
11886 				}
11887 				// JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
11888 				ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
11889 #if SIZEOF_ZEND_LONG == 8
11890 				if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
11891 				 || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
11892 					/* comapre only the lower 32-bits to allow load fusion on x86_64 */
11893 					cond = ir_ULT(ir_TRUNC_U32(h), ref);
11894 				} else {
11895 					cond = ir_ULT(h, ir_ZEXT_L(ref));
11896 				}
11897 #else
11898 				cond = ir_ULT(h, ref);
11899 #endif
11900 				if (type == BP_JIT_IS) {
11901 					if (not_found_exit_addr) {
11902 						ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11903 					} else {
11904 						ir_ref if_fit = ir_IF(cond);
11905 						ir_IF_FALSE(if_fit);
11906 						ir_END_list(*end_inputs);
11907 						ir_IF_TRUE(if_fit);
11908 					}
11909 				} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11910 					ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11911 				} else if (type == BP_VAR_IS && not_found_exit_addr) {
11912 					ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11913 				} else if (type == BP_VAR_RW && not_found_exit_addr) {
11914 					ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11915 				} else if (type == BP_VAR_IS && result_type_guard) {
11916 					ir_ref if_fit = ir_IF(cond);
11917 					ir_IF_FALSE(if_fit);
11918 					ir_END_list(*not_found_inputs);
11919 					ir_IF_TRUE(if_fit);
11920 				} else {
11921 					ir_ref if_fit = ir_IF(cond);
11922 					ir_IF_FALSE(if_fit);
11923 					ir_END_list(idx_not_found_inputs);
11924 					ir_IF_TRUE(if_fit);
11925 				}
11926 				// JIT: _ret = &_ht->arPacked[h];
11927 				ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
11928 				ref = ir_BITCAST_A(ref);
11929 				ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
11930 				if (type == BP_JIT_IS) {
11931 					ir_refs_add(test_zval_values, ref);
11932 					ir_refs_add(test_zval_inputs, ir_END());
11933 				}
11934 			}
11935 		}
11936 		switch (type) {
11937 			case BP_JIT_IS:
11938 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11939 					if (if_packed) {
11940 						ir_IF_FALSE(if_packed);
11941 						if_packed = IR_UNUSED;
11942 					}
11943 					if (!op2_loaded) {
11944 						// JIT: hval = Z_LVAL_P(dim);
11945 						h = jit_Z_LVAL(jit, op2_addr);
11946 						op2_loaded = 1;
11947 					}
11948 					if (packed_loaded) {
11949 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11950 					} else {
11951 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11952 					}
11953 					if (not_found_exit_addr) {
11954 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11955 					} else {
11956 						if_found = ir_IF(ref);
11957 						ir_IF_FALSE(if_found);
11958 						ir_END_list(*end_inputs);
11959 						ir_IF_TRUE(if_found);
11960 					}
11961 					ir_refs_add(test_zval_values, ref);
11962 					ir_refs_add(test_zval_inputs, ir_END());
11963 				} else if (!not_found_exit_addr && !packed_loaded) {
11964 					ir_END_list(*end_inputs);
11965 				}
11966 				break;
11967 			case BP_VAR_R:
11968 			case BP_VAR_IS:
11969 			case BP_VAR_UNSET:
11970 				if (packed_loaded) {
11971 					ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
11972 
11973 					if (result_type_guard) {
11974 						/* perform IS_UNDEF check only after result type guard (during deoptimization) */
11975 					} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11976 						ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
11977 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11978 						ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
11979 					} else {
11980 						ir_ref if_def = ir_IF(type_ref);
11981 						ir_IF_FALSE(if_def);
11982 						ir_END_list(idx_not_found_inputs);
11983 						ir_IF_TRUE(if_def);
11984 					}
11985 					ir_refs_add(found_inputs, ir_END());
11986 					ir_refs_add(found_vals, ref);
11987 				}
11988 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11989 					if (if_packed) {
11990 						ir_IF_FALSE(if_packed);
11991 						if_packed = IR_UNUSED;
11992 					}
11993 					if (!op2_loaded) {
11994 						// JIT: hval = Z_LVAL_P(dim);
11995 						h = jit_Z_LVAL(jit, op2_addr);
11996 						op2_loaded = 1;
11997 					}
11998 					if (packed_loaded) {
11999 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12000 					} else {
12001 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12002 					}
12003 					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12004 						ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12005 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
12006 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12007 					} else if (type == BP_VAR_IS && result_type_guard) {
12008 						if_found = ir_IF(ref);
12009 						ir_IF_FALSE(if_found);
12010 						ir_END_list(*not_found_inputs);
12011 						ir_IF_TRUE(if_found);
12012 					} else {
12013 						if_found = ir_IF(ref);
12014 						ir_IF_FALSE(if_found);
12015 						ir_END_list(idx_not_found_inputs);
12016 						ir_IF_TRUE(if_found);
12017 					}
12018 					ir_refs_add(found_inputs, ir_END());
12019 					ir_refs_add(found_vals, ref);
12020 				} else if (!packed_loaded) {
12021 					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12022 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12023 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
12024 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
12025 					} else if (type == BP_VAR_IS && result_type_guard) {
12026 						ir_END_list(*not_found_inputs);
12027 					} else {
12028 						ir_END_list(idx_not_found_inputs);
12029 					}
12030 				}
12031 
12032 				if (idx_not_found_inputs) {
12033 					ir_MERGE_list(idx_not_found_inputs);
12034 					switch (type) {
12035 						case BP_VAR_R:
12036 							ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
12037 							// JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
12038 							// JIT: retval = &EG(uninitialized_zval);
12039 							jit_SET_EX_OPLINE(jit, opline);
12040 							if (Z_MODE(op2_addr) == IS_REG) {
12041 								if (!op2_loaded) {
12042 									// JIT: hval = Z_LVAL_P(dim);
12043 									h = jit_Z_LVAL(jit, op2_addr);
12044 								}
12045 								if (GCC_GLOBAL_REGS) {
12046 									ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h);
12047 								} else {
12048 									ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h, jit_FP(jit));
12049 								}
12050 							} else {
12051 								ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
12052 							}
12053 							ir_END_list(*end_inputs);
12054 							break;
12055 						case BP_VAR_IS:
12056 						case BP_VAR_UNSET:
12057 							if (!not_found_exit_addr) {
12058 								// JIT: retval = &EG(uninitialized_zval);
12059 								jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12060 								ir_END_list(*end_inputs);
12061 							}
12062 							break;
12063 						default:
12064 							ZEND_UNREACHABLE();
12065 					}
12066                 }
12067 				break;
12068 			case BP_VAR_RW:
12069 				if (packed_loaded) {
12070 					if (not_found_exit_addr) {
12071 						ir_refs_add(found_inputs, ir_END());
12072 						ir_refs_add(found_vals, ref);
12073 					} else {
12074 						ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12075 						ir_IF_TRUE(if_def);
12076 						ir_refs_add(found_inputs, ir_END());
12077 						ir_refs_add(found_vals, ref);
12078 						ir_IF_FALSE_cold(if_def);
12079 						ir_END_list(idx_not_found_inputs);
12080 					}
12081 				}
12082 				if (!packed_loaded ||
12083 						!not_found_exit_addr ||
12084 						(op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
12085 					if (if_packed) {
12086 						ir_IF_FALSE(if_packed);
12087 						if_packed = IR_UNUSED;
12088 						ir_END_list(idx_not_found_inputs);
12089 					} else if (!packed_loaded) {
12090 						ir_END_list(idx_not_found_inputs);
12091 					}
12092 
12093 					ir_MERGE_list(idx_not_found_inputs);
12094 					if (!op2_loaded) {
12095 						// JIT: hval = Z_LVAL_P(dim);
12096 						h = jit_Z_LVAL(jit, op2_addr);
12097 					}
12098 					if (packed_loaded) {
12099 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
12100 							ht_ref, h);
12101 					} else {
12102 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
12103 					}
12104 					if (not_found_exit_addr) {
12105 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12106 					} else {
12107 						if_found = ir_IF(ref);
12108 						ir_IF_FALSE(if_found);
12109 						ir_END_list(*end_inputs);
12110 						ir_IF_TRUE(if_found);
12111 					}
12112 					ir_refs_add(found_inputs, ir_END());
12113 					ir_refs_add(found_vals, ref);
12114 				}
12115 				break;
12116 			case BP_VAR_W:
12117 				if (packed_loaded) {
12118 					ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12119 					ir_IF_TRUE_cold(if_def);
12120 					ir_refs_add(found_inputs, ir_END());
12121 					ir_refs_add(found_vals, ref);
12122 					ir_IF_FALSE(if_def);
12123 					ir_END_list(idx_not_found_inputs);
12124 				}
12125 				if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
12126 					if (if_packed) {
12127 						ir_IF_FALSE(if_packed);
12128 						if_packed = IR_UNUSED;
12129 						ir_END_list(idx_not_found_inputs);
12130 					} else if (!packed_loaded) {
12131 						ir_END_list(idx_not_found_inputs);
12132 					}
12133 					ir_MERGE_list(idx_not_found_inputs);
12134 					if (!op2_loaded) {
12135 						// JIT: hval = Z_LVAL_P(dim);
12136 						h = jit_Z_LVAL(jit, op2_addr);
12137 					}
12138 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
12139 					ir_refs_add(found_inputs, ir_END());
12140 					ir_refs_add(found_vals, ref);
12141 				}
12142 				break;
12143 			default:
12144 				ZEND_UNREACHABLE();
12145 		}
12146 	}
12147 
12148 	if (op2_info & MAY_BE_STRING) {
12149 		ir_ref key;
12150 
12151 		if (if_type) {
12152 			ir_IF_FALSE(if_type);
12153 			if_type = IS_UNUSED;
12154 		}
12155 
12156 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12157 			// JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
12158 			if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
12159 			ir_IF_TRUE(if_type);
12160 		}
12161 
12162 		// JIT: offset_key = Z_STR_P(dim);
12163 		key = jit_Z_PTR(jit, op2_addr);
12164 
12165 		// JIT: retval = zend_hash_find(ht, offset_key);
12166 		switch (type) {
12167 			case BP_JIT_IS:
12168 				if (opline->op2_type != IS_CONST) {
12169 					ir_ref if_num, end1, ref2;
12170 
12171 					if_num = ir_IF(
12172 						ir_ULE(
12173 							ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12174 							ir_CONST_CHAR('9')));
12175 					ir_IF_TRUE_cold(if_num);
12176 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12177 					end1 = ir_END();
12178 					ir_IF_FALSE(if_num);
12179 					ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12180 					ir_MERGE_WITH(end1);
12181 					ref = ir_PHI_2(IR_ADDR, ref2, ref);
12182 				} else {
12183 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12184 				}
12185 				if (not_found_exit_addr) {
12186 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12187 				} else {
12188 					if_found = ir_IF(ref);
12189 					ir_IF_FALSE(if_found);
12190 					ir_END_list(*end_inputs);
12191 					ir_IF_TRUE(if_found);
12192 				}
12193 				ir_refs_add(test_zval_values, ref);
12194 				ir_refs_add(test_zval_inputs, ir_END());
12195 				break;
12196 			case BP_VAR_R:
12197 			case BP_VAR_IS:
12198 			case BP_VAR_UNSET:
12199 				if (opline->op2_type != IS_CONST) {
12200 					ir_ref if_num, end1, ref2;
12201 
12202 					if_num = ir_IF(
12203 						ir_ULE(
12204 							ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12205 							ir_CONST_CHAR('9')));
12206 					ir_IF_TRUE_cold(if_num);
12207 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12208 					end1 = ir_END();
12209 					ir_IF_FALSE(if_num);
12210 					ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12211 					ir_MERGE_WITH(end1);
12212 					ref = ir_PHI_2(IR_ADDR, ref2, ref);
12213 				} else {
12214 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12215 				}
12216 				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12217 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12218 				} else if (type == BP_VAR_IS && not_found_exit_addr) {
12219 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12220 				} else if (type == BP_VAR_IS && result_type_guard) {
12221 					if_found = ir_IF(ref);
12222 					ir_IF_FALSE(if_found);
12223 					ir_END_list(*not_found_inputs);
12224 					ir_IF_TRUE(if_found);
12225 				} else {
12226 					if_found = ir_IF(ref);
12227 					switch (type) {
12228 						case BP_VAR_R:
12229 							ir_IF_FALSE_cold(if_found);
12230 							// JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
12231 							jit_SET_EX_OPLINE(jit, opline);
12232 							ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
12233 							ir_END_list(*end_inputs);
12234 							break;
12235 						case BP_VAR_IS:
12236 						case BP_VAR_UNSET:
12237 							ir_IF_FALSE(if_found);
12238 							// JIT: retval = &EG(uninitialized_zval);
12239 							jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12240 							ir_END_list(*end_inputs);
12241 							break;
12242 						default:
12243 							ZEND_UNREACHABLE();
12244 					}
12245 					ir_IF_TRUE(if_found);
12246 				}
12247 				ir_refs_add(found_inputs, ir_END());
12248 				ir_refs_add(found_vals, ref);
12249 				break;
12250 			case BP_VAR_RW:
12251 				if (opline->op2_type != IS_CONST) {
12252 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
12253 				} else {
12254 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
12255 				}
12256 				if (not_found_exit_addr) {
12257 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12258 				} else {
12259 					if_found = ir_IF(ref);
12260 					ir_IF_FALSE(if_found);
12261 					ir_END_list(*end_inputs);
12262 					ir_IF_TRUE(if_found);
12263 				}
12264 				ir_refs_add(found_inputs, ir_END());
12265 				ir_refs_add(found_vals, ref);
12266 				break;
12267 			case BP_VAR_W:
12268 				if (opline->op2_type != IS_CONST) {
12269 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12270 				} else {
12271 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12272 				}
12273 				ir_refs_add(found_inputs, ir_END());
12274 				ir_refs_add(found_vals, ref);
12275 				break;
12276 			default:
12277 				ZEND_UNREACHABLE();
12278 		}
12279 	}
12280 
12281 	if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12282 	    if (if_type) {
12283 			ir_IF_FALSE_cold(if_type);
12284 			if_type = IS_UNDEF;
12285 		}
12286 		if (type != BP_VAR_RW) {
12287 			jit_SET_EX_OPLINE(jit, opline);
12288 		}
12289 		ref = jit_ZVAL_ADDR(jit, op2_addr);
12290 		switch (type) {
12291 			case BP_VAR_R:
12292 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12293 					ht_ref,
12294 					ref,
12295 					jit_ZVAL_ADDR(jit, res_addr));
12296 				ir_END_list(*end_inputs);
12297 				break;
12298 			case BP_JIT_IS:
12299 				ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12300 				if (not_found_exit_addr) {
12301 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12302 					ir_refs_add(found_inputs, ir_END());
12303 				} else if (found_exit_addr) {
12304 					ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12305 					ir_END_list(*end_inputs);
12306 				} else {
12307 					if_found = ir_IF(ref);
12308 					ir_IF_TRUE(if_found);
12309 					ir_refs_add(found_inputs, ir_END());
12310 					ir_IF_FALSE(if_found);
12311 					ir_END_list(*end_inputs);
12312 				}
12313 				break;
12314 			case BP_VAR_IS:
12315 			case BP_VAR_UNSET:
12316 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12317 					ht_ref,
12318 					ref,
12319 					jit_ZVAL_ADDR(jit, res_addr));
12320 				ir_END_list(*end_inputs);
12321 				break;
12322 			case BP_VAR_RW:
12323 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12324 				if_found = ir_IF(ref);
12325 				ir_IF_TRUE(if_found);
12326 				ir_refs_add(found_inputs, ir_END());
12327 				ir_refs_add(found_vals, ref);
12328 				ir_IF_FALSE(if_found);
12329 				ir_END_list(*end_inputs);
12330 				break;
12331 			case BP_VAR_W:
12332 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12333 				if_found = ir_IF(ref);
12334 				ir_IF_TRUE(if_found);
12335 				ir_refs_add(found_inputs, ir_END());
12336 				ir_refs_add(found_vals, ref);
12337 				ir_IF_FALSE(if_found);
12338 				ir_END_list(*end_inputs);
12339 				break;
12340 			default:
12341 				ZEND_UNREACHABLE();
12342 		}
12343 	}
12344 
12345 	if (type == BP_JIT_IS
12346 	 && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12347 	 	/* dead code */
12348 		ir_END_list(*end_inputs);
12349 	} else if (type == BP_JIT_IS
12350 	 && (op1_info & MAY_BE_ARRAY)
12351 	 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12352 	 && test_zval_inputs->count) {
12353 
12354 		ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12355 		ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12356 
12357 		if (op1_info & MAY_BE_ARRAY_OF_REF) {
12358 			ref = jit_ZVAL_DEREF_ref(jit, ref);
12359 		}
12360 		cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12361 		if (not_found_exit_addr) {
12362 			ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12363 			ir_refs_add(found_inputs, ir_END());
12364 		} else if (found_exit_addr) {
12365 			ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12366 			ir_END_list(*end_inputs);
12367 		} else {
12368 			ir_ref if_set = ir_IF(cond);
12369 			ir_IF_FALSE(if_set);
12370 			ir_END_list(*end_inputs);
12371 			ir_IF_TRUE(if_set);
12372 			ir_refs_add(found_inputs, ir_END());
12373 		}
12374 	}
12375 
12376 	return 1;
12377 }
12378 
12379 static int zend_jit_fetch_dim_read(zend_jit_ctx       *jit,
12380                                    const zend_op      *opline,
12381                                    zend_ssa           *ssa,
12382                                    const zend_ssa_op  *ssa_op,
12383                                    uint32_t            op1_info,
12384                                    zend_jit_addr       op1_addr,
12385                                    bool           op1_avoid_refcounting,
12386                                    uint32_t            op2_info,
12387                                    zend_jit_addr       op2_addr,
12388                                    zend_ssa_range     *op2_range,
12389                                    uint32_t            res_info,
12390                                    zend_jit_addr       res_addr,
12391                                    uint8_t             dim_type)
12392 {
12393 	zend_jit_addr orig_op1_addr;
12394 	const void *exit_addr = NULL;
12395 	const void *not_found_exit_addr = NULL;
12396 	bool result_type_guard = 0;
12397 	bool result_avoid_refcounting = 0;
12398 	uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12399 	int may_throw = 0;
12400 	ir_ref if_type = IR_UNUSED;
12401 	ir_ref end_inputs = IR_UNUSED;
12402 	ir_ref not_found_inputs = IR_UNUSED;
12403 
12404 	orig_op1_addr = OP1_ADDR();
12405 
12406 	if (opline->opcode != ZEND_FETCH_DIM_IS
12407 	 && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12408 	 && !has_concrete_type(op1_info)) {
12409 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12410 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12411 		if (!exit_addr) {
12412 			return 0;
12413 		}
12414 	}
12415 
12416 	if ((res_info & MAY_BE_GUARD)
12417 	 && JIT_G(current_frame)
12418 	 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12419 
12420 		if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12421 			result_type_guard = 1;
12422 			res_info &= ~MAY_BE_GUARD;
12423 			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12424 		}
12425 
12426 		if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12427 		 && (opline->opcode == ZEND_FETCH_LIST_R
12428 		  || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12429 		  || op1_avoid_refcounting)
12430 		 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12431 		 && (ssa_op+1)->op1_use == ssa_op->result_def
12432 		 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12433 		 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12434 			result_avoid_refcounting = 1;
12435 			ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12436 		}
12437 
12438 		if (opline->opcode == ZEND_FETCH_DIM_IS
12439 		 && !(res_info & MAY_BE_NULL)) {
12440 			uint32_t flags = 0;
12441 			uint32_t old_op1_info = 0;
12442 			uint32_t old_info;
12443 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12444 			int32_t exit_point;
12445 
12446 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
12447 			 && !op1_avoid_refcounting) {
12448 				flags |= ZEND_JIT_EXIT_FREE_OP1;
12449 			}
12450 			if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12451 			 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12452 				flags |= ZEND_JIT_EXIT_FREE_OP2;
12453 			}
12454 
12455 			if (op1_avoid_refcounting) {
12456 				old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12457 				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12458 			}
12459 
12460 			old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12461 			SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12462 			SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_TYPE_ONLY);
12463 			exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12464 			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12465 			not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12466 			if (!not_found_exit_addr) {
12467 				return 0;
12468 			}
12469 
12470 			if (op1_avoid_refcounting) {
12471 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12472 			}
12473 		}
12474 	}
12475 
12476 	if (op1_info & MAY_BE_REF) {
12477 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12478 		ref = jit_ZVAL_DEREF_ref(jit, ref);
12479 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12480 	}
12481 
12482 	if (op1_info & MAY_BE_ARRAY) {
12483 		ir_ref ht_ref, ref;
12484 		zend_jit_addr val_addr;
12485 		ir_refs *found_inputs, *found_vals;
12486 
12487 		ir_refs_init(found_inputs, 10);
12488 		ir_refs_init(found_vals, 10);
12489 
12490 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12491 			if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12492 				jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12493 			} else {
12494 				if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12495 				ir_IF_TRUE(if_type);
12496 			}
12497 		}
12498 
12499 		ht_ref = jit_Z_PTR(jit, op1_addr);
12500 
12501 		if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12502 		    (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12503 			may_throw = 1;
12504 		}
12505 
12506 		if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12507 				(opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12508 				op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12509 				result_type_guard, ht_ref, found_inputs, found_vals,
12510 				&end_inputs, &not_found_inputs)) {
12511 			return 0;
12512 		}
12513 
12514 		if (found_inputs->count) {
12515 			ir_MERGE_N(found_inputs->count, found_inputs->refs);
12516 			ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12517 			val_addr = ZEND_ADDR_REF_ZVAL(ref);
12518 
12519 			if (result_type_guard) {
12520 				uint8_t type = concrete_type(res_info);
12521 				uint32_t flags = 0;
12522 
12523 				if (opline->opcode != ZEND_FETCH_LIST_R
12524 				 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12525 				 && !op1_avoid_refcounting) {
12526 					flags |= ZEND_JIT_EXIT_FREE_OP1;
12527 				}
12528 				if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12529 				 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12530 					flags |= ZEND_JIT_EXIT_FREE_OP2;
12531 				}
12532 
12533 				val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12534 					(op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12535 				if (!val_addr) {
12536 					return 0;
12537 				}
12538 
12539 				if (not_found_inputs) {
12540 					ir_END_list(not_found_inputs);
12541 					ir_MERGE_list(not_found_inputs);
12542 				}
12543 
12544 				// ZVAL_COPY
12545 				jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12546 				if (Z_MODE(res_addr) != IS_REG) {
12547 				} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12548 					return 0;
12549 				}
12550 			} else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12551 				// ZVAL_COPY_DEREF
12552 				ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12553 				if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12554 					return 0;
12555 				}
12556 			} else  {
12557 				// ZVAL_COPY
12558 				jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, 1);
12559 			}
12560 
12561 			ir_END_list(end_inputs);
12562 		} else if (not_found_inputs) {
12563 			ir_MERGE_list(not_found_inputs);
12564 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12565 			ir_END_list(end_inputs);
12566 		} else if (!end_inputs && jit->ctx.control) {
12567 			ir_END_list(end_inputs); /* dead code */
12568 		}
12569 	}
12570 
12571 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12572 		if (if_type) {
12573 			ir_IF_FALSE_cold(if_type);
12574 			if_type = IS_UNDEF;
12575 		}
12576 
12577 		if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12578 			ir_ref str_ref;
12579 
12580 			may_throw = 1;
12581 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12582 				if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12583 					jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12584 				} else {
12585 					if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12586 					ir_IF_TRUE(if_type);
12587 				}
12588 			}
12589 			jit_SET_EX_OPLINE(jit, opline);
12590 			str_ref = jit_Z_PTR(jit, op1_addr);
12591 			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12592 				ir_ref ref;
12593 
12594 				if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12595 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12596 						str_ref, jit_Z_LVAL(jit, op2_addr));
12597 				} else {
12598 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12599 						str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12600 				}
12601 				jit_set_Z_PTR(jit, res_addr, ref);
12602 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12603 			} else {
12604 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12605 					str_ref,
12606 					jit_ZVAL_ADDR(jit, op2_addr),
12607 					jit_ZVAL_ADDR(jit, res_addr));
12608 			}
12609 			ir_END_list(end_inputs);
12610 		}
12611 
12612 		if (op1_info & MAY_BE_OBJECT) {
12613 			ir_ref arg2;
12614 
12615 			if (if_type) {
12616 				ir_IF_FALSE_cold(if_type);
12617 				if_type = IS_UNDEF;
12618 			}
12619 
12620 			may_throw = 1;
12621 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12622 				if (exit_addr) {
12623 					jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12624 				} else {
12625 					if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12626 					ir_IF_TRUE(if_type);
12627 				}
12628 			}
12629 
12630 			jit_SET_EX_OPLINE(jit, opline);
12631 			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12632 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12633 				arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12634 			} else {
12635 				arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12636 			}
12637 
12638 			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12639 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12640 					jit_ZVAL_ADDR(jit, op1_addr),
12641 					arg2,
12642 					jit_ZVAL_ADDR(jit, res_addr));
12643 			} else {
12644 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12645 					jit_ZVAL_ADDR(jit, op1_addr),
12646 					arg2,
12647 					jit_ZVAL_ADDR(jit, res_addr));
12648 			}
12649 
12650 			ir_END_list(end_inputs);
12651 		}
12652 
12653 		if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12654 		 && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12655 
12656 			if (if_type) {
12657 				ir_IF_FALSE_cold(if_type);
12658 				if_type = IS_UNDEF;
12659 			}
12660 
12661 			if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12662 				jit_SET_EX_OPLINE(jit, opline);
12663 				if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12664 					may_throw = 1;
12665 					zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL, 0, 1, 0);
12666 				}
12667 
12668 				if (op2_info & MAY_BE_UNDEF) {
12669 					may_throw = 1;
12670 					zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL, 0, 1, 0);
12671 				}
12672 			}
12673 
12674 			if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
12675 				ir_ref ref;
12676 
12677 				may_throw = 1;
12678 				if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12679 					ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
12680 				} else {
12681 					jit_SET_EX_OPLINE(jit, opline);
12682 					ref = jit_ZVAL_ADDR(jit, op1_addr);
12683 				}
12684 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
12685 			}
12686 
12687 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12688 			ir_END_list(end_inputs);
12689 		}
12690 	}
12691 
12692 	if (end_inputs) {
12693 		ir_MERGE_list(end_inputs);
12694 
12695 #ifdef ZEND_JIT_USE_RC_INFERENCE
12696 		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12697 			/* Magic offsetGet() may increase refcount of the key */
12698 			op2_info |= MAY_BE_RCN;
12699 		}
12700 #endif
12701 
12702 		if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
12703 			if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
12704 				may_throw = 1;
12705 			}
12706 			jit_FREE_OP(jit,  opline->op2_type, opline->op2, op2_info, opline);
12707 		}
12708 		if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12709 			if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
12710 				if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
12711 					may_throw = 1;
12712 				}
12713 				jit_FREE_OP(jit,  opline->op1_type, opline->op1, op1_info, opline);
12714 			}
12715 		}
12716 
12717 		if (may_throw) {
12718 			zend_jit_check_exception(jit);
12719 		}
12720 	} else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
12721 		ir_BEGIN(IR_UNUSED); /* unreachable tail */
12722 	}
12723 
12724 	return 1;
12725 }
12726 
12727 static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx   *jit,
12728                                                    const zend_op  *opline,
12729                                                    uint32_t       *op1_info_ptr,
12730                                                    zend_jit_addr   op1_addr,
12731                                                    ir_ref         *if_type,
12732                                                    ir_ref         *ht_ref,
12733                                                    int            *may_throw)
12734 {
12735 	ir_ref ref = IR_UNUSED;
12736 	ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
12737 	ir_refs *array_inputs, *array_values;
12738 	uint32_t op1_info = *op1_info_ptr;
12739 
12740 	ir_refs_init(array_inputs, 4);
12741 	ir_refs_init(array_values, 4);
12742 
12743 	ref = jit_ZVAL_ADDR(jit, op1_addr);
12744 	if (op1_info & MAY_BE_REF) {
12745 		ir_ref if_reference, if_array, end1, ref2;
12746 
12747 		*may_throw = 1;
12748 		if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
12749 		ir_IF_FALSE(if_reference);
12750 		end1 = ir_END();
12751 		ir_IF_TRUE_cold(if_reference);
12752 		array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
12753 		if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
12754 		ir_IF_TRUE(if_array);
12755 		array_reference_end = ir_END();
12756 		ir_IF_FALSE_cold(if_array);
12757 		if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
12758 			jit_SET_EX_OPLINE(jit, opline);
12759 		}
12760 		ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
12761 		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
12762 
12763 		ir_MERGE_WITH(end1);
12764 		ref = ir_PHI_2(IR_ADDR, ref2, ref);
12765 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12766 	}
12767 
12768 	if (op1_info & MAY_BE_ARRAY) {
12769 		ir_ref op1_ref = ref;
12770 
12771 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12772 			*if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12773 			ir_IF_TRUE(*if_type);
12774 		}
12775 		if (array_reference_end) {
12776 			ir_MERGE_WITH(array_reference_end);
12777 			op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
12778 		}
12779 		// JIT: SEPARATE_ARRAY()
12780 		ref = jit_Z_PTR_ref(jit, op1_ref);
12781 		if (RC_MAY_BE_N(op1_info)) {
12782 			if (RC_MAY_BE_1(op1_info)) {
12783 				ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
12784 				ir_IF_TRUE(if_refcount_1);
12785 				ir_refs_add(array_inputs, ir_END());
12786 				ir_refs_add(array_values, ref);
12787 				ir_IF_FALSE(if_refcount_1);
12788 			}
12789 			ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
12790 		}
12791 		if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
12792 			ir_refs_add(array_inputs, ir_END());
12793 			ir_refs_add(array_values, ref);
12794 		}
12795 	}
12796 
12797 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
12798 		if (*if_type) {
12799 			ir_IF_FALSE_cold(*if_type);
12800 			*if_type = IR_UNUSED;
12801 		}
12802 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12803 			*if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
12804 			ir_IF_TRUE(*if_type);
12805 		}
12806 		if ((op1_info & MAY_BE_UNDEF)
12807 		 && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
12808 			ir_ref end1 = IR_UNUSED;
12809 
12810 			*may_throw = 1;
12811 			if (op1_info & MAY_BE_NULL) {
12812 				ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
12813 				ir_IF_TRUE(if_def);
12814 				end1 = ir_END();
12815 				ir_IF_FALSE(if_def);
12816 			}
12817 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
12818 			if (end1) {
12819 				ir_MERGE_WITH(end1);
12820 			}
12821 		}
12822 		// JIT: ZVAL_ARR(container, zend_new_array(8));
12823 		ref = ir_CALL_1(IR_ADDR,
12824 			jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
12825 			jit_ZVAL_ADDR(jit, op1_addr));
12826 		if (array_inputs->count) {
12827 			ir_refs_add(array_inputs, ir_END());
12828 			ir_refs_add(array_values, ref);
12829 		}
12830 		op1_info &= ~(MAY_BE_UNDEF | MAY_BE_NULL);
12831 		op1_info |= MAY_BE_ARRAY | MAY_BE_RC1;
12832 		*op1_info_ptr = op1_info;
12833 	}
12834 
12835 	if (array_inputs->count) {
12836 		ir_MERGE_N(array_inputs->count, array_inputs->refs);
12837 		ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
12838 	}
12839 
12840 	*ht_ref = ref;
12841 	return op1_addr;
12842 }
12843 
12844 static int zend_jit_fetch_dim(zend_jit_ctx   *jit,
12845                               const zend_op  *opline,
12846                               uint32_t        op1_info,
12847                               zend_jit_addr   op1_addr,
12848                               uint32_t        op2_info,
12849                               zend_jit_addr   op2_addr,
12850                               zend_ssa_range *op2_range,
12851                               zend_jit_addr   res_addr,
12852                               uint8_t         dim_type)
12853 {
12854 	int may_throw = 0;
12855 	ir_ref end_inputs = IR_UNUSED;
12856 	ir_ref ref, if_type = IR_UNUSED, ht_ref;
12857 
12858 	if (opline->opcode == ZEND_FETCH_DIM_RW) {
12859 		jit_SET_EX_OPLINE(jit, opline);
12860 	}
12861 
12862 	op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
12863 
12864 	if (op1_info & MAY_BE_ARRAY) {
12865 		ir_refs *found_inputs, *found_vals;
12866 
12867 		ir_refs_init(found_inputs, 8);
12868 		ir_refs_init(found_vals, 8);
12869 
12870 		if (opline->op2_type == IS_UNUSED) {
12871 			ir_ref if_ok;
12872 
12873 			may_throw = 1;
12874 			// JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
12875 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
12876 				ht_ref, jit_EG(uninitialized_zval));
12877 
12878 			// JIT: if (UNEXPECTED(!var_ptr)) {
12879 			if_ok = ir_IF(ref);
12880 			ir_IF_FALSE_cold(if_ok);
12881 			if (opline->opcode != ZEND_FETCH_DIM_RW) {
12882 				jit_SET_EX_OPLINE(jit, opline);
12883 			}
12884 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
12885 			ir_END_list(end_inputs);
12886 
12887 			ir_IF_TRUE(if_ok);
12888 			jit_set_Z_PTR(jit, res_addr, ref);
12889 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12890 
12891 			ir_END_list(end_inputs);
12892 		} else {
12893 			uint32_t type;
12894 
12895 			switch (opline->opcode) {
12896 				case ZEND_FETCH_DIM_W:
12897 				case ZEND_FETCH_LIST_W:
12898 					type = BP_VAR_W;
12899 					break;
12900 				case ZEND_FETCH_DIM_RW:
12901 					may_throw = 1;
12902 					type = BP_VAR_RW;
12903 					break;
12904 				case ZEND_FETCH_DIM_UNSET:
12905 					type = BP_VAR_UNSET;
12906 					break;
12907 				default:
12908 					ZEND_UNREACHABLE();
12909 			}
12910 
12911 			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12912 				may_throw = 1;
12913 			}
12914 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
12915 					op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
12916 					0, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
12917 				return 0;
12918 			}
12919 
12920 			if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
12921 				if (end_inputs) {
12922 					ir_MERGE_list(end_inputs);
12923 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12924 					end_inputs = ir_END();
12925 				}
12926 			} else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12927 				/* impossible dead path */
12928 				end_inputs = ir_END();
12929 			} else {
12930 				ZEND_ASSERT(end_inputs == IR_UNUSED);
12931 			}
12932 
12933 			if (found_inputs->count) {
12934 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
12935 				ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12936 				jit_set_Z_PTR(jit, res_addr, ref);
12937 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12938 				ir_END_list(end_inputs);
12939 			}
12940 
12941 		}
12942 	}
12943 
12944 	if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
12945 		ir_ref arg2;
12946 
12947 		may_throw = 1;
12948 
12949 		if (if_type) {
12950 			ir_IF_FALSE(if_type);
12951 			if_type = IR_UNUSED;
12952 		}
12953 
12954 		if (opline->opcode != ZEND_FETCH_DIM_RW) {
12955 			jit_SET_EX_OPLINE(jit, opline);
12956 		}
12957 
12958 	    if (opline->op2_type == IS_UNUSED) {
12959 			arg2 = IR_NULL;
12960 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12961 			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12962 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
12963 		} else {
12964 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12965 		}
12966 
12967 		switch (opline->opcode) {
12968 			case ZEND_FETCH_DIM_W:
12969 			case ZEND_FETCH_LIST_W:
12970 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
12971 					jit_ZVAL_ADDR(jit, op1_addr),
12972 					arg2,
12973 					jit_ZVAL_ADDR(jit, res_addr));
12974 				break;
12975 			case ZEND_FETCH_DIM_RW:
12976 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
12977 					jit_ZVAL_ADDR(jit, op1_addr),
12978 					arg2,
12979 					jit_ZVAL_ADDR(jit, res_addr));
12980 				break;
12981 //			case ZEND_FETCH_DIM_UNSET:
12982 //				|	EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
12983 //				break;
12984 			default:
12985 				ZEND_UNREACHABLE();
12986 			}
12987 
12988 		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12989 			ir_END_list(end_inputs);
12990 		}
12991 	}
12992 
12993 #ifdef ZEND_JIT_USE_RC_INFERENCE
12994 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
12995 		/* ASSIGN_DIM may increase refcount of the key */
12996 		op2_info |= MAY_BE_RCN;
12997 	}
12998 #endif
12999 
13000 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
13001 	 && (op2_info & MAY_HAVE_DTOR)
13002 	 && (op2_info & MAY_BE_RC1)) {
13003 		may_throw = 1;
13004 	}
13005 
13006 	if (end_inputs) {
13007 		ir_MERGE_list(end_inputs);
13008 	}
13009 
13010 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13011 
13012 	if (may_throw) {
13013 		zend_jit_check_exception(jit);
13014 	}
13015 
13016 	return 1;
13017 }
13018 
13019 static int zend_jit_isset_isempty_dim(zend_jit_ctx   *jit,
13020                                       const zend_op  *opline,
13021                                       uint32_t        op1_info,
13022                                       zend_jit_addr   op1_addr,
13023                                       bool       op1_avoid_refcounting,
13024                                       uint32_t        op2_info,
13025                                       zend_jit_addr   op2_addr,
13026                                       zend_ssa_range *op2_range,
13027                                       uint8_t         dim_type,
13028                                       int             may_throw,
13029                                       uint8_t         smart_branch_opcode,
13030                                       uint32_t        target_label,
13031                                       uint32_t        target_label2,
13032                                       const void     *exit_addr)
13033 {
13034 	zend_jit_addr res_addr;
13035 	ir_ref if_type = IR_UNUSED;
13036 	ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
13037 	ir_refs *true_inputs;
13038 
13039 	ir_refs_init(true_inputs, 8);
13040 
13041 	// TODO: support for empty() ???
13042 	ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
13043 
13044 	res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13045 
13046 	if (op1_info & MAY_BE_REF) {
13047 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
13048 		ref = jit_ZVAL_DEREF_ref(jit, ref);
13049 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
13050 	}
13051 
13052 	if (op1_info & MAY_BE_ARRAY) {
13053 		const void *found_exit_addr = NULL;
13054 		const void *not_found_exit_addr = NULL;
13055 		ir_ref ht_ref;
13056 
13057 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
13058 			if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
13059 			ir_IF_TRUE(if_type);
13060 		}
13061 
13062 		ht_ref = jit_Z_PTR(jit, op1_addr);
13063 
13064 		if (exit_addr
13065 		 && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
13066 		 && !may_throw
13067 		 && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
13068 		 && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
13069 			if (smart_branch_opcode == ZEND_JMPNZ) {
13070 				found_exit_addr = exit_addr;
13071 			} else {
13072 				not_found_exit_addr = exit_addr;
13073 			}
13074 		}
13075 		if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
13076 				op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
13077 				0, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
13078 			return 0;
13079 		}
13080 
13081 		if (found_exit_addr) {
13082 			ir_MERGE_list(false_inputs);
13083 			return 1;
13084 		} else if (not_found_exit_addr) {
13085 			ir_MERGE_N(true_inputs->count, true_inputs->refs);
13086 			return 1;
13087 		}
13088 	}
13089 
13090 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
13091 		if (if_type) {
13092 			ir_IF_FALSE(if_type);
13093 			if_type = IR_UNUSED;
13094 		}
13095 
13096 		if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
13097 			ir_ref ref, arg1, arg2, if_true;
13098 
13099 			jit_SET_EX_OPLINE(jit, opline);
13100 			arg1 = jit_ZVAL_ADDR(jit, op1_addr);
13101 			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13102 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13103 				arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
13104 			} else {
13105 				arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13106 			}
13107 			ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
13108 			if_true = ir_IF(ref);
13109 			ir_IF_TRUE(if_true);
13110 			ir_refs_add(true_inputs, ir_END());
13111 			ir_IF_FALSE(if_true);
13112 			ir_END_list(false_inputs);
13113 		} else {
13114 			if (op2_info & MAY_BE_UNDEF) {
13115 				ir_ref end1 = IR_UNUSED;
13116 
13117 				if (op2_info & MAY_BE_ANY) {
13118 					ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
13119 					ir_IF_TRUE(if_def);
13120 					end1 = ir_END();
13121 					ir_IF_FALSE(if_def);
13122 				}
13123 				jit_SET_EX_OPLINE(jit, opline);
13124 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
13125 				if (end1) {
13126 					ir_MERGE_WITH(end1);
13127 				}
13128 			}
13129 			ir_END_list(false_inputs);
13130 		}
13131 	}
13132 
13133 #ifdef ZEND_JIT_USE_RC_INFERENCE
13134 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
13135 		/* Magic offsetExists() may increase refcount of the key */
13136 		op2_info |= MAY_BE_RCN;
13137 	}
13138 #endif
13139 
13140 	if (true_inputs->count) {
13141 		ir_MERGE_N(true_inputs->count, true_inputs->refs);
13142 
13143 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13144 		if (!op1_avoid_refcounting) {
13145 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13146 		}
13147 		if (may_throw) {
13148 			zend_jit_check_exception_undef_result(jit, opline);
13149 		}
13150 		if (!(opline->extended_value & ZEND_ISEMPTY)) {
13151 			if (exit_addr) {
13152 				if (smart_branch_opcode == ZEND_JMPNZ) {
13153 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13154 				} else {
13155 					ir_END_list(end_inputs);
13156 				}
13157 			} else if (smart_branch_opcode) {
13158 				if (smart_branch_opcode == ZEND_JMPZ) {
13159 					_zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13160 				} else if (smart_branch_opcode == ZEND_JMPNZ) {
13161 					_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13162 				} else {
13163 					ZEND_UNREACHABLE();
13164 				}
13165 			} else {
13166 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
13167 				ir_END_list(end_inputs);
13168 			}
13169 		} else {
13170 			ZEND_UNREACHABLE(); // TODO: support for empty()
13171 		}
13172 	}
13173 
13174 	ir_MERGE_list(false_inputs);
13175 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13176 	if (!op1_avoid_refcounting) {
13177 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13178 	}
13179 	if (may_throw) {
13180 		zend_jit_check_exception_undef_result(jit, opline);
13181 	}
13182 	if (!(opline->extended_value & ZEND_ISEMPTY)) {
13183 		if (exit_addr) {
13184 			if (smart_branch_opcode == ZEND_JMPZ) {
13185 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13186 			} else {
13187 				ir_END_list(end_inputs);
13188 			}
13189 		} else if (smart_branch_opcode) {
13190 			if (smart_branch_opcode == ZEND_JMPZ) {
13191 				_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13192 			} else if (smart_branch_opcode == ZEND_JMPNZ) {
13193 				_zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13194 			} else {
13195 				ZEND_UNREACHABLE();
13196 			}
13197 		} else {
13198 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
13199 			ir_END_list(end_inputs);
13200 		}
13201 	} else {
13202 		ZEND_UNREACHABLE(); // TODO: support for empty()
13203 	}
13204 
13205     if (!exit_addr && smart_branch_opcode) {
13206 		jit->b = -1;
13207     } else {
13208 		ir_MERGE_list(end_inputs);
13209     }
13210 
13211 	return 1;
13212 }
13213 
13214 static int zend_jit_assign_dim(zend_jit_ctx  *jit,
13215                                const zend_op *opline,
13216                                uint32_t       op1_info,
13217                                zend_jit_addr  op1_addr,
13218                                bool           op1_indirect,
13219                                uint32_t       op2_info,
13220                                zend_jit_addr  op2_addr,
13221                                zend_ssa_range *op2_range,
13222                                uint32_t       val_info,
13223                                zend_jit_addr  op3_addr,
13224                                zend_jit_addr  op3_def_addr,
13225                                zend_jit_addr  res_addr,
13226                                uint8_t        dim_type,
13227                                int            may_throw)
13228 {
13229 	ir_ref if_type = IR_UNUSED;
13230 	ir_ref end_inputs = IR_UNUSED, ht_ref;
13231 
13232 	if (op3_addr != op3_def_addr && op3_def_addr) {
13233 		if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
13234 			return 0;
13235 		}
13236 		if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
13237 			op3_addr = op3_def_addr;
13238 		}
13239 	}
13240 
13241 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
13242 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13243 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13244 
13245 		if (!exit_addr) {
13246 			return 0;
13247 		}
13248 
13249 		jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
13250 
13251 		val_info &= ~MAY_BE_UNDEF;
13252 	}
13253 
13254 	op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13255 
13256 	if (op1_info & MAY_BE_ARRAY) {
13257 		if (opline->op2_type == IS_UNUSED) {
13258 			uint32_t var_info = MAY_BE_NULL;
13259 			ir_ref if_ok, ref;
13260 			zend_jit_addr var_addr;
13261 
13262 			// JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13263 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13264 				ht_ref, jit_EG(uninitialized_zval));
13265 
13266 			// JIT: if (UNEXPECTED(!var_ptr)) {
13267 			if_ok = ir_IF(ref);
13268 			ir_IF_FALSE_cold(if_ok);
13269 
13270 			// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13271 			jit_SET_EX_OPLINE(jit, opline);
13272 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13273 
13274 			ir_END_list(end_inputs);
13275 
13276 			ir_IF_TRUE(if_ok);
13277 			var_addr = ZEND_ADDR_REF_ZVAL(ref);
13278 			if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13279 				return 0;
13280 			}
13281 		} else {
13282 			uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13283 			zend_jit_addr var_addr;
13284 			ir_ref ref;
13285 			ir_refs *found_inputs, *found_values;
13286 
13287 			ir_refs_init(found_inputs, 8);
13288 			ir_refs_init(found_values, 8);
13289 
13290 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13291 					op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13292 					0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13293 				return 0;
13294 			}
13295 
13296 			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13297 				var_info |= MAY_BE_REF;
13298 			}
13299 			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13300 				var_info |= MAY_BE_RC1;
13301 			}
13302 
13303 			if (found_inputs->count) {
13304 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
13305 				ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13306 				var_addr = ZEND_ADDR_REF_ZVAL(ref);
13307 
13308 				// JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13309 				if (opline->op1_type == IS_VAR
13310 				 && Z_MODE(op3_addr) != IS_REG
13311 				 && opline->result_type == IS_UNUSED
13312 				 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13313 					if (!zend_jit_assign_to_variable_call(jit, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13314 						return 0;
13315 					}
13316 				} else {
13317 					if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0, 0)) {
13318 						return 0;
13319 					}
13320 				}
13321 			}
13322 		}
13323 
13324 		ir_END_list(end_inputs);
13325 	}
13326 
13327 	if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13328 		ir_ref arg2, arg4;
13329 
13330 		if (if_type) {
13331 			ir_IF_FALSE_cold(if_type);
13332 			if_type = IR_UNUSED;
13333 		}
13334 
13335 		jit_SET_EX_OPLINE(jit, opline);
13336 
13337 	    if (opline->op2_type == IS_UNUSED) {
13338 			arg2 = IR_NULL;
13339 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13340 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13341 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13342 		} else {
13343 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13344 		}
13345 
13346 		if (opline->result_type == IS_UNUSED) {
13347 			arg4 = IR_NULL;
13348 		} else {
13349 			arg4 = jit_ZVAL_ADDR(jit, res_addr);
13350 		}
13351 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13352 			jit_ZVAL_ADDR(jit, op1_addr),
13353 			arg2,
13354 			jit_ZVAL_ADDR(jit, op3_addr),
13355 			arg4);
13356 
13357 #ifdef ZEND_JIT_USE_RC_INFERENCE
13358 		if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13359 			/* ASSIGN_DIM may increase refcount of the value */
13360 			val_info |= MAY_BE_RCN;
13361 		}
13362 #endif
13363 
13364 		jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13365 
13366 		ir_END_list(end_inputs);
13367 	}
13368 
13369 #ifdef ZEND_JIT_USE_RC_INFERENCE
13370 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
13371 		/* ASSIGN_DIM may increase refcount of the key */
13372 		op2_info |= MAY_BE_RCN;
13373 	}
13374 #endif
13375 
13376 	ir_MERGE_list(end_inputs);
13377 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13378 
13379 	if (!op1_indirect) {
13380 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13381 	}
13382 
13383 	if (may_throw) {
13384 		zend_jit_check_exception(jit);
13385 	}
13386 
13387 	return 1;
13388 }
13389 
13390 static int zend_jit_assign_dim_op(zend_jit_ctx   *jit,
13391                                   const zend_op  *opline,
13392                                   uint32_t        op1_info,
13393                                   uint32_t        op1_def_info,
13394                                   zend_jit_addr   op1_addr,
13395                                   bool            op1_indirect,
13396                                   uint32_t        op2_info,
13397                                   zend_jit_addr   op2_addr,
13398                                   zend_ssa_range *op2_range,
13399                                   uint32_t        op1_data_info,
13400                                   zend_jit_addr   op3_addr,
13401                                   zend_ssa_range *op1_data_range,
13402                                   uint8_t         dim_type,
13403                                   int             may_throw)
13404 {
13405 	zend_jit_addr var_addr = IS_UNUSED;
13406 	const void *not_found_exit_addr = NULL;
13407 	uint32_t var_info = MAY_BE_NULL;
13408 	ir_ref if_type = IS_UNUSED;
13409 	ir_ref end_inputs = IR_UNUSED, ht_ref;
13410 	bool emit_fast_path = 1;
13411 
13412 	ZEND_ASSERT(opline->result_type == IS_UNUSED);
13413 
13414 	if (may_throw) {
13415 		jit_SET_EX_OPLINE(jit, opline);
13416 	}
13417 
13418 	op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13419 
13420 	if (op1_info & MAY_BE_ARRAY) {
13421 		uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13422 
13423 		if (opline->op2_type == IS_UNUSED) {
13424 			var_info = MAY_BE_NULL;
13425 			ir_ref if_ok, ref;
13426 
13427 			// JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13428 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13429 				ht_ref, jit_EG(uninitialized_zval));
13430 
13431 			// JIT: if (UNEXPECTED(!var_ptr)) {
13432 			if_ok = ir_IF(ref);
13433 			ir_IF_FALSE_cold(if_ok);
13434 
13435 			// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13436 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13437 
13438 			ir_END_list(end_inputs);
13439 
13440 			ir_IF_TRUE(if_ok);
13441 			var_addr = ZEND_ADDR_REF_ZVAL(ref);
13442 		} else {
13443 			ir_ref ref;
13444 			ir_refs *found_inputs, *found_values;
13445 
13446 			ir_refs_init(found_inputs, 8);
13447 			ir_refs_init(found_values, 8);
13448 
13449 			var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13450 			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13451 				var_info |= MAY_BE_REF;
13452 			}
13453 			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13454 				var_info |= MAY_BE_RC1;
13455 			}
13456 
13457 			if (dim_type != IS_UNKNOWN
13458 			 && dim_type != IS_UNDEF
13459 			 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13460 			 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13461 			 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13462 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13463 				not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13464 				if (!not_found_exit_addr) {
13465 					return 0;
13466 				}
13467 			}
13468 
13469 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13470 					op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13471 					0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13472 				return 0;
13473 			}
13474 
13475 			if (found_inputs->count) {
13476 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
13477 				ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13478 				var_addr = ZEND_ADDR_REF_ZVAL(ref);
13479 
13480 				if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13481 					jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13482 					var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13483 				}
13484 				if (var_info & MAY_BE_REF) {
13485 					binary_op_type binary_op = get_binary_op(opline->extended_value);
13486 					ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13487 
13488 					ref = jit_ZVAL_ADDR(jit, var_addr);
13489 					if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13490 					ir_IF_FALSE(if_ref);
13491 					noref_path = ir_END();
13492 					ir_IF_TRUE(if_ref);
13493 
13494 					reference = jit_Z_PTR_ref(jit, ref);
13495 					ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13496 					if_typed = jit_if_TYPED_REF(jit, reference);
13497 					ir_IF_FALSE(if_typed);
13498 					ref_path = ir_END();
13499 					ir_IF_TRUE_cold(if_typed);
13500 
13501 					arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13502 					ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13503 						reference, arg2, ir_CONST_FC_FUNC(binary_op));
13504 
13505 					ir_END_list(end_inputs);
13506 
13507 					ir_MERGE_2(noref_path, ref_path);
13508 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
13509 					var_addr = ZEND_ADDR_REF_ZVAL(ref);
13510 				}
13511 			} else {
13512 				emit_fast_path = 0;
13513 			}
13514 		}
13515 
13516 		if (emit_fast_path) {
13517 			uint8_t val_op_type = (opline+1)->op1_type;
13518 
13519 			if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13520 				/* prevent FREE_OP in the helpers */
13521 				val_op_type = IS_CV;
13522 			}
13523 
13524 			switch (opline->extended_value) {
13525 				case ZEND_ADD:
13526 				case ZEND_SUB:
13527 				case ZEND_MUL:
13528 				case ZEND_DIV:
13529 					if (!zend_jit_math_helper(jit, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, op3_addr, op1_data_info, 0, var_addr, var_def_info, var_info,
13530 							1 /* may overflow */, may_throw)) {
13531 						return 0;
13532 					}
13533 					break;
13534 				case ZEND_BW_OR:
13535 				case ZEND_BW_AND:
13536 				case ZEND_BW_XOR:
13537 				case ZEND_SL:
13538 				case ZEND_SR:
13539 				case ZEND_MOD:
13540 					if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13541 							IS_CV, opline->op1, var_addr, var_info, NULL,
13542 							val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13543 							op1_data_range,
13544 							0, var_addr, var_def_info, var_info, may_throw)) {
13545 						return 0;
13546 					}
13547 					break;
13548 				case ZEND_CONCAT:
13549 					if (!zend_jit_concat_helper(jit, opline, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, op3_addr, op1_data_info, var_addr,
13550 							may_throw)) {
13551 						return 0;
13552 					}
13553 					break;
13554 				default:
13555 					ZEND_UNREACHABLE();
13556 			}
13557 
13558 			ir_END_list(end_inputs);
13559 		}
13560 	}
13561 
13562 	if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13563 		binary_op_type binary_op;
13564 		ir_ref arg2;
13565 
13566 		if (if_type) {
13567 			ir_IF_FALSE_cold(if_type);
13568 			if_type = IS_UNUSED;
13569 		}
13570 
13571 	    if (opline->op2_type == IS_UNUSED) {
13572 			arg2 = IR_NULL;
13573 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13574 			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13575 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13576 		} else {
13577 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13578 		}
13579 		binary_op = get_binary_op(opline->extended_value);
13580 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13581 			jit_ZVAL_ADDR(jit, op1_addr),
13582 			arg2,
13583 			jit_ZVAL_ADDR(jit, op3_addr),
13584 			ir_CONST_FC_FUNC(binary_op));
13585 		ir_END_list(end_inputs);
13586 	}
13587 
13588 	if (end_inputs) {
13589 		ir_MERGE_list(end_inputs);
13590 	}
13591 
13592 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13593 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13594 	if (!op1_indirect) {
13595 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
13596 	}
13597 	if (may_throw) {
13598 		zend_jit_check_exception(jit);
13599 	}
13600 
13601 	return 1;
13602 }
13603 
13604 static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13605 {
13606 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13607 
13608 	// JIT: ZVAL_COPY(res, value);
13609 	if (opline->op1_type == IS_CONST) {
13610 		zval *zv = RT_CONSTANT(opline, opline->op1);
13611 
13612 		jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
13613 	} else {
13614 		zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13615 
13616 		jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13617 	}
13618 
13619 	// JIT: Z_FE_POS_P(res) = 0;
13620 	ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13621 
13622 	return 1;
13623 }
13624 
13625 static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13626 {
13627 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13628 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13629 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13630 	ir_ref ref;
13631 
13632 	if (!exit_addr) {
13633 		return 0;
13634 	}
13635 
13636 	ref = ir_AND_U32(
13637 		ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
13638 		ir_CONST_U32(HASH_FLAG_PACKED));
13639 	if (op_info & MAY_BE_ARRAY_PACKED) {
13640 		ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13641 	} else {
13642 		ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
13643 	}
13644 
13645 	return 1;
13646 }
13647 
13648 static int zend_jit_fe_fetch(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, uint8_t exit_opcode, const void *exit_addr)
13649 {
13650 	zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13651 	ir_ref ref, ht_ref, hash_pos_ref, packed_pos_ref, hash_p_ref = IR_UNUSED, packed_p_ref = IR_UNUSED, if_packed = IR_UNUSED;
13652 	ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
13653 	ir_ref exit_inputs = IR_UNUSED;
13654 
13655 	if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
13656 		/* empty array */
13657 		if (exit_addr) {
13658 			if (exit_opcode == ZEND_JMP) {
13659 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13660 			}
13661 		} else {
13662 			zend_basic_block *bb;
13663 
13664 			ZEND_ASSERT(jit->b >= 0);
13665 			bb = &jit->ssa->cfg.blocks[jit->b];
13666 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
13667 			jit->b = -1;
13668 		}
13669 		return 1;
13670 	}
13671 
13672 	// JIT: array = EX_VAR(opline->op1.var);
13673 	// JIT: fe_ht = Z_ARRVAL_P(array);
13674 	ht_ref = jit_Z_PTR(jit, op1_addr);
13675 
13676 	if (op1_info & MAY_BE_PACKED_GUARD) {
13677 		if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
13678 			return 0;
13679 		}
13680 	}
13681 
13682 	// JIT: pos = Z_FE_POS_P(array);
13683 	hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
13684 
13685 	if (MAY_BE_HASH(op1_info)) {
13686 		ir_ref loop_ref, pos2_ref, p2_ref;
13687 
13688 		if (MAY_BE_PACKED(op1_info)) {
13689 			ref = ir_AND_U32(
13690 				ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
13691 				ir_CONST_U32(HASH_FLAG_PACKED));
13692 			if_packed = ir_IF(ref);
13693 			ir_IF_FALSE(if_packed);
13694 		}
13695 
13696 		// JIT: p = fe_ht->arData + pos;
13697 		if (sizeof(void*) == 8) {
13698 			ref = ir_ZEXT_A(hash_pos_ref);
13699 		} else {
13700 			ref = ir_BITCAST_A(hash_pos_ref);
13701 		}
13702 		hash_p_ref = ir_ADD_A(
13703 			ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
13704 			ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
13705 
13706 		loop_ref = ir_LOOP_BEGIN(ir_END());
13707 		hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
13708 		hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
13709 
13710 		// JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13711 		ref = ir_ULT(hash_pos_ref,
13712 			ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13713 
13714 		// JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13715 		// JIT: ZEND_VM_CONTINUE();
13716 
13717 		if (exit_addr) {
13718 			if (exit_opcode == ZEND_JMP) {
13719 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13720 			} else {
13721 				ir_ref if_fit = ir_IF(ref);
13722 				ir_IF_FALSE(if_fit);
13723 				ir_END_list(exit_inputs);
13724 				ir_IF_TRUE(if_fit);
13725 			}
13726 		} else {
13727 			ir_ref if_fit = ir_IF(ref);
13728 			ir_IF_FALSE(if_fit);
13729 			ir_END_list(exit_inputs);
13730 			ir_IF_TRUE(if_fit);
13731 		}
13732 
13733 		// JIT: pos++;
13734 		pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
13735 
13736 		// JIT: value_type = Z_TYPE_INFO_P(value);
13737 		// JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13738 		if (!exit_addr || exit_opcode == ZEND_JMP) {
13739 			if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
13740 			ir_IF_FALSE(if_def_hash);
13741 		} else {
13742 			ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
13743 		}
13744 
13745 		// JIT: p++;
13746 		p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
13747 
13748 		ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13749 		ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
13750 		ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
13751 
13752 		if (MAY_BE_PACKED(op1_info)) {
13753 			ir_IF_TRUE(if_packed);
13754 		}
13755 	}
13756 	if (MAY_BE_PACKED(op1_info)) {
13757 		ir_ref loop_ref, pos2_ref, p2_ref;
13758 
13759 		// JIT: p = fe_ht->arPacked + pos;
13760 		if (sizeof(void*) == 8) {
13761 			ref = ir_ZEXT_A(packed_pos_ref);
13762 		} else {
13763 			ref = ir_BITCAST_A(packed_pos_ref);
13764 		}
13765 		packed_p_ref = ir_ADD_A(
13766 			ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
13767 			ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
13768 
13769 		loop_ref = ir_LOOP_BEGIN(ir_END());
13770 		packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
13771 		packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
13772 
13773 		// JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13774 		ref = ir_ULT(packed_pos_ref,
13775 			ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13776 
13777 		// JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13778 		// JIT: ZEND_VM_CONTINUE();
13779 		if (exit_addr) {
13780 			if (exit_opcode == ZEND_JMP) {
13781 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13782 			} else {
13783 				ir_ref if_fit = ir_IF(ref);
13784 				ir_IF_FALSE(if_fit);
13785 				ir_END_list(exit_inputs);
13786 				ir_IF_TRUE(if_fit);
13787 			}
13788 		} else {
13789 			ir_ref if_fit = ir_IF(ref);
13790 			ir_IF_FALSE(if_fit);
13791 			ir_END_list(exit_inputs);
13792 			ir_IF_TRUE(if_fit);
13793 		}
13794 
13795 		// JIT: pos++;
13796 		pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
13797 
13798 		// JIT: value_type = Z_TYPE_INFO_P(value);
13799 		// JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13800 		if (!exit_addr || exit_opcode == ZEND_JMP) {
13801 			if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
13802 			ir_IF_FALSE(if_def_packed);
13803 		} else {
13804 			ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
13805 		}
13806 
13807 		// JIT: p++;
13808 		p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
13809 
13810 		ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13811 		ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
13812 		ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
13813 	}
13814 
13815 	if (!exit_addr || exit_opcode == ZEND_JMP) {
13816 		zend_jit_addr val_addr;
13817 		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
13818 		uint32_t val_info;
13819 		ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
13820 
13821 		if (RETURN_VALUE_USED(opline)) {
13822 			zend_jit_addr res_addr = RES_ADDR();
13823 
13824 			if (MAY_BE_HASH(op1_info)) {
13825 				ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
13826 
13827 				ZEND_ASSERT(if_def_hash);
13828 				ir_IF_TRUE(if_def_hash);
13829 
13830 				// JIT: Z_FE_POS_P(array) = pos + 1;
13831 				ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13832 					ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
13833 
13834 				if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13835 					key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
13836 				}
13837 				if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
13838 				 && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
13839 					// JIT: if (!p->key) {
13840 					if_key = ir_IF(key_ref);
13841 					ir_IF_TRUE(if_key);
13842 				}
13843 				if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13844 					ir_ref if_interned, interned_path;
13845 
13846 					// JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
13847 					jit_set_Z_PTR(jit, res_addr, key_ref);
13848 					ref = ir_AND_U32(
13849 						ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
13850 						ir_CONST_U32(IS_STR_INTERNED));
13851 					if_interned = ir_IF(ref);
13852 					ir_IF_TRUE(if_interned);
13853 
13854 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
13855 
13856 					interned_path = ir_END();
13857 					ir_IF_FALSE(if_interned);
13858 
13859 					jit_GC_ADDREF(jit, key_ref);
13860 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
13861 
13862 					ir_MERGE_WITH(interned_path);
13863 
13864 					if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13865 						key_path = ir_END();
13866 					}
13867 				}
13868 				if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13869 					if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13870 						ir_IF_FALSE(if_key);
13871 					}
13872 					// JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
13873 					ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
13874 					jit_set_Z_LVAL(jit, res_addr, ref);
13875 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13876 
13877 					if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13878 						ir_MERGE_WITH(key_path);
13879 					}
13880 				}
13881 				if (MAY_BE_PACKED(op1_info)) {
13882 					hash_path = ir_END();
13883 				} else {
13884 					p_ref = hash_p_ref;
13885 				}
13886 			}
13887 			if (MAY_BE_PACKED(op1_info)) {
13888 				ZEND_ASSERT(if_def_packed);
13889 				ir_IF_TRUE(if_def_packed);
13890 
13891 				// JIT: Z_FE_POS_P(array) = pos + 1;
13892 				ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13893 					ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
13894 
13895 				// JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
13896 				if (sizeof(zend_long) == 8) {
13897 					packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
13898 				} else {
13899 					packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
13900 				}
13901 				jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
13902 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13903 
13904 				if (MAY_BE_HASH(op1_info)) {
13905 					ir_MERGE_WITH(hash_path);
13906 					p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
13907 				} else {
13908 					p_ref = packed_p_ref;
13909 				}
13910 			}
13911 		} else {
13912 			ir_ref pos_ref = IR_UNUSED;
13913 
13914 			if (if_def_hash && if_def_packed) {
13915 				ir_IF_TRUE(if_def_hash);
13916 				ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
13917 				pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
13918 				p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
13919 			} else if (if_def_hash) {
13920 				ir_IF_TRUE(if_def_hash);
13921 				pos_ref = hash_pos_ref;
13922 				p_ref = hash_p_ref;
13923 			} else if (if_def_packed) {
13924 				ir_IF_TRUE(if_def_packed);
13925 				pos_ref = packed_pos_ref;
13926 				p_ref = packed_p_ref;
13927 			} else {
13928 				ZEND_UNREACHABLE();
13929 			}
13930 
13931 			// JIT: Z_FE_POS_P(array) = pos + 1;
13932 			ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13933 				ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
13934 		}
13935 
13936 		val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
13937 		if (val_info & MAY_BE_ARRAY) {
13938 			val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13939 		}
13940 		if (op1_info & MAY_BE_ARRAY_OF_REF) {
13941 			val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
13942 				MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13943 		} else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13944 			val_info |= MAY_BE_RC1 | MAY_BE_RCN;
13945 		}
13946 
13947 		val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
13948 		if (opline->op2_type == IS_CV) {
13949 			// JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
13950 			if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, 1)) {
13951 				return 0;
13952 			}
13953 		} else {
13954 			// JIT: ZVAL_COPY(res, value);
13955 			jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, 1);
13956 		}
13957 
13958 		if (!exit_addr) {
13959 			zend_basic_block *bb;
13960 
13961 			ZEND_ASSERT(jit->b >= 0);
13962 			bb = &jit->ssa->cfg.blocks[jit->b];
13963 			_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
13964 			ZEND_ASSERT(exit_inputs);
13965 			if (!jit->ctx.ir_base[exit_inputs].op2) {
13966 				ref = exit_inputs;
13967 			} else {
13968 				ir_MERGE_list(exit_inputs);
13969 				ref = ir_END();
13970 			}
13971 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
13972 			jit->b = -1;
13973 		}
13974 	} else {
13975 		ZEND_ASSERT(exit_inputs);
13976 		ir_MERGE_list(exit_inputs);
13977 	}
13978 
13979 	return 1;
13980 }
13981 
13982 static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
13983 {
13984 	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13985 	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13986 	ir_ref ref = jit_Z_PTR(jit, this_addr);
13987 
13988 	jit_set_Z_PTR(jit, var_addr, ref);
13989 	jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
13990 	jit_GC_ADDREF(jit, ref);
13991 
13992 	return 1;
13993 }
13994 
13995 static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
13996 {
13997 	if (!op_array->scope ||
13998 			(op_array->fn_flags & ZEND_ACC_STATIC) ||
13999 			((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) {
14000 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14001 			if (!JIT_G(current_frame) ||
14002 			    !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
14003 
14004 				zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14005 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14006 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14007 
14008 				if (!exit_addr) {
14009 					return 0;
14010 				}
14011 
14012 				jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
14013 
14014 				if (JIT_G(current_frame)) {
14015 					TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
14016 				}
14017 			}
14018 		} else {
14019 			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14020 			ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
14021 
14022 			ir_IF_FALSE_cold(if_object);
14023 			jit_SET_EX_OPLINE(jit, opline);
14024 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
14025 
14026 			ir_IF_TRUE(if_object);
14027 		}
14028 	}
14029 
14030 	if (!check_only) {
14031 		if (!zend_jit_load_this(jit, opline->result.var)) {
14032 			return 0;
14033 		}
14034 	}
14035 
14036 	return 1;
14037 }
14038 
14039 static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
14040 {
14041 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14042 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14043 
14044 	if (!exit_addr) {
14045 		return 0;
14046 	}
14047 
14048 	ir_GUARD(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce))), ir_CONST_ADDR(ce)),
14049 		ir_CONST_ADDR(exit_addr));
14050 
14051 	return 1;
14052 }
14053 
14054 static int zend_jit_fetch_obj(zend_jit_ctx         *jit,
14055                               const zend_op        *opline,
14056                               const zend_op_array  *op_array,
14057                               zend_ssa             *ssa,
14058                               const zend_ssa_op    *ssa_op,
14059                               uint32_t              op1_info,
14060                               zend_jit_addr         op1_addr,
14061                               bool                  op1_indirect,
14062                               zend_class_entry     *ce,
14063                               bool                  ce_is_instanceof,
14064                               bool                  on_this,
14065                               bool                  delayed_fetch_this,
14066                               bool                  op1_avoid_refcounting,
14067                               zend_class_entry     *trace_ce,
14068                               zend_jit_addr         res_addr,
14069                               uint8_t               prop_type,
14070                               int                   may_throw)
14071 {
14072 	zval *member;
14073 	zend_property_info *prop_info;
14074 	bool may_be_dynamic = 1;
14075 	zend_jit_addr prop_addr;
14076 	uint32_t res_info = RES_INFO();
14077 	ir_ref prop_type_ref = IR_UNUSED;
14078 	ir_ref obj_ref = IR_UNUSED;
14079 	ir_ref prop_ref = IR_UNUSED;
14080 	ir_ref end_inputs = IR_UNUSED;
14081 	ir_ref slow_inputs = IR_UNUSED;
14082 	ir_ref end_values = IR_UNUSED;
14083 
14084 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14085 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14086 
14087 	member = RT_CONSTANT(opline, opline->op2);
14088 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14089 	prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
14090 
14091 	if (on_this) {
14092 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14093 		obj_ref = jit_Z_PTR(jit, this_addr);
14094 	} else {
14095 		if (opline->op1_type == IS_VAR
14096 		 && opline->opcode == ZEND_FETCH_OBJ_W
14097 		 && (op1_info & MAY_BE_INDIRECT)
14098 		 && Z_REG(op1_addr) == ZREG_FP) {
14099 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14100 		}
14101 		if (op1_info & MAY_BE_REF) {
14102 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14103 		}
14104 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14105 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14106 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14107 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14108 
14109 				if (!exit_addr) {
14110 					return 0;
14111 				}
14112 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14113 			} else {
14114 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14115 
14116 				ir_IF_FALSE_cold(if_obj);
14117 				if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14118 					ir_ref op1_ref = IR_UNUSED;
14119 
14120 					jit_SET_EX_OPLINE(jit, opline);
14121 					if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
14122 						zend_jit_addr orig_op1_addr = OP1_ADDR();
14123 						ir_ref fast_path = IR_UNUSED;
14124 
14125 						if (op1_info & MAY_BE_ANY) {
14126 							ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
14127 							ir_IF_TRUE(if_def);
14128 							fast_path = ir_END();
14129 							ir_IF_FALSE_cold(if_def);
14130 						}
14131 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
14132 							ir_CONST_U32(opline->op1.var));
14133 						if (fast_path) {
14134 							ir_MERGE_WITH(fast_path);
14135 						}
14136 						op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
14137 					} else {
14138 						op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
14139 					}
14140 					if (opline->opcode == ZEND_FETCH_OBJ_W) {
14141 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
14142 							op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14143 						jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14144 					} else {
14145 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
14146 							op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14147 						jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14148 					}
14149 				} else {
14150 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14151 				}
14152 				ir_END_list(end_inputs);
14153 
14154 				ir_IF_TRUE(if_obj);
14155 			}
14156 		}
14157 		obj_ref = jit_Z_PTR(jit, op1_addr);
14158 	}
14159 
14160 	ZEND_ASSERT(obj_ref);
14161 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14162 		prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
14163 		if (prop_info) {
14164 			ce = trace_ce;
14165 			ce_is_instanceof = 0;
14166 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14167 				if (on_this && JIT_G(current_frame)
14168 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14169 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14170 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14171 					if (on_this && JIT_G(current_frame)) {
14172 						JIT_G(current_frame)->ce = ce;
14173 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14174 					}
14175 				} else {
14176 					return 0;
14177 				}
14178 				if (ssa->var_info && ssa_op->op1_use >= 0) {
14179 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14180 					ssa->var_info[ssa_op->op1_use].ce = ce;
14181 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14182 				}
14183 			}
14184 		}
14185 	}
14186 
14187 	if (!prop_info) {
14188 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14189 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14190 		ir_ref if_same = ir_IF(ir_EQ(ref,
14191 			ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14192 
14193 		ir_IF_FALSE_cold(if_same);
14194 		ir_END_list(slow_inputs);
14195 
14196 		ir_IF_TRUE(if_same);
14197 		ir_ref offset_ref = ir_LOAD_A(
14198 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14199 
14200 		may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array);
14201 		if (may_be_dynamic) {
14202 			ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14203 			if (opline->opcode == ZEND_FETCH_OBJ_W) {
14204 				ir_IF_TRUE_cold(if_dynamic);
14205 				ir_END_list(slow_inputs);
14206 			} else {
14207 				ir_IF_TRUE_cold(if_dynamic);
14208 				jit_SET_EX_OPLINE(jit, opline);
14209 
14210 				if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14211 					if (Z_MODE(res_addr) == IS_REG) {
14212 						ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
14213 							obj_ref, offset_ref);
14214 						ir_END_PHI_list(end_values, val_addr);
14215 					} else {
14216 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
14217 							obj_ref, offset_ref);
14218 						ir_END_list(end_inputs);
14219 					}
14220 				} else {
14221 					if (Z_MODE(res_addr) == IS_REG) {
14222 						ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
14223 							obj_ref, offset_ref);
14224 						ir_END_PHI_list(end_values, val_addr);
14225 					} else {
14226 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
14227 							obj_ref, offset_ref);
14228 						ir_END_list(end_inputs);
14229 					}
14230 				}
14231 			}
14232 			ir_IF_FALSE(if_dynamic);
14233 		}
14234 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14235 		prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
14236 		ir_ref if_def = ir_IF(prop_type_ref);
14237 		ir_IF_FALSE_cold(if_def);
14238 		ir_END_list(slow_inputs);
14239 		ir_IF_TRUE(if_def);
14240 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14241 		if (opline->opcode == ZEND_FETCH_OBJ_W
14242 		 && (!ce ||	ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
14243 			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14244 
14245 			ir_ref allowed_inputs = IR_UNUSED;
14246 			ir_ref forbidden_inputs = IR_UNUSED;
14247 
14248 			ir_ref prop_info_ref = ir_LOAD_A(
14249 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14250 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14251 
14252 			ir_IF_TRUE_cold(if_has_prop_info);
14253 
14254 			ir_ref prop_flags = ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags)));
14255 			ir_ref if_readonly_or_avis = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK)));
14256 
14257 			ir_IF_FALSE(if_readonly_or_avis);
14258 			ir_END_list(allowed_inputs);
14259 
14260 			ir_IF_TRUE_cold(if_readonly_or_avis);
14261 
14262 			ir_ref if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14263 			ir_IF_TRUE(if_readonly);
14264 			ir_END_list(forbidden_inputs);
14265 
14266 			ir_IF_FALSE(if_readonly);
14267 			ir_ref has_avis_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), prop_info_ref);
14268 			ir_ref if_avis_access = ir_IF(has_avis_access);
14269 			ir_IF_TRUE(if_avis_access);
14270 			ir_END_list(allowed_inputs);
14271 
14272 			ir_IF_FALSE(if_avis_access);
14273 			ir_END_list(forbidden_inputs);
14274 
14275 			ir_MERGE_list(forbidden_inputs);
14276 
14277 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14278 			ir_IF_TRUE(if_prop_obj);
14279 			ref = jit_Z_PTR(jit, prop_addr);
14280 			jit_GC_ADDREF(jit, ref);
14281 			jit_set_Z_PTR(jit, res_addr, ref);
14282 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14283 			ir_END_list(end_inputs);
14284 
14285 			ir_IF_FALSE_cold(if_prop_obj);
14286 
14287 			jit_SET_EX_OPLINE(jit, opline);
14288 			if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14289 			ir_IF_TRUE(if_readonly);
14290 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), prop_info_ref);
14291 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14292 			ir_END_list(end_inputs);
14293 
14294 			ir_IF_FALSE(if_readonly);
14295 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14296 				prop_info_ref, ir_CONST_ADDR("indirectly modify"));
14297 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14298 			ir_END_list(end_inputs);
14299 
14300 			ir_MERGE_list(allowed_inputs);
14301 
14302 			if (flags == ZEND_FETCH_DIM_WRITE) {
14303 				jit_SET_EX_OPLINE(jit, opline);
14304 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14305 					prop_ref, prop_info_ref);
14306 				ir_END_list(end_inputs);
14307 				ir_IF_FALSE(if_has_prop_info);
14308 			} else if (flags == ZEND_FETCH_REF) {
14309 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14310 					prop_ref,
14311 					prop_info_ref,
14312 					jit_ZVAL_ADDR(jit, res_addr));
14313 				ir_END_list(end_inputs);
14314 				ir_IF_FALSE(if_has_prop_info);
14315 			} else {
14316 				ZEND_ASSERT(flags == 0);
14317 				ir_MERGE_WITH_EMPTY_FALSE(if_has_prop_info);
14318 			}
14319 		}
14320 	} else {
14321 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14322 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14323 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14324 			if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14325 				/* perform IS_UNDEF check only after result type guard (during deoptimization) */
14326 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14327 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14328 
14329 				if (!exit_addr) {
14330 					return 0;
14331 				}
14332 				prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14333 				ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14334 			}
14335 		} else {
14336 			prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14337 			ir_ref if_def = ir_IF(prop_type_ref);
14338 			ir_IF_FALSE_cold(if_def);
14339 			ir_END_list(slow_inputs);
14340 			ir_IF_TRUE(if_def);
14341 		}
14342 		if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14343 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14344 			ir_IF_TRUE(if_prop_obj);
14345 			ir_ref ref = jit_Z_PTR(jit, prop_addr);
14346 			jit_GC_ADDREF(jit, ref);
14347 			jit_set_Z_PTR(jit, res_addr, ref);
14348 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14349 			ir_END_list(end_inputs);
14350 
14351 			ir_IF_FALSE_cold(if_prop_obj);
14352 			jit_SET_EX_OPLINE(jit, opline);
14353 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), ir_CONST_ADDR(prop_info));
14354 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14355 			ir_END_list(end_inputs);
14356 
14357 			goto result_fetched;
14358 		} else if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)) {
14359 			/* Readonly properties which are also asymmetric are never mutable indirectly, which is
14360 			 * handled by the previous branch. */
14361 			ir_ref has_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), ir_CONST_ADDR(prop_info));
14362 
14363 			ir_ref if_access = ir_IF(has_access);
14364 			ir_IF_FALSE_cold(if_access);
14365 
14366 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14367 			ir_IF_TRUE(if_prop_obj);
14368 			ir_ref ref = jit_Z_PTR(jit, prop_addr);
14369 			jit_GC_ADDREF(jit, ref);
14370 			jit_set_Z_PTR(jit, res_addr, ref);
14371 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14372 			ir_END_list(end_inputs);
14373 
14374 			ir_IF_FALSE_cold(if_prop_obj);
14375 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14376 				ir_CONST_ADDR(prop_info), ir_CONST_ADDR("indirectly modify"));
14377 			ir_END_list(end_inputs);
14378 
14379 			ir_IF_TRUE(if_access);
14380 		}
14381 
14382 		if (opline->opcode == ZEND_FETCH_OBJ_W
14383 		 && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
14384 		 && ZEND_TYPE_IS_SET(prop_info->type)) {
14385 			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14386 
14387 			if (flags == ZEND_FETCH_DIM_WRITE) {
14388 				if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14389 					if (!prop_type_ref) {
14390 						prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14391 					}
14392 					ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14393 					ir_IF_TRUE_cold(if_null_or_flase);
14394 					jit_SET_EX_OPLINE(jit, opline);
14395 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14396 						prop_ref, ir_CONST_ADDR(prop_info));
14397 					ir_END_list(end_inputs);
14398 					ir_IF_FALSE(if_null_or_flase);
14399 				}
14400 			} else if (flags == ZEND_FETCH_REF) {
14401 				ir_ref ref;
14402 
14403 				if (!prop_type_ref) {
14404 					prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14405 				}
14406 
14407 				ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14408 				ir_IF_FALSE(if_reference);
14409 				if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14410 					ref = ir_CONST_ADDR(prop_info);
14411 				} else {
14412 					int prop_info_offset =
14413 						(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14414 
14415 					ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14416 					ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14417 					ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14418 				}
14419 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14420 					prop_ref,
14421 					ref,
14422 					jit_ZVAL_ADDR(jit, res_addr));
14423 				ir_END_list(end_inputs);
14424 				ir_IF_TRUE(if_reference);
14425 			} else {
14426 				ZEND_UNREACHABLE();
14427 			}
14428 		}
14429 	}
14430 
14431 	if (opline->opcode == ZEND_FETCH_OBJ_W) {
14432 		ZEND_ASSERT(prop_ref);
14433 		jit_set_Z_PTR(jit, res_addr, prop_ref);
14434 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14435 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14436 			ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14437 		}
14438 		ir_END_list(end_inputs);
14439 	} else {
14440 		if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
14441 		 || Z_MODE(res_addr) == IS_REG) {
14442 			ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14443 		} else {
14444 			prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14445 
14446 			if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14447 				return 0;
14448 			}
14449 			ir_END_list(end_inputs);
14450 		}
14451 	}
14452 
14453 result_fetched:
14454 	if (op1_avoid_refcounting) {
14455 		SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14456 	}
14457 
14458 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14459 		ir_MERGE_list(slow_inputs);
14460 		jit_SET_EX_OPLINE(jit, opline);
14461 
14462 		if (opline->opcode == ZEND_FETCH_OBJ_W) {
14463 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14464 			ir_END_list(end_inputs);
14465 		} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14466 			if (Z_MODE(res_addr) == IS_REG) {
14467 				ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14468 				ir_END_PHI_list(end_values, val_ref);
14469 			} else {
14470 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14471 				ir_END_list(end_inputs);
14472 			}
14473 		} else {
14474 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14475 			ir_END_list(end_inputs);
14476 		}
14477 	}
14478 
14479 	if (end_values) {
14480 		ir_ref val_ref = ir_PHI_list(end_values);
14481 		zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14482 		bool result_avoid_refcounting = 0;
14483 
14484 		ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14485 			|| opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14486 			|| opline->opcode == ZEND_FETCH_OBJ_IS);
14487 		ZEND_ASSERT(end_inputs == IR_UNUSED);
14488 		if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14489 			uint8_t type = concrete_type(res_info);
14490 			uint32_t flags = 0;
14491 
14492 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14493 			 && !delayed_fetch_this
14494 			 && !op1_avoid_refcounting) {
14495 				flags = ZEND_JIT_EXIT_FREE_OP1;
14496 			}
14497 
14498 			if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14499 			 && !(flags & ZEND_JIT_EXIT_FREE_OP1)
14500 			 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
14501 			 && (ssa_op+1)->op1_use == ssa_op->result_def
14502 			 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14503 				result_avoid_refcounting = 1;
14504 				ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14505 			}
14506 
14507 			val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14508 				1, flags, op1_avoid_refcounting);
14509 			if (!val_addr) {
14510 				return 0;
14511 			}
14512 
14513 			res_info &= ~MAY_BE_GUARD;
14514 			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14515 		}
14516 
14517 		// ZVAL_COPY
14518 		jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14519 
14520 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14521 			return 0;
14522 		}
14523 	} else {
14524 		ir_MERGE_list(end_inputs);
14525 	}
14526 
14527 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14528 		if (opline->op1_type == IS_VAR
14529 		 && opline->opcode == ZEND_FETCH_OBJ_W
14530 		 && (op1_info & MAY_BE_RC1)) {
14531 			zend_jit_addr orig_op1_addr = OP1_ADDR();
14532 			ir_ref if_refcounted, ptr, refcount, if_non_zero;
14533 			ir_ref merge_inputs = IR_UNUSED;
14534 
14535 			if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14536 			ir_IF_FALSE( if_refcounted);
14537 			ir_END_list(merge_inputs);
14538 			ir_IF_TRUE( if_refcounted);
14539 			ptr = jit_Z_PTR(jit, orig_op1_addr);
14540 			refcount = jit_GC_DELREF(jit, ptr);
14541 			if_non_zero = ir_IF(refcount);
14542 			ir_IF_TRUE( if_non_zero);
14543 			ir_END_list(merge_inputs);
14544 			ir_IF_FALSE( if_non_zero);
14545 			jit_SET_EX_OPLINE(jit, opline);
14546 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14547 			ir_END_list(merge_inputs);
14548 			ir_MERGE_list(merge_inputs);
14549 		} else if (!op1_avoid_refcounting) {
14550 			if (on_this) {
14551 				op1_info &= ~MAY_BE_RC1;
14552 			}
14553 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14554 		}
14555 	}
14556 
14557 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14558 	 && prop_info
14559 	 && (opline->opcode != ZEND_FETCH_OBJ_W ||
14560 	     !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14561 	     !ZEND_TYPE_IS_SET(prop_info->type))
14562 	 && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14563 		may_throw = 0;
14564 	}
14565 
14566 	if (may_throw) {
14567 		zend_jit_check_exception(jit);
14568 	}
14569 
14570 	return 1;
14571 }
14572 
14573 static int zend_jit_assign_obj(zend_jit_ctx         *jit,
14574                                const zend_op        *opline,
14575                                const zend_op_array  *op_array,
14576                                zend_ssa             *ssa,
14577                                const zend_ssa_op    *ssa_op,
14578                                uint32_t              op1_info,
14579                                zend_jit_addr         op1_addr,
14580                                uint32_t              val_info,
14581                                zend_jit_addr         val_addr,
14582                                zend_jit_addr         val_def_addr,
14583                                zend_jit_addr         res_addr,
14584                                bool                  op1_indirect,
14585                                zend_class_entry     *ce,
14586                                bool                  ce_is_instanceof,
14587                                bool                  on_this,
14588                                bool                  delayed_fetch_this,
14589                                zend_class_entry     *trace_ce,
14590                                uint8_t               prop_type,
14591                                int                   may_throw)
14592 {
14593 	zval *member;
14594 	zend_string *name;
14595 	zend_property_info *prop_info;
14596 	zend_jit_addr prop_addr;
14597 	ir_ref obj_ref = IR_UNUSED;
14598 	ir_ref prop_ref = IR_UNUSED;
14599 	ir_ref delayed_end_input = IR_UNUSED;
14600 	ir_ref end_inputs = IR_UNUSED;
14601 	ir_ref slow_inputs = IR_UNUSED;
14602 	uint32_t res_info = RES_INFO();
14603 
14604 	if (val_addr != val_def_addr && val_def_addr) {
14605 		if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14606 			return 0;
14607 		}
14608 		if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14609 			val_addr = val_def_addr;
14610 		}
14611 	}
14612 
14613 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14614 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14615 
14616 	member = RT_CONSTANT(opline, opline->op2);
14617 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14618 	name = Z_STR_P(member);
14619 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14620 
14621 	if (on_this) {
14622 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14623 		obj_ref = jit_Z_PTR(jit, this_addr);
14624 	} else {
14625 		if (opline->op1_type == IS_VAR
14626 		 && (op1_info & MAY_BE_INDIRECT)
14627 		 && Z_REG(op1_addr) == ZREG_FP) {
14628 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14629 		}
14630 		if (op1_info & MAY_BE_REF) {
14631 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14632 		}
14633 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14634 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14635 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14636 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14637 
14638 				if (!exit_addr) {
14639 					return 0;
14640 				}
14641 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14642 			} else {
14643 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14644 				ir_IF_FALSE_cold(if_obj);
14645 
14646 				jit_SET_EX_OPLINE(jit, opline);
14647 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14648 					jit_ZVAL_ADDR(jit, op1_addr),
14649 					ir_CONST_ADDR(ZSTR_VAL(name)));
14650 
14651 				if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
14652 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14653 				}
14654 
14655 				ir_END_list(end_inputs);
14656 
14657 				ir_IF_TRUE(if_obj);
14658 			}
14659 		}
14660 		obj_ref = jit_Z_PTR(jit, op1_addr);
14661 	}
14662 
14663 	ZEND_ASSERT(obj_ref);
14664 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14665 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14666 		if (prop_info) {
14667 			ce = trace_ce;
14668 			ce_is_instanceof = 0;
14669 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14670 				if (on_this && JIT_G(current_frame)
14671 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14672 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14673 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14674 					if (on_this && JIT_G(current_frame)) {
14675 						JIT_G(current_frame)->ce = ce;
14676 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14677 					}
14678 				} else {
14679 					return 0;
14680 				}
14681 				if (ssa->var_info && ssa_op->op1_use >= 0) {
14682 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14683 					ssa->var_info[ssa_op->op1_use].ce = ce;
14684 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14685 				}
14686 				if (ssa->var_info && ssa_op->op1_def >= 0) {
14687 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14688 					ssa->var_info[ssa_op->op1_def].ce = ce;
14689 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14690 				}
14691 			}
14692 		}
14693 	}
14694 
14695 	if (!prop_info) {
14696 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14697 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14698 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14699 
14700 		ir_IF_FALSE_cold(if_same);
14701 		ir_END_list(slow_inputs);
14702 
14703 		ir_IF_TRUE(if_same);
14704 		ir_ref offset_ref = ir_LOAD_A(
14705 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14706 
14707 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14708 		ir_IF_TRUE_cold(if_dynamic);
14709 		ir_END_list(slow_inputs);
14710 
14711 		ir_IF_FALSE(if_dynamic);
14712 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14713 		ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14714 		ir_IF_FALSE_cold(if_def);
14715 		ir_END_list(slow_inputs);
14716 
14717 		ir_IF_TRUE(if_def);
14718 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14719 
14720 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14721 			ir_ref arg3, arg4;
14722 			ir_ref prop_info_ref = ir_LOAD_A(
14723 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14724 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14725 			ir_IF_TRUE_cold(if_has_prop_info);
14726 
14727 			if (Z_MODE(val_addr) == IS_REG) {
14728 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14729 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14730 					return 0;
14731 				}
14732 				arg3 = jit_ZVAL_ADDR(jit, real_addr);
14733 			} else {
14734 				arg3 = jit_ZVAL_ADDR(jit, val_addr);
14735 			}
14736 
14737 			if (!RETURN_VALUE_USED(opline)) {
14738 				arg4 = IR_NULL;
14739 			} else if (Z_MODE(res_addr) == IS_REG) {
14740 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14741 				arg4 = jit_ZVAL_ADDR(jit, real_addr);
14742 			} else {
14743 				arg4 = jit_ZVAL_ADDR(jit, res_addr);
14744 			}
14745 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14746 			jit_SET_EX_OPLINE(jit, opline);
14747 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14748 				prop_ref,
14749 				prop_info_ref,
14750 				arg3,
14751 				arg4);
14752 
14753 			if ((opline+1)->op1_type == IS_CONST) {
14754 				// TODO: ???
14755 				// if (Z_TYPE_P(value) == orig_type) {
14756 				// CACHE_PTR_EX(cache_slot + 2, NULL);
14757 			}
14758 
14759 			if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14760 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14761 				if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14762 					return 0;
14763 				}
14764 			}
14765 
14766 			ir_END_list(end_inputs);
14767 			ir_IF_FALSE(if_has_prop_info);
14768 		}
14769 	} else {
14770 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14771 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14772 		/* With the exception of __clone(), readonly assignment always happens on IS_UNDEF, doding
14773 		 * the fast path. Thus, the fast path is not useful. */
14774 		if (prop_info->flags & ZEND_ACC_READONLY) {
14775 			ZEND_ASSERT(slow_inputs == IR_UNUSED);
14776 			goto slow_path;
14777 		}
14778 		// Undefined property with potential magic __get()/__set() or lazy object
14779 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14780 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14781 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14782 
14783 			if (!exit_addr) {
14784 				return 0;
14785 			}
14786 			ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14787 		} else {
14788 			ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14789 			ir_IF_FALSE_cold(if_def);
14790 			ir_END_list(slow_inputs);
14791 			ir_IF_TRUE(if_def);
14792 		}
14793 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14794 			ir_ref ref, arg3, arg4;
14795 
14796 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14797 			jit_SET_EX_OPLINE(jit, opline);
14798 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14799 				ref = ir_CONST_ADDR(prop_info);
14800 			} else {
14801 				int prop_info_offset =
14802 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14803 
14804 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14805 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14806 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14807 			}
14808 			if (Z_MODE(val_addr) == IS_REG) {
14809 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14810 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14811 					return 0;
14812 				}
14813 				arg3 = jit_ZVAL_ADDR(jit, real_addr);
14814 			} else {
14815 				arg3 = jit_ZVAL_ADDR(jit, val_addr);
14816 			}
14817 			if (!RETURN_VALUE_USED(opline)) {
14818 				arg4 = IR_NULL;
14819 			} else if (Z_MODE(res_addr) == IS_REG) {
14820 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14821 				arg4 = jit_ZVAL_ADDR(jit, real_addr);
14822 			} else {
14823 				arg4 = jit_ZVAL_ADDR(jit, res_addr);
14824 			}
14825 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14826 				prop_ref,
14827 				ref,
14828 				arg3,
14829 				arg4);
14830 
14831 			if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14832 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14833 				if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14834 					return 0;
14835 				}
14836 			}
14837 			ir_END_list(end_inputs);
14838 		}
14839 	}
14840 
14841 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14842 		if (Z_MODE(val_addr) != IS_REG
14843 		 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
14844 		 && opline->result_type == IS_UNUSED) {
14845 			if (!zend_jit_assign_to_variable_call(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
14846 				return 0;
14847 			}
14848 		} else {
14849 			if (!zend_jit_assign_to_variable(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0, 0)) {
14850 				return 0;
14851 			}
14852 		}
14853 		if (end_inputs || slow_inputs) {
14854 			if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14855 			 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14856 				/* skip FREE_OP_DATA() */
14857 				delayed_end_input = ir_END();
14858 			} else {
14859 				ir_END_list(end_inputs);
14860 			}
14861 		}
14862 	}
14863 
14864 	if (slow_inputs) {
14865 		ir_ref arg3, arg5;
14866 
14867 		ir_MERGE_list(slow_inputs);
14868 
14869 slow_path:
14870 		jit_SET_EX_OPLINE(jit, opline);
14871 
14872 		if (Z_MODE(val_addr) == IS_REG) {
14873 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14874 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14875 				return 0;
14876 			}
14877 			arg3 = jit_ZVAL_ADDR(jit, real_addr);
14878 		} else {
14879 			arg3 = jit_ZVAL_ADDR(jit, val_addr);
14880 		}
14881 		if (!RETURN_VALUE_USED(opline)) {
14882 			arg5 = IR_NULL;
14883 		} else if (Z_MODE(res_addr) == IS_REG) {
14884 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14885 			arg5 = jit_ZVAL_ADDR(jit, real_addr);
14886 		} else {
14887 			arg5 = jit_ZVAL_ADDR(jit, res_addr);
14888 		}
14889 
14890 		// JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14891 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14892 		ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
14893 			obj_ref,
14894 			ir_CONST_ADDR(name),
14895 			arg3,
14896 			ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
14897 			arg5);
14898 
14899 		if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14900 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14901 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14902 				return 0;
14903 			}
14904 		}
14905 		ir_END_list(end_inputs);
14906 	}
14907 
14908 	if (end_inputs) {
14909 		ir_MERGE_list(end_inputs);
14910 
14911 		if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14912 			val_info |= MAY_BE_RC1|MAY_BE_RCN;
14913 		}
14914 		jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
14915 
14916 		if (delayed_end_input) {
14917 			ir_MERGE_WITH(delayed_end_input);
14918 		}
14919 	}
14920 
14921 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14922 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14923 	}
14924 
14925 	if (may_throw) {
14926 		zend_jit_check_exception(jit);
14927 	}
14928 
14929 	return 1;
14930 }
14931 
14932 static int zend_jit_assign_obj_op(zend_jit_ctx         *jit,
14933                                   const zend_op        *opline,
14934                                   const zend_op_array  *op_array,
14935                                   zend_ssa             *ssa,
14936                                   const zend_ssa_op    *ssa_op,
14937                                   uint32_t              op1_info,
14938                                   zend_jit_addr         op1_addr,
14939                                   uint32_t              val_info,
14940                                   zend_jit_addr         val_addr,
14941                                   zend_ssa_range       *val_range,
14942                                   bool                  op1_indirect,
14943                                   zend_class_entry     *ce,
14944                                   bool                  ce_is_instanceof,
14945                                   bool                  on_this,
14946                                   bool                  delayed_fetch_this,
14947                                   zend_class_entry     *trace_ce,
14948                                   uint8_t               prop_type)
14949 {
14950 	zval *member;
14951 	zend_string *name;
14952 	zend_property_info *prop_info;
14953 	zend_jit_addr prop_addr;
14954 	bool use_prop_guard = 0;
14955 	bool may_throw = 0;
14956 	binary_op_type binary_op = get_binary_op(opline->extended_value);
14957 	ir_ref obj_ref = IR_UNUSED;
14958 	ir_ref prop_ref = IR_UNUSED;
14959 	ir_ref end_inputs = IR_UNUSED;
14960 	ir_ref slow_inputs = IR_UNUSED;
14961 
14962 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14963 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14964 	ZEND_ASSERT(opline->result_type == IS_UNUSED);
14965 
14966 	member = RT_CONSTANT(opline, opline->op2);
14967 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14968 	name = Z_STR_P(member);
14969 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14970 
14971 	if (on_this) {
14972 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14973 		obj_ref = jit_Z_PTR(jit, this_addr);
14974 	} else {
14975 		if (opline->op1_type == IS_VAR
14976 		 && (op1_info & MAY_BE_INDIRECT)
14977 		 && Z_REG(op1_addr) == ZREG_FP) {
14978 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14979 		}
14980 		if (op1_info & MAY_BE_REF) {
14981 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14982 		}
14983 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14984 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14985 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14986 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14987 
14988 				if (!exit_addr) {
14989 					return 0;
14990 				}
14991 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14992 			} else {
14993 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14994 				ir_IF_FALSE_cold(if_obj);
14995 
14996 				jit_SET_EX_OPLINE(jit, opline);
14997 				ir_CALL_2(IR_VOID,
14998 					(op1_info & MAY_BE_UNDEF) ?
14999 						ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
15000 						ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
15001 					jit_ZVAL_ADDR(jit, op1_addr),
15002 					ir_CONST_ADDR(ZSTR_VAL(name)));
15003 
15004 				may_throw = 1;
15005 
15006 				ir_END_list(end_inputs);
15007 				ir_IF_TRUE(if_obj);
15008 			}
15009 		}
15010 		obj_ref = jit_Z_PTR(jit, op1_addr);
15011 	}
15012 
15013 	ZEND_ASSERT(obj_ref);
15014 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15015 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15016 		if (prop_info) {
15017 			ce = trace_ce;
15018 			ce_is_instanceof = 0;
15019 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15020 				if (on_this && JIT_G(current_frame)
15021 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15022 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15023 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15024 					if (on_this && JIT_G(current_frame)) {
15025 						JIT_G(current_frame)->ce = ce;
15026 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15027 					}
15028 				} else {
15029 					return 0;
15030 				}
15031 				if (ssa->var_info && ssa_op->op1_use >= 0) {
15032 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15033 					ssa->var_info[ssa_op->op1_use].ce = ce;
15034 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15035 				}
15036 				if (ssa->var_info && ssa_op->op1_def >= 0) {
15037 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15038 					ssa->var_info[ssa_op->op1_def].ce = ce;
15039 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15040 				}
15041 			}
15042 		}
15043 	}
15044 
15045 	use_prop_guard = (prop_type != IS_UNKNOWN
15046 		&& prop_type != IS_UNDEF
15047 		&& prop_type != IS_REFERENCE
15048 		&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15049 
15050 	if (!prop_info) {
15051 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15052 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15053 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15054 
15055 		ir_IF_FALSE_cold(if_same);
15056 		ir_END_list(slow_inputs);
15057 
15058 		ir_IF_TRUE(if_same);
15059 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15060 			ir_ref prop_info_ref = ir_LOAD_A(
15061 				ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15062 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15063 			ir_IF_TRUE_cold(if_has_prop_info);
15064 			ir_END_list(slow_inputs);
15065 
15066 			ir_IF_FALSE(if_has_prop_info);
15067 		}
15068 		ir_ref offset_ref = ir_LOAD_A(
15069 			ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15070 
15071 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15072 		ir_IF_TRUE_cold(if_dynamic);
15073 		ir_END_list(slow_inputs);
15074 
15075 		ir_IF_FALSE(if_dynamic);
15076 
15077 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
15078 		if (!use_prop_guard) {
15079 			ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15080 			ir_IF_FALSE_cold(if_def);
15081 			ir_END_list(slow_inputs);
15082 
15083 			ir_IF_TRUE(if_def);
15084 		}
15085 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15086 	} else {
15087 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15088 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15089 
15090 		if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15091 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15092 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15093 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15094 
15095 				if (!exit_addr) {
15096 					return 0;
15097 				}
15098 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15099 			} else {
15100 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15101 				ir_IF_FALSE_cold(if_def);
15102 				ir_END_list(slow_inputs);
15103 				ir_IF_TRUE(if_def);
15104 			}
15105 		}
15106 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
15107 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15108 
15109 			may_throw = 1;
15110 
15111 			jit_SET_EX_OPLINE(jit, opline);
15112 
15113 			if (Z_MODE(val_addr) == IS_REG) {
15114 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15115 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15116 					return 0;
15117 				}
15118 				arg2 = jit_ZVAL_ADDR(jit, real_addr);
15119 			} else {
15120 				arg2 = jit_ZVAL_ADDR(jit, val_addr);
15121 			}
15122 
15123 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15124 			ir_IF_FALSE(if_ref);
15125 			noref_path = ir_END();
15126 			ir_IF_TRUE(if_ref);
15127 
15128 			reference = jit_Z_PTR(jit, prop_addr);
15129 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15130 			if_typed = jit_if_TYPED_REF(jit, reference);
15131 			ir_IF_FALSE(if_typed);
15132 			ref_path = ir_END();
15133 			ir_IF_TRUE_cold(if_typed);
15134 
15135 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15136 				reference,
15137 				arg2,
15138 				ir_CONST_FC_FUNC(binary_op));
15139 
15140 			ir_END_list(end_inputs);
15141 
15142 			ir_MERGE_2(noref_path, ref_path);
15143 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15144 			prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15145 
15146 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15147 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15148 				ref = ir_CONST_ADDR(prop_info);
15149 			} else {
15150 				int prop_info_offset =
15151 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15152 
15153 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15154 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15155 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15156 			}
15157 
15158 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
15159 				prop_ref,
15160 				ref,
15161 				arg2,
15162 				ir_CONST_FC_FUNC(binary_op));
15163 
15164 			ir_END_list(end_inputs);
15165 		}
15166 	}
15167 
15168 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15169 		zend_jit_addr var_addr = prop_addr;
15170 		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15171 		uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15172 
15173 		if (use_prop_guard) {
15174 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15175 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15176 			if (!exit_addr) {
15177 				return 0;
15178 			}
15179 
15180 			jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15181 			var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15182 		}
15183 
15184 		if (var_info & MAY_BE_REF) {
15185 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15186 
15187 			may_throw = 1;
15188 
15189 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15190 			ir_IF_FALSE(if_ref);
15191 			noref_path = ir_END();
15192 			ir_IF_TRUE(if_ref);
15193 
15194 			reference = jit_Z_PTR(jit, var_addr);
15195 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15196 			if_typed = jit_if_TYPED_REF(jit, reference);
15197 			ir_IF_FALSE(if_typed);
15198 			ref_path = ir_END();
15199 			ir_IF_TRUE_cold(if_typed);
15200 
15201 			jit_SET_EX_OPLINE(jit, opline);
15202 
15203 			if (Z_MODE(val_addr) == IS_REG) {
15204 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15205 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15206 					return 0;
15207 				}
15208 				arg2 = jit_ZVAL_ADDR(jit, real_addr);
15209 			} else {
15210 				arg2 = jit_ZVAL_ADDR(jit, val_addr);
15211 			}
15212 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15213 				reference,
15214 				arg2,
15215 				ir_CONST_FC_FUNC(binary_op));
15216 
15217 			ir_END_list(end_inputs);
15218 
15219 			ir_MERGE_2(noref_path, ref_path);
15220 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15221 			var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15222 
15223 			var_info &= ~MAY_BE_REF;
15224 		}
15225 
15226 		uint8_t val_op_type = (opline+1)->op1_type;
15227 		if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
15228 			/* prevent FREE_OP in the helpers */
15229 			val_op_type = IS_CV;
15230 		}
15231 
15232 		switch (opline->extended_value) {
15233 			case ZEND_ADD:
15234 			case ZEND_SUB:
15235 			case ZEND_MUL:
15236 				if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15237 				    (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15238 					if (opline->extended_value != ZEND_ADD ||
15239 					    (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
15240 					    (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
15241 						may_throw = 1;
15242 					}
15243 				}
15244 				if (!zend_jit_math_helper(jit, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, val_addr, val_info, 0, var_addr, var_def_info, var_info,
15245 						1 /* may overflow */, 0)) {
15246 					return 0;
15247 				}
15248 				break;
15249 			case ZEND_BW_OR:
15250 			case ZEND_BW_AND:
15251 			case ZEND_BW_XOR:
15252 				if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15253 				    (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15254 					if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
15255 					    (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
15256 						may_throw = 1;
15257 					}
15258 				}
15259 				goto long_math;
15260 			case ZEND_SL:
15261 			case ZEND_SR:
15262 				if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15263 				    (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15264 					may_throw = 1;
15265 				}
15266 				if (val_op_type != IS_CONST ||
15267 				    Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15268 				    Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
15269 					may_throw = 1;
15270 				}
15271 				goto long_math;
15272 			case ZEND_MOD:
15273 				if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15274 				    (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15275 					may_throw = 1;
15276 				}
15277 				if (val_op_type != IS_CONST ||
15278 				    Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15279 				    Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
15280 					may_throw = 1;
15281 				}
15282 long_math:
15283 				if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
15284 						IS_CV, opline->op1, var_addr, var_info, NULL,
15285 						val_op_type, (opline+1)->op1, val_addr, val_info,
15286 						val_range,
15287 						0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
15288 					return 0;
15289 				}
15290 				break;
15291 			case ZEND_CONCAT:
15292 				may_throw = 1;
15293 				if (!zend_jit_concat_helper(jit, opline, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, val_addr, val_info, var_addr,
15294 						0)) {
15295 					return 0;
15296 				}
15297 				break;
15298 			default:
15299 				ZEND_UNREACHABLE();
15300 		}
15301 		if (end_inputs || slow_inputs) {
15302 			ir_END_list(end_inputs);
15303 		}
15304 	}
15305 
15306 	if (slow_inputs) {
15307 		ir_ref arg3;
15308 
15309 		ir_MERGE_list(slow_inputs);
15310 
15311 		may_throw = 1;
15312 
15313 		if (Z_MODE(val_addr) == IS_REG) {
15314 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15315 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15316 				return 0;
15317 			}
15318 			arg3 = jit_ZVAL_ADDR(jit, real_addr);
15319 		} else {
15320 			arg3 = jit_ZVAL_ADDR(jit, val_addr);
15321 		}
15322 		jit_SET_EX_OPLINE(jit, opline);
15323 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15324 		ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15325 			obj_ref,
15326 			ir_CONST_ADDR(name),
15327 			arg3,
15328 			ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15329 			ir_CONST_FC_FUNC(binary_op));
15330 
15331 		ir_END_list(end_inputs);
15332 	}
15333 
15334 	if (end_inputs) {
15335 		ir_MERGE_list(end_inputs);
15336 	}
15337 
15338 	if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15339 		val_info |= MAY_BE_RC1|MAY_BE_RCN;
15340 	}
15341 
15342 	// JIT: FREE_OP_DATA();
15343 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15344 
15345 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15346 		if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15347 			may_throw = 1;
15348 		}
15349 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15350 	}
15351 
15352 	if (may_throw) {
15353 		zend_jit_check_exception(jit);
15354 	}
15355 
15356 	return 1;
15357 }
15358 
15359 static int zend_jit_incdec_obj(zend_jit_ctx         *jit,
15360                                const zend_op        *opline,
15361                                const zend_op_array  *op_array,
15362                                zend_ssa             *ssa,
15363                                const zend_ssa_op    *ssa_op,
15364                                uint32_t              op1_info,
15365                                zend_jit_addr         op1_addr,
15366                                bool                  op1_indirect,
15367                                zend_class_entry     *ce,
15368                                bool                  ce_is_instanceof,
15369                                bool                  on_this,
15370                                bool                  delayed_fetch_this,
15371                                zend_class_entry     *trace_ce,
15372                                uint8_t               prop_type)
15373 {
15374 	zval *member;
15375 	zend_string *name;
15376 	zend_property_info *prop_info;
15377 	zend_jit_addr res_addr = 0;
15378 	zend_jit_addr prop_addr;
15379 	bool use_prop_guard = 0;
15380 	bool may_throw = 0;
15381 	uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15382 	ir_ref obj_ref = IR_UNUSED;
15383 	ir_ref prop_ref = IR_UNUSED;
15384 	ir_ref end_inputs = IR_UNUSED;
15385 	ir_ref slow_inputs = IR_UNUSED;
15386 
15387 	ZEND_ASSERT(opline->op2_type == IS_CONST);
15388 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15389 
15390 	if (opline->result_type != IS_UNUSED) {
15391 		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15392 	}
15393 
15394 	member = RT_CONSTANT(opline, opline->op2);
15395 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15396 	name = Z_STR_P(member);
15397 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15398 
15399 	if (on_this) {
15400 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15401 		obj_ref = jit_Z_PTR(jit, this_addr);
15402 	} else {
15403 		if (opline->op1_type == IS_VAR
15404 		 && (op1_info & MAY_BE_INDIRECT)
15405 		 && Z_REG(op1_addr) == ZREG_FP) {
15406 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15407 		}
15408 		if (op1_info & MAY_BE_REF) {
15409 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15410 		}
15411 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15412 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15413 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15414 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15415 
15416 				if (!exit_addr) {
15417 					return 0;
15418 				}
15419 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15420 			} else {
15421 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15422 				ir_IF_FALSE_cold(if_obj);
15423 
15424 				jit_SET_EX_OPLINE(jit, opline);
15425 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15426 					jit_ZVAL_ADDR(jit, op1_addr),
15427 					ir_CONST_ADDR(ZSTR_VAL(name)));
15428 
15429 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15430 				ir_IF_TRUE(if_obj);
15431 			}
15432 		}
15433 		obj_ref = jit_Z_PTR(jit, op1_addr);
15434 	}
15435 
15436 	ZEND_ASSERT(obj_ref);
15437 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15438 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15439 		if (prop_info) {
15440 			ce = trace_ce;
15441 			ce_is_instanceof = 0;
15442 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15443 				if (on_this && JIT_G(current_frame)
15444 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15445 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15446 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15447 					if (on_this && JIT_G(current_frame)) {
15448 						JIT_G(current_frame)->ce = ce;
15449 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15450 					}
15451 				} else {
15452 					return 0;
15453 				}
15454 				if (ssa->var_info && ssa_op->op1_use >= 0) {
15455 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15456 					ssa->var_info[ssa_op->op1_use].ce = ce;
15457 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15458 				}
15459 				if (ssa->var_info && ssa_op->op1_def >= 0) {
15460 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15461 					ssa->var_info[ssa_op->op1_def].ce = ce;
15462 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15463 				}
15464 			}
15465 		}
15466 	}
15467 
15468 	use_prop_guard = (prop_type != IS_UNKNOWN
15469 		&& prop_type != IS_UNDEF
15470 		&& prop_type != IS_REFERENCE
15471 		&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15472 
15473 	if (!prop_info) {
15474 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15475 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15476 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15477 
15478 		ir_IF_FALSE_cold(if_same);
15479 		ir_END_list(slow_inputs);
15480 
15481 		ir_IF_TRUE(if_same);
15482 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15483 			ir_ref prop_info_ref = ir_LOAD_A(
15484 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15485 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15486 			ir_IF_TRUE_cold(if_has_prop_info);
15487 			ir_END_list(slow_inputs);
15488 
15489 			ir_IF_FALSE(if_has_prop_info);
15490 		}
15491 		ir_ref offset_ref = ir_LOAD_A(
15492 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15493 
15494 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15495 		ir_IF_TRUE_cold(if_dynamic);
15496 		ir_END_list(slow_inputs);
15497 
15498 		ir_IF_FALSE(if_dynamic);
15499 
15500 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
15501 		if (!use_prop_guard) {
15502 			ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15503 			ir_IF_FALSE_cold(if_def);
15504 			ir_END_list(slow_inputs);
15505 
15506 			ir_IF_TRUE(if_def);
15507 		}
15508 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15509 	} else {
15510 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15511 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15512 
15513 		if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15514 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15515 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15516 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15517 
15518 				if (!exit_addr) {
15519 					return 0;
15520 				}
15521 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15522 			} else {
15523 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15524 				ir_IF_FALSE_cold(if_def);
15525 				ir_END_list(slow_inputs);
15526 				ir_IF_TRUE(if_def);
15527 			}
15528 		}
15529 
15530 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
15531 			const void *func;
15532 			ir_ref ref;
15533 
15534 			may_throw = 1;
15535 			jit_SET_EX_OPLINE(jit, opline);
15536 
15537 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15538 				ref = ir_CONST_ADDR(prop_info);
15539 			} else {
15540 				int prop_info_offset =
15541 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15542 
15543 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15544 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15545 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15546 			}
15547 
15548 			if (opline->result_type == IS_UNUSED) {
15549 				switch (opline->opcode) {
15550 					case ZEND_PRE_INC_OBJ:
15551 					case ZEND_POST_INC_OBJ:
15552 						func = zend_jit_inc_typed_prop;
15553 						break;
15554 					case ZEND_PRE_DEC_OBJ:
15555 					case ZEND_POST_DEC_OBJ:
15556 						func = zend_jit_dec_typed_prop;
15557 						break;
15558 					default:
15559 						ZEND_UNREACHABLE();
15560 				}
15561 
15562 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
15563 			} else {
15564 				switch (opline->opcode) {
15565 					case ZEND_PRE_INC_OBJ:
15566 						func = zend_jit_pre_inc_typed_prop;
15567 						break;
15568 					case ZEND_PRE_DEC_OBJ:
15569 						func = zend_jit_pre_dec_typed_prop;
15570 						break;
15571 					case ZEND_POST_INC_OBJ:
15572 						func = zend_jit_post_inc_typed_prop;
15573 						break;
15574 					case ZEND_POST_DEC_OBJ:
15575 						func = zend_jit_post_dec_typed_prop;
15576 						break;
15577 					default:
15578 						ZEND_UNREACHABLE();
15579 				}
15580 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func),
15581 					prop_ref,
15582 					ref,
15583 					jit_ZVAL_ADDR(jit, res_addr));
15584 			}
15585 			ir_END_list(end_inputs);
15586 		}
15587 	}
15588 
15589 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15590 		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15591 		zend_jit_addr var_addr = prop_addr;
15592 		ir_ref if_long = IR_UNUSED;
15593 		ir_ref if_overflow = IR_UNUSED;
15594 
15595 		if (use_prop_guard) {
15596 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15597 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15598 			if (!exit_addr) {
15599 				return 0;
15600 			}
15601 
15602 			jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15603 			var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15604 		}
15605 
15606 		if (var_info & MAY_BE_REF) {
15607 			const void *func;
15608 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
15609 
15610 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15611 			ir_IF_FALSE(if_ref);
15612 			noref_path = ir_END();
15613 			ir_IF_TRUE(if_ref);
15614 
15615 			reference = jit_Z_PTR(jit, var_addr);
15616 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15617 			if_typed = jit_if_TYPED_REF(jit, reference);
15618 			ir_IF_FALSE(if_typed);
15619 			ref_path = ir_END();
15620 			ir_IF_TRUE_cold(if_typed);
15621 
15622 			switch (opline->opcode) {
15623 				case ZEND_PRE_INC_OBJ:
15624 					func = zend_jit_pre_inc_typed_ref;
15625 					break;
15626 				case ZEND_PRE_DEC_OBJ:
15627 					func = zend_jit_pre_dec_typed_ref;
15628 					break;
15629 				case ZEND_POST_INC_OBJ:
15630 					func = zend_jit_post_inc_typed_ref;
15631 					break;
15632 				case ZEND_POST_DEC_OBJ:
15633 					func = zend_jit_post_dec_typed_ref;
15634 					break;
15635 				default:
15636 					ZEND_UNREACHABLE();
15637 			}
15638 
15639 			may_throw = 1;
15640 			jit_SET_EX_OPLINE(jit, opline);
15641 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func),
15642 				reference,
15643 				(opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15644 
15645 			ir_END_list(end_inputs);
15646 
15647 			ir_MERGE_2(noref_path, ref_path);
15648 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15649 			var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15650 
15651 			var_info &= ~MAY_BE_REF;
15652 		}
15653 
15654 		if (var_info & MAY_BE_LONG) {
15655 			ir_ref addr, ref;
15656 
15657 			if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15658 				if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
15659 				ir_IF_TRUE(if_long);
15660 			}
15661 
15662 			addr = jit_ZVAL_ADDR(jit, var_addr);
15663 			ref = ir_LOAD_L(addr);
15664 			if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15665 				if (opline->result_type != IS_UNUSED) {
15666 					jit_set_Z_LVAL(jit, res_addr, ref);
15667 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15668 				}
15669 			}
15670 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15671 				ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
15672 			} else {
15673 				ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
15674 			}
15675 
15676 			ir_STORE(addr, ref);
15677 			if_overflow = ir_IF(ir_OVERFLOW(ref));
15678 			ir_IF_FALSE(if_overflow);
15679 
15680 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
15681 				if (opline->result_type != IS_UNUSED) {
15682 					jit_set_Z_LVAL(jit, res_addr, ref);
15683 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15684 				}
15685 			}
15686 			ir_END_list(end_inputs);
15687 		}
15688 
15689 		if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15690 			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15691 				may_throw = 1;
15692 			}
15693 			if (if_long) {
15694 				ir_IF_FALSE_cold(if_long);
15695 			}
15696 			if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15697 				jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, 1);
15698 			}
15699 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15700 				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15701 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
15702 						jit_ZVAL_ADDR(jit, var_addr),
15703 						jit_ZVAL_ADDR(jit, res_addr));
15704 				} else {
15705 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function),
15706 						jit_ZVAL_ADDR(jit, var_addr));
15707 				}
15708 			} else {
15709 				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15710 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
15711 						jit_ZVAL_ADDR(jit, var_addr),
15712 						jit_ZVAL_ADDR(jit, res_addr));
15713 				} else {
15714 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function),
15715 						jit_ZVAL_ADDR(jit, var_addr));
15716 				}
15717 			}
15718 
15719 			ir_END_list(end_inputs);
15720 		}
15721 		if (var_info & MAY_BE_LONG) {
15722 			ir_IF_TRUE_cold(if_overflow);
15723 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15724 #if SIZEOF_ZEND_LONG == 4
15725 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
15726 				jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
15727 #else
15728 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
15729 #endif
15730 				jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15731 				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15732 #if SIZEOF_ZEND_LONG == 4
15733 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
15734 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
15735 #else
15736 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
15737 #endif
15738 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15739 				}
15740 			} else {
15741 #if SIZEOF_ZEND_LONG == 4
15742 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
15743 				jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
15744 #else
15745 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
15746 #endif
15747 				jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15748 				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15749 #if SIZEOF_ZEND_LONG == 4
15750 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
15751 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
15752 #else
15753 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
15754 #endif
15755 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15756 				}
15757 			}
15758 			if (opline->result_type != IS_UNUSED
15759 			 && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
15760 			 && prop_info
15761 			 && !ZEND_TYPE_IS_SET(prop_info->type)
15762 			 && (res_info & MAY_BE_GUARD)
15763 			 && (res_info & MAY_BE_LONG)) {
15764 				zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
15765 				uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
15766 				int32_t exit_point;
15767 				const void *exit_addr;
15768 
15769 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
15770 				exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15771 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15772 				if (!exit_addr) {
15773 					return 0;
15774 				}
15775 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
15776 				ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
15777 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15778 			} else {
15779 				ir_END_list(end_inputs);
15780 			}
15781 		}
15782 	}
15783 
15784 	if (slow_inputs) {
15785 		const void *func;
15786 
15787 		ir_MERGE_list(slow_inputs);
15788 
15789 		// JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
15790 		switch (opline->opcode) {
15791 			case ZEND_PRE_INC_OBJ:
15792 				func = zend_jit_pre_inc_obj_helper;
15793 				break;
15794 			case ZEND_PRE_DEC_OBJ:
15795 				func = zend_jit_pre_dec_obj_helper;
15796 				break;
15797 			case ZEND_POST_INC_OBJ:
15798 				func = zend_jit_post_inc_obj_helper;
15799 				break;
15800 			case ZEND_POST_DEC_OBJ:
15801 				func = zend_jit_post_dec_obj_helper;
15802 				break;
15803 			default:
15804 				ZEND_UNREACHABLE();
15805 		}
15806 
15807 		may_throw = 1;
15808 		jit_SET_EX_OPLINE(jit, opline);
15809 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15810 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func),
15811 			obj_ref,
15812 			ir_CONST_ADDR(name),
15813 			ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15814 			(opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15815 
15816 		ir_END_list(end_inputs);
15817 	}
15818 
15819 	if (end_inputs) {
15820 		ir_MERGE_list(end_inputs);
15821 	}
15822 
15823 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
15824 		if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15825 			may_throw = 1;
15826 		}
15827 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15828 	}
15829 
15830 	if (may_throw) {
15831 		zend_jit_check_exception(jit);
15832 	}
15833 
15834 	return 1;
15835 }
15836 
15837 static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
15838 {
15839 	zend_jit_addr res_addr = RES_ADDR();
15840 	uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
15841 	uint32_t flags;
15842 	ir_ref ref, ref2, if_cached, fast_path, cold_path, prop_info_ref, if_typed, if_def;
15843 	int fetch_type;
15844 	zend_property_info *known_prop_info = NULL;
15845 	zend_class_entry *ce;
15846 
15847 	ce = zend_get_known_class(op_array, opline, opline->op2_type, opline->op2);
15848 	if (ce) {
15849 		zval *zv = RT_CONSTANT(opline, opline->op1);
15850 		zend_string *prop_name;
15851 
15852 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
15853 		prop_name = Z_STR_P(zv);
15854 		zv = zend_hash_find(&ce->properties_info, prop_name);
15855 		if (zv) {
15856 			zend_property_info *prop_info = Z_PTR_P(zv);
15857 
15858 			if (prop_info->flags & ZEND_ACC_STATIC) {
15859 				if (prop_info->ce == op_array->scope
15860 				 || (prop_info->flags & ZEND_ACC_PUBLIC)
15861 				 || ((prop_info->flags & ZEND_ACC_PROTECTED)
15862 				  && op_array->scope
15863 				  && instanceof_function_slow(op_array->scope, prop_info->ce))) {
15864 					known_prop_info = prop_info;
15865 				}
15866 			}
15867 		}
15868 	}
15869 
15870 	switch (opline->opcode) {
15871 		case ZEND_FETCH_STATIC_PROP_R:
15872 		case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
15873 			fetch_type = BP_VAR_R;
15874 			break;
15875 		case ZEND_FETCH_STATIC_PROP_IS:
15876 			fetch_type = BP_VAR_IS;
15877 			break;
15878 		case ZEND_FETCH_STATIC_PROP_W:
15879 			fetch_type = BP_VAR_W;
15880 			break;
15881 		case ZEND_FETCH_STATIC_PROP_RW:
15882 			fetch_type = BP_VAR_RW;
15883 			break;
15884 		case ZEND_FETCH_STATIC_PROP_UNSET:
15885 			fetch_type = BP_VAR_UNSET;
15886 			break;
15887 		EMPTY_SWITCH_DEFAULT_CASE();
15888 	}
15889 
15890 	// JIT: result = CACHED_PTR(cache_slot + sizeof(void *));
15891 	ref = ir_LOAD_A(
15892 		ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*)));
15893 
15894 	// JIT: if (result)
15895 	if_cached = ir_IF(ref);
15896 	ir_IF_TRUE(if_cached);
15897 
15898 	if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW) {
15899 		if (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type)) {
15900 			ir_ref merge = IR_UNUSED;
15901 
15902 			// JIT: if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
15903 			if_typed = IR_UNUSED;
15904 			if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
15905 			ir_IF_FALSE_cold(if_def);
15906 			if (!known_prop_info) {
15907 				// JIT: if (ZEND_TYPE_IS_SET(property_info->type))
15908 				prop_info_ref = ir_LOAD_L(
15909 					ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
15910 				if_typed = ir_IF(ir_AND_U32(
15911 					ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
15912 					ir_CONST_U32(_ZEND_TYPE_MASK)));
15913 				ir_IF_FALSE(if_typed);
15914 				ir_END_list(merge);
15915 				ir_IF_TRUE(if_typed);
15916 			}
15917 			// JIT:	zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
15918 			//			ZSTR_VAL(property_info->ce->name),
15919 			//			zend_get_unmangled_property_name(property_info->name));
15920 			jit_SET_EX_OPLINE(jit, opline);
15921 			ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_uninit_static_prop));
15922 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
15923 
15924 			ir_IF_TRUE(if_def);
15925 			if (!known_prop_info) {
15926 				ir_END_list(merge);
15927 				ir_MERGE_list(merge);
15928 			}
15929 		}
15930 	} else if (fetch_type == BP_VAR_W) {
15931 		flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
15932 		if (flags && (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type))) {
15933 		    ir_ref merge = IR_UNUSED;
15934 
15935 			if (!known_prop_info) {
15936 				// JIT: if (ZEND_TYPE_IS_SET(property_info->type))
15937 				prop_info_ref = ir_LOAD_L(
15938 					ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
15939 				if_typed = ir_IF(ir_AND_U32(
15940 					ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
15941 					ir_CONST_U32(_ZEND_TYPE_MASK)));
15942 				ir_IF_FALSE(if_typed);
15943 				ir_END_list(merge);
15944 				ir_IF_TRUE(if_typed);
15945 			} else {
15946 				prop_info_ref = ir_CONST_ADDR(known_prop_info);
15947 			}
15948 
15949 			// JIT: zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
15950 			ir_ref if_ok = ir_IF(ir_CALL_5(IR_BOOL, ir_CONST_FUNC(zend_handle_fetch_obj_flags),
15951 				IR_NULL, ref, IR_NULL, prop_info_ref, ir_CONST_U32(flags)));
15952 			ir_IF_FALSE_cold(if_ok);
15953 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
15954 			ir_IF_TRUE(if_ok);
15955 			if (!known_prop_info) {
15956 				ir_END_list(merge);
15957 				ir_MERGE_list(merge);
15958 			}
15959 		}
15960 	}
15961 
15962 	fast_path = ir_END();
15963 
15964 	ir_IF_FALSE_cold(if_cached);
15965 	jit_SET_EX_OPLINE(jit, opline);
15966 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_fetch_static_property), jit_FP(jit), ir_CONST_I32(fetch_type));
15967 	zend_jit_check_exception_undef_result(jit, opline);
15968 	cold_path = ir_END();
15969 
15970 	ir_MERGE_2(fast_path, cold_path);
15971 	ref = ir_PHI_2(IR_ADDR, ref, ref2);
15972 
15973 	if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_IS) {
15974 		// JIT: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), result);
15975 		if (!zend_jit_zval_copy_deref(jit, res_addr, ZEND_ADDR_REF_ZVAL(ref),
15976 				jit_Z_TYPE_INFO_ref(jit, ref))) {
15977 			return 0;
15978 		}
15979 	} else {
15980 		// JIT: ZVAL_INDIRECT(EX_VAR(opline->result.var), result);
15981 		jit_set_Z_PTR(jit, res_addr, ref);
15982 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
15983 	}
15984 
15985 	return 1;
15986 }
15987 
15988 static int zend_jit_switch(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info)
15989 {
15990 	HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
15991 	const zend_op *next_opline = NULL;
15992 	ir_refs *slow_inputs;
15993 
15994 	ir_refs_init(slow_inputs, 8);
15995 
15996 	if (trace) {
15997 		ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
15998 		ZEND_ASSERT(trace->opline != NULL);
15999 		next_opline = trace->opline;
16000 	}
16001 
16002 	if (opline->op1_type == IS_CONST) {
16003 		zval *zv = RT_CONSTANT(opline, opline->op1);
16004 		zval *jump_zv = NULL;
16005 		int b;
16006 
16007 		if (opline->opcode == ZEND_SWITCH_LONG) {
16008 			if (Z_TYPE_P(zv) == IS_LONG) {
16009 				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16010 			}
16011 		} else if (opline->opcode == ZEND_SWITCH_STRING) {
16012 			if (Z_TYPE_P(zv) == IS_STRING) {
16013 				jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16014 			}
16015 		} else if (opline->opcode == ZEND_MATCH) {
16016 			if (Z_TYPE_P(zv) == IS_LONG) {
16017 				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16018 			} else if (Z_TYPE_P(zv) == IS_STRING) {
16019 				jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16020 			}
16021 		} else {
16022 			ZEND_UNREACHABLE();
16023 		}
16024 		if (next_opline) {
16025 			const zend_op *target;
16026 
16027 			if (jump_zv != NULL) {
16028 				target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
16029 			} else {
16030 				target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16031 			}
16032 			ZEND_ASSERT(target == next_opline);
16033 		} else {
16034 			if (jump_zv != NULL) {
16035 				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
16036 			} else {
16037 				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
16038 			}
16039 			_zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
16040 			jit->b = -1;
16041 		}
16042 	} else {
16043 		zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
16044 		uint32_t op1_info = OP1_INFO();
16045 		zend_jit_addr op1_addr = OP1_ADDR();
16046 		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16047 		const zend_op *target;
16048 		int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
16049 		int b;
16050 		int32_t exit_point;
16051 		const void *exit_addr;
16052 		const void *default_label = NULL;
16053 		zval *zv;
16054 
16055 		if (next_opline) {
16056 			if (next_opline != default_opline) {
16057 				exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
16058 				default_label = zend_jit_trace_get_exit_addr(exit_point);
16059 				if (!default_label) {
16060 					return 0;
16061 				}
16062 			}
16063 		}
16064 
16065 		if (opline->opcode == ZEND_SWITCH_LONG) {
16066 			if (op1_info & MAY_BE_LONG) {
16067 				const void *fallback_label = NULL;
16068 
16069 				if (next_opline) {
16070 					if (next_opline != opline + 1) {
16071 						exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16072 						fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16073 						if (!fallback_label) {
16074 							return 0;
16075 						}
16076 					}
16077 				}
16078 				if (op1_info & MAY_BE_REF) {
16079 					ir_ref ref, if_long, fast_path, ref2;
16080 
16081 					ref = jit_ZVAL_ADDR(jit, op1_addr);
16082 					if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16083 					ir_IF_TRUE(if_long);
16084 					fast_path = ir_END();
16085 					ir_IF_FALSE_cold(if_long);
16086 
16087 					// JIT: ZVAL_DEREF(op)
16088 					if (fallback_label) {
16089 						jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16090 					} else {
16091 						ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
16092 						ir_IF_FALSE_cold(if_ref);
16093 						ir_refs_add(slow_inputs, ir_END());
16094 						ir_IF_TRUE(if_ref);
16095 					}
16096 
16097 					ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16098 					op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16099 
16100 					if (fallback_label) {
16101 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16102 					} else {
16103 						if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16104 						ir_IF_FALSE_cold(if_long);
16105 						ir_refs_add(slow_inputs, ir_END());
16106 						ir_IF_TRUE(if_long);
16107 					}
16108 
16109 					ir_MERGE_2(fast_path, ir_END());
16110 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
16111 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16112 				} else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16113 					if (fallback_label) {
16114 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16115 					} else {
16116 						ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16117 						ir_IF_FALSE_cold(if_long);
16118 						ir_refs_add(slow_inputs, ir_END());
16119 						ir_IF_TRUE(if_long);
16120 					}
16121 				}
16122 				ir_ref ref = jit_Z_LVAL(jit, op1_addr);
16123 
16124 				if (!HT_IS_PACKED(jumptable)) {
16125 					ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16126 						ir_CONST_ADDR(jumptable), ref);
16127 					ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16128 					/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16129 					if (sizeof(Bucket) == 32) {
16130 						ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16131 					} else {
16132 						ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16133 					}
16134 				}
16135 				ref = ir_SWITCH(ref);
16136 
16137 				if (next_opline) {
16138 					ir_ref continue_list = IR_UNUSED;
16139 
16140 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16141 						ir_ref idx;
16142 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16143 
16144 						if (HT_IS_PACKED(jumptable)) {
16145 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
16146 						} else {
16147 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16148 						}
16149 						ir_CASE_VAL(ref, idx);
16150 						if (target == next_opline) {
16151 							ir_END_list(continue_list);
16152 						} else {
16153 							exit_point = zend_jit_trace_get_exit_point(target, 0);
16154 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16155 							if (!exit_addr) {
16156 								return 0;
16157 							}
16158 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16159 						}
16160 					} ZEND_HASH_FOREACH_END();
16161 
16162 					ir_CASE_DEFAULT(ref);
16163 					if (next_opline == default_opline) {
16164 						ir_END_list(continue_list);
16165 					} else {
16166 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16167 					}
16168 					if (continue_list) {
16169 						ir_MERGE_list(continue_list);
16170 					} else {
16171 						ZEND_ASSERT(slow_inputs->count);
16172 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16173 					}
16174 				} else {
16175 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16176 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16177 						b = ssa->cfg.map[target - op_array->opcodes];
16178 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16179 					} ZEND_HASH_FOREACH_END();
16180 
16181 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16182 					if (slow_inputs->count) {
16183 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16184 						_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16185 					}
16186 					jit->b = -1;
16187 				}
16188 			} else if (!next_opline) {
16189 				_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16190 				jit->b = -1;
16191 			}
16192 		} else if (opline->opcode == ZEND_SWITCH_STRING) {
16193 			if (op1_info & MAY_BE_STRING) {
16194 				const void *fallback_label = NULL;
16195 
16196 				if (next_opline) {
16197 					if (next_opline != opline + 1) {
16198 						exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16199 						fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16200 						if (!fallback_label) {
16201 							return 0;
16202 						}
16203 					}
16204 				}
16205 				if (op1_info & MAY_BE_REF) {
16206 					ir_ref ref, if_string, fast_path, ref2;
16207 
16208 					ref = jit_ZVAL_ADDR(jit, op1_addr);
16209 					if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16210 					ir_IF_TRUE(if_string);
16211 					fast_path = ir_END();
16212 					ir_IF_FALSE_cold(if_string);
16213 
16214 					// JIT: ZVAL_DEREF(op)
16215 					if (fallback_label) {
16216 						jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16217 					} else {
16218 						ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16219 						ir_IF_FALSE_cold(if_ref);
16220 						ir_refs_add(slow_inputs, ir_END());
16221 						ir_IF_TRUE(if_ref);
16222 					}
16223 
16224 					ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16225 					op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16226 
16227 					if (fallback_label) {
16228 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16229 					} else {
16230 						if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16231 						ir_IF_FALSE_cold(if_string);
16232 						ir_refs_add(slow_inputs, ir_END());
16233 						ir_IF_TRUE(if_string);
16234 					}
16235 
16236 					ir_MERGE_2(fast_path, ir_END());
16237 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
16238 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16239 				} else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
16240 					if (fallback_label) {
16241 						jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
16242 					} else {
16243 						ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16244 						ir_IF_FALSE_cold(if_string);
16245 						ir_refs_add(slow_inputs, ir_END());
16246 						ir_IF_TRUE(if_string);
16247 					}
16248 				}
16249 
16250 				ir_ref ref = jit_Z_PTR(jit, op1_addr);
16251 				ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16252 					ir_CONST_ADDR(jumptable), ref);
16253 				ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16254 				/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16255 				if (sizeof(Bucket) == 32) {
16256 					ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16257 				} else {
16258 					ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16259 				}
16260 				ref = ir_SWITCH(ref);
16261 
16262 				if (next_opline) {
16263 					ir_ref continue_list = IR_UNUSED;
16264 
16265 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16266 						ir_ref idx;
16267 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16268 
16269 						if (HT_IS_PACKED(jumptable)) {
16270 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
16271 						} else {
16272 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16273 						}
16274 						ir_CASE_VAL(ref, idx);
16275 						if (target == next_opline) {
16276 							ir_END_list(continue_list);
16277 						} else {
16278 							exit_point = zend_jit_trace_get_exit_point(target, 0);
16279 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16280 							if (!exit_addr) {
16281 								return 0;
16282 							}
16283 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16284 						}
16285 					} ZEND_HASH_FOREACH_END();
16286 
16287 					ir_CASE_DEFAULT(ref);
16288 					if (next_opline == default_opline) {
16289 						ir_END_list(continue_list);
16290 					} else {
16291 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16292 					}
16293 					if (continue_list) {
16294 						ir_MERGE_list(continue_list);
16295 					} else {
16296 						ZEND_ASSERT(slow_inputs->count);
16297 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16298 					}
16299 				} else {
16300 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16301 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16302 						b = ssa->cfg.map[target - op_array->opcodes];
16303 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16304 					} ZEND_HASH_FOREACH_END();
16305 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16306 					if (slow_inputs->count) {
16307 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16308 						_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16309 					}
16310 					jit->b = -1;
16311 				}
16312 			} else if (!next_opline) {
16313 				_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16314 				jit->b = -1;
16315 			}
16316 		} else if (opline->opcode == ZEND_MATCH) {
16317 			ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
16318 			ir_ref continue_list = IR_UNUSED;
16319 
16320 			if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
16321 				ir_ref long_path = IR_UNUSED;
16322 
16323 				if (op1_info & MAY_BE_REF) {
16324 					op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
16325 				}
16326 				if (op1_info & MAY_BE_LONG) {
16327 					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16328 						if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
16329 							if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16330 							ir_IF_TRUE(if_type);
16331 						} else if (default_label) {
16332 							jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
16333 						} else if (next_opline) {
16334 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16335 							ir_IF_FALSE(if_type);
16336 							ir_END_list(continue_list);
16337 							ir_IF_TRUE(if_type);
16338 						} else {
16339 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16340 							ir_IF_FALSE(if_type);
16341 							ir_END_list(default_input_list);
16342 							ir_IF_TRUE(if_type);
16343 						}
16344 					}
16345 					ref = jit_Z_LVAL(jit, op1_addr);
16346 					ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16347 						ir_CONST_ADDR(jumptable), ref);
16348 					if (op1_info & MAY_BE_STRING) {
16349 						long_path = ir_END();
16350 					}
16351 				}
16352 				if (op1_info & MAY_BE_STRING) {
16353 					if (if_type) {
16354 						ir_IF_FALSE(if_type);
16355 						if_type = IS_UNUSED;
16356 					}
16357 					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
16358 						if (op1_info & MAY_BE_UNDEF) {
16359 							if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16360 							ir_IF_TRUE(if_type);
16361 						} else if (default_label) {
16362 							jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
16363 						} else if (next_opline) {
16364 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16365 							ir_IF_FALSE(if_type);
16366 							ir_END_list(continue_list);
16367 							ir_IF_TRUE(if_type);
16368 						} else {
16369 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16370 							ir_IF_FALSE(if_type);
16371 							ir_END_list(default_input_list);
16372 							ir_IF_TRUE(if_type);
16373 						}
16374 					}
16375 					ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
16376 					ref2 = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16377 						ir_CONST_ADDR(jumptable), ref2);
16378 					if (op1_info & MAY_BE_LONG) {
16379 						ir_MERGE_WITH(long_path);
16380 						ref = ir_PHI_2(IR_LONG, ref2, ref);
16381 					} else {
16382 						ref = ref2;
16383 					}
16384 				}
16385 
16386 				ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16387 				/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16388 				if (HT_IS_PACKED(jumptable)) {
16389 					ZEND_ASSERT(sizeof(zval) == 16);
16390 					ref = ir_SHR_L(ref, ir_CONST_LONG(4));
16391 				} else {
16392 					if (sizeof(Bucket) == 32) {
16393 						ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16394 					} else {
16395 						ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16396 					}
16397 				}
16398 				ref = ir_SWITCH(ref);
16399 
16400 				if (next_opline) {
16401 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16402 						ir_ref idx;
16403 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16404 
16405 						if (HT_IS_PACKED(jumptable)) {
16406 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
16407 						} else {
16408 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16409 						}
16410 						ir_CASE_VAL(ref, idx);
16411 						if (target == next_opline) {
16412 							ir_END_list(continue_list);
16413 						} else {
16414 							exit_point = zend_jit_trace_get_exit_point(target, 0);
16415 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16416 							if (!exit_addr) {
16417 								return 0;
16418 							}
16419 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16420 						}
16421 					} ZEND_HASH_FOREACH_END();
16422 
16423 					ir_CASE_DEFAULT(ref);
16424 					if (next_opline == default_opline) {
16425 						ir_END_list(continue_list);
16426 					} else {
16427 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16428 					}
16429 				} else {
16430 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16431 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16432 						b = ssa->cfg.map[target - op_array->opcodes];
16433 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16434 					} ZEND_HASH_FOREACH_END();
16435 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16436 				}
16437 			} else if (!(op1_info & MAY_BE_UNDEF)) {
16438 				if (next_opline) {
16439 					if (next_opline == default_opline) {
16440 						ir_END_list(continue_list);
16441 					} else {
16442 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16443 					}
16444 				} else {
16445 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16446 				}
16447 			}
16448 
16449 			if (op1_info & MAY_BE_UNDEF) {
16450 				if (if_type) {
16451 					ir_IF_FALSE(if_type);
16452 					if_type = IS_UNUSED;
16453 				}
16454 				if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16455 					if (default_label) {
16456 						jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16457 					} else if (next_opline) {
16458 						ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16459 						ir_IF_TRUE(if_def);
16460 						ir_END_list(continue_list);
16461 						ir_IF_FALSE_cold(if_def);
16462 					} else {
16463 						ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16464 						ir_IF_TRUE(if_def);
16465 						ir_END_list(default_input_list);
16466 						ir_IF_FALSE_cold(if_def);
16467 					}
16468 				}
16469 
16470 				jit_SET_EX_OPLINE(jit, opline);
16471 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16472 					ir_CONST_U32(opline->op1.var));
16473 				zend_jit_check_exception_undef_result(jit, opline);
16474 				if (default_label) {
16475 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16476 				} else if (next_opline) {
16477 					ir_END_list(continue_list);
16478 				} else {
16479 					ir_END_list(default_input_list);
16480 				}
16481 			}
16482 			if (next_opline) {
16483 				ZEND_ASSERT(continue_list);
16484 				ir_MERGE_list(continue_list);
16485 			} else {
16486 				if (default_input_list) {
16487 					if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16488 						ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16489 						jit->ctx.ir_base[ref].op3 = default_input_list;
16490 					} else {
16491 						ir_MERGE_list(default_input_list);
16492 						_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16493 					}
16494 				}
16495 				jit->b = -1;
16496 			}
16497 		} else {
16498 			ZEND_UNREACHABLE();
16499 		}
16500 	}
16501 	return 1;
16502 }
16503 
16504 static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16505 {
16506 	int i, count;
16507 	zend_basic_block *bb;
16508 
16509 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : (IR_START_BR_TARGET|IR_ENTRY_BR_TARGET));
16510 
16511 	jit->ctx.spill_base = ZREG_FP;
16512 
16513 	jit->op_array = jit->current_op_array = op_array;
16514 	jit->ssa = ssa;
16515 	jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16516 	jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16517 
16518 	count = 0;
16519 	for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
16520 		jit->bb_predecessors[i] = count;
16521 		count += bb->predecessors_count;
16522 	}
16523 	jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
16524 
16525 	if (!GCC_GLOBAL_REGS) {
16526 		ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16527 		jit_STORE_FP(jit, ref);
16528 		jit->ctx.flags |= IR_FASTCALL_FUNC;
16529 	}
16530 
16531 	return 1;
16532 }
16533 
16534 static void *zend_jit_finish(zend_jit_ctx *jit)
16535 {
16536 	void *entry;
16537 	size_t size;
16538 	zend_string *str = NULL;
16539 
16540 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP|
16541 			ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_SCCP|
16542 			ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS|ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
16543 		if (jit->name) {
16544 			str = zend_string_copy(jit->name);
16545 		} else {
16546 			str = zend_jit_func_name(jit->op_array);
16547 		}
16548 	}
16549 
16550 	if (jit->op_array) {
16551 		/* Only for function JIT */
16552 		_zend_jit_fix_merges(jit);
16553 #if defined(IR_TARGET_AARCH64)
16554 	} else if (jit->trace) {
16555 		jit->ctx.deoptimization_exits = jit->trace->exit_count;
16556 		jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
16557 #endif
16558 	} else {
16559 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
16560 		jit->ctx.flags |= IR_GEN_CACHE_DEMOTE;
16561 #endif
16562 	}
16563 
16564 	entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
16565 	if (entry) {
16566 		if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16567 #ifdef HAVE_CAPSTONE
16568 			if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16569 				if (str) {
16570 					ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
16571 				}
16572 				ir_disasm(str ? ZSTR_VAL(str) : "unknown",
16573 					entry, size,
16574 					(JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0,
16575 					&jit->ctx, stderr);
16576 			}
16577 #endif
16578 #ifndef _WIN32
16579 			if (str) {
16580 				if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
16581 					uintptr_t sp_offset = 0;
16582 
16583 //					ir_mem_unprotect(entry, size);
16584 					if (!(jit->ctx.flags & IR_FUNCTION)
16585 					 && zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16586 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
16587 						sp_offset = zend_jit_hybrid_vm_sp_adj;
16588 #else
16589 						sp_offset = sizeof(void*);
16590 #endif
16591 					} else {
16592 						sp_offset = sizeof(void*);
16593 					}
16594 					ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
16595 //					ir_mem_protect(entry, size);
16596 				}
16597 
16598 				if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16599 					ir_perf_map_register(ZSTR_VAL(str), entry, size);
16600 					if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
16601 						ir_perf_jitdump_register(ZSTR_VAL(str), entry, size);
16602 					}
16603 				}
16604 			}
16605 #endif
16606 		}
16607 
16608 		if (jit->op_array) {
16609 			/* Only for function JIT */
16610 			const zend_op_array *op_array = jit->op_array;
16611 			zend_op *opline = (zend_op*)op_array->opcodes;
16612 
16613 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
16614 				while (opline->opcode == ZEND_RECV) {
16615 					opline++;
16616 				}
16617 			}
16618 			opline->handler = entry;
16619 
16620 			if (jit->ctx.entries_count) {
16621 				/* For all entries */
16622 				int i = jit->ctx.entries_count;
16623 				do {
16624 					ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
16625 					op_array->opcodes[insn->op2].handler = (char*)entry + insn->op3;
16626 				} while (i != 0);
16627 			}
16628 		} else {
16629 			/* Only for tracing JIT */
16630 			zend_jit_trace_info *t = jit->trace;
16631 			zend_jit_trace_stack *stack;
16632 			uint32_t i;
16633 
16634 			if (t) {
16635 				for (i = 0; i < t->stack_map_size; i++) {
16636 					stack = t->stack_map + i;
16637 					if (stack->flags & ZREG_SPILL_SLOT) {
16638 						stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
16639 						stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
16640 					}
16641 				}
16642 			}
16643 
16644 			zend_jit_trace_add_code(entry, size);
16645 		}
16646 	}
16647 
16648 	if (str) {
16649 		zend_string_release(str);
16650 	}
16651 
16652 	return entry;
16653 }
16654 
16655 static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
16656 {
16657 	const void *entry;
16658 	size_t size;
16659 	ir_code_buffer code_buffer;
16660 
16661 	code_buffer.start = dasm_buf;
16662 	code_buffer.end = dasm_end;
16663 	code_buffer.pos = *dasm_ptr;
16664 
16665 	entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
16666 		&code_buffer, &size);
16667 
16668 	*dasm_ptr = code_buffer.pos;
16669 
16670 	if (entry) {
16671 #ifdef HAVE_CAPSTONE
16672 		if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16673 			uint32_t i;
16674 			char name[32];
16675 
16676 			for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
16677 				snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
16678 				ir_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
16679 			}
16680 		}
16681 #endif
16682 	}
16683 
16684 	return entry;
16685 }
16686 
16687 static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
16688 {
16689 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16690 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16691 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16692 
16693 	if (!exit_addr) {
16694 		return 0;
16695 	}
16696 	ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
16697 
16698 	return 1;
16699 }
16700 
16701 static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
16702 {
16703 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16704 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16705 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16706 
16707 	if (!exit_addr) {
16708 		return 0;
16709 	}
16710 	ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
16711 
16712 	return 1;
16713 }
16714 
16715 static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
16716 {
16717 	uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16718 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16719 
16720 	if (!exit_addr) {
16721 		return 0;
16722 	}
16723 	ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16724 
16725 	return 1;
16726 }
16727 
16728 static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
16729 {
16730 	uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
16731 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16732 
16733 	if (!exit_addr) {
16734 		return 0;
16735 	}
16736 
16737 	ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
16738 	zend_jit_set_last_valid_opline(jit, opline);
16739 
16740 	return 1;
16741 }
16742 
16743 static bool zend_jit_guard_reference(zend_jit_ctx  *jit,
16744                                      const zend_op *opline,
16745                                      zend_jit_addr *var_addr_ptr,
16746                                      zend_jit_addr *ref_addr_ptr,
16747                                      bool           add_ref_guard)
16748 {
16749 	zend_jit_addr var_addr = *var_addr_ptr;
16750 	const void *exit_addr = NULL;
16751 	ir_ref ref;
16752 
16753 	if (add_ref_guard) {
16754 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16755 
16756 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16757 		if (!exit_addr) {
16758 			return 0;
16759 		}
16760 
16761 		ref = jit_Z_TYPE(jit, var_addr);
16762 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16763 	}
16764 
16765 	ref = jit_Z_PTR(jit, var_addr);
16766 	*ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
16767 	ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16768 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
16769 	*var_addr_ptr = var_addr;
16770 
16771 	return 1;
16772 }
16773 
16774 static bool zend_jit_fetch_reference(zend_jit_ctx  *jit,
16775                                      const zend_op *opline,
16776                                      uint8_t        var_type,
16777                                      uint32_t      *var_info_ptr,
16778                                      zend_jit_addr *var_addr_ptr,
16779                                      bool           add_ref_guard,
16780                                      bool           add_type_guard)
16781 {
16782 	zend_jit_addr var_addr = *var_addr_ptr;
16783 	uint32_t var_info = *var_info_ptr;
16784 	const void *exit_addr = NULL;
16785 	ir_ref ref;
16786 
16787 	if (add_ref_guard || add_type_guard) {
16788 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16789 
16790 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16791 		if (!exit_addr) {
16792 			return 0;
16793 		}
16794 	}
16795 
16796 	if (add_ref_guard) {
16797 		ref = jit_Z_TYPE(jit, var_addr);
16798 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16799 	}
16800 	if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
16801 		/* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
16802 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
16803 			jit_ZVAL_ADDR(jit, var_addr));
16804 		*var_addr_ptr = var_addr;
16805 	} else {
16806 		ref = jit_Z_PTR(jit, var_addr);
16807 		ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16808 		var_addr = ZEND_ADDR_REF_ZVAL(ref);
16809 		*var_addr_ptr = var_addr;
16810 	}
16811 
16812 	if (var_type != IS_UNKNOWN) {
16813 		var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16814 	}
16815 	if (add_type_guard
16816 	 && var_type != IS_UNKNOWN
16817 	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16818 		ref = jit_Z_TYPE(jit, var_addr);
16819 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
16820 
16821 		ZEND_ASSERT(var_info & (1 << var_type));
16822 		if (var_type < IS_STRING) {
16823 			var_info = (1 << var_type);
16824 		} else if (var_type != IS_ARRAY) {
16825 			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16826 		} else {
16827 			var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
16828 		}
16829 
16830 		*var_info_ptr = var_info;
16831 	} else {
16832 		var_info &= ~MAY_BE_REF;
16833 		*var_info_ptr = var_info;
16834 	}
16835 	*var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
16836 
16837 	return 1;
16838 }
16839 
16840 static bool zend_jit_fetch_indirect_var(zend_jit_ctx *jit, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_indirect_guard)
16841 {
16842 	zend_jit_addr var_addr = *var_addr_ptr;
16843 	uint32_t var_info = *var_info_ptr;
16844 	int32_t exit_point;
16845 	const void *exit_addr;
16846 	ir_ref ref = IR_UNUSED;
16847 
16848 	if (add_indirect_guard) {
16849 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16850 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16851 
16852 		if (!exit_addr) {
16853 			return 0;
16854 		}
16855 		jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
16856 		ref = jit_Z_PTR(jit, var_addr);
16857 	} else {
16858 		/* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
16859 		 * is eliminated by store forwarding (S2L) */
16860 		ref = jit_Z_PTR(jit, var_addr);
16861 	}
16862 	*var_info_ptr &= ~MAY_BE_INDIRECT;
16863 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
16864 	*var_addr_ptr = var_addr;
16865 
16866 	if (var_type != IS_UNKNOWN) {
16867 		var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16868 	}
16869 	if (!(var_type & IS_TRACE_REFERENCE)
16870 	 && var_type != IS_UNKNOWN
16871 	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16872 		exit_point = zend_jit_trace_get_exit_point(opline, 0);
16873 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16874 
16875 		if (!exit_addr) {
16876 			return 0;
16877 		}
16878 
16879 		jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
16880 
16881 		//var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
16882 		ZEND_ASSERT(var_info & (1 << var_type));
16883 		if (var_type < IS_STRING) {
16884 			var_info = (1 << var_type);
16885 		} else if (var_type != IS_ARRAY) {
16886 			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16887 		} else {
16888 			var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
16889 		}
16890 
16891 		*var_info_ptr = var_info;
16892 	}
16893 
16894 	return 1;
16895 }
16896 
16897 static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_array, const zend_op *opline, int may_throw, zend_jit_trace_rec *trace)
16898 {
16899 	zend_jit_op_array_trace_extension *jit_extension =
16900 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
16901 	size_t offset = jit_extension->offset;
16902 	const void *handler =
16903 		(zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
16904 	ir_ref ref;
16905 
16906 	zend_jit_set_ip(jit, opline);
16907 	if (GCC_GLOBAL_REGS) {
16908 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
16909 	} else {
16910 		ref = jit_FP(jit);
16911 		ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
16912 	}
16913 	if (may_throw
16914 	 && opline->opcode != ZEND_RETURN
16915 	 && opline->opcode != ZEND_RETURN_BY_REF) {
16916 		zend_jit_check_exception(jit);
16917 	}
16918 
16919 	while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
16920 		trace++;
16921 	}
16922 
16923 	if (!GCC_GLOBAL_REGS
16924 	 && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
16925 		if (opline->opcode == ZEND_RETURN ||
16926 		    opline->opcode == ZEND_RETURN_BY_REF ||
16927 		    opline->opcode == ZEND_DO_UCALL ||
16928 		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
16929 		    opline->opcode == ZEND_DO_FCALL ||
16930 		    opline->opcode == ZEND_GENERATOR_CREATE) {
16931 
16932 			ir_ref addr = jit_EG(current_execute_data);
16933 
16934 			jit_STORE_FP(jit, ir_LOAD_A(addr));
16935 		}
16936 	}
16937 
16938 	if (zend_jit_trace_may_exit(op_array, opline)) {
16939 		if (opline->opcode == ZEND_RETURN ||
16940 		    opline->opcode == ZEND_RETURN_BY_REF ||
16941 		    opline->opcode == ZEND_GENERATOR_CREATE) {
16942 
16943 			if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16944 				if (trace->op != ZEND_JIT_TRACE_END ||
16945 				    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16946 				     trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16947 					/* this check may be handled by the following OPLINE guard or jmp [IP] */
16948 					ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
16949 						jit_STUB_ADDR(jit, jit_stub_trace_halt));
16950 				}
16951 			} else if (GCC_GLOBAL_REGS) {
16952 				ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16953 			} else {
16954 				ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16955 			}
16956 		} else if (opline->opcode == ZEND_GENERATOR_RETURN ||
16957 		           opline->opcode == ZEND_YIELD ||
16958 		           opline->opcode == ZEND_YIELD_FROM) {
16959 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
16960 			ir_BEGIN(IR_UNUSED); /* unreachable block */
16961 		}
16962 		if (trace->op != ZEND_JIT_TRACE_END ||
16963 		    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16964 		     trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16965 
16966 			const zend_op *next_opline = trace->opline;
16967 			const zend_op *exit_opline = NULL;
16968 			uint32_t exit_point;
16969 			const void *exit_addr;
16970 			uint32_t old_info = 0;
16971 			uint32_t old_res_info = 0;
16972 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16973 
16974 			if (zend_is_smart_branch(opline)) {
16975 				bool exit_if_true = 0;
16976 				exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
16977 			} else {
16978 				switch (opline->opcode) {
16979 					case ZEND_JMPZ:
16980 					case ZEND_JMPNZ:
16981 					case ZEND_JMPZ_EX:
16982 					case ZEND_JMPNZ_EX:
16983 					case ZEND_JMP_SET:
16984 					case ZEND_COALESCE:
16985 					case ZEND_JMP_NULL:
16986 					case ZEND_FE_RESET_R:
16987 					case ZEND_FE_RESET_RW:
16988 						exit_opline = (trace->opline == opline + 1) ?
16989 							OP_JMP_ADDR(opline, opline->op2) :
16990 							opline + 1;
16991 						break;
16992 					case ZEND_FE_FETCH_R:
16993 					case ZEND_FE_FETCH_RW:
16994 						exit_opline = (trace->opline == opline + 1) ?
16995 							ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
16996 							opline + 1;
16997 						break;
16998 
16999 				}
17000 			}
17001 
17002 			switch (opline->opcode) {
17003 				case ZEND_FE_FETCH_R:
17004 				case ZEND_FE_FETCH_RW:
17005 					if (opline->op2_type != IS_UNUSED) {
17006 						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
17007 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
17008 					}
17009 					break;
17010 				case ZEND_BIND_INIT_STATIC_OR_JMP:
17011 					if (opline->op1_type == IS_CV) {
17012 						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
17013 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
17014 					}
17015 					break;
17016 			}
17017 			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17018 				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
17019 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
17020 			}
17021 			exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
17022 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17023 
17024 			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17025 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
17026 			}
17027 			switch (opline->opcode) {
17028 				case ZEND_FE_FETCH_R:
17029 				case ZEND_FE_FETCH_RW:
17030 					if (opline->op2_type != IS_UNUSED) {
17031 						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
17032 					}
17033 					break;
17034 				case ZEND_BIND_INIT_STATIC_OR_JMP:
17035 					if (opline->op1_type == IS_CV) {
17036 						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
17037 					}
17038 					break;
17039 			}
17040 
17041 			if (!exit_addr) {
17042 				return 0;
17043 			}
17044 			ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
17045 		}
17046 	}
17047 
17048 	zend_jit_set_last_valid_opline(jit, trace->opline);
17049 
17050 	return 1;
17051 }
17052 
17053 static int zend_jit_deoptimizer_start(zend_jit_ctx        *jit,
17054                                       zend_string         *name,
17055                                       uint32_t             trace_num,
17056                                       uint32_t             exit_num)
17057 {
17058 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
17059 
17060 	jit->ctx.spill_base = ZREG_FP;
17061 
17062 	jit->op_array = NULL;
17063 	jit->ssa = NULL;
17064 	jit->name = zend_string_copy(name);
17065 
17066 	jit->ctx.flags |= IR_SKIP_PROLOGUE;
17067 
17068 	return 1;
17069 }
17070 
17071 static int zend_jit_trace_start(zend_jit_ctx        *jit,
17072                                 const zend_op_array *op_array,
17073                                 zend_ssa            *ssa,
17074                                 zend_string         *name,
17075                                 uint32_t             trace_num,
17076                                 zend_jit_trace_info *parent,
17077                                 uint32_t             exit_num)
17078 {
17079 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
17080 
17081 	jit->ctx.spill_base = ZREG_FP;
17082 
17083 	jit->op_array = NULL;
17084 	jit->current_op_array = op_array;
17085 	jit->ssa = ssa;
17086 	jit->name = zend_string_copy(name);
17087 
17088 	if (!GCC_GLOBAL_REGS) {
17089 		if (!parent) {
17090 			ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
17091 			jit_STORE_FP(jit, ref);
17092 			jit->ctx.flags |= IR_FASTCALL_FUNC;
17093 		}
17094 	}
17095 
17096 	if (parent) {
17097 		jit->ctx.flags |= IR_SKIP_PROLOGUE;
17098 	}
17099 
17100 	if (parent) {
17101 		int i;
17102 		int parent_vars_count = parent->exit_info[exit_num].stack_size;
17103 		zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
17104 			parent->stack_map +
17105 			parent->exit_info[exit_num].stack_offset;
17106 
17107 		/* prevent clobbering of registers used for deoptimization */
17108 		for (i = 0; i < parent_vars_count; i++) {
17109 			if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
17110 			 && STACK_REG(parent_stack, i) != ZREG_NONE) {
17111 				int32_t reg = STACK_REG(parent_stack, i);
17112 				ir_type type;
17113 
17114 				if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
17115 					type = IR_ADDR;
17116 				} else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
17117 					type = IR_LONG;
17118 				} else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
17119 					type = IR_DOUBLE;
17120 				} else {
17121 					ZEND_UNREACHABLE();
17122 				}
17123 				if (ssa && ssa->vars[i].no_val) {
17124 					/* pass */
17125 				} else {
17126 					ir_ref ref = ir_RLOAD(type, reg);
17127 
17128 					if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
17129 						/* op3 is used as a flag that the value is already stored in memory.
17130 						 * In case the IR framework decides to spill the result of IR_LOAD,
17131 						 * it doesn't have to store the value once again.
17132 						 *
17133 						 * See: insn->op3 check in ir_emit_rload()
17134 						 */
17135 						ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
17136 					}
17137 				}
17138 			}
17139 		}
17140 	}
17141 
17142 	if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
17143 		ZEND_ASSERT(parent->exit_info[exit_num].poly_func_reg >= 0 && parent->exit_info[exit_num].poly_this_reg >= 0);
17144 		ir_RLOAD_A(parent->exit_info[exit_num].poly_func_reg);
17145 		ir_RLOAD_A(parent->exit_info[exit_num].poly_this_reg);
17146 	}
17147 
17148 	ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
17149 
17150 	return 1;
17151 }
17152 
17153 static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
17154 {
17155 	return ir_LOOP_BEGIN(ir_END());
17156 }
17157 
17158 static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
17159 {
17160 	int dst_var = phi->ssa_var;
17161 	int src_var = phi->sources[0];
17162 	ir_ref ref;
17163 
17164 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
17165 	ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
17166 
17167 	ref = ir_PHI_2(
17168 		(jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
17169 		zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
17170 
17171 	src_var = phi->sources[1];
17172 	ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
17173 	jit->ra[src_var].flags |= ZREG_FORWARD;
17174 
17175 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
17176 }
17177 
17178 static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
17179 {
17180 	if (timeout_exit_addr) {
17181 		zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17182 	}
17183 	ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
17184 	ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
17185 	return 1;
17186 }
17187 
17188 static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
17189 {
17190 	if (GCC_GLOBAL_REGS) {
17191 		if (!original_handler) {
17192 			ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
17193 		} else {
17194 			ir_TAILCALL(IR_VOID, zend_jit_orig_opline_handler(jit));
17195 		}
17196 	} else {
17197 		if (original_handler) {
17198 			ir_ref ref;
17199 			ir_ref addr = zend_jit_orig_opline_handler(jit);
17200 
17201 #if defined(IR_TARGET_X86)
17202 			addr = ir_CAST_FC_FUNC(addr);
17203 #endif
17204 			ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
17205 			if (opline &&
17206 			    (opline->opcode == ZEND_RETURN
17207 			  || opline->opcode == ZEND_RETURN_BY_REF
17208 			  || opline->opcode == ZEND_GENERATOR_RETURN
17209 			  || opline->opcode == ZEND_GENERATOR_CREATE
17210 			  || opline->opcode == ZEND_YIELD
17211 			  || opline->opcode == ZEND_YIELD_FROM)) {
17212 				ir_RETURN(ref);
17213 				return 1;
17214 			}
17215 		}
17216 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
17217 	}
17218 	return 1;
17219 }
17220 
17221 static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr)
17222 {
17223 	return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
17224 }
17225 
17226 static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
17227 {
17228 	const void *link_addr;
17229 
17230 	/* Skip prologue. */
17231 	ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
17232 	link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
17233 
17234 	if (timeout_exit_addr) {
17235 		zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17236 	}
17237 	ir_IJMP(ir_CONST_ADDR(link_addr));
17238 
17239 	return 1;
17240 }
17241 
17242 static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, zend_jit_trace_rec *trace)
17243 {
17244 	uint32_t op1_info, op2_info;
17245 
17246 	switch (opline->opcode) {
17247 		case ZEND_SEND_VAR:
17248 		case ZEND_SEND_VAL:
17249 		case ZEND_SEND_VAL_EX:
17250 			return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
17251 		case ZEND_QM_ASSIGN:
17252 		case ZEND_IS_SMALLER:
17253 		case ZEND_IS_SMALLER_OR_EQUAL:
17254 		case ZEND_IS_EQUAL:
17255 		case ZEND_IS_NOT_EQUAL:
17256 		case ZEND_IS_IDENTICAL:
17257 		case ZEND_IS_NOT_IDENTICAL:
17258 		case ZEND_CASE:
17259 			return 1;
17260 		case ZEND_RETURN:
17261 			return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
17262 		case ZEND_ASSIGN:
17263 			return (opline->op1_type == IS_CV);
17264 		case ZEND_ASSIGN_OP:
17265 			if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
17266 				return 0;
17267 			}
17268 			op1_info = OP1_INFO();
17269 			op2_info = OP2_INFO();
17270 			return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
17271 		case ZEND_ADD:
17272 		case ZEND_SUB:
17273 		case ZEND_MUL:
17274 			op1_info = OP1_INFO();
17275 			op2_info = OP2_INFO();
17276 			if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
17277 				return 0;
17278 			}
17279 			if (trace && trace->op1_type != IS_UNKNOWN) {
17280 				op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17281 			}
17282 			if (trace && trace->op2_type != IS_UNKNOWN) {
17283 				op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17284 			}
17285 			return !(op1_info & MAY_BE_UNDEF)
17286 				&& !(op2_info & MAY_BE_UNDEF)
17287 				&& (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
17288 				&& (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
17289 		case ZEND_BW_OR:
17290 		case ZEND_BW_AND:
17291 		case ZEND_BW_XOR:
17292 		case ZEND_SL:
17293 		case ZEND_SR:
17294 		case ZEND_MOD:
17295 			op1_info = OP1_INFO();
17296 			op2_info = OP2_INFO();
17297 			if (trace && trace->op1_type != IS_UNKNOWN) {
17298 				op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17299 			}
17300 			if (trace && trace->op2_type != IS_UNKNOWN) {
17301 				op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17302 			}
17303 			return (op1_info & MAY_BE_LONG)
17304 				&& (op2_info & MAY_BE_LONG);
17305 		case ZEND_PRE_INC:
17306 		case ZEND_PRE_DEC:
17307 		case ZEND_POST_INC:
17308 		case ZEND_POST_DEC:
17309 			op1_info = OP1_INFO();
17310 			return opline->op1_type == IS_CV
17311 				&& (op1_info & MAY_BE_LONG)
17312 				&& !(op1_info & MAY_BE_REF);
17313 		case ZEND_STRLEN:
17314 			op1_info = OP1_INFO();
17315 			return (opline->op1_type & (IS_CV|IS_CONST))
17316 				&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
17317 		case ZEND_COUNT:
17318 			op1_info = OP1_INFO();
17319 			return (opline->op1_type & (IS_CV|IS_CONST))
17320 				&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
17321 		case ZEND_JMPZ:
17322 		case ZEND_JMPNZ:
17323 			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17324 				if (!ssa->cfg.map) {
17325 					return 0;
17326 				}
17327 				if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
17328 				    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
17329 					return 0;
17330 				}
17331 			}
17332 			ZEND_FALLTHROUGH;
17333 		case ZEND_BOOL:
17334 		case ZEND_BOOL_NOT:
17335 		case ZEND_JMPZ_EX:
17336 		case ZEND_JMPNZ_EX:
17337 			return 1;
17338 		case ZEND_FETCH_CONSTANT:
17339 			return 1;
17340 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
17341 			if ((opline->extended_value & ZEND_ISEMPTY)) {
17342 				return 0;
17343 			}
17344 			ZEND_FALLTHROUGH;
17345 		case ZEND_FETCH_DIM_R:
17346 		case ZEND_FETCH_DIM_IS:
17347 		case ZEND_FETCH_LIST_R:
17348 			op1_info = OP1_INFO();
17349 			op2_info = OP2_INFO();
17350 			if (trace
17351 			 && trace->op1_type != IS_UNKNOWN
17352 			 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17353 				op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17354 			}
17355 			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17356 					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17357 					 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17358 		case ZEND_ASSIGN_DIM_OP:
17359 			if (opline->result_type != IS_UNUSED) {
17360 				return 0;
17361 			}
17362 			if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17363 				return 0;
17364 			}
17365 			ZEND_FALLTHROUGH;
17366 		case ZEND_ASSIGN_DIM:
17367 		case ZEND_FETCH_DIM_W:
17368 		case ZEND_FETCH_DIM_RW:
17369 		case ZEND_FETCH_LIST_W:
17370 			op1_info = OP1_INFO();
17371 			op2_info = OP2_INFO();
17372 			if (trace) {
17373 				if (opline->op1_type == IS_CV) {
17374 					if ((opline->opcode == ZEND_ASSIGN_DIM
17375 					  || opline->opcode == ZEND_ASSIGN_DIM_OP)
17376 					 && (opline+1)->op1_type == IS_CV
17377 					 && (opline+1)->op1.var == opline->op1.var) {
17378 						/* skip $a[x] = $a; */
17379 						return 0;
17380 					}
17381 				} else if (opline->op1_type == IS_VAR) {
17382 					if (trace->op1_type == IS_UNKNOWN
17383 					 || !(trace->op1_type & IS_TRACE_INDIRECT)
17384 					 || opline->result_type != IS_UNUSED) {
17385 						return 0;
17386 					}
17387 				}
17388 				if (trace->op1_type != IS_UNKNOWN
17389 				 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17390 					op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17391 				}
17392 			} else {
17393 				if (opline->op1_type != IS_CV) {
17394 					return 0;
17395 				}
17396 			}
17397 			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17398 					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17399 					 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17400 		case ZEND_ASSIGN_OBJ_OP:
17401 			if (opline->result_type != IS_UNUSED) {
17402 				return 0;
17403 			}
17404 			if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17405 				return 0;
17406 			}
17407 			ZEND_FALLTHROUGH;
17408 		case ZEND_FETCH_OBJ_R:
17409 		case ZEND_ASSIGN_OBJ:
17410 			if (opline->op2_type != IS_CONST
17411 			 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
17412 			 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
17413 				return 0;
17414 			}
17415 			op1_info = OP1_INFO();
17416 			return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
17417 	}
17418 	return 0;
17419 }
17420 
17421 static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
17422 {
17423 	if (ssa->vars[var].no_val) {
17424 		/* we don't need the value */
17425 		return 0;
17426 	}
17427 
17428 	if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
17429 		/* Disable global register allocation,
17430 		 * register allocation for SSA variables connected through Phi functions
17431 		 */
17432 		if (ssa->vars[var].definition_phi) {
17433 			return 0;
17434 		}
17435 		if (ssa->vars[var].phi_use_chain) {
17436 			zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
17437 			do {
17438 				if (!ssa->vars[phi->ssa_var].no_val) {
17439 					return 0;
17440 				}
17441 				phi = zend_ssa_next_use_phi(ssa, var, phi);
17442 			} while (phi);
17443 		}
17444 	}
17445 
17446 	if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
17447 	    ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
17448 	    /* bad type */
17449 		return 0;
17450 	}
17451 
17452 	return 1;
17453 }
17454 
17455 static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17456 {
17457 	if (!zend_jit_var_supports_reg(ssa, var)) {
17458 		return 0;
17459 	}
17460 
17461 	if (ssa->vars[var].definition >= 0) {
17462 		uint32_t def = ssa->vars[var].definition;
17463 		if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17464 			return 0;
17465 		}
17466 	}
17467 
17468 	if (ssa->vars[var].use_chain >= 0) {
17469 		int use = ssa->vars[var].use_chain;
17470 
17471 		do {
17472 			if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17473 			    !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17474 				return 0;
17475 			}
17476 			use = zend_ssa_next_use(ssa->ops, var, use);
17477 		} while (use >= 0);
17478 	}
17479 
17480 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17481 		int def_block, use_block, b, use, j;
17482 		zend_basic_block *bb;
17483 		zend_ssa_phi *p;
17484 		bool ret = 1;
17485 		zend_worklist worklist;
17486 		ALLOCA_FLAG(use_heap)
17487 
17488 		/* Check if live range is split by ENTRY block */
17489 		if (ssa->vars[var].definition >= 0) {
17490 			def_block =ssa->cfg.map[ssa->vars[var].definition];
17491 		} else {
17492 			ZEND_ASSERT(ssa->vars[var].definition_phi);
17493 			def_block = ssa->vars[var].definition_phi->block;
17494 		}
17495 
17496 		ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
17497 
17498 		if (ssa->vars[var].use_chain >= 0) {
17499 			use = ssa->vars[var].use_chain;
17500 			do {
17501 				use_block = ssa->cfg.map[use];
17502 				if (use_block != def_block) {
17503 					zend_worklist_push(&worklist, use_block);
17504 				}
17505 				use = zend_ssa_next_use(ssa->ops, var, use);
17506 			} while (use >= 0);
17507 		}
17508 
17509 		p = ssa->vars[var].phi_use_chain;
17510 		while (p) {
17511 			use_block = p->block;
17512 			if (use_block != def_block) {
17513 				bb = &ssa->cfg.blocks[use_block];
17514 				for (j = 0; j < bb->predecessors_count; j++) {
17515 					if (p->sources[j] == var) {
17516 						use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
17517 						if (use_block != def_block) {
17518 							zend_worklist_push(&worklist, use_block);
17519 						}
17520 					}
17521 				}
17522 			}
17523 			p = zend_ssa_next_use_phi(ssa, var, p);
17524 		}
17525 
17526 		while (zend_worklist_len(&worklist) != 0) {
17527 			b = zend_worklist_pop(&worklist);
17528 			bb = &ssa->cfg.blocks[b];
17529 			if (bb->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
17530 				ret = 0;
17531 				break;
17532 			}
17533 			for (j = 0; j < bb->predecessors_count; j++) {
17534 				b = ssa->cfg.predecessors[bb->predecessor_offset + j];
17535 				if (b != def_block) {
17536 					zend_worklist_push(&worklist, b);
17537 				}
17538 			}
17539 		}
17540 
17541 		ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
17542 
17543 		return ret;
17544 	}
17545 
17546 	return 1;
17547 }
17548 
17549 static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
17550 	// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
17551 	ir_ref observer_handler;
17552 	zend_function *fbc = ZEND_FLF_FUNC(opline);
17553 	// Not need for runtime cache or generator checks here, we just need if_unobserved
17554 	ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17555 
17556 	// Call zend_frameless_observed_call for the main logic.
17557 	ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
17558 
17559 	ir_ref skip = ir_END();
17560 	ir_IF_TRUE(if_unobserved);
17561 	return skip;
17562 }
17563 
17564 static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
17565 {
17566 	jit_SET_EX_OPLINE(jit, opline);
17567 
17568 	void *function = ZEND_FLF_HANDLER(opline);
17569 	zend_jit_addr res_addr = RES_ADDR();
17570 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17571 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17572 
17573 	ir_ref skip_observer = IR_UNUSED;
17574 	if (ZEND_OBSERVER_ENABLED) {
17575 		skip_observer = jit_frameless_observer(jit, opline);
17576 	}
17577 
17578 	ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17579 
17580 	if (skip_observer != IR_UNUSED) {
17581 		ir_MERGE_WITH(skip_observer);
17582 	}
17583 
17584 	zend_jit_check_exception(jit);
17585 }
17586 
17587 static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
17588 {
17589 	jit_SET_EX_OPLINE(jit, opline);
17590 
17591 	/* Avoid dropping RC check in case op escapes. */
17592 	if (op1_info & MAY_BE_RC1) {
17593 		op1_info |= MAY_BE_RCN;
17594 	}
17595 
17596 	void *function = ZEND_FLF_HANDLER(opline);
17597 	zend_jit_addr res_addr = RES_ADDR();
17598 	zend_jit_addr op1_addr = OP1_ADDR();
17599 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17600 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17601 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17602 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17603 		op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17604 		op1_info &= ~MAY_BE_UNDEF;
17605 		op1_info |= MAY_BE_NULL;
17606 		op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17607 	}
17608 	if (op1_info & MAY_BE_REF) {
17609 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17610 	}
17611 
17612 	ir_ref skip_observer = IR_UNUSED;
17613 	if (ZEND_OBSERVER_ENABLED) {
17614 		skip_observer = jit_frameless_observer(jit, opline);
17615 	}
17616 
17617 	ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17618 
17619 	if (skip_observer != IR_UNUSED) {
17620 		ir_MERGE_WITH(skip_observer);
17621 	}
17622 
17623 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17624 	zend_jit_check_exception(jit);
17625 }
17626 
17627 static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
17628 {
17629 	jit_SET_EX_OPLINE(jit, opline);
17630 
17631 	/* Avoid dropping RC check in case op escapes. */
17632 	if (op1_info & MAY_BE_RC1) {
17633 		op1_info |= MAY_BE_RCN;
17634 	}
17635 	if (op2_info & MAY_BE_RC1) {
17636 		op2_info |= MAY_BE_RCN;
17637 	}
17638 
17639 	void *function = ZEND_FLF_HANDLER(opline);
17640 	zend_jit_addr res_addr = RES_ADDR();
17641 	zend_jit_addr op1_addr = OP1_ADDR();
17642 	zend_jit_addr op2_addr = OP2_ADDR();
17643 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17644 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17645 	ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17646 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17647 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17648 		op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17649 		op1_info &= ~MAY_BE_UNDEF;
17650 		op1_info |= MAY_BE_NULL;
17651 		op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17652 	}
17653 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17654 		op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17655 		op2_info &= ~MAY_BE_UNDEF;
17656 		op2_info |= MAY_BE_NULL;
17657 		op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17658 	}
17659 	if (op1_info & MAY_BE_REF) {
17660 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17661 	}
17662 	if (op2_info & MAY_BE_REF) {
17663 		op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17664 	}
17665 
17666 	ir_ref skip_observer = IR_UNUSED;
17667 	if (ZEND_OBSERVER_ENABLED) {
17668 		skip_observer = jit_frameless_observer(jit, opline);
17669 	}
17670 
17671 	ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17672 
17673 	if (skip_observer != IR_UNUSED) {
17674 		ir_MERGE_WITH(skip_observer);
17675 	}
17676 
17677 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17678 	/* Set OP1 to UNDEF in case FREE_OP2() throws. */
17679 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17680 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17681 	}
17682 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17683 	zend_jit_check_exception(jit);
17684 }
17685 
17686 static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, uint32_t op1_data_info)
17687 {
17688 	jit_SET_EX_OPLINE(jit, opline);
17689 
17690 	/* Avoid dropping RC check in case op escapes. */
17691 	if (op1_info & MAY_BE_RC1) {
17692 		op1_info |= MAY_BE_RCN;
17693 	}
17694 	if (op2_info & MAY_BE_RC1) {
17695 		op2_info |= MAY_BE_RCN;
17696 	}
17697 	if (op1_data_info & MAY_BE_RC1) {
17698 		op1_data_info |= MAY_BE_RCN;
17699 	}
17700 
17701 	void *function = ZEND_FLF_HANDLER(opline);
17702 	uint8_t op_data_type = (opline + 1)->op1_type;
17703 	zend_jit_addr res_addr = RES_ADDR();
17704 	zend_jit_addr op1_addr = OP1_ADDR();
17705 	zend_jit_addr op2_addr = OP2_ADDR();
17706 	zend_jit_addr op3_addr = OP1_DATA_ADDR();
17707 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17708 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17709 	ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17710 	ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
17711 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17712 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17713 		op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17714 		op1_info &= ~MAY_BE_UNDEF;
17715 		op1_info |= MAY_BE_NULL;
17716 		op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17717 	}
17718 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17719 		op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17720 		op2_info &= ~MAY_BE_UNDEF;
17721 		op2_info |= MAY_BE_NULL;
17722 		op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17723 	}
17724 	if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
17725 		op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17726 		op1_data_info &= ~MAY_BE_UNDEF;
17727 		op1_data_info |= MAY_BE_NULL;
17728 		op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
17729 	}
17730 	if (op1_info & MAY_BE_REF) {
17731 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17732 	}
17733 	if (op2_info & MAY_BE_REF) {
17734 		op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17735 	}
17736 	if (op1_data_info & MAY_BE_REF) {
17737 		op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
17738 	}
17739 
17740 	ir_ref skip_observer = IR_UNUSED;
17741 	if (ZEND_OBSERVER_ENABLED) {
17742 		skip_observer = jit_frameless_observer(jit, opline);
17743 	}
17744 
17745 	ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17746 
17747 	if (skip_observer != IR_UNUSED) {
17748 		ir_MERGE_WITH(skip_observer);
17749 	}
17750 
17751 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17752 	/* Set OP1 to UNDEF in case FREE_OP2() throws. */
17753 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
17754 	 && ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
17755 	  || (op_data_type & (IS_VAR|IS_TMP_VAR)))) {
17756 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17757 	}
17758 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17759 	/* If OP1 is a TMP|VAR, we don't need to set OP2 to UNDEF on free because
17760 	 * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
17761 	if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR))
17762 	 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17763 	 && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17764 		jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
17765 	}
17766 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
17767 	zend_jit_check_exception(jit);
17768 }
17769 
17770 /*
17771  * Local variables:
17772  * tab-width: 4
17773  * c-basic-offset: 4
17774  * indent-tabs-mode: t
17775  * End:
17776  */
17777