xref: /php-src/ext/opcache/jit/zend_jit_ir.c (revision daba40c6)
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_metod_call_frame);
3022 	REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
3023 	REGISTER_HELPER(zend_jit_free_trampoline_helper);
3024 	REGISTER_HELPER(zend_jit_verify_return_slow);
3025 	REGISTER_HELPER(zend_jit_deprecated_helper);
3026 	REGISTER_HELPER(zend_jit_undefined_long_key);
3027 	REGISTER_HELPER(zend_jit_undefined_long_key_ex);
3028 	REGISTER_HELPER(zend_jit_undefined_string_key);
3029 	REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3030 	REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3031 	REGISTER_HELPER(zend_free_extra_named_params);
3032 	REGISTER_HELPER(zend_jit_free_call_frame);
3033 	REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3034 	REGISTER_HELPER(zend_jit_verify_arg_slow);
3035 	REGISTER_HELPER(zend_missing_arg_error);
3036 	REGISTER_HELPER(zend_jit_only_vars_by_reference);
3037 	REGISTER_HELPER(zend_jit_leave_func_helper);
3038 	REGISTER_HELPER(zend_jit_leave_nested_func_helper);
3039 	REGISTER_HELPER(zend_jit_leave_top_func_helper);
3040 	REGISTER_HELPER(zend_jit_fetch_global_helper);
3041 	REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3042 	REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3043 	REGISTER_HELPER(zend_jit_hash_lookup_rw);
3044 	REGISTER_HELPER(zend_jit_symtable_find);
3045 	REGISTER_HELPER(zend_jit_symtable_lookup_w);
3046 	REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3047 	REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3048 	REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3049 	REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3050 	REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3051 	REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3052 	REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3053 	REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3054 	REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3055 	REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3056 	REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3057 	REGISTER_HELPER(zend_jit_invalid_array_access);
3058 	REGISTER_HELPER(zend_jit_zval_array_dup);
3059 	REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3060 	REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3061 	REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3062 	REGISTER_HELPER(zend_jit_isset_dim_helper);
3063 	REGISTER_HELPER(zend_jit_assign_dim_helper);
3064 	REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3065 	REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3066 	REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3067 	REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3068 	REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3069 	REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3070 	REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3071 	REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3072 	REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3073 	REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3074 	REGISTER_HELPER(zend_jit_check_array_promotion);
3075 	REGISTER_HELPER(zend_jit_create_typed_ref);
3076 	REGISTER_HELPER(zend_jit_invalid_property_write);
3077 	REGISTER_HELPER(zend_jit_invalid_property_read);
3078 	REGISTER_HELPER(zend_jit_extract_helper);
3079 	REGISTER_HELPER(zend_jit_invalid_property_assign);
3080 	REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3081 	REGISTER_HELPER(zend_jit_assign_obj_helper);
3082 	REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3083 	REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3084 	REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3085 	REGISTER_HELPER(zend_jit_invalid_property_incdec);
3086 	REGISTER_HELPER(zend_jit_inc_typed_prop);
3087 	REGISTER_HELPER(zend_jit_dec_typed_prop);
3088 	REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3089 	REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3090 	REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3091 	REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3092 	REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3093 	REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3094 	REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3095 	REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3096 	REGISTER_HELPER(zend_jit_rope_end);
3097 	REGISTER_HELPER(zend_fcall_interrupt);
3098 
3099 #ifndef ZTS
3100 	REGISTER_DATA(EG(current_execute_data));
3101 	REGISTER_DATA(EG(exception));
3102 	REGISTER_DATA(EG(opline_before_exception));
3103 	REGISTER_DATA(EG(vm_interrupt));
3104 	REGISTER_DATA(EG(timed_out));
3105 	REGISTER_DATA(EG(uninitialized_zval));
3106 	REGISTER_DATA(EG(zend_constants));
3107 	REGISTER_DATA(EG(jit_trace_num));
3108 	REGISTER_DATA(EG(vm_stack_top));
3109 	REGISTER_DATA(EG(vm_stack_end));
3110 	REGISTER_DATA(EG(exception_op));
3111 	REGISTER_DATA(EG(symbol_table));
3112 
3113 	REGISTER_DATA(CG(map_ptr_base));
3114 #endif
3115 #endif
3116 }
3117 
zend_jit_calc_trace_prologue_size(void)3118 static void zend_jit_calc_trace_prologue_size(void)
3119 {
3120 	zend_jit_ctx jit_ctx;
3121 	zend_jit_ctx *jit = &jit_ctx;
3122 	void *entry;
3123 	size_t size;
3124 
3125 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
3126 
3127 	if (!GCC_GLOBAL_REGS) {
3128 		ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3129 		jit_STORE_FP(jit, ref);
3130 		jit->ctx.flags |= IR_FASTCALL_FUNC;
3131 	}
3132 
3133 	ir_UNREACHABLE();
3134 
3135 	entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3136 	zend_jit_free_ctx(jit);
3137 
3138 	if (!entry) {
3139 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3140 	}
3141 
3142 	zend_jit_trace_prologue_size = size;
3143 }
3144 
3145 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3146 static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3147 
3148 typedef struct _Unwind_Context _Unwind_Context;
3149 typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3150 extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
3151 extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
3152 
3153 typedef struct _zend_jit_unwind_arg {
3154 	int cnt;
3155 	uintptr_t cfa[3];
3156 } zend_jit_unwind_arg;
3157 
zend_jit_unwind_cb(_Unwind_Context * ctx,void * a)3158 static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3159 {
3160 	zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
3161 	arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3162 	arg->cnt++;
3163 	if (arg->cnt == 3) {
3164 		return 5; // _URC_END_OF_STACK
3165 	}
3166 	return 0; // _URC_NO_REASON;
3167 }
3168 
zend_jit_touch_vm_stack_data(void * vm_stack_data)3169 static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3170 {
3171 	zend_jit_unwind_arg arg;
3172 
3173 	memset(&arg, 0, sizeof(arg));
3174 	_Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3175 	if (arg.cnt == 3) {
3176 		zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3177 	}
3178 }
3179 
3180 extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3181 
zend_jit_set_sp_adj_vm(void)3182 static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3183 {
3184 	void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3185 
3186 	orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3187 	zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3188 	execute_ex(NULL);                                        // set sp_adj[SP_ADJ_VM]
3189 	zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3190 }
3191 #endif
3192 
zend_jit_setup(void)3193 static void zend_jit_setup(void)
3194 {
3195 #if defined(IR_TARGET_X86)
3196 	if (!zend_cpu_supports_sse2()) {
3197 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3198 	}
3199 #endif
3200 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3201 	allowed_opt_flags = 0;
3202 	if (zend_cpu_supports_avx()) {
3203 		allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3204 	}
3205 # if defined(PHP_HAVE_BUILTIN_CPU_SUPPORTS) && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
3206 	if (zend_cpu_supports_cldemote()) {
3207 		default_mflags |= IR_X86_CLDEMOTE;
3208 	}
3209 # endif
3210 #endif
3211 #ifdef ZTS
3212 #if defined(IR_TARGET_AARCH64)
3213 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3214 
3215 # ifdef __FreeBSD__
3216 	if (tsrm_ls_cache_tcb_offset == 0) {
3217 		TLSDescriptor **where;
3218 
3219 		__asm__(
3220 			"adrp %0, :tlsdesc:_tsrm_ls_cache\n"
3221 			"add %0, %0, :tlsdesc_lo12:_tsrm_ls_cache\n"
3222 			: "=r" (where));
3223 		/* See https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst
3224 		 * section "Relocations for thread-local storage".
3225 		 * The first entry holds a pointer to the variable's TLS descriptor resolver function and the second entry holds
3226 		 * a platform-specific offset or pointer. */
3227 		TLSDescriptor *tlsdesc = where[1];
3228 
3229 		tsrm_tls_offset = tlsdesc->offset;
3230 		/* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/22ca6db50f4e6bd75a141f57cf953d8de6531a06/lib/libc/gen/tls.c#L88) */
3231 		tsrm_tls_index = (tlsdesc->index + 1) * 8;
3232 	}
3233 # else
3234 	ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0);
3235 # endif
3236 # elif defined(_WIN64)
3237 	tsrm_tls_index  = _tls_index * sizeof(void*);
3238 
3239 	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3240 	/* Probably, it might be better solution */
3241 	do {
3242 		void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
3243 		void *val = _tsrm_ls_cache;
3244 		size_t offset = 0;
3245 		size_t size = (char*)&_tls_end - (char*)&_tls_start;
3246 
3247 		while (offset < size) {
3248 			if (*tls_mem == val) {
3249 				tsrm_tls_offset = offset;
3250 				break;
3251 			}
3252 			tls_mem++;
3253 			offset += sizeof(void*);
3254 		}
3255 		if (offset >= size) {
3256 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3257 		}
3258 	} while(0);
3259 # elif defined(ZEND_WIN32)
3260 	tsrm_tls_index  = _tls_index * sizeof(void*);
3261 
3262 	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3263 	/* Probably, it might be better solution */
3264 	do {
3265 		void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
3266 		void *val = _tsrm_ls_cache;
3267 		size_t offset = 0;
3268 		size_t size = (char*)&_tls_end - (char*)&_tls_start;
3269 
3270 		while (offset < size) {
3271 			if (*tls_mem == val) {
3272 				tsrm_tls_offset = offset;
3273 				break;
3274 			}
3275 			tls_mem++;
3276 			offset += sizeof(void*);
3277 		}
3278 		if (offset >= size) {
3279 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3280 		}
3281 	} while(0);
3282 # elif defined(__APPLE__) && defined(__x86_64__)
3283 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3284 	if (tsrm_ls_cache_tcb_offset == 0) {
3285 		size_t *ti;
3286 		__asm__(
3287 			"leaq __tsrm_ls_cache(%%rip),%0"
3288 			: "=r" (ti));
3289 		tsrm_tls_offset = ti[2];
3290 		tsrm_tls_index = ti[1] * 8;
3291 	}
3292 # elif defined(__GNUC__) && defined(__x86_64__)
3293 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3294 	if (tsrm_ls_cache_tcb_offset == 0) {
3295 #if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && \
3296 	!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3297 		size_t ret;
3298 
3299 		asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
3300 			: "=r" (ret));
3301 		tsrm_ls_cache_tcb_offset = ret;
3302 #elif defined(__MUSL__)
3303 		size_t *ti;
3304 
3305 		__asm__(
3306 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3307 			: "=a" (ti));
3308 		tsrm_tls_offset = ti[1];
3309 		tsrm_tls_index = ti[0] * 8;
3310 #elif defined(__FreeBSD__)
3311 		size_t *ti;
3312 
3313 		__asm__(
3314 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3315 			: "=a" (ti));
3316 		tsrm_tls_offset = ti[1];
3317 		/* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/bf56e8b9c8639ac4447d223b83cdc128107cc3cd/libexec/rtld-elf/rtld.c#L5260) */
3318 		tsrm_tls_index = (ti[0] + 1) * 8;
3319 #else
3320 		size_t *ti;
3321 
3322 		__asm__(
3323 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3324 			: "=a" (ti));
3325 		tsrm_tls_offset = ti[1];
3326 		tsrm_tls_index = ti[0] * 16;
3327 #endif
3328 	}
3329 # elif defined(__GNUC__) && defined(__i386__)
3330 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3331 	if (tsrm_ls_cache_tcb_offset == 0) {
3332 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3333 		size_t ret;
3334 
3335 		asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
3336 			: "=a" (ret));
3337 		tsrm_ls_cache_tcb_offset = ret;
3338 #else
3339 		size_t *ti, _ebx, _ecx, _edx;
3340 
3341 		__asm__(
3342 			"call 1f\n"
3343 			".subsection 1\n"
3344 			"1:\tmovl (%%esp), %%ebx\n\t"
3345 			"ret\n"
3346 			".previous\n\t"
3347 			"addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
3348 			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
3349 			"call ___tls_get_addr@plt\n\t"
3350 			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
3351 			: "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
3352 		tsrm_tls_offset = ti[1];
3353 		tsrm_tls_index = ti[0] * 8;
3354 #endif
3355 	}
3356 # endif
3357 #endif
3358 
3359 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3360 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3361 		zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3362 	}
3363 #endif
3364 
3365 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3366 		zend_jit_setup_disasm();
3367 	}
3368 
3369 #ifndef _WIN32
3370 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3371 		ir_perf_jitdump_open();
3372 	}
3373 
3374 #endif
3375 	zend_long debug = JIT_G(debug);
3376 	if (!(debug & ZEND_JIT_DEBUG_ASM_STUBS)) {
3377 		JIT_G(debug) &= ~(ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_FINAL|
3378 			ZEND_JIT_DEBUG_IR_CODEGEN|
3379 			ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_CFG|ZEND_JIT_DEBUG_IR_AFTER_GCM|
3380 			ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS);
3381 	}
3382 
3383 	zend_jit_calc_trace_prologue_size();
3384 	zend_jit_setup_stubs();
3385 	JIT_G(debug) = debug;
3386 }
3387 
zend_jit_shutdown_ir(void)3388 static void zend_jit_shutdown_ir(void)
3389 {
3390 #ifndef _WIN32
3391 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3392 		ir_perf_jitdump_close();
3393 	}
3394 	if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
3395 		ir_gdb_unregister_all();
3396 	}
3397 #endif
3398 #ifdef HAVE_CAPSTONE
3399 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3400 		ir_disasm_free();
3401 	}
3402 #endif
3403 }
3404 
3405 /* PHP control flow reconstruction helpers */
jit_IF_ex(zend_jit_ctx * jit,ir_ref condition,ir_ref true_block)3406 static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3407 {
3408 	ir_ref ref = ir_IF(condition);
3409 	/* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3410 	 *
3411 	 * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3412 	 * to start target block
3413 	 */
3414 	ir_set_op(&jit->ctx, ref, 3, true_block);
3415 	return ref;
3416 }
3417 
jit_IF_TRUE_FALSE_ex(zend_jit_ctx * jit,ir_ref if_ref,ir_ref true_block)3418 static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3419 {
3420 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3421 	ZEND_ASSERT(if_ref);
3422 	ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3423 	ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3424 	if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3425 		ir_IF_TRUE(if_ref);
3426 	} else {
3427 		ir_IF_FALSE(if_ref);
3428 	}
3429 }
3430 
_zend_jit_add_predecessor_ref(zend_jit_ctx * jit,int b,int pred,ir_ref ref)3431 static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3432 {
3433 	int i, *p;
3434 	zend_basic_block *bb;
3435 	ir_ref *r, header;
3436 
3437 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3438 	bb = &jit->ssa->cfg.blocks[b];
3439 	p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3440 	r = &jit->bb_edges[jit->bb_predecessors[b]];
3441 	for (i = 0; i < bb->predecessors_count; i++, p++, r++) {
3442 		if (*p == pred) {
3443 			ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3444 			header = jit->bb_start_ref[b];
3445 			if (header) {
3446 				/* this is back edge */
3447 				ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3448 				if (jit->ctx.ir_base[ref].op == IR_END) {
3449 					jit->ctx.ir_base[ref].op = IR_LOOP_END;
3450 				} else if (jit->ctx.ir_base[ref].op == IR_IF) {
3451 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3452 					ref = ir_LOOP_END();
3453 				} else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3454 					ir_BEGIN(ref);
3455 					ref = ir_LOOP_END();
3456 				} else {
3457 					ZEND_UNREACHABLE();
3458 				}
3459 				ir_MERGE_SET_OP(header, i + 1, ref);
3460 			}
3461 			*r = ref;
3462 			return;
3463 		}
3464 	}
3465 	ZEND_UNREACHABLE();
3466 }
3467 
_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)3468 static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3469                                                 uint32_t      true_label,
3470                                                 uint32_t      false_label,
3471                                                 ir_ref        true_inputs,
3472                                                 ir_ref        false_inputs)
3473 {
3474 	ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3475 
3476 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3477 	if (true_inputs) {
3478 		ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3479 		if (!jit->ctx.ir_base[true_inputs].op2) {
3480 			true_path = true_inputs;
3481 		} else {
3482 			ir_MERGE_list(true_inputs);
3483 			true_path = ir_END();
3484 		}
3485 	}
3486 	if (false_inputs) {
3487 		ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3488 		if (!jit->ctx.ir_base[false_inputs].op2) {
3489 			false_path = false_inputs;
3490 		} else {
3491 			ir_MERGE_list(false_inputs);
3492 			false_path = ir_END();
3493 		}
3494 	}
3495 
3496 	if (true_label == false_label && true_path && false_path) {
3497 		ir_MERGE_2(true_path, false_path);
3498 		_zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3499 	} else if (!true_path && !false_path) {
3500 		/* dead code */
3501 		true_path = ir_END();
3502 		_zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3503 	} else {
3504 		if (true_path) {
3505 			_zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3506 		}
3507 		if (false_path) {
3508 			_zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3509 		}
3510 	}
3511 
3512 	jit->b = -1;
3513 }
3514 
_zend_jit_fix_merges(zend_jit_ctx * jit)3515 static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3516 {
3517 	int i, count;
3518 	ir_ref j, k, n, *p, *q, *r;
3519 	ir_ref ref;
3520 	ir_insn *insn, *phi;
3521 
3522 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3523 	count = jit->ssa->cfg.blocks_count;
3524 	for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3525 		ref = *p;
3526 		if (ref) {
3527 			insn = &jit->ctx.ir_base[ref];
3528 			if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3529 				n = insn->inputs_count;
3530 				/* Remove IS_UNUSED inputs */
3531 				for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3532 					if (*q) {
3533 						if (q != r) {
3534 							*r = *q;
3535 							phi = insn + 1 + (n >> 2);
3536 							while (phi->op == IR_PI) {
3537 								phi++;
3538 							}
3539 							while (phi->op == IR_PHI) {
3540 								ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3541 								phi += 1 + ((n + 1) >> 2);
3542 							}
3543 						}
3544 						k++;
3545 						r++;
3546 					}
3547 				}
3548 				if (k != n) {
3549 					ir_ref n2, k2;
3550 
3551 					if (k <= 1) {
3552 						insn->op = IR_BEGIN;
3553 						insn->inputs_count = 0;
3554 					} else {
3555 						insn->inputs_count = k;
3556 					}
3557 					n2 = 1 + (n >> 2);
3558 					k2 = 1 + (k >> 2);
3559 					while (k2 != n2) {
3560 						(insn+k2)->optx = IR_NOP;
3561 						k2++;
3562 					}
3563 					phi = insn + 1 + (n >> 2);
3564 					while (phi->op == IR_PI) {
3565 						phi++;
3566 					}
3567 					while (phi->op == IR_PHI) {
3568 						if (k <= 1) {
3569 							phi->op = IR_COPY;
3570 							phi->op1 = phi->op2;
3571 							phi->op2 = 1;
3572 							phi->inputs_count = 0;
3573 						} else {
3574 							phi->inputs_count = k + 1;
3575 						}
3576 						n2 = 1 + ((n + 1) >> 2);
3577 						k2 = 1 + ((k + 1) >> 2);
3578 						while (k2 != n2) {
3579 							(phi+k2)->optx = IR_NOP;
3580 							k2++;
3581 						}
3582 						phi += 1 + ((n + 1) >> 2);
3583 					}
3584 				}
3585 			}
3586 		}
3587 	}
3588 }
3589 
zend_jit_case_start(zend_jit_ctx * jit,int switch_b,int case_b,ir_ref switch_ref)3590 static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3591 {
3592 	zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3593 	const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3594 
3595 	if (opline->opcode == ZEND_SWITCH_LONG
3596 	 || opline->opcode == ZEND_SWITCH_STRING
3597 	 || opline->opcode == ZEND_MATCH) {
3598 		HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3599 		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3600 		int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3601 		zval *zv;
3602 		ir_ref list = IR_UNUSED, idx;
3603 		bool first = 1;
3604 
3605 		ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3606 			const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3607 			int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3608 
3609 			if (b == case_b) {
3610 				if (!first) {
3611 					ir_END_list(list);
3612 				}
3613 				if (HT_IS_PACKED(jumptable)) {
3614 					idx = ir_CONST_LONG(zv - jumptable->arPacked);
3615 				} else {
3616 					idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3617 				}
3618 				ir_CASE_VAL(switch_ref, idx);
3619 				first = 0;
3620 			}
3621 		} ZEND_HASH_FOREACH_END();
3622 		if (default_b == case_b) {
3623 			if (!first) {
3624 				ir_END_list(list);
3625 			}
3626 			if (jit->ctx.ir_base[switch_ref].op3) {
3627 				/* op3 may contain a list of additional "default" path inputs for MATCH */
3628 				ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3629 				jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3630 				ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3631 				ir_ref end = ref;
3632 				while (jit->ctx.ir_base[end].op2) {
3633 					ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3634 					end = jit->ctx.ir_base[end].op2;
3635 				}
3636 				jit->ctx.ir_base[end].op2 = list;
3637 				list = ref;
3638 			}
3639 			ir_CASE_DEFAULT(switch_ref);
3640 		}
3641 		if (list) {
3642 			ir_END_list(list);
3643 			ir_MERGE_list(list);
3644 		}
3645 	} else {
3646 		ZEND_UNREACHABLE();
3647 	}
3648 }
3649 
zend_jit_bb_start(zend_jit_ctx * jit,int b)3650 static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3651 {
3652 	zend_basic_block *bb;
3653 	int i, n, *p, pred;
3654 	ir_ref ref, bb_start;
3655 
3656 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3657 	ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3658 	bb = &jit->ssa->cfg.blocks[b];
3659 	ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3660 	n = bb->predecessors_count;
3661 
3662 	if (n == 0) {
3663 		/* pass */
3664 		ZEND_ASSERT(jit->ctx.control);
3665 #if ZEND_DEBUG
3666 		ref = jit->ctx.control;
3667 		ir_insn *insn = &jit->ctx.ir_base[ref];
3668 		while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3669 			ref = insn->op1;
3670 			insn = &jit->ctx.ir_base[ref];
3671 		}
3672 		ZEND_ASSERT(insn->op == IR_START);
3673 		ZEND_ASSERT(ref == 1);
3674 #endif
3675 		bb_start = 1;
3676 		if (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
3677 			/* prvent END/BEGIN merging */
3678 			jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3679 			bb_start = jit->ctx.control;
3680 		}
3681 	} else if (n == 1) {
3682 		ZEND_ASSERT(!jit->ctx.control);
3683 		pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3684 		ref = jit->bb_edges[jit->bb_predecessors[b]];
3685 		if (ref == IR_UNUSED) {
3686 			if (!jit->ctx.control) {
3687 				ir_BEGIN(IR_UNUSED); /* unreachable block */
3688 			}
3689 		} else {
3690 			ir_op op = jit->ctx.ir_base[ref].op;
3691 
3692 			if (op == IR_IF) {
3693 				if (!jit->ctx.control) {
3694 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3695 				} else {
3696 					ir_ref entry_path = ir_END();
3697 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3698 					ir_MERGE_WITH(entry_path);
3699 				}
3700 			} else if (op == IR_SWITCH) {
3701 				zend_jit_case_start(jit, pred, b, ref);
3702 			} else {
3703 				if (!jit->ctx.control) {
3704 					ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3705 					if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3706 					 && (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)) {
3707 						/* prvent END/BEGIN merging */
3708 						jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3709 					} else {
3710 						ir_BEGIN(ref);
3711 					}
3712 				} else {
3713 					ir_MERGE_WITH(ref);
3714 				}
3715 			}
3716 		}
3717 		bb_start = jit->ctx.control;
3718 	} else {
3719 		int forward_edges_count = 0;
3720 		int back_edges_count = 0;
3721 		ir_ref *pred_refs;
3722 		ir_ref entry_path = IR_UNUSED;
3723 		ALLOCA_FLAG(use_heap);
3724 
3725 		ZEND_ASSERT(!jit->ctx.control);
3726 		if (jit->ctx.control) {
3727 			entry_path = ir_END();
3728 		}
3729 		pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3730 		for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3731 			pred = *p;
3732 			if (jit->bb_start_ref[pred]) {
3733 				/* forward edge */
3734 				forward_edges_count++;
3735 				ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3736 				if (ref == IR_UNUSED) {
3737 					/* dead edge */
3738 					pred_refs[i] = IR_UNUSED;
3739 				} else {
3740 					ir_op op = jit->ctx.ir_base[ref].op;
3741 
3742 					if (op == IR_IF) {
3743 						jit_IF_TRUE_FALSE_ex(jit, ref, b);
3744 						pred_refs[i] = ir_END();
3745 					} else if (op == IR_SWITCH) {
3746 						zend_jit_case_start(jit, pred, b, ref);
3747 						pred_refs[i] = ir_END();
3748 					} else {
3749 						ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3750 						pred_refs[i] = ref;
3751 					}
3752 				}
3753 			} else {
3754 				/* backward edge */
3755 				back_edges_count++;
3756 				pred_refs[i] = IR_UNUSED;
3757 			}
3758 		}
3759 
3760 		if (bb->flags & ZEND_BB_LOOP_HEADER) {
3761 			ZEND_ASSERT(back_edges_count != 0);
3762 			ZEND_ASSERT(forward_edges_count != 0);
3763 			ir_MERGE_N(n, pred_refs);
3764 			jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3765 			bb_start = jit->ctx.control;
3766 			if (entry_path) {
3767 				ir_MERGE_WITH(entry_path);
3768 			}
3769 		} else {
3770 //			ZEND_ASSERT(back_edges_count != 0);
3771 			/* edges from exceptional blocks may be counted as back edges */
3772 			ir_MERGE_N(n, pred_refs);
3773 			bb_start = jit->ctx.control;
3774 			if (entry_path) {
3775 				ir_MERGE_WITH(entry_path);
3776 			}
3777 		}
3778 		free_alloca(pred_refs, use_heap);
3779 	}
3780 	jit->b = b;
3781 	jit->bb_start_ref[b] = bb_start;
3782 
3783 	if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3784 		jit->ctx.fold_cse_limit = bb_start;
3785 	}
3786 
3787 	return 1;
3788 }
3789 
zend_jit_bb_end(zend_jit_ctx * jit,int b)3790 static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3791 {
3792 	int succ;
3793 	zend_basic_block *bb;
3794 
3795 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3796 	if (jit->b != b) {
3797 		return 1;
3798 	}
3799 
3800 	bb = &jit->ssa->cfg.blocks[b];
3801 	ZEND_ASSERT(bb->successors_count != 0);
3802 	if (bb->successors_count == 1) {
3803 		succ = bb->successors[0];
3804 	} else {
3805 		const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3806 
3807 		/* Use only the following successor of SWITCH and FE_RESET_R */
3808 		ZEND_ASSERT(opline->opcode == ZEND_SWITCH_LONG
3809 		 || opline->opcode == ZEND_SWITCH_STRING
3810 		 || opline->opcode == ZEND_MATCH
3811 		 || opline->opcode == ZEND_FE_RESET_R);
3812 		succ = b + 1;
3813 	}
3814 	_zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3815 	jit->b = -1;
3816 	return 1;
3817 }
3818 
jit_CMP_IP(zend_jit_ctx * jit,ir_op op,const zend_op * next_opline)3819 static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3820 {
3821 	ir_ref ref;
3822 
3823 #if 1
3824 	if (GCC_GLOBAL_REGS) {
3825 		ref = jit_IP32(jit);
3826 	} else {
3827 		ref = ir_LOAD_U32(jit_EX(opline));
3828 	}
3829 	ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3830 #else
3831 	if (GCC_GLOBAL_REGS) {
3832 		ref = jit_IP(jit);
3833 	} else {
3834 		ref = ir_LOAD_A(jit_EX(opline));
3835 	}
3836 	ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
3837 #endif
3838 	return ref;
3839 }
3840 
zend_jit_jmp_frameless(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr,zend_jmp_fl_result guard)3841 static int zend_jit_jmp_frameless(
3842 	zend_jit_ctx *jit,
3843 	const zend_op *opline,
3844 	const void *exit_addr,
3845 	zend_jmp_fl_result guard
3846 ) {
3847 	ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
3848 	zend_basic_block *bb;
3849 
3850 	// JIT: CACHED_PTR(opline->extended_value)
3851 	cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
3852 	cache_result = ir_LOAD_L(cache_slot_ref);
3853 
3854 	// JIT: if (UNEXPECTED(!result))
3855 	if_ref = ir_IF(cache_result);
3856 	ir_IF_FALSE_cold(if_ref);
3857 	zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3858 	function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3859 		ir_CONST_ADDR(func_name_zv),
3860 		cache_slot_ref);
3861 	ir_MERGE_WITH_EMPTY_TRUE(if_ref);
3862 
3863 	phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
3864 
3865 	if (exit_addr) {
3866 		ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3867 	} else {
3868 		ZEND_ASSERT(jit->b >= 0);
3869 		bb = &jit->ssa->cfg.blocks[jit->b];
3870 		// JIT: if (result == ZEND_JMP_FL_HIT)
3871 		ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3872 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3873 		_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3874 		jit->b = -1;
3875 	}
3876 
3877 	return 1;
3878 }
3879 
zend_jit_cond_jmp(zend_jit_ctx * jit,const zend_op * next_opline,int target_block)3880 static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
3881 {
3882 	ir_ref ref;
3883 	zend_basic_block *bb;
3884 
3885 	ZEND_ASSERT(jit->b >= 0);
3886 	bb = &jit->ssa->cfg.blocks[jit->b];
3887 
3888 	ZEND_ASSERT(bb->successors_count == 2);
3889 	if (bb->successors[0] == bb->successors[1]) {
3890 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
3891 		jit->b = -1;
3892 		zend_jit_set_last_valid_opline(jit, next_opline);
3893 		return 1;
3894 	}
3895 
3896 	ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
3897 
3898 	_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3899 	_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3900 
3901 	jit->b = -1;
3902 	zend_jit_set_last_valid_opline(jit, next_opline);
3903 
3904 	return 1;
3905 }
3906 
zend_jit_set_cond(zend_jit_ctx * jit,const zend_op * next_opline,uint32_t var)3907 static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *next_opline, uint32_t var)
3908 {
3909 	ir_ref ref;
3910 
3911 	ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, IR_EQ, next_opline)), ir_CONST_U32(IS_FALSE));
3912 
3913 	// EX_VAR(var) = ...
3914 	ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
3915 
3916 	zend_jit_reset_last_valid_opline(jit);
3917 	return zend_jit_set_ip(jit, next_opline - 1);
3918 }
3919 
3920 /* PHP JIT handlers */
zend_jit_check_exception(zend_jit_ctx * jit)3921 static void zend_jit_check_exception(zend_jit_ctx *jit)
3922 {
3923 	ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3924 		jit_STUB_ADDR(jit, jit_stub_exception_handler));
3925 }
3926 
zend_jit_check_exception_undef_result(zend_jit_ctx * jit,const zend_op * opline)3927 static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
3928 {
3929 	ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3930 		jit_STUB_ADDR(jit,
3931 			(opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
3932 }
3933 
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)3934 static void zend_jit_type_check_undef(zend_jit_ctx  *jit,
3935                                       ir_ref         type,
3936                                       uint32_t       var,
3937                                       const zend_op *opline,
3938                                       bool           check_exception,
3939                                       bool           in_cold_path,
3940                                       bool           undef_result)
3941 {
3942 	ir_ref if_def = ir_IF(type);
3943 
3944 	if (!in_cold_path) {
3945 		ir_IF_FALSE_cold(if_def);
3946 	} else {
3947 		ir_IF_FALSE(if_def);
3948 	}
3949 	if (opline) {
3950 		jit_SET_EX_OPLINE(jit, opline);
3951 	}
3952 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3953 	if (check_exception) {
3954 		if (undef_result) {
3955 			zend_jit_check_exception_undef_result(jit, opline);
3956 		} else {
3957 			zend_jit_check_exception(jit);
3958 		}
3959 	}
3960 	ir_MERGE_WITH_EMPTY_TRUE(if_def);
3961 }
3962 
zend_jit_zval_check_undef(zend_jit_ctx * jit,ir_ref ref,uint32_t var,const zend_op * opline,bool check_exception)3963 static ir_ref zend_jit_zval_check_undef(zend_jit_ctx  *jit,
3964                                         ir_ref         ref,
3965                                         uint32_t       var,
3966                                         const zend_op *opline,
3967                                         bool           check_exception)
3968 {
3969 	ir_ref if_def, ref2;
3970 
3971 	if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
3972 	ir_IF_FALSE_cold(if_def);
3973 
3974 	if (opline) {
3975 		jit_SET_EX_OPLINE(jit, opline);
3976 	}
3977 
3978 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3979 
3980 	if (check_exception) {
3981 		zend_jit_check_exception(jit);
3982 	}
3983 
3984 	ref2 = jit_EG(uninitialized_zval);
3985 
3986 	ir_MERGE_WITH_EMPTY_TRUE(if_def);
3987 
3988 	return ir_PHI_2(IR_ADDR, ref2, ref);
3989 }
3990 
zend_jit_recv_entry(zend_jit_ctx * jit,int b)3991 static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
3992 {
3993 	zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
3994 	int pred;
3995 	ir_ref ref;
3996 
3997 	ZEND_ASSERT(bb->predecessors_count > 0);
3998 
3999 	pred = jit->bb_predecessors[b];
4000 	ref = jit->bb_edges[pred];
4001 
4002 	ZEND_ASSERT(ref);
4003 	ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
4004 
4005 	/* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4006 	ir_ENTRY(ref, bb->start);
4007 	if (!GCC_GLOBAL_REGS) {
4008 		/* 2 is hardcoded reference to IR_PARAM */
4009 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4010 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4011 		jit_STORE_FP(jit, 2);
4012 	}
4013 
4014 	ir_MERGE_WITH(ref);
4015 	jit->bb_edges[pred] = ir_END();
4016 }
4017 
zend_jit_osr_entry(zend_jit_ctx * jit,int b)4018 static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4019 {
4020 	zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4021 	ir_ref ref = ir_END();
4022 
4023 	/* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4024 	ir_ENTRY(ref, bb->start);
4025 	if (!GCC_GLOBAL_REGS) {
4026 		/* 2 is hardcoded reference to IR_PARAM */
4027 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4028 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4029 		jit_STORE_FP(jit, 2);
4030 	}
4031 
4032 	ir_MERGE_WITH(ref);
4033 }
4034 
zend_jit_continue_entry(zend_jit_ctx * jit,ir_ref src,unsigned int label)4035 static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4036 {
4037 	ir_ENTRY(src, label);
4038 	if (!GCC_GLOBAL_REGS) {
4039 		/* 2 is hardcoded reference to IR_PARAM */
4040 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4041 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4042 		jit_STORE_FP(jit, 2);
4043 	}
4044 	return ir_END();
4045 }
4046 
zend_jit_handler(zend_jit_ctx * jit,const zend_op * opline,int may_throw)4047 static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4048 {
4049 	ir_ref ref;
4050 	const void *handler;
4051 
4052 	zend_jit_set_ip(jit, opline);
4053 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4054 		handler = zend_get_opcode_handler_func(opline);
4055 	} else {
4056 		handler = opline->handler;
4057 	}
4058 	if (GCC_GLOBAL_REGS) {
4059 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4060 	} else {
4061 		ref = jit_FP(jit);
4062 		ref = ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(handler), ref);
4063 	}
4064 	if (may_throw) {
4065 		zend_jit_check_exception(jit);
4066 	}
4067 	/* Skip the following OP_DATA */
4068 	switch (opline->opcode) {
4069 		case ZEND_ASSIGN_DIM:
4070 		case ZEND_ASSIGN_OBJ:
4071 		case ZEND_ASSIGN_STATIC_PROP:
4072 		case ZEND_ASSIGN_DIM_OP:
4073 		case ZEND_ASSIGN_OBJ_OP:
4074 		case ZEND_ASSIGN_STATIC_PROP_OP:
4075 		case ZEND_ASSIGN_STATIC_PROP_REF:
4076 		case ZEND_ASSIGN_OBJ_REF:
4077 			zend_jit_set_last_valid_opline(jit, opline + 2);
4078 			break;
4079 		default:
4080 			zend_jit_set_last_valid_opline(jit, opline + 1);
4081 			break;
4082 	}
4083 	return 1;
4084 }
4085 
zend_jit_tail_handler(zend_jit_ctx * jit,const zend_op * opline)4086 static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4087 {
4088 	const void *handler;
4089 	ir_ref ref;
4090 	zend_basic_block *bb;
4091 
4092 	zend_jit_set_ip(jit, opline);
4093 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4094 		if (opline->opcode == ZEND_DO_UCALL ||
4095 		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4096 		    opline->opcode == ZEND_DO_FCALL ||
4097 		    opline->opcode == ZEND_RETURN) {
4098 
4099 			/* Use inlined HYBRID VM handler */
4100 			handler = opline->handler;
4101 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4102 		} else {
4103 			handler = zend_get_opcode_handler_func(opline);
4104 			ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4105 			ref = ir_LOAD_A(jit_IP(jit));
4106 			ir_TAILCALL(IR_VOID, ref);
4107 		}
4108 	} else {
4109 		handler = opline->handler;
4110 		if (GCC_GLOBAL_REGS) {
4111 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4112 		} else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4113 		 && (opline->opcode == ZEND_CATCH
4114 		  || opline->opcode == ZEND_FAST_CALL
4115 		  || opline->opcode == ZEND_FAST_RET
4116 		  || opline->opcode == ZEND_MATCH_ERROR
4117 		  || opline->opcode == ZEND_THROW
4118 		  || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4119 			ref = jit_FP(jit);
4120 			ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4121 			ir_RETURN(ir_CONST_I32(1));
4122 		} else {
4123 			ref = jit_FP(jit);
4124 			ir_TAILCALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4125 		}
4126 	}
4127 	if (jit->b >= 0) {
4128 		bb = &jit->ssa->cfg.blocks[jit->b];
4129 		if (bb->successors_count > 0
4130 		 && (opline->opcode == ZEND_DO_FCALL
4131 		  || opline->opcode == ZEND_DO_UCALL
4132 		  || opline->opcode == ZEND_DO_FCALL_BY_NAME
4133 		  || opline->opcode == ZEND_INCLUDE_OR_EVAL
4134 		  || opline->opcode == ZEND_GENERATOR_CREATE
4135 		  || opline->opcode == ZEND_YIELD
4136 		  || opline->opcode == ZEND_YIELD_FROM
4137 		  || opline->opcode == ZEND_FAST_CALL)) {
4138 			/* Add a fake control edge from UNREACHABLE to the following ENTRY */
4139 			int succ;
4140 
4141 			if (bb->successors_count == 1) {
4142 				succ = bb->successors[0];
4143 				ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
4144 			} else {
4145 				/* Use only the following successor of FAST_CALL */
4146 				ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4147 				succ = jit->b + 1;
4148 				/* we need an entry */
4149 				jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4150 			}
4151 			ref = jit->ctx.insns_count - 1;
4152 			ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4153 			ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4154 			_zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4155 		}
4156 		jit->b = -1;
4157 		zend_jit_reset_last_valid_opline(jit);
4158 	}
4159 	return 1;
4160 }
4161 
zend_jit_call(zend_jit_ctx * jit,const zend_op * opline,unsigned int next_block)4162 static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4163 {
4164 	return zend_jit_tail_handler(jit, opline);
4165 }
4166 
zend_jit_spill_store(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info,bool set_type)4167 static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4168 {
4169 	ZEND_ASSERT(Z_MODE(src) == IS_REG);
4170 	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4171 
4172 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4173 		jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4174 		if (set_type &&
4175 		    (Z_REG(dst) != ZREG_FP ||
4176 		     !JIT_G(current_frame) ||
4177 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4178 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4179 		}
4180 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4181 		jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4182 		if (set_type &&
4183 		    (Z_REG(dst) != ZREG_FP ||
4184 		     !JIT_G(current_frame) ||
4185 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4186 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4187 		}
4188 	} else {
4189 		ZEND_UNREACHABLE();
4190 	}
4191 	return 1;
4192 }
4193 
zend_jit_spill_store_inv(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4194 static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4195 {
4196 	ZEND_ASSERT(Z_MODE(src) == IS_REG);
4197 	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4198 
4199 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4200 		jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4201 		if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4202 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4203 		} else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4204 			/* invalidate memory type */
4205 			STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4206 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4207 		}
4208 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4209 		jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4210 		if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4211 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4212 		} else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4213 			/* invalidate memory type */
4214 			STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4215 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4216 		}
4217 	} else {
4218 		ZEND_UNREACHABLE();
4219 	}
4220 	return 1;
4221 }
4222 
zend_jit_load_reg(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4223 static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4224 {
4225 	ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
4226 	ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4227 
4228 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4229 		zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4230 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4231 		zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4232 	} else {
4233 		ZEND_UNREACHABLE();
4234 	}
4235 	return 1;
4236 }
4237 
zend_jit_store_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var,bool set_type)4238 static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4239 {
4240 	zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4241 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4242 
4243 	return zend_jit_spill_store(jit, src, dst, info, set_type);
4244 }
4245 
zend_jit_store_ref(zend_jit_ctx * jit,uint32_t info,int var,int32_t src,bool set_type)4246 static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4247 {
4248 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4249 
4250 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4251 		jit_set_Z_LVAL(jit, dst, src);
4252 		if (set_type &&
4253 		    (Z_REG(dst) != ZREG_FP ||
4254 		     !JIT_G(current_frame) ||
4255 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4256 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4257 		}
4258 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4259 		jit_set_Z_DVAL(jit, dst, src);
4260 		if (set_type &&
4261 		    (Z_REG(dst) != ZREG_FP ||
4262 		     !JIT_G(current_frame) ||
4263 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4264 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4265 		}
4266 	} else {
4267 		ZEND_UNREACHABLE();
4268 	}
4269 	return 1;
4270 }
4271 
zend_jit_deopt_rload(zend_jit_ctx * jit,ir_type type,int32_t reg)4272 static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4273 {
4274 	ir_ref ref = jit->ctx.control;
4275 	ir_insn *insn;
4276 
4277 	while (1) {
4278 		insn = &jit->ctx.ir_base[ref];
4279 		if (insn->op == IR_RLOAD && insn->op2 == reg) {
4280 			ZEND_ASSERT(insn->type == type);
4281 			return ref;
4282 		} else if (insn->op == IR_START) {
4283 			break;
4284 		}
4285 		ref = insn->op1;
4286 	}
4287 	return ir_RLOAD(type, reg);
4288 }
4289 
zend_jit_store_const_long(zend_jit_ctx * jit,int var,zend_long val)4290 static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4291 {
4292 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4293 	ir_ref src = ir_CONST_LONG(val);
4294 
4295 	if (jit->ra && jit->ra[var].ref == IR_NULL) {
4296 		zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4297 	}
4298 	jit_set_Z_LVAL(jit, dst, src);
4299 	jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4300 	return 1;
4301 }
4302 
zend_jit_store_const_double(zend_jit_ctx * jit,int var,double val)4303 static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4304 {
4305 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4306 	ir_ref src = ir_CONST_DOUBLE(val);
4307 
4308 	if (jit->ra && jit->ra[var].ref == IR_NULL) {
4309 		zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4310 	}
4311 	jit_set_Z_DVAL(jit, dst, src);
4312 	jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4313 	return 1;
4314 }
4315 
zend_jit_store_type(zend_jit_ctx * jit,int var,uint8_t type)4316 static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4317 {
4318 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4319 
4320 	ZEND_ASSERT(type <= IS_DOUBLE);
4321 	jit_set_Z_TYPE_INFO(jit, dst, type);
4322 	return 1;
4323 }
4324 
zend_jit_store_reg(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,bool in_mem,bool set_type)4325 static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4326 {
4327 	zend_jit_addr src;
4328 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4329 	ir_type type;
4330 
4331 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4332 		type = IR_LONG;
4333 		src = zend_jit_deopt_rload(jit, type, reg);
4334 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4335 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4336 		} else if (!in_mem) {
4337 			jit_set_Z_LVAL(jit, dst, src);
4338 			if (set_type &&
4339 			    (Z_REG(dst) != ZREG_FP ||
4340 			     !JIT_G(current_frame) ||
4341 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4342 				jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4343 			}
4344 		}
4345 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4346 		type = IR_DOUBLE;
4347 		src = zend_jit_deopt_rload(jit, type, reg);
4348 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4349 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4350 		} else if (!in_mem) {
4351 			jit_set_Z_DVAL(jit, dst, src);
4352 			if (set_type &&
4353 			    (Z_REG(dst) != ZREG_FP ||
4354 			     !JIT_G(current_frame) ||
4355 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4356 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4357 			}
4358 		}
4359 	} else {
4360 		ZEND_UNREACHABLE();
4361 	}
4362 	return 1;
4363 }
4364 
zend_jit_store_spill_slot(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,int32_t offset,bool set_type)4365 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)
4366 {
4367 	zend_jit_addr src;
4368 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4369 
4370 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4371 		src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4372 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4373 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4374 		} else {
4375 			jit_set_Z_LVAL(jit, dst, src);
4376 			if (set_type &&
4377 			    (Z_REG(dst) != ZREG_FP ||
4378 			     !JIT_G(current_frame) ||
4379 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4380 				jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4381 			}
4382 		}
4383 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4384 		src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4385 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4386 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4387 		} else {
4388 			jit_set_Z_DVAL(jit, dst, src);
4389 			if (set_type &&
4390 			    (Z_REG(dst) != ZREG_FP ||
4391 			     !JIT_G(current_frame) ||
4392 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4393 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4394 			}
4395 		}
4396 	} else {
4397 		ZEND_UNREACHABLE();
4398 	}
4399 	return 1;
4400 }
4401 
zend_jit_store_var_type(zend_jit_ctx * jit,int var,uint32_t type)4402 static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4403 {
4404 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4405 
4406 	jit_set_Z_TYPE_INFO(jit, dst, type);
4407 	return 1;
4408 }
4409 
zend_jit_zval_try_addref(zend_jit_ctx * jit,zend_jit_addr var_addr)4410 static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4411 {
4412 	ir_ref if_refcounted, end1;
4413 
4414 	if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4415 	ir_IF_FALSE(if_refcounted);
4416 	end1 = ir_END();
4417 	ir_IF_TRUE(if_refcounted);
4418 	jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4419 	ir_MERGE_WITH(end1);
4420 	return 1;
4421 }
4422 
zend_jit_store_var_if_necessary(zend_jit_ctx * jit,int var,zend_jit_addr src,uint32_t info)4423 static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4424 {
4425 	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4426 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4427 		return zend_jit_spill_store(jit, src, dst, info, 1);
4428 	}
4429 	return 1;
4430 }
4431 
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)4432 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)
4433 {
4434 	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4435 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4436 		bool set_type = 1;
4437 
4438 		if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4439 		    (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4440 			if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4441 				if (JIT_G(current_frame)) {
4442 					uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4443 
4444 					if (mem_type != IS_UNKNOWN
4445 					 && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4446 						set_type = 0;
4447 					}
4448 				} else {
4449 					set_type = 0;
4450 				}
4451 			}
4452 		}
4453 		return zend_jit_spill_store(jit, src, dst, info, set_type);
4454 	}
4455 	return 1;
4456 }
4457 
zend_jit_load_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var)4458 static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4459 {
4460 	zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4461 	zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4462 
4463 	return zend_jit_load_reg(jit, src, dst, info);
4464 }
4465 
zend_jit_invalidate_var_if_necessary(zend_jit_ctx * jit,uint8_t op_type,zend_jit_addr addr,znode_op op)4466 static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4467 {
4468 	if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4469 		/* Invalidate operand type to prevent incorrect destuction by exception_handler_free_op1_op2() */
4470 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4471 		jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4472 	}
4473 	return 1;
4474 }
4475 
zend_jit_update_regs(zend_jit_ctx * jit,uint32_t var,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4476 static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4477 {
4478 	if (!zend_jit_same_addr(src, dst)) {
4479 		if (Z_MODE(src) == IS_REG) {
4480 			if (Z_MODE(dst) == IS_REG) {
4481 				zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4482 				if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4483 					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4484 
4485 					if (!zend_jit_spill_store(jit, dst, var_addr, info,
4486 							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4487 							JIT_G(current_frame) == NULL ||
4488 							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4489 							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4490 					)) {
4491 						return 0;
4492 					}
4493 				}
4494 			} else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4495 				if (!Z_LOAD(src) && !Z_STORE(src)) {
4496 					if (!zend_jit_spill_store(jit, src, dst, info,
4497 							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4498 							JIT_G(current_frame) == NULL ||
4499 							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4500 							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4501 					)) {
4502 						return 0;
4503 					}
4504 				}
4505 			} else {
4506 				ZEND_UNREACHABLE();
4507 			}
4508 		} else if (Z_MODE(src) == IS_MEM_ZVAL) {
4509 			if (Z_MODE(dst) == IS_REG) {
4510 				if (!zend_jit_load_reg(jit, src, dst, info)) {
4511 					return 0;
4512 				}
4513 			} else {
4514 				ZEND_UNREACHABLE();
4515 			}
4516 		} else {
4517 			ZEND_UNREACHABLE();
4518 		}
4519 	} else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4520 		dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4521 		if (!zend_jit_spill_store(jit, src, dst, info,
4522 				JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4523 				JIT_G(current_frame) == NULL ||
4524 				STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4525 				(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4526 		)) {
4527 			return 0;
4528 		}
4529 	}
4530 	return 1;
4531 }
4532 
4533 struct jit_observer_fcall_is_unobserved_data {
4534 	ir_ref if_unobserved;
4535 	ir_ref ir_end_inputs;
4536 };
4537 
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)4538 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) {
4539 	ir_ref run_time_cache;
4540 	struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4541 	if (func) {
4542 		ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4543 	} else {
4544 		// JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4545 		ZEND_ASSERT(rx != IR_UNUSED);
4546 		ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4547 			ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4548 			ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4549 		ir_IF_TRUE(if_trampoline_or_generator);
4550 		ir_END_list(data.ir_end_inputs);
4551 		ir_IF_FALSE(if_trampoline_or_generator);
4552 	}
4553 	if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4554 		// JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4555 		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)));
4556 #ifndef ZTS
4557 	} else if (func && rx == IS_UNUSED) { // happens for internal functions only
4558 		ZEND_ASSERT(!ZEND_USER_CODE(func->type));
4559 		run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4560 #endif
4561 	} else {
4562 		// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4563 		if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4564 			run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4565 		} else {
4566 			// JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4567 			run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4568 			ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4569 			ir_IF_TRUE(if_odd);
4570 
4571 			ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4572 
4573 			ir_ref if_odd_end = ir_END();
4574 			ir_IF_FALSE(if_odd);
4575 
4576 			// JIT: if (func->common.runtime_cache != NULL) {
4577 			ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4578 			ir_IF_TRUE(if_rt_cache);
4579 			ir_END_list(data.ir_end_inputs);
4580 			ir_IF_FALSE(if_rt_cache);
4581 
4582 			ir_MERGE_WITH(if_odd_end);
4583 			run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4584 		}
4585 	}
4586 	// JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4587 	if (func) {
4588 		*observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4589 	} else {
4590 		// JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4591 		ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4592 		ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4593 		ir_IF_TRUE(if_internal_func);
4594 
4595 		ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4596 
4597 		ir_ref if_internal_func_end = ir_END();
4598 		ir_IF_FALSE(if_internal_func);
4599 
4600 		ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4601 
4602 		ir_MERGE_WITH(if_internal_func_end);
4603 		*observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
4604 	}
4605 
4606 	// JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4607 	data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4608 	ir_IF_FALSE(data.if_unobserved);
4609 	return data;
4610 }
4611 
4612 /* 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)4613 static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4614 	ir_END_list(data->ir_end_inputs);
4615 	ir_IF_TRUE(data->if_unobserved);
4616 	ir_END_list(data->ir_end_inputs);
4617 	ir_MERGE_list(data->ir_end_inputs);
4618 }
4619 
jit_observer_fcall_begin(zend_jit_ctx * jit,ir_ref rx,ir_ref observer_handler)4620 static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4621 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4622 }
4623 
jit_observer_fcall_end(zend_jit_ctx * jit,ir_ref rx,ir_ref res_ref)4624 static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4625 	// JIT: if (execute_data == EG(current_observed_frame)) {
4626 	ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4627 	ir_IF_TRUE(has_end_observer);
4628 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4629 		rx, res_ref);
4630 	ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4631 }
4632 
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)4633 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)
4634 {
4635 	ir_ref if_long = IR_UNUSED;
4636 	ir_ref op1_lval_ref = IR_UNUSED;
4637 	ir_ref ref;
4638 	ir_op op;
4639 
4640 	if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4641 		if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4642 		ir_IF_TRUE(if_long);
4643 	}
4644 	if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4645 		op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4646 		jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4647 		if (Z_MODE(res_addr) != IS_REG) {
4648 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4649 		}
4650 	}
4651 	if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4652 	 && Z_MODE(op1_addr) == IS_REG
4653 	 && !Z_LOAD(op1_addr)
4654 	 && !Z_STORE(op1_addr)) {
4655 		jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4656 	}
4657 	if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4658 		op = may_overflow ? IR_ADD_OV : IR_ADD;
4659 	} else {
4660 		op = may_overflow ? IR_SUB_OV : IR_SUB;
4661 	}
4662 	if (!op1_lval_ref) {
4663 		op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4664 	}
4665 	ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4666 	if (op1_def_info & MAY_BE_LONG) {
4667 		jit_set_Z_LVAL(jit, op1_def_addr, ref);
4668 	}
4669 	if (may_overflow &&
4670 	    (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4671 	     ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4672 		int32_t exit_point;
4673 		const void *exit_addr;
4674 		zend_jit_trace_stack *stack;
4675 		uint32_t old_op1_info, old_res_info = 0;
4676 
4677 		stack = JIT_G(current_frame)->stack;
4678 		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4679 		SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4680 		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4681 			SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4682 		} else {
4683 			SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4684 		}
4685 		if (opline->result_type != IS_UNUSED) {
4686 			old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4687 			if (opline->opcode == ZEND_PRE_INC) {
4688 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4689 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4690 			} else if (opline->opcode == ZEND_PRE_DEC) {
4691 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4692 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4693 			} else if (opline->opcode == ZEND_POST_INC) {
4694 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4695 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MAX));
4696 			} else if (opline->opcode == ZEND_POST_DEC) {
4697 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4698 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MIN));
4699 			}
4700 		}
4701 
4702 		exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4703 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4704 		ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4705 
4706 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4707 		    opline->result_type != IS_UNUSED) {
4708 			jit_set_Z_LVAL(jit, res_addr, ref);
4709 			if (Z_MODE(res_addr) != IS_REG) {
4710 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4711 			}
4712 		}
4713 
4714 		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4715 		if (opline->result_type != IS_UNUSED) {
4716 			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4717 		}
4718 	} else if (may_overflow) {
4719 		ir_ref if_overflow;
4720 		ir_ref merge_inputs = IR_UNUSED;
4721 
4722 		if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4723 		 || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) ==  (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4724 			int32_t exit_point;
4725 			const void *exit_addr;
4726 			zend_jit_trace_stack *stack;
4727 			uint32_t old_res_info = 0;
4728 
4729 			stack = JIT_G(current_frame)->stack;
4730 			if (opline->result_type != IS_UNUSED) {
4731 				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4732 				if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4733 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4734 				}
4735 			}
4736 			exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4737 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4738 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4739 			    opline->result_type != IS_UNUSED) {
4740 				if_overflow = ir_IF(ir_OVERFLOW(ref));
4741 				ir_IF_FALSE_cold(if_overflow);
4742 				jit_set_Z_LVAL(jit, res_addr, ref);
4743 				if (Z_MODE(res_addr) != IS_REG) {
4744 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4745 				}
4746 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
4747 				ir_IF_TRUE(if_overflow);
4748 			} else {
4749 				ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4750 			}
4751 			if (opline->result_type != IS_UNUSED) {
4752 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4753 			}
4754 		} else {
4755 			if_overflow = ir_IF(ir_OVERFLOW(ref));
4756 			ir_IF_FALSE(if_overflow);
4757 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4758 			    opline->result_type != IS_UNUSED) {
4759 				jit_set_Z_LVAL(jit, res_addr, ref);
4760 				if (Z_MODE(res_addr) != IS_REG) {
4761 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4762 				}
4763 			}
4764 			ir_END_list(merge_inputs);
4765 
4766 			/* overflow => cold path */
4767 			ir_IF_TRUE_cold(if_overflow);
4768 		}
4769 
4770 		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4771 			if (Z_MODE(op1_def_addr) == IS_REG) {
4772 				jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4773 			} else {
4774 #if SIZEOF_ZEND_LONG == 4
4775 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0));
4776 				jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0x41e00000));
4777 #else
4778 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4779 #endif
4780 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4781 			}
4782 		} else {
4783 			if (Z_MODE(op1_def_addr) == IS_REG) {
4784 				jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4785 			} else {
4786 #if SIZEOF_ZEND_LONG == 4
4787 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x00200000));
4788 				jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0xc1e00000));
4789 #else
4790 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4791 #endif
4792 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4793 			}
4794 		}
4795 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4796 		    opline->result_type != IS_UNUSED) {
4797 			if (opline->opcode == ZEND_PRE_INC) {
4798 				if (Z_MODE(res_addr) == IS_REG) {
4799 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4800 				} else {
4801 #if SIZEOF_ZEND_LONG == 4
4802 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
4803 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
4804 #else
4805 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4806 #endif
4807 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4808 				}
4809 			} else {
4810 				if (Z_MODE(res_addr) == IS_REG) {
4811 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4812 				} else {
4813 #if SIZEOF_ZEND_LONG == 4
4814 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
4815 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
4816 #else
4817 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
4818 #endif
4819 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4820 				}
4821 			}
4822 		}
4823 
4824 		if (merge_inputs) {
4825 			ir_END_list(merge_inputs);
4826 			ir_MERGE_list(merge_inputs);
4827 		}
4828 	} else {
4829 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4830 		    opline->result_type != IS_UNUSED) {
4831 			jit_set_Z_LVAL(jit, res_addr, ref);
4832 			if (Z_MODE(res_addr) != IS_REG) {
4833 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4834 			}
4835 		}
4836 	}
4837 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4838 		ir_ref merge_inputs = ir_END();
4839 
4840 		/* !is_long => cold path */
4841 		ir_IF_FALSE_cold(if_long);
4842 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4843 			jit_SET_EX_OPLINE(jit, opline);
4844 			if (op1_info & MAY_BE_UNDEF) {
4845 				ir_ref if_def;
4846 
4847 				if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
4848 				ir_IF_FALSE_cold(if_def);
4849 
4850 				// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
4851 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
4852 
4853 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
4854 				ir_MERGE_WITH_EMPTY_TRUE(if_def);
4855 
4856 				op1_info |= MAY_BE_NULL;
4857 			}
4858 
4859 			ref = jit_ZVAL_ADDR(jit, op1_addr);
4860 
4861 			if (op1_info & MAY_BE_REF) {
4862 				ir_ref if_ref, if_typed, func, ref2, arg2;
4863 
4864 				if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
4865 				ir_IF_TRUE(if_ref);
4866 				ref2 = jit_Z_PTR_ref(jit, ref);
4867 
4868 				if_typed = jit_if_TYPED_REF(jit, ref2);
4869 				ir_IF_TRUE(if_typed);
4870 
4871 				if (RETURN_VALUE_USED(opline)) {
4872 					ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
4873 					arg2 = jit_ZVAL_ADDR(jit, res_addr);
4874 				} else {
4875 					arg2 = IR_NULL;
4876 				}
4877 				if (opline->opcode == ZEND_PRE_INC) {
4878 					func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
4879 				} else if (opline->opcode == ZEND_PRE_DEC) {
4880 					func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
4881 				} else if (opline->opcode == ZEND_POST_INC) {
4882 					func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
4883 				} else if (opline->opcode == ZEND_POST_DEC) {
4884 					func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
4885 				} else {
4886 					ZEND_UNREACHABLE();
4887 				}
4888 
4889 				ir_CALL_2(IR_VOID, func, ref2, arg2);
4890 				zend_jit_check_exception(jit);
4891 				ir_END_list(merge_inputs);
4892 
4893 				ir_IF_FALSE(if_typed);
4894 				ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
4895 				ir_MERGE_WITH_EMPTY_FALSE(if_ref);
4896 				ref = ir_PHI_2(IR_ADDR, ref2, ref);
4897 			}
4898 
4899 			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4900 				jit_ZVAL_COPY(jit,
4901 					res_addr,
4902 					res_use_info,
4903 					ZEND_ADDR_REF_ZVAL(ref), op1_info, 1);
4904 			}
4905 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4906 				if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
4907 					ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4908 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
4909 				} else {
4910 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function), ref);
4911 				}
4912 			} else {
4913 				if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
4914 					ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4915 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec), ref, arg2);
4916 				} else {
4917 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function), ref);
4918 				}
4919 			}
4920 			if (may_throw) {
4921 				zend_jit_check_exception(jit);
4922 			}
4923 		} else {
4924 			ref = jit_Z_DVAL(jit, op1_addr);
4925 			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4926 				jit_set_Z_DVAL(jit, res_addr, ref);
4927 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4928 			}
4929 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4930 				op = IR_ADD;
4931 			} else {
4932 				op = IR_SUB;
4933 			}
4934 			ref = ir_BINARY_OP_D(op, ref, ir_CONST_DOUBLE(1.0));
4935 			jit_set_Z_DVAL(jit, op1_def_addr, ref);
4936 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4937 			    opline->result_type != IS_UNUSED) {
4938 				jit_set_Z_DVAL(jit, res_addr, ref);
4939 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4940 			}
4941 		}
4942 		ir_END_list(merge_inputs);
4943 		ir_MERGE_list(merge_inputs);
4944 	}
4945 	if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
4946 		return 0;
4947 	}
4948 	if (opline->result_type != IS_UNUSED) {
4949 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
4950 			return 0;
4951 		}
4952 	}
4953 	return 1;
4954 }
4955 
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)4956 static int zend_jit_math_long_long(zend_jit_ctx   *jit,
4957                                    const zend_op  *opline,
4958                                    uint8_t         opcode,
4959                                    zend_jit_addr   op1_addr,
4960                                    zend_jit_addr   op2_addr,
4961                                    zend_jit_addr   res_addr,
4962                                    uint32_t        res_info,
4963                                    uint32_t        res_use_info,
4964                                    int             may_overflow)
4965 {
4966 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4967 	ir_op op;
4968 	ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
4969 
4970 	if (opcode == ZEND_ADD) {
4971 		op = may_overflow ? IR_ADD_OV : IR_ADD;
4972 	} else if (opcode == ZEND_SUB) {
4973 		op = may_overflow ? IR_SUB_OV : IR_SUB;
4974 	} else if (opcode == ZEND_MUL) {
4975 		op = may_overflow ? IR_MUL_OV : IR_MUL;
4976 	} else {
4977 		ZEND_UNREACHABLE();
4978 	}
4979 	op1 = jit_Z_LVAL(jit, op1_addr);
4980 	op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
4981 	ref = ir_BINARY_OP_L(op, op1, op2);
4982 
4983 	if (may_overflow) {
4984 		if (res_info & MAY_BE_GUARD) {
4985 			if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
4986 				zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
4987 				uint32_t old_res_info;
4988 				int32_t exit_point;
4989 				const void *exit_addr;
4990 
4991 				if (opline->opcode == ZEND_ADD
4992 				 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
4993 					old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4994 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4995 					SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4996 					exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4997 					SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4998 				} else if (opline->opcode == ZEND_SUB
4999 				 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5000 					old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5001 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5002 					SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5003 					exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5004 					SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5005 				} else {
5006 					exit_point = zend_jit_trace_get_exit_point(opline, 0);
5007 				}
5008 
5009 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5010 				if (!exit_addr) {
5011 					return 0;
5012 				}
5013 				ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5014 				may_overflow = 0;
5015 			} else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
5016 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
5017 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5018 
5019 				if (!exit_addr) {
5020 					return 0;
5021 				}
5022 				ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5023 			} else {
5024 				ZEND_UNREACHABLE();
5025 			}
5026 		} else {
5027 			if_overflow = ir_IF(ir_OVERFLOW(ref));
5028 			ir_IF_FALSE(if_overflow);
5029 		}
5030 	}
5031 
5032 	if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5033 		jit_set_Z_LVAL(jit, res_addr, ref);
5034 
5035 		if (Z_MODE(res_addr) != IS_REG) {
5036 			if (!zend_jit_same_addr(op1_addr, res_addr)) {
5037 				if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5038 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5039 				}
5040 			}
5041 		}
5042 	}
5043 
5044 	if (may_overflow) {
5045 		ir_ref fast_path = IR_UNUSED;
5046 
5047 		if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5048 			fast_path = ir_END();
5049 			ir_IF_TRUE_cold(if_overflow);
5050 		}
5051 		if (opcode == ZEND_ADD) {
5052 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5053 				if (Z_MODE(res_addr) == IS_REG) {
5054 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5055 				} else {
5056 #if SIZEOF_ZEND_LONG == 4
5057 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
5058 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
5059 #else
5060 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5061 #endif
5062 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5063 				}
5064 				if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5065 					ir_MERGE_WITH(fast_path);
5066 				}
5067 				return 1;
5068 			}
5069 			op = IR_ADD;
5070 		} else if (opcode == ZEND_SUB) {
5071 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5072 				if (Z_MODE(res_addr) == IS_REG) {
5073 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5074 				} else {
5075 #if SIZEOF_ZEND_LONG == 4
5076 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
5077 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
5078 #else
5079 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
5080 #endif
5081 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5082 				}
5083 				if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5084 					ir_MERGE_WITH(fast_path);
5085 				}
5086 				return 1;
5087 			}
5088 			op = IR_SUB;
5089 		} else if (opcode == ZEND_MUL) {
5090 			op = IR_MUL;
5091 		} else {
5092 			ZEND_UNREACHABLE();
5093 		}
5094 #if 1
5095 		/* reload */
5096 		op1 = jit_Z_LVAL(jit, op1_addr);
5097 		op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5098 #endif
5099 #if 1
5100 		/* disable CSE */
5101 		ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5102 		jit->ctx.fold_cse_limit = 0x7fffffff;
5103 #endif
5104 		op1 = ir_INT2D(op1);
5105 		op2 = ir_INT2D(op2);
5106 #if 1
5107 		jit->ctx.fold_cse_limit = old_cse_limit;
5108 #endif
5109 		ref = ir_BINARY_OP_D(op, op1, op2);
5110 		jit_set_Z_DVAL(jit, res_addr, ref);
5111 		if (Z_MODE(res_addr) != IS_REG) {
5112 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5113 		}
5114 		if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5115 			ir_MERGE_WITH(fast_path);
5116 		}
5117 	}
5118 
5119 	return 1;
5120 }
5121 
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)5122 static int zend_jit_math_long_double(zend_jit_ctx   *jit,
5123                                      uint8_t         opcode,
5124                                      zend_jit_addr   op1_addr,
5125                                      zend_jit_addr   op2_addr,
5126                                      zend_jit_addr   res_addr,
5127                                      uint32_t        res_use_info)
5128 {
5129 	ir_op op;
5130 	ir_ref op1, op2, ref;
5131 
5132 	if (opcode == ZEND_ADD) {
5133 		op = IR_ADD;
5134 	} else if (opcode == ZEND_SUB) {
5135 		op = IR_SUB;
5136 	} else if (opcode == ZEND_MUL) {
5137 		op = IR_MUL;
5138 	} else if (opcode == ZEND_DIV) {
5139 		op = IR_DIV;
5140 	} else {
5141 		ZEND_UNREACHABLE();
5142 	}
5143 	op1 = jit_Z_LVAL(jit, op1_addr);
5144 	op2 = jit_Z_DVAL(jit, op2_addr);
5145 	ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5146 	jit_set_Z_DVAL(jit, res_addr, ref);
5147 
5148 	if (Z_MODE(res_addr) != IS_REG) {
5149 		if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5150 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5151 		}
5152 	}
5153 	return 1;
5154 }
5155 
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)5156 static int zend_jit_math_double_long(zend_jit_ctx   *jit,
5157                                      uint8_t         opcode,
5158                                      zend_jit_addr   op1_addr,
5159                                      zend_jit_addr   op2_addr,
5160                                      zend_jit_addr   res_addr,
5161                                      uint32_t        res_use_info)
5162 {
5163 	ir_op op;
5164 	ir_ref op1, op2, ref;
5165 
5166 	if (opcode == ZEND_ADD) {
5167 		op = IR_ADD;
5168 	} else if (opcode == ZEND_SUB) {
5169 		op = IR_SUB;
5170 	} else if (opcode == ZEND_MUL) {
5171 		op = IR_MUL;
5172 	} else if (opcode == ZEND_DIV) {
5173 		op = IR_DIV;
5174 	} else {
5175 		ZEND_UNREACHABLE();
5176 	}
5177 	op1 = jit_Z_DVAL(jit, op1_addr);
5178 	op2 = jit_Z_LVAL(jit, op2_addr);
5179 	ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5180 	jit_set_Z_DVAL(jit, res_addr, ref);
5181 
5182 	if (Z_MODE(res_addr) != IS_REG) {
5183 		if (!zend_jit_same_addr(op1_addr, res_addr)) {
5184 			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5185 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5186 			}
5187 		}
5188 	}
5189 	return 1;
5190 }
5191 
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)5192 static int zend_jit_math_double_double(zend_jit_ctx   *jit,
5193                                        uint8_t         opcode,
5194                                        zend_jit_addr   op1_addr,
5195                                        zend_jit_addr   op2_addr,
5196                                        zend_jit_addr   res_addr,
5197                                        uint32_t        res_use_info)
5198 {
5199 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5200 	ir_op op;
5201 	ir_ref op1, op2, ref;
5202 
5203 	if (opcode == ZEND_ADD) {
5204 		op = IR_ADD;
5205 	} else if (opcode == ZEND_SUB) {
5206 		op = IR_SUB;
5207 	} else if (opcode == ZEND_MUL) {
5208 		op = IR_MUL;
5209 	} else if (opcode == ZEND_DIV) {
5210 		op = IR_DIV;
5211 	} else {
5212 		ZEND_UNREACHABLE();
5213 	}
5214 	op1 = jit_Z_DVAL(jit, op1_addr);
5215 	op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5216 	ref = ir_BINARY_OP_D(op, op1, op2);
5217 	jit_set_Z_DVAL(jit, res_addr, ref);
5218 
5219 	if (Z_MODE(res_addr) != IS_REG) {
5220 		if (!zend_jit_same_addr(op1_addr, res_addr)) {
5221 			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5222 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5223 			}
5224 		}
5225 	}
5226 	return 1;
5227 }
5228 
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)5229 static int zend_jit_math_helper(zend_jit_ctx   *jit,
5230                                 const zend_op  *opline,
5231                                 uint8_t         opcode,
5232                                 uint8_t         op1_type,
5233                                 znode_op        op1,
5234                                 zend_jit_addr   op1_addr,
5235                                 uint32_t        op1_info,
5236                                 uint8_t         op2_type,
5237                                 znode_op        op2,
5238                                 zend_jit_addr   op2_addr,
5239                                 uint32_t        op2_info,
5240                                 uint32_t        res_var,
5241                                 zend_jit_addr   res_addr,
5242                                 uint32_t        res_info,
5243                                 uint32_t        res_use_info,
5244                                 int             may_overflow,
5245                                 int             may_throw)
5246 {
5247 	ir_ref if_op1_long = IR_UNUSED;
5248 	ir_ref if_op1_double = IR_UNUSED;
5249 	ir_ref if_op2_double = IR_UNUSED;
5250 	ir_ref if_op1_long_op2_long = IR_UNUSED;
5251 	ir_ref if_op1_long_op2_double = IR_UNUSED;
5252 	ir_ref if_op1_double_op2_double = IR_UNUSED;
5253 	ir_ref if_op1_double_op2_long = IR_UNUSED;
5254 	ir_ref slow_inputs = IR_UNUSED;
5255 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5256 	ir_refs *end_inputs;
5257 	ir_refs *res_inputs;
5258 
5259 	ir_refs_init(end_inputs, 6);
5260 	ir_refs_init(res_inputs, 6);
5261 
5262 	if (Z_MODE(op1_addr) == IS_REG) {
5263 		if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5264 			/* Force load */
5265 			zend_jit_use_reg(jit, op1_addr);
5266 		}
5267 	} else if (Z_MODE(op2_addr) == IS_REG) {
5268 		if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5269 			/* Force load */
5270 			zend_jit_use_reg(jit, op2_addr);
5271 		}
5272 	}
5273 
5274 	if (Z_MODE(res_addr) == IS_REG) {
5275 		jit->delay_var = Z_SSA_VAR(res_addr);
5276 		jit->delay_refs = res_inputs;
5277 	}
5278 
5279 	if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5280 		if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5281 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5282 			ir_IF_TRUE(if_op1_long);
5283 		}
5284 		if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5285 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5286 			ir_IF_TRUE(if_op1_long_op2_long);
5287 		}
5288 		if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5289 			return 0;
5290 		}
5291 		ir_refs_add(end_inputs, ir_END());
5292 		if (if_op1_long) {
5293 			ir_IF_FALSE_cold(if_op1_long);
5294 			ir_END_list(slow_inputs);
5295 		}
5296 		if (if_op1_long_op2_long) {
5297 			ir_IF_FALSE_cold(if_op1_long_op2_long);
5298 			ir_END_list(slow_inputs);
5299 		}
5300 	} else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
5301 		if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5302 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5303 			ir_IF_TRUE(if_op1_long);
5304 		}
5305 		if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5306 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5307 			ir_IF_FALSE_cold(if_op1_long_op2_long);
5308 			if (op2_info & MAY_BE_DOUBLE) {
5309 				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5310 					if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5311 					ir_IF_FALSE_cold(if_op1_long_op2_double);
5312 					ir_END_list(slow_inputs);
5313 					ir_IF_TRUE(if_op1_long_op2_double);
5314 				}
5315 				if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5316 					return 0;
5317 				}
5318 				ir_refs_add(end_inputs, ir_END());
5319 			} else {
5320 				ir_END_list(slow_inputs);
5321 			}
5322 			ir_IF_TRUE(if_op1_long_op2_long);
5323 		}
5324 		if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5325 			return 0;
5326 		}
5327 		ir_refs_add(end_inputs, ir_END());
5328 
5329 		if (if_op1_long) {
5330 			ir_IF_FALSE_cold(if_op1_long);
5331 		}
5332 
5333 		if (op1_info & MAY_BE_DOUBLE) {
5334 			if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5335 				if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5336 				ir_IF_FALSE_cold(if_op1_double);
5337 				ir_END_list(slow_inputs);
5338 				ir_IF_TRUE(if_op1_double);
5339 			}
5340 			if (op2_info & MAY_BE_DOUBLE) {
5341 				if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5342 					if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5343 					ir_IF_TRUE(if_op1_double_op2_double);
5344 				}
5345 				if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5346 					return 0;
5347 				}
5348 				ir_refs_add(end_inputs, ir_END());
5349 				if (if_op1_double_op2_double) {
5350 					ir_IF_FALSE_cold(if_op1_double_op2_double);
5351 				}
5352 			}
5353 			if (!same_ops) {
5354 				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5355 					if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5356 					ir_IF_FALSE_cold(if_op1_double_op2_long);
5357 					ir_END_list(slow_inputs);
5358 					ir_IF_TRUE(if_op1_double_op2_long);
5359 				}
5360 				if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5361 					return 0;
5362 				}
5363 				ir_refs_add(end_inputs, ir_END());
5364 			} else if (if_op1_double_op2_double) {
5365 				ir_END_list(slow_inputs);
5366 			}
5367 		} else if (if_op1_long) {
5368 			ir_END_list(slow_inputs);
5369 		}
5370 	} else if ((op1_info & MAY_BE_DOUBLE) &&
5371 	           !(op1_info & MAY_BE_LONG) &&
5372 	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5373 	           (res_info & MAY_BE_DOUBLE)) {
5374 		if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5375 			if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5376 			ir_IF_FALSE_cold(if_op1_double);
5377 			ir_END_list(slow_inputs);
5378 			ir_IF_TRUE(if_op1_double);
5379 		}
5380 		if (op2_info & MAY_BE_DOUBLE) {
5381 			if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5382 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5383 				ir_IF_TRUE(if_op1_double_op2_double);
5384 			}
5385 			if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5386 				return 0;
5387 			}
5388 			ir_refs_add(end_inputs, ir_END());
5389 			if (if_op1_double_op2_double) {
5390 				ir_IF_FALSE_cold(if_op1_double_op2_double);
5391 			}
5392 		}
5393 		if (!same_ops && (op2_info & MAY_BE_LONG)) {
5394 			if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5395 				if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5396 				ir_IF_FALSE_cold(if_op1_double_op2_long);
5397 				ir_END_list(slow_inputs);
5398 				ir_IF_TRUE(if_op1_double_op2_long);
5399 			}
5400 			if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5401 				return 0;
5402 			}
5403 			ir_refs_add(end_inputs, ir_END());
5404 		} else if (if_op1_double_op2_double) {
5405 			ir_END_list(slow_inputs);
5406 		}
5407 	} else if ((op2_info & MAY_BE_DOUBLE) &&
5408 	           !(op2_info & MAY_BE_LONG) &&
5409 	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5410 	           (res_info & MAY_BE_DOUBLE)) {
5411 		if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5412 			if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5413 			ir_IF_FALSE_cold(if_op2_double);
5414 			ir_END_list(slow_inputs);
5415 			ir_IF_TRUE(if_op2_double);
5416 		}
5417 		if (op1_info & MAY_BE_DOUBLE) {
5418 			if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5419 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5420 				ir_IF_TRUE(if_op1_double_op2_double);
5421 			}
5422 			if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5423 				return 0;
5424 			}
5425 			ir_refs_add(end_inputs, ir_END());
5426 			if (if_op1_double_op2_double) {
5427 				ir_IF_FALSE_cold(if_op1_double_op2_double);
5428 			}
5429 		}
5430 		if (!same_ops && (op1_info & MAY_BE_LONG)) {
5431 			if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5432 				if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5433 				ir_IF_FALSE_cold(if_op1_long_op2_double);
5434 				ir_END_list(slow_inputs);
5435 				ir_IF_TRUE(if_op1_long_op2_double);
5436 			}
5437 			if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5438 				return 0;
5439 			}
5440 			ir_refs_add(end_inputs, ir_END());
5441 		} else if (if_op1_double_op2_double) {
5442 			ir_END_list(slow_inputs);
5443 		}
5444 	}
5445 
5446 	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5447 		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5448 		ir_ref func, arg1, arg2, arg3;
5449 
5450 		if (slow_inputs) {
5451 			ir_MERGE_list(slow_inputs);
5452 		}
5453 
5454 		if (Z_MODE(op1_addr) == IS_REG) {
5455 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5456 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5457 				return 0;
5458 			}
5459 			op1_addr = real_addr;
5460 		}
5461 		if (Z_MODE(op2_addr) == IS_REG) {
5462 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5463 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5464 				return 0;
5465 			}
5466 			op2_addr = real_addr;
5467 		}
5468 		if (Z_MODE(res_addr) == IS_REG) {
5469 			arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5470 		} else {
5471 			arg1 = jit_ZVAL_ADDR(jit, res_addr);
5472 		}
5473 		arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5474 		arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5475 		jit_SET_EX_OPLINE(jit, opline);
5476 		if (opcode == ZEND_ADD) {
5477 			func = ir_CONST_FC_FUNC(add_function);
5478 		} else if (opcode == ZEND_SUB) {
5479 			func = ir_CONST_FC_FUNC(sub_function);
5480 		} else if (opcode == ZEND_MUL) {
5481 			func = ir_CONST_FC_FUNC(mul_function);
5482 		} else if (opcode == ZEND_DIV) {
5483 			func = ir_CONST_FC_FUNC(div_function);
5484 		} else {
5485 			ZEND_UNREACHABLE();
5486 		}
5487 		ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5488 
5489 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5490 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5491 
5492 		if (may_throw) {
5493 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5494 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5495 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5496 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5497 				zend_jit_check_exception_undef_result(jit, opline);
5498 			} else {
5499 				zend_jit_check_exception(jit);
5500 			}
5501 		}
5502 		if (Z_MODE(res_addr) == IS_REG) {
5503 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5504 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5505 				return 0;
5506 			}
5507 		}
5508 		ir_refs_add(end_inputs, ir_END());
5509 	}
5510 
5511 	if (end_inputs->count) {
5512 		ir_MERGE_N(end_inputs->count, end_inputs->refs);
5513 	}
5514 
5515 	if (Z_MODE(res_addr) == IS_REG) {
5516 		ZEND_ASSERT(jit->delay_refs == res_inputs);
5517 		ZEND_ASSERT(end_inputs->count == res_inputs->count);
5518 		jit->delay_var = -1;
5519 		jit->delay_refs = NULL;
5520 		if (res_inputs->count == 1) {
5521 			zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5522 		} else {
5523 			ir_ref phi = ir_PHI_N((res_info & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE, res_inputs->count, res_inputs->refs);
5524 			zend_jit_def_reg(jit, res_addr, phi);
5525 		}
5526 	}
5527 
5528 	return 1;
5529 }
5530 
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)5531 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)
5532 {
5533 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5534 
5535 	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)) {
5536 		return 0;
5537 	}
5538 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5539 		return 0;
5540 	}
5541 	return 1;
5542 }
5543 
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)5544 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)
5545 {
5546 	ir_ref ref;
5547 	ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5548 	ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5549 
5550 	ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5551 	jit_set_Z_PTR(jit, res_addr, ref);
5552 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5553 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5554 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5555 	return 1;
5556 }
5557 
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)5558 static int zend_jit_long_math_helper(zend_jit_ctx   *jit,
5559                                      const zend_op  *opline,
5560                                      uint8_t         opcode,
5561                                      uint8_t         op1_type,
5562                                      znode_op        op1,
5563                                      zend_jit_addr   op1_addr,
5564                                      uint32_t        op1_info,
5565                                      zend_ssa_range *op1_range,
5566                                      uint8_t         op2_type,
5567                                      znode_op        op2,
5568                                      zend_jit_addr   op2_addr,
5569                                      uint32_t        op2_info,
5570                                      zend_ssa_range *op2_range,
5571                                      uint32_t        res_var,
5572                                      zend_jit_addr   res_addr,
5573                                      uint32_t        res_info,
5574                                      uint32_t        res_use_info,
5575                                      int             may_throw)
5576 {
5577 	ir_ref ref = IR_UNUSED;
5578 	ir_ref if_long1 = IR_UNUSED;
5579 	ir_ref if_long2 = IR_UNUSED;
5580 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5581 	ir_refs *res_inputs;
5582 
5583 	ir_refs_init(res_inputs, 2);
5584 
5585 	if (Z_MODE(op1_addr) == IS_REG
5586 	 && Z_LOAD(op1_addr)
5587 	 && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5588 		/* Force load */
5589 		zend_jit_use_reg(jit, op1_addr);
5590 	}
5591 	if (Z_MODE(op2_addr) == IS_REG
5592 	 && Z_LOAD(op2_addr)
5593 	 && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5594 		/* Force load */
5595 		zend_jit_use_reg(jit, op2_addr);
5596 	}
5597 
5598 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5599 		if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5600 		ir_IF_TRUE(if_long1);
5601 	}
5602 	if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5603 		if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5604 		ir_IF_TRUE(if_long2);
5605 	}
5606 
5607 	if (opcode == ZEND_SL) {
5608 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5609 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5610 
5611 			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5612 				if (EXPECTED(op2_lval > 0)) {
5613 					ref = ir_CONST_LONG(0);
5614 				} else {
5615 					zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5616 					zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5617 					jit_SET_EX_OPLINE(jit, opline);
5618 					ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5619 					if (Z_MODE(res_addr) == IS_REG) {
5620 						ref = ir_CONST_LONG(0); // dead code
5621 					}
5622 				}
5623 			} else {
5624 				ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5625 			}
5626 		} else {
5627 			ref = jit_Z_LVAL(jit, op2_addr);
5628 			if (!op2_range ||
5629 			     op2_range->min < 0 ||
5630 			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5631 
5632 				ir_ref if_wrong, cold_path, ref2, if_ok;
5633 				ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5634 
5635 				if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5636 				ir_IF_TRUE_cold(if_wrong);
5637 				if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5638 				ir_IF_FALSE(if_ok);
5639 				jit_SET_EX_OPLINE(jit, opline);
5640 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5641 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5642 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5643 				ir_IF_TRUE(if_ok);
5644 				ref2 = ir_CONST_LONG(0);
5645 				cold_path = ir_END();
5646 				ir_IF_FALSE(if_wrong);
5647 				ref = ir_SHL_L(op1_ref, ref);
5648 				ir_MERGE_WITH(cold_path);
5649 				ref = ir_PHI_2(IR_LONG, ref, ref2);
5650 			} else {
5651 				ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5652 			}
5653 		}
5654 	} else if (opcode == ZEND_SR) {
5655 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5656 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5657 
5658 			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5659 				if (EXPECTED(op2_lval > 0)) {
5660 					ref = ir_SAR_L(
5661 						jit_Z_LVAL(jit, op1_addr),
5662 						ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5663 				} else {
5664 					zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5665 					zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5666 					jit_SET_EX_OPLINE(jit, opline);
5667 					ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5668 					if (Z_MODE(res_addr) == IS_REG) {
5669 						ref = ir_CONST_LONG(0); // dead code
5670 					}
5671 				}
5672 			} else {
5673 				ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5674 			}
5675 		} else {
5676 			ref = jit_Z_LVAL(jit, op2_addr);
5677 			if (!op2_range ||
5678 			     op2_range->min < 0 ||
5679 			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5680 
5681 				ir_ref if_wrong, cold_path, ref2, if_ok;
5682 
5683 				if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5684 				ir_IF_TRUE_cold(if_wrong);
5685 				if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5686 				ir_IF_FALSE(if_ok);
5687 				jit_SET_EX_OPLINE(jit, opline);
5688 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5689 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5690 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5691 				ir_IF_TRUE(if_ok);
5692 				ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5693 				cold_path = ir_END();
5694 				ir_IF_FALSE(if_wrong);
5695 				ir_MERGE_WITH(cold_path);
5696 				ref = ir_PHI_2(IR_LONG, ref, ref2);
5697 			}
5698 			ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5699 		}
5700 	} else if (opcode == ZEND_MOD) {
5701 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5702 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5703 
5704 			if (op2_lval == 0) {
5705 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5706 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5707 				jit_SET_EX_OPLINE(jit, opline);
5708 				ir_GUARD(IR_FALSE,	jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5709 				if (Z_MODE(res_addr) == IS_REG) {
5710 					ref = ir_CONST_LONG(0); // dead code
5711 				}
5712 			} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5713 				ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5714 			} else {
5715 				ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5716 			}
5717 		} else {
5718 			ir_ref zero_path = 0;
5719 			ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5720 
5721 			ref = jit_Z_LVAL(jit, op2_addr);
5722 			if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5723 				ir_ref if_ok = ir_IF(ref);
5724 				ir_IF_FALSE(if_ok);
5725 				jit_SET_EX_OPLINE(jit, opline);
5726 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5727 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5728 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5729 				ir_IF_TRUE(if_ok);
5730 			}
5731 
5732 			/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5733 			if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5734 				ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5735 				ir_IF_TRUE_cold(if_minus_one);
5736 				zero_path = ir_END();
5737 				ir_IF_FALSE(if_minus_one);
5738 			}
5739 			ref = ir_MOD_L(op1_ref, ref);
5740 
5741 			if (zero_path) {
5742 				ir_MERGE_WITH(zero_path);
5743 				ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5744 			}
5745 		}
5746 	} else {
5747 		ir_op op;
5748 		ir_ref op1, op2;
5749 
5750 		if (opcode == ZEND_BW_OR) {
5751 			op = IR_OR;
5752 		} else if (opcode == ZEND_BW_AND) {
5753 			op = IR_AND;
5754 		} else if (opcode == ZEND_BW_XOR) {
5755 			op = IR_XOR;
5756 		} else {
5757 			ZEND_UNREACHABLE();
5758 		}
5759 		op1 = jit_Z_LVAL(jit, op1_addr);
5760 		op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5761 		ref = ir_BINARY_OP_L(op, op1, op2);
5762 	}
5763 
5764 	if (ref) {
5765 		if (Z_MODE(res_addr) == IS_REG
5766 		 && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5767 		  || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5768 			jit->delay_var = Z_SSA_VAR(res_addr);
5769 			jit->delay_refs = res_inputs;
5770 		}
5771 		jit_set_Z_LVAL(jit, res_addr, ref);
5772 		if (Z_MODE(res_addr) != IS_REG) {
5773 			if (!zend_jit_same_addr(op1_addr, res_addr)) {
5774 				if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5775 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5776 				}
5777 			}
5778 		}
5779 	}
5780 
5781 	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5782 		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5783 		ir_ref fast_path = ir_END();
5784 		ir_ref func, arg1, arg2, arg3;
5785 
5786 		if (if_long2 && if_long1) {
5787 			ir_ref ref;
5788 			ir_IF_FALSE_cold(if_long2);
5789 			ref = ir_END();
5790 			ir_IF_FALSE_cold(if_long1);
5791 			ir_MERGE_2(ref, ir_END());
5792 		} else if (if_long1) {
5793 			ir_IF_FALSE_cold(if_long1);
5794 		} else if (if_long2) {
5795 			ir_IF_FALSE_cold(if_long2);
5796 		}
5797 
5798 		if (op1_info & MAY_BE_UNDEF) {
5799 			ir_ref if_def, ref, ref2;
5800 
5801 			ref = jit_ZVAL_ADDR(jit, op1_addr);
5802 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5803 			ir_IF_FALSE_cold(if_def);
5804 
5805 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5806 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5807 
5808 			ref2 = jit_EG(uninitialized_zval);
5809 			ir_MERGE_WITH_EMPTY_TRUE(if_def);
5810 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
5811 			op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5812 		}
5813 
5814 		if (op2_info & MAY_BE_UNDEF) {
5815 			ir_ref if_def, ref, ref2;
5816 
5817 			ref = jit_ZVAL_ADDR(jit, op2_addr);
5818 			if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5819 			ir_IF_FALSE_cold(if_def);
5820 
5821 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
5822 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
5823 
5824 			ref2 = jit_EG(uninitialized_zval);
5825 			ir_MERGE_WITH_EMPTY_TRUE(if_def);
5826 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
5827 			op2_addr = ZEND_ADDR_REF_ZVAL(ref);
5828 		}
5829 
5830 		if (Z_MODE(op1_addr) == IS_REG) {
5831 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5832 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5833 				return 0;
5834 			}
5835 			op1_addr = real_addr;
5836 		}
5837 		if (Z_MODE(op2_addr) == IS_REG) {
5838 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5839 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5840 				return 0;
5841 			}
5842 			op2_addr = real_addr;
5843 		}
5844 		if (Z_MODE(res_addr) == IS_REG) {
5845 			arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5846 		} else {
5847 			arg1 = jit_ZVAL_ADDR(jit, res_addr);
5848 		}
5849 		arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5850 		arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5851 		jit_SET_EX_OPLINE(jit, opline);
5852 		if (opcode == ZEND_BW_OR) {
5853 			func = ir_CONST_FC_FUNC(bitwise_or_function);
5854 		} else if (opcode == ZEND_BW_AND) {
5855 			func = ir_CONST_FC_FUNC(bitwise_and_function);
5856 		} else if (opcode == ZEND_BW_XOR) {
5857 			func = ir_CONST_FC_FUNC(bitwise_xor_function);
5858 		} else if (opcode == ZEND_SL) {
5859 			func = ir_CONST_FC_FUNC(shift_left_function);
5860 		} else if (opcode == ZEND_SR) {
5861 			func = ir_CONST_FC_FUNC(shift_right_function);
5862 		} else if (opcode == ZEND_MOD) {
5863 			func = ir_CONST_FC_FUNC(mod_function);
5864 		} else {
5865 			ZEND_UNREACHABLE();
5866 		}
5867 		ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5868 
5869 		if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5870 			/* compound assignment may decrement "op2" refcount */
5871 			op2_info |= MAY_BE_RC1;
5872 		}
5873 
5874 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5875 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5876 
5877 		if (may_throw) {
5878 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5879 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5880 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5881 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5882 				zend_jit_check_exception_undef_result(jit, opline);
5883 			} else {
5884 				zend_jit_check_exception(jit);
5885 			}
5886 		}
5887 
5888 		if (Z_MODE(res_addr) == IS_REG) {
5889 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5890 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5891 				return 0;
5892 			}
5893 		}
5894 
5895 		ir_MERGE_2(fast_path, ir_END());
5896 
5897 		if (Z_MODE(res_addr) == IS_REG) {
5898 			ZEND_ASSERT(jit->delay_refs == res_inputs);
5899 			ZEND_ASSERT(res_inputs->count == 2);
5900 			jit->delay_var = -1;
5901 			jit->delay_refs = NULL;
5902 			if (res_inputs->count == 1) {
5903 				zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5904 			} else {
5905 				ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
5906 				zend_jit_def_reg(jit, res_addr, phi);
5907 			}
5908 		}
5909 	}
5910 
5911 	return 1;
5912 }
5913 
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)5914 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)
5915 {
5916 	ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
5917 
5918 	if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
5919 			opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
5920 			opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
5921 			opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
5922 		return 0;
5923 	}
5924 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5925 		return 0;
5926 	}
5927 	return 1;
5928 }
5929 
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)5930 static int zend_jit_concat_helper(zend_jit_ctx   *jit,
5931                                   const zend_op  *opline,
5932                                   uint8_t         op1_type,
5933                                   znode_op        op1,
5934                                   zend_jit_addr   op1_addr,
5935                                   uint32_t        op1_info,
5936                                   uint8_t         op2_type,
5937                                   znode_op        op2,
5938                                   zend_jit_addr   op2_addr,
5939                                   uint32_t        op2_info,
5940                                   zend_jit_addr   res_addr,
5941                                   int             may_throw)
5942 {
5943 	ir_ref if_op1_string = IR_UNUSED;
5944 	ir_ref if_op2_string = IR_UNUSED;
5945 	ir_ref fast_path = IR_UNUSED;
5946 
5947 	if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5948 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5949 			if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
5950 			ir_IF_TRUE(if_op1_string);
5951 		}
5952 		if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5953 			if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
5954 			ir_IF_TRUE(if_op2_string);
5955 		}
5956 		if (zend_jit_same_addr(op1_addr, res_addr)) {
5957 			ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5958 			ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
5959 
5960 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
5961 			/* concatenation with itself may reduce refcount */
5962 			op2_info |= MAY_BE_RC1;
5963 		} else {
5964 			ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5965 			ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5966 			ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5967 
5968 			if (op1_type == IS_CV || op1_type == IS_CONST) {
5969 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
5970 			} else {
5971 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
5972 			}
5973 		}
5974 		/* concatenation with empty string may increase refcount */
5975 		op2_info |= MAY_BE_RCN;
5976 		jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
5977 		if (if_op1_string || if_op2_string) {
5978 			fast_path = ir_END();
5979 		}
5980 	}
5981 	if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
5982 	    (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
5983 		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5984 			if (if_op1_string && if_op2_string) {
5985 				ir_IF_FALSE(if_op1_string);
5986 				ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
5987 			} else if (if_op1_string) {
5988 				ir_IF_FALSE_cold(if_op1_string);
5989 			} else if (if_op2_string) {
5990 				ir_IF_FALSE_cold(if_op2_string);
5991 			}
5992 		}
5993 		ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5994 		ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5995 		ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5996 
5997 		jit_SET_EX_OPLINE(jit, opline);
5998 		ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(concat_function), arg1, arg2, arg3);
5999 		/* concatenation with empty string may increase refcount */
6000 		op1_info |= MAY_BE_RCN;
6001 		op2_info |= MAY_BE_RCN;
6002 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6003 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6004 		if (may_throw) {
6005 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6006 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6007 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6008 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6009 				zend_jit_check_exception_undef_result(jit, opline);
6010 			} else {
6011 				zend_jit_check_exception(jit);
6012 			}
6013 		}
6014 		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6015 			ir_MERGE_WITH(fast_path);
6016 		}
6017 	}
6018 	return 1;
6019 }
6020 
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)6021 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)
6022 {
6023 	zend_jit_addr op1_addr, op2_addr;
6024 
6025 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6026 	ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
6027 
6028 	op1_addr = OP1_ADDR();
6029 	op2_addr = OP2_ADDR();
6030 
6031 	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);
6032 }
6033 
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)6034 static int zend_jit_assign_op(zend_jit_ctx   *jit,
6035                               const zend_op  *opline,
6036                               uint32_t        op1_info,
6037                               zend_jit_addr   op1_addr,
6038                               zend_ssa_range *op1_range,
6039                               uint32_t        op1_def_info,
6040                               zend_jit_addr   op1_def_addr,
6041                               uint32_t        op1_mem_info,
6042                               uint32_t        op2_info,
6043                               zend_jit_addr   op2_addr,
6044                               zend_ssa_range *op2_range,
6045                               int             may_overflow,
6046                               int             may_throw)
6047 {
6048 	int result = 1;
6049 	ir_ref slow_path = IR_UNUSED;
6050 
6051 	ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6052 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6053 
6054 	if (op1_info & MAY_BE_REF) {
6055 		ir_ref ref, ref2, arg2, op1_noref_path;
6056 		ir_ref if_op1_ref = IR_UNUSED;
6057 		ir_ref if_op1_typed = IR_UNUSED;
6058 		binary_op_type binary_op = get_binary_op(opline->extended_value);
6059 
6060 		ref = jit_ZVAL_ADDR(jit, op1_addr);
6061 		if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6062 		ir_IF_FALSE(if_op1_ref);
6063 		op1_noref_path = ir_END();
6064 		ir_IF_TRUE(if_op1_ref);
6065 		ref2 = jit_Z_PTR_ref(jit, ref);
6066 
6067 		if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6068 		ir_IF_TRUE_cold(if_op1_typed);
6069 
6070 		if (Z_MODE(op2_addr) == IS_REG) {
6071 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6072 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6073 				return 0;
6074 			}
6075 			arg2 = jit_ZVAL_ADDR(jit, real_addr);
6076 		} else {
6077 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6078 		}
6079 		jit_SET_EX_OPLINE(jit, opline);
6080 		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6081 		 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6082 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6083 				ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6084 		} else {
6085 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6086 				ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6087 		}
6088 		zend_jit_check_exception(jit);
6089 		slow_path = ir_END();
6090 
6091 		ir_IF_FALSE(if_op1_typed);
6092 		ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6093 
6094 		ir_MERGE_WITH(op1_noref_path);
6095 		ref = ir_PHI_2(IR_ADDR, ref2, ref);
6096 		ZEND_ASSERT(op1_addr == op1_def_addr);
6097 		op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6098 	}
6099 
6100 	switch (opline->extended_value) {
6101 		case ZEND_ADD:
6102 		case ZEND_SUB:
6103 		case ZEND_MUL:
6104 		case ZEND_DIV:
6105 			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);
6106 			break;
6107 		case ZEND_BW_OR:
6108 		case ZEND_BW_AND:
6109 		case ZEND_BW_XOR:
6110 		case ZEND_SL:
6111 		case ZEND_SR:
6112 		case ZEND_MOD:
6113 			result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6114 				opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6115 				opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6116 				opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6117 			break;
6118 		case ZEND_CONCAT:
6119 			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);
6120 			break;
6121 		default:
6122 			ZEND_UNREACHABLE();
6123 	}
6124 
6125 	if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
6126 		return 0;
6127 	}
6128 
6129 	if (op1_info & MAY_BE_REF) {
6130 		ir_MERGE_WITH(slow_path);
6131 	}
6132 
6133 	return result;
6134 }
6135 
jit_ZVAL_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6136 static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6137 {
6138 	ir_ref if_ref, ref2;
6139 
6140 	if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6141 	ir_IF_TRUE(if_ref);
6142 	ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6143 	ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6144 	return ir_PHI_2(IR_ADDR, ref2, ref);
6145 }
6146 
jit_ZVAL_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6147 static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6148 {
6149 	ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6150 	ref = jit_ZVAL_DEREF_ref(jit, ref);
6151 	return ZEND_ADDR_REF_ZVAL(ref);
6152 }
6153 
jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6154 static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6155 {
6156 	ir_ref if_ref, ref2;
6157 
6158 	if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6159 	ir_IF_TRUE(if_ref);
6160 	ref2 = jit_Z_PTR_ref(jit, ref);
6161 	ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6162 	return ir_PHI_2(IR_ADDR, ref2, ref);
6163 }
6164 
jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6165 static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6166 {
6167 	ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6168 	ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6169 	return ZEND_ADDR_REF_ZVAL(ref);
6170 }
6171 
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)6172 static int zend_jit_simple_assign(zend_jit_ctx   *jit,
6173                                   const zend_op  *opline,
6174                                   zend_jit_addr   var_addr,
6175                                   uint32_t        var_info,
6176                                   uint32_t        var_def_info,
6177                                   uint8_t         val_type,
6178                                   zend_jit_addr   val_addr,
6179                                   uint32_t        val_info,
6180                                   zend_jit_addr   res_addr,
6181                                   bool            check_exception)
6182 {
6183 	ir_ref end_inputs = IR_UNUSED;
6184 
6185 	if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6186 		zval *zv = Z_ZV(val_addr);
6187 
6188 		if (!res_addr) {
6189 			jit_ZVAL_COPY_CONST(jit,
6190 				var_addr,
6191 				var_info, var_def_info,
6192 				zv, 1);
6193 		} else {
6194 			jit_ZVAL_COPY_CONST(jit,
6195 				var_addr,
6196 				var_info, var_def_info,
6197 				zv, 1);
6198 			jit_ZVAL_COPY_CONST(jit,
6199 				res_addr,
6200 				-1, var_def_info,
6201 				zv, 1);
6202 		}
6203 	} else {
6204 		if (val_info & MAY_BE_UNDEF) {
6205 			ir_ref if_def, ret;
6206 
6207 			if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6208 			ir_IF_FALSE_cold(if_def);
6209 
6210 			jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6211 			if (res_addr) {
6212 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6213 			}
6214 			jit_SET_EX_OPLINE(jit, opline);
6215 
6216 			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6217 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6218 			ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6219 
6220 			if (check_exception) {
6221 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6222 			}
6223 
6224 			ir_END_list(end_inputs);
6225 			ir_IF_TRUE(if_def);
6226 		}
6227 		if (val_info & MAY_BE_REF) {
6228 			if (val_type == IS_CV) {
6229 				ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6230 				ref = jit_ZVAL_DEREF_ref(jit, ref);
6231 				val_addr = ZEND_ADDR_REF_ZVAL(ref);
6232 			} else {
6233 				ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6234 
6235 				ref = jit_ZVAL_ADDR(jit, val_addr);
6236 				type = jit_Z_TYPE_ref(jit, ref);
6237 				if_ref = ir_IF(ir_EQ(type, ir_CONST_U8(IS_REFERENCE)));
6238 
6239 				ir_IF_TRUE_cold(if_ref);
6240 				ref = jit_Z_PTR_ref(jit, ref);
6241 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
6242 				if (!res_addr) {
6243 					jit_ZVAL_COPY(jit,
6244 						var_addr,
6245 						var_info,
6246 						ZEND_ADDR_REF_ZVAL(ref2), val_info, 1);
6247 				} else {
6248 					jit_ZVAL_COPY_2(jit,
6249 						res_addr,
6250 						var_addr,
6251 						var_info,
6252 						ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6253 				}
6254 
6255 				refcount = jit_GC_DELREF(jit, ref);
6256 				if_not_zero = ir_IF(refcount);
6257 				ir_IF_FALSE(if_not_zero);
6258 				// TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6259 				// This is related to GH-10168 (keep this before GH-10168 is completely closed)
6260 				// jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6261 				jit_ZVAL_DTOR(jit, ref, val_info, opline);
6262 				ir_END_list(end_inputs);
6263 				ir_IF_TRUE(if_not_zero);
6264 				ir_END_list(end_inputs);
6265 
6266 				ir_IF_FALSE(if_ref);
6267 			}
6268 		}
6269 
6270 		if (!res_addr) {
6271 			jit_ZVAL_COPY(jit,
6272 				var_addr,
6273 				var_info,
6274 				val_addr, val_info, val_type == IS_CV);
6275 		} else {
6276 			jit_ZVAL_COPY_2(jit,
6277 				res_addr,
6278 				var_addr,
6279 				var_info,
6280 				val_addr, val_info, val_type == IS_CV ? 2 : 1);
6281 		}
6282 	}
6283 
6284 	if (end_inputs) {
6285 		ir_END_list(end_inputs);
6286 		ir_MERGE_list(end_inputs);
6287 	}
6288 
6289 	return 1;
6290 }
6291 
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)6292 static int zend_jit_assign_to_variable_call(zend_jit_ctx   *jit,
6293                                             const zend_op  *opline,
6294                                             zend_jit_addr   __var_use_addr,
6295                                             zend_jit_addr   var_addr,
6296                                             uint32_t        __var_info,
6297                                             uint32_t        __var_def_info,
6298                                             uint8_t         val_type,
6299                                             zend_jit_addr   val_addr,
6300                                             uint32_t        val_info,
6301                                             zend_jit_addr   __res_addr,
6302                                             bool       __check_exception)
6303 {
6304 	jit_stub_id func;
6305 	ir_ref undef_path = IR_UNUSED;
6306 
6307 	if (val_info & MAY_BE_UNDEF) {
6308 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6309 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6310 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6311 
6312 			if (!exit_addr) {
6313 				return 0;
6314 			}
6315 
6316 			jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6317 		} else {
6318 			ir_ref if_def;
6319 
6320 			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6321 			if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6322 			ir_IF_FALSE_cold(if_def);
6323 			jit_SET_EX_OPLINE(jit, opline);
6324 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6325 
6326 			ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6327 				jit_ZVAL_ADDR(jit, var_addr),
6328 				jit_EG(uninitialized_zval));
6329 
6330 			undef_path = ir_END();
6331 			ir_IF_TRUE(if_def);
6332 		}
6333 	}
6334 
6335 	if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6336 		func = jit_stub_assign_tmp;
6337 	} else if (val_type == IS_CONST) {
6338 		func = jit_stub_assign_const;
6339 	} else if (val_type == IS_TMP_VAR) {
6340 		func = jit_stub_assign_tmp;
6341 	} else if (val_type == IS_VAR) {
6342 		if (!(val_info & MAY_BE_REF)) {
6343 			func = jit_stub_assign_tmp;
6344 		} else {
6345 			func = jit_stub_assign_var;
6346 		}
6347 	} else if (val_type == IS_CV) {
6348 		if (!(val_info & MAY_BE_REF)) {
6349 			func = jit_stub_assign_cv_noref;
6350 		} else {
6351 			func = jit_stub_assign_cv;
6352 		}
6353 	} else {
6354 		ZEND_UNREACHABLE();
6355 	}
6356 
6357 	if (opline) {
6358 		jit_SET_EX_OPLINE(jit, opline);
6359 	}
6360 
6361 	ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6362 		jit_ZVAL_ADDR(jit, var_addr),
6363 		jit_ZVAL_ADDR(jit, val_addr));
6364 
6365 	if (undef_path) {
6366 		ir_MERGE_WITH(undef_path);
6367 	}
6368 
6369 	return 1;
6370 }
6371 
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)6372 static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
6373                                        const zend_op  *opline,
6374                                        zend_jit_addr   var_use_addr,
6375                                        zend_jit_addr   var_addr,
6376                                        uint32_t        var_info,
6377                                        uint32_t        var_def_info,
6378                                        uint8_t         val_type,
6379                                        zend_jit_addr   val_addr,
6380                                        uint32_t        val_info,
6381                                        zend_jit_addr   res_addr,
6382                                        zend_jit_addr   ref_addr,
6383                                        bool       check_exception)
6384 {
6385 	ir_ref if_refcounted = IR_UNUSED;
6386 	ir_ref simple_inputs = IR_UNUSED;
6387 	bool done = 0;
6388 	zend_jit_addr real_res_addr = 0;
6389 	ir_refs *end_inputs;
6390 	ir_refs *res_inputs;
6391 
6392 	ir_refs_init(end_inputs, 6);
6393 	ir_refs_init(res_inputs, 6);
6394 
6395 	if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6396 		/* Force load */
6397 		zend_jit_use_reg(jit, val_addr);
6398 	}
6399 
6400 	if (Z_MODE(var_addr) == IS_REG) {
6401 		jit->delay_var = Z_SSA_VAR(var_addr);
6402 		jit->delay_refs = res_inputs;
6403 		if (Z_MODE(res_addr) == IS_REG) {
6404 			real_res_addr = res_addr;
6405 			res_addr = 0;
6406 		}
6407 	} else if (Z_MODE(res_addr) == IS_REG) {
6408 		jit->delay_var = Z_SSA_VAR(res_addr);
6409 		jit->delay_refs = res_inputs;
6410 	}
6411 
6412 	if ((var_info & MAY_BE_REF) || ref_addr) {
6413 		ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6414 		uintptr_t func;
6415 
6416 		if (!ref_addr) {
6417 			ref = jit_ZVAL_ADDR(jit, var_use_addr);
6418 			if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6419 			ir_IF_TRUE(if_ref);
6420 			ref2 = jit_Z_PTR_ref(jit, ref);
6421 		} else {
6422 			ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6423 		}
6424 		if_typed = jit_if_TYPED_REF(jit, ref2);
6425 		ir_IF_TRUE_cold(if_typed);
6426 		jit_SET_EX_OPLINE(jit, opline);
6427 		if (Z_MODE(val_addr) == IS_REG) {
6428 			zend_jit_addr real_addr;
6429 
6430 			if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6431 				real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6432 			} else {
6433 				ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6434 				real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6435 			}
6436 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6437 				return 0;
6438 			}
6439 			arg2 = jit_ZVAL_ADDR(jit, real_addr);
6440 		} else {
6441 			arg2 = jit_ZVAL_ADDR(jit, val_addr);
6442 		}
6443 		if (!res_addr) {
6444 			if (val_type == IS_CONST) {
6445 				func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6446 			} else if (val_type == IS_TMP_VAR) {
6447 				func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6448 			} else if (val_type == IS_VAR) {
6449 				func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6450 			} else if (val_type == IS_CV) {
6451 				func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6452 			} else {
6453 				ZEND_UNREACHABLE();
6454 			}
6455 			ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6456 		} else {
6457 			if (val_type == IS_CONST) {
6458 				func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6459 			} else if (val_type == IS_TMP_VAR) {
6460 				func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6461 			} else if (val_type == IS_VAR) {
6462 				func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6463 			} else if (val_type == IS_CV) {
6464 				func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6465 			} else {
6466 				ZEND_UNREACHABLE();
6467 			}
6468 			ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6469 		}
6470 		if (check_exception) {
6471 			zend_jit_check_exception(jit);
6472 		}
6473 		ir_refs_add(end_inputs, ir_END());
6474 
6475 		if (!ref_addr) {
6476 			ir_IF_FALSE(if_ref);
6477 			non_ref_path = ir_END();
6478 			ir_IF_FALSE(if_typed);
6479 			ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6480 			ir_MERGE_WITH(non_ref_path);
6481 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
6482 			var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6483 		} else {
6484 			ir_IF_FALSE(if_typed);
6485 		}
6486 	}
6487 
6488 	if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6489 		ir_ref ref, counter, if_not_zero;
6490 
6491 		if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6492 			if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6493 			ir_IF_FALSE(if_refcounted);
6494 			ir_END_list(simple_inputs);
6495 			ir_IF_TRUE_cold(if_refcounted);
6496 		} else if (RC_MAY_BE_1(var_info)) {
6497 			done = 1;
6498 		}
6499 		ref = jit_Z_PTR(jit, var_use_addr);
6500 		if (RC_MAY_BE_1(var_info)) {
6501 			if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0)) {
6502 				return 0;
6503 			}
6504 			counter = jit_GC_DELREF(jit, ref);
6505 
6506 			if_not_zero = ir_IF(counter);
6507 			ir_IF_FALSE(if_not_zero);
6508 			jit_ZVAL_DTOR(jit, ref, var_info, opline);
6509 			if (check_exception) {
6510 				zend_jit_check_exception(jit);
6511 			}
6512 			ir_refs_add(end_inputs, ir_END());
6513 			ir_IF_TRUE(if_not_zero);
6514 			if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6515 				ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6516 				ir_IF_FALSE(if_may_leak);
6517 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6518 
6519 				if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6520 					ZEND_ASSERT(jit->delay_refs == res_inputs);
6521 					ZEND_ASSERT(res_inputs->count > 0);
6522 					ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6523 				}
6524 				if (check_exception && (val_info & MAY_BE_UNDEF)) {
6525 					zend_jit_check_exception(jit);
6526 				}
6527 				ir_refs_add(end_inputs, ir_END());
6528 				ir_IF_TRUE(if_may_leak);
6529 			}
6530 			if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6531 				ZEND_ASSERT(jit->delay_refs == res_inputs);
6532 				ZEND_ASSERT(res_inputs->count > 0);
6533 				ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6534 			}
6535 			if (check_exception && (val_info & MAY_BE_UNDEF)) {
6536 				zend_jit_check_exception(jit);
6537 			}
6538 			ir_refs_add(end_inputs, ir_END());
6539 		} else /* if (RC_MAY_BE_N(var_info)) */ {
6540 			jit_GC_DELREF(jit, ref);
6541 			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6542 				ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6543 				ir_IF_FALSE(if_may_leak);
6544 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6545 				ir_END_list(simple_inputs);
6546 				ir_IF_TRUE(if_may_leak);
6547 			}
6548 			ir_END_list(simple_inputs);
6549 		}
6550 	}
6551 
6552 	if (simple_inputs) {
6553 		ir_MERGE_list(simple_inputs);
6554 	}
6555 
6556 	if (!done) {
6557 		if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6558 			return 0;
6559 		}
6560 		if (end_inputs->count) {
6561 			ir_refs_add(end_inputs, ir_END());
6562 		}
6563 	}
6564 
6565 	if (end_inputs->count) {
6566 		ir_MERGE_N(end_inputs->count, end_inputs->refs);
6567 	}
6568 
6569 	if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6570 		ir_ref phi;
6571 
6572 		ZEND_ASSERT(jit->delay_refs == res_inputs);
6573 		ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6574 		jit->delay_var = -1;
6575 		jit->delay_refs = NULL;
6576 		if (res_inputs->count == 1) {
6577 			phi = res_inputs->refs[0];
6578 		} else {
6579 			phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6580 				res_inputs->count, res_inputs->refs);
6581 		}
6582 		if (Z_MODE(var_addr) == IS_REG) {
6583 			if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6584 				phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6585 			}
6586 			zend_jit_def_reg(jit, var_addr, phi);
6587 			if (real_res_addr) {
6588 				if (var_def_info & MAY_BE_LONG) {
6589 					jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6590 				} else {
6591 					jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6592 				}
6593 			}
6594 		} else {
6595 			zend_jit_def_reg(jit, res_addr, phi);
6596 		}
6597 	}
6598 
6599 	return 1;
6600 }
6601 
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)6602 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)
6603 {
6604 	if (op1_addr != op1_def_addr) {
6605 		if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6606 			return 0;
6607 		}
6608 		if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6609 			op1_addr = op1_def_addr;
6610 		}
6611 	}
6612 
6613 	if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 1)) {
6614 		return 0;
6615 	}
6616 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6617 		return 0;
6618 	}
6619 	return 1;
6620 }
6621 
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)6622 static int zend_jit_assign(zend_jit_ctx  *jit,
6623                            const zend_op *opline,
6624                            uint32_t       op1_info,
6625                            zend_jit_addr  op1_use_addr,
6626                            uint32_t       op1_def_info,
6627                            zend_jit_addr  op1_addr,
6628                            uint32_t       op2_info,
6629                            zend_jit_addr  op2_addr,
6630                            zend_jit_addr  op2_def_addr,
6631                            uint32_t       res_info,
6632                            zend_jit_addr  res_addr,
6633                            zend_jit_addr  ref_addr,
6634                            int            may_throw)
6635 {
6636 	ZEND_ASSERT(opline->op1_type == IS_CV);
6637 
6638 	if (op2_addr != op2_def_addr) {
6639 		if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6640 			return 0;
6641 		}
6642 		if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6643 			op2_addr = op2_def_addr;
6644 		}
6645 	}
6646 
6647 	if (Z_MODE(op1_addr) != IS_REG
6648 	 && Z_MODE(op1_use_addr) == IS_REG
6649 	 && !Z_LOAD(op1_use_addr)
6650 	 && !Z_STORE(op1_use_addr)) {
6651 		/* Force type update */
6652 		op1_info |= MAY_BE_UNDEF;
6653 	}
6654 	if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6655 			opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6656 		return 0;
6657 	}
6658 	if (Z_MODE(op1_addr) == IS_REG) {
6659 		if (Z_STORE(op1_addr)) {
6660 			if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6661 				return 0;
6662 			}
6663 		} else if ((op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
6664 			&& Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6665 			&& Z_REG(op1_use_addr) == ZREG_FP
6666 			&& EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6667 			/* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6668 			if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6669 				jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6670 				if (JIT_G(current_frame)) {
6671 					SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6672 				}
6673 			} else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6674 				jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6675 				if (JIT_G(current_frame)) {
6676 					SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6677 				}
6678 			} else {
6679 				ZEND_UNREACHABLE();
6680 			}
6681 		}
6682 	}
6683 	if (opline->result_type != IS_UNUSED) {
6684 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6685 			return 0;
6686 		}
6687 	}
6688 
6689 	return 1;
6690 }
6691 
zend_jit_cmp_op(const zend_op * opline)6692 static ir_op zend_jit_cmp_op(const zend_op *opline)
6693 {
6694 	ir_op op;
6695 
6696 	switch (opline->opcode) {
6697 		case ZEND_IS_EQUAL:
6698 		case ZEND_IS_IDENTICAL:
6699 		case ZEND_CASE:
6700 		case ZEND_CASE_STRICT:
6701 			op = IR_EQ;
6702 			break;
6703 		case ZEND_IS_NOT_EQUAL:
6704 		case ZEND_IS_NOT_IDENTICAL:
6705 			op = IR_NE;
6706 			break;
6707 		case ZEND_IS_SMALLER:
6708 			op = IR_LT;
6709 			break;
6710 		case ZEND_IS_SMALLER_OR_EQUAL:
6711 			op = IR_LE;
6712 			break;
6713 		default:
6714 			ZEND_UNREACHABLE();
6715 	}
6716 	return op;
6717 }
6718 
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)6719 static ir_ref zend_jit_cmp_long_long(zend_jit_ctx   *jit,
6720                                      const zend_op  *opline,
6721                                      zend_ssa_range *op1_range,
6722                                      zend_jit_addr   op1_addr,
6723                                      zend_ssa_range *op2_range,
6724                                      zend_jit_addr   op2_addr,
6725                                      zend_jit_addr   res_addr,
6726                                      uint8_t         smart_branch_opcode,
6727                                      uint32_t        target_label,
6728                                      uint32_t        target_label2,
6729                                      const void     *exit_addr,
6730                                      bool       skip_comparison)
6731 {
6732 	ir_ref ref;
6733 	bool result;
6734 
6735 	if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6736 		if (!smart_branch_opcode ||
6737 		    smart_branch_opcode == ZEND_JMPZ_EX ||
6738 		    smart_branch_opcode == ZEND_JMPNZ_EX) {
6739 			jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6740 		}
6741 		if (smart_branch_opcode && !exit_addr) {
6742 			if (smart_branch_opcode == ZEND_JMPZ ||
6743 			    smart_branch_opcode == ZEND_JMPZ_EX) {
6744 				return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6745 			} else if (smart_branch_opcode == ZEND_JMPNZ ||
6746 			           smart_branch_opcode == ZEND_JMPNZ_EX) {
6747 				return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6748 			} else {
6749 				ZEND_UNREACHABLE();
6750 			}
6751 		}
6752 		if (opline->opcode != ZEND_IS_IDENTICAL
6753 		 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6754 		 && opline->opcode != ZEND_CASE_STRICT) {
6755 			return ir_END();
6756 		} else {
6757 			return IR_NULL; /* success */
6758 		}
6759 	}
6760 
6761 	ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6762 
6763 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6764 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6765 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6766 	}
6767 	if (exit_addr) {
6768 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6769 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6770 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6771 			} else {
6772 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6773 			}
6774 		} else {
6775 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6776 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6777 			} else {
6778 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6779 			}
6780 		}
6781 	} else if (smart_branch_opcode) {
6782 		return jit_IF_ex(jit, ref,
6783 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6784 	}
6785 
6786 	if (opline->opcode != ZEND_IS_IDENTICAL
6787 	 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6788 	 && opline->opcode != ZEND_CASE_STRICT) {
6789 		return ir_END();
6790 	} else {
6791 		return IR_NULL; /* success */
6792 	}
6793 }
6794 
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)6795 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)
6796 {
6797 	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));
6798 
6799 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6800 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6801 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6802 	}
6803 	if (exit_addr) {
6804 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6805 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6806 		} else {
6807 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6808 		}
6809 	} else if (smart_branch_opcode) {
6810 		return jit_IF_ex(jit, ref,
6811 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6812 	}
6813 	return ir_END();
6814 }
6815 
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)6816 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)
6817 {
6818 	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)));
6819 
6820 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6821 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6822 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6823 	}
6824 	if (exit_addr) {
6825 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6826 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6827 		} else {
6828 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6829 		}
6830 	} else if (smart_branch_opcode) {
6831 		return jit_IF_ex(jit, ref,
6832 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6833 	}
6834 	return ir_END();
6835 }
6836 
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)6837 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)
6838 {
6839 	ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
6840 
6841 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6842 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6843 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6844 	}
6845 	if (exit_addr) {
6846 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6847 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6848 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6849 			} else {
6850 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6851 			}
6852 		} else {
6853 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6854 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6855 			} else {
6856 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6857 			}
6858 		}
6859 	} else if (smart_branch_opcode) {
6860 		return jit_IF_ex(jit, ref,
6861 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6862 	}
6863 	if (opline->opcode != ZEND_IS_IDENTICAL
6864 	 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6865 	 && opline->opcode != ZEND_CASE_STRICT) {
6866 		return ir_END();
6867 	} else {
6868 		return IR_NULL; /* success */
6869 	}
6870 }
6871 
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)6872 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)
6873 {
6874 	ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
6875 
6876 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6877 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6878 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6879 	}
6880 	if (exit_addr) {
6881 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6882 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6883 		} else {
6884 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6885 		}
6886 	} else if (smart_branch_opcode) {
6887 		return jit_IF_ex(jit, ref,
6888 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6889 	}
6890 
6891 	return ir_END();
6892 }
6893 
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)6894 static int zend_jit_cmp(zend_jit_ctx   *jit,
6895                         const zend_op  *opline,
6896                         uint32_t        op1_info,
6897                         zend_ssa_range *op1_range,
6898                         zend_jit_addr   op1_addr,
6899                         uint32_t        op2_info,
6900                         zend_ssa_range *op2_range,
6901                         zend_jit_addr   op2_addr,
6902                         zend_jit_addr   res_addr,
6903                         int             may_throw,
6904                         uint8_t         smart_branch_opcode,
6905                         uint32_t        target_label,
6906                         uint32_t        target_label2,
6907                         const void     *exit_addr,
6908                         bool       skip_comparison)
6909 {
6910 	ir_ref ref = IR_UNUSED;
6911 	ir_ref if_op1_long = IR_UNUSED;
6912 	ir_ref if_op1_double = IR_UNUSED;
6913 	ir_ref if_op2_double = IR_UNUSED;
6914 	ir_ref if_op1_long_op2_long = IR_UNUSED;
6915 	ir_ref if_op1_long_op2_double = IR_UNUSED;
6916 	ir_ref if_op1_double_op2_double = IR_UNUSED;
6917 	ir_ref if_op1_double_op2_long = IR_UNUSED;
6918 	ir_ref slow_inputs = IR_UNUSED;
6919 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
6920 	bool has_slow =
6921 		(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6922 		(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6923 		((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
6924 		 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
6925 	ir_refs *end_inputs;
6926 
6927 	ir_refs_init(end_inputs, 8);
6928 
6929 	if (Z_MODE(op1_addr) == IS_REG) {
6930 		if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
6931 			/* Force load */
6932 			zend_jit_use_reg(jit, op1_addr);
6933 		}
6934 	} else if (Z_MODE(op2_addr) == IS_REG) {
6935 		if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
6936 			/* Force load */
6937 			zend_jit_use_reg(jit, op2_addr);
6938 		}
6939 	}
6940 
6941 	if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
6942 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
6943 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
6944 			ir_IF_TRUE(if_op1_long);
6945 		}
6946 		if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
6947 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
6948 			ir_IF_FALSE_cold(if_op1_long_op2_long);
6949 			if (op2_info & MAY_BE_DOUBLE) {
6950 				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6951 					if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6952 					ir_IF_FALSE_cold(if_op1_long_op2_double);
6953 					ir_END_list(slow_inputs);
6954 					ir_IF_TRUE(if_op1_long_op2_double);
6955 				}
6956 				ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6957 				if (!ref) {
6958 					return 0;
6959 				}
6960 				ir_refs_add(end_inputs, ref);
6961 			} else {
6962 				ir_END_list(slow_inputs);
6963 			}
6964 			ir_IF_TRUE(if_op1_long_op2_long);
6965 		}
6966 		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);
6967 		if (!ref) {
6968 			return 0;
6969 		}
6970 		ir_refs_add(end_inputs, ref);
6971 
6972 		if (if_op1_long) {
6973 			ir_IF_FALSE_cold(if_op1_long);
6974 		}
6975 		if (op1_info & MAY_BE_DOUBLE) {
6976 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6977 				if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
6978 				ir_IF_FALSE_cold(if_op1_double);
6979 				ir_END_list(slow_inputs);
6980 				ir_IF_TRUE(if_op1_double);
6981 			}
6982 			if (op2_info & MAY_BE_DOUBLE) {
6983 				if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
6984 					if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6985 					ir_IF_TRUE(if_op1_double_op2_double);
6986 				}
6987 				ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6988 				if (!ref) {
6989 					return 0;
6990 				}
6991 				ir_refs_add(end_inputs, ref);
6992 				if (if_op1_double_op2_double) {
6993 					ir_IF_FALSE_cold(if_op1_double_op2_double);
6994 				}
6995 			}
6996 			if (!same_ops) {
6997 				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6998 					if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
6999 					ir_IF_FALSE_cold(if_op1_double_op2_long);
7000 					ir_END_list(slow_inputs);
7001 					ir_IF_TRUE(if_op1_double_op2_long);
7002 				}
7003 				ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7004 				if (!ref) {
7005 					return 0;
7006 				}
7007 				ir_refs_add(end_inputs, ref);
7008 			} else if (if_op1_double_op2_double) {
7009 				ir_END_list(slow_inputs);
7010 			}
7011 		} else if (if_op1_long) {
7012 			ir_END_list(slow_inputs);
7013 		}
7014 	} else if ((op1_info & MAY_BE_DOUBLE) &&
7015 	           !(op1_info & MAY_BE_LONG) &&
7016 	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7017 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7018 			if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7019 			ir_IF_FALSE_cold(if_op1_double);
7020 			ir_END_list(slow_inputs);
7021 			ir_IF_TRUE(if_op1_double);
7022 		}
7023 		if (op2_info & MAY_BE_DOUBLE) {
7024 			if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7025 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7026 				ir_IF_TRUE(if_op1_double_op2_double);
7027 			}
7028 			ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7029 			if (!ref) {
7030 				return 0;
7031 			}
7032 			ir_refs_add(end_inputs, ref);
7033 			if (if_op1_double_op2_double) {
7034 				ir_IF_FALSE_cold(if_op1_double_op2_double);
7035 			}
7036 		}
7037 		if (!same_ops && (op2_info & MAY_BE_LONG)) {
7038 			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7039 				if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7040 				ir_IF_FALSE_cold(if_op1_double_op2_long);
7041 				ir_END_list(slow_inputs);
7042 				ir_IF_TRUE(if_op1_double_op2_long);
7043 			}
7044 			ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7045 			if (!ref) {
7046 				return 0;
7047 			}
7048 			ir_refs_add(end_inputs, ref);
7049 		} else if (if_op1_double_op2_double) {
7050 			ir_END_list(slow_inputs);
7051 		}
7052 	} else if ((op2_info & MAY_BE_DOUBLE) &&
7053 	           !(op2_info & MAY_BE_LONG) &&
7054 	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7055 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7056 			if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7057 			ir_IF_FALSE_cold(if_op2_double);
7058 			ir_END_list(slow_inputs);
7059 			ir_IF_TRUE(if_op2_double);
7060 		}
7061 		if (op1_info & MAY_BE_DOUBLE) {
7062 			if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7063 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7064 				ir_IF_TRUE(if_op1_double_op2_double);
7065 			}
7066 			ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7067 			if (!ref) {
7068 				return 0;
7069 			}
7070 			ir_refs_add(end_inputs, ref);
7071 			if (if_op1_double_op2_double) {
7072 				ir_IF_FALSE_cold(if_op1_double_op2_double);
7073 			}
7074 		}
7075 		if (!same_ops && (op1_info & MAY_BE_LONG)) {
7076 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7077 				if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7078 				ir_IF_FALSE_cold(if_op1_long_op2_double);
7079 				ir_END_list(slow_inputs);
7080 				ir_IF_TRUE(if_op1_long_op2_double);
7081 			}
7082 			ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7083 			if (!ref) {
7084 				return 0;
7085 			}
7086 			ir_refs_add(end_inputs, ref);
7087 		} else if (if_op1_double_op2_double) {
7088 			ir_END_list(slow_inputs);
7089 		}
7090 	}
7091 
7092 	if (has_slow ||
7093 	    (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7094 	    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7095 	    ir_ref op1, op2, ref;
7096 
7097 		if (slow_inputs) {
7098 			ir_MERGE_list(slow_inputs);
7099 		}
7100 		jit_SET_EX_OPLINE(jit, opline);
7101 
7102 		if (Z_MODE(op1_addr) == IS_REG) {
7103 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7104 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7105 				return 0;
7106 			}
7107 			op1_addr = real_addr;
7108 		}
7109 		if (Z_MODE(op2_addr) == IS_REG) {
7110 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7111 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7112 				return 0;
7113 			}
7114 			op2_addr = real_addr;
7115 		}
7116 
7117 		op1 = jit_ZVAL_ADDR(jit, op1_addr);
7118 		if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7119 			op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, 0);
7120 		}
7121 		op2 = jit_ZVAL_ADDR(jit, op2_addr);
7122 		if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7123 			op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, 0);
7124 		}
7125 		ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7126 		if (opline->opcode != ZEND_CASE) {
7127 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7128 		}
7129 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7130 		if (may_throw) {
7131 			zend_jit_check_exception_undef_result(jit, opline);
7132 		}
7133 
7134 		ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7135 		if (!ref) {
7136 			return 0;
7137 		}
7138 		ir_refs_add(end_inputs, ref);
7139 	}
7140 
7141 	if (end_inputs->count) {
7142 		uint32_t n = end_inputs->count;
7143 
7144 		if (smart_branch_opcode && !exit_addr) {
7145 			zend_basic_block *bb;
7146 			ir_ref ref;
7147 			uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7148 				target_label2 : target_label;
7149 			uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7150 				target_label : target_label2;
7151 
7152 			ZEND_ASSERT(jit->b >= 0);
7153 			bb = &jit->ssa->cfg.blocks[jit->b];
7154 			ZEND_ASSERT(bb->successors_count == 2);
7155 
7156 			if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7157 				ir_ref merge_inputs = IR_UNUSED;
7158 
7159 				while (n) {
7160 					n--;
7161 					ir_IF_TRUE(end_inputs->refs[n]);
7162 					ir_END_list(merge_inputs);
7163 					ir_IF_FALSE(end_inputs->refs[n]);
7164 					ir_END_list(merge_inputs);
7165 				}
7166 				ir_MERGE_list(merge_inputs);
7167 				_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7168 			} else if (n == 1) {
7169 				ref = end_inputs->refs[0];
7170 				_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7171 				_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7172 			} else {
7173 				ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7174 
7175 				while (n) {
7176 					n--;
7177 					ir_IF_TRUE(end_inputs->refs[n]);
7178 					ir_END_list(true_inputs);
7179 					ir_IF_FALSE(end_inputs->refs[n]);
7180 					ir_END_list(false_inputs);
7181 				}
7182 				ir_MERGE_list(true_inputs);
7183 				_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7184 				ir_MERGE_list(false_inputs);
7185 				_zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7186 			}
7187 			jit->b = -1;
7188 		} else {
7189 			ir_MERGE_N(n, end_inputs->refs);
7190 		}
7191 	} else if (smart_branch_opcode && !exit_addr) {
7192 		/* dead code */
7193 		_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7194 		jit->b = -1;
7195 	}
7196 
7197 	return 1;
7198 }
7199 
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)7200 static int zend_jit_identical(zend_jit_ctx   *jit,
7201                               const zend_op  *opline,
7202                               uint32_t        op1_info,
7203                               zend_ssa_range *op1_range,
7204                               zend_jit_addr   op1_addr,
7205                               uint32_t        op2_info,
7206                               zend_ssa_range *op2_range,
7207                               zend_jit_addr   op2_addr,
7208                               zend_jit_addr   res_addr,
7209                               int             may_throw,
7210                               uint8_t         smart_branch_opcode,
7211                               uint32_t        target_label,
7212                               uint32_t        target_label2,
7213                               const void     *exit_addr,
7214                               bool       skip_comparison)
7215 {
7216 	bool always_false = 0, always_true = 0;
7217 	ir_ref ref = IR_UNUSED;
7218 
7219 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7220 		ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7221 		op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, 0);
7222 		op1_info |= MAY_BE_NULL;
7223 		op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7224 	}
7225 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7226 		ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7227 		op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, 0);
7228 		op2_info |= MAY_BE_NULL;
7229 		op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7230 	}
7231 
7232 	if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7233 		always_false = 1;
7234 	} else if (has_concrete_type(op1_info)
7235 	 && has_concrete_type(op2_info)
7236 	 && concrete_type(op1_info) == concrete_type(op2_info)
7237 	 && concrete_type(op1_info) <= IS_TRUE) {
7238 		always_true = 1;
7239 	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7240 		if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7241 			always_true = 1;
7242 		} else {
7243 			always_false = 1;
7244 		}
7245 	}
7246 
7247 	if (always_true) {
7248 		if (opline->opcode != ZEND_CASE_STRICT) {
7249 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7250 		}
7251 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7252 		if (!smart_branch_opcode
7253 		 || smart_branch_opcode == ZEND_JMPZ_EX
7254 		 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7255 			jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7256 		}
7257 		if (may_throw) {
7258 			zend_jit_check_exception(jit);
7259 		}
7260 		if (exit_addr) {
7261 			if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7262 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7263 			}
7264 		} else if (smart_branch_opcode) {
7265 			uint32_t label;
7266 
7267 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7268 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7269 					target_label : target_label2;
7270 			} else {
7271 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7272 					target_label2 : target_label;
7273 			}
7274 			_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7275 			jit->b = -1;
7276 		}
7277 		return 1;
7278 	} else if (always_false) {
7279 		if (opline->opcode != ZEND_CASE_STRICT) {
7280 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7281 		}
7282 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7283 		if (!smart_branch_opcode
7284 		 || smart_branch_opcode == ZEND_JMPZ_EX
7285 		 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7286 			jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7287 		}
7288 		if (may_throw) {
7289 			zend_jit_check_exception(jit);
7290 		}
7291 		if (exit_addr) {
7292 			if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7293 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7294 			}
7295 		} else if (smart_branch_opcode) {
7296 			uint32_t label;
7297 
7298 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7299 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7300 					target_label2 : target_label;
7301 			} else {
7302 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7303 					target_label : target_label2;
7304 			}
7305 			_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7306 			jit->b = -1;
7307 		}
7308 		return 1;
7309 	}
7310 
7311 	if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7312 		ref = jit_ZVAL_ADDR(jit, op1_addr);
7313 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7314 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7315 	}
7316 	if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7317 		ref = jit_ZVAL_ADDR(jit, op2_addr);
7318 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7319 		op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7320 	}
7321 
7322 	if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7323 	    (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7324 		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);
7325 		if (!ref) {
7326 			return 0;
7327 		}
7328 	} else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7329 	           (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7330 		ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7331 		if (!ref) {
7332 			return 0;
7333 		}
7334 	} else {
7335 		if (opline->op1_type != IS_CONST) {
7336 			if (Z_MODE(op1_addr) == IS_REG) {
7337 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7338 				if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7339 					return 0;
7340 				}
7341 				op1_addr = real_addr;
7342 			}
7343 		}
7344 		if (opline->op2_type != IS_CONST) {
7345 			if (Z_MODE(op2_addr) == IS_REG) {
7346 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7347 				if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7348 					return 0;
7349 				}
7350 			}
7351 		}
7352 
7353 		if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7354 			zval *val = Z_ZV(op1_addr);
7355 
7356 			ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7357 		} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7358 			zval *val = Z_ZV(op2_addr);
7359 
7360 			ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7361 		} else {
7362 			if (Z_MODE(op1_addr) == IS_REG) {
7363 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7364 				if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7365 					return 0;
7366 				}
7367 				op1_addr = real_addr;
7368 			}
7369 			if (Z_MODE(op2_addr) == IS_REG) {
7370 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7371 				if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7372 					return 0;
7373 				}
7374 				op2_addr = real_addr;
7375 			}
7376 			if (may_throw) {
7377 				jit_SET_EX_OPLINE(jit, opline);
7378 			}
7379 
7380 			ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_is_identical),
7381 				jit_ZVAL_ADDR(jit, op1_addr),
7382 				jit_ZVAL_ADDR(jit, op2_addr));
7383 		}
7384 
7385 		if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7386 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7387 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7388 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7389 			} else {
7390 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7391 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7392 			}
7393 		}
7394 		if (opline->opcode != ZEND_CASE_STRICT) {
7395 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7396 		}
7397 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7398 		if (may_throw) {
7399 			zend_jit_check_exception_undef_result(jit, opline);
7400 		}
7401 		if (exit_addr) {
7402 			if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7403 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7404 			} else {
7405 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7406 			}
7407 		} else if (smart_branch_opcode) {
7408 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7409 				/* swap labels */
7410 				uint32_t tmp = target_label;
7411 				target_label = target_label2;
7412 				target_label2 = tmp;
7413 			}
7414 			ref = jit_IF_ex(jit, ref,
7415 				(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7416 		}
7417 	}
7418 
7419 	if (smart_branch_opcode && !exit_addr) {
7420 		zend_basic_block *bb;
7421 
7422 		ZEND_ASSERT(jit->b >= 0);
7423 		bb = &jit->ssa->cfg.blocks[jit->b];
7424 		ZEND_ASSERT(bb->successors_count == 2);
7425 
7426 		if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7427 			ir_IF_TRUE(ref);
7428 			ir_MERGE_WITH_EMPTY_FALSE(ref);
7429 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7430 		} else {
7431 			ZEND_ASSERT(bb->successors_count == 2);
7432 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7433 			_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7434 		}
7435 		jit->b = -1;
7436 	}
7437 
7438 	return 1;
7439 }
7440 
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)7441 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)
7442 {
7443 	uint32_t true_label = -1;
7444 	uint32_t false_label = -1;
7445 	bool set_bool = 0;
7446 	bool set_bool_not = 0;
7447 	bool always_true = 0, always_false = 0;
7448 	ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7449 	ir_type type = IR_UNUSED;
7450 
7451 	if (branch_opcode == ZEND_BOOL) {
7452 		set_bool = 1;
7453 	} else if (branch_opcode == ZEND_BOOL_NOT) {
7454 		set_bool = 1;
7455 		set_bool_not = 1;
7456 	} else if (branch_opcode == ZEND_JMPZ) {
7457 		true_label = target_label2;
7458 		false_label = target_label;
7459 	} else if (branch_opcode == ZEND_JMPNZ) {
7460 		true_label = target_label;
7461 		false_label = target_label2;
7462 	} else if (branch_opcode == ZEND_JMPZ_EX) {
7463 		set_bool = 1;
7464 		true_label = target_label2;
7465 		false_label = target_label;
7466 	} else if (branch_opcode == ZEND_JMPNZ_EX) {
7467 		set_bool = 1;
7468 		true_label = target_label;
7469 		false_label = target_label2;
7470 	} else {
7471 		ZEND_UNREACHABLE();
7472 	}
7473 
7474 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7475 		ref = jit_ZVAL_ADDR(jit, op1_addr);
7476 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7477 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7478 	}
7479 
7480 	if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
7481 		if (zend_is_true(Z_ZV(op1_addr))) {
7482 			always_true = 1;
7483 		} else {
7484 			always_false = 1;
7485 		}
7486 	} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7487 		if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7488 			always_true = 1;
7489 		} else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7490 			if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7491 				ref = jit_ZVAL_ADDR(jit, op1_addr);
7492 				zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, 0);
7493 			}
7494 			always_false = 1;
7495 		}
7496 	}
7497 
7498 	if (always_true) {
7499 		if (set_bool) {
7500 			jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7501 		}
7502 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7503 		if (may_throw) {
7504 			zend_jit_check_exception(jit);
7505 		}
7506 		if (true_label != (uint32_t)-1) {
7507 			ZEND_ASSERT(exit_addr == NULL);
7508 			_zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7509 			jit->b = -1;
7510 		}
7511 		return 1;
7512 	} else if (always_false) {
7513 		if (set_bool) {
7514 			jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7515 		}
7516 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7517 		if (may_throw) {
7518 			zend_jit_check_exception(jit);
7519 		}
7520 		if (false_label != (uint32_t)-1) {
7521 			ZEND_ASSERT(exit_addr == NULL);
7522 			_zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7523 			jit->b = -1;
7524 		}
7525 		return 1;
7526 	}
7527 
7528 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7529 		type = jit_Z_TYPE(jit, op1_addr);
7530 		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7531 			ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7532 
7533 			ir_IF_TRUE_cold(if_type);
7534 
7535 			if (op1_info & MAY_BE_UNDEF) {
7536 				zend_jit_type_check_undef(jit,
7537 					type,
7538 					opline->op1.var,
7539 					opline, 1, 0, 1);
7540 			}
7541 			if (set_bool) {
7542 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7543 			}
7544 			if (exit_addr) {
7545 				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
7546 					ir_END_list(end_inputs);
7547 				} else {
7548 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7549 				}
7550 			} else if (false_label != (uint32_t)-1) {
7551 				ir_END_list(false_inputs);
7552 			} else {
7553 				ir_END_list(end_inputs);
7554 			}
7555 			ir_IF_FALSE(if_type);
7556 		}
7557 
7558 		if (op1_info & MAY_BE_TRUE) {
7559 			ir_ref if_type = IR_UNUSED;
7560 
7561 			if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7562 				if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7563 
7564 				ir_IF_TRUE(if_type);
7565 			}
7566 			if (set_bool) {
7567 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7568 			}
7569 			if (exit_addr) {
7570 				if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7571 					ir_END_list(end_inputs);
7572 				} else {
7573 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7574 				}
7575 			} else if (true_label != (uint32_t)-1) {
7576 				ir_END_list(true_inputs);
7577 			} else {
7578 				ir_END_list(end_inputs);
7579 			}
7580 			if (if_type) {
7581 				ir_IF_FALSE(if_type);
7582 			}
7583 		}
7584 	}
7585 
7586 	if (op1_info & MAY_BE_LONG) {
7587 		ir_ref if_long = IR_UNUSED;
7588 		ir_ref ref;
7589 
7590 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
7591 			if (!type) {
7592 				type = jit_Z_TYPE(jit, op1_addr);
7593 			}
7594 			if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7595 			ir_IF_TRUE(if_long);
7596 		}
7597 		ref = jit_Z_LVAL(jit, op1_addr);
7598 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7599 			ref = ir_NE(ref, ir_CONST_LONG(0));
7600 			if (set_bool_not) {
7601 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7602 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7603 			} else {
7604 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7605 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7606 			}
7607 			ir_END_list(end_inputs);
7608 		} else if (exit_addr) {
7609 			if (set_bool) {
7610 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7611 					ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, ir_CONST_LONG(0))), ir_CONST_U32(IS_FALSE)));
7612 			}
7613 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7614 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7615 			} else {
7616 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7617 			}
7618 			ir_END_list(end_inputs);
7619 		} else {
7620 			ir_ref if_val = ir_IF(ref);
7621 			ir_IF_TRUE(if_val);
7622 			if (set_bool) {
7623 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7624 			}
7625 			ir_END_list(true_inputs);
7626 			ir_IF_FALSE(if_val);
7627 			if (set_bool) {
7628 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7629 			}
7630 			ir_END_list(false_inputs);
7631 		}
7632 		if (if_long) {
7633 			ir_IF_FALSE(if_long);
7634 		}
7635 	}
7636 
7637 	if (op1_info & MAY_BE_DOUBLE) {
7638 		ir_ref if_double = IR_UNUSED;
7639 		ir_ref ref;
7640 
7641 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7642 			if (!type) {
7643 				type = jit_Z_TYPE(jit, op1_addr);
7644 			}
7645 			if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7646 			ir_IF_TRUE(if_double);
7647 		}
7648 		ref = ir_NE(jit_Z_DVAL(jit, op1_addr), ir_CONST_DOUBLE(0.0));
7649 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7650 			if (set_bool_not) {
7651 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7652 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7653 			} else {
7654 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7655 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7656 			}
7657 			ir_END_list(end_inputs);
7658 		} else if (exit_addr) {
7659 		    if (set_bool) {
7660 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7661 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7662 		    }
7663 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7664 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7665 			} else {
7666 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7667 			}
7668 			ir_END_list(end_inputs);
7669 		} else {
7670 			ir_ref if_val = ir_IF(ref);
7671 			ir_IF_TRUE(if_val);
7672 			if (set_bool) {
7673 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7674 			}
7675 			ir_END_list(true_inputs);
7676 			ir_IF_FALSE(if_val);
7677 			if (set_bool) {
7678 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7679 			}
7680 			ir_END_list(false_inputs);
7681 		}
7682 		if (if_double) {
7683 			ir_IF_FALSE(if_double);
7684 		}
7685 	}
7686 
7687 	if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7688 		jit_SET_EX_OPLINE(jit, opline);
7689 		ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7690 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7691 		if (may_throw) {
7692 			zend_jit_check_exception_undef_result(jit, opline);
7693 		}
7694 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7695 			if (set_bool_not) {
7696 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7697 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7698 			} else {
7699 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7700 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7701 			}
7702 			if (end_inputs) {
7703 				ir_END_list(end_inputs);
7704 			}
7705 		} else if (exit_addr) {
7706 			if (set_bool) {
7707 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7708 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7709 			}
7710 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7711 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7712 			} else {
7713 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7714 			}
7715 			if (end_inputs) {
7716 				ir_END_list(end_inputs);
7717 			}
7718 		} else {
7719 			ir_ref if_val = ir_IF(ref);
7720 			ir_IF_TRUE(if_val);
7721 			if (set_bool) {
7722 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7723 			}
7724 			ir_END_list(true_inputs);
7725 			ir_IF_FALSE(if_val);
7726 			if (set_bool) {
7727 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7728 			}
7729 			ir_END_list(false_inputs);
7730 		}
7731 	}
7732 
7733 	if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7734 		if (end_inputs) {
7735 			ir_MERGE_list(end_inputs);
7736 		}
7737 	} else {
7738 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7739 	}
7740 
7741 	return 1;
7742 }
7743 
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)7744 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)
7745 {
7746 	uint32_t defined_label = (uint32_t)-1;
7747 	uint32_t undefined_label = (uint32_t)-1;
7748 	zval *zv = RT_CONSTANT(opline, opline->op1);
7749 	zend_jit_addr res_addr = 0;
7750 	ir_ref ref, ref2, if_set, if_zero, if_set2;
7751 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7752 
7753 	if (smart_branch_opcode && !exit_addr) {
7754 		if (smart_branch_opcode == ZEND_JMPZ) {
7755 			defined_label = target_label2;
7756 			undefined_label = target_label;
7757 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
7758 			defined_label = target_label;
7759 			undefined_label = target_label2;
7760 		} else {
7761 			ZEND_UNREACHABLE();
7762 		}
7763 	} else {
7764 		res_addr = RES_ADDR();
7765 	}
7766 
7767 	// if (CACHED_PTR(opline->extended_value)) {
7768 	ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7769 
7770 	if_set = ir_IF(ref);
7771 
7772 	ir_IF_FALSE_cold(if_set);
7773 	if_zero = ir_END();
7774 
7775 	ir_IF_TRUE(if_set);
7776 	if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7777 	ir_IF_FALSE(if_set2);
7778 
7779 	if (exit_addr) {
7780 		if (smart_branch_opcode == ZEND_JMPNZ) {
7781 			jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7782 		} else {
7783 			ir_END_list(end_inputs);
7784 		}
7785 	} else if (smart_branch_opcode) {
7786 		ir_END_list(true_inputs);
7787 	} else {
7788 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7789 		ir_END_list(end_inputs);
7790 	}
7791 
7792 	ir_IF_TRUE_cold(if_set2);
7793 
7794 	ref2 = jit_EG(zend_constants);
7795 	ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7796 	if (sizeof(void*) == 8) {
7797 		ref = ir_TRUNC_U32(ref);
7798 	}
7799 	ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7800 	ref2 = ir_IF(ref2);
7801 	ir_IF_TRUE(ref2);
7802 
7803 	if (exit_addr) {
7804 		if (smart_branch_opcode == ZEND_JMPZ) {
7805 			jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7806 		} else {
7807 			ir_END_list(end_inputs);
7808 		}
7809 	} else if (smart_branch_opcode) {
7810 		ir_END_list(false_inputs);
7811 	} else {
7812 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7813 		ir_END_list(end_inputs);
7814 	}
7815 
7816 	ir_IF_FALSE(ref2);
7817 	ir_MERGE_2(if_zero, ir_END());
7818 
7819 	jit_SET_EX_OPLINE(jit, opline);
7820 	ref2 = ir_NE(ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_check_constant), ir_CONST_ADDR(zv)), IR_NULL);
7821 	if (exit_addr) {
7822 		if (smart_branch_opcode == ZEND_JMPZ) {
7823 			ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
7824 		} else {
7825 			ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
7826 		}
7827 		ir_END_list(end_inputs);
7828 	} else if (smart_branch_opcode) {
7829 		ref2 = ir_IF(ref2);
7830 		ir_IF_TRUE(ref2);
7831 		ir_END_list(true_inputs);
7832 		ir_IF_FALSE(ref2);
7833 		ir_END_list(false_inputs);
7834 	} else {
7835 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7836 			ir_ADD_U32(ir_ZEXT_U32(ref2), ir_CONST_U32(IS_FALSE)));
7837 		ir_END_list(end_inputs);
7838 	}
7839 
7840 	if (!smart_branch_opcode || exit_addr) {
7841 		if (end_inputs) {
7842 			ir_MERGE_list(end_inputs);
7843 		}
7844 	} else {
7845 		_zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
7846 	}
7847 
7848 	return 1;
7849 }
7850 
zend_jit_escape_if_undef(zend_jit_ctx * jit,int var,uint32_t flags,const zend_op * opline,int8_t reg)7851 static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
7852 {
7853 	zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7854 	ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
7855 
7856 	ir_IF_FALSE_cold(if_def);
7857 
7858 	if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7859 		if (!zend_jit_save_call_chain(jit, -1)) {
7860 			return 0;
7861 		}
7862 	}
7863 
7864 	if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
7865 	 && (opline-1)->opcode != ZEND_FETCH_LIST_R
7866 	 && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
7867 	 && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
7868 		zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
7869 
7870 		zend_jit_zval_try_addref(jit, val_addr);
7871 	}
7872 
7873 	jit_LOAD_IP_ADDR(jit, opline - 1);
7874 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
7875 
7876 	ir_IF_TRUE(if_def);
7877 
7878 	return 1;
7879 }
7880 
zend_jit_restore_zval(zend_jit_ctx * jit,int var,int8_t reg)7881 static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
7882 {
7883 	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
7884 	zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7885 
7886 	// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
7887 	jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, 1);
7888 	return 1;
7889 }
7890 
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)7891 static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx         *jit,
7892                                                       const zend_op        *opline,
7893                                                       zend_jit_addr         val_addr,
7894                                                       uint8_t               type,
7895                                                       bool                  deref,
7896                                                       uint32_t              flags,
7897                                                       bool                  op1_avoid_refcounting)
7898 {
7899 	zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
7900 	int32_t exit_point;
7901 	const void *res_exit_addr = NULL;
7902 	ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
7903 	ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
7904 	uint32_t old_op1_info = 0;
7905 	uint32_t old_info;
7906 	ir_ref old_ref;
7907 
7908 
7909 	if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7910 		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
7911 		if (op1_avoid_refcounting
7912 		 || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
7913 		  && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
7914 			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
7915 		}
7916 	}
7917 	old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
7918 	old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7919 	CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7920 	SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
7921 
7922 	if (deref) {
7923 		ir_ref if_type;
7924 
7925 		if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7926 			if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
7927 		} else {
7928 			if_type = jit_if_Z_TYPE(jit, val_addr, type);
7929 		}
7930 		ir_IF_TRUE(if_type);
7931 		end1 = ir_END();
7932 		ref1 = ref;
7933 		ir_IF_FALSE_cold(if_type);
7934 
7935 		SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7936 		exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7937 		res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7938 		if (!res_exit_addr) {
7939 			return 0;
7940 		}
7941 
7942 		jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
7943 		ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
7944 		val_addr = ZEND_ADDR_REF_ZVAL(ref);
7945 	}
7946 
7947 	SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7948 	exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7949 	res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7950 	if (!res_exit_addr) {
7951 		return 0;
7952 	}
7953 
7954 	if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7955 		ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
7956 	} else {
7957 		jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
7958 	}
7959 
7960 	if (deref) {
7961 		ir_MERGE_WITH(end1);
7962 		ref = ir_PHI_2(IR_ADDR, ref, ref1);
7963 	}
7964 
7965 	val_addr = ZEND_ADDR_REF_ZVAL(ref);
7966 
7967 	SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
7968 	SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
7969 	if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7970 		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
7971 	}
7972 
7973 	return val_addr;
7974 }
7975 
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)7976 static int zend_jit_fetch_constant(zend_jit_ctx         *jit,
7977                                    const zend_op        *opline,
7978                                    const zend_op_array  *op_array,
7979                                    zend_ssa             *ssa,
7980                                    const zend_ssa_op    *ssa_op,
7981                                    zend_jit_addr         res_addr)
7982 {
7983 	zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
7984 	uint32_t res_info = RES_INFO();
7985 	ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
7986 
7987 	// JIT: c = CACHED_PTR(opline->extended_value);
7988 	ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7989 
7990 	// JIT: if (c != NULL)
7991 	if_set = ir_IF(ref);
7992 
7993 	if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
7994 		// JIT: if (!IS_SPECIAL_CACHE_VAL(c))
7995 		ir_IF_FALSE_cold(if_set);
7996 		not_set_path = ir_END();
7997 		ir_IF_TRUE(if_set);
7998 		if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7999 		ir_IF_TRUE_cold(if_special);
8000 		special_path = ir_END();
8001 		ir_IF_FALSE(if_special);
8002 		fast_path = ir_END();
8003 		ir_MERGE_2(not_set_path, special_path);
8004 	} else {
8005 		ir_IF_TRUE(if_set);
8006 		fast_path = ir_END();
8007 		ir_IF_FALSE_cold(if_set);
8008 	}
8009 
8010 	// JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
8011 	jit_SET_EX_OPLINE(jit, opline);
8012 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_constant),
8013 		ir_CONST_ADDR(zv),
8014 		ir_CONST_U32(opline->op1.num));
8015 	ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8016 
8017 	ir_MERGE_WITH(fast_path);
8018 	ref = ir_PHI_2(IR_ADDR, ref2, ref);
8019 
8020 	if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
8021 		uint8_t type = concrete_type(res_info);
8022 		zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
8023 
8024 		const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, 0, 0, 0);
8025 		if (!const_addr) {
8026 			return 0;
8027 		}
8028 
8029 		res_info &= ~MAY_BE_GUARD;
8030 		ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
8031 
8032 		// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8033 		jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, 1);
8034 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
8035 			return 0;
8036 		}
8037 	} else {
8038 		ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
8039 
8040 		// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8041 		jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, 1);
8042 	}
8043 
8044 
8045 	return 1;
8046 }
8047 
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)8048 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)
8049 {
8050 	uint32_t  mask;
8051 	zend_jit_addr op1_addr = OP1_ADDR();
8052 	zend_jit_addr res_addr = 0;
8053 	uint32_t true_label = -1, false_label = -1;
8054 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8055 
8056 	// TODO: support for is_resource() ???
8057 	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8058 
8059 	if (smart_branch_opcode && !exit_addr) {
8060 		if (smart_branch_opcode == ZEND_JMPZ) {
8061 			true_label = target_label2;
8062 			false_label = target_label;
8063 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
8064 			true_label = target_label;
8065 			false_label = target_label2;
8066 		} else {
8067 			ZEND_UNREACHABLE();
8068 		}
8069 	} else {
8070 		res_addr = RES_ADDR();
8071 	}
8072 
8073 	if (op1_info & MAY_BE_UNDEF) {
8074 		ir_ref if_def = IR_UNUSED;
8075 
8076 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8077 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8078 			ir_IF_FALSE_cold(if_def);
8079 		}
8080 
8081 		jit_SET_EX_OPLINE(jit, opline);
8082 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8083 		zend_jit_check_exception_undef_result(jit, opline);
8084 		if (opline->extended_value & MAY_BE_NULL) {
8085 			if (exit_addr) {
8086 				if (smart_branch_opcode == ZEND_JMPNZ) {
8087 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8088 				} else {
8089 					ir_END_list(end_inputs);
8090 				}
8091 			} else if (smart_branch_opcode) {
8092 				ir_END_list(true_inputs);
8093 			} else {
8094 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8095 				ir_END_list(end_inputs);
8096 			}
8097 		} else {
8098 			if (exit_addr) {
8099 				if (smart_branch_opcode == ZEND_JMPZ) {
8100 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8101 				} else {
8102 					ir_END_list(end_inputs);
8103 				}
8104 			} else if (smart_branch_opcode) {
8105 				ir_END_list(false_inputs);
8106 			} else {
8107 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8108 				if (if_def) {
8109 					ir_END_list(end_inputs);
8110 				}
8111 			}
8112 		}
8113 
8114 		if (if_def) {
8115 			ir_IF_TRUE(if_def);
8116 			op1_info |= MAY_BE_NULL;
8117 		}
8118 	}
8119 
8120 	if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8121 		mask = opline->extended_value;
8122 		if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8123 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8124 			if (exit_addr) {
8125 				if (smart_branch_opcode == ZEND_JMPNZ) {
8126 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8127 				} else if (end_inputs) {
8128 					ir_END_list(end_inputs);
8129 				}
8130 			} else if (smart_branch_opcode) {
8131 				ir_END_list(true_inputs);
8132 			} else {
8133 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8134 				ir_END_list(end_inputs);
8135 			}
8136 	    } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8137 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8138 			if (exit_addr) {
8139 				if (smart_branch_opcode == ZEND_JMPZ) {
8140 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8141 				} else if (end_inputs) {
8142 					ir_END_list(end_inputs);
8143 				}
8144 			} else if (smart_branch_opcode) {
8145 				ir_END_list(false_inputs);
8146 			} else {
8147 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8148 				ir_END_list(end_inputs);
8149 			}
8150 		} else {
8151 			ir_ref ref;
8152 			bool invert = 0;
8153 			uint8_t type;
8154 
8155 			switch (mask) {
8156 				case MAY_BE_NULL:   type = IS_NULL;   break;
8157 				case MAY_BE_FALSE:  type = IS_FALSE;  break;
8158 				case MAY_BE_TRUE:   type = IS_TRUE;   break;
8159 				case MAY_BE_LONG:   type = IS_LONG;   break;
8160 				case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8161 				case MAY_BE_STRING: type = IS_STRING; break;
8162 				case MAY_BE_ARRAY:  type = IS_ARRAY;  break;
8163 				case MAY_BE_OBJECT: type = IS_OBJECT; break;
8164 				case MAY_BE_ANY - MAY_BE_NULL:     type = IS_NULL;   invert = 1; break;
8165 				case MAY_BE_ANY - MAY_BE_FALSE:    type = IS_FALSE;  invert = 1; break;
8166 				case MAY_BE_ANY - MAY_BE_TRUE:     type = IS_TRUE;   invert = 1; break;
8167 				case MAY_BE_ANY - MAY_BE_LONG:     type = IS_LONG;   invert = 1; break;
8168 				case MAY_BE_ANY - MAY_BE_DOUBLE:   type = IS_DOUBLE; invert = 1; break;
8169 				case MAY_BE_ANY - MAY_BE_STRING:   type = IS_STRING; invert = 1; break;
8170 				case MAY_BE_ANY - MAY_BE_ARRAY:    type = IS_ARRAY;  invert = 1; break;
8171 				case MAY_BE_ANY - MAY_BE_OBJECT:   type = IS_OBJECT; invert = 1; break;
8172 				case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break;
8173 				default:
8174 					type = 0;
8175 			}
8176 
8177 			if (op1_info & MAY_BE_REF) {
8178 				ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8179 				ref = jit_ZVAL_DEREF_ref(jit, ref);
8180 				op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8181 			}
8182 			if (type == 0) {
8183 				ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8184 				if (!smart_branch_opcode) {
8185 					ref = ir_NE(ref, ir_CONST_U32(0));
8186 				}
8187 			} else if (invert) {
8188 				ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8189 			} else {
8190 				ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8191 			}
8192 
8193 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8194 
8195 			if (exit_addr) {
8196 				if (smart_branch_opcode == ZEND_JMPZ) {
8197 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8198 				} else {
8199 					ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8200 				}
8201 				if (end_inputs) {
8202 					ir_END_list(end_inputs);
8203 				}
8204 			} else if (smart_branch_opcode) {
8205 				ir_ref if_val = ir_IF(ref);
8206 				ir_IF_TRUE(if_val);
8207 				ir_END_list(true_inputs);
8208 				ir_IF_FALSE(if_val);
8209 				ir_END_list(false_inputs);
8210 			} else {
8211 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8212 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8213 				ir_END_list(end_inputs);
8214 			}
8215 	    }
8216 	}
8217 
8218 	if (!smart_branch_opcode || exit_addr) {
8219 		if (end_inputs) {
8220 			ir_MERGE_list(end_inputs);
8221 		} else if (exit_addr && !jit->ctx.control) {
8222 			ir_BEGIN(IR_UNUSED); /* unreachable block */
8223 		}
8224 	} else {
8225 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8226 	}
8227 
8228 	return 1;
8229 }
8230 
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)8231 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)
8232 {
8233 	zend_jit_addr res_addr = RES_ADDR();
8234 	uint32_t true_label = -1, false_label = -1;
8235 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8236 
8237 	// TODO: support for empty() ???
8238 	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8239 
8240 	if (smart_branch_opcode && !exit_addr) {
8241 		if (smart_branch_opcode == ZEND_JMPZ) {
8242 			true_label = target_label2;
8243 			false_label = target_label;
8244 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
8245 			true_label = target_label;
8246 			false_label = target_label2;
8247 		} else {
8248 			ZEND_UNREACHABLE();
8249 		}
8250 	} else {
8251 		res_addr = RES_ADDR();
8252 	}
8253 
8254 	if (op1_info & MAY_BE_REF) {
8255 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8256 		ref = jit_ZVAL_DEREF_ref(jit, ref);
8257 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8258 	}
8259 
8260 	if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8261 		if (exit_addr) {
8262 			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8263 		} else if (smart_branch_opcode) {
8264 			ir_END_list(true_inputs);
8265 		} else {
8266 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8267 			ir_END_list(end_inputs);
8268 		}
8269 	} else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8270 		if (exit_addr) {
8271 			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8272 		} else if (smart_branch_opcode) {
8273 			ir_END_list(false_inputs);
8274 		} else {
8275 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8276 			ir_END_list(end_inputs);
8277 		}
8278 	} else {
8279 		ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8280 		if (exit_addr) {
8281 			if (smart_branch_opcode == ZEND_JMPNZ) {
8282 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8283 			} else {
8284 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8285 			}
8286 		} else if (smart_branch_opcode) {
8287 			ir_ref if_val = ir_IF(ref);
8288 			ir_IF_TRUE(if_val);
8289 			ir_END_list(true_inputs);
8290 			ir_IF_FALSE(if_val);
8291 			ir_END_list(false_inputs);
8292 		} else {
8293 			jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8294 				ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8295 			ir_END_list(end_inputs);
8296 		}
8297 	}
8298 
8299 	if (!smart_branch_opcode || exit_addr) {
8300 		if (end_inputs) {
8301 			ir_MERGE_list(end_inputs);
8302 		}
8303 	} else {
8304 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8305 	}
8306 
8307 	return 1;
8308 }
8309 
8310 /* copy of hidden zend_closure */
8311 typedef struct _zend_closure {
8312 	zend_object       std;
8313 	zend_function     func;
8314 	zval              this_ptr;
8315 	zend_class_entry *called_scope;
8316 	zif_handler       orig_internal_handler;
8317 } zend_closure;
8318 
zend_jit_stack_check(zend_jit_ctx * jit,const zend_op * opline,uint32_t used_stack)8319 static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8320 {
8321 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8322 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8323 
8324 	if (!exit_addr) {
8325 		return 0;
8326 	}
8327 
8328 	// JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8329 	ir_GUARD(
8330 		ir_UGE(
8331 			ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8332 			ir_CONST_ADDR(used_stack)),
8333 		ir_CONST_ADDR(exit_addr));
8334 
8335 	return 1;
8336 }
8337 
zend_jit_free_trampoline(zend_jit_ctx * jit,int8_t func_reg)8338 static int zend_jit_free_trampoline(zend_jit_ctx *jit, int8_t func_reg)
8339 {
8340 	// JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8341 	ir_ref func = ir_RLOAD_A(func_reg);
8342 	ir_ref if_trampoline = ir_IF(ir_AND_U32(
8343 		ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8344 		ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
8345 
8346 	ir_IF_TRUE(if_trampoline);
8347 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8348 	ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8349 
8350 	return 1;
8351 }
8352 
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)8353 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)
8354 {
8355 	uint32_t used_stack;
8356 	ir_ref used_stack_ref = IR_UNUSED;
8357 	bool stack_check = 1;
8358 	ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8359 
8360 	ZEND_ASSERT(func_ref != IR_NULL);
8361 	if (func) {
8362 		used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8363 		if ((int)used_stack <= checked_stack) {
8364 			stack_check = 0;
8365 		}
8366 		used_stack_ref = ir_CONST_ADDR(used_stack);
8367 	} else {
8368 		ir_ref num_args_ref;
8369 		ir_ref if_internal_func = IR_UNUSED;
8370 
8371 		used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8372 		used_stack_ref = ir_CONST_ADDR(used_stack);
8373 
8374 		if (!is_closure) {
8375 			used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8376 
8377 			// JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8378 			ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
8379 			if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8380 			ir_IF_FALSE(if_internal_func);
8381 		}
8382 
8383 		// JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8384 		num_args_ref = ir_CONST_U32(opline->extended_value);
8385 		if (!is_closure) {
8386 			ref = ir_SUB_U32(
8387 				ir_SUB_U32(
8388 					ir_MIN_U32(
8389 						num_args_ref,
8390 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.num_args)))),
8391 					ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.last_var)))),
8392 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8393 		} else {
8394 			ref = ir_SUB_U32(
8395 				ir_SUB_U32(
8396 					ir_MIN_U32(
8397 						num_args_ref,
8398 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8399 					ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8400 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8401 		}
8402 		ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8403 		if (sizeof(void*) == 8) {
8404 			ref = ir_SEXT_A(ref);
8405 		}
8406 		ref = ir_SUB_A(used_stack_ref, ref);
8407 
8408 		if (is_closure) {
8409 			used_stack_ref = ref;
8410 		} else {
8411 			ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8412 			used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8413 		}
8414 	}
8415 
8416 	zend_jit_start_reuse_ip(jit);
8417 
8418 	// JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8419 	jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8420 
8421 	if (stack_check) {
8422 		// JIT: Check Stack Overflow
8423 		ref = ir_UGE(
8424 			ir_SUB_A(
8425 				ir_LOAD_A(jit_EG(vm_stack_end)),
8426 				jit_IP(jit)),
8427 			used_stack_ref);
8428 
8429 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8430 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8431 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8432 
8433 			if (!exit_addr) {
8434 				return 0;
8435 			}
8436 
8437 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8438 		} else {
8439 			if_enough_stack = ir_IF(ref);
8440 			ir_IF_FALSE_cold(if_enough_stack);
8441 
8442 #ifdef _WIN32
8443 			if (0) {
8444 #else
8445 			if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8446 #endif
8447 				jit_SET_EX_OPLINE(jit, opline);
8448 				ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8449 			} else {
8450 				if (!is_closure) {
8451 					ref = func_ref;
8452 				} else {
8453 					ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8454 				}
8455 				jit_SET_EX_OPLINE(jit, opline);
8456 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8457 					used_stack_ref, ref);
8458 			}
8459 			jit_STORE_IP(jit, ref);
8460 
8461 			cold_path = ir_END();
8462 			ir_IF_TRUE(if_enough_stack);
8463 		}
8464 	}
8465 
8466 	ref = jit_EG(vm_stack_top);
8467 	rx = jit_IP(jit);
8468 #if !OPTIMIZE_FOR_SIZE
8469 	/* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8470 	 * This vesions is longer but faster
8471 	 *    mov EG(vm_stack_top), %CALL
8472 	 *    lea size(%call), %tmp
8473 	 *    mov %tmp, EG(vm_stack_top)
8474 	 */
8475 	top = rx;
8476 #else
8477 	/* JIT: EG(vm_stack_top) += used_stack;
8478 	 * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8479 	 *    mov EG(vm_stack_top), %CALL
8480 	 *    add $size, EG(vm_stack_top)
8481 	 */
8482 	top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8483 #endif
8484 	ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8485 
8486 	// JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8487 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8488 		// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8489 		ir_STORE(jit_CALL(rx, This.u1.type_info), ir_CONST_U32(IS_UNDEF | ZEND_CALL_NESTED_FUNCTION));
8490 	}
8491 #ifdef _WIN32
8492 	if (0) {
8493 #else
8494 	if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8495 #endif
8496 		if (cold_path) {
8497 			ir_MERGE_WITH(cold_path);
8498 			rx = jit_IP(jit);
8499 		}
8500 
8501 		// JIT: call->func = func;
8502 		ir_STORE(jit_CALL(rx, func), func_ref);
8503 	} else {
8504 		if (!is_closure) {
8505 			// JIT: call->func = func;
8506 			ir_STORE(jit_CALL(rx, func), func_ref);
8507 		} else {
8508 			// JIT: call->func = &closure->func;
8509 			ir_STORE(jit_CALL(rx, func), ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8510 		}
8511 		if (cold_path) {
8512 			ir_MERGE_WITH(cold_path);
8513 			rx = jit_IP(jit);
8514 		}
8515 	}
8516 	if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8517 		// JIT: Z_PTR(call->This) = obj;
8518 		ZEND_ASSERT(this_ref != IR_NULL);
8519 		ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8520 	    if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8521 			// JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8522 			ref = jit_CALL(rx, This.u1.type_info);
8523 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8524 				ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS));
8525 			} else {
8526 				ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_HAS_THIS)));
8527 			}
8528 	    } else {
8529 			if (opline->op1_type == IS_CV) {
8530 				// JIT: GC_ADDREF(obj);
8531 				jit_GC_ADDREF(jit, this_ref);
8532 			}
8533 
8534 			// JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8535 			ref = jit_CALL(rx, This.u1.type_info);
8536 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8537 				ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS));
8538 			} else {
8539 				ir_STORE(ref,
8540 					ir_OR_U32(ir_LOAD_U32(ref),
8541 						ir_CONST_U32(ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)));
8542 			}
8543 	    }
8544 	} else if (!is_closure) {
8545 		// JIT: Z_CE(call->This) = called_scope;
8546 		ir_STORE(jit_CALL(rx, This), IR_NULL);
8547 	} else {
8548 		ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8549 
8550 		if (opline->op2_type == IS_CV) {
8551 			// JIT: GC_ADDREF(closure);
8552 			jit_GC_ADDREF(jit, func_ref);
8553 		}
8554 
8555 		// JIT: RX(object_or_called_scope) = closure->called_scope;
8556 		object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8557 
8558 		// JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8559 		//      (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8560 		call_info = ir_OR_U32(
8561 			ir_AND_U32(
8562 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8563 				ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
8564 			ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
8565 		// JIT: if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
8566 		if_cond = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.u1.v.type))));
8567 		ir_IF_TRUE(if_cond);
8568 
8569 		// JIT: call_info |= ZEND_CALL_HAS_THIS;
8570 		call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
8571 
8572 		// JIT: object_or_called_scope = Z_OBJ(closure->this_ptr);
8573 		object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.value.ptr)));
8574 
8575 		ir_MERGE_WITH_EMPTY_FALSE(if_cond);
8576 		call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8577 		object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8578 
8579 		// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8580 		ref = jit_CALL(rx, This.u1.type_info);
8581 		ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), call_info));
8582 
8583 		// JIT: Z_PTR(call->This) = object_or_called_scope;
8584 		ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8585 
8586 		// JIT: if (closure->func.op_array.run_time_cache__ptr)
8587 		if_cond = ir_IF(ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.run_time_cache__ptr))));
8588 		ir_IF_FALSE(if_cond);
8589 
8590 		// JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8591 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8592 			ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8593 
8594 		ir_MERGE_WITH_EMPTY_TRUE(if_cond);
8595 	}
8596 
8597 	// JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8598 	ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8599 
8600 	return 1;
8601 }
8602 
8603 static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8604 {
8605 	int32_t exit_point;
8606 	const void *exit_addr;
8607 	ir_ref call;
8608 
8609 	if (func->type == ZEND_INTERNAL_FUNCTION) {
8610 #ifdef ZEND_WIN32
8611 		// TODO: ASLR may cause different addresses in different workers ???
8612 		return 0;
8613 #endif
8614 	} else if (func->type == ZEND_USER_FUNCTION) {
8615 		if (!zend_accel_in_shm(func->op_array.opcodes)) {
8616 			/* op_array and op_array->opcodes are not persistent. We can't link. */
8617 			return 0;
8618 		}
8619 	} else {
8620 		ZEND_UNREACHABLE();
8621 		return 0;
8622 	}
8623 
8624 	exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8625 	exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8626 	if (!exit_addr) {
8627 		return 0;
8628 	}
8629 
8630 	// call = EX(call);
8631 	call = ir_LOAD_A(jit_EX(call));
8632 	while (level > 0) {
8633 		// call = call->prev_execute_data
8634 		call = ir_LOAD_A(jit_CALL(call, prev_execute_data));
8635 		level--;
8636 	}
8637 
8638 	if (func->type == ZEND_USER_FUNCTION &&
8639 	    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8640 	     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8641 	     !func->common.function_name)) {
8642 		const zend_op *opcodes = func->op_array.opcodes;
8643 
8644 		// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8645 		ir_GUARD(
8646 			ir_EQ(
8647 				ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(call, func)), offsetof(zend_op_array, opcodes))),
8648 				ir_CONST_ADDR(opcodes)),
8649 			ir_CONST_ADDR(exit_addr));
8650 	} else {
8651 		// JIT: if (call->func != func) goto exit_addr;
8652 		ir_GUARD(ir_EQ(ir_LOAD_A(jit_CALL(call, func)), ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8653 	}
8654 
8655 	return 1;
8656 }
8657 
8658 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)
8659 {
8660 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
8661 	zend_call_info *call_info = NULL;
8662 	zend_function *func = NULL;
8663 	ir_ref func_ref = IR_UNUSED;
8664 
8665 	if (jit->delayed_call_level) {
8666 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8667 			return 0;
8668 		}
8669 	}
8670 
8671 	if (info) {
8672 		call_info = info->callee_info;
8673 		while (call_info && call_info->caller_init_opline != opline) {
8674 			call_info = call_info->next_callee;
8675 		}
8676 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
8677 			func = call_info->callee_func;
8678 		}
8679 	}
8680 
8681 	if (!func
8682 	 && trace
8683 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8684 #ifdef _WIN32
8685 		/* ASLR */
8686 		if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8687 			func = (zend_function*)trace->func;
8688 		}
8689 #else
8690 		func = (zend_function*)trace->func;
8691 #endif
8692 	}
8693 
8694 #ifdef _WIN32
8695 	if (0) {
8696 #else
8697 	if (opline->opcode == ZEND_INIT_FCALL
8698 	 && func
8699 	 && func->type == ZEND_INTERNAL_FUNCTION) {
8700 #endif
8701 		/* load constant address later */
8702 		func_ref = ir_CONST_ADDR(func);
8703 	} else if (func && op_array == &func->op_array) {
8704 		/* recursive call */
8705 		if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8706 		 || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8707 			func_ref = ir_LOAD_A(jit_EX(func));
8708 		} else {
8709 			func_ref = ir_CONST_ADDR(func);
8710 		}
8711 	} else {
8712 		ir_ref if_func, cache_slot_ref, ref;
8713 
8714 		// JIT: if (CACHED_PTR(opline->result.num))
8715 		cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8716 		func_ref = ir_LOAD_A(cache_slot_ref);
8717 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8718 		 && func
8719 		 && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8720 		 && opline->opcode != ZEND_INIT_FCALL) {
8721 			/* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8722 			if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8723 		} else {
8724 			if_func = ir_IF(func_ref);
8725 		}
8726 		ir_IF_FALSE_cold(if_func);
8727 		if (opline->opcode == ZEND_INIT_FCALL
8728 		 && func
8729 		 && func->type == ZEND_USER_FUNCTION
8730 		 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8731 			ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8732 		    ir_STORE(cache_slot_ref, ref);
8733 			ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8734 		} else {
8735 			zval *zv = RT_CONSTANT(opline, opline->op2);
8736 
8737 			if (opline->opcode == ZEND_INIT_FCALL) {
8738 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8739 					ir_CONST_ADDR(Z_STR_P(zv)),
8740 					cache_slot_ref);
8741 			} else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8742 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8743 					ir_CONST_ADDR(Z_STR_P(zv + 1)),
8744 					cache_slot_ref);
8745 			} else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8746 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8747 					ir_CONST_ADDR(zv),
8748 					cache_slot_ref);
8749 			} else {
8750 				ZEND_UNREACHABLE();
8751 			}
8752 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8753 				int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8754 					func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8755 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8756 
8757 				if (!exit_addr) {
8758 					return 0;
8759 				}
8760 				if (!func || opline->opcode == ZEND_INIT_FCALL) {
8761 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8762 				} else if (func->type == ZEND_USER_FUNCTION
8763 					 && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
8764 					const zend_op *opcodes = func->op_array.opcodes;
8765 
8766 					ir_GUARD(
8767 						ir_EQ(
8768 							ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_op_array, opcodes))),
8769 							ir_CONST_ADDR(opcodes)),
8770 						ir_CONST_ADDR(exit_addr));
8771 				} else {
8772 					ir_GUARD(ir_EQ(ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8773 				}
8774 			} else {
8775 jit_SET_EX_OPLINE(jit, opline);
8776 				ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8777 			}
8778 		}
8779 		ir_MERGE_WITH_EMPTY_TRUE(if_func);
8780 		func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8781 	}
8782 
8783 	if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, IR_UNUSED)) {
8784 		return 0;
8785 	}
8786 
8787 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8788 		if (!zend_jit_save_call_chain(jit, call_level)) {
8789 			return 0;
8790 		}
8791 	} else {
8792 		ZEND_ASSERT(call_level > 0);
8793 		jit->delayed_call_level = call_level;
8794 		delayed_call_chain = 1;
8795 	}
8796 
8797 	return 1;
8798 }
8799 
8800 static int zend_jit_init_method_call(zend_jit_ctx         *jit,
8801                                      const zend_op        *opline,
8802                                      uint32_t              b,
8803                                      const zend_op_array  *op_array,
8804                                      zend_ssa             *ssa,
8805                                      const zend_ssa_op    *ssa_op,
8806                                      int                   call_level,
8807                                      uint32_t              op1_info,
8808                                      zend_jit_addr         op1_addr,
8809                                      zend_class_entry     *ce,
8810                                      bool                  ce_is_instanceof,
8811                                      bool                  on_this,
8812                                      bool                  delayed_fetch_this,
8813                                      zend_class_entry     *trace_ce,
8814                                      zend_jit_trace_rec   *trace,
8815                                      int                   checked_stack,
8816                                      int8_t                func_reg,
8817                                      int8_t                this_reg,
8818                                      bool                  polymorphic_side_trace)
8819 {
8820 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
8821 	zend_call_info *call_info = NULL;
8822 	zend_function *func = NULL;
8823 	zval *function_name;
8824 	ir_ref if_static = IR_UNUSED, cold_path, this_ref = IR_NULL, func_ref = IR_NULL;
8825 
8826 	ZEND_ASSERT(opline->op2_type == IS_CONST);
8827 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
8828 
8829 	function_name = RT_CONSTANT(opline, opline->op2);
8830 
8831 	if (info) {
8832 		call_info = info->callee_info;
8833 		while (call_info && call_info->caller_init_opline != opline) {
8834 			call_info = call_info->next_callee;
8835 		}
8836 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
8837 			func = call_info->callee_func;
8838 		}
8839 	}
8840 
8841 	if (polymorphic_side_trace) {
8842 		/* function is passed in r0 from parent_trace */
8843 		ZEND_ASSERT(func_reg >= 0 && this_reg >= 0);
8844 		func_ref = zend_jit_deopt_rload(jit, IR_ADDR, func_reg);
8845 		this_ref = zend_jit_deopt_rload(jit, IR_ADDR, this_reg);
8846 	} else {
8847 		ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
8848 
8849 		if (on_this) {
8850 			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
8851 			this_ref = jit_Z_PTR(jit, this_addr);
8852 		} else {
8853 		    if (op1_info & MAY_BE_REF) {
8854 				if (opline->op1_type == IS_CV) {
8855 					// JIT: ZVAL_DEREF(op1)
8856 					ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8857 					ref = jit_ZVAL_DEREF_ref(jit, ref);
8858 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8859 				} else {
8860 					ir_ref if_ref;
8861 
8862 					/* Hack: Convert reference to regular value to simplify JIT code */
8863 					ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
8864 
8865 					if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
8866 					ir_IF_TRUE(if_ref);
8867 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
8868 
8869 					ir_MERGE_WITH_EMPTY_FALSE(if_ref);
8870 				}
8871 			}
8872 			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
8873 				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8874 					int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8875 					const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8876 
8877 					if (!exit_addr) {
8878 						return 0;
8879 					}
8880 					ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
8881 						ir_CONST_ADDR(exit_addr));
8882 				} else {
8883 					ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
8884 
8885 					ir_IF_FALSE_cold(if_object);
8886 
8887 					jit_SET_EX_OPLINE(jit, opline);
8888 					if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8889 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
8890 							jit_ZVAL_ADDR(jit, op1_addr));
8891 					} else {
8892 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
8893 							jit_ZVAL_ADDR(jit, op1_addr));
8894 					}
8895 					ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
8896 					ir_IF_TRUE(if_object);
8897 				}
8898 			}
8899 
8900 			this_ref = jit_Z_PTR(jit, op1_addr);
8901 		}
8902 
8903 		if (jit->delayed_call_level) {
8904 			if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8905 				return 0;
8906 			}
8907 		}
8908 
8909 		if (func) {
8910 			// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8911 			ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
8912 
8913 			if_found = ir_IF(ref);
8914 			ir_IF_TRUE(if_found);
8915 			fast_path = ir_END();
8916 		} else {
8917 			// JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
8918 			run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
8919 			ref = ir_EQ(
8920 				ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
8921 				ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
8922 			if_found = ir_IF(ref);
8923 			ir_IF_TRUE(if_found);
8924 
8925 			// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8926 			ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
8927 			fast_path = ir_END();
8928 
8929 		}
8930 
8931 		ir_IF_FALSE_cold(if_found);
8932 		jit_SET_EX_OPLINE(jit, opline);
8933 
8934 		if (!jit->ctx.fixed_call_stack_size) {
8935 			// JIT: alloca(sizeof(void*));
8936 			this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
8937 		} else {
8938 			this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
8939 		}
8940 		ir_STORE(this_ref2, this_ref);
8941 
8942 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8943 			ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
8944 					this_ref,
8945 					ir_CONST_ADDR(function_name),
8946 					this_ref2);
8947 		} else {
8948 			ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
8949 					this_ref,
8950 					ir_CONST_ADDR(function_name),
8951 					this_ref2);
8952 		}
8953 
8954 		this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
8955 		if (!jit->ctx.fixed_call_stack_size) {
8956 			// JIT: revert alloca
8957 			ir_AFREE(ir_CONST_ADDR(0x10));
8958 		}
8959 
8960 		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8961 
8962 		ir_MERGE_WITH(fast_path);
8963 		func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
8964 		this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
8965 	}
8966 
8967 	if ((!func || zend_jit_may_be_modified(func, op_array))
8968 	 && trace
8969 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
8970 	 && trace->func
8971 #ifdef _WIN32
8972 	 && trace->func->type != ZEND_INTERNAL_FUNCTION
8973 #endif
8974 	) {
8975 		int32_t exit_point;
8976 		const void *exit_addr;
8977 
8978 		exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
8979 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8980 		if (!exit_addr) {
8981 			return 0;
8982 		}
8983 
8984 		jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
8985 		jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
8986 
8987 		func = (zend_function*)trace->func;
8988 
8989 		if (func->type == ZEND_USER_FUNCTION &&
8990 		    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8991 		     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8992 		     !func->common.function_name)) {
8993 			const zend_op *opcodes = func->op_array.opcodes;
8994 
8995 			ir_GUARD(
8996 				ir_EQ(
8997 					ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8998 					ir_CONST_ADDR(opcodes)),
8999 				ir_CONST_ADDR(exit_addr));
9000 		} else {
9001 			ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9002 		}
9003 	}
9004 
9005 	if (!func) {
9006 		// JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9007 		if_static = ir_IF(ir_AND_U32(
9008 			ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9009 			ir_CONST_U32(ZEND_ACC_STATIC)));
9010 		ir_IF_TRUE_cold(if_static);
9011 	}
9012 
9013 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9014 		ir_ref ret;
9015 
9016 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9017 			ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_metod_call_frame_tmp),
9018 					this_ref,
9019 					func_ref,
9020 					ir_CONST_U32(opline->extended_value));
9021 		} else {
9022 			ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_metod_call_frame),
9023 					this_ref,
9024 					func_ref,
9025 					ir_CONST_U32(opline->extended_value));
9026 		}
9027 
9028 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
9029 			ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9030 		}
9031 		jit_STORE_IP(jit, ret);
9032 	}
9033 
9034 	if (!func) {
9035 		cold_path = ir_END();
9036 		ir_IF_FALSE(if_static);
9037 	}
9038 
9039 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9040 		if (!zend_jit_push_call_frame(jit, opline, NULL, func, 0, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
9041 			return 0;
9042 		}
9043 	}
9044 
9045 	if (!func) {
9046 		ir_MERGE_WITH(cold_path);
9047 	}
9048 	zend_jit_start_reuse_ip(jit);
9049 
9050 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9051 		if (!zend_jit_save_call_chain(jit, call_level)) {
9052 			return 0;
9053 		}
9054 	} else {
9055 		ZEND_ASSERT(call_level > 0);
9056 		delayed_call_chain = 1;
9057 		jit->delayed_call_level = call_level;
9058 	}
9059 
9060 	return 1;
9061 }
9062 
9063 static int zend_jit_init_closure_call(zend_jit_ctx         *jit,
9064                                       const zend_op        *opline,
9065                                       uint32_t              b,
9066                                       const zend_op_array  *op_array,
9067                                       zend_ssa             *ssa,
9068                                       const zend_ssa_op    *ssa_op,
9069                                       int                   call_level,
9070                                       zend_jit_trace_rec   *trace,
9071                                       int                   checked_stack)
9072 {
9073 	zend_function *func = NULL;
9074 	zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9075 	ir_ref ref;
9076 
9077 	ref = jit_Z_PTR(jit, op2_addr);
9078 
9079 	if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9080 	 && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9081 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9082 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9083 
9084 		if (!exit_addr) {
9085 			return 0;
9086 		}
9087 
9088 		ir_GUARD(
9089 			ir_EQ(
9090 				ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_object, ce))),
9091 				ir_CONST_ADDR(zend_ce_closure)),
9092 			ir_CONST_ADDR(exit_addr));
9093 
9094 		if (ssa->var_info && ssa_op->op2_use >= 0) {
9095 			ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9096 			ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9097 			ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9098 		}
9099 	}
9100 
9101 	if (trace
9102 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9103 	 && trace->func
9104 	 && trace->func->type == ZEND_USER_FUNCTION) {
9105 		const zend_op *opcodes;
9106 		int32_t exit_point;
9107 		const void *exit_addr;
9108 
9109 		func = (zend_function*)trace->func;
9110 		opcodes = func->op_array.opcodes;
9111 		exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9112 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9113 		if (!exit_addr) {
9114 			return 0;
9115 		}
9116 
9117 		ir_GUARD(
9118 			ir_EQ(
9119 				ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9120 				ir_CONST_ADDR(opcodes)),
9121 			ir_CONST_ADDR(exit_addr));
9122 	}
9123 
9124 	if (jit->delayed_call_level) {
9125 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9126 			return 0;
9127 		}
9128 	}
9129 
9130 	if (!zend_jit_push_call_frame(jit, opline, NULL, func, 1, 0, checked_stack, ref, IR_UNUSED)) {
9131 		return 0;
9132 	}
9133 
9134 	if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9135 		if (!zend_jit_save_call_chain(jit, call_level)) {
9136 			return 0;
9137 		}
9138 	} else {
9139 		ZEND_ASSERT(call_level > 0);
9140 		delayed_call_chain = 1;
9141 		jit->delayed_call_level = call_level;
9142 	}
9143 
9144 	if (trace
9145 	 && trace->op == ZEND_JIT_TRACE_END
9146 	 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
9147 		if (!zend_jit_set_ip(jit, opline + 1)) {
9148 			return 0;
9149 		}
9150 	}
9151 
9152 	return 1;
9153 }
9154 
9155 static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9156 {
9157 	uint32_t arg_num = opline->op2.num;
9158 	zend_jit_addr arg_addr;
9159 
9160 	ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
9161 
9162 	if (!zend_jit_reuse_ip(jit)) {
9163 		return 0;
9164 	}
9165 
9166 	if (opline->opcode == ZEND_SEND_VAL_EX) {
9167 		uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9168 
9169 		ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
9170 
9171 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9172 		 && JIT_G(current_frame)
9173 		 && JIT_G(current_frame)->call
9174 		 && JIT_G(current_frame)->call->func) {
9175 			if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9176 				/* Don't generate code that always throws exception */
9177 				return 0;
9178 			}
9179 		} else {
9180 			ir_ref cond = ir_AND_U32(
9181 				ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9182 				ir_CONST_U32(mask));
9183 
9184 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9185 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9186 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9187 				if (!exit_addr) {
9188 					return 0;
9189 				}
9190 				ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9191 			} else {
9192 				ir_ref if_pass_by_ref;
9193 
9194 				if_pass_by_ref = ir_IF(cond);
9195 
9196 				ir_IF_TRUE_cold(if_pass_by_ref);
9197 				if (Z_MODE(op1_addr) == IS_REG) {
9198 					/* set type to avoid zval_ptr_dtor() on uninitialized value */
9199 					zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9200 					jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9201 				}
9202 				jit_SET_EX_OPLINE(jit, opline);
9203 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9204 
9205 				ir_IF_FALSE(if_pass_by_ref);
9206 			}
9207 		}
9208 	}
9209 
9210 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9211 
9212 	if (opline->op1_type == IS_CONST) {
9213 		zval *zv = RT_CONSTANT(opline, opline->op1);
9214 
9215 		jit_ZVAL_COPY_CONST(jit,
9216 			arg_addr,
9217 			MAY_BE_ANY, MAY_BE_ANY,
9218 			zv, 1);
9219 	} else {
9220 		jit_ZVAL_COPY(jit,
9221 			arg_addr,
9222 			MAY_BE_ANY,
9223 			op1_addr, op1_info, 0);
9224 	}
9225 
9226 	return 1;
9227 }
9228 
9229 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)
9230 {
9231 	zend_jit_addr op1_addr, arg_addr, ref_addr;
9232 	ir_ref ref_path = IR_UNUSED;
9233 
9234 	op1_addr = OP1_ADDR();
9235 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9236 
9237 	if (!zend_jit_reuse_ip(jit)) {
9238 		return 0;
9239 	}
9240 
9241 	if (opline->op1_type == IS_VAR) {
9242 		if (op1_info & MAY_BE_INDIRECT) {
9243 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9244 		}
9245 	} else if (opline->op1_type == IS_CV) {
9246 		if (op1_info & MAY_BE_UNDEF) {
9247 			if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9248 				// JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9249 				ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9250 				ir_IF_FALSE(if_def);
9251 				// JIT: ZVAL_NULL(op1)
9252 				jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9253 				ir_MERGE_WITH_EMPTY_TRUE(if_def);
9254 			}
9255 			op1_info &= ~MAY_BE_UNDEF;
9256 			op1_info |= MAY_BE_NULL;
9257 		}
9258 	} else {
9259 		ZEND_UNREACHABLE();
9260 	}
9261 
9262 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9263 		ir_ref ref, ref2;
9264 
9265 		if (op1_info & MAY_BE_REF) {
9266 			ir_ref if_ref;
9267 
9268 			// JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9269 			if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9270 			ir_IF_TRUE(if_ref);
9271 			// JIT: ref = Z_PTR_P(op1)
9272 			ref = jit_Z_PTR(jit, op1_addr);
9273 			// JIT: GC_ADDREF(ref)
9274 			jit_GC_ADDREF(jit, ref);
9275 			// JIT: ZVAL_REFERENCE(arg, ref)
9276 			jit_set_Z_PTR(jit, arg_addr, ref);
9277 			jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9278 			ref_path = ir_END();
9279 			ir_IF_FALSE(if_ref);
9280 		}
9281 
9282 		// JIT: ZVAL_NEW_REF(arg, varptr);
9283 		// JIT: ref = emalloc(sizeof(zend_reference));
9284 		ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9285 		// JIT: GC_REFCOUNT(ref) = 2
9286 		jit_set_GC_REFCOUNT(jit, ref, 2);
9287 		// JIT: GC_TYPE(ref) = GC_REFERENCE
9288 		ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, gc.u.type_info)), ir_CONST_U32(GC_REFERENCE));
9289 		ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr)), IR_NULL);
9290 		ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9291 		ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9292 
9293         // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9294 		jit_ZVAL_COPY(jit,
9295 			ref_addr,
9296 			MAY_BE_ANY,
9297 			op1_addr, op1_info, 0);
9298 
9299 		// JIT: ZVAL_REFERENCE(arg, ref)
9300 		jit_set_Z_PTR(jit, op1_addr, ref);
9301 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9302 
9303 		// JIT: ZVAL_REFERENCE(arg, ref)
9304 		jit_set_Z_PTR(jit, arg_addr, ref);
9305 		jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9306 	}
9307 
9308 	if (ref_path) {
9309 		ir_MERGE_WITH(ref_path);
9310 	}
9311 
9312 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9313 
9314 	return 1;
9315 }
9316 
9317 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)
9318 {
9319 	uint32_t arg_num = opline->op2.num;
9320 	zend_jit_addr arg_addr;
9321 	ir_ref end_inputs = IR_UNUSED;
9322 
9323 	ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9324 	     opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9325 	    arg_num <= MAX_ARG_FLAG_NUM);
9326 
9327 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9328 
9329 	if (!zend_jit_reuse_ip(jit)) {
9330 		return 0;
9331 	}
9332 
9333 	if (opline->opcode == ZEND_SEND_VAR_EX) {
9334 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9335 		 && JIT_G(current_frame)
9336 		 && JIT_G(current_frame)->call
9337 		 && JIT_G(current_frame)->call->func) {
9338 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9339 				if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9340 					return 0;
9341 				}
9342 				return 1;
9343 			}
9344 		} else {
9345 			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9346 
9347 			// JIT: if (RX->func->quick_arg_flags & mask)
9348 			ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9349 				ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9350 				ir_CONST_U32(mask)));
9351 			ir_IF_TRUE_cold(if_send_by_ref);
9352 
9353 			if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9354 				return 0;
9355 			}
9356 
9357 			ir_END_list(end_inputs);
9358 			ir_IF_FALSE(if_send_by_ref);
9359 		}
9360 	} else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9361 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9362 		 && JIT_G(current_frame)
9363 		 && JIT_G(current_frame)->call
9364 		 && JIT_G(current_frame)->call->func) {
9365 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9366 
9367 		        // JIT: ZVAL_COPY_VALUE(arg, op1)
9368 				jit_ZVAL_COPY(jit,
9369 					arg_addr,
9370 					MAY_BE_ANY,
9371 					op1_addr, op1_info, 0);
9372 
9373 				if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9374 					if (!(op1_info & MAY_BE_REF)) {
9375 						/* Don't generate code that always throws exception */
9376 						return 0;
9377 					} else {
9378 						int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9379 						const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9380 						if (!exit_addr) {
9381 							return 0;
9382 						}
9383 
9384 						// JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9385 						ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9386 							ir_CONST_ADDR(exit_addr));
9387 					}
9388 				}
9389 				return 1;
9390 			}
9391 		} else {
9392 			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9393 			ir_ref func, if_send_by_ref, if_prefer_ref;
9394 
9395 			// JIT: if (RX->func->quick_arg_flags & mask)
9396 			func = ir_LOAD_A(jit_RX(func));
9397 			if_send_by_ref = ir_IF(ir_AND_U32(
9398 				ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9399 				ir_CONST_U32(mask)));
9400 			ir_IF_TRUE_cold(if_send_by_ref);
9401 
9402 			mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9403 
9404 	        // JIT: ZVAL_COPY_VALUE(arg, op1)
9405 			jit_ZVAL_COPY(jit,
9406 				arg_addr,
9407 				MAY_BE_ANY,
9408 				op1_addr, op1_info, 0);
9409 
9410 			if (op1_info & MAY_BE_REF) {
9411 				ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9412 				ir_IF_TRUE(if_ref);
9413 				ir_END_list(end_inputs);
9414 				ir_IF_FALSE(if_ref);
9415 			}
9416 
9417 			// JIT: if (RX->func->quick_arg_flags & mask)
9418 			if_prefer_ref = ir_IF(ir_AND_U32(
9419 				ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9420 				ir_CONST_U32(mask)));
9421 			ir_IF_TRUE(if_prefer_ref);
9422 			ir_END_list(end_inputs);
9423 			ir_IF_FALSE(if_prefer_ref);
9424 
9425 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9426 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9427 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9428 				if (!exit_addr) {
9429 					return 0;
9430 				}
9431 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9432 			} else {
9433 				jit_SET_EX_OPLINE(jit, opline);
9434 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9435 					jit_ZVAL_ADDR(jit, arg_addr));
9436 				zend_jit_check_exception(jit);
9437 				ir_END_list(end_inputs);
9438 			}
9439 
9440 			ir_IF_FALSE(if_send_by_ref);
9441 		}
9442 	} else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9443 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9444 		 && JIT_G(current_frame)
9445 		 && JIT_G(current_frame)->call
9446 		 && JIT_G(current_frame)->call->func) {
9447 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9448 				if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9449 					return 0;
9450 				}
9451 				return 1;
9452 			}
9453 		} else {
9454 			// JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9455 			ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9456 				ir_LOAD_U32(jit_RX(This.u1.type_info)),
9457 				ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9458 			ir_IF_TRUE_cold(if_send_by_ref);
9459 
9460 			if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9461 				return 0;
9462 			}
9463 
9464 			ir_END_list(end_inputs);
9465 			ir_IF_FALSE(if_send_by_ref);
9466 		}
9467 	}
9468 
9469 	if (op1_info & MAY_BE_UNDEF) {
9470 		ir_ref ref, if_def = IR_UNUSED;
9471 
9472 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9473 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9474 			ir_IF_FALSE_cold(if_def);
9475 		}
9476 
9477 		// JIT: zend_jit_undefined_op_helper(opline->op1.var)
9478 		jit_SET_EX_OPLINE(jit, opline);
9479 		ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9480 			ir_CONST_U32(opline->op1.var));
9481 
9482 		// JIT: ZVAL_NULL(arg)
9483 		jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9484 
9485 		// JIT: check_exception
9486 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9487 
9488 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9489 			ir_END_list(end_inputs);
9490 			ir_IF_TRUE(if_def);
9491 		} else {
9492 			if (end_inputs) {
9493 				ir_END_list(end_inputs);
9494 				ir_MERGE_list(end_inputs);
9495 			}
9496 			return 1;
9497 		}
9498 	}
9499 
9500 	if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9501         // JIT: ZVAL_COPY_VALUE(arg, op1)
9502 		jit_ZVAL_COPY(jit,
9503 			arg_addr,
9504 			MAY_BE_ANY,
9505 			op1_addr, op1_info, 0);
9506 		if (op1_info & MAY_BE_REF) {
9507 				// JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9508 				ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9509 				ir_IF_TRUE(if_ref);
9510 				ir_END_list(end_inputs);
9511 				ir_IF_FALSE(if_ref);
9512 		}
9513 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9514 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9515 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9516 			if (!exit_addr) {
9517 				return 0;
9518 			}
9519 			ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9520 		} else {
9521 			jit_SET_EX_OPLINE(jit, opline);
9522 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9523 				jit_ZVAL_ADDR(jit, arg_addr));
9524 			zend_jit_check_exception(jit);
9525 		}
9526 	} else {
9527 		if (op1_info & MAY_BE_REF) {
9528 			if (opline->op1_type == IS_CV) {
9529 				ir_ref ref;
9530 
9531 				// JIT: ZVAL_DEREF(op1)
9532 				ref = jit_ZVAL_ADDR(jit, op1_addr);
9533 				ref = jit_ZVAL_DEREF_ref(jit, ref);
9534 				op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9535 
9536 		        // JIT: ZVAL_COPY(arg, op1)
9537 				jit_ZVAL_COPY(jit,
9538 					arg_addr,
9539 					MAY_BE_ANY,
9540 					op1_addr, op1_info, 1);
9541 			} else {
9542 				ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9543 				zend_jit_addr ref_addr;
9544 
9545 				// JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9546 				if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9547 				ir_IF_TRUE_cold(if_ref);
9548 
9549 				// JIT: ref = Z_COUNTED_P(op1);
9550 				ref = jit_Z_PTR(jit, op1_addr);
9551 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9552 				ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9553 
9554 				// JIT: ZVAL_COPY_VALUE(arg, op1);
9555 				jit_ZVAL_COPY(jit,
9556 					arg_addr,
9557 					MAY_BE_ANY,
9558 					ref_addr, op1_info, 0);
9559 
9560 				// JIT: if (GC_DELREF(ref) != 0)
9561 				refcount = jit_GC_DELREF(jit, ref);
9562 				if_not_zero = ir_IF(refcount);
9563 				ir_IF_TRUE(if_not_zero);
9564 
9565                 // JIT: if (Z_REFCOUNTED_P(arg)
9566 				if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9567 				ir_IF_TRUE(if_refcounted);
9568 				// JIT: Z_ADDREF_P(arg)
9569 				jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9570 				ir_END_list(end_inputs);
9571 				ir_IF_FALSE(if_refcounted);
9572 				ir_END_list(end_inputs);
9573 
9574 				ir_IF_FALSE(if_not_zero);
9575 
9576 				// JIT: efree(ref)
9577 				jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9578 				ir_END_list(end_inputs);
9579 
9580 				ir_IF_FALSE(if_ref);
9581 
9582 				// JIT: ZVAL_COPY_VALUE(arg, op1);
9583 				jit_ZVAL_COPY(jit,
9584 					arg_addr,
9585 					MAY_BE_ANY,
9586 					op1_addr, op1_info, 0);
9587 			}
9588 		} else {
9589 			if (op1_addr != op1_def_addr) {
9590 				if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9591 					return 0;
9592 				}
9593 				if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9594 					op1_addr = op1_def_addr;
9595 				}
9596 			}
9597 
9598 	        // JIT: ZVAL_COPY_VALUE(arg, op1)
9599 			jit_ZVAL_COPY(jit,
9600 				arg_addr,
9601 				MAY_BE_ANY,
9602 				op1_addr, op1_info, opline->op1_type == IS_CV);
9603 		}
9604 	}
9605 
9606 	if (end_inputs) {
9607 		ir_END_list(end_inputs);
9608 		ir_MERGE_list(end_inputs);
9609 	}
9610 
9611 	return 1;
9612 }
9613 
9614 static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
9615 {
9616 	uint32_t arg_num = opline->op2.num;
9617 	ir_ref ref;
9618 
9619 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9620 	 && JIT_G(current_frame)
9621 	 && JIT_G(current_frame)->call
9622 	 && JIT_G(current_frame)->call->func) {
9623 		if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9624 			if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
9625 				TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
9626 				// JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9627 				if (jit->reuse_ip) {
9628 					ref = jit_IP(jit);
9629 				} else {
9630 					ref = ir_LOAD_A(jit_EX(call));
9631 				}
9632 				ref = jit_CALL(ref, This.u1.type_info);
9633 				ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9634 			}
9635 		} else {
9636 			if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
9637 				TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
9638 				// JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9639 				if (jit->reuse_ip) {
9640 					ref = jit_IP(jit);
9641 				} else {
9642 					ref = ir_LOAD_A(jit_EX(call));
9643 				}
9644 				ref = jit_CALL(ref, This.u1.type_info);
9645 				ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9646 			}
9647 		}
9648 	} else {
9649 		// JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
9650 		uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9651 		ir_ref rx, if_ref, cold_path;
9652 
9653 		if (!zend_jit_reuse_ip(jit)) {
9654 			return 0;
9655 		}
9656 
9657 		rx = jit_IP(jit);
9658 
9659 		ref = ir_AND_U32(
9660 			ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_function, quick_arg_flags))),
9661 			ir_CONST_U32(mask));
9662 		if_ref = ir_IF(ref);
9663 		ir_IF_TRUE_cold(if_ref);
9664 
9665 		// JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9666 		ref = jit_CALL(rx, This.u1.type_info);
9667 		ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9668 
9669 		cold_path = ir_END();
9670 		ir_IF_FALSE(if_ref);
9671 
9672 		// JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9673 		ref = jit_CALL(rx, This.u1.type_info);
9674 		ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9675 
9676 		ir_MERGE_WITH(cold_path);
9677 	}
9678 
9679 	return 1;
9680 }
9681 
9682 static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
9683 {
9684 	ir_ref call, if_may_have_undef, ret;
9685 
9686 	if (jit->reuse_ip) {
9687 		call = jit_IP(jit);
9688 	} else {
9689 		call = ir_LOAD_A(jit_EX(call));
9690 	}
9691 
9692 	if_may_have_undef = ir_IF(ir_AND_U8(
9693 		ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
9694 		ir_CONST_U8(ZEND_CALL_MAY_HAVE_UNDEF >> 24)));
9695 
9696 	ir_IF_TRUE_cold(if_may_have_undef);
9697 	jit_SET_EX_OPLINE(jit, opline);
9698 	ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_handle_undef_args), call);
9699 	ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9700 	ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
9701 
9702 	return 1;
9703 }
9704 
9705 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)
9706 {
9707 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
9708 	zend_call_info *call_info = NULL;
9709 	const zend_function *func = NULL;
9710 	uint32_t i;
9711 	uint32_t call_num_args = 0;
9712 	bool unknown_num_args = 0;
9713 	const void *exit_addr = NULL;
9714 	const zend_op *prev_opline;
9715 	ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
9716 
9717 	prev_opline = opline - 1;
9718 	while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
9719 		prev_opline--;
9720 	}
9721 	if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
9722 			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
9723 		unknown_num_args = 1;
9724 	}
9725 
9726 	if (info) {
9727 		call_info = info->callee_info;
9728 		while (call_info && call_info->caller_call_opline != opline) {
9729 			call_info = call_info->next_callee;
9730 		}
9731 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
9732 			func = call_info->callee_func;
9733 		}
9734 		if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
9735 		 && JIT_G(current_frame)
9736 		 && JIT_G(current_frame)->call
9737 		 && !JIT_G(current_frame)->call->func) {
9738 			call_info = NULL; func = NULL; /* megamorphic call from trait */
9739 		}
9740 	}
9741 	if (!func) {
9742 		/* resolve function at run time */
9743 	} else if (func->type == ZEND_USER_FUNCTION) {
9744 		ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
9745 		call_num_args = call_info->num_args;
9746 	} else if (func->type == ZEND_INTERNAL_FUNCTION) {
9747 		ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
9748 		call_num_args = call_info->num_args;
9749 	} else {
9750 		ZEND_UNREACHABLE();
9751 	}
9752 
9753 	if (trace && !func) {
9754 		if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
9755 			ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION);
9756 #ifndef ZEND_WIN32
9757 			// TODO: ASLR may cause different addresses in different workers ???
9758 			func = trace->func;
9759 			if (JIT_G(current_frame) &&
9760 			    JIT_G(current_frame)->call &&
9761 			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9762 				call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9763 			} else {
9764 				unknown_num_args = 1;
9765 			}
9766 #endif
9767 		} else if (trace->op == ZEND_JIT_TRACE_ENTER) {
9768 			ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
9769 			if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
9770 				func = trace->func;
9771 				if (JIT_G(current_frame) &&
9772 				    JIT_G(current_frame)->call &&
9773 				    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9774 					call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9775 				} else {
9776 					unknown_num_args = 1;
9777 				}
9778 			}
9779 		}
9780 	}
9781 
9782 	bool may_have_extra_named_params =
9783 		opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS &&
9784 		(!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
9785 
9786 	if (!jit->reuse_ip) {
9787 		zend_jit_start_reuse_ip(jit);
9788 		// JIT: call = EX(call);
9789 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
9790 	}
9791 	rx = jit_IP(jit);
9792 	zend_jit_stop_reuse_ip(jit);
9793 
9794 	jit_SET_EX_OPLINE(jit, opline);
9795 
9796 	if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
9797 		if (!func) {
9798 			if (trace) {
9799 				uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9800 
9801 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9802 				if (!exit_addr) {
9803 					return 0;
9804 				}
9805 
9806 				func_ref = ir_LOAD_A(jit_CALL(rx, func));
9807 				ir_GUARD_NOT(
9808 					ir_AND_U32(
9809 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
9810 						ir_CONST_U32(ZEND_ACC_DEPRECATED)),
9811 					ir_CONST_ADDR(exit_addr));
9812 			}
9813 		}
9814 	}
9815 
9816 	if (!jit->delayed_call_level) {
9817 		// JIT: EX(call) = call->prev_execute_data;
9818 		ir_STORE(jit_EX(call),
9819 			(call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
9820 	}
9821 	delayed_call_chain = 0;
9822 	jit->delayed_call_level = 0;
9823 
9824 	// JIT: call->prev_execute_data = execute_data;
9825 	ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
9826 
9827 	if (!func) {
9828 		if (!func_ref) {
9829 			func_ref = ir_LOAD_A(jit_CALL(rx, func));
9830 		}
9831 	}
9832 
9833 	if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
9834 		if (!func) {
9835 			if (!trace) {
9836 				ir_ref if_deprecated, ret;
9837 
9838 				if_deprecated = ir_IF(ir_AND_U32(
9839 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
9840 						ir_CONST_U32(ZEND_ACC_DEPRECATED)));
9841 				ir_IF_TRUE_cold(if_deprecated);
9842 
9843 				if (GCC_GLOBAL_REGS) {
9844 					ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
9845 				} else {
9846 					ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
9847 				}
9848 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9849 				ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
9850 			}
9851 		} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
9852 			ir_ref ret;
9853 
9854 			if (GCC_GLOBAL_REGS) {
9855 				ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
9856 			} else {
9857 				ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
9858 			}
9859 			ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9860 		}
9861 	}
9862 
9863 	if (!func
9864 	 && opline->opcode != ZEND_DO_UCALL
9865 	 && opline->opcode != ZEND_DO_ICALL) {
9866 		ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
9867 		if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
9868 		ir_IF_TRUE(if_user);
9869 	}
9870 
9871 	if ((!func || func->type == ZEND_USER_FUNCTION)
9872 	 && opline->opcode != ZEND_DO_ICALL) {
9873 		bool recursive_call_through_jmp = 0;
9874 
9875 		// JIT: EX(call) = NULL;
9876 		ir_STORE(jit_CALL(rx, call), IR_NULL);
9877 
9878 		// JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
9879 		ir_STORE(jit_CALL(rx, return_value),
9880 			RETURN_VALUE_USED(opline) ?
9881 				jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
9882 				IR_NULL);
9883 
9884 		// JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
9885 		if (!func || func->op_array.cache_size) {
9886 			ir_ref run_time_cache;
9887 
9888 			if (func && op_array == &func->op_array) {
9889 				/* recursive call */
9890 				run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
9891 			} else if (func
9892 			 && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
9893 			 && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
9894 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
9895 					(uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
9896 			} else if ((func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) ||
9897 					(JIT_G(current_frame) &&
9898 					 JIT_G(current_frame)->call &&
9899 					 TRACE_FRAME_IS_CLOSURE_CALL(JIT_G(current_frame)->call))) {
9900 				/* Closures always use direct pointers */
9901 				ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
9902 
9903 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
9904 			} else {
9905 				ir_ref if_odd, run_time_cache2;
9906 				ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
9907 
9908 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
9909 				if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
9910 				ir_IF_TRUE(if_odd);
9911 
9912 				run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
9913 
9914 				ir_MERGE_WITH_EMPTY_FALSE(if_odd);
9915 				run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
9916 			}
9917 
9918 			ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
9919 		}
9920 
9921 		// JIT: EG(current_execute_data) = execute_data = call;
9922 		ir_STORE(jit_EG(current_execute_data), rx);
9923 		jit_STORE_FP(jit, rx);
9924 
9925 		// JIT: opline = op_array->opcodes;
9926 		if (func && !unknown_num_args) {
9927 
9928 			for (i = call_num_args; i < func->op_array.last_var; i++) {
9929 				uint32_t n = EX_NUM_TO_VAR(i);
9930 				zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
9931 
9932 				jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
9933 			}
9934 
9935 			if (call_num_args <= func->op_array.num_args) {
9936 				if (!trace || (trace->op == ZEND_JIT_TRACE_END
9937 				 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
9938 					uint32_t num_args;
9939 
9940 					if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
9941 						if (trace) {
9942 							num_args = 0;
9943 						} else if (call_info) {
9944 							num_args = skip_valid_arguments(op_array, ssa, call_info);
9945 						} else {
9946 							num_args = call_num_args;
9947 						}
9948 					} else {
9949 						num_args = call_num_args;
9950 					}
9951 					if (zend_accel_in_shm(func->op_array.opcodes)) {
9952 						jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
9953 					} else {
9954 						if (!func_ref) {
9955 							func_ref = ir_LOAD_A(jit_CALL(rx, func));
9956 						}
9957 						ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
9958 						if (num_args) {
9959 							ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
9960 						}
9961 						jit_LOAD_IP(jit, ip);
9962 					}
9963 
9964 					if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
9965 						/* recursive call */
9966 						recursive_call_through_jmp = 1;
9967 					}
9968 				}
9969 			} else {
9970 				if (!trace || (trace->op == ZEND_JIT_TRACE_END
9971 				 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
9972 					ir_ref ip;
9973 
9974 					if (zend_accel_in_shm(func->op_array.opcodes)) {
9975 						ip = ir_CONST_ADDR(func->op_array.opcodes);
9976 					} else {
9977 						if (!func_ref) {
9978 							func_ref = ir_LOAD_A(jit_CALL(rx, func));
9979 						}
9980 						ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
9981 					}
9982 					jit_LOAD_IP(jit, ip);
9983 				}
9984 				if (GCC_GLOBAL_REGS) {
9985 					ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
9986 				} else {
9987 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
9988 				}
9989 			}
9990 		} else {
9991 			ir_ref ip;
9992 			ir_ref merge_inputs = IR_UNUSED;
9993 
9994 			// JIT: opline = op_array->opcodes
9995 			if (func && zend_accel_in_shm(func->op_array.opcodes)) {
9996 				ip = ir_CONST_ADDR(func->op_array.opcodes);
9997 			} else {
9998 				if (!func_ref) {
9999 					func_ref = ir_LOAD_A(jit_CALL(rx, func));
10000 				}
10001 				ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10002 			}
10003 			jit_LOAD_IP(jit, ip);
10004 
10005 			// JIT: num_args = EX_NUM_ARGS();
10006 			ir_ref num_args, first_extra_arg;
10007 
10008 			num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
10009 			if (func) {
10010 				first_extra_arg = ir_CONST_U32(func->op_array.num_args);
10011 			} else {
10012 				// JIT: first_extra_arg = op_array->num_args;
10013 				ZEND_ASSERT(func_ref);
10014 				first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
10015 			}
10016 
10017 			// JIT: if (UNEXPECTED(num_args > first_extra_arg))
10018 			ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
10019 			ir_IF_TRUE_cold(if_extra_args);
10020 			if (GCC_GLOBAL_REGS) {
10021 				ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10022 			} else {
10023 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
10024 			}
10025 			ir_END_list(merge_inputs);
10026 			ir_IF_FALSE(if_extra_args);
10027 			if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10028 				if (!func) {
10029 					// JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10030 					ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
10031 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10032 						ir_CONST_U32(ZEND_ACC_HAS_TYPE_HINTS)));
10033 					ir_IF_TRUE(if_has_type_hints);
10034 					ir_END_list(merge_inputs);
10035 					ir_IF_FALSE(if_has_type_hints);
10036 				}
10037 				// JIT: opline += num_args;
10038 
10039 				ir_ref ref = ir_MUL_U32(num_args, ir_CONST_U32(sizeof(zend_op)));
10040 
10041 				if (sizeof(void*) == 8) {
10042 					ref = ir_ZEXT_A(ref);
10043 				}
10044 
10045 				if (GCC_GLOBAL_REGS) {
10046 					jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10047 				} else {
10048 					ir_ref addr = jit_EX(opline);
10049 
10050 					ir_STORE(addr, ir_ADD_A(ir_LOAD_A(addr), ref));
10051 				}
10052 			}
10053 
10054 			ir_END_list(merge_inputs);
10055 			ir_MERGE_list(merge_inputs);
10056 
10057 			// JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10058 			ir_ref last_var;
10059 
10060 			if (func) {
10061 				last_var = ir_CONST_U32(func->op_array.last_var);
10062 			} else {
10063 				ZEND_ASSERT(func_ref);
10064 				last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10065 			}
10066 
10067 			ir_ref idx = ir_SUB_U32(last_var, num_args);
10068 			ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10069 			ir_IF_TRUE(if_need);
10070 
10071 			// JIT: zval *var = EX_VAR_NUM(num_args);
10072 			if (sizeof(void*) == 8) {
10073 				num_args = ir_ZEXT_A(num_args);
10074 			}
10075 			ir_ref var_ref = ir_ADD_OFFSET(
10076 				ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10077 				(ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10078 
10079 			ir_ref loop = ir_LOOP_BEGIN(ir_END());
10080 			var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10081 			idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10082 			ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10083 			ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10084 			ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10085 			ir_PHI_SET_OP(idx, 2, idx2);
10086 			ir_ref if_not_zero = ir_IF(idx2);
10087 			ir_IF_TRUE(if_not_zero);
10088 			ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10089 			ir_IF_FALSE(if_not_zero);
10090 			ir_MERGE_WITH_EMPTY_FALSE(if_need);
10091 		}
10092 
10093 		if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10094 			ir_ref observer_handler;
10095 			ir_ref rx = jit_FP(jit);
10096 			struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10097 			if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10098 				ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10099 				jit_SET_EX_OPLINE(jit, trace[1].opline);
10100 			} else if (GCC_GLOBAL_REGS) {
10101 				// EX(opline) = opline
10102 				ir_STORE(jit_EX(opline), jit_IP(jit));
10103 			}
10104 			jit_observer_fcall_begin(jit, rx, observer_handler);
10105 
10106 			if (trace) {
10107 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10108 
10109 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10110 				if (!exit_addr) {
10111 					return 0;
10112 				}
10113 			} else {
10114 				exit_addr = NULL;
10115 			}
10116 
10117 			zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr);
10118 
10119 			jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10120 		}
10121 
10122 		if (trace) {
10123 			if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10124 				user_path = ir_END();
10125 			}
10126 		} else {
10127 			zend_basic_block *bb;
10128 
10129 			do {
10130 				if (recursive_call_through_jmp) {
10131 					ir_ref begin, end;
10132 					ir_insn *insn;
10133 
10134 					/* attempt to convert direct recursive call into loop */
10135 					begin = jit->bb_start_ref[call_num_args];
10136 					ZEND_ASSERT(begin != IR_UNUSED);
10137 					insn = &jit->ctx.ir_base[begin];
10138 					if (insn->op == IR_BEGIN) {
10139 						end = ir_LOOP_END();
10140 						insn = &jit->ctx.ir_base[begin];
10141 						insn->op = IR_LOOP_BEGIN;
10142 						insn->inputs_count = 2;
10143 						insn->op2 = end;
10144 						break;
10145 					} else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10146 							&& insn->inputs_count == 2) {
10147 						end = ir_LOOP_END();
10148 						insn = &jit->ctx.ir_base[begin];
10149 						insn->op = IR_LOOP_BEGIN;
10150 						insn->inputs_count = 3;
10151 						insn->op3 = end;
10152 						break;
10153 					} else if (insn->op == IR_LOOP_BEGIN && insn->inputs_count == 3) {
10154 						ZEND_ASSERT(jit->ctx.ir_base[insn->op3].op == IR_LOOP_END);
10155 						jit->ctx.ir_base[insn->op3].op = IR_END;
10156 						ir_MERGE_2(insn->op3, ir_END());
10157 						end = ir_LOOP_END();
10158 						insn = &jit->ctx.ir_base[begin];
10159 						insn->op3 = end;
10160 						break;
10161 					}
10162 				}
10163 				/* fallback to indirect JMP or RETURN */
10164 				if (GCC_GLOBAL_REGS) {
10165 					ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10166 				} else {
10167 					ir_RETURN(ir_CONST_I32(1));
10168 				}
10169 			} while (0);
10170 
10171 			bb = &jit->ssa->cfg.blocks[jit->b];
10172 			if (bb->successors_count > 0) {
10173 				int succ;
10174 				ir_ref ref;
10175 
10176 				ZEND_ASSERT(bb->successors_count == 1);
10177 				succ = bb->successors[0];
10178 				/* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10179 				ref = jit->ctx.insns_count - 1;
10180 				ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10181 					|| jit->ctx.ir_base[ref].op == IR_RETURN
10182 					|| jit->ctx.ir_base[ref].op == IR_LOOP_END);
10183 				ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
10184 				ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10185 				if (func || (opline->opcode == ZEND_DO_UCALL)) {
10186 					_zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10187 					jit->b = -1;
10188 				} else {
10189 					user_path = ref;
10190 				}
10191 			}
10192 		}
10193 	}
10194 
10195 	if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10196 	 && (opline->opcode != ZEND_DO_UCALL)) {
10197 		if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10198 			ir_IF_FALSE(if_user);
10199 		}
10200 
10201 		// JIT: EG(current_execute_data) = execute_data;
10202 		ir_STORE(jit_EG(current_execute_data), rx);
10203 
10204 		bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10205 		if (may_have_observer) {
10206 			ir_ref observer_handler;
10207 			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)));
10208 			jit_observer_fcall_begin(jit, rx, observer_handler);
10209 			jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10210 		}
10211 
10212 		// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10213 		ir_ref res_addr = IR_UNUSED, func_ptr;
10214 
10215 		if (RETURN_VALUE_USED(opline)) {
10216 			res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10217 		} else {
10218 			/* CPU stack allocated temporary zval */
10219 			ir_ref ptr;
10220 
10221 			if (!jit->ctx.fixed_call_stack_size) {
10222 				// JIT: alloca(sizeof(void*));
10223 				ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10224 			} else {
10225 				ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10226 			}
10227 			res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10228 		}
10229 
10230 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10231 
10232 		zend_jit_reset_last_valid_opline(jit);
10233 
10234 		// JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10235 		ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10236 		if (zend_execute_internal) {
10237 			ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
10238 		} else {
10239 			if (func) {
10240 				func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10241 			} else {
10242 				func_ptr = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler)));
10243 #if defined(IR_TARGET_X86)
10244 				func_ptr = ir_CAST_FC_FUNC(func_ptr);
10245 #endif
10246 			}
10247 			ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10248 		}
10249 
10250 		if (may_have_observer) {
10251 			jit_observer_fcall_end(jit, rx, res_ref);
10252 		}
10253 
10254 		/* When zend_interrupt_function is set, it gets called while
10255 		 * the frame is still on top. This is less efficient than
10256 		 * doing it later once it's popped off. There is code further
10257 		 * down that handles when there isn't an interrupt function.
10258 		 */
10259 		if (zend_interrupt_function) {
10260 			// JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
10261 			ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
10262 			ir_IF_TRUE_cold(if_interrupt);
10263 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), rx);
10264 			ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
10265 		}
10266 
10267 		// JIT: EG(current_execute_data) = execute_data;
10268 		ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10269 
10270 		// JIT: zend_vm_stack_free_args(call);
10271 		if (func && !unknown_num_args) {
10272 			for (i = 0; i < call_num_args; i++ ) {
10273 				if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10274 					uint32_t offset = EX_NUM_TO_VAR(i);
10275 					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
10276 
10277 					jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, opline);
10278 				}
10279 			}
10280 		} else {
10281 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10282 		}
10283 
10284 		if (may_have_extra_named_params) {
10285 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10286 			ir_ref if_has_named = ir_IF(ir_AND_U8(
10287 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10288 				ir_CONST_U8(ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)));
10289 			ir_IF_TRUE_cold(if_has_named);
10290 
10291 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_extra_named_params),
10292 				ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10293 
10294 			ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10295 		}
10296 
10297 		if (opline->opcode == ZEND_DO_FCALL) {
10298 			// TODO: optimize ???
10299 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10300 			ir_ref if_release_this = ir_IF(ir_AND_U8(
10301 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10302 				ir_CONST_U8(ZEND_CALL_RELEASE_THIS >> 16)));
10303 			ir_IF_TRUE_cold(if_release_this);
10304 
10305 			// JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10306 			jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10307 
10308 			ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10309 		}
10310 
10311 
10312 		ir_ref allocated_path = IR_UNUSED;
10313 
10314 		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10315 		    !JIT_G(current_frame) ||
10316 		    !JIT_G(current_frame)->call ||
10317 		    !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10318 		    prev_opline->opcode == ZEND_SEND_UNPACK ||
10319 		    prev_opline->opcode == ZEND_SEND_ARRAY ||
10320 			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10321 
10322 			// JIT: zend_vm_stack_free_call_frame(call);
10323 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10324 			ir_ref if_allocated = ir_IF(ir_AND_U8(
10325 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10326 				ir_CONST_U8(ZEND_CALL_ALLOCATED >> 16)));
10327 			ir_IF_TRUE_cold(if_allocated);
10328 
10329 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10330 
10331 			allocated_path = ir_END();
10332 			ir_IF_FALSE(if_allocated);
10333 		}
10334 
10335 		ir_STORE(jit_EG(vm_stack_top), rx);
10336 
10337 		if (allocated_path) {
10338 			ir_MERGE_WITH(allocated_path);
10339 		}
10340 
10341 		if (!RETURN_VALUE_USED(opline)) {
10342 			zend_class_entry *ce;
10343 			bool ce_is_instanceof;
10344 			uint32_t func_info = call_info ?
10345 				zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10346 				(MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10347 
10348 			/* If an exception is thrown, the return_value may stay at the
10349 			 * original value of null. */
10350 			func_info |= MAY_BE_NULL;
10351 
10352 			if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10353 				ir_ref sp = ir_RLOAD_A(IR_REG_SP);
10354 				res_addr = ZEND_ADDR_REF_ZVAL(sp);
10355 				jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
10356 			}
10357 			if (!jit->ctx.fixed_call_stack_size) {
10358 				// JIT: revert alloca
10359 				ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10360 			}
10361 		}
10362 
10363 		// JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10364 		ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10365 			jit_STUB_ADDR(jit, jit_stub_icall_throw));
10366 
10367 		/* If there isn't a zend_interrupt_function, the timeout is
10368 		 * handled here because it's more efficient.
10369 		 */
10370 		if (!zend_interrupt_function) {
10371 			// TODO: Can we avoid checking for interrupts after each call ???
10372 			if (trace && jit->last_valid_opline != opline) {
10373 				int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10374 
10375 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10376 				if (!exit_addr) {
10377 					return 0;
10378 				}
10379 			} else {
10380 				exit_addr = NULL;
10381 			}
10382 
10383 			zend_jit_check_timeout(jit, opline + 1, exit_addr);
10384 		}
10385 
10386 		if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10387 			jit_LOAD_IP_ADDR(jit, opline + 1);
10388 		} else if (trace
10389 		 && trace->op == ZEND_JIT_TRACE_END
10390 		 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
10391 			jit_LOAD_IP_ADDR(jit, opline + 1);
10392 		}
10393 	}
10394 
10395 	if (user_path) {
10396 		ir_MERGE_WITH(user_path);
10397 	}
10398 
10399 	return 1;
10400 }
10401 
10402 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)
10403 {
10404 	ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10405 
10406 	ir_IF_FALSE(if_skip_constructor);
10407 
10408 	if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10409 		if (!zend_jit_tail_handler(jit, opline)) {
10410 			return 0;
10411 		}
10412 	} else {
10413 		if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10414 			return 0;
10415 		}
10416 	}
10417 
10418 	/* override predecessors of the next block */
10419 	ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10420 	if (!jit->ctx.control) {
10421 		ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10422 		ir_IF_TRUE(if_skip_constructor);
10423 		ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10424 		jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10425 	} else {
10426 		ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10427 		/* merge current control path with the true branch of constructor skip condition */
10428 		ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10429 		jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10430 
10431 		jit->b = -1;
10432 	}
10433 
10434 	return 1;
10435 }
10436 
10437 static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
10438 {
10439 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10440 	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10441 	ir_ref ref, fast_path = IR_UNUSED;
10442 
10443 	ref = jit_ZVAL_ADDR(jit, res_addr);
10444 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10445 	 && JIT_G(current_frame)
10446 	 && JIT_G(current_frame)->prev) {
10447 		zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10448 		uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10449 
10450 		if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10451 			return 1;
10452 		}
10453 	}
10454 
10455 	if (ZEND_ARG_SEND_MODE(arg_info)) {
10456 		if (opline->opcode == ZEND_RECV_INIT) {
10457 			ref = jit_ZVAL_DEREF_ref(jit, ref);
10458 		} else {
10459 			ref = jit_Z_PTR_ref(jit, ref);
10460 			ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
10461 		}
10462 	}
10463 
10464 	if (type_mask != 0) {
10465 		if (is_power_of_two(type_mask)) {
10466 			uint32_t type_code = concrete_type(type_mask);
10467 			ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10468 			ir_IF_TRUE(if_ok);
10469 			fast_path = ir_END();
10470 			ir_IF_FALSE_cold(if_ok);
10471 		} else {
10472 			ir_ref if_ok = ir_IF(ir_AND_U32(
10473 				ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10474 				ir_CONST_U32(type_mask)));
10475 			ir_IF_TRUE(if_ok);
10476 			fast_path = ir_END();
10477 			ir_IF_FALSE_cold(if_ok);
10478 		}
10479 	}
10480 
10481 	jit_SET_EX_OPLINE(jit, opline);
10482 	ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10483 		ref, ir_CONST_ADDR(arg_info));
10484 
10485 	if (check_exception) {
10486 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10487 	}
10488 
10489 	if (fast_path) {
10490 		ir_MERGE_WITH(fast_path);
10491 	}
10492 
10493 	return 1;
10494 }
10495 
10496 static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
10497 {
10498 	uint32_t arg_num = opline->op1.num;
10499 	zend_arg_info *arg_info = NULL;
10500 
10501 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10502 		if (EXPECTED(arg_num <= op_array->num_args)) {
10503 			arg_info = &op_array->arg_info[arg_num-1];
10504 		} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10505 			arg_info = &op_array->arg_info[op_array->num_args];
10506 		}
10507 		if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10508 			arg_info = NULL;
10509 		}
10510 	}
10511 
10512 	if (arg_info || (opline+1)->opcode != ZEND_RECV) {
10513 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10514 			if (!JIT_G(current_frame) ||
10515 			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
10516 			    arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10517 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10518 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10519 
10520 				if (!exit_addr) {
10521 					return 0;
10522 				}
10523 				ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
10524 					ir_CONST_ADDR(exit_addr));
10525 			}
10526 		} else {
10527 			ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10528 			ir_IF_FALSE_cold(if_ok);
10529 
10530 			jit_SET_EX_OPLINE(jit, opline);
10531 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_missing_arg_error), jit_FP(jit));
10532 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10533 			ir_IF_TRUE(if_ok);
10534 		}
10535 	}
10536 
10537 	if (arg_info) {
10538 		if (!zend_jit_verify_arg_type(jit, opline, arg_info, 1)) {
10539 			return 0;
10540 		}
10541 	}
10542 
10543 	return 1;
10544 }
10545 
10546 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)
10547 {
10548 	uint32_t arg_num = opline->op1.num;
10549 	zval *zv = RT_CONSTANT(opline, opline->op2);
10550 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10551 	ir_ref ref, if_fail, skip_path = IR_UNUSED;
10552 
10553 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10554 	 && JIT_G(current_frame)
10555 	 && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
10556 		if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10557 			jit_ZVAL_COPY_CONST(jit,
10558 				res_addr,
10559 				-1, -1,
10560 				zv, 1);
10561 		}
10562 	} else {
10563 		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10564 		    (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
10565 			ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10566 			ir_IF_TRUE(if_skip);
10567 			skip_path = ir_END();
10568 			ir_IF_FALSE(if_skip);
10569 		}
10570 		jit_ZVAL_COPY_CONST(jit,
10571 			res_addr,
10572 			-1, -1,
10573 			zv, 1);
10574 	}
10575 
10576 	if (Z_CONSTANT_P(zv)) {
10577 		jit_SET_EX_OPLINE(jit, opline);
10578 		ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zval_update_constant_ex),
10579 			jit_ZVAL_ADDR(jit, res_addr),
10580 			ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), offsetof(zend_op_array, scope))));
10581 
10582 		if_fail = ir_IF(ref);
10583 		ir_IF_TRUE_cold(if_fail);
10584 		jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, opline);
10585 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10586 		ir_IF_FALSE(if_fail);
10587 	}
10588 
10589 	if (skip_path) {
10590 		ir_MERGE_WITH(skip_path);
10591 	}
10592 
10593 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10594 		do {
10595 			zend_arg_info *arg_info;
10596 
10597 			if (arg_num <= op_array->num_args) {
10598 				arg_info = &op_array->arg_info[arg_num-1];
10599 			} else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
10600 				arg_info = &op_array->arg_info[op_array->num_args];
10601 			} else {
10602 				break;
10603 			}
10604 			if (!ZEND_TYPE_IS_SET(arg_info->type)) {
10605 				break;
10606 			}
10607 			if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw)) {
10608 				return 0;
10609 			}
10610 		} while (0);
10611 	}
10612 
10613 	return 1;
10614 }
10615 
10616 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)
10617 {
10618 	zend_arg_info *arg_info = &op_array->arg_info[-1];
10619 	ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
10620 	zend_jit_addr op1_addr = OP1_ADDR();
10621 	bool needs_slow_check = 1;
10622 	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10623 	ir_ref fast_path = IR_UNUSED;
10624 
10625 	if (type_mask != 0) {
10626 		if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
10627 			/* pass */
10628 		} else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
10629 			needs_slow_check = 0;
10630 		} else if (is_power_of_two(type_mask)) {
10631 			uint32_t type_code = concrete_type(type_mask);
10632 			ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
10633 
10634 			ir_IF_TRUE(if_ok);
10635 			fast_path = ir_END();
10636 			ir_IF_FALSE_cold(if_ok);
10637 		} else {
10638 			ir_ref if_ok = ir_IF(ir_AND_U32(
10639 				ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
10640 				ir_CONST_U32(type_mask)));
10641 
10642 			ir_IF_TRUE(if_ok);
10643 			fast_path = ir_END();
10644 			ir_IF_FALSE_cold(if_ok);
10645 		}
10646 	}
10647 	if (needs_slow_check) {
10648 		ir_ref ref;
10649 
10650 		jit_SET_EX_OPLINE(jit, opline);
10651 		ref = jit_ZVAL_ADDR(jit, op1_addr);
10652 		if (op1_info & MAY_BE_UNDEF) {
10653 			ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1);
10654 		}
10655 
10656 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
10657 			ref,
10658 			ir_LOAD_A(jit_EX(func)),
10659 			ir_CONST_ADDR(arg_info),
10660 			ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num));
10661 
10662 		zend_jit_check_exception(jit);
10663 
10664 		if (fast_path) {
10665 			ir_MERGE_WITH(fast_path);
10666 		}
10667 	}
10668 
10669 	return 1;
10670 }
10671 
10672 static int zend_jit_leave_frame(zend_jit_ctx *jit)
10673 {
10674 	// JIT: EG(current_execute_data) = EX(prev_execute_data);
10675 	ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10676 	return 1;
10677 }
10678 
10679 static int zend_jit_free_cvs(zend_jit_ctx *jit)
10680 {
10681 	// JIT: EG(current_execute_data) = EX(prev_execute_data);
10682 	ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10683 
10684 	// JIT: zend_free_compiled_variables(execute_data);
10685 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_compiled_variables), jit_FP(jit));
10686 	return 1;
10687 }
10688 
10689 static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
10690 {
10691 	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10692 		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
10693 
10694 		jit_ZVAL_PTR_DTOR(jit, var_addr, info, 1, NULL);
10695 	}
10696 	return 1;
10697 }
10698 
10699 static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
10700 {
10701 	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10702 		jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, opline);
10703 	}
10704 	return 1;
10705 }
10706 
10707 static int zend_jit_leave_func(zend_jit_ctx         *jit,
10708                                const zend_op_array  *op_array,
10709                                const zend_op        *opline,
10710                                uint32_t              op1_info,
10711                                bool             left_frame,
10712                                zend_jit_trace_rec   *trace,
10713                                zend_jit_trace_info  *trace_info,
10714                                int                   indirect_var_access,
10715                                int                   may_throw)
10716 {
10717 	bool may_be_top_frame =
10718 		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10719 		!JIT_G(current_frame) ||
10720 		!TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
10721 	bool may_need_call_helper =
10722 		indirect_var_access || /* may have symbol table */
10723 		!op_array->function_name || /* may have symbol table */
10724 		may_be_top_frame ||
10725 		(op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
10726 		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10727 		!JIT_G(current_frame) ||
10728 		TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
10729 		(uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
10730 	bool may_need_release_this =
10731 		!(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
10732 		op_array->scope &&
10733 		!(op_array->fn_flags & ZEND_ACC_STATIC) &&
10734 		(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10735 		 !JIT_G(current_frame) ||
10736 		 !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
10737 	ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
10738 
10739 	if (may_need_call_helper) {
10740 		if (!left_frame) {
10741 			left_frame = 1;
10742 		    if (!zend_jit_leave_frame(jit)) {
10743 				return 0;
10744 		    }
10745 		}
10746 		/* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
10747 		call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10748 		ref = ir_AND_U32(call_info,
10749 			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));
10750 		if (trace && trace->op != ZEND_JIT_TRACE_END) {
10751 			ir_ref if_slow = ir_IF(ref);
10752 
10753 			ir_IF_TRUE_cold(if_slow);
10754 			if (!GCC_GLOBAL_REGS) {
10755 				ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit));
10756 			} else {
10757 				ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper));
10758 			}
10759 
10760 			if (may_be_top_frame) {
10761 				// TODO: try to avoid this check ???
10762 				if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
10763 #if 0
10764 					/* this check should be handled by the following OPLINE guard */
10765 					|	cmp IP, zend_jit_halt_op
10766 					|	je ->trace_halt
10767 #endif
10768 				} else if (GCC_GLOBAL_REGS) {
10769 					ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10770 				} else {
10771 					ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10772 				}
10773 			}
10774 
10775 			if (!GCC_GLOBAL_REGS) {
10776 				// execute_data = EG(current_execute_data)
10777 				jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
10778 			}
10779 			cold_path = ir_END();
10780 			ir_IF_FALSE(if_slow);
10781 		} else {
10782 			ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
10783 		}
10784 	}
10785 
10786 	if ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
10787 		if (!left_frame) {
10788 			left_frame = 1;
10789 		    if (!zend_jit_leave_frame(jit)) {
10790 				return 0;
10791 		    }
10792 		}
10793 		// JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
10794 		jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
10795 	} else if (may_need_release_this) {
10796 		ir_ref if_release, fast_path = IR_UNUSED;
10797 
10798 		if (!left_frame) {
10799 			left_frame = 1;
10800 		    if (!zend_jit_leave_frame(jit)) {
10801 				return 0;
10802 		    }
10803 		}
10804 		if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
10805 			// JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
10806 			if (!call_info) {
10807 				call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10808 			}
10809 			if_release = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_RELEASE_THIS)));
10810 			ir_IF_FALSE(if_release);
10811 			fast_path = ir_END();
10812 			ir_IF_TRUE(if_release);
10813 		}
10814 		// JIT: OBJ_RELEASE(execute_data->This))
10815 		jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
10816 		if (fast_path) {
10817 			ir_MERGE_WITH(fast_path);
10818 		}
10819 		// TODO: avoid EG(excption) check for $this->foo() calls
10820 		may_throw = 1;
10821 	}
10822 
10823 	// JIT: EG(vm_stack_top) = (zval*)execute_data
10824 	ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
10825 
10826 	// JITL execute_data = EX(prev_execute_data)
10827 	jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
10828 
10829 	if (!left_frame) {
10830 		// JIT: EG(current_execute_data) = execute_data
10831 		ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10832 	}
10833 
10834 	if (trace) {
10835 		if (trace->op != ZEND_JIT_TRACE_END
10836 		 && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
10837 			zend_jit_reset_last_valid_opline(jit);
10838 		} else {
10839 			if (GCC_GLOBAL_REGS) {
10840 				/* We add extra RLOAD and RSTORE to make fusion for persistent register
10841 				 *     mov (%FP), %IP
10842 				 *     add $0x1c, %IP
10843 				 * The naive (commented) code leads to extra register allocation and move.
10844 				 *     mov (%FP), %tmp
10845 				 *     add $0x1c, %tmp
10846 				 *     mov %tmp, %FP
10847 				 */
10848 #if 0
10849 				jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
10850 #else
10851 				jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
10852 				jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
10853 #endif
10854 			} else {
10855 				ir_ref ref = jit_EX(opline);
10856 
10857 				ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
10858 			}
10859 		}
10860 
10861 		if (cold_path) {
10862 			ir_MERGE_WITH(cold_path);
10863 		}
10864 
10865 		if (trace->op == ZEND_JIT_TRACE_BACK
10866 		 && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
10867 			const zend_op *next_opline = trace->opline;
10868 
10869 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
10870 			 && (op1_info & MAY_BE_RC1)
10871 			 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
10872 				/* exception might be thrown during destruction of unused return value */
10873 				// JIT: if (EG(exception))
10874 				ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
10875 			}
10876 			do {
10877 				trace++;
10878 			} while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
10879 			ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
10880 			next_opline = trace->opline;
10881 			ZEND_ASSERT(next_opline != NULL);
10882 
10883 			if (trace->op == ZEND_JIT_TRACE_END
10884 			 && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
10885 				trace_info->flags |= ZEND_JIT_TRACE_LOOP;
10886 
10887 				ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
10888 
10889 				ir_IF_TRUE(if_eq);
10890 				ZEND_ASSERT(jit->trace_loop_ref);
10891 				ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
10892 				ir_MERGE_SET_OP(jit->trace_loop_ref, 2, ir_END());
10893 				ir_IF_FALSE(if_eq);
10894 
10895 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
10896 				ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10897 #else
10898 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
10899 #endif
10900 			} else {
10901 				ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
10902 			}
10903 
10904 			zend_jit_set_last_valid_opline(jit, trace->opline);
10905 
10906 			return 1;
10907 		} else if (may_throw ||
10908 				(((opline->op1_type & (IS_VAR|IS_TMP_VAR))
10909 				  && (op1_info & MAY_BE_RC1)
10910 				  && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
10911 				 && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
10912 			// JIT: if (EG(exception))
10913 			ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
10914 		}
10915 
10916 		return 1;
10917 	} else {
10918 		// JIT: if (EG(exception))
10919 		ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
10920 		// JIT: opline = EX(opline) + 1
10921 		if (GCC_GLOBAL_REGS) {
10922 			jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
10923 			jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
10924 		} else {
10925 			ir_ref ref = jit_EX(opline);
10926 
10927 			ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
10928 		}
10929 	}
10930 
10931 	if (GCC_GLOBAL_REGS) {
10932 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10933 	} else {
10934 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
10935 	}
10936 
10937 	jit->b = -1;
10938 
10939 	return 1;
10940 }
10941 
10942 static void zend_jit_common_return(zend_jit_ctx *jit)
10943 {
10944 	ZEND_ASSERT(jit->return_inputs);
10945 	ir_MERGE_list(jit->return_inputs);
10946 }
10947 
10948 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)
10949 {
10950 	zend_jit_addr ret_addr;
10951 	int8_t return_value_used = -1;
10952 	ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
10953 
10954 	ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
10955 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
10956 
10957 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10958 		jit->return_inputs = IR_UNUSED;
10959 		if (JIT_G(current_frame)) {
10960 			if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
10961 				return_value_used = 1;
10962 			} else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
10963 				return_value_used = 0;
10964 			} else {
10965 				return_value_used = -1;
10966 			}
10967 		}
10968 	}
10969 
10970 	if (ZEND_OBSERVER_ENABLED) {
10971 		if (Z_MODE(op1_addr) == IS_REG) {
10972 			zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
10973 
10974 			if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
10975 				return 0;
10976 			}
10977 			op1_addr = dst;
10978 		}
10979 		jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
10980 	}
10981 
10982 	// JIT: if (!EX(return_value))
10983 	return_value = ir_LOAD_A(jit_EX(return_value));
10984 	ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
10985 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
10986 	    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
10987 		if (return_value_used == -1) {
10988 			if_return_value_used = ir_IF(return_value);
10989 			ir_IF_FALSE_cold(if_return_value_used);
10990 		}
10991 		if (return_value_used != 1) {
10992 			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
10993 				ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
10994 				ir_IF_FALSE(if_refcounted);
10995 				ir_END_list(jit->return_inputs);
10996 				ir_IF_TRUE(if_refcounted);
10997 			}
10998 			ref = jit_Z_PTR(jit, op1_addr);
10999 			refcount = jit_GC_DELREF(jit, ref);
11000 
11001 			if (RC_MAY_BE_1(op1_info)) {
11002 				if (RC_MAY_BE_N(op1_info)) {
11003 					ir_ref if_non_zero = ir_IF(refcount);
11004 					ir_IF_TRUE(if_non_zero);
11005 					ir_END_list(jit->return_inputs);
11006 					ir_IF_FALSE(if_non_zero);
11007 				}
11008 				jit_ZVAL_DTOR(jit, ref, op1_info, opline);
11009 			}
11010 			if (return_value_used == -1) {
11011 				ir_END_list(jit->return_inputs);
11012 			}
11013 		}
11014 	} else if (return_value_used == -1) {
11015 		if_return_value_used = ir_IF(return_value);
11016 		ir_IF_FALSE_cold(if_return_value_used);
11017 		ir_END_list(jit->return_inputs);
11018 	}
11019 
11020 	if (if_return_value_used) {
11021 		ir_IF_TRUE(if_return_value_used);
11022 	}
11023 
11024 	if (return_value_used == 0) {
11025 		if (jit->return_inputs) {
11026 			ZEND_ASSERT(JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE);
11027 			ir_END_list(jit->return_inputs);
11028 			ir_MERGE_list(jit->return_inputs);
11029 			jit->return_inputs = IR_UNUSED;
11030 		}
11031 		return 1;
11032 	}
11033 
11034 	if (opline->op1_type == IS_CONST) {
11035 		zval *zv = RT_CONSTANT(opline, opline->op1);
11036 
11037 		jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
11038 	} else if (opline->op1_type == IS_TMP_VAR) {
11039 		jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11040 	} else if (opline->op1_type == IS_CV) {
11041 		if (op1_info & MAY_BE_REF) {
11042 			ref = jit_ZVAL_ADDR(jit, op1_addr);
11043 			ref = jit_ZVAL_DEREF_ref(jit, ref);
11044 			op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11045 		}
11046 
11047 		if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11048 			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11049 			    (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11050 			    !op_array->function_name) {
11051 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 1);
11052 			} else if (return_value_used != 1) {
11053 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11054 				// JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11055 				jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11056 			} else {
11057 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11058 			}
11059 		} else {
11060 			jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11061 		}
11062 	} else {
11063 		if (op1_info & MAY_BE_REF) {
11064 			ir_ref if_ref, ref2, if_non_zero;
11065 			zend_jit_addr ref_addr;
11066 
11067 			if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11068 			ir_IF_TRUE_cold(if_ref);
11069 
11070 			// JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11071 			ref = jit_Z_PTR(jit, op1_addr);
11072 
11073 			// JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11074 			ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
11075 			ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11076 			jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, 0);
11077 			ref2 = jit_GC_DELREF(jit, ref);
11078 			if_non_zero = ir_IF(ref2);
11079 			ir_IF_TRUE(if_non_zero);
11080 
11081 			// JIT: if (IS_REFCOUNTED())
11082 			ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11083 			ir_IF_FALSE(if_refcounted);
11084 			ir_END_list(jit->return_inputs);
11085 			ir_IF_TRUE(if_refcounted);
11086 
11087 			// JIT: ADDREF
11088 			ref2 = jit_Z_PTR(jit, ret_addr);
11089 			jit_GC_ADDREF(jit, ref2);
11090 			ir_END_list(jit->return_inputs);
11091 
11092 			ir_IF_FALSE(if_non_zero);
11093 
11094 			jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11095 			ir_END_list(jit->return_inputs);
11096 
11097 			ir_IF_FALSE(if_ref);
11098 		}
11099 		jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11100 	}
11101 
11102 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11103 		if (jit->return_inputs) {
11104 			ir_END_list(jit->return_inputs);
11105 			ir_MERGE_list(jit->return_inputs);
11106 			jit->return_inputs = IR_UNUSED;
11107 		}
11108 	} else {
11109 		ir_END_list(jit->return_inputs);
11110 		jit->b = -1;
11111 	}
11112 
11113 	return 1;
11114 }
11115 
11116 static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11117 {
11118 	zend_jit_addr op1_addr = OP1_ADDR();
11119 	zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11120 	ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11121 	ir_ref if_fit, if_reference, if_same_key, fast_path;
11122 	ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11123 
11124 	// JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11125 	cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11126 	idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11127 
11128 	// JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11129 	num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11130 		ir_CONST_U32(sizeof(Bucket)));
11131 	if (sizeof(void*) == 8) {
11132 		num_used_ref = ir_ZEXT_A(num_used_ref);
11133 	}
11134 	if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11135 	ir_IF_FALSE_cold(if_fit);
11136 	ir_END_list(slow_inputs);
11137 	ir_IF_TRUE(if_fit);
11138 
11139 	// JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11140 	bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11141 	if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11142 	ir_IF_FALSE_cold(if_reference);
11143 	ir_END_list(slow_inputs);
11144 	ir_IF_TRUE(if_reference);
11145 
11146 	// JIT: (EXPECTED(p->key == varname))
11147 	if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11148 	ir_IF_FALSE_cold(if_same_key);
11149 	ir_END_list(slow_inputs);
11150 	ir_IF_TRUE(if_same_key);
11151 
11152 	// JIT: GC_ADDREF(Z_PTR(p->val))
11153 	ref = jit_Z_PTR_ref(jit, bucket_ref);
11154 	jit_GC_ADDREF(jit, ref);
11155 
11156 	fast_path = ir_END();
11157 	ir_MERGE_list(slow_inputs);
11158 
11159 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11160 		ir_CONST_ADDR(varname),
11161 		cache_slot_ref);
11162 
11163 	ir_MERGE_WITH(fast_path);
11164 	ref = ir_PHI_2(IR_ADDR, ref2, ref);
11165 
11166 	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11167 		ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11168 
11169 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11170 			// JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11171 			if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11172 			ir_IF_TRUE_cold(if_refcounted);
11173 		}
11174 
11175 		// JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11176 		ref2 = jit_Z_PTR(jit, op1_addr);
11177 
11178 		// JIT: ZVAL_REF(variable_ptr, ref)
11179 		jit_set_Z_PTR(jit, op1_addr, ref);
11180 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11181 
11182 		// JIT: if (GC_DELREF(garbage) == 0)
11183 		refcount = jit_GC_DELREF(jit, ref2);
11184 		if_non_zero = ir_IF(refcount);
11185 		if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11186 			ir_IF_TRUE(if_non_zero);
11187 			ir_END_list(end_inputs);
11188 		}
11189 		ir_IF_FALSE(if_non_zero);
11190 
11191 		jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11192 		if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11193 			ir_END_list(end_inputs);
11194 			ir_IF_TRUE(if_non_zero);
11195 
11196 			// JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11197 			if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11198 			ir_IF_TRUE(if_may_not_leak);
11199 			ir_END_list(end_inputs);
11200 			ir_IF_FALSE(if_may_not_leak);
11201 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref2);
11202 		}
11203 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11204 			ir_END_list(end_inputs);
11205 			ir_IF_FALSE(if_refcounted);
11206 		}
11207 	}
11208 
11209 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11210 		// JIT: ZVAL_REF(variable_ptr, ref)
11211 		jit_set_Z_PTR(jit, op1_addr, ref);
11212 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11213 	}
11214 
11215 	if (end_inputs) {
11216 		ir_END_list(end_inputs);
11217 		ir_MERGE_list(end_inputs);
11218 	}
11219 
11220 	return 1;
11221 }
11222 
11223 static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11224 {
11225 	zend_jit_addr op1_addr = OP1_ADDR();
11226 
11227 	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11228 		if (may_throw) {
11229 			jit_SET_EX_OPLINE(jit, opline);
11230 		}
11231 		if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11232 			ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11233 
11234 			if (op1_info & MAY_BE_ARRAY) {
11235 				if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11236 				ir_IF_TRUE(if_array);
11237 				ir_END_list(end_inputs);
11238 				ir_IF_FALSE(if_array);
11239 			}
11240 			ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11241 			if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11242 			ir_IF_TRUE(if_exists);
11243 			ir_END_list(end_inputs);
11244 			ir_IF_FALSE(if_exists);
11245 
11246 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_hash_iterator_del), ref);
11247 
11248 			ir_END_list(end_inputs);
11249 			ir_MERGE_list(end_inputs);
11250 		}
11251 
11252 		jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11253 
11254 		if (may_throw) {
11255 			zend_jit_check_exception(jit);
11256 		}
11257 	}
11258 
11259 	return 1;
11260 }
11261 
11262 static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11263 {
11264 	if (opline->op1_type == IS_CONST) {
11265 		zval *zv;
11266 		size_t len;
11267 
11268 		zv = RT_CONSTANT(opline, opline->op1);
11269 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11270 		len = Z_STRLEN_P(zv);
11271 
11272 		if (len > 0) {
11273 			const char *str = Z_STRVAL_P(zv);
11274 
11275 			jit_SET_EX_OPLINE(jit, opline);
11276 			ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11277 				ir_CONST_ADDR(str), ir_CONST_ADDR(len));
11278 
11279 			zend_jit_check_exception(jit);
11280 		}
11281 	} else {
11282 		zend_jit_addr op1_addr = OP1_ADDR();
11283 		ir_ref ref;
11284 
11285 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11286 
11287 		jit_SET_EX_OPLINE(jit, opline);
11288 
11289 		ref = jit_Z_PTR(jit, op1_addr);
11290 		ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11291 			ir_ADD_OFFSET(ref, offsetof(zend_string, val)),
11292 			ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_string, len))));
11293 
11294 		if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11295 			jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11296 		}
11297 
11298 		zend_jit_check_exception(jit);
11299 	}
11300 	return 1;
11301 }
11302 
11303 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)
11304 {
11305 	if (opline->op1_type == IS_CONST) {
11306 		zval *zv;
11307 		size_t len;
11308 
11309 		zv = RT_CONSTANT(opline, opline->op1);
11310 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11311 		len = Z_STRLEN_P(zv);
11312 
11313 		jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11314 		if (Z_MODE(res_addr) != IS_REG) {
11315 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11316 		} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11317 			return 0;
11318 		}
11319 	} else {
11320 		ir_ref ref;
11321 
11322 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11323 
11324 		ref = jit_Z_PTR(jit, op1_addr);
11325 		ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(zend_string, len)));
11326 		jit_set_Z_LVAL(jit, res_addr, ref);
11327 
11328 		if (Z_MODE(res_addr) == IS_REG) {
11329 			if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11330 				return 0;
11331 			}
11332 		} else {
11333 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11334 		}
11335 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11336 	}
11337 	return 1;
11338 }
11339 
11340 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)
11341 {
11342 	if (opline->op1_type == IS_CONST) {
11343 		zval *zv;
11344 		zend_long count;
11345 
11346 		zv = RT_CONSTANT(opline, opline->op1);
11347 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
11348 		count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11349 
11350 		jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11351 		if (Z_MODE(res_addr) != IS_REG) {
11352 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11353 		} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11354 			return 0;
11355 		}
11356 	} else {
11357 		ir_ref ref;
11358 
11359 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
11360 		// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11361 
11362 		ref = jit_Z_PTR(jit, op1_addr);
11363 		if (sizeof(void*) == 8) {
11364 			ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11365 			ref = ir_ZEXT_L(ref);
11366 		} else {
11367 			ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11368 		}
11369 		jit_set_Z_LVAL(jit, res_addr, ref);
11370 
11371 		if (Z_MODE(res_addr) == IS_REG) {
11372 			if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11373 				return 0;
11374 			}
11375 		} else {
11376 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11377 		}
11378 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11379 	}
11380 
11381 	if (may_throw) {
11382 		zend_jit_check_exception(jit);
11383 	}
11384 	return 1;
11385 }
11386 
11387 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)
11388 {
11389 	HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11390 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11391 	ir_ref ref;
11392 
11393 	ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11394 	ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
11395 
11396 	// JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11397 	if (opline->op1_type != IS_CONST) {
11398 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find),
11399 			ir_CONST_ADDR(ht),
11400 			jit_Z_PTR(jit, op1_addr));
11401 	} else {
11402 		zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11403 
11404 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash),
11405 			ir_CONST_ADDR(ht), ir_CONST_ADDR(str));
11406 	}
11407 
11408 	if (exit_addr) {
11409 		if (smart_branch_opcode == ZEND_JMPZ) {
11410 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11411 		} else {
11412 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11413 		}
11414 	} else if (smart_branch_opcode) {
11415 		zend_basic_block *bb;
11416 
11417 		ZEND_ASSERT(jit->b >= 0);
11418 		bb = &jit->ssa->cfg.blocks[jit->b];
11419 		ZEND_ASSERT(bb->successors_count == 2);
11420 		ref = jit_IF_ex(jit, ref,
11421 			(smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11422 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11423 		_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11424 		jit->b = -1;
11425 	} else {
11426 		jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11427 			ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, IR_NULL)), ir_CONST_U32(IS_FALSE)));
11428 	}
11429 
11430 	return 1;
11431 }
11432 
11433 static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11434 {
11435 	uint32_t offset;
11436 
11437 	offset = (opline->opcode == ZEND_ROPE_INIT) ?
11438 		opline->result.var :
11439 		opline->op1.var + opline->extended_value * sizeof(zend_string*);
11440 
11441 	if (opline->op2_type == IS_CONST) {
11442 		zval *zv = RT_CONSTANT(opline, opline->op2);
11443 		zend_string *str;
11444 
11445 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11446 		str = Z_STR_P(zv);
11447 
11448 		ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11449 	} else {
11450 		zend_jit_addr op2_addr = OP2_ADDR();
11451 		ir_ref ref;
11452 
11453 		ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11454 
11455 		ref = jit_Z_PTR(jit, op2_addr);
11456 		ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11457 		if (opline->op2_type == IS_CV) {
11458 			ir_ref if_refcounted, long_path;
11459 
11460 			if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11461 			ir_IF_TRUE(if_refcounted);
11462 			jit_GC_ADDREF(jit, ref);
11463 			long_path = ir_END();
11464 
11465 			ir_IF_FALSE(if_refcounted);
11466 			ir_MERGE_WITH(long_path);
11467 		}
11468 	}
11469 
11470 	if (opline->opcode == ZEND_ROPE_END) {
11471 		zend_jit_addr res_addr = RES_ADDR();
11472 		ir_ref ref;
11473 
11474 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11475 			ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11476 			ir_CONST_U32(opline->extended_value));
11477 
11478 		jit_set_Z_PTR(jit, res_addr, ref);
11479 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11480 	}
11481 
11482 	return 1;
11483 }
11484 
11485 static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
11486 {
11487 	ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
11488 	ir_refs *merge_inputs, *types, *ptrs;
11489 #if SIZEOF_ZEND_LONG == 4
11490 	ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
11491 	ir_refs *values; /* we need this only for zval.w2 copy */
11492 #endif
11493 
11494 	ir_refs_init(merge_inputs, 4);
11495 	ir_refs_init(types, 4);
11496 	ir_refs_init(ptrs, 4);
11497 #if SIZEOF_ZEND_LONG == 4
11498 	ir_refs_init(values, 4);
11499 #endif
11500 
11501 	// JIT: ptr = Z_PTR_P(val);
11502 	ptr = jit_Z_PTR(jit, val_addr);
11503 
11504 	// JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11505 	if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11506 	ir_IF_FALSE_cold(if_refcounted);
11507 	ir_refs_add(merge_inputs, ir_END());
11508 	ir_refs_add(types, type);
11509 	ir_refs_add(ptrs, ptr);
11510 #if SIZEOF_ZEND_LONG == 4
11511 	ir_refs_add(values, val);
11512 #endif
11513 
11514 	ir_IF_TRUE(if_refcounted);
11515 
11516 	// JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
11517 	if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
11518 //	if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
11519 	ir_IF_TRUE(if_reference);
11520 
11521 	// JIT:	val = Z_REFVAL_P(val);
11522 	val2 = ir_ADD_OFFSET(ptr, offsetof(zend_reference, val));
11523 	type2 = jit_Z_TYPE_INFO_ref(jit, val2);
11524 	ptr2 = jit_Z_PTR_ref(jit, val2);
11525 
11526 	// JIT:	if (Z_OPT_REFCOUNTED_P(val)) {
11527 	if_refcounted2 = ir_IF(ir_AND_U32(type2, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11528 	ir_IF_FALSE_cold(if_refcounted2);
11529 	ir_refs_add(merge_inputs, ir_END());
11530 	ir_refs_add(types, type2);
11531 	ir_refs_add(ptrs, ptr2);
11532 #if SIZEOF_ZEND_LONG == 4
11533 	ir_refs_add(values, val2);
11534 #endif
11535 
11536 	ir_IF_TRUE(if_refcounted2);
11537 	ir_MERGE_WITH_EMPTY_FALSE(if_reference);
11538 	type = ir_PHI_2(IR_U32, type2, type);
11539 	ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
11540 #if SIZEOF_ZEND_LONG == 4
11541 	val = ir_PHI_2(IR_ADDR, val2, val);
11542 #endif
11543 
11544 	// JIT:	Z_ADDREF_P(val);
11545 	jit_GC_ADDREF(jit, ptr);
11546 	ir_refs_add(merge_inputs, ir_END());
11547 	ir_refs_add(types, type);
11548 	ir_refs_add(ptrs, ptr);
11549 #if SIZEOF_ZEND_LONG == 4
11550 	ir_refs_add(values, val);
11551 #endif
11552 
11553 	ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
11554 	type = ir_PHI_N(IR_U32, types->count, types->refs);
11555 	ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
11556 #if SIZEOF_ZEND_LONG == 4
11557 	val = ir_PHI_N(IR_ADDR, values->count, values->refs);
11558 	val_addr = ZEND_ADDR_REF_ZVAL(val);
11559 #endif
11560 
11561 	// JIT: Z_PTR_P(res) = ptr;
11562 	jit_set_Z_PTR(jit, res_addr, ptr);
11563 #if SIZEOF_ZEND_LONG == 4
11564 	jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
11565 #endif
11566 	jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
11567 
11568 	return 1;
11569 }
11570 
11571 static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx  *jit,
11572                                                   const zend_op *opline,
11573                                                   uint32_t       type,
11574                                                   uint32_t       op1_info,
11575                                                   uint32_t       op2_info,
11576                                                   zend_jit_addr  op2_addr,
11577                                                   zend_ssa_range *op2_range,
11578                                                   uint8_t        dim_type,
11579                                                   const void    *found_exit_addr,
11580                                                   const void    *not_found_exit_addr,
11581                                                   const void    *exit_addr,
11582                                                   bool           result_type_guard,
11583                                                   ir_ref         ht_ref,
11584                                                   ir_refs       *found_inputs,
11585                                                   ir_refs       *found_vals,
11586                                                   ir_ref        *end_inputs,
11587                                                   ir_ref        *not_found_inputs)
11588 {
11589 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11590 	ir_ref ref = IR_UNUSED, cond, if_found;
11591 	ir_ref if_type = IS_UNUSED;
11592 	ir_refs *test_zval_inputs, *test_zval_values;
11593 
11594 	ir_refs_init(test_zval_inputs, 4);
11595 	ir_refs_init(test_zval_values, 4);
11596 
11597 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11598 	 && type == BP_VAR_R
11599 	 && !exit_addr) {
11600 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11601 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11602 		if (!exit_addr) {
11603 			return 0;
11604 		}
11605 	}
11606 
11607 	if (op2_info & MAY_BE_LONG) {
11608 		bool op2_loaded = 0;
11609 		bool packed_loaded = 0;
11610 		bool bad_packed_key = 0;
11611 		ir_ref if_packed = IS_UNDEF;
11612 		ir_ref h = IR_UNUSED;
11613 		ir_ref idx_not_found_inputs = IR_UNUSED;
11614 
11615 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
11616 			// JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
11617 			if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
11618 			ir_IF_TRUE(if_type);
11619 		}
11620 		if (op1_info & MAY_BE_PACKED_GUARD) {
11621 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
11622 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11623 
11624 			if (!exit_addr) {
11625 				return 0;
11626 			}
11627 			cond = ir_AND_U32(
11628 				ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11629 				ir_CONST_U32(HASH_FLAG_PACKED));
11630 			if (op1_info & MAY_BE_ARRAY_PACKED) {
11631 				ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11632 			} else {
11633 				ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
11634 			}
11635 		}
11636 		if (type == BP_VAR_W) {
11637 			// JIT: hval = Z_LVAL_P(dim);
11638 			h = jit_Z_LVAL(jit, op2_addr);
11639 			op2_loaded = 1;
11640 		}
11641 		if (op1_info & MAY_BE_ARRAY_PACKED) {
11642 			zend_long val = -1;
11643 
11644 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
11645 				val = Z_LVAL_P(Z_ZV(op2_addr));
11646 				if (val >= 0 && val < HT_MAX_SIZE) {
11647 					packed_loaded = 1;
11648 				} else {
11649 					bad_packed_key = 1;
11650 				}
11651 				h = ir_CONST_LONG(val);
11652 			} else {
11653 				if (!op2_loaded) {
11654 					// JIT: hval = Z_LVAL_P(dim);
11655 					h = jit_Z_LVAL(jit, op2_addr);
11656 					op2_loaded = 1;
11657 				}
11658 				packed_loaded = 1;
11659 			}
11660 
11661 			if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
11662 				/* don't generate "fast" code for packed array */
11663 				packed_loaded = 0;
11664 			}
11665 
11666 			if (packed_loaded) {
11667 				// JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
11668 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11669 					if_packed = ir_IF(
11670 						ir_AND_U32(
11671 							ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11672 							ir_CONST_U32(HASH_FLAG_PACKED)));
11673 					ir_IF_TRUE(if_packed);
11674 				}
11675 				// JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
11676 				ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
11677 #if SIZEOF_ZEND_LONG == 8
11678 				if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
11679 				 || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
11680 					/* comapre only the lower 32-bits to allow load fusion on x86_64 */
11681 					cond = ir_ULT(ir_TRUNC_U32(h), ref);
11682 				} else {
11683 					cond = ir_ULT(h, ir_ZEXT_L(ref));
11684 				}
11685 #else
11686 				cond = ir_ULT(h, ref);
11687 #endif
11688 				if (type == BP_JIT_IS) {
11689 					if (not_found_exit_addr) {
11690 						ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11691 					} else {
11692 						ir_ref if_fit = ir_IF(cond);
11693 						ir_IF_FALSE(if_fit);
11694 						ir_END_list(*end_inputs);
11695 						ir_IF_TRUE(if_fit);
11696 					}
11697 				} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11698 					ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11699 				} else if (type == BP_VAR_IS && not_found_exit_addr) {
11700 					ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11701 				} else if (type == BP_VAR_RW && not_found_exit_addr) {
11702 					ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11703 				} else if (type == BP_VAR_IS && result_type_guard) {
11704 					ir_ref if_fit = ir_IF(cond);
11705 					ir_IF_FALSE(if_fit);
11706 					ir_END_list(*not_found_inputs);
11707 					ir_IF_TRUE(if_fit);
11708 				} else {
11709 					ir_ref if_fit = ir_IF(cond);
11710 					ir_IF_FALSE(if_fit);
11711 					ir_END_list(idx_not_found_inputs);
11712 					ir_IF_TRUE(if_fit);
11713 				}
11714 				// JIT: _ret = &_ht->arPacked[h];
11715 				ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
11716 				ref = ir_BITCAST_A(ref);
11717 				ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
11718 				if (type == BP_JIT_IS) {
11719 					ir_refs_add(test_zval_values, ref);
11720 					ir_refs_add(test_zval_inputs, ir_END());
11721 				}
11722 			}
11723 		}
11724 		switch (type) {
11725 			case BP_JIT_IS:
11726 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11727 					if (if_packed) {
11728 						ir_IF_FALSE(if_packed);
11729 						if_packed = IR_UNUSED;
11730 					}
11731 					if (!op2_loaded) {
11732 						// JIT: hval = Z_LVAL_P(dim);
11733 						h = jit_Z_LVAL(jit, op2_addr);
11734 						op2_loaded = 1;
11735 					}
11736 					if (packed_loaded) {
11737 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11738 					} else {
11739 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11740 					}
11741 					if (not_found_exit_addr) {
11742 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11743 					} else {
11744 						if_found = ir_IF(ref);
11745 						ir_IF_FALSE(if_found);
11746 						ir_END_list(*end_inputs);
11747 						ir_IF_TRUE(if_found);
11748 					}
11749 					ir_refs_add(test_zval_values, ref);
11750 					ir_refs_add(test_zval_inputs, ir_END());
11751 				} else if (!not_found_exit_addr && !packed_loaded) {
11752 					ir_END_list(*end_inputs);
11753 				}
11754 				break;
11755 			case BP_VAR_R:
11756 			case BP_VAR_IS:
11757 			case BP_VAR_UNSET:
11758 				if (packed_loaded) {
11759 					ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
11760 
11761 					if (result_type_guard) {
11762 						/* perform IS_UNDEF check only after result type guard (during deoptimization) */
11763 					} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11764 						ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
11765 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11766 						ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
11767 					} else {
11768 						ir_ref if_def = ir_IF(type_ref);
11769 						ir_IF_FALSE(if_def);
11770 						ir_END_list(idx_not_found_inputs);
11771 						ir_IF_TRUE(if_def);
11772 					}
11773 					ir_refs_add(found_inputs, ir_END());
11774 					ir_refs_add(found_vals, ref);
11775 				}
11776 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11777 					if (if_packed) {
11778 						ir_IF_FALSE(if_packed);
11779 						if_packed = IR_UNUSED;
11780 					}
11781 					if (!op2_loaded) {
11782 						// JIT: hval = Z_LVAL_P(dim);
11783 						h = jit_Z_LVAL(jit, op2_addr);
11784 						op2_loaded = 1;
11785 					}
11786 					if (packed_loaded) {
11787 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11788 					} else {
11789 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11790 					}
11791 					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11792 						ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11793 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11794 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11795 					} else if (type == BP_VAR_IS && result_type_guard) {
11796 						if_found = ir_IF(ref);
11797 						ir_IF_FALSE(if_found);
11798 						ir_END_list(*not_found_inputs);
11799 						ir_IF_TRUE(if_found);
11800 					} else {
11801 						if_found = ir_IF(ref);
11802 						ir_IF_FALSE(if_found);
11803 						ir_END_list(idx_not_found_inputs);
11804 						ir_IF_TRUE(if_found);
11805 					}
11806 					ir_refs_add(found_inputs, ir_END());
11807 					ir_refs_add(found_vals, ref);
11808 				} else if (!packed_loaded) {
11809 					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11810 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
11811 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11812 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
11813 					} else if (type == BP_VAR_IS && result_type_guard) {
11814 						ir_END_list(*not_found_inputs);
11815 					} else {
11816 						ir_END_list(idx_not_found_inputs);
11817 					}
11818 				}
11819 
11820 				if (idx_not_found_inputs) {
11821 					ir_MERGE_list(idx_not_found_inputs);
11822 					switch (type) {
11823 						case BP_VAR_R:
11824 							ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
11825 							// JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
11826 							// JIT: retval = &EG(uninitialized_zval);
11827 							jit_SET_EX_OPLINE(jit, opline);
11828 							if (Z_MODE(op2_addr) == IS_REG) {
11829 								if (!op2_loaded) {
11830 									// JIT: hval = Z_LVAL_P(dim);
11831 									h = jit_Z_LVAL(jit, op2_addr);
11832 								}
11833 								if (GCC_GLOBAL_REGS) {
11834 									ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h);
11835 								} else {
11836 									ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h, jit_FP(jit));
11837 								}
11838 							} else {
11839 								ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
11840 							}
11841 							ir_END_list(*end_inputs);
11842 							break;
11843 						case BP_VAR_IS:
11844 						case BP_VAR_UNSET:
11845 							if (!not_found_exit_addr) {
11846 								// JIT: retval = &EG(uninitialized_zval);
11847 								jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
11848 								ir_END_list(*end_inputs);
11849 							}
11850 							break;
11851 						default:
11852 							ZEND_UNREACHABLE();
11853 					}
11854                 }
11855 				break;
11856 			case BP_VAR_RW:
11857 				if (packed_loaded) {
11858 					if (not_found_exit_addr) {
11859 						ir_refs_add(found_inputs, ir_END());
11860 						ir_refs_add(found_vals, ref);
11861 					} else {
11862 						ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
11863 						ir_IF_TRUE(if_def);
11864 						ir_refs_add(found_inputs, ir_END());
11865 						ir_refs_add(found_vals, ref);
11866 						ir_IF_FALSE_cold(if_def);
11867 						ir_END_list(idx_not_found_inputs);
11868 					}
11869 				}
11870 				if (!packed_loaded ||
11871 						!not_found_exit_addr ||
11872 						(op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
11873 					if (if_packed) {
11874 						ir_IF_FALSE(if_packed);
11875 						if_packed = IR_UNUSED;
11876 						ir_END_list(idx_not_found_inputs);
11877 					} else if (!packed_loaded) {
11878 						ir_END_list(idx_not_found_inputs);
11879 					}
11880 
11881 					ir_MERGE_list(idx_not_found_inputs);
11882 					if (!op2_loaded) {
11883 						// JIT: hval = Z_LVAL_P(dim);
11884 						h = jit_Z_LVAL(jit, op2_addr);
11885 					}
11886 					if (packed_loaded) {
11887 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
11888 							ht_ref, h);
11889 					} else {
11890 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
11891 					}
11892 					if (not_found_exit_addr) {
11893 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11894 					} else {
11895 						if_found = ir_IF(ref);
11896 						ir_IF_FALSE(if_found);
11897 						ir_END_list(*end_inputs);
11898 						ir_IF_TRUE(if_found);
11899 					}
11900 					ir_refs_add(found_inputs, ir_END());
11901 					ir_refs_add(found_vals, ref);
11902 				}
11903 				break;
11904 			case BP_VAR_W:
11905 				if (packed_loaded) {
11906 					ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
11907 					ir_IF_TRUE_cold(if_def);
11908 					ir_refs_add(found_inputs, ir_END());
11909 					ir_refs_add(found_vals, ref);
11910 					ir_IF_FALSE(if_def);
11911 					ir_END_list(idx_not_found_inputs);
11912 				}
11913 				if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
11914 					if (if_packed) {
11915 						ir_IF_FALSE(if_packed);
11916 						if_packed = IR_UNUSED;
11917 						ir_END_list(idx_not_found_inputs);
11918 					} else if (!packed_loaded) {
11919 						ir_END_list(idx_not_found_inputs);
11920 					}
11921 					ir_MERGE_list(idx_not_found_inputs);
11922 					if (!op2_loaded) {
11923 						// JIT: hval = Z_LVAL_P(dim);
11924 						h = jit_Z_LVAL(jit, op2_addr);
11925 					}
11926 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
11927 					ir_refs_add(found_inputs, ir_END());
11928 					ir_refs_add(found_vals, ref);
11929 				}
11930 				break;
11931 			default:
11932 				ZEND_UNREACHABLE();
11933 		}
11934 	}
11935 
11936 	if (op2_info & MAY_BE_STRING) {
11937 		ir_ref key;
11938 
11939 		if (if_type) {
11940 			ir_IF_FALSE(if_type);
11941 			if_type = IS_UNUSED;
11942 		}
11943 
11944 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
11945 			// JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
11946 			if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
11947 			ir_IF_TRUE(if_type);
11948 		}
11949 
11950 		// JIT: offset_key = Z_STR_P(dim);
11951 		key = jit_Z_PTR(jit, op2_addr);
11952 
11953 		// JIT: retval = zend_hash_find(ht, offset_key);
11954 		switch (type) {
11955 			case BP_JIT_IS:
11956 				if (opline->op2_type != IS_CONST) {
11957 					ir_ref if_num, end1, ref2;
11958 
11959 					if_num = ir_IF(
11960 						ir_ULE(
11961 							ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
11962 							ir_CONST_CHAR('9')));
11963 					ir_IF_TRUE_cold(if_num);
11964 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
11965 					end1 = ir_END();
11966 					ir_IF_FALSE(if_num);
11967 					ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
11968 					ir_MERGE_WITH(end1);
11969 					ref = ir_PHI_2(IR_ADDR, ref2, ref);
11970 				} else {
11971 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
11972 				}
11973 				if (not_found_exit_addr) {
11974 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11975 				} else {
11976 					if_found = ir_IF(ref);
11977 					ir_IF_FALSE(if_found);
11978 					ir_END_list(*end_inputs);
11979 					ir_IF_TRUE(if_found);
11980 				}
11981 				ir_refs_add(test_zval_values, ref);
11982 				ir_refs_add(test_zval_inputs, ir_END());
11983 				break;
11984 			case BP_VAR_R:
11985 			case BP_VAR_IS:
11986 			case BP_VAR_UNSET:
11987 				if (opline->op2_type != IS_CONST) {
11988 					ir_ref if_num, end1, ref2;
11989 
11990 					if_num = ir_IF(
11991 						ir_ULE(
11992 							ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
11993 							ir_CONST_CHAR('9')));
11994 					ir_IF_TRUE_cold(if_num);
11995 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
11996 					end1 = ir_END();
11997 					ir_IF_FALSE(if_num);
11998 					ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
11999 					ir_MERGE_WITH(end1);
12000 					ref = ir_PHI_2(IR_ADDR, ref2, ref);
12001 				} else {
12002 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12003 				}
12004 				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12005 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12006 				} else if (type == BP_VAR_IS && not_found_exit_addr) {
12007 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12008 				} else if (type == BP_VAR_IS && result_type_guard) {
12009 					if_found = ir_IF(ref);
12010 					ir_IF_FALSE(if_found);
12011 					ir_END_list(*not_found_inputs);
12012 					ir_IF_TRUE(if_found);
12013 				} else {
12014 					if_found = ir_IF(ref);
12015 					switch (type) {
12016 						case BP_VAR_R:
12017 							ir_IF_FALSE_cold(if_found);
12018 							// JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
12019 							jit_SET_EX_OPLINE(jit, opline);
12020 							ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
12021 							ir_END_list(*end_inputs);
12022 							break;
12023 						case BP_VAR_IS:
12024 						case BP_VAR_UNSET:
12025 							ir_IF_FALSE(if_found);
12026 							// JIT: retval = &EG(uninitialized_zval);
12027 							jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12028 							ir_END_list(*end_inputs);
12029 							break;
12030 						default:
12031 							ZEND_UNREACHABLE();
12032 					}
12033 					ir_IF_TRUE(if_found);
12034 				}
12035 				ir_refs_add(found_inputs, ir_END());
12036 				ir_refs_add(found_vals, ref);
12037 				break;
12038 			case BP_VAR_RW:
12039 				if (opline->op2_type != IS_CONST) {
12040 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
12041 				} else {
12042 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
12043 				}
12044 				if (not_found_exit_addr) {
12045 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12046 				} else {
12047 					if_found = ir_IF(ref);
12048 					ir_IF_FALSE(if_found);
12049 					ir_END_list(*end_inputs);
12050 					ir_IF_TRUE(if_found);
12051 				}
12052 				ir_refs_add(found_inputs, ir_END());
12053 				ir_refs_add(found_vals, ref);
12054 				break;
12055 			case BP_VAR_W:
12056 				if (opline->op2_type != IS_CONST) {
12057 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12058 				} else {
12059 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12060 				}
12061 				ir_refs_add(found_inputs, ir_END());
12062 				ir_refs_add(found_vals, ref);
12063 				break;
12064 			default:
12065 				ZEND_UNREACHABLE();
12066 		}
12067 	}
12068 
12069 	if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12070 	    if (if_type) {
12071 			ir_IF_FALSE_cold(if_type);
12072 			if_type = IS_UNDEF;
12073 		}
12074 		if (type != BP_VAR_RW) {
12075 			jit_SET_EX_OPLINE(jit, opline);
12076 		}
12077 		ref = jit_ZVAL_ADDR(jit, op2_addr);
12078 		switch (type) {
12079 			case BP_VAR_R:
12080 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12081 					ht_ref,
12082 					ref,
12083 					jit_ZVAL_ADDR(jit, res_addr));
12084 				ir_END_list(*end_inputs);
12085 				break;
12086 			case BP_JIT_IS:
12087 				ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12088 				if (not_found_exit_addr) {
12089 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12090 					ir_refs_add(found_inputs, ir_END());
12091 				} else if (found_exit_addr) {
12092 					ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12093 					ir_END_list(*end_inputs);
12094 				} else {
12095 					if_found = ir_IF(ref);
12096 					ir_IF_TRUE(if_found);
12097 					ir_refs_add(found_inputs, ir_END());
12098 					ir_IF_FALSE(if_found);
12099 					ir_END_list(*end_inputs);
12100 				}
12101 				break;
12102 			case BP_VAR_IS:
12103 			case BP_VAR_UNSET:
12104 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12105 					ht_ref,
12106 					ref,
12107 					jit_ZVAL_ADDR(jit, res_addr));
12108 				ir_END_list(*end_inputs);
12109 				break;
12110 			case BP_VAR_RW:
12111 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12112 				if_found = ir_IF(ref);
12113 				ir_IF_TRUE(if_found);
12114 				ir_refs_add(found_inputs, ir_END());
12115 				ir_refs_add(found_vals, ref);
12116 				ir_IF_FALSE(if_found);
12117 				ir_END_list(*end_inputs);
12118 				break;
12119 			case BP_VAR_W:
12120 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12121 				if_found = ir_IF(ref);
12122 				ir_IF_TRUE(if_found);
12123 				ir_refs_add(found_inputs, ir_END());
12124 				ir_refs_add(found_vals, ref);
12125 				ir_IF_FALSE(if_found);
12126 				ir_END_list(*end_inputs);
12127 				break;
12128 			default:
12129 				ZEND_UNREACHABLE();
12130 		}
12131 	}
12132 
12133 	if (type == BP_JIT_IS
12134 	 && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12135 	 	/* dead code */
12136 		ir_END_list(*end_inputs);
12137 	} else if (type == BP_JIT_IS
12138 	 && (op1_info & MAY_BE_ARRAY)
12139 	 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12140 	 && test_zval_inputs->count) {
12141 
12142 		ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12143 		ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12144 
12145 		if (op1_info & MAY_BE_ARRAY_OF_REF) {
12146 			ref = jit_ZVAL_DEREF_ref(jit, ref);
12147 		}
12148 		cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12149 		if (not_found_exit_addr) {
12150 			ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12151 			ir_refs_add(found_inputs, ir_END());
12152 		} else if (found_exit_addr) {
12153 			ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12154 			ir_END_list(*end_inputs);
12155 		} else {
12156 			ir_ref if_set = ir_IF(cond);
12157 			ir_IF_FALSE(if_set);
12158 			ir_END_list(*end_inputs);
12159 			ir_IF_TRUE(if_set);
12160 			ir_refs_add(found_inputs, ir_END());
12161 		}
12162 	}
12163 
12164 	return 1;
12165 }
12166 
12167 static int zend_jit_fetch_dim_read(zend_jit_ctx       *jit,
12168                                    const zend_op      *opline,
12169                                    zend_ssa           *ssa,
12170                                    const zend_ssa_op  *ssa_op,
12171                                    uint32_t            op1_info,
12172                                    zend_jit_addr       op1_addr,
12173                                    bool           op1_avoid_refcounting,
12174                                    uint32_t            op2_info,
12175                                    zend_jit_addr       op2_addr,
12176                                    zend_ssa_range     *op2_range,
12177                                    uint32_t            res_info,
12178                                    zend_jit_addr       res_addr,
12179                                    uint8_t             dim_type)
12180 {
12181 	zend_jit_addr orig_op1_addr;
12182 	const void *exit_addr = NULL;
12183 	const void *not_found_exit_addr = NULL;
12184 	bool result_type_guard = 0;
12185 	bool result_avoid_refcounting = 0;
12186 	uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12187 	int may_throw = 0;
12188 	ir_ref if_type = IR_UNUSED;
12189 	ir_ref end_inputs = IR_UNUSED;
12190 	ir_ref not_found_inputs = IR_UNUSED;
12191 
12192 	orig_op1_addr = OP1_ADDR();
12193 
12194 	if (opline->opcode != ZEND_FETCH_DIM_IS
12195 	 && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12196 	 && !has_concrete_type(op1_info)) {
12197 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12198 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12199 		if (!exit_addr) {
12200 			return 0;
12201 		}
12202 	}
12203 
12204 	if ((res_info & MAY_BE_GUARD)
12205 	 && JIT_G(current_frame)
12206 	 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12207 
12208 		if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12209 			result_type_guard = 1;
12210 			res_info &= ~MAY_BE_GUARD;
12211 			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12212 		}
12213 
12214 		if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12215 		 && (opline->opcode == ZEND_FETCH_LIST_R
12216 		  || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12217 		  || op1_avoid_refcounting)
12218 		 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12219 		 && (ssa_op+1)->op1_use == ssa_op->result_def
12220 		 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12221 		 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12222 			result_avoid_refcounting = 1;
12223 			ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12224 		}
12225 
12226 		if (opline->opcode == ZEND_FETCH_DIM_IS
12227 		 && !(res_info & MAY_BE_NULL)) {
12228 			uint32_t flags = 0;
12229 			uint32_t old_op1_info = 0;
12230 			uint32_t old_info;
12231 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12232 			int32_t exit_point;
12233 
12234 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
12235 			 && !op1_avoid_refcounting) {
12236 				flags |= ZEND_JIT_EXIT_FREE_OP1;
12237 			}
12238 			if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12239 			 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12240 				flags |= ZEND_JIT_EXIT_FREE_OP2;
12241 			}
12242 
12243 			if (op1_avoid_refcounting) {
12244 				old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12245 				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12246 			}
12247 
12248 			old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12249 			SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12250 			SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_TYPE_ONLY);
12251 			exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12252 			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12253 			not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12254 			if (!not_found_exit_addr) {
12255 				return 0;
12256 			}
12257 
12258 			if (op1_avoid_refcounting) {
12259 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12260 			}
12261 		}
12262 	}
12263 
12264 	if (op1_info & MAY_BE_REF) {
12265 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12266 		ref = jit_ZVAL_DEREF_ref(jit, ref);
12267 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12268 	}
12269 
12270 	if (op1_info & MAY_BE_ARRAY) {
12271 		ir_ref ht_ref, ref;
12272 		zend_jit_addr val_addr;
12273 		ir_refs *found_inputs, *found_vals;
12274 
12275 		ir_refs_init(found_inputs, 10);
12276 		ir_refs_init(found_vals, 10);
12277 
12278 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12279 			if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12280 				jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12281 			} else {
12282 				if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12283 				ir_IF_TRUE(if_type);
12284 			}
12285 		}
12286 
12287 		ht_ref = jit_Z_PTR(jit, op1_addr);
12288 
12289 		if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12290 		    (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12291 			may_throw = 1;
12292 		}
12293 
12294 		if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12295 				(opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12296 				op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12297 				result_type_guard, ht_ref, found_inputs, found_vals,
12298 				&end_inputs, &not_found_inputs)) {
12299 			return 0;
12300 		}
12301 
12302 		if (found_inputs->count) {
12303 			ir_MERGE_N(found_inputs->count, found_inputs->refs);
12304 			ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12305 			val_addr = ZEND_ADDR_REF_ZVAL(ref);
12306 
12307 			if (result_type_guard) {
12308 				uint8_t type = concrete_type(res_info);
12309 				uint32_t flags = 0;
12310 
12311 				if (opline->opcode != ZEND_FETCH_LIST_R
12312 				 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12313 				 && !op1_avoid_refcounting) {
12314 					flags |= ZEND_JIT_EXIT_FREE_OP1;
12315 				}
12316 				if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12317 				 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12318 					flags |= ZEND_JIT_EXIT_FREE_OP2;
12319 				}
12320 
12321 				val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12322 					(op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12323 				if (!val_addr) {
12324 					return 0;
12325 				}
12326 
12327 				if (not_found_inputs) {
12328 					ir_END_list(not_found_inputs);
12329 					ir_MERGE_list(not_found_inputs);
12330 				}
12331 
12332 				// ZVAL_COPY
12333 				jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12334 				if (Z_MODE(res_addr) != IS_REG) {
12335 				} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12336 					return 0;
12337 				}
12338 			} else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12339 				// ZVAL_COPY_DEREF
12340 				ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12341 				if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12342 					return 0;
12343 				}
12344 			} else  {
12345 				// ZVAL_COPY
12346 				jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, 1);
12347 			}
12348 
12349 			ir_END_list(end_inputs);
12350 		} else if (not_found_inputs) {
12351 			ir_MERGE_list(not_found_inputs);
12352 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12353 			ir_END_list(end_inputs);
12354 		} else if (!end_inputs && jit->ctx.control) {
12355 			ir_END_list(end_inputs); /* dead code */
12356 		}
12357 	}
12358 
12359 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12360 		if (if_type) {
12361 			ir_IF_FALSE_cold(if_type);
12362 			if_type = IS_UNDEF;
12363 		}
12364 
12365 		if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12366 			ir_ref str_ref;
12367 
12368 			may_throw = 1;
12369 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12370 				if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12371 					jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12372 				} else {
12373 					if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12374 					ir_IF_TRUE(if_type);
12375 				}
12376 			}
12377 			jit_SET_EX_OPLINE(jit, opline);
12378 			str_ref = jit_Z_PTR(jit, op1_addr);
12379 			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12380 				ir_ref ref;
12381 
12382 				if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12383 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12384 						str_ref, jit_Z_LVAL(jit, op2_addr));
12385 				} else {
12386 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12387 						str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12388 				}
12389 				jit_set_Z_PTR(jit, res_addr, ref);
12390 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12391 			} else {
12392 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12393 					str_ref,
12394 					jit_ZVAL_ADDR(jit, op2_addr),
12395 					jit_ZVAL_ADDR(jit, res_addr));
12396 			}
12397 			ir_END_list(end_inputs);
12398 		}
12399 
12400 		if (op1_info & MAY_BE_OBJECT) {
12401 			ir_ref arg2;
12402 
12403 			if (if_type) {
12404 				ir_IF_FALSE_cold(if_type);
12405 				if_type = IS_UNDEF;
12406 			}
12407 
12408 			may_throw = 1;
12409 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12410 				if (exit_addr) {
12411 					jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12412 				} else {
12413 					if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12414 					ir_IF_TRUE(if_type);
12415 				}
12416 			}
12417 
12418 			jit_SET_EX_OPLINE(jit, opline);
12419 			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12420 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12421 				arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12422 			} else {
12423 				arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12424 			}
12425 
12426 			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12427 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12428 					jit_ZVAL_ADDR(jit, op1_addr),
12429 					arg2,
12430 					jit_ZVAL_ADDR(jit, res_addr));
12431 			} else {
12432 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12433 					jit_ZVAL_ADDR(jit, op1_addr),
12434 					arg2,
12435 					jit_ZVAL_ADDR(jit, res_addr));
12436 			}
12437 
12438 			ir_END_list(end_inputs);
12439 		}
12440 
12441 		if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12442 		 && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12443 
12444 			if (if_type) {
12445 				ir_IF_FALSE_cold(if_type);
12446 				if_type = IS_UNDEF;
12447 			}
12448 
12449 			if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12450 				jit_SET_EX_OPLINE(jit, opline);
12451 				if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12452 					may_throw = 1;
12453 					zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL, 0, 1, 0);
12454 				}
12455 
12456 				if (op2_info & MAY_BE_UNDEF) {
12457 					may_throw = 1;
12458 					zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL, 0, 1, 0);
12459 				}
12460 			}
12461 
12462 			if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
12463 				ir_ref ref;
12464 
12465 				may_throw = 1;
12466 				if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12467 					ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
12468 				} else {
12469 					jit_SET_EX_OPLINE(jit, opline);
12470 					ref = jit_ZVAL_ADDR(jit, op1_addr);
12471 				}
12472 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
12473 			}
12474 
12475 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12476 			ir_END_list(end_inputs);
12477 		}
12478 	}
12479 
12480 	if (end_inputs) {
12481 		ir_MERGE_list(end_inputs);
12482 
12483 #ifdef ZEND_JIT_USE_RC_INFERENCE
12484 		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12485 			/* Magic offsetGet() may increase refcount of the key */
12486 			op2_info |= MAY_BE_RCN;
12487 		}
12488 #endif
12489 
12490 		if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
12491 			if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
12492 				may_throw = 1;
12493 			}
12494 			jit_FREE_OP(jit,  opline->op2_type, opline->op2, op2_info, opline);
12495 		}
12496 		if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12497 			if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
12498 				if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
12499 					may_throw = 1;
12500 				}
12501 				jit_FREE_OP(jit,  opline->op1_type, opline->op1, op1_info, opline);
12502 			}
12503 		}
12504 
12505 		if (may_throw) {
12506 			zend_jit_check_exception(jit);
12507 		}
12508 	} else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
12509 		ir_BEGIN(IR_UNUSED); /* unreachable tail */
12510 	}
12511 
12512 	return 1;
12513 }
12514 
12515 static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx   *jit,
12516                                                    const zend_op  *opline,
12517                                                    uint32_t        op1_info,
12518                                                    zend_jit_addr   op1_addr,
12519                                                    ir_ref         *if_type,
12520                                                    ir_ref         *ht_ref,
12521                                                    int            *may_throw)
12522 {
12523 	ir_ref ref = IR_UNUSED;
12524 	ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
12525 	ir_refs *array_inputs, *array_values;
12526 
12527 	ir_refs_init(array_inputs, 4);
12528 	ir_refs_init(array_values, 4);
12529 
12530 	ref = jit_ZVAL_ADDR(jit, op1_addr);
12531 	if (op1_info & MAY_BE_REF) {
12532 		ir_ref if_reference, if_array, end1, ref2;
12533 
12534 		*may_throw = 1;
12535 		if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
12536 		ir_IF_FALSE(if_reference);
12537 		end1 = ir_END();
12538 		ir_IF_TRUE_cold(if_reference);
12539 		array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
12540 		if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
12541 		ir_IF_TRUE(if_array);
12542 		array_reference_end = ir_END();
12543 		ir_IF_FALSE_cold(if_array);
12544 		if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
12545 			jit_SET_EX_OPLINE(jit, opline);
12546 		}
12547 		ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
12548 		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
12549 
12550 		ir_MERGE_WITH(end1);
12551 		ref = ir_PHI_2(IR_ADDR, ref2, ref);
12552 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12553 	}
12554 
12555 	if (op1_info & MAY_BE_ARRAY) {
12556 		ir_ref op1_ref = ref;
12557 
12558 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12559 			*if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12560 			ir_IF_TRUE(*if_type);
12561 		}
12562 		if (array_reference_end) {
12563 			ir_MERGE_WITH(array_reference_end);
12564 			op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
12565 		}
12566 		// JIT: SEPARATE_ARRAY()
12567 		ref = jit_Z_PTR_ref(jit, op1_ref);
12568 		if (RC_MAY_BE_N(op1_info)) {
12569 			if (RC_MAY_BE_1(op1_info)) {
12570 				ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
12571 				ir_IF_TRUE(if_refcount_1);
12572 				ir_refs_add(array_inputs, ir_END());
12573 				ir_refs_add(array_values, ref);
12574 				ir_IF_FALSE(if_refcount_1);
12575 			}
12576 			ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
12577 		}
12578 		if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
12579 			ir_refs_add(array_inputs, ir_END());
12580 			ir_refs_add(array_values, ref);
12581 		}
12582 	}
12583 
12584 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
12585 		if (*if_type) {
12586 			ir_IF_FALSE_cold(*if_type);
12587 			*if_type = IR_UNUSED;
12588 		}
12589 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12590 			*if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
12591 			ir_IF_TRUE(*if_type);
12592 		}
12593 		if ((op1_info & MAY_BE_UNDEF)
12594 		 && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
12595 			ir_ref end1 = IR_UNUSED;
12596 
12597 			*may_throw = 1;
12598 			if (op1_info & MAY_BE_NULL) {
12599 				ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
12600 				ir_IF_TRUE(if_def);
12601 				end1 = ir_END();
12602 				ir_IF_FALSE(if_def);
12603 			}
12604 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
12605 			if (end1) {
12606 				ir_MERGE_WITH(end1);
12607 			}
12608 		}
12609 		// JIT: ZVAL_ARR(container, zend_new_array(8));
12610 		ref = ir_CALL_1(IR_ADDR,
12611 			jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
12612 			jit_ZVAL_ADDR(jit, op1_addr));
12613 		if (array_inputs->count) {
12614 			ir_refs_add(array_inputs, ir_END());
12615 			ir_refs_add(array_values, ref);
12616 		}
12617 	}
12618 
12619 	if (array_inputs->count) {
12620 		ir_MERGE_N(array_inputs->count, array_inputs->refs);
12621 		ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
12622 	}
12623 
12624 	*ht_ref = ref;
12625 	return op1_addr;
12626 }
12627 
12628 static int zend_jit_fetch_dim(zend_jit_ctx   *jit,
12629                               const zend_op  *opline,
12630                               uint32_t        op1_info,
12631                               zend_jit_addr   op1_addr,
12632                               uint32_t        op2_info,
12633                               zend_jit_addr   op2_addr,
12634                               zend_ssa_range *op2_range,
12635                               zend_jit_addr   res_addr,
12636                               uint8_t         dim_type)
12637 {
12638 	int may_throw = 0;
12639 	ir_ref end_inputs = IR_UNUSED;
12640 	ir_ref ref, if_type = IR_UNUSED, ht_ref;
12641 
12642 	if (opline->opcode == ZEND_FETCH_DIM_RW) {
12643 		jit_SET_EX_OPLINE(jit, opline);
12644 	}
12645 
12646 	op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
12647 
12648 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12649 		ir_refs *found_inputs, *found_vals;
12650 
12651 		ir_refs_init(found_inputs, 8);
12652 		ir_refs_init(found_vals, 8);
12653 
12654 		if (opline->op2_type == IS_UNUSED) {
12655 			ir_ref if_ok;
12656 
12657 			may_throw = 1;
12658 			// JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
12659 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
12660 				ht_ref, jit_EG(uninitialized_zval));
12661 
12662 			// JIT: if (UNEXPECTED(!var_ptr)) {
12663 			if_ok = ir_IF(ref);
12664 			ir_IF_FALSE_cold(if_ok);
12665 			if (opline->opcode != ZEND_FETCH_DIM_RW) {
12666 				jit_SET_EX_OPLINE(jit, opline);
12667 			}
12668 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
12669 			ir_END_list(end_inputs);
12670 
12671 			ir_IF_TRUE(if_ok);
12672 			jit_set_Z_PTR(jit, res_addr, ref);
12673 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12674 
12675 			ir_END_list(end_inputs);
12676 		} else {
12677 			uint32_t type;
12678 
12679 			switch (opline->opcode) {
12680 				case ZEND_FETCH_DIM_W:
12681 				case ZEND_FETCH_LIST_W:
12682 					type = BP_VAR_W;
12683 					break;
12684 				case ZEND_FETCH_DIM_RW:
12685 					may_throw = 1;
12686 					type = BP_VAR_RW;
12687 					break;
12688 				case ZEND_FETCH_DIM_UNSET:
12689 					type = BP_VAR_UNSET;
12690 					break;
12691 				default:
12692 					ZEND_UNREACHABLE();
12693 			}
12694 
12695 			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12696 				may_throw = 1;
12697 			}
12698 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
12699 					op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
12700 					0, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
12701 				return 0;
12702 			}
12703 
12704 			if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
12705 				if (end_inputs) {
12706 					ir_MERGE_list(end_inputs);
12707 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12708 					end_inputs = ir_END();
12709 				}
12710 			} else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12711 				/* impossible dead path */
12712 				end_inputs = ir_END();
12713 			} else {
12714 				ZEND_ASSERT(end_inputs == IR_UNUSED);
12715 			}
12716 
12717 			if (found_inputs->count) {
12718 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
12719 				ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12720 				jit_set_Z_PTR(jit, res_addr, ref);
12721 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12722 				ir_END_list(end_inputs);
12723 			}
12724 
12725 		}
12726 	}
12727 
12728 	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12729 		ir_ref arg2;
12730 
12731 		may_throw = 1;
12732 
12733 		if (if_type) {
12734 			ir_IF_FALSE(if_type);
12735 			if_type = IR_UNUSED;
12736 		}
12737 
12738 		if (opline->opcode != ZEND_FETCH_DIM_RW) {
12739 			jit_SET_EX_OPLINE(jit, opline);
12740 		}
12741 
12742 	    if (opline->op2_type == IS_UNUSED) {
12743 			arg2 = IR_NULL;
12744 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12745 			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12746 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
12747 		} else {
12748 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12749 		}
12750 
12751 		switch (opline->opcode) {
12752 			case ZEND_FETCH_DIM_W:
12753 			case ZEND_FETCH_LIST_W:
12754 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
12755 					jit_ZVAL_ADDR(jit, op1_addr),
12756 					arg2,
12757 					jit_ZVAL_ADDR(jit, res_addr));
12758 				break;
12759 			case ZEND_FETCH_DIM_RW:
12760 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
12761 					jit_ZVAL_ADDR(jit, op1_addr),
12762 					arg2,
12763 					jit_ZVAL_ADDR(jit, res_addr));
12764 				break;
12765 //			case ZEND_FETCH_DIM_UNSET:
12766 //				|	EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
12767 //				break;
12768 			default:
12769 				ZEND_UNREACHABLE();
12770 			}
12771 
12772 		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12773 			ir_END_list(end_inputs);
12774 		}
12775 	}
12776 
12777 #ifdef ZEND_JIT_USE_RC_INFERENCE
12778 	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))) {
12779 		/* ASSIGN_DIM may increase refcount of the key */
12780 		op2_info |= MAY_BE_RCN;
12781 	}
12782 #endif
12783 
12784 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
12785 	 && (op2_info & MAY_HAVE_DTOR)
12786 	 && (op2_info & MAY_BE_RC1)) {
12787 		may_throw = 1;
12788 	}
12789 
12790 	if (end_inputs) {
12791 		ir_MERGE_list(end_inputs);
12792 	}
12793 
12794 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12795 
12796 	if (may_throw) {
12797 		zend_jit_check_exception(jit);
12798 	}
12799 
12800 	return 1;
12801 }
12802 
12803 static int zend_jit_isset_isempty_dim(zend_jit_ctx   *jit,
12804                                       const zend_op  *opline,
12805                                       uint32_t        op1_info,
12806                                       zend_jit_addr   op1_addr,
12807                                       bool       op1_avoid_refcounting,
12808                                       uint32_t        op2_info,
12809                                       zend_jit_addr   op2_addr,
12810                                       zend_ssa_range *op2_range,
12811                                       uint8_t         dim_type,
12812                                       int             may_throw,
12813                                       uint8_t         smart_branch_opcode,
12814                                       uint32_t        target_label,
12815                                       uint32_t        target_label2,
12816                                       const void     *exit_addr)
12817 {
12818 	zend_jit_addr res_addr;
12819 	ir_ref if_type = IR_UNUSED;
12820 	ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
12821 	ir_refs *true_inputs;
12822 
12823 	ir_refs_init(true_inputs, 8);
12824 
12825 	// TODO: support for empty() ???
12826 	ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
12827 
12828 	res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
12829 
12830 	if (op1_info & MAY_BE_REF) {
12831 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12832 		ref = jit_ZVAL_DEREF_ref(jit, ref);
12833 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12834 	}
12835 
12836 	if (op1_info & MAY_BE_ARRAY) {
12837 		const void *found_exit_addr = NULL;
12838 		const void *not_found_exit_addr = NULL;
12839 		ir_ref ht_ref;
12840 
12841 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12842 			if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12843 			ir_IF_TRUE(if_type);
12844 		}
12845 
12846 		ht_ref = jit_Z_PTR(jit, op1_addr);
12847 
12848 		if (exit_addr
12849 		 && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
12850 		 && !may_throw
12851 		 && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
12852 		 && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
12853 			if (smart_branch_opcode == ZEND_JMPNZ) {
12854 				found_exit_addr = exit_addr;
12855 			} else {
12856 				not_found_exit_addr = exit_addr;
12857 			}
12858 		}
12859 		if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
12860 				op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
12861 				0, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
12862 			return 0;
12863 		}
12864 
12865 		if (found_exit_addr) {
12866 			ir_MERGE_list(false_inputs);
12867 			return 1;
12868 		} else if (not_found_exit_addr) {
12869 			ir_MERGE_N(true_inputs->count, true_inputs->refs);
12870 			return 1;
12871 		}
12872 	}
12873 
12874 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12875 		if (if_type) {
12876 			ir_IF_FALSE(if_type);
12877 			if_type = IR_UNUSED;
12878 		}
12879 
12880 		if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
12881 			ir_ref ref, arg1, arg2, if_true;
12882 
12883 			jit_SET_EX_OPLINE(jit, opline);
12884 			arg1 = jit_ZVAL_ADDR(jit, op1_addr);
12885 			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12886 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12887 				arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12888 			} else {
12889 				arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12890 			}
12891 			ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
12892 			if_true = ir_IF(ref);
12893 			ir_IF_TRUE(if_true);
12894 			ir_refs_add(true_inputs, ir_END());
12895 			ir_IF_FALSE(if_true);
12896 			ir_END_list(false_inputs);
12897 		} else {
12898 			if (op2_info & MAY_BE_UNDEF) {
12899 				ir_ref end1 = IR_UNUSED;
12900 
12901 				if (op2_info & MAY_BE_ANY) {
12902 					ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
12903 					ir_IF_TRUE(if_def);
12904 					end1 = ir_END();
12905 					ir_IF_FALSE(if_def);
12906 				}
12907 				jit_SET_EX_OPLINE(jit, opline);
12908 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
12909 				if (end1) {
12910 					ir_MERGE_WITH(end1);
12911 				}
12912 			}
12913 			ir_END_list(false_inputs);
12914 		}
12915 	}
12916 
12917 #ifdef ZEND_JIT_USE_RC_INFERENCE
12918 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12919 		/* Magic offsetExists() may increase refcount of the key */
12920 		op2_info |= MAY_BE_RCN;
12921 	}
12922 #endif
12923 
12924 	if (true_inputs->count) {
12925 		ir_MERGE_N(true_inputs->count, true_inputs->refs);
12926 
12927 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12928 		if (!op1_avoid_refcounting) {
12929 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
12930 		}
12931 		if (may_throw) {
12932 			zend_jit_check_exception_undef_result(jit, opline);
12933 		}
12934 		if (!(opline->extended_value & ZEND_ISEMPTY)) {
12935 			if (exit_addr) {
12936 				if (smart_branch_opcode == ZEND_JMPNZ) {
12937 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12938 				} else {
12939 					ir_END_list(end_inputs);
12940 				}
12941 			} else if (smart_branch_opcode) {
12942 				if (smart_branch_opcode == ZEND_JMPZ) {
12943 					_zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
12944 				} else if (smart_branch_opcode == ZEND_JMPNZ) {
12945 					_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
12946 				} else {
12947 					ZEND_UNREACHABLE();
12948 				}
12949 			} else {
12950 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
12951 				ir_END_list(end_inputs);
12952 			}
12953 		} else {
12954 			ZEND_UNREACHABLE(); // TODO: support for empty()
12955 		}
12956 	}
12957 
12958 	ir_MERGE_list(false_inputs);
12959 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12960 	if (!op1_avoid_refcounting) {
12961 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
12962 	}
12963 	if (may_throw) {
12964 		zend_jit_check_exception_undef_result(jit, opline);
12965 	}
12966 	if (!(opline->extended_value & ZEND_ISEMPTY)) {
12967 		if (exit_addr) {
12968 			if (smart_branch_opcode == ZEND_JMPZ) {
12969 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12970 			} else {
12971 				ir_END_list(end_inputs);
12972 			}
12973 		} else if (smart_branch_opcode) {
12974 			if (smart_branch_opcode == ZEND_JMPZ) {
12975 				_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
12976 			} else if (smart_branch_opcode == ZEND_JMPNZ) {
12977 				_zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
12978 			} else {
12979 				ZEND_UNREACHABLE();
12980 			}
12981 		} else {
12982 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
12983 			ir_END_list(end_inputs);
12984 		}
12985 	} else {
12986 		ZEND_UNREACHABLE(); // TODO: support for empty()
12987 	}
12988 
12989     if (!exit_addr && smart_branch_opcode) {
12990 		jit->b = -1;
12991     } else {
12992 		ir_MERGE_list(end_inputs);
12993     }
12994 
12995 	return 1;
12996 }
12997 
12998 static int zend_jit_assign_dim(zend_jit_ctx  *jit,
12999                                const zend_op *opline,
13000                                uint32_t       op1_info,
13001                                zend_jit_addr  op1_addr,
13002                                uint32_t       op2_info,
13003                                zend_jit_addr  op2_addr,
13004                                zend_ssa_range *op2_range,
13005                                uint32_t       val_info,
13006                                zend_jit_addr  op3_addr,
13007                                zend_jit_addr  op3_def_addr,
13008                                zend_jit_addr  res_addr,
13009                                uint8_t        dim_type,
13010                                int            may_throw)
13011 {
13012 	ir_ref if_type = IR_UNUSED;
13013 	ir_ref end_inputs = IR_UNUSED, ht_ref;
13014 
13015 	if (op3_addr != op3_def_addr && op3_def_addr) {
13016 		if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
13017 			return 0;
13018 		}
13019 		if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
13020 			op3_addr = op3_def_addr;
13021 		}
13022 	}
13023 
13024 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
13025 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13026 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13027 
13028 		if (!exit_addr) {
13029 			return 0;
13030 		}
13031 
13032 		jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
13033 
13034 		val_info &= ~MAY_BE_UNDEF;
13035 	}
13036 
13037 	op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13038 
13039 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13040 		if (opline->op2_type == IS_UNUSED) {
13041 			uint32_t var_info = MAY_BE_NULL;
13042 			ir_ref if_ok, ref;
13043 			zend_jit_addr var_addr;
13044 
13045 			// JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13046 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13047 				ht_ref, jit_EG(uninitialized_zval));
13048 
13049 			// JIT: if (UNEXPECTED(!var_ptr)) {
13050 			if_ok = ir_IF(ref);
13051 			ir_IF_FALSE_cold(if_ok);
13052 
13053 			// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13054 			jit_SET_EX_OPLINE(jit, opline);
13055 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13056 
13057 			ir_END_list(end_inputs);
13058 
13059 			ir_IF_TRUE(if_ok);
13060 			var_addr = ZEND_ADDR_REF_ZVAL(ref);
13061 			if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13062 				return 0;
13063 			}
13064 		} else {
13065 			uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13066 			zend_jit_addr var_addr;
13067 			ir_ref ref;
13068 			ir_refs *found_inputs, *found_values;
13069 
13070 			ir_refs_init(found_inputs, 8);
13071 			ir_refs_init(found_values, 8);
13072 
13073 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13074 					op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13075 					0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13076 				return 0;
13077 			}
13078 
13079 			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13080 				var_info |= MAY_BE_REF;
13081 			}
13082 			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13083 				var_info |= MAY_BE_RC1;
13084 			}
13085 
13086 			if (found_inputs->count) {
13087 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
13088 				ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13089 				var_addr = ZEND_ADDR_REF_ZVAL(ref);
13090 
13091 				// JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13092 				if (opline->op1_type == IS_VAR
13093 				 && Z_MODE(op3_addr) != IS_REG
13094 				 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13095 					ZEND_ASSERT(opline->result_type == IS_UNUSED);
13096 					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)) {
13097 						return 0;
13098 					}
13099 				} else {
13100 					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)) {
13101 						return 0;
13102 					}
13103 				}
13104 			}
13105 		}
13106 
13107 		ir_END_list(end_inputs);
13108 	}
13109 
13110 	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13111 		ir_ref arg2, arg4;
13112 
13113 		if (if_type) {
13114 			ir_IF_FALSE_cold(if_type);
13115 			if_type = IR_UNUSED;
13116 		}
13117 
13118 		jit_SET_EX_OPLINE(jit, opline);
13119 
13120 	    if (opline->op2_type == IS_UNUSED) {
13121 			arg2 = IR_NULL;
13122 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13123 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13124 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13125 		} else {
13126 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13127 		}
13128 
13129 		if (opline->result_type == IS_UNUSED) {
13130 			arg4 = IR_NULL;
13131 		} else {
13132 			arg4 = jit_ZVAL_ADDR(jit, res_addr);
13133 		}
13134 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13135 			jit_ZVAL_ADDR(jit, op1_addr),
13136 			arg2,
13137 			jit_ZVAL_ADDR(jit, op3_addr),
13138 			arg4);
13139 
13140 #ifdef ZEND_JIT_USE_RC_INFERENCE
13141 		if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13142 			/* ASSIGN_DIM may increase refcount of the value */
13143 			val_info |= MAY_BE_RCN;
13144 		}
13145 #endif
13146 
13147 		jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13148 
13149 		ir_END_list(end_inputs);
13150 	}
13151 
13152 #ifdef ZEND_JIT_USE_RC_INFERENCE
13153 	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))) {
13154 		/* ASSIGN_DIM may increase refcount of the key */
13155 		op2_info |= MAY_BE_RCN;
13156 	}
13157 #endif
13158 
13159 	ir_MERGE_list(end_inputs);
13160 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13161 
13162 	if (may_throw) {
13163 		zend_jit_check_exception(jit);
13164 	}
13165 
13166 	return 1;
13167 }
13168 
13169 static int zend_jit_assign_dim_op(zend_jit_ctx   *jit,
13170                                   const zend_op  *opline,
13171                                   uint32_t        op1_info,
13172                                   uint32_t        op1_def_info,
13173                                   zend_jit_addr   op1_addr,
13174                                   uint32_t        op2_info,
13175                                   zend_jit_addr   op2_addr,
13176                                   zend_ssa_range *op2_range,
13177                                   uint32_t        op1_data_info,
13178                                   zend_jit_addr   op3_addr,
13179                                   zend_ssa_range *op1_data_range,
13180                                   uint8_t         dim_type,
13181                                   int             may_throw)
13182 {
13183 	zend_jit_addr var_addr = IS_UNUSED;
13184 	const void *not_found_exit_addr = NULL;
13185 	uint32_t var_info = MAY_BE_NULL;
13186 	ir_ref if_type = IS_UNUSED;
13187 	ir_ref end_inputs = IR_UNUSED, ht_ref;
13188 	bool emit_fast_path = 1;
13189 
13190 	ZEND_ASSERT(opline->result_type == IS_UNUSED);
13191 
13192 	if (may_throw) {
13193 		jit_SET_EX_OPLINE(jit, opline);
13194 	}
13195 
13196 	op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13197 
13198 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13199 		uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13200 
13201 		if (opline->op2_type == IS_UNUSED) {
13202 			var_info = MAY_BE_NULL;
13203 			ir_ref if_ok, ref;
13204 
13205 			// JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13206 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13207 				ht_ref, jit_EG(uninitialized_zval));
13208 
13209 			// JIT: if (UNEXPECTED(!var_ptr)) {
13210 			if_ok = ir_IF(ref);
13211 			ir_IF_FALSE_cold(if_ok);
13212 
13213 			// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13214 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13215 
13216 			ir_END_list(end_inputs);
13217 
13218 			ir_IF_TRUE(if_ok);
13219 			var_addr = ZEND_ADDR_REF_ZVAL(ref);
13220 		} else {
13221 			ir_ref ref;
13222 			ir_refs *found_inputs, *found_values;
13223 
13224 			ir_refs_init(found_inputs, 8);
13225 			ir_refs_init(found_values, 8);
13226 
13227 			var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13228 			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13229 				var_info |= MAY_BE_REF;
13230 			}
13231 			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13232 				var_info |= MAY_BE_RC1;
13233 			}
13234 
13235 			if (dim_type != IS_UNKNOWN
13236 			 && dim_type != IS_UNDEF
13237 			 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13238 			 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13239 			 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13240 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13241 				not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13242 				if (!not_found_exit_addr) {
13243 					return 0;
13244 				}
13245 			}
13246 
13247 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13248 					op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13249 					0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13250 				return 0;
13251 			}
13252 
13253 			if (found_inputs->count) {
13254 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
13255 				ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13256 				var_addr = ZEND_ADDR_REF_ZVAL(ref);
13257 
13258 				if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13259 					jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13260 					var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13261 				}
13262 				if (var_info & MAY_BE_REF) {
13263 					binary_op_type binary_op = get_binary_op(opline->extended_value);
13264 					ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13265 
13266 					ref = jit_ZVAL_ADDR(jit, var_addr);
13267 					if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13268 					ir_IF_FALSE(if_ref);
13269 					noref_path = ir_END();
13270 					ir_IF_TRUE(if_ref);
13271 
13272 					reference = jit_Z_PTR_ref(jit, ref);
13273 					ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13274 					if_typed = jit_if_TYPED_REF(jit, reference);
13275 					ir_IF_FALSE(if_typed);
13276 					ref_path = ir_END();
13277 					ir_IF_TRUE_cold(if_typed);
13278 
13279 					arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13280 					ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13281 						reference, arg2, ir_CONST_FC_FUNC(binary_op));
13282 
13283 					ir_END_list(end_inputs);
13284 
13285 					ir_MERGE_2(noref_path, ref_path);
13286 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
13287 					var_addr = ZEND_ADDR_REF_ZVAL(ref);
13288 				}
13289 			} else {
13290 				emit_fast_path = 0;
13291 			}
13292 		}
13293 
13294 		if (emit_fast_path) {
13295 			uint8_t val_op_type = (opline+1)->op1_type;
13296 
13297 			if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13298 				/* prevent FREE_OP in the helpers */
13299 				val_op_type = IS_CV;
13300 			}
13301 
13302 			switch (opline->extended_value) {
13303 				case ZEND_ADD:
13304 				case ZEND_SUB:
13305 				case ZEND_MUL:
13306 				case ZEND_DIV:
13307 					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,
13308 							1 /* may overflow */, may_throw)) {
13309 						return 0;
13310 					}
13311 					break;
13312 				case ZEND_BW_OR:
13313 				case ZEND_BW_AND:
13314 				case ZEND_BW_XOR:
13315 				case ZEND_SL:
13316 				case ZEND_SR:
13317 				case ZEND_MOD:
13318 					if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13319 							IS_CV, opline->op1, var_addr, var_info, NULL,
13320 							val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13321 							op1_data_range,
13322 							0, var_addr, var_def_info, var_info, may_throw)) {
13323 						return 0;
13324 					}
13325 					break;
13326 				case ZEND_CONCAT:
13327 					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,
13328 							may_throw)) {
13329 						return 0;
13330 					}
13331 					break;
13332 				default:
13333 					ZEND_UNREACHABLE();
13334 			}
13335 
13336 			ir_END_list(end_inputs);
13337 		}
13338 	}
13339 
13340 	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13341 		binary_op_type binary_op;
13342 		ir_ref arg2;
13343 
13344 		if (if_type) {
13345 			ir_IF_FALSE_cold(if_type);
13346 			if_type = IS_UNUSED;
13347 		}
13348 
13349 	    if (opline->op2_type == IS_UNUSED) {
13350 			arg2 = IR_NULL;
13351 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13352 			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13353 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13354 		} else {
13355 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13356 		}
13357 		binary_op = get_binary_op(opline->extended_value);
13358 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13359 			jit_ZVAL_ADDR(jit, op1_addr),
13360 			arg2,
13361 			jit_ZVAL_ADDR(jit, op3_addr),
13362 			ir_CONST_FC_FUNC(binary_op));
13363 		ir_END_list(end_inputs);
13364 	}
13365 
13366 	if (end_inputs) {
13367 		ir_MERGE_list(end_inputs);
13368 	}
13369 
13370 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13371 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13372 	if (may_throw) {
13373 		zend_jit_check_exception(jit);
13374 	}
13375 
13376 	return 1;
13377 }
13378 
13379 static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13380 {
13381 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13382 
13383 	// JIT: ZVAL_COPY(res, value);
13384 	if (opline->op1_type == IS_CONST) {
13385 		zval *zv = RT_CONSTANT(opline, opline->op1);
13386 
13387 		jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
13388 	} else {
13389 		zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13390 
13391 		jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13392 	}
13393 
13394 	// JIT: Z_FE_POS_P(res) = 0;
13395 	ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13396 
13397 	return 1;
13398 }
13399 
13400 static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13401 {
13402 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13403 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13404 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13405 	ir_ref ref;
13406 
13407 	if (!exit_addr) {
13408 		return 0;
13409 	}
13410 
13411 	ref = ir_AND_U32(
13412 		ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
13413 		ir_CONST_U32(HASH_FLAG_PACKED));
13414 	if (op_info & MAY_BE_ARRAY_PACKED) {
13415 		ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13416 	} else {
13417 		ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
13418 	}
13419 
13420 	return 1;
13421 }
13422 
13423 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)
13424 {
13425 	zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13426 	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;
13427 	ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
13428 	ir_ref exit_inputs = IR_UNUSED;
13429 
13430 	if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
13431 		/* empty array */
13432 		if (exit_addr) {
13433 			if (exit_opcode == ZEND_JMP) {
13434 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13435 			}
13436 		} else {
13437 			zend_basic_block *bb;
13438 
13439 			ZEND_ASSERT(jit->b >= 0);
13440 			bb = &jit->ssa->cfg.blocks[jit->b];
13441 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
13442 			jit->b = -1;
13443 		}
13444 		return 1;
13445 	}
13446 
13447 	// JIT: array = EX_VAR(opline->op1.var);
13448 	// JIT: fe_ht = Z_ARRVAL_P(array);
13449 	ht_ref = jit_Z_PTR(jit, op1_addr);
13450 
13451 	if (op1_info & MAY_BE_PACKED_GUARD) {
13452 		if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
13453 			return 0;
13454 		}
13455 	}
13456 
13457 	// JIT: pos = Z_FE_POS_P(array);
13458 	hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
13459 
13460 	if (MAY_BE_HASH(op1_info)) {
13461 		ir_ref loop_ref, pos2_ref, p2_ref;
13462 
13463 		if (MAY_BE_PACKED(op1_info)) {
13464 			ref = ir_AND_U32(
13465 				ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
13466 				ir_CONST_U32(HASH_FLAG_PACKED));
13467 			if_packed = ir_IF(ref);
13468 			ir_IF_FALSE(if_packed);
13469 		}
13470 
13471 		// JIT: p = fe_ht->arData + pos;
13472 		if (sizeof(void*) == 8) {
13473 			ref = ir_ZEXT_A(hash_pos_ref);
13474 		} else {
13475 			ref = ir_BITCAST_A(hash_pos_ref);
13476 		}
13477 		hash_p_ref = ir_ADD_A(
13478 			ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
13479 			ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
13480 
13481 		loop_ref = ir_LOOP_BEGIN(ir_END());
13482 		hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
13483 		hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
13484 
13485 		// JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13486 		ref = ir_ULT(hash_pos_ref,
13487 			ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13488 
13489 		// JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13490 		// JIT: ZEND_VM_CONTINUE();
13491 
13492 		if (exit_addr) {
13493 			if (exit_opcode == ZEND_JMP) {
13494 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13495 			} else {
13496 				ir_ref if_fit = ir_IF(ref);
13497 				ir_IF_FALSE(if_fit);
13498 				ir_END_list(exit_inputs);
13499 				ir_IF_TRUE(if_fit);
13500 			}
13501 		} else {
13502 			ir_ref if_fit = ir_IF(ref);
13503 			ir_IF_FALSE(if_fit);
13504 			ir_END_list(exit_inputs);
13505 			ir_IF_TRUE(if_fit);
13506 		}
13507 
13508 		// JIT: pos++;
13509 		pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
13510 
13511 		// JIT: value_type = Z_TYPE_INFO_P(value);
13512 		// JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13513 		if (!exit_addr || exit_opcode == ZEND_JMP) {
13514 			if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
13515 			ir_IF_FALSE(if_def_hash);
13516 		} else {
13517 			ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
13518 		}
13519 
13520 		// JIT: p++;
13521 		p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
13522 
13523 		ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13524 		ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
13525 		ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
13526 
13527 		if (MAY_BE_PACKED(op1_info)) {
13528 			ir_IF_TRUE(if_packed);
13529 		}
13530 	}
13531 	if (MAY_BE_PACKED(op1_info)) {
13532 		ir_ref loop_ref, pos2_ref, p2_ref;
13533 
13534 		// JIT: p = fe_ht->arPacked + pos;
13535 		if (sizeof(void*) == 8) {
13536 			ref = ir_ZEXT_A(packed_pos_ref);
13537 		} else {
13538 			ref = ir_BITCAST_A(packed_pos_ref);
13539 		}
13540 		packed_p_ref = ir_ADD_A(
13541 			ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
13542 			ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
13543 
13544 		loop_ref = ir_LOOP_BEGIN(ir_END());
13545 		packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
13546 		packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
13547 
13548 		// JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13549 		ref = ir_ULT(packed_pos_ref,
13550 			ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13551 
13552 		// JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13553 		// JIT: ZEND_VM_CONTINUE();
13554 		if (exit_addr) {
13555 			if (exit_opcode == ZEND_JMP) {
13556 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13557 			} else {
13558 				ir_ref if_fit = ir_IF(ref);
13559 				ir_IF_FALSE(if_fit);
13560 				ir_END_list(exit_inputs);
13561 				ir_IF_TRUE(if_fit);
13562 			}
13563 		} else {
13564 			ir_ref if_fit = ir_IF(ref);
13565 			ir_IF_FALSE(if_fit);
13566 			ir_END_list(exit_inputs);
13567 			ir_IF_TRUE(if_fit);
13568 		}
13569 
13570 		// JIT: pos++;
13571 		pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
13572 
13573 		// JIT: value_type = Z_TYPE_INFO_P(value);
13574 		// JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13575 		if (!exit_addr || exit_opcode == ZEND_JMP) {
13576 			if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
13577 			ir_IF_FALSE(if_def_packed);
13578 		} else {
13579 			ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
13580 		}
13581 
13582 		// JIT: p++;
13583 		p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
13584 
13585 		ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13586 		ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
13587 		ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
13588 	}
13589 
13590 	if (!exit_addr || exit_opcode == ZEND_JMP) {
13591 		zend_jit_addr val_addr;
13592 		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
13593 		uint32_t val_info;
13594 		ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
13595 
13596 		if (RETURN_VALUE_USED(opline)) {
13597 			zend_jit_addr res_addr = RES_ADDR();
13598 
13599 			if (MAY_BE_HASH(op1_info)) {
13600 				ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
13601 
13602 				ZEND_ASSERT(if_def_hash);
13603 				ir_IF_TRUE(if_def_hash);
13604 
13605 				// JIT: Z_FE_POS_P(array) = pos + 1;
13606 				ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13607 					ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
13608 
13609 				if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13610 					key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
13611 				}
13612 				if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
13613 				 && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
13614 					// JIT: if (!p->key) {
13615 					if_key = ir_IF(key_ref);
13616 					ir_IF_TRUE(if_key);
13617 				}
13618 				if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13619 					ir_ref if_interned, interned_path;
13620 
13621 					// JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
13622 					jit_set_Z_PTR(jit, res_addr, key_ref);
13623 					ref = ir_AND_U32(
13624 						ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
13625 						ir_CONST_U32(IS_STR_INTERNED));
13626 					if_interned = ir_IF(ref);
13627 					ir_IF_TRUE(if_interned);
13628 
13629 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
13630 
13631 					interned_path = ir_END();
13632 					ir_IF_FALSE(if_interned);
13633 
13634 					jit_GC_ADDREF(jit, key_ref);
13635 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
13636 
13637 					ir_MERGE_WITH(interned_path);
13638 
13639 					if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13640 						key_path = ir_END();
13641 					}
13642 				}
13643 				if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13644 					if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13645 						ir_IF_FALSE(if_key);
13646 					}
13647 					// JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
13648 					ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
13649 					jit_set_Z_LVAL(jit, res_addr, ref);
13650 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13651 
13652 					if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13653 						ir_MERGE_WITH(key_path);
13654 					}
13655 				}
13656 				if (MAY_BE_PACKED(op1_info)) {
13657 					hash_path = ir_END();
13658 				} else {
13659 					p_ref = hash_p_ref;
13660 				}
13661 			}
13662 			if (MAY_BE_PACKED(op1_info)) {
13663 				ZEND_ASSERT(if_def_packed);
13664 				ir_IF_TRUE(if_def_packed);
13665 
13666 				// JIT: Z_FE_POS_P(array) = pos + 1;
13667 				ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13668 					ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
13669 
13670 				// JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
13671 				if (sizeof(zend_long) == 8) {
13672 					packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
13673 				} else {
13674 					packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
13675 				}
13676 				jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
13677 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13678 
13679 				if (MAY_BE_HASH(op1_info)) {
13680 					ir_MERGE_WITH(hash_path);
13681 					p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
13682 				} else {
13683 					p_ref = packed_p_ref;
13684 				}
13685 			}
13686 		} else {
13687 			ir_ref pos_ref = IR_UNUSED;
13688 
13689 			if (if_def_hash && if_def_packed) {
13690 				ir_IF_TRUE(if_def_hash);
13691 				ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
13692 				pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
13693 				p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
13694 			} else if (if_def_hash) {
13695 				ir_IF_TRUE(if_def_hash);
13696 				pos_ref = hash_pos_ref;
13697 				p_ref = hash_p_ref;
13698 			} else if (if_def_packed) {
13699 				ir_IF_TRUE(if_def_packed);
13700 				pos_ref = packed_pos_ref;
13701 				p_ref = packed_p_ref;
13702 			} else {
13703 				ZEND_UNREACHABLE();
13704 			}
13705 
13706 			// JIT: Z_FE_POS_P(array) = pos + 1;
13707 			ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13708 				ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
13709 		}
13710 
13711 		val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
13712 		if (val_info & MAY_BE_ARRAY) {
13713 			val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13714 		}
13715 		if (op1_info & MAY_BE_ARRAY_OF_REF) {
13716 			val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
13717 				MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13718 		} else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13719 			val_info |= MAY_BE_RC1 | MAY_BE_RCN;
13720 		}
13721 
13722 		val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
13723 		if (opline->op2_type == IS_CV) {
13724 			// JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
13725 			if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, 1)) {
13726 				return 0;
13727 			}
13728 		} else {
13729 			// JIT: ZVAL_COPY(res, value);
13730 			jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, 1);
13731 		}
13732 
13733 		if (!exit_addr) {
13734 			zend_basic_block *bb;
13735 
13736 			ZEND_ASSERT(jit->b >= 0);
13737 			bb = &jit->ssa->cfg.blocks[jit->b];
13738 			_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
13739 			ZEND_ASSERT(exit_inputs);
13740 			if (!jit->ctx.ir_base[exit_inputs].op2) {
13741 				ref = exit_inputs;
13742 			} else {
13743 				ir_MERGE_list(exit_inputs);
13744 				ref = ir_END();
13745 			}
13746 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
13747 			jit->b = -1;
13748 		}
13749 	} else {
13750 		ZEND_ASSERT(exit_inputs);
13751 		ir_MERGE_list(exit_inputs);
13752 	}
13753 
13754 	return 1;
13755 }
13756 
13757 static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
13758 {
13759 	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13760 	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13761 	ir_ref ref = jit_Z_PTR(jit, this_addr);
13762 
13763 	jit_set_Z_PTR(jit, var_addr, ref);
13764 	jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
13765 	jit_GC_ADDREF(jit, ref);
13766 
13767 	return 1;
13768 }
13769 
13770 static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
13771 {
13772 	if (!op_array->scope ||
13773 			(op_array->fn_flags & ZEND_ACC_STATIC) ||
13774 			((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) {
13775 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13776 			if (!JIT_G(current_frame) ||
13777 			    !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
13778 
13779 				zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13780 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13781 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13782 
13783 				if (!exit_addr) {
13784 					return 0;
13785 				}
13786 
13787 				jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
13788 
13789 				if (JIT_G(current_frame)) {
13790 					TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
13791 				}
13792 			}
13793 		} else {
13794 			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13795 			ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
13796 
13797 			ir_IF_FALSE_cold(if_object);
13798 			jit_SET_EX_OPLINE(jit, opline);
13799 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
13800 
13801 			ir_IF_TRUE(if_object);
13802 		}
13803 	}
13804 
13805 	if (!check_only) {
13806 		if (!zend_jit_load_this(jit, opline->result.var)) {
13807 			return 0;
13808 		}
13809 	}
13810 
13811 	return 1;
13812 }
13813 
13814 static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
13815 {
13816 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13817 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13818 
13819 	if (!exit_addr) {
13820 		return 0;
13821 	}
13822 
13823 	ir_GUARD(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce))), ir_CONST_ADDR(ce)),
13824 		ir_CONST_ADDR(exit_addr));
13825 
13826 	return 1;
13827 }
13828 
13829 static int zend_jit_fetch_obj(zend_jit_ctx         *jit,
13830                               const zend_op        *opline,
13831                               const zend_op_array  *op_array,
13832                               zend_ssa             *ssa,
13833                               const zend_ssa_op    *ssa_op,
13834                               uint32_t              op1_info,
13835                               zend_jit_addr         op1_addr,
13836                               bool                  op1_indirect,
13837                               zend_class_entry     *ce,
13838                               bool                  ce_is_instanceof,
13839                               bool                  on_this,
13840                               bool                  delayed_fetch_this,
13841                               bool                  op1_avoid_refcounting,
13842                               zend_class_entry     *trace_ce,
13843                               zend_jit_addr         res_addr,
13844                               uint8_t               prop_type,
13845                               int                   may_throw)
13846 {
13847 	zval *member;
13848 	zend_property_info *prop_info;
13849 	bool may_be_dynamic = 1;
13850 	zend_jit_addr prop_addr;
13851 	uint32_t res_info = RES_INFO();
13852 	ir_ref prop_type_ref = IR_UNUSED;
13853 	ir_ref obj_ref = IR_UNUSED;
13854 	ir_ref prop_ref = IR_UNUSED;
13855 	ir_ref end_inputs = IR_UNUSED;
13856 	ir_ref slow_inputs = IR_UNUSED;
13857 	ir_ref end_values = IR_UNUSED;
13858 
13859 	ZEND_ASSERT(opline->op2_type == IS_CONST);
13860 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
13861 
13862 	member = RT_CONSTANT(opline, opline->op2);
13863 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
13864 	prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
13865 
13866 	if (on_this) {
13867 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13868 		obj_ref = jit_Z_PTR(jit, this_addr);
13869 	} else {
13870 		if (opline->op1_type == IS_VAR
13871 		 && opline->opcode == ZEND_FETCH_OBJ_W
13872 		 && (op1_info & MAY_BE_INDIRECT)
13873 		 && Z_REG(op1_addr) == ZREG_FP) {
13874 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
13875 		}
13876 		if (op1_info & MAY_BE_REF) {
13877 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
13878 		}
13879 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
13880 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13881 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13882 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13883 
13884 				if (!exit_addr) {
13885 					return 0;
13886 				}
13887 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
13888 			} else {
13889 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
13890 
13891 				ir_IF_FALSE_cold(if_obj);
13892 				if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13893 					ir_ref op1_ref = IR_UNUSED;
13894 
13895 					jit_SET_EX_OPLINE(jit, opline);
13896 					if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
13897 						zend_jit_addr orig_op1_addr = OP1_ADDR();
13898 						ir_ref fast_path = IR_UNUSED;
13899 
13900 						if (op1_info & MAY_BE_ANY) {
13901 							ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
13902 							ir_IF_TRUE(if_def);
13903 							fast_path = ir_END();
13904 							ir_IF_FALSE_cold(if_def);
13905 						}
13906 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
13907 							ir_CONST_U32(opline->op1.var));
13908 						if (fast_path) {
13909 							ir_MERGE_WITH(fast_path);
13910 						}
13911 						op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
13912 					} else {
13913 						op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
13914 					}
13915 					if (opline->opcode == ZEND_FETCH_OBJ_W) {
13916 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
13917 							op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
13918 						jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
13919 					} else {
13920 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
13921 							op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
13922 						jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13923 					}
13924 				} else {
13925 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13926 				}
13927 				ir_END_list(end_inputs);
13928 
13929 				ir_IF_TRUE(if_obj);
13930 			}
13931 		}
13932 		obj_ref = jit_Z_PTR(jit, op1_addr);
13933 	}
13934 
13935 	ZEND_ASSERT(obj_ref);
13936 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
13937 		prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
13938 		if (prop_info) {
13939 			ce = trace_ce;
13940 			ce_is_instanceof = 0;
13941 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
13942 				if (on_this && JIT_G(current_frame)
13943 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
13944 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
13945 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
13946 					if (on_this && JIT_G(current_frame)) {
13947 						JIT_G(current_frame)->ce = ce;
13948 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
13949 					}
13950 				} else {
13951 					return 0;
13952 				}
13953 				if (ssa->var_info && ssa_op->op1_use >= 0) {
13954 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
13955 					ssa->var_info[ssa_op->op1_use].ce = ce;
13956 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
13957 				}
13958 			}
13959 		}
13960 	}
13961 
13962 	if (!prop_info) {
13963 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
13964 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
13965 		ir_ref if_same = ir_IF(ir_EQ(ref,
13966 			ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
13967 
13968 		ir_IF_FALSE_cold(if_same);
13969 		ir_END_list(slow_inputs);
13970 
13971 		ir_IF_TRUE(if_same);
13972 		ir_ref offset_ref = ir_LOAD_A(
13973 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
13974 
13975 		may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array);
13976 		if (may_be_dynamic) {
13977 			ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
13978 			if (opline->opcode == ZEND_FETCH_OBJ_W) {
13979 				ir_IF_TRUE_cold(if_dynamic);
13980 				ir_END_list(slow_inputs);
13981 			} else {
13982 				ir_IF_TRUE_cold(if_dynamic);
13983 				jit_SET_EX_OPLINE(jit, opline);
13984 
13985 				if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13986 					if (Z_MODE(res_addr) == IS_REG) {
13987 						ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
13988 							obj_ref, offset_ref);
13989 						ir_END_PHI_list(end_values, val_addr);
13990 					} else {
13991 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
13992 							obj_ref, offset_ref);
13993 						ir_END_list(end_inputs);
13994 					}
13995 				} else {
13996 					if (Z_MODE(res_addr) == IS_REG) {
13997 						ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
13998 							obj_ref, offset_ref);
13999 						ir_END_PHI_list(end_values, val_addr);
14000 					} else {
14001 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
14002 							obj_ref, offset_ref);
14003 						ir_END_list(end_inputs);
14004 					}
14005 				}
14006 			}
14007 			ir_IF_FALSE(if_dynamic);
14008 		}
14009 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14010 		prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
14011 		ir_ref if_def = ir_IF(prop_type_ref);
14012 		ir_IF_FALSE_cold(if_def);
14013 		ir_END_list(slow_inputs);
14014 		ir_IF_TRUE(if_def);
14015 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14016 		if (opline->opcode == ZEND_FETCH_OBJ_W
14017 		 && (!ce ||	ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
14018 			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14019 
14020 			ir_ref allowed_inputs = IR_UNUSED;
14021 			ir_ref forbidden_inputs = IR_UNUSED;
14022 
14023 			ir_ref prop_info_ref = ir_LOAD_A(
14024 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14025 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14026 
14027 			ir_IF_TRUE_cold(if_has_prop_info);
14028 
14029 			ir_ref prop_flags = ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags)));
14030 			ir_ref if_readonly_or_avis = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK)));
14031 
14032 			ir_IF_FALSE(if_readonly_or_avis);
14033 			ir_END_list(allowed_inputs);
14034 
14035 			ir_IF_TRUE_cold(if_readonly_or_avis);
14036 
14037 			ir_ref if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14038 			ir_IF_TRUE(if_readonly);
14039 			ir_END_list(forbidden_inputs);
14040 
14041 			ir_IF_FALSE(if_readonly);
14042 			ir_ref has_avis_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), prop_info_ref);
14043 			ir_ref if_avis_access = ir_IF(has_avis_access);
14044 			ir_IF_TRUE(if_avis_access);
14045 			ir_END_list(allowed_inputs);
14046 
14047 			ir_IF_FALSE(if_avis_access);
14048 			ir_END_list(forbidden_inputs);
14049 
14050 			ir_MERGE_list(forbidden_inputs);
14051 
14052 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14053 			ir_IF_TRUE(if_prop_obj);
14054 			ref = jit_Z_PTR(jit, prop_addr);
14055 			jit_GC_ADDREF(jit, ref);
14056 			jit_set_Z_PTR(jit, res_addr, ref);
14057 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14058 			ir_END_list(end_inputs);
14059 
14060 			ir_IF_FALSE_cold(if_prop_obj);
14061 
14062 			jit_SET_EX_OPLINE(jit, opline);
14063 			if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14064 			ir_IF_TRUE(if_readonly);
14065 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), prop_info_ref);
14066 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14067 			ir_END_list(end_inputs);
14068 
14069 			ir_IF_FALSE(if_readonly);
14070 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14071 				prop_info_ref, ir_CONST_ADDR("indirectly modify"));
14072 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14073 			ir_END_list(end_inputs);
14074 
14075 			ir_MERGE_list(allowed_inputs);
14076 
14077 			if (flags == ZEND_FETCH_DIM_WRITE) {
14078 				jit_SET_EX_OPLINE(jit, opline);
14079 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14080 					prop_ref, prop_info_ref);
14081 				ir_END_list(end_inputs);
14082 				ir_IF_FALSE(if_has_prop_info);
14083 			} else if (flags == ZEND_FETCH_REF) {
14084 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14085 					prop_ref,
14086 					prop_info_ref,
14087 					jit_ZVAL_ADDR(jit, res_addr));
14088 				ir_END_list(end_inputs);
14089 				ir_IF_FALSE(if_has_prop_info);
14090 			} else {
14091 				ZEND_ASSERT(flags == 0);
14092 				ir_MERGE_WITH_EMPTY_FALSE(if_has_prop_info);
14093 			}
14094 		}
14095 	} else {
14096 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14097 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14098 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14099 			if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14100 				/* perform IS_UNDEF check only after result type guard (during deoptimization) */
14101 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14102 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14103 
14104 				if (!exit_addr) {
14105 					return 0;
14106 				}
14107 				prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14108 				ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14109 			}
14110 		} else {
14111 			prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14112 			ir_ref if_def = ir_IF(prop_type_ref);
14113 			ir_IF_FALSE_cold(if_def);
14114 			ir_END_list(slow_inputs);
14115 			ir_IF_TRUE(if_def);
14116 		}
14117 		if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14118 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14119 			ir_IF_TRUE(if_prop_obj);
14120 			ir_ref ref = jit_Z_PTR(jit, prop_addr);
14121 			jit_GC_ADDREF(jit, ref);
14122 			jit_set_Z_PTR(jit, res_addr, ref);
14123 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14124 			ir_END_list(end_inputs);
14125 
14126 			ir_IF_FALSE_cold(if_prop_obj);
14127 			jit_SET_EX_OPLINE(jit, opline);
14128 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), ir_CONST_ADDR(prop_info));
14129 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14130 			ir_END_list(end_inputs);
14131 
14132 			goto result_fetched;
14133 		} else if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)) {
14134 			/* Readonly properties which are also asymmetric are never mutable indirectly, which is
14135 			 * handled by the previous branch. */
14136 			ir_ref has_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), ir_CONST_ADDR(prop_info));
14137 
14138 			ir_ref if_access = ir_IF(has_access);
14139 			ir_IF_FALSE_cold(if_access);
14140 
14141 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14142 			ir_IF_TRUE(if_prop_obj);
14143 			ir_ref ref = jit_Z_PTR(jit, prop_addr);
14144 			jit_GC_ADDREF(jit, ref);
14145 			jit_set_Z_PTR(jit, res_addr, ref);
14146 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14147 			ir_END_list(end_inputs);
14148 
14149 			ir_IF_FALSE_cold(if_prop_obj);
14150 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14151 				ir_CONST_ADDR(prop_info), ir_CONST_ADDR("indirectly modify"));
14152 			ir_END_list(end_inputs);
14153 
14154 			ir_IF_TRUE(if_access);
14155 		}
14156 
14157 		if (opline->opcode == ZEND_FETCH_OBJ_W
14158 		 && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
14159 		 && ZEND_TYPE_IS_SET(prop_info->type)) {
14160 			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14161 
14162 			if (flags == ZEND_FETCH_DIM_WRITE) {
14163 				if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14164 					if (!prop_type_ref) {
14165 						prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14166 					}
14167 					ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14168 					ir_IF_TRUE_cold(if_null_or_flase);
14169 					jit_SET_EX_OPLINE(jit, opline);
14170 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14171 						prop_ref, ir_CONST_ADDR(prop_info));
14172 					ir_END_list(end_inputs);
14173 					ir_IF_FALSE(if_null_or_flase);
14174 				}
14175 			} else if (flags == ZEND_FETCH_REF) {
14176 				ir_ref ref;
14177 
14178 				if (!prop_type_ref) {
14179 					prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14180 				}
14181 
14182 				ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14183 				ir_IF_FALSE(if_reference);
14184 				if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14185 					ref = ir_CONST_ADDR(prop_info);
14186 				} else {
14187 					int prop_info_offset =
14188 						(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14189 
14190 					ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14191 					ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14192 					ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14193 				}
14194 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14195 					prop_ref,
14196 					ref,
14197 					jit_ZVAL_ADDR(jit, res_addr));
14198 				ir_END_list(end_inputs);
14199 				ir_IF_TRUE(if_reference);
14200 			} else {
14201 				ZEND_UNREACHABLE();
14202 			}
14203 		}
14204 	}
14205 
14206 	if (opline->opcode == ZEND_FETCH_OBJ_W) {
14207 		ZEND_ASSERT(prop_ref);
14208 		jit_set_Z_PTR(jit, res_addr, prop_ref);
14209 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14210 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14211 			ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14212 		}
14213 		ir_END_list(end_inputs);
14214 	} else {
14215 		if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
14216 		 || Z_MODE(res_addr) == IS_REG) {
14217 			ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14218 		} else {
14219 			prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14220 
14221 			if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14222 				return 0;
14223 			}
14224 			ir_END_list(end_inputs);
14225 		}
14226 	}
14227 
14228 result_fetched:
14229 	if (op1_avoid_refcounting) {
14230 		SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14231 	}
14232 
14233 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14234 		ir_MERGE_list(slow_inputs);
14235 		jit_SET_EX_OPLINE(jit, opline);
14236 
14237 		if (opline->opcode == ZEND_FETCH_OBJ_W) {
14238 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14239 			ir_END_list(end_inputs);
14240 		} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14241 			if (Z_MODE(res_addr) == IS_REG) {
14242 				ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14243 				ir_END_PHI_list(end_values, val_ref);
14244 			} else {
14245 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14246 				ir_END_list(end_inputs);
14247 			}
14248 		} else {
14249 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14250 			ir_END_list(end_inputs);
14251 		}
14252 	}
14253 
14254 	if (end_values) {
14255 		ir_ref val_ref = ir_PHI_list(end_values);
14256 		zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14257 		bool result_avoid_refcounting = 0;
14258 
14259 		ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14260 			|| opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14261 			|| opline->opcode == ZEND_FETCH_OBJ_IS);
14262 		ZEND_ASSERT(end_inputs == IR_UNUSED);
14263 		if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14264 			uint8_t type = concrete_type(res_info);
14265 			uint32_t flags = 0;
14266 
14267 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14268 			 && !delayed_fetch_this
14269 			 && !op1_avoid_refcounting) {
14270 				flags = ZEND_JIT_EXIT_FREE_OP1;
14271 			}
14272 
14273 			if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14274 			 && !(flags & ZEND_JIT_EXIT_FREE_OP1)
14275 			 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
14276 			 && (ssa_op+1)->op1_use == ssa_op->result_def
14277 			 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14278 				result_avoid_refcounting = 1;
14279 				ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14280 			}
14281 
14282 			val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14283 				1, flags, op1_avoid_refcounting);
14284 			if (!val_addr) {
14285 				return 0;
14286 			}
14287 
14288 			res_info &= ~MAY_BE_GUARD;
14289 			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14290 		}
14291 
14292 		// ZVAL_COPY
14293 		jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14294 
14295 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14296 			return 0;
14297 		}
14298 	} else {
14299 		ir_MERGE_list(end_inputs);
14300 	}
14301 
14302 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14303 		if (opline->op1_type == IS_VAR
14304 		 && opline->opcode == ZEND_FETCH_OBJ_W
14305 		 && (op1_info & MAY_BE_RC1)) {
14306 			zend_jit_addr orig_op1_addr = OP1_ADDR();
14307 			ir_ref if_refcounted, ptr, refcount, if_non_zero;
14308 			ir_ref merge_inputs = IR_UNUSED;
14309 
14310 			if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14311 			ir_IF_FALSE( if_refcounted);
14312 			ir_END_list(merge_inputs);
14313 			ir_IF_TRUE( if_refcounted);
14314 			ptr = jit_Z_PTR(jit, orig_op1_addr);
14315 			refcount = jit_GC_DELREF(jit, ptr);
14316 			if_non_zero = ir_IF(refcount);
14317 			ir_IF_TRUE( if_non_zero);
14318 			ir_END_list(merge_inputs);
14319 			ir_IF_FALSE( if_non_zero);
14320 			jit_SET_EX_OPLINE(jit, opline);
14321 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14322 			ir_END_list(merge_inputs);
14323 			ir_MERGE_list(merge_inputs);
14324 		} else if (!op1_avoid_refcounting) {
14325 			if (on_this) {
14326 				op1_info &= ~MAY_BE_RC1;
14327 			}
14328 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14329 		}
14330 	}
14331 
14332 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14333 	 && prop_info
14334 	 && (opline->opcode != ZEND_FETCH_OBJ_W ||
14335 	     !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14336 	     !ZEND_TYPE_IS_SET(prop_info->type))
14337 	 && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14338 		may_throw = 0;
14339 	}
14340 
14341 	if (may_throw) {
14342 		zend_jit_check_exception(jit);
14343 	}
14344 
14345 	return 1;
14346 }
14347 
14348 static int zend_jit_assign_obj(zend_jit_ctx         *jit,
14349                                const zend_op        *opline,
14350                                const zend_op_array  *op_array,
14351                                zend_ssa             *ssa,
14352                                const zend_ssa_op    *ssa_op,
14353                                uint32_t              op1_info,
14354                                zend_jit_addr         op1_addr,
14355                                uint32_t              val_info,
14356                                zend_jit_addr         val_addr,
14357                                zend_jit_addr         val_def_addr,
14358                                zend_jit_addr         res_addr,
14359                                bool                  op1_indirect,
14360                                zend_class_entry     *ce,
14361                                bool                  ce_is_instanceof,
14362                                bool                  on_this,
14363                                bool                  delayed_fetch_this,
14364                                zend_class_entry     *trace_ce,
14365                                uint8_t               prop_type,
14366                                int                   may_throw)
14367 {
14368 	zval *member;
14369 	zend_string *name;
14370 	zend_property_info *prop_info;
14371 	zend_jit_addr prop_addr;
14372 	ir_ref obj_ref = IR_UNUSED;
14373 	ir_ref prop_ref = IR_UNUSED;
14374 	ir_ref delayed_end_input = IR_UNUSED;
14375 	ir_ref end_inputs = IR_UNUSED;
14376 	ir_ref slow_inputs = IR_UNUSED;
14377 	uint32_t res_info = RES_INFO();
14378 
14379 	if (val_addr != val_def_addr && val_def_addr) {
14380 		if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14381 			return 0;
14382 		}
14383 		if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14384 			val_addr = val_def_addr;
14385 		}
14386 	}
14387 
14388 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14389 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14390 
14391 	member = RT_CONSTANT(opline, opline->op2);
14392 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14393 	name = Z_STR_P(member);
14394 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14395 
14396 	if (on_this) {
14397 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14398 		obj_ref = jit_Z_PTR(jit, this_addr);
14399 	} else {
14400 		if (opline->op1_type == IS_VAR
14401 		 && (op1_info & MAY_BE_INDIRECT)
14402 		 && Z_REG(op1_addr) == ZREG_FP) {
14403 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14404 		}
14405 		if (op1_info & MAY_BE_REF) {
14406 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14407 		}
14408 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14409 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14410 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14411 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14412 
14413 				if (!exit_addr) {
14414 					return 0;
14415 				}
14416 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14417 			} else {
14418 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14419 				ir_IF_FALSE_cold(if_obj);
14420 
14421 				jit_SET_EX_OPLINE(jit, opline);
14422 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14423 					jit_ZVAL_ADDR(jit, op1_addr),
14424 					ir_CONST_ADDR(ZSTR_VAL(name)));
14425 
14426 				if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
14427 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14428 				}
14429 
14430 				ir_END_list(end_inputs);
14431 
14432 				ir_IF_TRUE(if_obj);
14433 			}
14434 		}
14435 		obj_ref = jit_Z_PTR(jit, op1_addr);
14436 	}
14437 
14438 	ZEND_ASSERT(obj_ref);
14439 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14440 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14441 		if (prop_info) {
14442 			ce = trace_ce;
14443 			ce_is_instanceof = 0;
14444 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14445 				if (on_this && JIT_G(current_frame)
14446 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14447 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14448 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14449 					if (on_this && JIT_G(current_frame)) {
14450 						JIT_G(current_frame)->ce = ce;
14451 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14452 					}
14453 				} else {
14454 					return 0;
14455 				}
14456 				if (ssa->var_info && ssa_op->op1_use >= 0) {
14457 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14458 					ssa->var_info[ssa_op->op1_use].ce = ce;
14459 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14460 				}
14461 				if (ssa->var_info && ssa_op->op1_def >= 0) {
14462 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14463 					ssa->var_info[ssa_op->op1_def].ce = ce;
14464 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14465 				}
14466 			}
14467 		}
14468 	}
14469 
14470 	if (!prop_info) {
14471 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14472 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14473 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14474 
14475 		ir_IF_FALSE_cold(if_same);
14476 		ir_END_list(slow_inputs);
14477 
14478 		ir_IF_TRUE(if_same);
14479 		ir_ref offset_ref = ir_LOAD_A(
14480 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14481 
14482 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14483 		ir_IF_TRUE_cold(if_dynamic);
14484 		ir_END_list(slow_inputs);
14485 
14486 		ir_IF_FALSE(if_dynamic);
14487 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14488 		ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14489 		ir_IF_FALSE_cold(if_def);
14490 		ir_END_list(slow_inputs);
14491 
14492 		ir_IF_TRUE(if_def);
14493 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14494 
14495 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14496 			ir_ref arg3, arg4;
14497 			ir_ref prop_info_ref = ir_LOAD_A(
14498 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14499 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14500 			ir_IF_TRUE_cold(if_has_prop_info);
14501 
14502 			if (Z_MODE(val_addr) == IS_REG) {
14503 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14504 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14505 					return 0;
14506 				}
14507 				arg3 = jit_ZVAL_ADDR(jit, real_addr);
14508 			} else {
14509 				arg3 = jit_ZVAL_ADDR(jit, val_addr);
14510 			}
14511 
14512 			if (!RETURN_VALUE_USED(opline)) {
14513 				arg4 = IR_NULL;
14514 			} else if (Z_MODE(res_addr) == IS_REG) {
14515 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14516 				arg4 = jit_ZVAL_ADDR(jit, real_addr);
14517 			} else {
14518 				arg4 = jit_ZVAL_ADDR(jit, res_addr);
14519 			}
14520 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14521 			jit_SET_EX_OPLINE(jit, opline);
14522 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14523 				prop_ref,
14524 				prop_info_ref,
14525 				arg3,
14526 				arg4);
14527 
14528 			if ((opline+1)->op1_type == IS_CONST) {
14529 				// TODO: ???
14530 				// if (Z_TYPE_P(value) == orig_type) {
14531 				// CACHE_PTR_EX(cache_slot + 2, NULL);
14532 			}
14533 
14534 			if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14535 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14536 				if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14537 					return 0;
14538 				}
14539 			}
14540 
14541 			ir_END_list(end_inputs);
14542 			ir_IF_FALSE(if_has_prop_info);
14543 		}
14544 	} else {
14545 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14546 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14547 		/* With the exception of __clone(), readonly assignment always happens on IS_UNDEF, doding
14548 		 * the fast path. Thus, the fast path is not useful. */
14549 		if (prop_info->flags & ZEND_ACC_READONLY) {
14550 			ZEND_ASSERT(slow_inputs == IR_UNUSED);
14551 			goto slow_path;
14552 		}
14553 		// Undefined property with potential magic __get()/__set() or lazy object
14554 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14555 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14556 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14557 
14558 			if (!exit_addr) {
14559 				return 0;
14560 			}
14561 			ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14562 		} else {
14563 			ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14564 			ir_IF_FALSE_cold(if_def);
14565 			ir_END_list(slow_inputs);
14566 			ir_IF_TRUE(if_def);
14567 		}
14568 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14569 			ir_ref ref, arg3, arg4;
14570 
14571 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14572 			jit_SET_EX_OPLINE(jit, opline);
14573 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14574 				ref = ir_CONST_ADDR(prop_info);
14575 			} else {
14576 				int prop_info_offset =
14577 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14578 
14579 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14580 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14581 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14582 			}
14583 			if (Z_MODE(val_addr) == IS_REG) {
14584 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14585 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14586 					return 0;
14587 				}
14588 				arg3 = jit_ZVAL_ADDR(jit, real_addr);
14589 			} else {
14590 				arg3 = jit_ZVAL_ADDR(jit, val_addr);
14591 			}
14592 			if (!RETURN_VALUE_USED(opline)) {
14593 				arg4 = IR_NULL;
14594 			} else if (Z_MODE(res_addr) == IS_REG) {
14595 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14596 				arg4 = jit_ZVAL_ADDR(jit, real_addr);
14597 			} else {
14598 				arg4 = jit_ZVAL_ADDR(jit, res_addr);
14599 			}
14600 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14601 				prop_ref,
14602 				ref,
14603 				arg3,
14604 				arg4);
14605 
14606 			if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14607 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14608 				if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14609 					return 0;
14610 				}
14611 			}
14612 			ir_END_list(end_inputs);
14613 		}
14614 	}
14615 
14616 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14617 		if (Z_MODE(val_addr) != IS_REG
14618 		 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
14619 		 && opline->result_type == IS_UNUSED) {
14620 			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)) {
14621 				return 0;
14622 			}
14623 		} else {
14624 			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)) {
14625 				return 0;
14626 			}
14627 		}
14628 		if (end_inputs || slow_inputs) {
14629 			if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14630 			 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14631 				/* skip FREE_OP_DATA() */
14632 				delayed_end_input = ir_END();
14633 			} else {
14634 				ir_END_list(end_inputs);
14635 			}
14636 		}
14637 	}
14638 
14639 	if (slow_inputs) {
14640 		ir_ref arg3, arg5;
14641 
14642 		ir_MERGE_list(slow_inputs);
14643 
14644 slow_path:
14645 		jit_SET_EX_OPLINE(jit, opline);
14646 
14647 		if (Z_MODE(val_addr) == IS_REG) {
14648 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14649 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14650 				return 0;
14651 			}
14652 			arg3 = jit_ZVAL_ADDR(jit, real_addr);
14653 		} else {
14654 			arg3 = jit_ZVAL_ADDR(jit, val_addr);
14655 		}
14656 		if (!RETURN_VALUE_USED(opline)) {
14657 			arg5 = IR_NULL;
14658 		} else if (Z_MODE(res_addr) == IS_REG) {
14659 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14660 			arg5 = jit_ZVAL_ADDR(jit, real_addr);
14661 		} else {
14662 			arg5 = jit_ZVAL_ADDR(jit, res_addr);
14663 		}
14664 
14665 		// JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14666 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14667 		ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
14668 			obj_ref,
14669 			ir_CONST_ADDR(name),
14670 			arg3,
14671 			ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
14672 			arg5);
14673 
14674 		if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14675 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14676 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14677 				return 0;
14678 			}
14679 		}
14680 		ir_END_list(end_inputs);
14681 	}
14682 
14683 	if (end_inputs) {
14684 		ir_MERGE_list(end_inputs);
14685 
14686 		if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14687 			val_info |= MAY_BE_RC1|MAY_BE_RCN;
14688 		}
14689 		jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
14690 
14691 		if (delayed_end_input) {
14692 			ir_MERGE_WITH(delayed_end_input);
14693 		}
14694 	}
14695 
14696 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14697 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14698 	}
14699 
14700 	if (may_throw) {
14701 		zend_jit_check_exception(jit);
14702 	}
14703 
14704 	return 1;
14705 }
14706 
14707 static int zend_jit_assign_obj_op(zend_jit_ctx         *jit,
14708                                   const zend_op        *opline,
14709                                   const zend_op_array  *op_array,
14710                                   zend_ssa             *ssa,
14711                                   const zend_ssa_op    *ssa_op,
14712                                   uint32_t              op1_info,
14713                                   zend_jit_addr         op1_addr,
14714                                   uint32_t              val_info,
14715                                   zend_jit_addr         val_addr,
14716                                   zend_ssa_range       *val_range,
14717                                   bool                  op1_indirect,
14718                                   zend_class_entry     *ce,
14719                                   bool                  ce_is_instanceof,
14720                                   bool                  on_this,
14721                                   bool                  delayed_fetch_this,
14722                                   zend_class_entry     *trace_ce,
14723                                   uint8_t               prop_type)
14724 {
14725 	zval *member;
14726 	zend_string *name;
14727 	zend_property_info *prop_info;
14728 	zend_jit_addr prop_addr;
14729 	bool use_prop_guard = 0;
14730 	bool may_throw = 0;
14731 	binary_op_type binary_op = get_binary_op(opline->extended_value);
14732 	ir_ref obj_ref = IR_UNUSED;
14733 	ir_ref prop_ref = IR_UNUSED;
14734 	ir_ref end_inputs = IR_UNUSED;
14735 	ir_ref slow_inputs = IR_UNUSED;
14736 
14737 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14738 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14739 	ZEND_ASSERT(opline->result_type == IS_UNUSED);
14740 
14741 	member = RT_CONSTANT(opline, opline->op2);
14742 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14743 	name = Z_STR_P(member);
14744 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14745 
14746 	if (on_this) {
14747 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14748 		obj_ref = jit_Z_PTR(jit, this_addr);
14749 	} else {
14750 		if (opline->op1_type == IS_VAR
14751 		 && (op1_info & MAY_BE_INDIRECT)
14752 		 && Z_REG(op1_addr) == ZREG_FP) {
14753 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14754 		}
14755 		if (op1_info & MAY_BE_REF) {
14756 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14757 		}
14758 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14759 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14760 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14761 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14762 
14763 				if (!exit_addr) {
14764 					return 0;
14765 				}
14766 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14767 			} else {
14768 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14769 				ir_IF_FALSE_cold(if_obj);
14770 
14771 				jit_SET_EX_OPLINE(jit, opline);
14772 				ir_CALL_2(IR_VOID,
14773 					(op1_info & MAY_BE_UNDEF) ?
14774 						ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
14775 						ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14776 					jit_ZVAL_ADDR(jit, op1_addr),
14777 					ir_CONST_ADDR(ZSTR_VAL(name)));
14778 
14779 				may_throw = 1;
14780 
14781 				ir_END_list(end_inputs);
14782 				ir_IF_TRUE(if_obj);
14783 			}
14784 		}
14785 		obj_ref = jit_Z_PTR(jit, op1_addr);
14786 	}
14787 
14788 	ZEND_ASSERT(obj_ref);
14789 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14790 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14791 		if (prop_info) {
14792 			ce = trace_ce;
14793 			ce_is_instanceof = 0;
14794 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14795 				if (on_this && JIT_G(current_frame)
14796 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14797 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14798 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14799 					if (on_this && JIT_G(current_frame)) {
14800 						JIT_G(current_frame)->ce = ce;
14801 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14802 					}
14803 				} else {
14804 					return 0;
14805 				}
14806 				if (ssa->var_info && ssa_op->op1_use >= 0) {
14807 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14808 					ssa->var_info[ssa_op->op1_use].ce = ce;
14809 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14810 				}
14811 				if (ssa->var_info && ssa_op->op1_def >= 0) {
14812 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14813 					ssa->var_info[ssa_op->op1_def].ce = ce;
14814 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14815 				}
14816 			}
14817 		}
14818 	}
14819 
14820 	use_prop_guard = (prop_type != IS_UNKNOWN
14821 		&& prop_type != IS_UNDEF
14822 		&& prop_type != IS_REFERENCE
14823 		&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
14824 
14825 	if (!prop_info) {
14826 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14827 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14828 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14829 
14830 		ir_IF_FALSE_cold(if_same);
14831 		ir_END_list(slow_inputs);
14832 
14833 		ir_IF_TRUE(if_same);
14834 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14835 			ir_ref prop_info_ref = ir_LOAD_A(
14836 				ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14837 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14838 			ir_IF_TRUE_cold(if_has_prop_info);
14839 			ir_END_list(slow_inputs);
14840 
14841 			ir_IF_FALSE(if_has_prop_info);
14842 		}
14843 		ir_ref offset_ref = ir_LOAD_A(
14844 			ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14845 
14846 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14847 		ir_IF_TRUE_cold(if_dynamic);
14848 		ir_END_list(slow_inputs);
14849 
14850 		ir_IF_FALSE(if_dynamic);
14851 
14852 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14853 		if (!use_prop_guard) {
14854 			ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14855 			ir_IF_FALSE_cold(if_def);
14856 			ir_END_list(slow_inputs);
14857 
14858 			ir_IF_TRUE(if_def);
14859 		}
14860 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14861 	} else {
14862 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14863 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14864 
14865 		if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
14866 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14867 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14868 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14869 
14870 				if (!exit_addr) {
14871 					return 0;
14872 				}
14873 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14874 			} else {
14875 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14876 				ir_IF_FALSE_cold(if_def);
14877 				ir_END_list(slow_inputs);
14878 				ir_IF_TRUE(if_def);
14879 			}
14880 		}
14881 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14882 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
14883 
14884 			may_throw = 1;
14885 
14886 			jit_SET_EX_OPLINE(jit, opline);
14887 
14888 			if (Z_MODE(val_addr) == IS_REG) {
14889 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14890 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14891 					return 0;
14892 				}
14893 				arg2 = jit_ZVAL_ADDR(jit, real_addr);
14894 			} else {
14895 				arg2 = jit_ZVAL_ADDR(jit, val_addr);
14896 			}
14897 
14898 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
14899 			ir_IF_FALSE(if_ref);
14900 			noref_path = ir_END();
14901 			ir_IF_TRUE(if_ref);
14902 
14903 			reference = jit_Z_PTR(jit, prop_addr);
14904 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
14905 			if_typed = jit_if_TYPED_REF(jit, reference);
14906 			ir_IF_FALSE(if_typed);
14907 			ref_path = ir_END();
14908 			ir_IF_TRUE_cold(if_typed);
14909 
14910 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
14911 				reference,
14912 				arg2,
14913 				ir_CONST_FC_FUNC(binary_op));
14914 
14915 			ir_END_list(end_inputs);
14916 
14917 			ir_MERGE_2(noref_path, ref_path);
14918 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
14919 			prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14920 
14921 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14922 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14923 				ref = ir_CONST_ADDR(prop_info);
14924 			} else {
14925 				int prop_info_offset =
14926 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14927 
14928 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14929 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14930 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14931 			}
14932 
14933 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
14934 				prop_ref,
14935 				ref,
14936 				arg2,
14937 				ir_CONST_FC_FUNC(binary_op));
14938 
14939 			ir_END_list(end_inputs);
14940 		}
14941 	}
14942 
14943 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14944 		zend_jit_addr var_addr = prop_addr;
14945 		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
14946 		uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
14947 
14948 		if (use_prop_guard) {
14949 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14950 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14951 			if (!exit_addr) {
14952 				return 0;
14953 			}
14954 
14955 			jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
14956 			var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
14957 		}
14958 
14959 		if (var_info & MAY_BE_REF) {
14960 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
14961 
14962 			may_throw = 1;
14963 
14964 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
14965 			ir_IF_FALSE(if_ref);
14966 			noref_path = ir_END();
14967 			ir_IF_TRUE(if_ref);
14968 
14969 			reference = jit_Z_PTR(jit, var_addr);
14970 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
14971 			if_typed = jit_if_TYPED_REF(jit, reference);
14972 			ir_IF_FALSE(if_typed);
14973 			ref_path = ir_END();
14974 			ir_IF_TRUE_cold(if_typed);
14975 
14976 			jit_SET_EX_OPLINE(jit, opline);
14977 
14978 			if (Z_MODE(val_addr) == IS_REG) {
14979 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14980 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14981 					return 0;
14982 				}
14983 				arg2 = jit_ZVAL_ADDR(jit, real_addr);
14984 			} else {
14985 				arg2 = jit_ZVAL_ADDR(jit, val_addr);
14986 			}
14987 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
14988 				reference,
14989 				arg2,
14990 				ir_CONST_FC_FUNC(binary_op));
14991 
14992 			ir_END_list(end_inputs);
14993 
14994 			ir_MERGE_2(noref_path, ref_path);
14995 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
14996 			var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14997 
14998 			var_info &= ~MAY_BE_REF;
14999 		}
15000 
15001 		uint8_t val_op_type = (opline+1)->op1_type;
15002 		if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
15003 			/* prevent FREE_OP in the helpers */
15004 			val_op_type = IS_CV;
15005 		}
15006 
15007 		switch (opline->extended_value) {
15008 			case ZEND_ADD:
15009 			case ZEND_SUB:
15010 			case ZEND_MUL:
15011 				if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15012 				    (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15013 					if (opline->extended_value != ZEND_ADD ||
15014 					    (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
15015 					    (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
15016 						may_throw = 1;
15017 					}
15018 				}
15019 				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,
15020 						1 /* may overflow */, 0)) {
15021 					return 0;
15022 				}
15023 				break;
15024 			case ZEND_BW_OR:
15025 			case ZEND_BW_AND:
15026 			case ZEND_BW_XOR:
15027 				if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15028 				    (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15029 					if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
15030 					    (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
15031 						may_throw = 1;
15032 					}
15033 				}
15034 				goto long_math;
15035 			case ZEND_SL:
15036 			case ZEND_SR:
15037 				if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15038 				    (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15039 					may_throw = 1;
15040 				}
15041 				if (val_op_type != IS_CONST ||
15042 				    Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15043 				    Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
15044 					may_throw = 1;
15045 				}
15046 				goto long_math;
15047 			case ZEND_MOD:
15048 				if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15049 				    (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15050 					may_throw = 1;
15051 				}
15052 				if (val_op_type != IS_CONST ||
15053 				    Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15054 				    Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
15055 					may_throw = 1;
15056 				}
15057 long_math:
15058 				if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
15059 						IS_CV, opline->op1, var_addr, var_info, NULL,
15060 						val_op_type, (opline+1)->op1, val_addr, val_info,
15061 						val_range,
15062 						0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
15063 					return 0;
15064 				}
15065 				break;
15066 			case ZEND_CONCAT:
15067 				may_throw = 1;
15068 				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,
15069 						0)) {
15070 					return 0;
15071 				}
15072 				break;
15073 			default:
15074 				ZEND_UNREACHABLE();
15075 		}
15076 		if (end_inputs || slow_inputs) {
15077 			ir_END_list(end_inputs);
15078 		}
15079 	}
15080 
15081 	if (slow_inputs) {
15082 		ir_ref arg3;
15083 
15084 		ir_MERGE_list(slow_inputs);
15085 
15086 		may_throw = 1;
15087 
15088 		if (Z_MODE(val_addr) == IS_REG) {
15089 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15090 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15091 				return 0;
15092 			}
15093 			arg3 = jit_ZVAL_ADDR(jit, real_addr);
15094 		} else {
15095 			arg3 = jit_ZVAL_ADDR(jit, val_addr);
15096 		}
15097 		jit_SET_EX_OPLINE(jit, opline);
15098 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15099 		ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15100 			obj_ref,
15101 			ir_CONST_ADDR(name),
15102 			arg3,
15103 			ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15104 			ir_CONST_FC_FUNC(binary_op));
15105 
15106 		ir_END_list(end_inputs);
15107 	}
15108 
15109 	if (end_inputs) {
15110 		ir_MERGE_list(end_inputs);
15111 	}
15112 
15113 	if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15114 		val_info |= MAY_BE_RC1|MAY_BE_RCN;
15115 	}
15116 
15117 	// JIT: FREE_OP_DATA();
15118 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15119 
15120 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15121 		if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15122 			may_throw = 1;
15123 		}
15124 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15125 	}
15126 
15127 	if (may_throw) {
15128 		zend_jit_check_exception(jit);
15129 	}
15130 
15131 	return 1;
15132 }
15133 
15134 static int zend_jit_incdec_obj(zend_jit_ctx         *jit,
15135                                const zend_op        *opline,
15136                                const zend_op_array  *op_array,
15137                                zend_ssa             *ssa,
15138                                const zend_ssa_op    *ssa_op,
15139                                uint32_t              op1_info,
15140                                zend_jit_addr         op1_addr,
15141                                bool                  op1_indirect,
15142                                zend_class_entry     *ce,
15143                                bool                  ce_is_instanceof,
15144                                bool                  on_this,
15145                                bool                  delayed_fetch_this,
15146                                zend_class_entry     *trace_ce,
15147                                uint8_t               prop_type)
15148 {
15149 	zval *member;
15150 	zend_string *name;
15151 	zend_property_info *prop_info;
15152 	zend_jit_addr res_addr = 0;
15153 	zend_jit_addr prop_addr;
15154 	bool use_prop_guard = 0;
15155 	bool may_throw = 0;
15156 	uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15157 	ir_ref obj_ref = IR_UNUSED;
15158 	ir_ref prop_ref = IR_UNUSED;
15159 	ir_ref end_inputs = IR_UNUSED;
15160 	ir_ref slow_inputs = IR_UNUSED;
15161 
15162 	ZEND_ASSERT(opline->op2_type == IS_CONST);
15163 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15164 
15165 	if (opline->result_type != IS_UNUSED) {
15166 		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15167 	}
15168 
15169 	member = RT_CONSTANT(opline, opline->op2);
15170 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15171 	name = Z_STR_P(member);
15172 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15173 
15174 	if (on_this) {
15175 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15176 		obj_ref = jit_Z_PTR(jit, this_addr);
15177 	} else {
15178 		if (opline->op1_type == IS_VAR
15179 		 && (op1_info & MAY_BE_INDIRECT)
15180 		 && Z_REG(op1_addr) == ZREG_FP) {
15181 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15182 		}
15183 		if (op1_info & MAY_BE_REF) {
15184 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15185 		}
15186 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15187 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15188 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15189 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15190 
15191 				if (!exit_addr) {
15192 					return 0;
15193 				}
15194 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15195 			} else {
15196 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15197 				ir_IF_FALSE_cold(if_obj);
15198 
15199 				jit_SET_EX_OPLINE(jit, opline);
15200 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15201 					jit_ZVAL_ADDR(jit, op1_addr),
15202 					ir_CONST_ADDR(ZSTR_VAL(name)));
15203 
15204 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15205 				ir_IF_TRUE(if_obj);
15206 			}
15207 		}
15208 		obj_ref = jit_Z_PTR(jit, op1_addr);
15209 	}
15210 
15211 	ZEND_ASSERT(obj_ref);
15212 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15213 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15214 		if (prop_info) {
15215 			ce = trace_ce;
15216 			ce_is_instanceof = 0;
15217 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15218 				if (on_this && JIT_G(current_frame)
15219 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15220 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15221 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15222 					if (on_this && JIT_G(current_frame)) {
15223 						JIT_G(current_frame)->ce = ce;
15224 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15225 					}
15226 				} else {
15227 					return 0;
15228 				}
15229 				if (ssa->var_info && ssa_op->op1_use >= 0) {
15230 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15231 					ssa->var_info[ssa_op->op1_use].ce = ce;
15232 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15233 				}
15234 				if (ssa->var_info && ssa_op->op1_def >= 0) {
15235 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15236 					ssa->var_info[ssa_op->op1_def].ce = ce;
15237 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15238 				}
15239 			}
15240 		}
15241 	}
15242 
15243 	use_prop_guard = (prop_type != IS_UNKNOWN
15244 		&& prop_type != IS_UNDEF
15245 		&& prop_type != IS_REFERENCE
15246 		&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15247 
15248 	if (!prop_info) {
15249 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15250 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15251 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15252 
15253 		ir_IF_FALSE_cold(if_same);
15254 		ir_END_list(slow_inputs);
15255 
15256 		ir_IF_TRUE(if_same);
15257 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15258 			ir_ref prop_info_ref = ir_LOAD_A(
15259 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15260 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15261 			ir_IF_TRUE_cold(if_has_prop_info);
15262 			ir_END_list(slow_inputs);
15263 
15264 			ir_IF_FALSE(if_has_prop_info);
15265 		}
15266 		ir_ref offset_ref = ir_LOAD_A(
15267 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15268 
15269 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15270 		ir_IF_TRUE_cold(if_dynamic);
15271 		ir_END_list(slow_inputs);
15272 
15273 		ir_IF_FALSE(if_dynamic);
15274 
15275 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
15276 		if (!use_prop_guard) {
15277 			ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15278 			ir_IF_FALSE_cold(if_def);
15279 			ir_END_list(slow_inputs);
15280 
15281 			ir_IF_TRUE(if_def);
15282 		}
15283 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15284 	} else {
15285 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15286 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15287 
15288 		if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15289 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15290 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15291 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15292 
15293 				if (!exit_addr) {
15294 					return 0;
15295 				}
15296 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15297 			} else {
15298 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15299 				ir_IF_FALSE_cold(if_def);
15300 				ir_END_list(slow_inputs);
15301 				ir_IF_TRUE(if_def);
15302 			}
15303 		}
15304 
15305 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
15306 			const void *func;
15307 			ir_ref ref;
15308 
15309 			may_throw = 1;
15310 			jit_SET_EX_OPLINE(jit, opline);
15311 
15312 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15313 				ref = ir_CONST_ADDR(prop_info);
15314 			} else {
15315 				int prop_info_offset =
15316 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15317 
15318 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15319 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15320 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15321 			}
15322 
15323 			if (opline->result_type == IS_UNUSED) {
15324 				switch (opline->opcode) {
15325 					case ZEND_PRE_INC_OBJ:
15326 					case ZEND_POST_INC_OBJ:
15327 						func = zend_jit_inc_typed_prop;
15328 						break;
15329 					case ZEND_PRE_DEC_OBJ:
15330 					case ZEND_POST_DEC_OBJ:
15331 						func = zend_jit_dec_typed_prop;
15332 						break;
15333 					default:
15334 						ZEND_UNREACHABLE();
15335 				}
15336 
15337 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
15338 			} else {
15339 				switch (opline->opcode) {
15340 					case ZEND_PRE_INC_OBJ:
15341 						func = zend_jit_pre_inc_typed_prop;
15342 						break;
15343 					case ZEND_PRE_DEC_OBJ:
15344 						func = zend_jit_pre_dec_typed_prop;
15345 						break;
15346 					case ZEND_POST_INC_OBJ:
15347 						func = zend_jit_post_inc_typed_prop;
15348 						break;
15349 					case ZEND_POST_DEC_OBJ:
15350 						func = zend_jit_post_dec_typed_prop;
15351 						break;
15352 					default:
15353 						ZEND_UNREACHABLE();
15354 				}
15355 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func),
15356 					prop_ref,
15357 					ref,
15358 					jit_ZVAL_ADDR(jit, res_addr));
15359 			}
15360 			ir_END_list(end_inputs);
15361 		}
15362 	}
15363 
15364 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15365 		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15366 		zend_jit_addr var_addr = prop_addr;
15367 		ir_ref if_long = IR_UNUSED;
15368 		ir_ref if_overflow = IR_UNUSED;
15369 
15370 		if (use_prop_guard) {
15371 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15372 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15373 			if (!exit_addr) {
15374 				return 0;
15375 			}
15376 
15377 			jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15378 			var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15379 		}
15380 
15381 		if (var_info & MAY_BE_REF) {
15382 			const void *func;
15383 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
15384 
15385 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15386 			ir_IF_FALSE(if_ref);
15387 			noref_path = ir_END();
15388 			ir_IF_TRUE(if_ref);
15389 
15390 			reference = jit_Z_PTR(jit, var_addr);
15391 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15392 			if_typed = jit_if_TYPED_REF(jit, reference);
15393 			ir_IF_FALSE(if_typed);
15394 			ref_path = ir_END();
15395 			ir_IF_TRUE_cold(if_typed);
15396 
15397 			switch (opline->opcode) {
15398 				case ZEND_PRE_INC_OBJ:
15399 					func = zend_jit_pre_inc_typed_ref;
15400 					break;
15401 				case ZEND_PRE_DEC_OBJ:
15402 					func = zend_jit_pre_dec_typed_ref;
15403 					break;
15404 				case ZEND_POST_INC_OBJ:
15405 					func = zend_jit_post_inc_typed_ref;
15406 					break;
15407 				case ZEND_POST_DEC_OBJ:
15408 					func = zend_jit_post_dec_typed_ref;
15409 					break;
15410 				default:
15411 					ZEND_UNREACHABLE();
15412 			}
15413 
15414 			may_throw = 1;
15415 			jit_SET_EX_OPLINE(jit, opline);
15416 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func),
15417 				reference,
15418 				(opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15419 
15420 			ir_END_list(end_inputs);
15421 
15422 			ir_MERGE_2(noref_path, ref_path);
15423 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15424 			var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15425 
15426 			var_info &= ~MAY_BE_REF;
15427 		}
15428 
15429 		if (var_info & MAY_BE_LONG) {
15430 			ir_ref addr, ref;
15431 
15432 			if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15433 				if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
15434 				ir_IF_TRUE(if_long);
15435 			}
15436 
15437 			addr = jit_ZVAL_ADDR(jit, var_addr);
15438 			ref = ir_LOAD_L(addr);
15439 			if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15440 				if (opline->result_type != IS_UNUSED) {
15441 					jit_set_Z_LVAL(jit, res_addr, ref);
15442 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15443 				}
15444 			}
15445 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15446 				ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
15447 			} else {
15448 				ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
15449 			}
15450 
15451 			ir_STORE(addr, ref);
15452 			if_overflow = ir_IF(ir_OVERFLOW(ref));
15453 			ir_IF_FALSE(if_overflow);
15454 
15455 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
15456 				if (opline->result_type != IS_UNUSED) {
15457 					jit_set_Z_LVAL(jit, res_addr, ref);
15458 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15459 				}
15460 			}
15461 			ir_END_list(end_inputs);
15462 		}
15463 
15464 		if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15465 			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15466 				may_throw = 1;
15467 			}
15468 			if (if_long) {
15469 				ir_IF_FALSE_cold(if_long);
15470 			}
15471 			if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15472 				jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, 1);
15473 			}
15474 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15475 				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15476 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
15477 						jit_ZVAL_ADDR(jit, var_addr),
15478 						jit_ZVAL_ADDR(jit, res_addr));
15479 				} else {
15480 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function),
15481 						jit_ZVAL_ADDR(jit, var_addr));
15482 				}
15483 			} else {
15484 				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15485 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
15486 						jit_ZVAL_ADDR(jit, var_addr),
15487 						jit_ZVAL_ADDR(jit, res_addr));
15488 				} else {
15489 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function),
15490 						jit_ZVAL_ADDR(jit, var_addr));
15491 				}
15492 			}
15493 
15494 			ir_END_list(end_inputs);
15495 		}
15496 		if (var_info & MAY_BE_LONG) {
15497 			ir_IF_TRUE_cold(if_overflow);
15498 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15499 #if SIZEOF_ZEND_LONG == 4
15500 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
15501 				jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
15502 #else
15503 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
15504 #endif
15505 				jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15506 				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15507 #if SIZEOF_ZEND_LONG == 4
15508 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
15509 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
15510 #else
15511 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
15512 #endif
15513 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15514 				}
15515 			} else {
15516 #if SIZEOF_ZEND_LONG == 4
15517 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
15518 				jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
15519 #else
15520 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
15521 #endif
15522 				jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15523 				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15524 #if SIZEOF_ZEND_LONG == 4
15525 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
15526 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
15527 #else
15528 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
15529 #endif
15530 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15531 				}
15532 			}
15533 			if (opline->result_type != IS_UNUSED
15534 			 && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
15535 			 && prop_info
15536 			 && !ZEND_TYPE_IS_SET(prop_info->type)
15537 			 && (res_info & MAY_BE_GUARD)
15538 			 && (res_info & MAY_BE_LONG)) {
15539 				zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
15540 				uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
15541 				int32_t exit_point;
15542 				const void *exit_addr;
15543 
15544 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
15545 				exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15546 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15547 				if (!exit_addr) {
15548 					return 0;
15549 				}
15550 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
15551 				ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
15552 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15553 			} else {
15554 				ir_END_list(end_inputs);
15555 			}
15556 		}
15557 	}
15558 
15559 	if (slow_inputs) {
15560 		const void *func;
15561 
15562 		ir_MERGE_list(slow_inputs);
15563 
15564 		// JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
15565 		switch (opline->opcode) {
15566 			case ZEND_PRE_INC_OBJ:
15567 				func = zend_jit_pre_inc_obj_helper;
15568 				break;
15569 			case ZEND_PRE_DEC_OBJ:
15570 				func = zend_jit_pre_dec_obj_helper;
15571 				break;
15572 			case ZEND_POST_INC_OBJ:
15573 				func = zend_jit_post_inc_obj_helper;
15574 				break;
15575 			case ZEND_POST_DEC_OBJ:
15576 				func = zend_jit_post_dec_obj_helper;
15577 				break;
15578 			default:
15579 				ZEND_UNREACHABLE();
15580 		}
15581 
15582 		may_throw = 1;
15583 		jit_SET_EX_OPLINE(jit, opline);
15584 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15585 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func),
15586 			obj_ref,
15587 			ir_CONST_ADDR(name),
15588 			ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15589 			(opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15590 
15591 		ir_END_list(end_inputs);
15592 	}
15593 
15594 	if (end_inputs) {
15595 		ir_MERGE_list(end_inputs);
15596 	}
15597 
15598 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
15599 		if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15600 			may_throw = 1;
15601 		}
15602 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15603 	}
15604 
15605 	if (may_throw) {
15606 		zend_jit_check_exception(jit);
15607 	}
15608 
15609 	return 1;
15610 }
15611 
15612 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)
15613 {
15614 	HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
15615 	const zend_op *next_opline = NULL;
15616 	ir_refs *slow_inputs;
15617 
15618 	ir_refs_init(slow_inputs, 8);
15619 
15620 	if (trace) {
15621 		ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
15622 		ZEND_ASSERT(trace->opline != NULL);
15623 		next_opline = trace->opline;
15624 	}
15625 
15626 	if (opline->op1_type == IS_CONST) {
15627 		zval *zv = RT_CONSTANT(opline, opline->op1);
15628 		zval *jump_zv = NULL;
15629 		int b;
15630 
15631 		if (opline->opcode == ZEND_SWITCH_LONG) {
15632 			if (Z_TYPE_P(zv) == IS_LONG) {
15633 				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
15634 			}
15635 		} else if (opline->opcode == ZEND_SWITCH_STRING) {
15636 			if (Z_TYPE_P(zv) == IS_STRING) {
15637 				jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
15638 			}
15639 		} else if (opline->opcode == ZEND_MATCH) {
15640 			if (Z_TYPE_P(zv) == IS_LONG) {
15641 				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
15642 			} else if (Z_TYPE_P(zv) == IS_STRING) {
15643 				jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
15644 			}
15645 		} else {
15646 			ZEND_UNREACHABLE();
15647 		}
15648 		if (next_opline) {
15649 			const zend_op *target;
15650 
15651 			if (jump_zv != NULL) {
15652 				target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
15653 			} else {
15654 				target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
15655 			}
15656 			ZEND_ASSERT(target == next_opline);
15657 		} else {
15658 			if (jump_zv != NULL) {
15659 				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
15660 			} else {
15661 				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
15662 			}
15663 			_zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
15664 			jit->b = -1;
15665 		}
15666 	} else {
15667 		zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
15668 		uint32_t op1_info = OP1_INFO();
15669 		zend_jit_addr op1_addr = OP1_ADDR();
15670 		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
15671 		const zend_op *target;
15672 		int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
15673 		int b;
15674 		int32_t exit_point;
15675 		const void *exit_addr;
15676 		const void *default_label = NULL;
15677 		zval *zv;
15678 
15679 		if (next_opline) {
15680 			if (next_opline != default_opline) {
15681 				exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
15682 				default_label = zend_jit_trace_get_exit_addr(exit_point);
15683 				if (!default_label) {
15684 					return 0;
15685 				}
15686 			}
15687 		}
15688 
15689 		if (opline->opcode == ZEND_SWITCH_LONG) {
15690 			if (op1_info & MAY_BE_LONG) {
15691 				const void *fallback_label = NULL;
15692 
15693 				if (next_opline) {
15694 					if (next_opline != opline + 1) {
15695 						exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15696 						fallback_label = zend_jit_trace_get_exit_addr(exit_point);
15697 						if (!fallback_label) {
15698 							return 0;
15699 						}
15700 					}
15701 				}
15702 				if (op1_info & MAY_BE_REF) {
15703 					ir_ref ref, if_long, fast_path, ref2;
15704 
15705 					ref = jit_ZVAL_ADDR(jit, op1_addr);
15706 					if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15707 					ir_IF_TRUE(if_long);
15708 					fast_path = ir_END();
15709 					ir_IF_FALSE_cold(if_long);
15710 
15711 					// JIT: ZVAL_DEREF(op)
15712 					if (fallback_label) {
15713 						jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
15714 					} else {
15715 						ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
15716 						ir_IF_FALSE_cold(if_ref);
15717 						ir_refs_add(slow_inputs, ir_END());
15718 						ir_IF_TRUE(if_ref);
15719 					}
15720 
15721 					ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
15722 					op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
15723 
15724 					if (fallback_label) {
15725 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15726 					} else {
15727 						if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15728 						ir_IF_FALSE_cold(if_long);
15729 						ir_refs_add(slow_inputs, ir_END());
15730 						ir_IF_TRUE(if_long);
15731 					}
15732 
15733 					ir_MERGE_2(fast_path, ir_END());
15734 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
15735 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
15736 				} else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
15737 					if (fallback_label) {
15738 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15739 					} else {
15740 						ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15741 						ir_IF_FALSE_cold(if_long);
15742 						ir_refs_add(slow_inputs, ir_END());
15743 						ir_IF_TRUE(if_long);
15744 					}
15745 				}
15746 				ir_ref ref = jit_Z_LVAL(jit, op1_addr);
15747 
15748 				if (!HT_IS_PACKED(jumptable)) {
15749 					ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
15750 						ir_CONST_ADDR(jumptable), ref);
15751 					ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
15752 					/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
15753 					if (sizeof(Bucket) == 32) {
15754 						ref = ir_SHR_L(ref, ir_CONST_LONG(5));
15755 					} else {
15756 						ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
15757 					}
15758 				}
15759 				ref = ir_SWITCH(ref);
15760 
15761 				if (next_opline) {
15762 					ir_ref continue_list = IR_UNUSED;
15763 
15764 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15765 						ir_ref idx;
15766 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15767 
15768 						if (HT_IS_PACKED(jumptable)) {
15769 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
15770 						} else {
15771 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
15772 						}
15773 						ir_CASE_VAL(ref, idx);
15774 						if (target == next_opline) {
15775 							ir_END_list(continue_list);
15776 						} else {
15777 							exit_point = zend_jit_trace_get_exit_point(target, 0);
15778 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15779 							if (!exit_addr) {
15780 								return 0;
15781 							}
15782 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15783 						}
15784 					} ZEND_HASH_FOREACH_END();
15785 
15786 					ir_CASE_DEFAULT(ref);
15787 					if (next_opline == default_opline) {
15788 						ir_END_list(continue_list);
15789 					} else {
15790 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
15791 					}
15792 					if (continue_list) {
15793 						ir_MERGE_list(continue_list);
15794 					} else {
15795 						ZEND_ASSERT(slow_inputs->count);
15796 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15797 					}
15798 				} else {
15799 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15800 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15801 						b = ssa->cfg.map[target - op_array->opcodes];
15802 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
15803 					} ZEND_HASH_FOREACH_END();
15804 
15805 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
15806 					if (slow_inputs->count) {
15807 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15808 						_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15809 					}
15810 					jit->b = -1;
15811 				}
15812 			} else if (!next_opline) {
15813 				_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15814 				jit->b = -1;
15815 			}
15816 		} else if (opline->opcode == ZEND_SWITCH_STRING) {
15817 			if (op1_info & MAY_BE_STRING) {
15818 				const void *fallback_label = NULL;
15819 
15820 				if (next_opline) {
15821 					if (next_opline != opline + 1) {
15822 						exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15823 						fallback_label = zend_jit_trace_get_exit_addr(exit_point);
15824 						if (!fallback_label) {
15825 							return 0;
15826 						}
15827 					}
15828 				}
15829 				if (op1_info & MAY_BE_REF) {
15830 					ir_ref ref, if_string, fast_path, ref2;
15831 
15832 					ref = jit_ZVAL_ADDR(jit, op1_addr);
15833 					if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15834 					ir_IF_TRUE(if_string);
15835 					fast_path = ir_END();
15836 					ir_IF_FALSE_cold(if_string);
15837 
15838 					// JIT: ZVAL_DEREF(op)
15839 					if (fallback_label) {
15840 						jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
15841 					} else {
15842 						ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15843 						ir_IF_FALSE_cold(if_ref);
15844 						ir_refs_add(slow_inputs, ir_END());
15845 						ir_IF_TRUE(if_ref);
15846 					}
15847 
15848 					ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
15849 					op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
15850 
15851 					if (fallback_label) {
15852 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15853 					} else {
15854 						if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15855 						ir_IF_FALSE_cold(if_string);
15856 						ir_refs_add(slow_inputs, ir_END());
15857 						ir_IF_TRUE(if_string);
15858 					}
15859 
15860 					ir_MERGE_2(fast_path, ir_END());
15861 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
15862 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
15863 				} else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
15864 					if (fallback_label) {
15865 						jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
15866 					} else {
15867 						ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15868 						ir_IF_FALSE_cold(if_string);
15869 						ir_refs_add(slow_inputs, ir_END());
15870 						ir_IF_TRUE(if_string);
15871 					}
15872 				}
15873 
15874 				ir_ref ref = jit_Z_PTR(jit, op1_addr);
15875 				ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
15876 					ir_CONST_ADDR(jumptable), ref);
15877 				ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
15878 				/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
15879 				if (sizeof(Bucket) == 32) {
15880 					ref = ir_SHR_L(ref, ir_CONST_LONG(5));
15881 				} else {
15882 					ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
15883 				}
15884 				ref = ir_SWITCH(ref);
15885 
15886 				if (next_opline) {
15887 					ir_ref continue_list = IR_UNUSED;
15888 
15889 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15890 						ir_ref idx;
15891 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15892 
15893 						if (HT_IS_PACKED(jumptable)) {
15894 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
15895 						} else {
15896 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
15897 						}
15898 						ir_CASE_VAL(ref, idx);
15899 						if (target == next_opline) {
15900 							ir_END_list(continue_list);
15901 						} else {
15902 							exit_point = zend_jit_trace_get_exit_point(target, 0);
15903 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15904 							if (!exit_addr) {
15905 								return 0;
15906 							}
15907 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15908 						}
15909 					} ZEND_HASH_FOREACH_END();
15910 
15911 					ir_CASE_DEFAULT(ref);
15912 					if (next_opline == default_opline) {
15913 						ir_END_list(continue_list);
15914 					} else {
15915 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
15916 					}
15917 					if (continue_list) {
15918 						ir_MERGE_list(continue_list);
15919 					} else {
15920 						ZEND_ASSERT(slow_inputs->count);
15921 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15922 					}
15923 				} else {
15924 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15925 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15926 						b = ssa->cfg.map[target - op_array->opcodes];
15927 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
15928 					} ZEND_HASH_FOREACH_END();
15929 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
15930 					if (slow_inputs->count) {
15931 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15932 						_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15933 					}
15934 					jit->b = -1;
15935 				}
15936 			} else if (!next_opline) {
15937 				_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15938 				jit->b = -1;
15939 			}
15940 		} else if (opline->opcode == ZEND_MATCH) {
15941 			ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
15942 			ir_ref continue_list = IR_UNUSED;
15943 
15944 			if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
15945 				ir_ref long_path = IR_UNUSED;
15946 
15947 				if (op1_info & MAY_BE_REF) {
15948 					op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15949 				}
15950 				if (op1_info & MAY_BE_LONG) {
15951 					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
15952 						if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
15953 							if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15954 							ir_IF_TRUE(if_type);
15955 						} else if (default_label) {
15956 							jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
15957 						} else if (next_opline) {
15958 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15959 							ir_IF_FALSE(if_type);
15960 							ir_END_list(continue_list);
15961 							ir_IF_TRUE(if_type);
15962 						} else {
15963 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15964 							ir_IF_FALSE(if_type);
15965 							ir_END_list(default_input_list);
15966 							ir_IF_TRUE(if_type);
15967 						}
15968 					}
15969 					ref = jit_Z_LVAL(jit, op1_addr);
15970 					ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
15971 						ir_CONST_ADDR(jumptable), ref);
15972 					if (op1_info & MAY_BE_STRING) {
15973 						long_path = ir_END();
15974 					}
15975 				}
15976 				if (op1_info & MAY_BE_STRING) {
15977 					if (if_type) {
15978 						ir_IF_FALSE(if_type);
15979 						if_type = IS_UNUSED;
15980 					}
15981 					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
15982 						if (op1_info & MAY_BE_UNDEF) {
15983 							if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15984 							ir_IF_TRUE(if_type);
15985 						} else if (default_label) {
15986 							jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
15987 						} else if (next_opline) {
15988 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15989 							ir_IF_FALSE(if_type);
15990 							ir_END_list(continue_list);
15991 							ir_IF_TRUE(if_type);
15992 						} else {
15993 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15994 							ir_IF_FALSE(if_type);
15995 							ir_END_list(default_input_list);
15996 							ir_IF_TRUE(if_type);
15997 						}
15998 					}
15999 					ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
16000 					ref2 = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16001 						ir_CONST_ADDR(jumptable), ref2);
16002 					if (op1_info & MAY_BE_LONG) {
16003 						ir_MERGE_WITH(long_path);
16004 						ref = ir_PHI_2(IR_LONG, ref2, ref);
16005 					} else {
16006 						ref = ref2;
16007 					}
16008 				}
16009 
16010 				ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16011 				/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16012 				if (HT_IS_PACKED(jumptable)) {
16013 					ZEND_ASSERT(sizeof(zval) == 16);
16014 					ref = ir_SHR_L(ref, ir_CONST_LONG(4));
16015 				} else {
16016 					if (sizeof(Bucket) == 32) {
16017 						ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16018 					} else {
16019 						ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16020 					}
16021 				}
16022 				ref = ir_SWITCH(ref);
16023 
16024 				if (next_opline) {
16025 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16026 						ir_ref idx;
16027 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16028 
16029 						if (HT_IS_PACKED(jumptable)) {
16030 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
16031 						} else {
16032 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16033 						}
16034 						ir_CASE_VAL(ref, idx);
16035 						if (target == next_opline) {
16036 							ir_END_list(continue_list);
16037 						} else {
16038 							exit_point = zend_jit_trace_get_exit_point(target, 0);
16039 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16040 							if (!exit_addr) {
16041 								return 0;
16042 							}
16043 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16044 						}
16045 					} ZEND_HASH_FOREACH_END();
16046 
16047 					ir_CASE_DEFAULT(ref);
16048 					if (next_opline == default_opline) {
16049 						ir_END_list(continue_list);
16050 					} else {
16051 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16052 					}
16053 				} else {
16054 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16055 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16056 						b = ssa->cfg.map[target - op_array->opcodes];
16057 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16058 					} ZEND_HASH_FOREACH_END();
16059 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16060 				}
16061 			} else if (!(op1_info & MAY_BE_UNDEF)) {
16062 				if (next_opline) {
16063 					if (next_opline == default_opline) {
16064 						ir_END_list(continue_list);
16065 					} else {
16066 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16067 					}
16068 				} else {
16069 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16070 				}
16071 			}
16072 
16073 			if (op1_info & MAY_BE_UNDEF) {
16074 				if (if_type) {
16075 					ir_IF_FALSE(if_type);
16076 					if_type = IS_UNUSED;
16077 				}
16078 				if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16079 					if (default_label) {
16080 						jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16081 					} else if (next_opline) {
16082 						ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16083 						ir_IF_TRUE(if_def);
16084 						ir_END_list(continue_list);
16085 						ir_IF_FALSE_cold(if_def);
16086 					} else {
16087 						ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16088 						ir_IF_TRUE(if_def);
16089 						ir_END_list(default_input_list);
16090 						ir_IF_FALSE_cold(if_def);
16091 					}
16092 				}
16093 
16094 				jit_SET_EX_OPLINE(jit, opline);
16095 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16096 					ir_CONST_U32(opline->op1.var));
16097 				zend_jit_check_exception_undef_result(jit, opline);
16098 				if (default_label) {
16099 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16100 				} else if (next_opline) {
16101 					ir_END_list(continue_list);
16102 				} else {
16103 					ir_END_list(default_input_list);
16104 				}
16105 			}
16106 			if (next_opline) {
16107 				ZEND_ASSERT(continue_list);
16108 				ir_MERGE_list(continue_list);
16109 			} else {
16110 				if (default_input_list) {
16111 					if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16112 						ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16113 						jit->ctx.ir_base[ref].op3 = default_input_list;
16114 					} else {
16115 						ir_MERGE_list(default_input_list);
16116 						_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16117 					}
16118 				}
16119 				jit->b = -1;
16120 			}
16121 		} else {
16122 			ZEND_UNREACHABLE();
16123 		}
16124 	}
16125 	return 1;
16126 }
16127 
16128 static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16129 {
16130 	int i, count;
16131 	zend_basic_block *bb;
16132 
16133 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : (IR_START_BR_TARGET|IR_ENTRY_BR_TARGET));
16134 
16135 	jit->ctx.spill_base = ZREG_FP;
16136 
16137 	jit->op_array = jit->current_op_array = op_array;
16138 	jit->ssa = ssa;
16139 	jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16140 	jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16141 
16142 	count = 0;
16143 	for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
16144 		jit->bb_predecessors[i] = count;
16145 		count += bb->predecessors_count;
16146 	}
16147 	jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
16148 
16149 	if (!GCC_GLOBAL_REGS) {
16150 		ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16151 		jit_STORE_FP(jit, ref);
16152 		jit->ctx.flags |= IR_FASTCALL_FUNC;
16153 	}
16154 
16155 	return 1;
16156 }
16157 
16158 static void *zend_jit_finish(zend_jit_ctx *jit)
16159 {
16160 	void *entry;
16161 	size_t size;
16162 	zend_string *str = NULL;
16163 
16164 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP|
16165 			ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_SCCP|
16166 			ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS|ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
16167 		if (jit->name) {
16168 			str = zend_string_copy(jit->name);
16169 		} else {
16170 			str = zend_jit_func_name(jit->op_array);
16171 		}
16172 	}
16173 
16174 	if (jit->op_array) {
16175 		/* Only for function JIT */
16176 		_zend_jit_fix_merges(jit);
16177 #if defined(IR_TARGET_AARCH64)
16178 	} else if (jit->trace) {
16179 		jit->ctx.deoptimization_exits = jit->trace->exit_count;
16180 		jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
16181 #endif
16182 	} else {
16183 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
16184 		jit->ctx.flags |= IR_GEN_CACHE_DEMOTE;
16185 #endif
16186 	}
16187 
16188 	entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
16189 	if (entry) {
16190 		if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16191 #ifdef HAVE_CAPSTONE
16192 			if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16193 				if (str) {
16194 					ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
16195 				}
16196 				ir_disasm(str ? ZSTR_VAL(str) : "unknown",
16197 					entry, size,
16198 					(JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0,
16199 					&jit->ctx, stderr);
16200 			}
16201 #endif
16202 #ifndef _WIN32
16203 			if (str) {
16204 				if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
16205 					uintptr_t sp_offset = 0;
16206 
16207 //					ir_mem_unprotect(entry, size);
16208 					if (!(jit->ctx.flags & IR_FUNCTION)
16209 					 && zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16210 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
16211 						sp_offset = zend_jit_hybrid_vm_sp_adj;
16212 #else
16213 						sp_offset = sizeof(void*);
16214 #endif
16215 					} else {
16216 						sp_offset = sizeof(void*);
16217 					}
16218 					ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
16219 //					ir_mem_protect(entry, size);
16220 				}
16221 
16222 				if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16223 					ir_perf_map_register(ZSTR_VAL(str), entry, size);
16224 					if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
16225 						ir_perf_jitdump_register(ZSTR_VAL(str), entry, size);
16226 					}
16227 				}
16228 			}
16229 #endif
16230 		}
16231 
16232 		if (jit->op_array) {
16233 			/* Only for function JIT */
16234 			const zend_op_array *op_array = jit->op_array;
16235 			zend_op *opline = (zend_op*)op_array->opcodes;
16236 
16237 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
16238 				while (opline->opcode == ZEND_RECV) {
16239 					opline++;
16240 				}
16241 			}
16242 			opline->handler = entry;
16243 
16244 			if (jit->ctx.entries_count) {
16245 				/* For all entries */
16246 				int i = jit->ctx.entries_count;
16247 				do {
16248 					ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
16249 					op_array->opcodes[insn->op2].handler = (char*)entry + insn->op3;
16250 				} while (i != 0);
16251 			}
16252 		} else {
16253 			/* Only for tracing JIT */
16254 			zend_jit_trace_info *t = jit->trace;
16255 			zend_jit_trace_stack *stack;
16256 			uint32_t i;
16257 
16258 			if (t) {
16259 				for (i = 0; i < t->stack_map_size; i++) {
16260 					stack = t->stack_map + i;
16261 					if (stack->flags & ZREG_SPILL_SLOT) {
16262 						stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
16263 						stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
16264 					}
16265 				}
16266 			}
16267 
16268 			zend_jit_trace_add_code(entry, size);
16269 		}
16270 	}
16271 
16272 	if (str) {
16273 		zend_string_release(str);
16274 	}
16275 
16276 	return entry;
16277 }
16278 
16279 static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
16280 {
16281 	const void *entry;
16282 	size_t size;
16283 	ir_code_buffer code_buffer;
16284 
16285 	code_buffer.start = dasm_buf;
16286 	code_buffer.end = dasm_end;
16287 	code_buffer.pos = *dasm_ptr;
16288 
16289 	entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
16290 		&code_buffer, &size);
16291 
16292 	*dasm_ptr = code_buffer.pos;
16293 
16294 	if (entry) {
16295 #ifdef HAVE_CAPSTONE
16296 		if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16297 			uint32_t i;
16298 			char name[32];
16299 
16300 			for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
16301 				snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
16302 				ir_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
16303 			}
16304 		}
16305 #endif
16306 	}
16307 
16308 	return entry;
16309 }
16310 
16311 static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
16312 {
16313 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16314 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16315 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16316 
16317 	if (!exit_addr) {
16318 		return 0;
16319 	}
16320 	ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
16321 
16322 	return 1;
16323 }
16324 
16325 static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
16326 {
16327 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16328 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16329 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16330 
16331 	if (!exit_addr) {
16332 		return 0;
16333 	}
16334 	ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
16335 
16336 	return 1;
16337 }
16338 
16339 static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
16340 {
16341 	uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16342 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16343 
16344 	if (!exit_addr) {
16345 		return 0;
16346 	}
16347 	ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16348 
16349 	return 1;
16350 }
16351 
16352 static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
16353 {
16354 	uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
16355 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16356 
16357 	if (!exit_addr) {
16358 		return 0;
16359 	}
16360 
16361 	ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
16362 	zend_jit_set_last_valid_opline(jit, opline);
16363 
16364 	return 1;
16365 }
16366 
16367 static bool zend_jit_guard_reference(zend_jit_ctx  *jit,
16368                                      const zend_op *opline,
16369                                      zend_jit_addr *var_addr_ptr,
16370                                      zend_jit_addr *ref_addr_ptr,
16371                                      bool           add_ref_guard)
16372 {
16373 	zend_jit_addr var_addr = *var_addr_ptr;
16374 	const void *exit_addr = NULL;
16375 	ir_ref ref;
16376 
16377 	if (add_ref_guard) {
16378 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16379 
16380 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16381 		if (!exit_addr) {
16382 			return 0;
16383 		}
16384 
16385 		ref = jit_Z_TYPE(jit, var_addr);
16386 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16387 	}
16388 
16389 	ref = jit_Z_PTR(jit, var_addr);
16390 	*ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
16391 	ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16392 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
16393 	*var_addr_ptr = var_addr;
16394 
16395 	return 1;
16396 }
16397 
16398 static bool zend_jit_fetch_reference(zend_jit_ctx  *jit,
16399                                      const zend_op *opline,
16400                                      uint8_t        var_type,
16401                                      uint32_t      *var_info_ptr,
16402                                      zend_jit_addr *var_addr_ptr,
16403                                      bool           add_ref_guard,
16404                                      bool           add_type_guard)
16405 {
16406 	zend_jit_addr var_addr = *var_addr_ptr;
16407 	uint32_t var_info = *var_info_ptr;
16408 	const void *exit_addr = NULL;
16409 	ir_ref ref;
16410 
16411 	if (add_ref_guard || add_type_guard) {
16412 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16413 
16414 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16415 		if (!exit_addr) {
16416 			return 0;
16417 		}
16418 	}
16419 
16420 	if (add_ref_guard) {
16421 		ref = jit_Z_TYPE(jit, var_addr);
16422 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16423 	}
16424 	if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
16425 		/* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
16426 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
16427 			jit_ZVAL_ADDR(jit, var_addr));
16428 		*var_addr_ptr = var_addr;
16429 	} else {
16430 		ref = jit_Z_PTR(jit, var_addr);
16431 		ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16432 		var_addr = ZEND_ADDR_REF_ZVAL(ref);
16433 		*var_addr_ptr = var_addr;
16434 	}
16435 
16436 	if (var_type != IS_UNKNOWN) {
16437 		var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16438 	}
16439 	if (add_type_guard
16440 	 && var_type != IS_UNKNOWN
16441 	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16442 		ref = jit_Z_TYPE(jit, var_addr);
16443 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
16444 
16445 		ZEND_ASSERT(var_info & (1 << var_type));
16446 		if (var_type < IS_STRING) {
16447 			var_info = (1 << var_type);
16448 		} else if (var_type != IS_ARRAY) {
16449 			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16450 		} else {
16451 			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));
16452 		}
16453 
16454 		*var_info_ptr = var_info;
16455 	} else {
16456 		var_info &= ~MAY_BE_REF;
16457 		*var_info_ptr = var_info;
16458 	}
16459 	*var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
16460 
16461 	return 1;
16462 }
16463 
16464 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)
16465 {
16466 	zend_jit_addr var_addr = *var_addr_ptr;
16467 	uint32_t var_info = *var_info_ptr;
16468 	int32_t exit_point;
16469 	const void *exit_addr;
16470 	ir_ref ref = IR_UNUSED;
16471 
16472 	if (add_indirect_guard) {
16473 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16474 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16475 
16476 		if (!exit_addr) {
16477 			return 0;
16478 		}
16479 		jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
16480 		ref = jit_Z_PTR(jit, var_addr);
16481 	} else {
16482 		/* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
16483 		 * is eliminated by store forwarding (S2L) */
16484 		ref = jit_Z_PTR(jit, var_addr);
16485 	}
16486 	*var_info_ptr &= ~MAY_BE_INDIRECT;
16487 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
16488 	*var_addr_ptr = var_addr;
16489 
16490 	if (var_type != IS_UNKNOWN) {
16491 		var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16492 	}
16493 	if (!(var_type & IS_TRACE_REFERENCE)
16494 	 && var_type != IS_UNKNOWN
16495 	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16496 		exit_point = zend_jit_trace_get_exit_point(opline, 0);
16497 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16498 
16499 		if (!exit_addr) {
16500 			return 0;
16501 		}
16502 
16503 		jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
16504 
16505 		//var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
16506 		ZEND_ASSERT(var_info & (1 << var_type));
16507 		if (var_type < IS_STRING) {
16508 			var_info = (1 << var_type);
16509 		} else if (var_type != IS_ARRAY) {
16510 			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16511 		} else {
16512 			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));
16513 		}
16514 
16515 		*var_info_ptr = var_info;
16516 	}
16517 
16518 	return 1;
16519 }
16520 
16521 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)
16522 {
16523 	zend_jit_op_array_trace_extension *jit_extension =
16524 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
16525 	size_t offset = jit_extension->offset;
16526 	const void *handler =
16527 		(zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
16528 	ir_ref ref;
16529 
16530 	zend_jit_set_ip(jit, opline);
16531 	if (GCC_GLOBAL_REGS) {
16532 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
16533 	} else {
16534 		ref = jit_FP(jit);
16535 		ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
16536 	}
16537 	if (may_throw
16538 	 && opline->opcode != ZEND_RETURN
16539 	 && opline->opcode != ZEND_RETURN_BY_REF) {
16540 		zend_jit_check_exception(jit);
16541 	}
16542 
16543 	while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
16544 		trace++;
16545 	}
16546 
16547 	if (!GCC_GLOBAL_REGS
16548 	 && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
16549 		if (opline->opcode == ZEND_RETURN ||
16550 		    opline->opcode == ZEND_RETURN_BY_REF ||
16551 		    opline->opcode == ZEND_DO_UCALL ||
16552 		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
16553 		    opline->opcode == ZEND_DO_FCALL ||
16554 		    opline->opcode == ZEND_GENERATOR_CREATE) {
16555 
16556 			ir_ref addr = jit_EG(current_execute_data);
16557 
16558 			jit_STORE_FP(jit, ir_LOAD_A(addr));
16559 		}
16560 	}
16561 
16562 	if (zend_jit_trace_may_exit(op_array, opline)) {
16563 		if (opline->opcode == ZEND_RETURN ||
16564 		    opline->opcode == ZEND_RETURN_BY_REF ||
16565 		    opline->opcode == ZEND_GENERATOR_CREATE) {
16566 
16567 			if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16568 				if (trace->op != ZEND_JIT_TRACE_END ||
16569 				    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16570 				     trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16571 					/* this check may be handled by the following OPLINE guard or jmp [IP] */
16572 					ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
16573 						jit_STUB_ADDR(jit, jit_stub_trace_halt));
16574 				}
16575 			} else if (GCC_GLOBAL_REGS) {
16576 				ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16577 			} else {
16578 				ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16579 			}
16580 		} else if (opline->opcode == ZEND_GENERATOR_RETURN ||
16581 		           opline->opcode == ZEND_YIELD ||
16582 		           opline->opcode == ZEND_YIELD_FROM) {
16583 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
16584 			ir_BEGIN(IR_UNUSED); /* unreachable block */
16585 		}
16586 		if (trace->op != ZEND_JIT_TRACE_END ||
16587 		    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16588 		     trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16589 
16590 			const zend_op *next_opline = trace->opline;
16591 			const zend_op *exit_opline = NULL;
16592 			uint32_t exit_point;
16593 			const void *exit_addr;
16594 			uint32_t old_info = 0;
16595 			uint32_t old_res_info = 0;
16596 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16597 
16598 			if (zend_is_smart_branch(opline)) {
16599 				bool exit_if_true = 0;
16600 				exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
16601 			} else {
16602 				switch (opline->opcode) {
16603 					case ZEND_JMPZ:
16604 					case ZEND_JMPNZ:
16605 					case ZEND_JMPZ_EX:
16606 					case ZEND_JMPNZ_EX:
16607 					case ZEND_JMP_SET:
16608 					case ZEND_COALESCE:
16609 					case ZEND_JMP_NULL:
16610 					case ZEND_FE_RESET_R:
16611 					case ZEND_FE_RESET_RW:
16612 						exit_opline = (trace->opline == opline + 1) ?
16613 							OP_JMP_ADDR(opline, opline->op2) :
16614 							opline + 1;
16615 						break;
16616 					case ZEND_FE_FETCH_R:
16617 					case ZEND_FE_FETCH_RW:
16618 						exit_opline = (trace->opline == opline + 1) ?
16619 							ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
16620 							opline + 1;
16621 						break;
16622 
16623 				}
16624 			}
16625 
16626 			switch (opline->opcode) {
16627 				case ZEND_FE_FETCH_R:
16628 				case ZEND_FE_FETCH_RW:
16629 					if (opline->op2_type != IS_UNUSED) {
16630 						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
16631 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
16632 					}
16633 					break;
16634 				case ZEND_BIND_INIT_STATIC_OR_JMP:
16635 					if (opline->op1_type == IS_CV) {
16636 						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
16637 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
16638 					}
16639 					break;
16640 			}
16641 			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
16642 				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
16643 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
16644 			}
16645 			exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
16646 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16647 
16648 			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
16649 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
16650 			}
16651 			switch (opline->opcode) {
16652 				case ZEND_FE_FETCH_R:
16653 				case ZEND_FE_FETCH_RW:
16654 					if (opline->op2_type != IS_UNUSED) {
16655 						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
16656 					}
16657 					break;
16658 				case ZEND_BIND_INIT_STATIC_OR_JMP:
16659 					if (opline->op1_type == IS_CV) {
16660 						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
16661 					}
16662 					break;
16663 			}
16664 
16665 			if (!exit_addr) {
16666 				return 0;
16667 			}
16668 			ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
16669 		}
16670 	}
16671 
16672 	zend_jit_set_last_valid_opline(jit, trace->opline);
16673 
16674 	return 1;
16675 }
16676 
16677 static int zend_jit_deoptimizer_start(zend_jit_ctx        *jit,
16678                                       zend_string         *name,
16679                                       uint32_t             trace_num,
16680                                       uint32_t             exit_num)
16681 {
16682 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
16683 
16684 	jit->ctx.spill_base = ZREG_FP;
16685 
16686 	jit->op_array = NULL;
16687 	jit->ssa = NULL;
16688 	jit->name = zend_string_copy(name);
16689 
16690 	jit->ctx.flags |= IR_SKIP_PROLOGUE;
16691 
16692 	return 1;
16693 }
16694 
16695 static int zend_jit_trace_start(zend_jit_ctx        *jit,
16696                                 const zend_op_array *op_array,
16697                                 zend_ssa            *ssa,
16698                                 zend_string         *name,
16699                                 uint32_t             trace_num,
16700                                 zend_jit_trace_info *parent,
16701                                 uint32_t             exit_num)
16702 {
16703 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
16704 
16705 	jit->ctx.spill_base = ZREG_FP;
16706 
16707 	jit->op_array = NULL;
16708 	jit->current_op_array = op_array;
16709 	jit->ssa = ssa;
16710 	jit->name = zend_string_copy(name);
16711 
16712 	if (!GCC_GLOBAL_REGS) {
16713 		if (!parent) {
16714 			ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16715 			jit_STORE_FP(jit, ref);
16716 			jit->ctx.flags |= IR_FASTCALL_FUNC;
16717 		}
16718 	}
16719 
16720 	if (parent) {
16721 		jit->ctx.flags |= IR_SKIP_PROLOGUE;
16722 	}
16723 
16724 	if (parent) {
16725 		int i;
16726 		int parent_vars_count = parent->exit_info[exit_num].stack_size;
16727 		zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
16728 			parent->stack_map +
16729 			parent->exit_info[exit_num].stack_offset;
16730 
16731 		/* prevent clobbering of registers used for deoptimization */
16732 		for (i = 0; i < parent_vars_count; i++) {
16733 			if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
16734 			 && STACK_REG(parent_stack, i) != ZREG_NONE) {
16735 				int32_t reg = STACK_REG(parent_stack, i);
16736 				ir_type type;
16737 
16738 				if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
16739 					type = IR_ADDR;
16740 				} else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
16741 					type = IR_LONG;
16742 				} else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
16743 					type = IR_DOUBLE;
16744 				} else {
16745 					ZEND_UNREACHABLE();
16746 				}
16747 				if (ssa && ssa->vars[i].no_val) {
16748 					/* pass */
16749 				} else {
16750 					ir_ref ref = ir_RLOAD(type, reg);
16751 
16752 					if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
16753 						/* op3 is used as a flag that the value is already stored in memory.
16754 						 * In case the IR framework decides to spill the result of IR_LOAD,
16755 						 * it doesn't have to store the value once again.
16756 						 *
16757 						 * See: insn->op3 check in ir_emit_rload()
16758 						 */
16759 						ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
16760 					}
16761 				}
16762 			}
16763 		}
16764 	}
16765 
16766 	if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
16767 		ZEND_ASSERT(parent->exit_info[exit_num].poly_func_reg >= 0 && parent->exit_info[exit_num].poly_this_reg >= 0);
16768 		ir_RLOAD_A(parent->exit_info[exit_num].poly_func_reg);
16769 		ir_RLOAD_A(parent->exit_info[exit_num].poly_this_reg);
16770 	}
16771 
16772 	ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
16773 
16774 	return 1;
16775 }
16776 
16777 static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
16778 {
16779 	return ir_LOOP_BEGIN(ir_END());
16780 }
16781 
16782 static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
16783 {
16784 	int dst_var = phi->ssa_var;
16785 	int src_var = phi->sources[0];
16786 	ir_ref ref;
16787 
16788 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
16789 	ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
16790 
16791 	ref = ir_PHI_2(
16792 		(jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
16793 		zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
16794 
16795 	src_var = phi->sources[1];
16796 	ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
16797 	jit->ra[src_var].flags |= ZREG_FORWARD;
16798 
16799 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
16800 }
16801 
16802 static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
16803 {
16804 	if (timeout_exit_addr) {
16805 		zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
16806 	}
16807 	ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
16808 	ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
16809 	return 1;
16810 }
16811 
16812 static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
16813 {
16814 	if (GCC_GLOBAL_REGS) {
16815 		if (!original_handler) {
16816 			ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
16817 		} else {
16818 			ir_TAILCALL(IR_VOID, zend_jit_orig_opline_handler(jit));
16819 		}
16820 	} else {
16821 		if (original_handler) {
16822 			ir_ref ref;
16823 			ir_ref addr = zend_jit_orig_opline_handler(jit);
16824 
16825 #if defined(IR_TARGET_X86)
16826 			addr = ir_CAST_FC_FUNC(addr);
16827 #endif
16828 			ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
16829 			if (opline &&
16830 			    (opline->opcode == ZEND_RETURN
16831 			  || opline->opcode == ZEND_RETURN_BY_REF
16832 			  || opline->opcode == ZEND_GENERATOR_RETURN
16833 			  || opline->opcode == ZEND_GENERATOR_CREATE
16834 			  || opline->opcode == ZEND_YIELD
16835 			  || opline->opcode == ZEND_YIELD_FROM)) {
16836 				ir_RETURN(ref);
16837 				return 1;
16838 			}
16839 		}
16840 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
16841 	}
16842 	return 1;
16843 }
16844 
16845 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)
16846 {
16847 	return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
16848 }
16849 
16850 static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
16851 {
16852 	const void *link_addr;
16853 
16854 	/* Skip prologue. */
16855 	ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
16856 	link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
16857 
16858 	if (timeout_exit_addr) {
16859 		zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
16860 	}
16861 	ir_IJMP(ir_CONST_ADDR(link_addr));
16862 
16863 	return 1;
16864 }
16865 
16866 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)
16867 {
16868 	uint32_t op1_info, op2_info;
16869 
16870 	switch (opline->opcode) {
16871 		case ZEND_SEND_VAR:
16872 		case ZEND_SEND_VAL:
16873 		case ZEND_SEND_VAL_EX:
16874 			return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
16875 		case ZEND_QM_ASSIGN:
16876 		case ZEND_IS_SMALLER:
16877 		case ZEND_IS_SMALLER_OR_EQUAL:
16878 		case ZEND_IS_EQUAL:
16879 		case ZEND_IS_NOT_EQUAL:
16880 		case ZEND_IS_IDENTICAL:
16881 		case ZEND_IS_NOT_IDENTICAL:
16882 		case ZEND_CASE:
16883 			return 1;
16884 		case ZEND_RETURN:
16885 			return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
16886 		case ZEND_ASSIGN:
16887 			return (opline->op1_type == IS_CV);
16888 		case ZEND_ASSIGN_OP:
16889 			if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
16890 				return 0;
16891 			}
16892 			op1_info = OP1_INFO();
16893 			op2_info = OP2_INFO();
16894 			return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
16895 		case ZEND_ADD:
16896 		case ZEND_SUB:
16897 		case ZEND_MUL:
16898 			op1_info = OP1_INFO();
16899 			op2_info = OP2_INFO();
16900 			if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
16901 				return 0;
16902 			}
16903 			if (trace && trace->op1_type != IS_UNKNOWN) {
16904 				op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16905 			}
16906 			if (trace && trace->op2_type != IS_UNKNOWN) {
16907 				op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16908 			}
16909 			return !(op1_info & MAY_BE_UNDEF)
16910 				&& !(op2_info & MAY_BE_UNDEF)
16911 				&& (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
16912 				&& (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
16913 		case ZEND_BW_OR:
16914 		case ZEND_BW_AND:
16915 		case ZEND_BW_XOR:
16916 		case ZEND_SL:
16917 		case ZEND_SR:
16918 		case ZEND_MOD:
16919 			op1_info = OP1_INFO();
16920 			op2_info = OP2_INFO();
16921 			if (trace && trace->op1_type != IS_UNKNOWN) {
16922 				op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16923 			}
16924 			if (trace && trace->op2_type != IS_UNKNOWN) {
16925 				op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16926 			}
16927 			return (op1_info & MAY_BE_LONG)
16928 				&& (op2_info & MAY_BE_LONG);
16929 		case ZEND_PRE_INC:
16930 		case ZEND_PRE_DEC:
16931 		case ZEND_POST_INC:
16932 		case ZEND_POST_DEC:
16933 			op1_info = OP1_INFO();
16934 			return opline->op1_type == IS_CV
16935 				&& (op1_info & MAY_BE_LONG)
16936 				&& !(op1_info & MAY_BE_REF);
16937 		case ZEND_STRLEN:
16938 			op1_info = OP1_INFO();
16939 			return (opline->op1_type & (IS_CV|IS_CONST))
16940 				&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
16941 		case ZEND_COUNT:
16942 			op1_info = OP1_INFO();
16943 			return (opline->op1_type & (IS_CV|IS_CONST))
16944 				&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
16945 		case ZEND_JMPZ:
16946 		case ZEND_JMPNZ:
16947 			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
16948 				if (!ssa->cfg.map) {
16949 					return 0;
16950 				}
16951 				if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
16952 				    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
16953 					return 0;
16954 				}
16955 			}
16956 			ZEND_FALLTHROUGH;
16957 		case ZEND_BOOL:
16958 		case ZEND_BOOL_NOT:
16959 		case ZEND_JMPZ_EX:
16960 		case ZEND_JMPNZ_EX:
16961 			return 1;
16962 		case ZEND_FETCH_CONSTANT:
16963 			return 1;
16964 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
16965 			if ((opline->extended_value & ZEND_ISEMPTY)) {
16966 				return 0;
16967 			}
16968 			ZEND_FALLTHROUGH;
16969 		case ZEND_FETCH_DIM_R:
16970 		case ZEND_FETCH_DIM_IS:
16971 		case ZEND_FETCH_LIST_R:
16972 			op1_info = OP1_INFO();
16973 			op2_info = OP2_INFO();
16974 			if (trace
16975 			 && trace->op1_type != IS_UNKNOWN
16976 			 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
16977 				op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
16978 			}
16979 			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
16980 					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
16981 					 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
16982 		case ZEND_ASSIGN_DIM_OP:
16983 			if (opline->result_type != IS_UNUSED) {
16984 				return 0;
16985 			}
16986 			if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
16987 				return 0;
16988 			}
16989 			ZEND_FALLTHROUGH;
16990 		case ZEND_ASSIGN_DIM:
16991 		case ZEND_FETCH_DIM_W:
16992 		case ZEND_FETCH_DIM_RW:
16993 		case ZEND_FETCH_LIST_W:
16994 			op1_info = OP1_INFO();
16995 			op2_info = OP2_INFO();
16996 			if (trace) {
16997 				if (opline->op1_type == IS_CV) {
16998 					if ((opline->opcode == ZEND_ASSIGN_DIM
16999 					  || opline->opcode == ZEND_ASSIGN_DIM_OP)
17000 					 && (opline+1)->op1_type == IS_CV
17001 					 && (opline+1)->op1.var == opline->op1.var) {
17002 						/* skip $a[x] = $a; */
17003 						return 0;
17004 					}
17005 				} else if (opline->op1_type == IS_VAR) {
17006 					if (trace->op1_type == IS_UNKNOWN
17007 					 || !(trace->op1_type & IS_TRACE_INDIRECT)
17008 					 || opline->result_type != IS_UNUSED) {
17009 						return 0;
17010 					}
17011 				}
17012 				if (trace->op1_type != IS_UNKNOWN
17013 				 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17014 					op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17015 				}
17016 			} else {
17017 				if (opline->op1_type != IS_CV) {
17018 					return 0;
17019 				}
17020 			}
17021 			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17022 					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17023 					 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17024 		case ZEND_ASSIGN_OBJ_OP:
17025 			if (opline->result_type != IS_UNUSED) {
17026 				return 0;
17027 			}
17028 			if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17029 				return 0;
17030 			}
17031 			ZEND_FALLTHROUGH;
17032 		case ZEND_FETCH_OBJ_R:
17033 		case ZEND_ASSIGN_OBJ:
17034 			if (opline->op2_type != IS_CONST
17035 			 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
17036 			 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
17037 				return 0;
17038 			}
17039 			op1_info = OP1_INFO();
17040 			return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
17041 	}
17042 	return 0;
17043 }
17044 
17045 static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
17046 {
17047 	if (ssa->vars[var].no_val) {
17048 		/* we don't need the value */
17049 		return 0;
17050 	}
17051 
17052 	if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
17053 		/* Disable global register allocation,
17054 		 * register allocation for SSA variables connected through Phi functions
17055 		 */
17056 		if (ssa->vars[var].definition_phi) {
17057 			return 0;
17058 		}
17059 		if (ssa->vars[var].phi_use_chain) {
17060 			zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
17061 			do {
17062 				if (!ssa->vars[phi->ssa_var].no_val) {
17063 					return 0;
17064 				}
17065 				phi = zend_ssa_next_use_phi(ssa, var, phi);
17066 			} while (phi);
17067 		}
17068 	}
17069 
17070 	if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
17071 	    ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
17072 	    /* bad type */
17073 		return 0;
17074 	}
17075 
17076 	return 1;
17077 }
17078 
17079 static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17080 {
17081 	if (!zend_jit_var_supports_reg(ssa, var)) {
17082 		return 0;
17083 	}
17084 
17085 	if (ssa->vars[var].definition >= 0) {
17086 		uint32_t def = ssa->vars[var].definition;
17087 		if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17088 			return 0;
17089 		}
17090 	}
17091 
17092 	if (ssa->vars[var].use_chain >= 0) {
17093 		int use = ssa->vars[var].use_chain;
17094 
17095 		do {
17096 			if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17097 			    !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17098 				return 0;
17099 			}
17100 			use = zend_ssa_next_use(ssa->ops, var, use);
17101 		} while (use >= 0);
17102 	}
17103 
17104 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17105 		int def_block, use_block, b, use, j;
17106 		zend_basic_block *bb;
17107 		zend_ssa_phi *p;
17108 		bool ret = 1;
17109 		zend_worklist worklist;
17110 		ALLOCA_FLAG(use_heap)
17111 
17112 		/* Check if live range is split by ENTRY block */
17113 		if (ssa->vars[var].definition >= 0) {
17114 			def_block =ssa->cfg.map[ssa->vars[var].definition];
17115 		} else {
17116 			ZEND_ASSERT(ssa->vars[var].definition_phi);
17117 			def_block = ssa->vars[var].definition_phi->block;
17118 		}
17119 
17120 		ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
17121 
17122 		if (ssa->vars[var].use_chain >= 0) {
17123 			use = ssa->vars[var].use_chain;
17124 			do {
17125 				use_block = ssa->cfg.map[use];
17126 				if (use_block != def_block) {
17127 					zend_worklist_push(&worklist, use_block);
17128 				}
17129 				use = zend_ssa_next_use(ssa->ops, var, use);
17130 			} while (use >= 0);
17131 		}
17132 
17133 		p = ssa->vars[var].phi_use_chain;
17134 		while (p) {
17135 			use_block = p->block;
17136 			if (use_block != def_block) {
17137 				bb = &ssa->cfg.blocks[use_block];
17138 				for (j = 0; j < bb->predecessors_count; j++) {
17139 					if (p->sources[j] == var) {
17140 						use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
17141 						if (use_block != def_block) {
17142 							zend_worklist_push(&worklist, use_block);
17143 						}
17144 					}
17145 				}
17146 			}
17147 			p = zend_ssa_next_use_phi(ssa, var, p);
17148 		}
17149 
17150 		while (zend_worklist_len(&worklist) != 0) {
17151 			b = zend_worklist_pop(&worklist);
17152 			bb = &ssa->cfg.blocks[b];
17153 			if (bb->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
17154 				ret = 0;
17155 				break;
17156 			}
17157 			for (j = 0; j < bb->predecessors_count; j++) {
17158 				b = ssa->cfg.predecessors[bb->predecessor_offset + j];
17159 				if (b != def_block) {
17160 					zend_worklist_push(&worklist, b);
17161 				}
17162 			}
17163 		}
17164 
17165 		ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
17166 
17167 		return ret;
17168 	}
17169 
17170 	return 1;
17171 }
17172 
17173 static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
17174 	// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
17175 	ir_ref observer_handler;
17176 	zend_function *fbc = ZEND_FLF_FUNC(opline);
17177 	// Not need for runtime cache or generator checks here, we just need if_unobserved
17178 	ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17179 
17180 	// Call zend_frameless_observed_call for the main logic.
17181 	ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
17182 
17183 	ir_ref skip = ir_END();
17184 	ir_IF_TRUE(if_unobserved);
17185 	return skip;
17186 }
17187 
17188 static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
17189 {
17190 	jit_SET_EX_OPLINE(jit, opline);
17191 
17192 	void *function = ZEND_FLF_HANDLER(opline);
17193 	zend_jit_addr res_addr = RES_ADDR();
17194 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17195 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17196 
17197 	ir_ref skip_observer = IR_UNUSED;
17198 	if (ZEND_OBSERVER_ENABLED) {
17199 		skip_observer = jit_frameless_observer(jit, opline);
17200 	}
17201 
17202 	ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17203 
17204 	if (skip_observer != IR_UNUSED) {
17205 		ir_MERGE_WITH(skip_observer);
17206 	}
17207 
17208 	zend_jit_check_exception(jit);
17209 }
17210 
17211 static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
17212 {
17213 	jit_SET_EX_OPLINE(jit, opline);
17214 
17215 	/* Avoid dropping RC check in case op escapes. */
17216 	if (op1_info & MAY_BE_RC1) {
17217 		op1_info |= MAY_BE_RCN;
17218 	}
17219 
17220 	void *function = ZEND_FLF_HANDLER(opline);
17221 	zend_jit_addr res_addr = RES_ADDR();
17222 	zend_jit_addr op1_addr = OP1_ADDR();
17223 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17224 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17225 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17226 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17227 		op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17228 		op1_info &= ~MAY_BE_UNDEF;
17229 		op1_info |= MAY_BE_NULL;
17230 		op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17231 	}
17232 	if (op1_info & MAY_BE_REF) {
17233 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17234 	}
17235 
17236 	ir_ref skip_observer = IR_UNUSED;
17237 	if (ZEND_OBSERVER_ENABLED) {
17238 		skip_observer = jit_frameless_observer(jit, opline);
17239 	}
17240 
17241 	ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17242 
17243 	if (skip_observer != IR_UNUSED) {
17244 		ir_MERGE_WITH(skip_observer);
17245 	}
17246 
17247 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17248 	zend_jit_check_exception(jit);
17249 }
17250 
17251 static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
17252 {
17253 	jit_SET_EX_OPLINE(jit, opline);
17254 
17255 	/* Avoid dropping RC check in case op escapes. */
17256 	if (op1_info & MAY_BE_RC1) {
17257 		op1_info |= MAY_BE_RCN;
17258 	}
17259 	if (op2_info & MAY_BE_RC1) {
17260 		op2_info |= MAY_BE_RCN;
17261 	}
17262 
17263 	void *function = ZEND_FLF_HANDLER(opline);
17264 	zend_jit_addr res_addr = RES_ADDR();
17265 	zend_jit_addr op1_addr = OP1_ADDR();
17266 	zend_jit_addr op2_addr = OP2_ADDR();
17267 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17268 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17269 	ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17270 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17271 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17272 		op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17273 		op1_info &= ~MAY_BE_UNDEF;
17274 		op1_info |= MAY_BE_NULL;
17275 		op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17276 	}
17277 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17278 		op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17279 		op2_info &= ~MAY_BE_UNDEF;
17280 		op2_info |= MAY_BE_NULL;
17281 		op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17282 	}
17283 	if (op1_info & MAY_BE_REF) {
17284 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17285 	}
17286 	if (op2_info & MAY_BE_REF) {
17287 		op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17288 	}
17289 
17290 	ir_ref skip_observer = IR_UNUSED;
17291 	if (ZEND_OBSERVER_ENABLED) {
17292 		skip_observer = jit_frameless_observer(jit, opline);
17293 	}
17294 
17295 	ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17296 
17297 	if (skip_observer != IR_UNUSED) {
17298 		ir_MERGE_WITH(skip_observer);
17299 	}
17300 
17301 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17302 	/* Set OP1 to UNDEF in case FREE_OP2() throws. */
17303 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17304 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17305 	}
17306 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17307 	zend_jit_check_exception(jit);
17308 }
17309 
17310 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)
17311 {
17312 	jit_SET_EX_OPLINE(jit, opline);
17313 
17314 	/* Avoid dropping RC check in case op escapes. */
17315 	if (op1_info & MAY_BE_RC1) {
17316 		op1_info |= MAY_BE_RCN;
17317 	}
17318 	if (op2_info & MAY_BE_RC1) {
17319 		op2_info |= MAY_BE_RCN;
17320 	}
17321 	if (op1_data_info & MAY_BE_RC1) {
17322 		op1_data_info |= MAY_BE_RCN;
17323 	}
17324 
17325 	void *function = ZEND_FLF_HANDLER(opline);
17326 	uint8_t op_data_type = (opline + 1)->op1_type;
17327 	zend_jit_addr res_addr = RES_ADDR();
17328 	zend_jit_addr op1_addr = OP1_ADDR();
17329 	zend_jit_addr op2_addr = OP2_ADDR();
17330 	zend_jit_addr op3_addr = OP1_DATA_ADDR();
17331 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17332 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17333 	ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17334 	ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
17335 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17336 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17337 		op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17338 		op1_info &= ~MAY_BE_UNDEF;
17339 		op1_info |= MAY_BE_NULL;
17340 		op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17341 	}
17342 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17343 		op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17344 		op2_info &= ~MAY_BE_UNDEF;
17345 		op2_info |= MAY_BE_NULL;
17346 		op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17347 	}
17348 	if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
17349 		op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17350 		op1_data_info &= ~MAY_BE_UNDEF;
17351 		op1_data_info |= MAY_BE_NULL;
17352 		op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
17353 	}
17354 	if (op1_info & MAY_BE_REF) {
17355 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17356 	}
17357 	if (op2_info & MAY_BE_REF) {
17358 		op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17359 	}
17360 	if (op1_data_info & MAY_BE_REF) {
17361 		op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
17362 	}
17363 
17364 	ir_ref skip_observer = IR_UNUSED;
17365 	if (ZEND_OBSERVER_ENABLED) {
17366 		skip_observer = jit_frameless_observer(jit, opline);
17367 	}
17368 
17369 	ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17370 
17371 	if (skip_observer != IR_UNUSED) {
17372 		ir_MERGE_WITH(skip_observer);
17373 	}
17374 
17375 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17376 	/* Set OP1 to UNDEF in case FREE_OP2() throws. */
17377 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
17378 	 && ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
17379 	  || (op_data_type & (IS_VAR|IS_TMP_VAR)))) {
17380 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17381 	}
17382 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17383 	/* If OP1 is a TMP|VAR, we don't need to set OP2 to UNDEF on free because
17384 	 * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
17385 	if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR))
17386 	 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17387 	 && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17388 		jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
17389 	}
17390 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
17391 	zend_jit_check_exception(jit);
17392 }
17393 
17394 /*
17395  * Local variables:
17396  * tab-width: 4
17397  * c-basic-offset: 4
17398  * indent-tabs-mode: t
17399  * End:
17400  */
17401