xref: /php-src/ext/opcache/jit/zend_jit_ir.c (revision 6a2c5318)
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 		return 0;
1293 	}
1294 	return 1;
1295 }
1296 
zend_jit_def_reg(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref val)1297 static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
1298 {
1299 	int var;
1300 
1301 	ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1302 	var = Z_SSA_VAR(addr);
1303 	if (var == jit->delay_var) {
1304 		ir_refs_add(jit->delay_refs, val);
1305 		return;
1306 	}
1307 	ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
1308 
1309 	/* Negative "var" has special meaning for IR */
1310 	if (val > 0 && !zend_jit_spilling_may_cause_conflict(jit, var, val)) {
1311 		val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
1312 	}
1313 	jit->ra[var].ref = val;
1314 
1315 	if (jit->ra[var].flags & ZREG_FORWARD) {
1316 		zend_ssa_phi *phi = jit->ssa->vars[var].phi_use_chain;
1317 		zend_basic_block *bb;
1318 		int n, j, *p;
1319 		ir_ref *q;
1320 
1321 		jit->ra[var].flags &= ~ZREG_FORWARD;
1322 		while (phi != NULL) {
1323 			zend_ssa_phi *dst_phi = phi;
1324 			int src_var = var;
1325 
1326 			if (dst_phi->pi >= 0) {
1327 				jit->ra[src_var].ref = val;
1328 				src_var = dst_phi->ssa_var;
1329 				if (!(jit->ra[src_var].flags & ZREG_FORWARD)) {
1330 					phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1331 					continue;
1332 				}
1333 				dst_phi = jit->ssa->vars[src_var].phi_use_chain;
1334 				ZEND_ASSERT(dst_phi != NULL && "reg forwarding");
1335 				ZEND_ASSERT(!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding");
1336 				jit->ra[src_var].flags &= ~ZREG_FORWARD;
1337 			}
1338 
1339 			if (jit->ra[dst_phi->ssa_var].ref > 0) {
1340 				ir_insn *phi_insn = &jit->ctx.ir_base[jit->ra[dst_phi->ssa_var].ref];
1341 				if (phi_insn->op == IR_PHI) {
1342 //					ZEND_ASSERT(ir_operands_count(ctx, phi_insn) == n + 1);
1343 					bb = &jit->ssa->cfg.blocks[dst_phi->block];
1344 					n = bb->predecessors_count;
1345 					for (j = 0, p = &dst_phi->sources[0], q = phi_insn->ops + 2; j < n; j++, p++, q++) {
1346 						if (*p == src_var) {
1347 							*q = val;
1348 						}
1349 					}
1350 				}
1351 			}
1352 
1353 			phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1354 		}
1355 	}
1356 }
1357 
zend_jit_use_reg(zend_jit_ctx * jit,zend_jit_addr addr)1358 static ir_ref zend_jit_use_reg(zend_jit_ctx *jit, zend_jit_addr addr)
1359 {
1360 	int var = Z_SSA_VAR(addr);
1361 
1362 	ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1363 	ZEND_ASSERT(jit->ra && jit->ra[var].ref);
1364 	if (jit->ra[var].ref == IR_NULL) {
1365 		zend_jit_addr mem_addr;
1366 		ir_ref ref;
1367 
1368 		ZEND_ASSERT(jit->ra[var].flags & ZREG_LOAD);
1369 		mem_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(jit->ssa->vars[var].var));
1370 		if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_LONG) {
1371 			ref = jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1372 		} else if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1373 			ref = jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1374 		} else {
1375 			ZEND_UNREACHABLE();
1376 		}
1377 		zend_jit_def_reg(jit, addr, ref);
1378 		return ref;
1379 	}
1380 	return jit->ra[Z_SSA_VAR(addr)].ref;
1381 }
1382 
zend_jit_gen_pi(zend_jit_ctx * jit,zend_ssa_phi * phi)1383 static void zend_jit_gen_pi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1384 {
1385 	int src_var = phi->sources[0];
1386 	int dst_var = phi->ssa_var;
1387 
1388 	ZEND_ASSERT(phi->pi >= 0);
1389 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1390 	ZEND_ASSERT(jit->ra[src_var].ref);
1391 
1392 	if (jit->ra[src_var].ref == IR_NULL) {
1393 		/* Not defined yet */
1394 		if (jit->ssa->vars[dst_var].use_chain < 0
1395 		 && jit->ssa->vars[dst_var].phi_use_chain) {
1396 			zend_ssa_phi *phi = jit->ssa->vars[dst_var].phi_use_chain;
1397 			if (!zend_ssa_next_use_phi(jit->ssa, dst_var, phi)) {
1398 				/* This is a Pi forwarded to Phi */
1399 				jit->ra[src_var].flags |= ZREG_FORWARD;
1400 				return;
1401 			}
1402 		}
1403 		ZEND_ASSERT(0 && "Not defined Pi source");
1404 	}
1405 	/* Reuse register */
1406 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var),
1407 		zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)));
1408 }
1409 
zend_jit_gen_phi(zend_jit_ctx * jit,zend_ssa_phi * phi)1410 static void zend_jit_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1411 {
1412 	int dst_var = phi->ssa_var;
1413 	zend_basic_block *bb = &jit->ssa->cfg.blocks[phi->block];
1414 	int n = bb->predecessors_count;
1415 	int i;
1416 	ir_type type = (jit->ssa->var_info[phi->ssa_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE;
1417 	ir_ref merge = jit->bb_start_ref[phi->block];
1418 	ir_ref ref;
1419 	ir_ref old_insns_count = jit->ctx.insns_count;
1420 	ir_ref same_src_ref = IR_UNUSED;
1421 	bool phi_inputs_are_the_same = 1;
1422 
1423 	ZEND_ASSERT(phi->pi < 0);
1424 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1425 	ZEND_ASSERT(merge);
1426 	ZEND_ASSERT(jit->ctx.ir_base[merge].op == IR_MERGE || jit->ctx.ir_base[merge].op == IR_LOOP_BEGIN);
1427 	ZEND_ASSERT(n == jit->ctx.ir_base[merge].inputs_count);
1428 
1429 	ref = ir_emit_N(&jit->ctx, IR_OPT(IR_PHI, type), n + 1);
1430 	ir_set_op(&jit->ctx, ref, 1, merge);
1431 
1432 	for (i = 0; i < n; i++) {
1433 		int src_var = phi->sources[i];
1434 
1435 		ZEND_ASSERT(jit->ra[src_var].ref);
1436 		if (jit->ra[src_var].ref == IR_NULL) {
1437 			jit->ra[src_var].flags |= ZREG_FORWARD;
1438 			phi_inputs_are_the_same = 0;
1439 		} else {
1440 			ir_ref src_ref = zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var));
1441 			if (i == 0) {
1442 				same_src_ref = src_ref;
1443 			} else if (same_src_ref != src_ref) {
1444 				phi_inputs_are_the_same = 0;
1445 			}
1446 			ir_set_op(&jit->ctx, ref, i + 2, src_ref);
1447 		}
1448 	}
1449 	if (phi_inputs_are_the_same) {
1450 		ref = same_src_ref;
1451 		jit->ctx.insns_count = old_insns_count;
1452 	}
1453 
1454 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
1455 }
1456 
jit_Z_LVAL(zend_jit_ctx * jit,zend_jit_addr addr)1457 static ir_ref jit_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1458 {
1459 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1460 		return ir_CONST_LONG(Z_LVAL_P(Z_ZV(addr)));
1461 	} else if (Z_MODE(addr) == IS_REG) {
1462 		return zend_jit_use_reg(jit, addr);
1463 	} else {
1464 		return jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1465 	}
1466 }
1467 
jit_set_Z_LVAL(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref lval)1468 static void jit_set_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1469 {
1470 	if (Z_MODE(addr) == IS_REG) {
1471 		zend_jit_def_reg(jit, addr, lval);
1472 	} else {
1473 		ir_STORE(jit_ZVAL_ADDR(jit, addr), lval);
1474 	}
1475 }
1476 
1477 #if SIZEOF_ZEND_LONG == 4
jit_Z_W2(zend_jit_ctx * jit,zend_jit_addr addr)1478 static ir_ref jit_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr)
1479 {
1480 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1481 		return ir_CONST_U32((Z_ZV(addr))->value.ww.w2);
1482 	} else {
1483 		return ir_LOAD_L(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)));
1484 	}
1485 }
1486 
jit_set_Z_W2(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref lval)1487 static void jit_set_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1488 {
1489 	ir_STORE(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)), lval);
1490 }
1491 #endif
1492 
jit_Z_DVAL(zend_jit_ctx * jit,zend_jit_addr addr)1493 static ir_ref jit_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1494 {
1495 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1496 		return ir_CONST_DOUBLE(Z_DVAL_P(Z_ZV(addr)));
1497 	} else if (Z_MODE(addr) == IS_REG) {
1498 		return zend_jit_use_reg(jit, addr);
1499 	} else {
1500 		return jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1501 	}
1502 }
1503 
jit_set_Z_DVAL(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref dval)1504 static void jit_set_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref dval)
1505 {
1506 	if (Z_MODE(addr) == IS_REG) {
1507 		zend_jit_def_reg(jit, addr, dval);
1508 	} else {
1509 		ir_STORE(jit_ZVAL_ADDR(jit, addr), dval);
1510 	}
1511 }
1512 
jit_Z_PTR_ref(zend_jit_ctx * jit,ir_ref ref)1513 static ir_ref jit_Z_PTR_ref(zend_jit_ctx *jit, ir_ref ref)
1514 {
1515 	return ir_LOAD_A(ref);
1516 }
1517 
jit_Z_PTR(zend_jit_ctx * jit,zend_jit_addr addr)1518 static ir_ref jit_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr)
1519 {
1520 	if (Z_MODE(addr) == IS_CONST_ZVAL) {
1521 		return ir_CONST_ADDR(Z_PTR_P(Z_ZV(addr)));
1522 	} else {
1523 		return jit_Z_PTR_ref(jit, jit_ZVAL_ADDR(jit, addr));
1524 	}
1525 }
1526 
jit_set_Z_PTR(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref ptr)1527 static void jit_set_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref ptr)
1528 {
1529 	ir_STORE(jit_ZVAL_ADDR(jit, addr), ptr);
1530 }
1531 
jit_GC_REFCOUNT(zend_jit_ctx * jit,ir_ref ref)1532 static ir_ref jit_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref)
1533 {
1534 	return ir_LOAD_U32(ref);
1535 }
1536 
jit_set_GC_REFCOUNT(zend_jit_ctx * jit,ir_ref ref,uint32_t refcount)1537 static void jit_set_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref, uint32_t refcount)
1538 {
1539 	ir_STORE(ref, ir_CONST_U32(refcount));
1540 }
1541 
jit_GC_ADDREF(zend_jit_ctx * jit,ir_ref ref)1542 static void jit_GC_ADDREF(zend_jit_ctx *jit, ir_ref ref)
1543 {
1544 	ir_STORE(ref, ir_ADD_U32(ir_LOAD_U32(ref), ir_CONST_U32(1)));
1545 }
1546 
jit_GC_ADDREF2(zend_jit_ctx * jit,ir_ref ref)1547 static void jit_GC_ADDREF2(zend_jit_ctx *jit, ir_ref ref)
1548 {
1549 	ir_ref counter = ir_LOAD_U32(ref);
1550 	ir_STORE(ref, ir_ADD_U32(counter, ir_CONST_U32(2)));
1551 }
1552 
jit_GC_DELREF(zend_jit_ctx * jit,ir_ref ref)1553 static ir_ref jit_GC_DELREF(zend_jit_ctx *jit, ir_ref ref)
1554 {
1555 	ir_ref counter = ir_LOAD_U32(ref);
1556 	counter = ir_SUB_U32(counter, ir_CONST_U32(1));
1557 	ir_STORE(ref, counter);
1558 	return counter;
1559 }
1560 
jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx * jit,ir_ref ref)1561 static ir_ref jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx *jit, ir_ref ref)
1562 {
1563 	return ir_IF(
1564 		ir_AND_U32(
1565 			ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_refcounted, gc.u.type_info))),
1566 			ir_CONST_U32(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))));
1567 }
1568 
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)1569 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)
1570 {
1571 	ir_ref ref = IR_UNUSED;
1572 
1573 	if (Z_TYPE_P(zv) > IS_TRUE) {
1574 		if (Z_TYPE_P(zv) == IS_DOUBLE) {
1575 			jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE(Z_DVAL_P(zv)));
1576 		} else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
1577 			jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE((double)Z_LVAL_P(zv)));
1578 		} else if (Z_TYPE_P(zv) == IS_LONG) {
1579 			jit_set_Z_LVAL(jit, dst, ir_CONST_LONG(Z_LVAL_P(zv)));
1580 		} else {
1581 			ref = ir_CONST_ADDR(Z_PTR_P(zv));
1582 			jit_set_Z_PTR(jit, dst, ref);
1583 			if (addref && Z_REFCOUNTED_P(zv)) {
1584 				jit_GC_ADDREF(jit, ref);
1585 			}
1586 		}
1587 	}
1588 	if (Z_MODE(dst) != IS_REG) {
1589 		if (dst_def_info == MAY_BE_DOUBLE) {
1590 			if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1591 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
1592 			}
1593 		} 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) {
1594 			jit_set_Z_TYPE_INFO(jit, dst, Z_TYPE_INFO_P(zv));
1595 		}
1596 	}
1597 }
1598 
jit_if_TYPED_REF(zend_jit_ctx * jit,ir_ref ref)1599 static ir_ref jit_if_TYPED_REF(zend_jit_ctx *jit, ir_ref ref)
1600 {
1601 	return ir_IF(ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr))));
1602 }
1603 
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)1604 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)
1605 {
1606 	ir_ref ref = IR_UNUSED;
1607 
1608 	if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1609 		if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1610 			jit_set_Z_LVAL(jit, dst, jit_Z_LVAL(jit, src));
1611 		} else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1612 			jit_set_Z_DVAL(jit, dst, jit_Z_DVAL(jit, src));
1613 		} else {
1614 #if SIZEOF_ZEND_LONG == 4
1615 			if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1616 				jit_set_Z_W2(jit, dst, jit_Z_W2(jit, src));
1617 			}
1618 #endif
1619 			ref = jit_Z_PTR(jit, src);
1620 			jit_set_Z_PTR(jit, dst, ref);
1621 		}
1622 	}
1623 	if (has_concrete_type(src_info & MAY_BE_ANY)
1624 	 && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1625      && !(src_info & MAY_BE_GUARD)) {
1626 		if (Z_MODE(dst) != IS_REG
1627 		 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1628 			uint8_t type = concrete_type(src_info);
1629 			jit_set_Z_TYPE_INFO(jit, dst, type);
1630 		}
1631 	} else {
1632 		ir_ref type = jit_Z_TYPE_INFO(jit, src);
1633 		jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1634 		if (addref) {
1635 			if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1636 				ir_ref if_refcounted = IR_UNUSED;
1637 
1638 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1639 					if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1640 					ir_IF_TRUE(if_refcounted);
1641 				}
1642 
1643 				jit_GC_ADDREF(jit, ref);
1644 
1645 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1646 					ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1647 				}
1648 			}
1649 		}
1650 	}
1651 }
1652 
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)1653 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)
1654 {
1655 	ir_ref ref = IR_UNUSED;
1656 
1657 	if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1658 		if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1659 			ref = jit_Z_LVAL(jit, src);
1660 			jit_set_Z_LVAL(jit, dst, ref);
1661 			jit_set_Z_LVAL(jit, dst2, ref);
1662 		} else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1663 			ref = jit_Z_DVAL(jit, src);
1664 			jit_set_Z_DVAL(jit, dst, ref);
1665 			jit_set_Z_DVAL(jit, dst2, ref);
1666 		} else {
1667 #if SIZEOF_ZEND_LONG == 4
1668 			if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1669 				ref = jit_Z_W2(jit, src);
1670 				jit_set_Z_W2(jit, dst, ref);
1671 				jit_set_Z_W2(jit, dst2, ref);
1672 			}
1673 #endif
1674 			ref = jit_Z_PTR(jit, src);
1675 			jit_set_Z_PTR(jit, dst, ref);
1676 			jit_set_Z_PTR(jit, dst2, ref);
1677 		}
1678 	}
1679 	if (has_concrete_type(src_info & MAY_BE_ANY)
1680 	 && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1681      && !(src_info & MAY_BE_GUARD)) {
1682 		uint8_t type = concrete_type(src_info);
1683 		ir_ref type_ref = ir_CONST_U32(type);
1684 
1685 		if (Z_MODE(dst) != IS_REG
1686 		 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1687 			jit_set_Z_TYPE_INFO_ex(jit, dst, type_ref);
1688 		}
1689 		if (Z_MODE(dst2) != IS_REG) {
1690 			jit_set_Z_TYPE_INFO_ex(jit, dst2, type_ref);
1691 		}
1692 	} else {
1693 		ir_ref type = jit_Z_TYPE_INFO(jit, src);
1694 		jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1695 		jit_set_Z_TYPE_INFO_ex(jit, dst2, type);
1696 		if (addref) {
1697 			if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1698 				ir_ref if_refcounted = IR_UNUSED;
1699 
1700 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1701 					if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1702 					ir_IF_TRUE(if_refcounted);
1703 				}
1704 
1705 				if (addref == 2) {
1706 					jit_GC_ADDREF2(jit, ref);
1707 				} else {
1708 					jit_GC_ADDREF(jit, ref);
1709 				}
1710 
1711 				if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1712 					ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1713 				}
1714 			}
1715 		}
1716 	}
1717 }
1718 
jit_ZVAL_DTOR(zend_jit_ctx * jit,ir_ref ref,uint32_t op_info,const zend_op * opline)1719 static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const zend_op *opline)
1720 {
1721 	if (!((op_info) & MAY_BE_GUARD)
1722 	 && has_concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1723 		uint8_t type = concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1724 		if (type == IS_STRING && !ZEND_DEBUG) {
1725 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(_efree), ref);
1726 				return;
1727 		} else if (type == IS_ARRAY) {
1728 			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)) {
1729 				if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1730 					jit_SET_EX_OPLINE(jit, opline);
1731 				}
1732 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_array_destroy), ref);
1733 			} else {
1734 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_array_free), ref);
1735 			}
1736 			return;
1737 		} else if (type == IS_OBJECT) {
1738 			if (opline) {
1739 				jit_SET_EX_OPLINE(jit, opline);
1740 			}
1741 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1742 			return;
1743 		}
1744 	}
1745 	if (opline) {
1746 		jit_SET_EX_OPLINE(jit, opline);
1747 	}
1748 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(rc_dtor_func), ref);
1749 }
1750 
jit_ZVAL_PTR_DTOR(zend_jit_ctx * jit,zend_jit_addr addr,uint32_t op_info,bool gc,const zend_op * opline)1751 static void jit_ZVAL_PTR_DTOR(zend_jit_ctx  *jit,
1752                               zend_jit_addr  addr,
1753                               uint32_t       op_info,
1754                               bool           gc,
1755                               const zend_op *opline)
1756 {
1757     ir_ref ref, ref2;
1758 	ir_ref if_refcounted = IR_UNUSED;
1759 	ir_ref if_not_zero = IR_UNUSED;
1760 	ir_ref end_inputs = IR_UNUSED;
1761 
1762 	if (op_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
1763 		if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1764 			if_refcounted = jit_if_REFCOUNTED(jit, addr);
1765 			ir_IF_FALSE(if_refcounted);
1766 			ir_END_list(end_inputs);
1767 			ir_IF_TRUE(if_refcounted);
1768 		}
1769 		ref = jit_Z_PTR(jit, addr);
1770 		ref2 = jit_GC_DELREF(jit, ref);
1771 
1772 		if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1773 			if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1774 				if_not_zero = ir_IF(ref2);
1775 				ir_IF_FALSE(if_not_zero);
1776 			}
1777 			// zval_dtor_func(r);
1778 			jit_ZVAL_DTOR(jit, ref, op_info, opline);
1779 			if (if_not_zero) {
1780 				ir_END_list(end_inputs);
1781 				ir_IF_TRUE(if_not_zero);
1782 			}
1783 		}
1784 		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))) {
1785 			ir_ref if_may_not_leak;
1786 
1787 			if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1788 				ir_ref if_ref, if_collectable;
1789 
1790 				if_ref = jit_if_Z_TYPE(jit, addr, IS_REFERENCE);
1791 				ir_IF_TRUE(if_ref);
1792 
1793 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
1794 
1795 				if_collectable = jit_if_COLLECTABLE_ref(jit, ref2);
1796 				ir_IF_FALSE(if_collectable);
1797 				ir_END_list(end_inputs);
1798 				ir_IF_TRUE(if_collectable);
1799 
1800 				ref2 = jit_Z_PTR_ref(jit, ref2);
1801 
1802 				ir_MERGE_WITH_EMPTY_FALSE(if_ref);
1803 				ref = ir_PHI_2(IR_ADDR, ref2, ref);
1804 			}
1805 
1806 			if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1807 			ir_IF_TRUE(if_may_not_leak);
1808 			ir_END_list(end_inputs);
1809 			ir_IF_FALSE(if_may_not_leak);
1810 
1811 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1812 		}
1813 
1814 		if (end_inputs) {
1815 			ir_END_list(end_inputs);
1816 			ir_MERGE_list(end_inputs);
1817 		}
1818 	}
1819 }
1820 
jit_FREE_OP(zend_jit_ctx * jit,uint8_t op_type,znode_op op,uint32_t op_info,const zend_op * opline)1821 static void jit_FREE_OP(zend_jit_ctx  *jit,
1822                         uint8_t        op_type,
1823                         znode_op       op,
1824                         uint32_t       op_info,
1825                         const zend_op *opline)
1826 {
1827 	if (op_type & (IS_VAR|IS_TMP_VAR)) {
1828 		jit_ZVAL_PTR_DTOR(jit,
1829 			ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var),
1830 			op_info, 0, opline);
1831 	}
1832 }
1833 
jit_OBJ_RELEASE(zend_jit_ctx * jit,ir_ref ref)1834 static void jit_OBJ_RELEASE(zend_jit_ctx  *jit, ir_ref ref)
1835 {
1836 	ir_ref end_inputs = IR_UNUSED;
1837     ir_ref if_not_zero, if_may_not_leak;
1838 
1839 	// JIT: if (GC_DELREF(obj) == 0) {
1840 	if_not_zero = ir_IF(jit_GC_DELREF(jit, ref));
1841 	ir_IF_FALSE(if_not_zero);
1842 
1843 	// JIT: zend_objects_store_del(obj)
1844 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1845 	ir_END_list(end_inputs);
1846 
1847 	ir_IF_TRUE(if_not_zero);
1848 	if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1849 
1850 	ir_IF_TRUE(if_may_not_leak);
1851 	ir_END_list(end_inputs);
1852 
1853 	ir_IF_FALSE(if_may_not_leak);
1854 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1855 	ir_END_list(end_inputs);
1856 
1857 	ir_MERGE_list(end_inputs);
1858 }
1859 
zend_jit_check_timeout(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr)1860 static int zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
1861 {
1862 	ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
1863 
1864 	if (exit_addr) {
1865 		ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1866 	} else if (!opline || jit->last_valid_opline == opline) {
1867 		ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1868 	} else {
1869 		ir_ref if_timeout = ir_IF(ref);
1870 
1871 		ir_IF_TRUE_cold(if_timeout);
1872 		jit_LOAD_IP_ADDR(jit, opline);
1873 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1874 		ir_IF_FALSE(if_timeout);
1875 	}
1876 	return 1;
1877 }
1878 
1879 /* stubs */
1880 
zend_jit_exception_handler_stub(zend_jit_ctx * jit)1881 static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
1882 {
1883 	const void *handler;
1884 
1885 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1886 		handler = zend_get_opcode_handler_func(EG(exception_op));
1887 
1888 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
1889 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
1890 	} else {
1891 		handler = EG(exception_op)->handler;
1892 
1893 		if (GCC_GLOBAL_REGS) {
1894 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
1895 		} else {
1896 			ir_ref ref, if_negative;
1897 
1898 			ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), jit_FP(jit));
1899 			if_negative = ir_IF(ir_LT(ref, ir_CONST_U32(0)));
1900 			ir_IF_TRUE(if_negative);
1901 			ir_MERGE_WITH_EMPTY_FALSE(if_negative);
1902 			ref = ir_PHI_2(IR_I32, ref, ir_CONST_I32(1));
1903 			ir_RETURN(ref);
1904 		}
1905 	}
1906 	return 1;
1907 }
1908 
zend_jit_exception_handler_undef_stub(zend_jit_ctx * jit)1909 static int zend_jit_exception_handler_undef_stub(zend_jit_ctx *jit)
1910 {
1911 	ir_ref ref, result_type, if_result_used;
1912 
1913 	ref = jit_EG(opline_before_exception);
1914 	result_type = ir_LOAD_U8(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result_type)));
1915 
1916 	if_result_used = ir_IF(ir_AND_U8(result_type, ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1917 	ir_IF_TRUE(if_result_used);
1918 
1919 	ref = ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result.var)));
1920 	if (sizeof(void*) == 8) {
1921 		ref = ir_ZEXT_A(ref);
1922 	}
1923 	ir_STORE(ir_ADD_OFFSET(ir_ADD_A(jit_FP(jit), ref), offsetof(zval, u1.type_info)), ir_CONST_U32(IS_UNDEF));
1924 	ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
1925 
1926 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
1927 
1928 	return 1;
1929 }
1930 
zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx * jit)1931 static int zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx *jit)
1932 {
1933 	ir_ref ref, if_dtor;
1934 	zend_jit_addr var_addr;
1935 
1936 	ref = ir_LOAD_A(jit_EG(opline_before_exception));
1937 	if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op1_type))),
1938 		ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1939 	ir_IF_TRUE(if_dtor);
1940 	ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op1.var)));
1941 	if (sizeof(void*) == 8) {
1942 		ref = ir_ZEXT_A(ref);
1943 	}
1944 	ref = ir_ADD_A(jit_FP(jit), ref);
1945 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
1946 	jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
1947 	ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
1948 
1949 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
1950 
1951 	return 1;
1952 }
1953 
zend_jit_exception_handler_free_op2_stub(zend_jit_ctx * jit)1954 static int zend_jit_exception_handler_free_op2_stub(zend_jit_ctx *jit)
1955 {
1956 	ir_ref ref, if_dtor;
1957 	zend_jit_addr var_addr;
1958 
1959 	ref = ir_LOAD_A(jit_EG(opline_before_exception));
1960 	if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op2_type))),
1961 		ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1962 	ir_IF_TRUE(if_dtor);
1963 	ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.var)));
1964 	if (sizeof(void*) == 8) {
1965 		ref = ir_ZEXT_A(ref);
1966 	}
1967 	ref = ir_ADD_A(jit_FP(jit), ref);
1968 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
1969 	jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
1970 	ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
1971 
1972 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
1973 
1974 	return 1;
1975 }
1976 
zend_jit_interrupt_handler_stub(zend_jit_ctx * jit)1977 static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit)
1978 {
1979 	ir_ref if_timeout, if_exception;
1980 
1981 	if (GCC_GLOBAL_REGS) {
1982 		// EX(opline) = opline
1983 		ir_STORE(jit_EX(opline), jit_IP(jit));
1984 	}
1985 
1986 	ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0));
1987 	if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0)));
1988 	ir_IF_FALSE(if_timeout);
1989 	ir_CALL(IR_VOID, ir_CONST_FUNC(zend_timeout));
1990 	ir_MERGE_WITH_EMPTY_TRUE(if_timeout);
1991 
1992 	if (zend_interrupt_function) {
1993 		ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_interrupt_function), jit_FP(jit));
1994 		if_exception = ir_IF(ir_LOAD_A(jit_EG(exception)));
1995 		ir_IF_TRUE(if_exception);
1996 		ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper));
1997 		ir_MERGE_WITH_EMPTY_FALSE(if_exception);
1998 
1999 		jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
2000 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2001 	}
2002 
2003 	if (GCC_GLOBAL_REGS) {
2004 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2005 	} else {
2006 		ir_RETURN(ir_CONST_I32(1));
2007 	}
2008 	return 1;
2009 }
2010 
zend_jit_leave_function_handler_stub(zend_jit_ctx * jit)2011 static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit)
2012 {
2013 	ir_ref call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
2014 	ir_ref if_top = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_TOP)));
2015 
2016 	ir_IF_FALSE(if_top);
2017 
2018 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2019 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2020 		jit_STORE_IP(jit,
2021 			ir_LOAD_A(jit_EX(opline)));
2022 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2023 	} else if (GCC_GLOBAL_REGS) {
2024 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2025 	} else {
2026 		ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info, jit_FP(jit));
2027 	}
2028 
2029 	ir_IF_TRUE(if_top);
2030 
2031 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2032 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2033 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2034 	} else if (GCC_GLOBAL_REGS) {
2035 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2036 	} else {
2037 		ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info, jit_FP(jit));
2038 	}
2039 
2040 	return 1;
2041 }
2042 
zend_jit_negative_shift_stub(zend_jit_ctx * jit)2043 static int zend_jit_negative_shift_stub(zend_jit_ctx *jit)
2044 {
2045 	ir_CALL_2(IR_VOID,
2046 		ir_CONST_FUNC_PROTO(zend_throw_error,
2047 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2048 		ir_CONST_ADDR(zend_ce_arithmetic_error),
2049 		ir_CONST_ADDR("Bit shift by negative number"));
2050 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2051 	return 1;
2052 }
2053 
zend_jit_mod_by_zero_stub(zend_jit_ctx * jit)2054 static int zend_jit_mod_by_zero_stub(zend_jit_ctx *jit)
2055 {
2056 	ir_CALL_2(IR_VOID,
2057 		ir_CONST_FUNC_PROTO(zend_throw_error,
2058 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2059 		ir_CONST_ADDR(zend_ce_division_by_zero_error),
2060 		ir_CONST_ADDR("Modulo by zero"));
2061 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2062 	return 1;
2063 }
2064 
zend_jit_invalid_this_stub(zend_jit_ctx * jit)2065 static int zend_jit_invalid_this_stub(zend_jit_ctx *jit)
2066 {
2067 	ir_CALL_2(IR_VOID,
2068 		ir_CONST_FUNC_PROTO(zend_throw_error,
2069 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2070 		IR_NULL,
2071 		ir_CONST_ADDR("Using $this when not in object context"));
2072 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2073 	return 1;
2074 }
2075 
zend_jit_undefined_function_stub(zend_jit_ctx * jit)2076 static int zend_jit_undefined_function_stub(zend_jit_ctx *jit)
2077 {
2078 	// JIT: load EX(opline)
2079 	ir_ref ref = ir_LOAD_A(jit_FP(jit));
2080 	ir_ref arg3 = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.constant)));
2081 
2082 	if (sizeof(void*) == 8) {
2083 		arg3 = ir_LOAD_A(ir_ADD_A(ref, ir_SEXT_A(arg3)));
2084 	} else {
2085 		arg3 = ir_LOAD_A(arg3);
2086 	}
2087 	arg3 = ir_ADD_OFFSET(arg3, offsetof(zend_string, val));
2088 
2089 	ir_CALL_3(IR_VOID,
2090 		ir_CONST_FUNC_PROTO(zend_throw_error,
2091 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2092 		IR_NULL,
2093 		ir_CONST_ADDR("Call to undefined function %s()"),
2094 		arg3);
2095 
2096 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2097 
2098 	return 1;
2099 }
2100 
zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx * jit)2101 static int zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx *jit)
2102 {
2103 	ir_ref opline, ref, rx, if_eq, if_tmp;
2104 
2105 	// JIT: opline = EX(opline)
2106 	opline = ir_LOAD_A(jit_FP(jit));
2107 
2108 	// JIT: ZVAL_UNDEF(ZEND_CALL_VAR(RX, opline->result.var))
2109 	ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2110 	if (sizeof(void*) == 8) {
2111 		ref = ir_ZEXT_A(ref);
2112 	}
2113 	rx = jit_IP(jit);
2114 	jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(rx, ref), ir_CONST_U32(IS_UNDEF));
2115 
2116 	// last EX(call) frame may be delayed
2117 	// JIT: if (EX(call) == RX)
2118 	ref = ir_LOAD_A(jit_EX(call));
2119 	if_eq = ir_IF(ir_EQ(rx, ref));
2120 	ir_IF_FALSE(if_eq);
2121 
2122 	// JIT: RX->prev_execute_data == EX(call)
2123 	ir_STORE(jit_CALL(rx, prev_execute_data), ref);
2124 
2125 	// JIT: EX(call) = RX
2126 	ir_STORE(jit_EX(call), rx);
2127 	ir_MERGE_WITH_EMPTY_TRUE(if_eq);
2128 
2129 	// JIT: IP = opline
2130 	jit_STORE_IP(jit, opline);
2131 
2132 	// JIT: zend_cannot_pass_by_reference(opline->op2.num)
2133 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_cannot_pass_by_reference),
2134 		ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.num))));
2135 
2136 	// JIT: if (IP->op1_type == IS_TMP_VAR)
2137 	ref = ir_LOAD_U8(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1_type)));
2138 	if_tmp = ir_IF(ir_EQ(ref, ir_CONST_U8(IS_TMP_VAR)));
2139 	ir_IF_TRUE(if_tmp);
2140 
2141 	// JIT: zval_ptr_dtor(EX_VAR(IP->op1.var))
2142 	ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1.var)));
2143 	if (sizeof(void*) == 8) {
2144 		ref = ir_ZEXT_A(ref);
2145 	}
2146 	ref = ir_ADD_A(jit_FP(jit), ref);
2147 	jit_ZVAL_PTR_DTOR(jit,
2148 		ZEND_ADDR_REF_ZVAL(ref),
2149 		MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
2150 	ir_MERGE_WITH_EMPTY_FALSE(if_tmp);
2151 
2152 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2153 
2154 	return 1;
2155 }
2156 
zend_jit_icall_throw_stub(zend_jit_ctx * jit)2157 static int zend_jit_icall_throw_stub(zend_jit_ctx *jit)
2158 {
2159 	ir_ref ip, if_set;
2160 
2161 	// JIT: zend_rethrow_exception(zend_execute_data *execute_data)
2162 	// JIT: if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
2163 	jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2164 	ip = jit_IP(jit);
2165 	if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2166 		ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2167 	ir_IF_FALSE(if_set);
2168 
2169 	// JIT: EG(opline_before_exception) = opline;
2170 	ir_STORE(jit_EG(opline_before_exception), ip);
2171 	ir_MERGE_WITH_EMPTY_TRUE(if_set);
2172 
2173 	// JIT: opline = EG(exception_op);
2174 	jit_STORE_IP(jit, jit_EG(exception_op));
2175 
2176 	if (GCC_GLOBAL_REGS) {
2177 		ir_STORE(jit_EX(opline), jit_IP(jit));
2178 	}
2179 
2180 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2181 
2182 	return 1;
2183 }
2184 
zend_jit_leave_throw_stub(zend_jit_ctx * jit)2185 static int zend_jit_leave_throw_stub(zend_jit_ctx *jit)
2186 {
2187 	ir_ref ip, if_set;
2188 
2189 	// JIT: if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
2190 	jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2191 	ip = jit_IP(jit);
2192 	if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2193 		ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2194 	ir_IF_FALSE(if_set);
2195 
2196 	// JIT: EG(opline_before_exception) = opline;
2197 	ir_STORE(jit_EG(opline_before_exception), ip);
2198 	ir_MERGE_WITH_EMPTY_TRUE(if_set);
2199 
2200 	// JIT: opline = EG(exception_op);
2201 	jit_LOAD_IP(jit, jit_EG(exception_op));
2202 
2203 	if (GCC_GLOBAL_REGS) {
2204 		ir_STORE(jit_EX(opline), jit_IP(jit));
2205 
2206 		// JIT: HANDLE_EXCEPTION()
2207 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2208 	} else {
2209 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
2210 	}
2211 
2212 	return 1;
2213 }
2214 
zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx * jit)2215 static int zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx *jit)
2216 {
2217 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2218 		return 0;
2219 	}
2220 
2221 	ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_runtime_jit));
2222 	ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2223 	return 1;
2224 }
2225 
zend_jit_hybrid_profile_jit_stub(zend_jit_ctx * jit)2226 static int zend_jit_hybrid_profile_jit_stub(zend_jit_ctx *jit)
2227 {
2228 	ir_ref addr, func, run_time_cache, jit_extension;
2229 
2230 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2231 		return 0;
2232 	}
2233 
2234 	addr = ir_CONST_ADDR(&zend_jit_profile_counter),
2235 	ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2236 
2237 	func = ir_LOAD_A(jit_EX(func));
2238 	run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
2239 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2240 
2241 	if (zend_jit_profile_counter_rid) {
2242 		addr = ir_ADD_OFFSET(run_time_cache, zend_jit_profile_counter_rid * sizeof(void*));
2243 	} else {
2244 		addr = run_time_cache;
2245 	}
2246 	ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2247 
2248 	addr = ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_extension, orig_handler));
2249 	ir_IJMP(ir_LOAD_A(addr));
2250 
2251 	return 1;
2252 }
2253 
_zend_jit_hybrid_hot_counter_stub(zend_jit_ctx * jit,uint32_t cost)2254 static int _zend_jit_hybrid_hot_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2255 {
2256 	ir_ref func, jit_extension, addr, ref, if_overflow;
2257 
2258 	func = ir_LOAD_A(jit_EX(func));
2259 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2260 	addr = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, counter)));
2261 	ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2262 	ir_STORE(addr, ref);
2263 	if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2264 
2265 	ir_IF_TRUE_cold(if_overflow);
2266 	ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2267 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_hot_func),
2268 		jit_FP(jit),
2269 		jit_IP(jit));
2270 	ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2271 
2272 	ir_IF_FALSE(if_overflow);
2273 	ref = ir_SUB_A(jit_IP(jit),
2274 		ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, opcodes))));
2275 	ref = ir_DIV_A(ref, ir_CONST_ADDR(sizeof(zend_op) / sizeof(void*)));
2276 
2277 	addr = ir_ADD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, orig_handlers)),
2278 		ref);
2279 	ir_IJMP(ir_LOAD_A(addr));
2280 
2281 	return 1;
2282 }
2283 
zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx * jit)2284 static int zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx *jit)
2285 {
2286 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2287 		return 0;
2288 	}
2289 
2290 	return _zend_jit_hybrid_hot_counter_stub(jit,
2291 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2292 }
2293 
zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx * jit)2294 static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit)
2295 {
2296 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2297 		return 0;
2298 	}
2299 
2300 	return _zend_jit_hybrid_hot_counter_stub(jit,
2301 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2302 }
2303 
_zend_jit_orig_opline_handler(zend_jit_ctx * jit,ir_ref offset)2304 static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset)
2305 {
2306 	ir_ref addr;
2307 
2308 	if (GCC_GLOBAL_REGS) {
2309 		addr = ir_ADD_A(offset, jit_IP(jit));
2310 	} else {
2311 		addr = ir_ADD_A(offset, ir_LOAD_A(jit_EX(opline)));
2312 	}
2313 
2314 	return ir_LOAD_A(addr);
2315 }
2316 
zend_jit_orig_opline_handler(zend_jit_ctx * jit)2317 static ir_ref zend_jit_orig_opline_handler(zend_jit_ctx *jit)
2318 {
2319 	ir_ref func, jit_extension, offset;
2320 
2321 	func = ir_LOAD_A(jit_EX(func));
2322 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2323 	offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2324 	return _zend_jit_orig_opline_handler(jit, offset);
2325 }
2326 
_zend_jit_hybrid_trace_counter_stub(zend_jit_ctx * jit,uint32_t cost)2327 static int _zend_jit_hybrid_trace_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2328 {
2329 	ir_ref func, jit_extension, offset, addr, ref, if_overflow, ret, if_halt;
2330 
2331 	func = ir_LOAD_A(jit_EX(func));
2332 	jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2333 	offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2334 	addr = ir_LOAD_A(ir_ADD_OFFSET(ir_ADD_A(offset, jit_IP(jit)), offsetof(zend_op_trace_info, counter)));
2335 	ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2336 	ir_STORE(addr, ref);
2337 	if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2338 
2339 	ir_IF_TRUE_cold(if_overflow);
2340 	ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2341 	ret = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_trace_hot_root),
2342 		jit_FP(jit),
2343 		jit_IP(jit));
2344 	if_halt = ir_IF(ir_LT(ret, ir_CONST_I32(0)));
2345 	ir_IF_FALSE(if_halt);
2346 
2347 	ref = jit_EG(current_execute_data);
2348 	jit_STORE_FP(jit, ir_LOAD_A(ref));
2349 	ref = ir_LOAD_A(jit_EX(opline));
2350 	jit_STORE_IP(jit, ref);
2351 	ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2352 
2353 	ir_IF_FALSE(if_overflow);
2354 	ir_IJMP(_zend_jit_orig_opline_handler(jit, offset));
2355 
2356 	ir_IF_TRUE(if_halt);
2357 	ir_IJMP(ir_CONST_FC_FUNC(zend_jit_halt_op->handler));
2358 
2359 	return 1;
2360 }
2361 
zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx * jit)2362 static int zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx *jit)
2363 {
2364 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2365 		return 0;
2366 	}
2367 
2368 	return _zend_jit_hybrid_trace_counter_stub(jit,
2369 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2370 }
2371 
zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx * jit)2372 static int zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx *jit)
2373 {
2374 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2375 		return 0;
2376 	}
2377 
2378 	return _zend_jit_hybrid_trace_counter_stub(jit,
2379 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2380 }
2381 
zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx * jit)2382 static int zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx *jit)
2383 {
2384 	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2385 		return 0;
2386 	}
2387 
2388 	return _zend_jit_hybrid_trace_counter_stub(jit,
2389 		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2390 }
2391 
zend_jit_trace_halt_stub(zend_jit_ctx * jit)2392 static int zend_jit_trace_halt_stub(zend_jit_ctx *jit)
2393 {
2394 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2395 		ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_halt_op->handler));
2396 	} else if (GCC_GLOBAL_REGS) {
2397 		jit_STORE_IP(jit, IR_NULL);
2398 		ir_RETURN(IR_VOID);
2399 	} else {
2400 		ir_RETURN(ir_CONST_I32(-1)); // ZEND_VM_RETURN
2401 	}
2402 	return 1;
2403 }
2404 
zend_jit_trace_escape_stub(zend_jit_ctx * jit)2405 static int zend_jit_trace_escape_stub(zend_jit_ctx *jit)
2406 {
2407 	if (GCC_GLOBAL_REGS) {
2408 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2409 	} else {
2410 		ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2411 	}
2412 
2413 	return 1;
2414 }
2415 
zend_jit_trace_exit_stub(zend_jit_ctx * jit)2416 static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
2417 {
2418 	ir_ref ref, ret, if_zero, addr;
2419 
2420 	if (GCC_GLOBAL_REGS) {
2421 		// EX(opline) = opline
2422 		ir_STORE(jit_EX(opline), jit_IP(jit));
2423 	}
2424 
2425 	ret = ir_EXITCALL(ir_CONST_FC_FUNC(zend_jit_trace_exit));
2426 
2427 	if_zero = ir_IF(ir_EQ(ret, ir_CONST_I32(0)));
2428 
2429 	ir_IF_TRUE(if_zero);
2430 
2431 	if (GCC_GLOBAL_REGS) {
2432 		ref = jit_EG(current_execute_data);
2433 		jit_STORE_FP(jit, ir_LOAD_A(ref));
2434 		ref = ir_LOAD_A(jit_EX(opline));
2435 		jit_STORE_IP(jit, ref);
2436 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2437 	} else {
2438 		ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2439 	}
2440 
2441 	ir_IF_FALSE(if_zero);
2442 
2443 	ir_GUARD(ir_GE(ret, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2444 
2445 	ref = jit_EG(current_execute_data);
2446 	jit_STORE_FP(jit, ir_LOAD_A(ref));
2447 
2448 	if (GCC_GLOBAL_REGS) {
2449 		ref = ir_LOAD_A(jit_EX(opline));
2450 		jit_STORE_IP(jit, ref);
2451 	}
2452 
2453 	// check for interrupt (try to avoid this ???)
2454 	if (!zend_jit_check_timeout(jit, NULL, NULL)) {
2455 		return 0;
2456 	}
2457 
2458 	addr = zend_jit_orig_opline_handler(jit);
2459 	if (GCC_GLOBAL_REGS) {
2460 		ir_TAILCALL(IR_VOID, addr);
2461 	} else {
2462 #if defined(IR_TARGET_X86)
2463 		addr = ir_CAST_FC_FUNC(addr);
2464 #endif
2465 		ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
2466 		ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2467 		ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2468 	}
2469 
2470 	return 1;
2471 }
2472 
zend_jit_undefined_offset_stub(zend_jit_ctx * jit)2473 static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit)
2474 {
2475 	if (GCC_GLOBAL_REGS) {
2476 		ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key));
2477 	} else {
2478 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit));
2479 	}
2480 
2481 	return 1;
2482 }
2483 
zend_jit_undefined_key_stub(zend_jit_ctx * jit)2484 static int zend_jit_undefined_key_stub(zend_jit_ctx *jit)
2485 {
2486 	if (GCC_GLOBAL_REGS) {
2487 		ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key));
2488 	} else {
2489 		ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit));
2490 	}
2491 
2492 	return 1;
2493 }
2494 
zend_jit_cannot_add_element_stub(zend_jit_ctx * jit)2495 static int zend_jit_cannot_add_element_stub(zend_jit_ctx *jit)
2496 {
2497 	ir_ref opline = ir_LOAD_A(jit_EX(opline));
2498 	ir_ref ref, if_result_used;
2499 
2500 	if_result_used = ir_IF(ir_AND_U8(
2501 		ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, result_type))),
2502 		ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2503 	ir_IF_TRUE(if_result_used);
2504 
2505 	ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2506 	if (sizeof(void*) == 8) {
2507 		ref = ir_ZEXT_A(ref);
2508 	}
2509 	jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_UNDEF));
2510 	ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2511 
2512 	ir_CALL_2(IR_VOID,
2513 		ir_CONST_FUNC_PROTO(zend_throw_error,
2514 			ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2515 		IR_NULL,
2516 		ir_CONST_ADDR("Cannot add element to the array as the next element is already occupied"));
2517 	ir_RETURN(IR_VOID);
2518 
2519 	return 1;
2520 }
2521 
zend_jit_assign_const_stub(zend_jit_ctx * jit)2522 static int zend_jit_assign_const_stub(zend_jit_ctx *jit)
2523 {
2524 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2525 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2526 
2527 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2528 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2529 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2530 
2531 	if (!zend_jit_assign_to_variable(
2532 			jit, NULL,
2533 			var_addr, var_addr, -1, -1,
2534 			IS_CONST, val_addr, val_info,
2535 			0, 0, 0)) {
2536 		return 0;
2537 	}
2538 	ir_RETURN(IR_VOID);
2539 	return 1;
2540 }
2541 
zend_jit_assign_tmp_stub(zend_jit_ctx * jit)2542 static int zend_jit_assign_tmp_stub(zend_jit_ctx *jit)
2543 {
2544 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2545 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2546 
2547 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2548 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2549 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2550 
2551 	if (!zend_jit_assign_to_variable(
2552 			jit, NULL,
2553 			var_addr, var_addr, -1, -1,
2554 			IS_TMP_VAR, val_addr, val_info,
2555 			0, 0, 0)) {
2556 		return 0;
2557 	}
2558 	ir_RETURN(IR_VOID);
2559 	return 1;
2560 }
2561 
zend_jit_assign_var_stub(zend_jit_ctx * jit)2562 static int zend_jit_assign_var_stub(zend_jit_ctx *jit)
2563 {
2564 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2565 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2566 
2567 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2568 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2569 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2570 
2571 	if (!zend_jit_assign_to_variable(
2572 			jit, NULL,
2573 			var_addr, var_addr, -1, -1,
2574 			IS_VAR, val_addr, val_info,
2575 			0, 0, 0)) {
2576 		return 0;
2577 	}
2578 	ir_RETURN(IR_VOID);
2579 	return 1;
2580 }
2581 
zend_jit_assign_cv_noref_stub(zend_jit_ctx * jit)2582 static int zend_jit_assign_cv_noref_stub(zend_jit_ctx *jit)
2583 {
2584 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2585 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2586 
2587 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2588 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2589 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2590 
2591 	if (!zend_jit_assign_to_variable(
2592 			jit, NULL,
2593 			var_addr, var_addr, -1, -1,
2594 			IS_CV, val_addr, val_info,
2595 			0, 0, 0)) {
2596 		return 0;
2597 	}
2598 	ir_RETURN(IR_VOID);
2599 	return 1;
2600 }
2601 
zend_jit_new_array_stub(zend_jit_ctx * jit)2602 static int zend_jit_new_array_stub(zend_jit_ctx *jit)
2603 {
2604 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2605 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2606 	ir_ref ref = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_zend_new_array_0));
2607 
2608 	jit_set_Z_PTR(jit, var_addr, ref);
2609 	jit_set_Z_TYPE_INFO(jit, var_addr, IS_ARRAY_EX);
2610 	ir_RETURN(ref);
2611 	return 1;
2612 }
2613 
zend_jit_assign_cv_stub(zend_jit_ctx * jit)2614 static int zend_jit_assign_cv_stub(zend_jit_ctx *jit)
2615 {
2616 	ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2617 	ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2618 
2619 	zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2620 	zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2621 	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2622 
2623 	if (!zend_jit_assign_to_variable(
2624 			jit, NULL,
2625 			var_addr, var_addr, -1, -1,
2626 			IS_CV, val_addr, val_info,
2627 			0, 0, 0)) {
2628 		return 0;
2629 	}
2630 	ir_RETURN(IR_VOID);
2631 	return 1;
2632 }
2633 
zend_jit_init_ctx(zend_jit_ctx * jit,uint32_t flags)2634 static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2635 {
2636 #if defined (__CET__) && (__CET__ & 1) != 0
2637 	flags |= IR_GEN_ENDBR;
2638 #endif
2639 	flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
2640 
2641 	ir_init(&jit->ctx, flags, 256, 1024);
2642 	jit->ctx.ret_type = -1;
2643 
2644 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2645 	jit->ctx.mflags |= default_mflags;
2646 	if (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX) {
2647 		jit->ctx.mflags |= IR_X86_AVX;
2648 	}
2649 #elif defined(IR_TARGET_AARCH64)
2650 	jit->ctx.get_veneer = zend_jit_get_veneer;
2651 	jit->ctx.set_veneer = zend_jit_set_veneer;
2652 #endif
2653 
2654 	jit->ctx.fixed_regset = (1<<ZREG_FP) | (1<<ZREG_IP);
2655 	if (!(flags & IR_FUNCTION)) {
2656 		jit->ctx.flags |= IR_NO_STACK_COMBINE;
2657 		if (zend_jit_vm_kind == ZEND_VM_KIND_CALL) {
2658 			jit->ctx.flags |= IR_FUNCTION;
2659 			/* Stack must be 16 byte aligned */
2660 			/* TODO: select stack size ??? */
2661 #if defined(IR_TARGET_AARCH64)
2662 			jit->ctx.flags |= IR_USE_FRAME_POINTER;
2663 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 16; /* 10 saved registers and 6 spill slots (8 bytes) */
2664 #elif defined(_WIN64)
2665 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 8 saved registers and 3 spill slots (8 bytes) */
2666 #elif defined(IR_TARGET_X86_64)
2667 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 9;  /* 6 saved registers and 3 spill slots (8 bytes) */
2668 #else /* IR_TARGET_x86 */
2669 			jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */
2670 #endif
2671 			if (GCC_GLOBAL_REGS) {
2672 				jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<<ZREG_FP) | (1<<ZREG_IP));
2673 			} else {
2674 				jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED;
2675 //#ifdef _WIN64
2676 //				jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
2677 //#endif
2678 			}
2679 			jit->ctx.fixed_call_stack_size = 16;
2680 		} else {
2681 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2682 			jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
2683 			if (jit->ctx.fixed_stack_red_zone > 16) {
2684 				jit->ctx.fixed_stack_frame_size = jit->ctx.fixed_stack_red_zone - 16;
2685 				jit->ctx.fixed_call_stack_size = 16;
2686 			}
2687 			jit->ctx.flags |= IR_MERGE_EMPTY_ENTRIES;
2688 #else
2689 			jit->ctx.fixed_stack_red_zone = 0;
2690 			jit->ctx.fixed_stack_frame_size = 32; /* 4 spill slots (8 bytes) or 8 spill slots (4 bytes) */
2691 			jit->ctx.fixed_call_stack_size = 16;
2692 #endif
2693 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2694 			jit->ctx.fixed_regset |= (1<<IR_REG_FP); /* prevent %rbp (%r5) usage */
2695 #endif
2696 		}
2697 	}
2698 
2699 	jit->ctx.snapshot_create = (ir_snapshot_create_t)jit_SNAPSHOT;
2700 
2701 	jit->op_array = NULL;
2702 	jit->current_op_array = NULL;
2703 	jit->ssa = NULL;
2704 	jit->name = NULL;
2705 	jit->last_valid_opline = NULL;
2706 	jit->use_last_valid_opline = 0;
2707 	jit->track_last_valid_opline = 0;
2708 	jit->reuse_ip = 0;
2709 	jit->delayed_call_level = 0;
2710 	delayed_call_chain = 0;
2711 	jit->b = -1;
2712 #ifdef ZTS
2713 	jit->tls = IR_UNUSED;
2714 #endif
2715 	jit->fp = IR_UNUSED;
2716 	jit->trace_loop_ref = IR_UNUSED;
2717 	jit->return_inputs = IR_UNUSED;
2718 	jit->bb_start_ref = NULL;
2719 	jit->bb_predecessors = NULL;
2720 	jit->bb_edges = NULL;
2721 	jit->trace = NULL;
2722 	jit->ra = NULL;
2723 	jit->delay_var = -1;
2724 	jit->delay_refs = NULL;
2725 	jit->eg_exception_addr = 0;
2726 	zend_hash_init(&jit->addr_hash, 64, NULL, NULL, 0);
2727 	memset(jit->stub_addr, 0, sizeof(jit->stub_addr));
2728 
2729 	ir_START();
2730 }
2731 
zend_jit_free_ctx(zend_jit_ctx * jit)2732 static int zend_jit_free_ctx(zend_jit_ctx *jit)
2733 {
2734 	if (jit->name) {
2735 		zend_string_release(jit->name);
2736 	}
2737 	zend_hash_destroy(&jit->addr_hash);
2738 	ir_free(&jit->ctx);
2739 	return 1;
2740 }
2741 
zend_jit_ir_compile(ir_ctx * ctx,size_t * size,const char * name)2742 static void *zend_jit_ir_compile(ir_ctx *ctx, size_t *size, const char *name)
2743 {
2744 	void *entry;
2745 	ir_code_buffer code_buffer;
2746 
2747 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_SRC) {
2748 		if (name) fprintf(stderr, "%s: ; after folding\n", name);
2749 		ir_save(ctx, 0, stderr);
2750 	}
2751 
2752 #if ZEND_DEBUG
2753 	ir_check(ctx);
2754 #endif
2755 
2756 	ir_build_def_use_lists(ctx);
2757 
2758 #if ZEND_DEBUG
2759 	ir_check(ctx);
2760 #endif
2761 
2762 #if 1
2763 	ir_sccp(ctx);
2764 #endif
2765 
2766 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCCP) {
2767 		if (name) fprintf(stderr, "%s: ; after SCCP\n", name);
2768 		ir_save(ctx, 0, stderr);
2769 	}
2770 
2771 	ir_build_cfg(ctx);
2772 	ir_build_dominators_tree(ctx);
2773 	ir_find_loops(ctx);
2774 
2775 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_CFG) {
2776 		if (name) fprintf(stderr, "%s: ; after CFG\n", name);
2777 		ir_save(ctx, IR_SAVE_CFG, stderr);
2778 	}
2779 
2780 	ir_gcm(ctx);
2781 
2782 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_GCM) {
2783 		if (name) fprintf(stderr, "%s: ; after GCM\n", name);
2784 		ir_save(ctx, IR_SAVE_CFG|IR_SAVE_CFG_MAP, stderr);
2785 	}
2786 
2787 	ir_schedule(ctx);
2788 
2789 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE) {
2790 		if (name) fprintf(stderr, "%s: ; after schedule\n", name);
2791 		ir_save(ctx, IR_SAVE_CFG, stderr);
2792 	}
2793 
2794 	ir_match(ctx);
2795 #if !defined(IR_TARGET_AARCH64)
2796 	ctx->flags &= ~IR_USE_FRAME_POINTER; /* don't use FRAME_POINTER even with ALLOCA, TODO: cleanup this ??? */
2797 #endif
2798 	ir_assign_virtual_registers(ctx);
2799 	ir_compute_live_ranges(ctx);
2800 	ir_coalesce(ctx);
2801 	ir_reg_alloc(ctx);
2802 
2803 	if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_REGS) {
2804 		if (name) fprintf(stderr, "%s: ; after register allocation\n", name);
2805 		ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2806 		ir_dump_live_ranges(ctx, stderr);
2807 	}
2808 
2809 	ir_schedule_blocks(ctx);
2810 
2811 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
2812 		if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_CODEGEN) {
2813 			if (name) fprintf(stderr, "%s: ; codegen\n", name);
2814 			ir_dump_codegen(ctx, stderr);
2815 		} else {
2816 			if (name) fprintf(stderr, "%s: ; final\n", name);
2817 			ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2818 		}
2819 	}
2820 
2821 #if ZEND_DEBUG
2822 	ir_check(ctx);
2823 #endif
2824 
2825 	code_buffer.start = dasm_buf;
2826 	code_buffer.end = dasm_end;
2827 	code_buffer.pos = *dasm_ptr;
2828 	ctx->code_buffer = &code_buffer;
2829 
2830 	entry = ir_emit_code(ctx, size);
2831 
2832 	*dasm_ptr = code_buffer.pos;
2833 
2834 #if defined(IR_TARGET_AARCH64)
2835 	if (ctx->flags2 & IR_HAS_VENEERS) {
2836 		zend_jit_commit_veneers();
2837 	}
2838 #endif
2839 
2840 	return entry;
2841 }
2842 
zend_jit_setup_stubs(void)2843 static void zend_jit_setup_stubs(void)
2844 {
2845 	zend_jit_ctx jit;
2846 	void *entry;
2847 	size_t size;
2848 	uint32_t i;
2849 
2850 	for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
2851 		zend_jit_init_ctx(&jit, zend_jit_stubs[i].flags);
2852 
2853 		if (!zend_jit_stubs[i].stub(&jit)) {
2854 			zend_jit_free_ctx(&jit);
2855 			zend_jit_stub_handlers[i] = NULL;
2856 			continue;
2857 		}
2858 
2859 		entry = zend_jit_ir_compile(&jit.ctx, &size, zend_jit_stubs[i].name);
2860 		if (!entry) {
2861 			zend_jit_free_ctx(&jit);
2862 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile stub");
2863 		}
2864 
2865 		zend_jit_stub_handlers[i] = entry;
2866 
2867 		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)) {
2868 #ifdef HAVE_CAPSTONE
2869 			if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
2870 				ir_disasm_add_symbol(zend_jit_stubs[i].name, (uintptr_t)entry, size);
2871 			}
2872 			if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_STUBS) {
2873 				ir_disasm(zend_jit_stubs[i].name,
2874 					entry, size, (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0, &jit.ctx, stderr);
2875 			}
2876 #endif
2877 #ifndef _WIN32
2878 			if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
2879 //				ir_mem_unprotect(entry, size);
2880 				ir_gdb_register(zend_jit_stubs[i].name, entry, size, 0, 0);
2881 //				ir_mem_protect(entry, size);
2882 			}
2883 
2884 			if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2885 				ir_perf_map_register(zend_jit_stubs[i].name, entry, size);
2886 				if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
2887 					ir_perf_jitdump_register(zend_jit_stubs[i].name, entry, size);
2888 				}
2889 			}
2890 #endif
2891 		}
2892 		zend_jit_free_ctx(&jit);
2893 	}
2894 }
2895 
2896 #define REGISTER_HELPER(n)  \
2897 	ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)n, sizeof(void*));
2898 #define REGISTER_DATA(n)  \
2899 	ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)&n, sizeof(n));
2900 
zend_jit_setup_disasm(void)2901 static void zend_jit_setup_disasm(void)
2902 {
2903 #ifdef HAVE_CAPSTONE
2904 	ir_disasm_init();
2905 
2906 	if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
2907 		zend_op opline;
2908 
2909 		memset(&opline, 0, sizeof(opline));
2910 
2911 		opline.opcode = ZEND_DO_UCALL;
2912 		opline.result_type = IS_UNUSED;
2913 		zend_vm_set_opcode_handler(&opline);
2914 		ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2915 
2916 		opline.opcode = ZEND_DO_UCALL;
2917 		opline.result_type = IS_VAR;
2918 		zend_vm_set_opcode_handler(&opline);
2919 		ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2920 
2921 		opline.opcode = ZEND_DO_FCALL_BY_NAME;
2922 		opline.result_type = IS_UNUSED;
2923 		zend_vm_set_opcode_handler(&opline);
2924 		ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2925 
2926 		opline.opcode = ZEND_DO_FCALL_BY_NAME;
2927 		opline.result_type = IS_VAR;
2928 		zend_vm_set_opcode_handler(&opline);
2929 		ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2930 
2931 		opline.opcode = ZEND_DO_FCALL;
2932 		opline.result_type = IS_UNUSED;
2933 		zend_vm_set_opcode_handler(&opline);
2934 		ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2935 
2936 		opline.opcode = ZEND_DO_FCALL;
2937 		opline.result_type = IS_VAR;
2938 		zend_vm_set_opcode_handler(&opline);
2939 		ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2940 
2941 		opline.opcode = ZEND_RETURN;
2942 		opline.op1_type = IS_CONST;
2943 		zend_vm_set_opcode_handler(&opline);
2944 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2945 
2946 		opline.opcode = ZEND_RETURN;
2947 		opline.op1_type = IS_TMP_VAR;
2948 		zend_vm_set_opcode_handler(&opline);
2949 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2950 
2951 		opline.opcode = ZEND_RETURN;
2952 		opline.op1_type = IS_VAR;
2953 		zend_vm_set_opcode_handler(&opline);
2954 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2955 
2956 		opline.opcode = ZEND_RETURN;
2957 		opline.op1_type = IS_CV;
2958 		zend_vm_set_opcode_handler(&opline);
2959 		ir_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2960 
2961 		ir_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
2962 	}
2963 
2964 	REGISTER_DATA(zend_jit_profile_counter);
2965 
2966 	REGISTER_HELPER(zend_runtime_jit);
2967 	REGISTER_HELPER(zend_jit_hot_func);
2968 	REGISTER_HELPER(zend_jit_trace_hot_root);
2969 	REGISTER_HELPER(zend_jit_trace_exit);
2970 
2971 	REGISTER_HELPER(zend_jit_array_free);
2972 	REGISTER_HELPER(zend_jit_undefined_op_helper);
2973 	REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
2974 	REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
2975 	REGISTER_HELPER(zend_jit_post_inc_typed_ref);
2976 	REGISTER_HELPER(zend_jit_post_dec_typed_ref);
2977 	REGISTER_HELPER(zend_jit_pre_inc);
2978 	REGISTER_HELPER(zend_jit_pre_dec);
2979 	REGISTER_HELPER(zend_jit_add_arrays_helper);
2980 	REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
2981 	REGISTER_HELPER(zend_jit_fast_concat_helper);
2982 	REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
2983 	REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
2984 	REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
2985 	REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
2986 	REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
2987 	REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
2988 	REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
2989 	REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
2990 	REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
2991 	REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
2992 	REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
2993 	REGISTER_HELPER(zend_jit_check_constant);
2994 	REGISTER_HELPER(zend_jit_get_constant);
2995 	REGISTER_HELPER(zend_jit_int_extend_stack_helper);
2996 	REGISTER_HELPER(zend_jit_extend_stack_helper);
2997 	REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
2998 	REGISTER_HELPER(zend_jit_find_func_helper);
2999 	REGISTER_HELPER(zend_jit_find_ns_func_helper);
3000 	REGISTER_HELPER(zend_jit_jmp_frameless_helper);
3001 	REGISTER_HELPER(zend_jit_unref_helper);
3002 	REGISTER_HELPER(zend_jit_invalid_method_call);
3003 	REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
3004 	REGISTER_HELPER(zend_jit_find_method_helper);
3005 	REGISTER_HELPER(zend_jit_find_method_tmp_helper);
3006 	REGISTER_HELPER(zend_jit_push_static_metod_call_frame);
3007 	REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
3008 	REGISTER_HELPER(zend_jit_free_trampoline_helper);
3009 	REGISTER_HELPER(zend_jit_verify_return_slow);
3010 	REGISTER_HELPER(zend_jit_deprecated_helper);
3011 	REGISTER_HELPER(zend_jit_undefined_long_key);
3012 	REGISTER_HELPER(zend_jit_undefined_string_key);
3013 	REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3014 	REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3015 	REGISTER_HELPER(zend_free_extra_named_params);
3016 	REGISTER_HELPER(zend_jit_free_call_frame);
3017 	REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3018 	REGISTER_HELPER(zend_jit_verify_arg_slow);
3019 	REGISTER_HELPER(zend_missing_arg_error);
3020 	REGISTER_HELPER(zend_jit_only_vars_by_reference);
3021 	REGISTER_HELPER(zend_jit_leave_func_helper);
3022 	REGISTER_HELPER(zend_jit_leave_nested_func_helper);
3023 	REGISTER_HELPER(zend_jit_leave_top_func_helper);
3024 	REGISTER_HELPER(zend_jit_fetch_global_helper);
3025 	REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3026 	REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3027 	REGISTER_HELPER(zend_jit_hash_lookup_rw);
3028 	REGISTER_HELPER(zend_jit_symtable_find);
3029 	REGISTER_HELPER(zend_jit_symtable_lookup_w);
3030 	REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3031 	REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3032 	REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3033 	REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3034 	REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3035 	REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3036 	REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3037 	REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3038 	REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3039 	REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3040 	REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3041 	REGISTER_HELPER(zend_jit_invalid_array_access);
3042 	REGISTER_HELPER(zend_jit_zval_array_dup);
3043 	REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3044 	REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3045 	REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3046 	REGISTER_HELPER(zend_jit_isset_dim_helper);
3047 	REGISTER_HELPER(zend_jit_assign_dim_helper);
3048 	REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3049 	REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3050 	REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3051 	REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3052 	REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3053 	REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3054 	REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3055 	REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3056 	REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3057 	REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3058 	REGISTER_HELPER(zend_jit_check_array_promotion);
3059 	REGISTER_HELPER(zend_jit_create_typed_ref);
3060 	REGISTER_HELPER(zend_jit_invalid_property_write);
3061 	REGISTER_HELPER(zend_jit_invalid_property_read);
3062 	REGISTER_HELPER(zend_jit_extract_helper);
3063 	REGISTER_HELPER(zend_jit_invalid_property_assign);
3064 	REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3065 	REGISTER_HELPER(zend_jit_assign_obj_helper);
3066 	REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3067 	REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3068 	REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3069 	REGISTER_HELPER(zend_jit_invalid_property_incdec);
3070 	REGISTER_HELPER(zend_jit_inc_typed_prop);
3071 	REGISTER_HELPER(zend_jit_dec_typed_prop);
3072 	REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3073 	REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3074 	REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3075 	REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3076 	REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3077 	REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3078 	REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3079 	REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3080 	REGISTER_HELPER(zend_jit_rope_end);
3081 
3082 #ifndef ZTS
3083 	REGISTER_DATA(EG(current_execute_data));
3084 	REGISTER_DATA(EG(exception));
3085 	REGISTER_DATA(EG(opline_before_exception));
3086 	REGISTER_DATA(EG(vm_interrupt));
3087 	REGISTER_DATA(EG(timed_out));
3088 	REGISTER_DATA(EG(uninitialized_zval));
3089 	REGISTER_DATA(EG(zend_constants));
3090 	REGISTER_DATA(EG(jit_trace_num));
3091 	REGISTER_DATA(EG(vm_stack_top));
3092 	REGISTER_DATA(EG(vm_stack_end));
3093 	REGISTER_DATA(EG(exception_op));
3094 	REGISTER_DATA(EG(symbol_table));
3095 
3096 	REGISTER_DATA(CG(map_ptr_base));
3097 #endif
3098 #endif
3099 }
3100 
zend_jit_calc_trace_prologue_size(void)3101 static void zend_jit_calc_trace_prologue_size(void)
3102 {
3103 	zend_jit_ctx jit_ctx;
3104 	zend_jit_ctx *jit = &jit_ctx;
3105 	void *entry;
3106 	size_t size;
3107 
3108 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
3109 
3110 	if (!GCC_GLOBAL_REGS) {
3111 		ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3112 		jit_STORE_FP(jit, ref);
3113 		jit->ctx.flags |= IR_FASTCALL_FUNC;
3114 	}
3115 
3116 	ir_UNREACHABLE();
3117 
3118 	entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3119 	zend_jit_free_ctx(jit);
3120 
3121 	if (!entry) {
3122 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3123 	}
3124 
3125 	zend_jit_trace_prologue_size = size;
3126 }
3127 
3128 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3129 static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3130 
3131 typedef struct _Unwind_Context _Unwind_Context;
3132 typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3133 extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
3134 extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
3135 
3136 typedef struct _zend_jit_unwind_arg {
3137 	int cnt;
3138 	uintptr_t cfa[3];
3139 } zend_jit_unwind_arg;
3140 
zend_jit_unwind_cb(_Unwind_Context * ctx,void * a)3141 static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3142 {
3143 	zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
3144 	arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3145 	arg->cnt++;
3146 	if (arg->cnt == 3) {
3147 		return 5; // _URC_END_OF_STACK
3148 	}
3149 	return 0; // _URC_NO_REASON;
3150 }
3151 
zend_jit_touch_vm_stack_data(void * vm_stack_data)3152 static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3153 {
3154 	zend_jit_unwind_arg arg;
3155 
3156 	memset(&arg, 0, sizeof(arg));
3157 	_Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3158 	if (arg.cnt == 3) {
3159 		zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3160 	}
3161 }
3162 
3163 extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3164 
zend_jit_set_sp_adj_vm(void)3165 static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3166 {
3167 	void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3168 
3169 	orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3170 	zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3171 	execute_ex(NULL);                                        // set sp_adj[SP_ADJ_VM]
3172 	zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3173 }
3174 #endif
3175 
zend_jit_setup(void)3176 static void zend_jit_setup(void)
3177 {
3178 #if defined(IR_TARGET_X86)
3179 	if (!zend_cpu_supports_sse2()) {
3180 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3181 	}
3182 #endif
3183 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3184 	allowed_opt_flags = 0;
3185 	if (zend_cpu_supports_avx()) {
3186 		allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3187 	}
3188 # if PHP_HAVE_BUILTIN_CPU_SUPPORTS && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
3189 	if (zend_cpu_supports_cldemote()) {
3190 		default_mflags |= IR_X86_CLDEMOTE;
3191 	}
3192 # endif
3193 #endif
3194 #ifdef ZTS
3195 #if defined(IR_TARGET_AARCH64)
3196 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3197 
3198 # ifdef __FreeBSD__
3199 	if (tsrm_ls_cache_tcb_offset == 0) {
3200 		TLSDescriptor **where;
3201 
3202 		__asm__(
3203 			"adrp %0, :tlsdesc:_tsrm_ls_cache\n"
3204 			"add %0, %0, :tlsdesc_lo12:_tsrm_ls_cache\n"
3205 			: "=r" (where));
3206 		/* See https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst
3207 		 * section "Relocations for thread-local storage".
3208 		 * The first entry holds a pointer to the variable's TLS descriptor resolver function and the second entry holds
3209 		 * a platform-specific offset or pointer. */
3210 		TLSDescriptor *tlsdesc = where[1];
3211 
3212 		tsrm_tls_offset = tlsdesc->offset;
3213 		/* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/22ca6db50f4e6bd75a141f57cf953d8de6531a06/lib/libc/gen/tls.c#L88) */
3214 		tsrm_tls_index = (tlsdesc->index + 1) * 8;
3215 	}
3216 # else
3217 	ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0);
3218 # endif
3219 # elif defined(_WIN64)
3220 	tsrm_tls_index  = _tls_index * sizeof(void*);
3221 
3222 	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3223 	/* Probably, it might be better solution */
3224 	do {
3225 		void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
3226 		void *val = _tsrm_ls_cache;
3227 		size_t offset = 0;
3228 		size_t size = (char*)&_tls_end - (char*)&_tls_start;
3229 
3230 		while (offset < size) {
3231 			if (*tls_mem == val) {
3232 				tsrm_tls_offset = offset;
3233 				break;
3234 			}
3235 			tls_mem++;
3236 			offset += sizeof(void*);
3237 		}
3238 		if (offset >= size) {
3239 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3240 		}
3241 	} while(0);
3242 # elif defined(ZEND_WIN32)
3243 	tsrm_tls_index  = _tls_index * sizeof(void*);
3244 
3245 	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3246 	/* Probably, it might be better solution */
3247 	do {
3248 		void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
3249 		void *val = _tsrm_ls_cache;
3250 		size_t offset = 0;
3251 		size_t size = (char*)&_tls_end - (char*)&_tls_start;
3252 
3253 		while (offset < size) {
3254 			if (*tls_mem == val) {
3255 				tsrm_tls_offset = offset;
3256 				break;
3257 			}
3258 			tls_mem++;
3259 			offset += sizeof(void*);
3260 		}
3261 		if (offset >= size) {
3262 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3263 		}
3264 	} while(0);
3265 # elif defined(__APPLE__) && defined(__x86_64__)
3266 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3267 	if (tsrm_ls_cache_tcb_offset == 0) {
3268 		size_t *ti;
3269 		__asm__(
3270 			"leaq __tsrm_ls_cache(%%rip),%0"
3271 			: "=r" (ti));
3272 		tsrm_tls_offset = ti[2];
3273 		tsrm_tls_index = ti[1] * 8;
3274 	}
3275 # elif defined(__GNUC__) && defined(__x86_64__)
3276 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3277 	if (tsrm_ls_cache_tcb_offset == 0) {
3278 #if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && \
3279 	!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3280 		size_t ret;
3281 
3282 		asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
3283 			: "=r" (ret));
3284 		tsrm_ls_cache_tcb_offset = ret;
3285 #elif defined(__MUSL__)
3286 		size_t *ti;
3287 
3288 		__asm__(
3289 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3290 			: "=a" (ti));
3291 		tsrm_tls_offset = ti[1];
3292 		tsrm_tls_index = ti[0] * 8;
3293 #elif defined(__FreeBSD__)
3294 		size_t *ti;
3295 
3296 		__asm__(
3297 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3298 			: "=a" (ti));
3299 		tsrm_tls_offset = ti[1];
3300 		/* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/bf56e8b9c8639ac4447d223b83cdc128107cc3cd/libexec/rtld-elf/rtld.c#L5260) */
3301 		tsrm_tls_index = (ti[0] + 1) * 8;
3302 #else
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] * 16;
3310 #endif
3311 	}
3312 # elif defined(__GNUC__) && defined(__i386__)
3313 	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3314 	if (tsrm_ls_cache_tcb_offset == 0) {
3315 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3316 		size_t ret;
3317 
3318 		asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
3319 			: "=a" (ret));
3320 		tsrm_ls_cache_tcb_offset = ret;
3321 #else
3322 		size_t *ti, _ebx, _ecx, _edx;
3323 
3324 		__asm__(
3325 			"call 1f\n"
3326 			".subsection 1\n"
3327 			"1:\tmovl (%%esp), %%ebx\n\t"
3328 			"ret\n"
3329 			".previous\n\t"
3330 			"addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
3331 			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
3332 			"call ___tls_get_addr@plt\n\t"
3333 			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
3334 			: "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
3335 		tsrm_tls_offset = ti[1];
3336 		tsrm_tls_index = ti[0] * 8;
3337 #endif
3338 	}
3339 # endif
3340 #endif
3341 
3342 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3343 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3344 		zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3345 	}
3346 #endif
3347 
3348 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3349 		zend_jit_setup_disasm();
3350 	}
3351 
3352 #ifndef _WIN32
3353 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3354 		ir_perf_jitdump_open();
3355 	}
3356 
3357 #endif
3358 	zend_long debug = JIT_G(debug);
3359 	if (!(debug & ZEND_JIT_DEBUG_ASM_STUBS)) {
3360 		JIT_G(debug) &= ~(ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_FINAL|
3361 			ZEND_JIT_DEBUG_IR_CODEGEN|
3362 			ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_CFG|ZEND_JIT_DEBUG_IR_AFTER_GCM|
3363 			ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS);
3364 	}
3365 
3366 	zend_jit_calc_trace_prologue_size();
3367 	zend_jit_setup_stubs();
3368 	JIT_G(debug) = debug;
3369 }
3370 
zend_jit_shutdown_ir(void)3371 static void zend_jit_shutdown_ir(void)
3372 {
3373 #ifndef _WIN32
3374 	if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3375 		ir_perf_jitdump_close();
3376 	}
3377 	if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
3378 		ir_gdb_unregister_all();
3379 	}
3380 #endif
3381 #ifdef HAVE_CAPSTONE
3382 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3383 		ir_disasm_free();
3384 	}
3385 #endif
3386 }
3387 
3388 /* PHP control flow reconstruction helpers */
jit_IF_ex(zend_jit_ctx * jit,ir_ref condition,ir_ref true_block)3389 static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3390 {
3391 	ir_ref ref = ir_IF(condition);
3392 	/* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3393 	 *
3394 	 * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3395 	 * to start target block
3396 	 */
3397 	ir_set_op(&jit->ctx, ref, 3, true_block);
3398 	return ref;
3399 }
3400 
jit_IF_TRUE_FALSE_ex(zend_jit_ctx * jit,ir_ref if_ref,ir_ref true_block)3401 static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3402 {
3403 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3404 	ZEND_ASSERT(if_ref);
3405 	ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3406 	ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3407 	if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3408 		ir_IF_TRUE(if_ref);
3409 	} else {
3410 		ir_IF_FALSE(if_ref);
3411 	}
3412 }
3413 
_zend_jit_add_predecessor_ref(zend_jit_ctx * jit,int b,int pred,ir_ref ref)3414 static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3415 {
3416 	int i, *p;
3417 	zend_basic_block *bb;
3418 	ir_ref *r, header;
3419 
3420 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3421 	bb = &jit->ssa->cfg.blocks[b];
3422 	p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3423 	r = &jit->bb_edges[jit->bb_predecessors[b]];
3424 	for (i = 0; i < bb->predecessors_count; i++, p++, r++) {
3425 		if (*p == pred) {
3426 			ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3427 			header = jit->bb_start_ref[b];
3428 			if (header) {
3429 				/* this is back edge */
3430 				ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3431 				if (jit->ctx.ir_base[ref].op == IR_END) {
3432 					jit->ctx.ir_base[ref].op = IR_LOOP_END;
3433 				} else if (jit->ctx.ir_base[ref].op == IR_IF) {
3434 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3435 					ref = ir_LOOP_END();
3436 				} else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3437 					ir_BEGIN(ref);
3438 					ref = ir_LOOP_END();
3439 				} else {
3440 					ZEND_UNREACHABLE();
3441 				}
3442 				ir_MERGE_SET_OP(header, i + 1, ref);
3443 			}
3444 			*r = ref;
3445 			return;
3446 		}
3447 	}
3448 	ZEND_UNREACHABLE();
3449 }
3450 
_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)3451 static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3452                                                 uint32_t      true_label,
3453                                                 uint32_t      false_label,
3454                                                 ir_ref        true_inputs,
3455                                                 ir_ref        false_inputs)
3456 {
3457 	ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3458 
3459 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3460 	if (true_inputs) {
3461 		ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3462 		if (!jit->ctx.ir_base[true_inputs].op2) {
3463 			true_path = true_inputs;
3464 		} else {
3465 			ir_MERGE_list(true_inputs);
3466 			true_path = ir_END();
3467 		}
3468 	}
3469 	if (false_inputs) {
3470 		ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3471 		if (!jit->ctx.ir_base[false_inputs].op2) {
3472 			false_path = false_inputs;
3473 		} else {
3474 			ir_MERGE_list(false_inputs);
3475 			false_path = ir_END();
3476 		}
3477 	}
3478 
3479 	if (true_label == false_label && true_path && false_path) {
3480 		ir_MERGE_2(true_path, false_path);
3481 		_zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3482 	} else if (!true_path && !false_path) {
3483 		/* dead code */
3484 		true_path = ir_END();
3485 		_zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3486 	} else {
3487 		if (true_path) {
3488 			_zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3489 		}
3490 		if (false_path) {
3491 			_zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3492 		}
3493 	}
3494 
3495 	jit->b = -1;
3496 }
3497 
_zend_jit_fix_merges(zend_jit_ctx * jit)3498 static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3499 {
3500 	int i, count;
3501 	ir_ref j, k, n, *p, *q, *r;
3502 	ir_ref ref;
3503 	ir_insn *insn, *phi;
3504 
3505 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3506 	count = jit->ssa->cfg.blocks_count;
3507 	for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3508 		ref = *p;
3509 		if (ref) {
3510 			insn = &jit->ctx.ir_base[ref];
3511 			if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3512 				n = insn->inputs_count;
3513 				/* Remove IS_UNUSED inputs */
3514 				for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3515 					if (*q) {
3516 						if (q != r) {
3517 							*r = *q;
3518 							phi = insn + 1 + (n >> 2);
3519 							while (phi->op == IR_PI) {
3520 								phi++;
3521 							}
3522 							while (phi->op == IR_PHI) {
3523 								ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3524 								phi += 1 + ((n + 1) >> 2);
3525 							}
3526 						}
3527 						k++;
3528 						r++;
3529 					}
3530 				}
3531 				if (k != n) {
3532 					ir_ref n2, k2;
3533 
3534 					if (k <= 1) {
3535 						insn->op = IR_BEGIN;
3536 						insn->inputs_count = 0;
3537 					} else {
3538 						insn->inputs_count = k;
3539 					}
3540 					n2 = 1 + (n >> 2);
3541 					k2 = 1 + (k >> 2);
3542 					while (k2 != n2) {
3543 						(insn+k2)->optx = IR_NOP;
3544 						k2++;
3545 					}
3546 					phi = insn + 1 + (n >> 2);
3547 					while (phi->op == IR_PI) {
3548 						phi++;
3549 					}
3550 					while (phi->op == IR_PHI) {
3551 						if (k <= 1) {
3552 							phi->op = IR_COPY;
3553 							phi->op1 = phi->op2;
3554 							phi->op2 = 1;
3555 							phi->inputs_count = 0;
3556 						} else {
3557 							phi->inputs_count = k + 1;
3558 						}
3559 						n2 = 1 + ((n + 1) >> 2);
3560 						k2 = 1 + ((k + 1) >> 2);
3561 						while (k2 != n2) {
3562 							(phi+k2)->optx = IR_NOP;
3563 							k2++;
3564 						}
3565 						phi += 1 + ((n + 1) >> 2);
3566 					}
3567 				}
3568 			}
3569 		}
3570 	}
3571 }
3572 
zend_jit_case_start(zend_jit_ctx * jit,int switch_b,int case_b,ir_ref switch_ref)3573 static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3574 {
3575 	zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3576 	const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3577 
3578 	if (opline->opcode == ZEND_SWITCH_LONG
3579 	 || opline->opcode == ZEND_SWITCH_STRING
3580 	 || opline->opcode == ZEND_MATCH) {
3581 		HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3582 		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3583 		int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3584 		zval *zv;
3585 		ir_ref list = IR_UNUSED, idx;
3586 		bool first = 1;
3587 
3588 		ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3589 			const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3590 			int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3591 
3592 			if (b == case_b) {
3593 				if (!first) {
3594 					ir_END_list(list);
3595 				}
3596 				if (HT_IS_PACKED(jumptable)) {
3597 					idx = ir_CONST_LONG(zv - jumptable->arPacked);
3598 				} else {
3599 					idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3600 				}
3601 				ir_CASE_VAL(switch_ref, idx);
3602 				first = 0;
3603 			}
3604 		} ZEND_HASH_FOREACH_END();
3605 		if (default_b == case_b) {
3606 			if (!first) {
3607 				ir_END_list(list);
3608 			}
3609 			if (jit->ctx.ir_base[switch_ref].op3) {
3610 				/* op3 may contain a list of additional "default" path inputs for MATCH */
3611 				ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3612 				jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3613 				ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3614 				ir_ref end = ref;
3615 				while (jit->ctx.ir_base[end].op2) {
3616 					ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3617 					end = jit->ctx.ir_base[end].op2;
3618 				}
3619 				jit->ctx.ir_base[end].op2 = list;
3620 				list = ref;
3621 			}
3622 			ir_CASE_DEFAULT(switch_ref);
3623 		}
3624 		if (list) {
3625 			ir_END_list(list);
3626 			ir_MERGE_list(list);
3627 		}
3628 	} else {
3629 		ZEND_UNREACHABLE();
3630 	}
3631 }
3632 
zend_jit_bb_start(zend_jit_ctx * jit,int b)3633 static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3634 {
3635 	zend_basic_block *bb;
3636 	int i, n, *p, pred;
3637 	ir_ref ref, bb_start;
3638 
3639 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3640 	ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3641 	bb = &jit->ssa->cfg.blocks[b];
3642 	ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3643 	n = bb->predecessors_count;
3644 
3645 	if (n == 0) {
3646 		/* pass */
3647 		ZEND_ASSERT(jit->ctx.control);
3648 #if ZEND_DEBUG
3649 		ref = jit->ctx.control;
3650 		ir_insn *insn = &jit->ctx.ir_base[ref];
3651 		while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3652 			ref = insn->op1;
3653 			insn = &jit->ctx.ir_base[ref];
3654 		}
3655 		ZEND_ASSERT(insn->op == IR_START);
3656 		ZEND_ASSERT(ref == 1);
3657 #endif
3658 		bb_start = 1;
3659 		if (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
3660 			/* prvent END/BEGIN merging */
3661 			jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3662 			bb_start = jit->ctx.control;
3663 		}
3664 	} else if (n == 1) {
3665 		ZEND_ASSERT(!jit->ctx.control);
3666 		pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3667 		ref = jit->bb_edges[jit->bb_predecessors[b]];
3668 		if (ref == IR_UNUSED) {
3669 			if (!jit->ctx.control) {
3670 				ir_BEGIN(IR_UNUSED); /* unreachable block */
3671 			}
3672 		} else {
3673 			ir_op op = jit->ctx.ir_base[ref].op;
3674 
3675 			if (op == IR_IF) {
3676 				if (!jit->ctx.control) {
3677 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3678 				} else {
3679 					ir_ref entry_path = ir_END();
3680 					jit_IF_TRUE_FALSE_ex(jit, ref, b);
3681 					ir_MERGE_WITH(entry_path);
3682 				}
3683 			} else if (op == IR_SWITCH) {
3684 				zend_jit_case_start(jit, pred, b, ref);
3685 			} else {
3686 				if (!jit->ctx.control) {
3687 					ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3688 					if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3689 					 && (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)) {
3690 						/* prvent END/BEGIN merging */
3691 						jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3692 					} else {
3693 						ir_BEGIN(ref);
3694 					}
3695 				} else {
3696 					ir_MERGE_WITH(ref);
3697 				}
3698 			}
3699 		}
3700 		bb_start = jit->ctx.control;
3701 	} else {
3702 		int forward_edges_count = 0;
3703 		int back_edges_count = 0;
3704 		ir_ref *pred_refs;
3705 		ir_ref entry_path = IR_UNUSED;
3706 		ALLOCA_FLAG(use_heap);
3707 
3708 		ZEND_ASSERT(!jit->ctx.control);
3709 		if (jit->ctx.control) {
3710 			entry_path = ir_END();
3711 		}
3712 		pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3713 		for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3714 			pred = *p;
3715 			if (jit->bb_start_ref[pred]) {
3716 				/* forward edge */
3717 				forward_edges_count++;
3718 				ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3719 				if (ref == IR_UNUSED) {
3720 					/* dead edge */
3721 					pred_refs[i] = IR_UNUSED;
3722 				} else {
3723 					ir_op op = jit->ctx.ir_base[ref].op;
3724 
3725 					if (op == IR_IF) {
3726 						jit_IF_TRUE_FALSE_ex(jit, ref, b);
3727 						pred_refs[i] = ir_END();
3728 					} else if (op == IR_SWITCH) {
3729 						zend_jit_case_start(jit, pred, b, ref);
3730 						pred_refs[i] = ir_END();
3731 					} else {
3732 						ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3733 						pred_refs[i] = ref;
3734 					}
3735 				}
3736 			} else {
3737 				/* backward edge */
3738 				back_edges_count++;
3739 				pred_refs[i] = IR_UNUSED;
3740 			}
3741 		}
3742 
3743 		if (bb->flags & ZEND_BB_LOOP_HEADER) {
3744 			ZEND_ASSERT(back_edges_count != 0);
3745 			ZEND_ASSERT(forward_edges_count != 0);
3746 			ir_MERGE_N(n, pred_refs);
3747 			jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3748 			bb_start = jit->ctx.control;
3749 			if (entry_path) {
3750 				ir_MERGE_WITH(entry_path);
3751 			}
3752 		} else {
3753 //			ZEND_ASSERT(back_edges_count != 0);
3754 			/* edges from exceptional blocks may be counted as back edges */
3755 			ir_MERGE_N(n, pred_refs);
3756 			bb_start = jit->ctx.control;
3757 			if (entry_path) {
3758 				ir_MERGE_WITH(entry_path);
3759 			}
3760 		}
3761 		free_alloca(pred_refs, use_heap);
3762 	}
3763 	jit->b = b;
3764 	jit->bb_start_ref[b] = bb_start;
3765 
3766 	if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3767 		jit->ctx.fold_cse_limit = bb_start;
3768 	}
3769 
3770 	return 1;
3771 }
3772 
zend_jit_bb_end(zend_jit_ctx * jit,int b)3773 static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3774 {
3775 	int succ;
3776 	zend_basic_block *bb;
3777 
3778 	ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3779 	if (jit->b != b) {
3780 		return 1;
3781 	}
3782 
3783 	bb = &jit->ssa->cfg.blocks[b];
3784 	ZEND_ASSERT(bb->successors_count != 0);
3785 	if (bb->successors_count == 1) {
3786 		succ = bb->successors[0];
3787 	} else {
3788 		const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3789 
3790 		/* Use only the following successor of SWITCH and FE_RESET_R */
3791 		ZEND_ASSERT(opline->opcode == ZEND_SWITCH_LONG
3792 		 || opline->opcode == ZEND_SWITCH_STRING
3793 		 || opline->opcode == ZEND_MATCH
3794 		 || opline->opcode == ZEND_FE_RESET_R);
3795 		succ = b + 1;
3796 	}
3797 	_zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3798 	jit->b = -1;
3799 	return 1;
3800 }
3801 
jit_CMP_IP(zend_jit_ctx * jit,ir_op op,const zend_op * next_opline)3802 static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3803 {
3804 	ir_ref ref;
3805 
3806 #if 1
3807 	if (GCC_GLOBAL_REGS) {
3808 		ref = jit_IP32(jit);
3809 	} else {
3810 		ref = ir_LOAD_U32(jit_EX(opline));
3811 	}
3812 	ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3813 #else
3814 	if (GCC_GLOBAL_REGS) {
3815 		ref = jit_IP(jit);
3816 	} else {
3817 		ref = ir_LOAD_A(jit_EX(opline));
3818 	}
3819 	ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
3820 #endif
3821 	return ref;
3822 }
3823 
zend_jit_jmp_frameless(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr,zend_jmp_fl_result guard)3824 static int zend_jit_jmp_frameless(
3825 	zend_jit_ctx *jit,
3826 	const zend_op *opline,
3827 	const void *exit_addr,
3828 	zend_jmp_fl_result guard
3829 ) {
3830 	ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
3831 	zend_basic_block *bb;
3832 
3833 	// JIT: CACHED_PTR(opline->extended_value)
3834 	cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
3835 	cache_result = ir_LOAD_L(cache_slot_ref);
3836 
3837 	// JIT: if (UNEXPECTED(!result))
3838 	if_ref = ir_IF(cache_result);
3839 	ir_IF_FALSE_cold(if_ref);
3840 	zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3841 	function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3842 		ir_CONST_ADDR(func_name_zv),
3843 		cache_slot_ref);
3844 	ir_MERGE_WITH_EMPTY_TRUE(if_ref);
3845 
3846 	phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
3847 
3848 	if (exit_addr) {
3849 		ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3850 	} else {
3851 		ZEND_ASSERT(jit->b >= 0);
3852 		bb = &jit->ssa->cfg.blocks[jit->b];
3853 		// JIT: if (result == ZEND_JMP_FL_HIT)
3854 		ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3855 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3856 		_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3857 		jit->b = -1;
3858 	}
3859 
3860 	return 1;
3861 }
3862 
zend_jit_cond_jmp(zend_jit_ctx * jit,const zend_op * next_opline,int target_block)3863 static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
3864 {
3865 	ir_ref ref;
3866 	zend_basic_block *bb;
3867 
3868 	ZEND_ASSERT(jit->b >= 0);
3869 	bb = &jit->ssa->cfg.blocks[jit->b];
3870 
3871 	ZEND_ASSERT(bb->successors_count == 2);
3872 	if (bb->successors[0] == bb->successors[1]) {
3873 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
3874 		jit->b = -1;
3875 		zend_jit_set_last_valid_opline(jit, next_opline);
3876 		return 1;
3877 	}
3878 
3879 	ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
3880 
3881 	_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3882 	_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3883 
3884 	jit->b = -1;
3885 	zend_jit_set_last_valid_opline(jit, next_opline);
3886 
3887 	return 1;
3888 }
3889 
zend_jit_set_cond(zend_jit_ctx * jit,const zend_op * next_opline,uint32_t var)3890 static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *next_opline, uint32_t var)
3891 {
3892 	ir_ref ref;
3893 
3894 	ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, IR_EQ, next_opline)), ir_CONST_U32(IS_FALSE));
3895 
3896 	// EX_VAR(var) = ...
3897 	ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
3898 
3899 	zend_jit_reset_last_valid_opline(jit);
3900 	return zend_jit_set_ip(jit, next_opline - 1);
3901 }
3902 
3903 /* PHP JIT handlers */
zend_jit_check_exception(zend_jit_ctx * jit)3904 static void zend_jit_check_exception(zend_jit_ctx *jit)
3905 {
3906 	ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3907 		jit_STUB_ADDR(jit, jit_stub_exception_handler));
3908 }
3909 
zend_jit_check_exception_undef_result(zend_jit_ctx * jit,const zend_op * opline)3910 static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
3911 {
3912 	ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3913 		jit_STUB_ADDR(jit,
3914 			(opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
3915 }
3916 
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)3917 static void zend_jit_type_check_undef(zend_jit_ctx  *jit,
3918                                       ir_ref         type,
3919                                       uint32_t       var,
3920                                       const zend_op *opline,
3921                                       bool           check_exception,
3922                                       bool           in_cold_path,
3923                                       bool           undef_result)
3924 {
3925 	ir_ref if_def = ir_IF(type);
3926 
3927 	if (!in_cold_path) {
3928 		ir_IF_FALSE_cold(if_def);
3929 	} else {
3930 		ir_IF_FALSE(if_def);
3931 	}
3932 	if (opline) {
3933 		jit_SET_EX_OPLINE(jit, opline);
3934 	}
3935 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3936 	if (check_exception) {
3937 		if (undef_result) {
3938 			zend_jit_check_exception_undef_result(jit, opline);
3939 		} else {
3940 			zend_jit_check_exception(jit);
3941 		}
3942 	}
3943 	ir_MERGE_WITH_EMPTY_TRUE(if_def);
3944 }
3945 
zend_jit_zval_check_undef(zend_jit_ctx * jit,ir_ref ref,uint32_t var,const zend_op * opline,bool check_exception)3946 static ir_ref zend_jit_zval_check_undef(zend_jit_ctx  *jit,
3947                                         ir_ref         ref,
3948                                         uint32_t       var,
3949                                         const zend_op *opline,
3950                                         bool           check_exception)
3951 {
3952 	ir_ref if_def, ref2;
3953 
3954 	if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
3955 	ir_IF_FALSE_cold(if_def);
3956 
3957 	if (opline) {
3958 		jit_SET_EX_OPLINE(jit, opline);
3959 	}
3960 
3961 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3962 
3963 	if (check_exception) {
3964 		zend_jit_check_exception(jit);
3965 	}
3966 
3967 	ref2 = jit_EG(uninitialized_zval);
3968 
3969 	ir_MERGE_WITH_EMPTY_TRUE(if_def);
3970 
3971 	return ir_PHI_2(IR_ADDR, ref2, ref);
3972 }
3973 
zend_jit_recv_entry(zend_jit_ctx * jit,int b)3974 static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
3975 {
3976 	zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
3977 	int pred;
3978 	ir_ref ref;
3979 
3980 	ZEND_ASSERT(bb->predecessors_count > 0);
3981 
3982 	pred = jit->bb_predecessors[b];
3983 	ref = jit->bb_edges[pred];
3984 
3985 	ZEND_ASSERT(ref);
3986 	ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3987 
3988 	/* Insert a MERGE block with additional ENTRY input between predecessor and this one */
3989 	ir_ENTRY(ref, bb->start);
3990 	if (!GCC_GLOBAL_REGS) {
3991 		/* 2 is hardcoded reference to IR_PARAM */
3992 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
3993 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
3994 		jit_STORE_FP(jit, 2);
3995 	}
3996 
3997 	ir_MERGE_WITH(ref);
3998 	jit->bb_edges[pred] = ir_END();
3999 }
4000 
zend_jit_osr_entry(zend_jit_ctx * jit,int b)4001 static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4002 {
4003 	zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4004 	ir_ref ref = ir_END();
4005 
4006 	/* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4007 	ir_ENTRY(ref, bb->start);
4008 	if (!GCC_GLOBAL_REGS) {
4009 		/* 2 is hardcoded reference to IR_PARAM */
4010 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4011 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4012 		jit_STORE_FP(jit, 2);
4013 	}
4014 
4015 	ir_MERGE_WITH(ref);
4016 }
4017 
zend_jit_continue_entry(zend_jit_ctx * jit,ir_ref src,unsigned int label)4018 static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4019 {
4020 	ir_ENTRY(src, label);
4021 	if (!GCC_GLOBAL_REGS) {
4022 		/* 2 is hardcoded reference to IR_PARAM */
4023 		ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4024 		ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4025 		jit_STORE_FP(jit, 2);
4026 	}
4027 	return ir_END();
4028 }
4029 
zend_jit_handler(zend_jit_ctx * jit,const zend_op * opline,int may_throw)4030 static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4031 {
4032 	ir_ref ref;
4033 	const void *handler;
4034 
4035 	zend_jit_set_ip(jit, opline);
4036 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4037 		handler = zend_get_opcode_handler_func(opline);
4038 	} else {
4039 		handler = opline->handler;
4040 	}
4041 	if (GCC_GLOBAL_REGS) {
4042 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4043 	} else {
4044 		ref = jit_FP(jit);
4045 		ref = ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(handler), ref);
4046 	}
4047 	if (may_throw) {
4048 		zend_jit_check_exception(jit);
4049 	}
4050 	/* Skip the following OP_DATA */
4051 	switch (opline->opcode) {
4052 		case ZEND_ASSIGN_DIM:
4053 		case ZEND_ASSIGN_OBJ:
4054 		case ZEND_ASSIGN_STATIC_PROP:
4055 		case ZEND_ASSIGN_DIM_OP:
4056 		case ZEND_ASSIGN_OBJ_OP:
4057 		case ZEND_ASSIGN_STATIC_PROP_OP:
4058 		case ZEND_ASSIGN_STATIC_PROP_REF:
4059 		case ZEND_ASSIGN_OBJ_REF:
4060 			zend_jit_set_last_valid_opline(jit, opline + 2);
4061 			break;
4062 		default:
4063 			zend_jit_set_last_valid_opline(jit, opline + 1);
4064 			break;
4065 	}
4066 	return 1;
4067 }
4068 
zend_jit_tail_handler(zend_jit_ctx * jit,const zend_op * opline)4069 static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4070 {
4071 	const void *handler;
4072 	ir_ref ref;
4073 	zend_basic_block *bb;
4074 
4075 	zend_jit_set_ip(jit, opline);
4076 	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4077 		if (opline->opcode == ZEND_DO_UCALL ||
4078 		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4079 		    opline->opcode == ZEND_DO_FCALL ||
4080 		    opline->opcode == ZEND_RETURN) {
4081 
4082 			/* Use inlined HYBRID VM handler */
4083 			handler = opline->handler;
4084 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4085 		} else {
4086 			handler = zend_get_opcode_handler_func(opline);
4087 			ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4088 			ref = ir_LOAD_A(jit_IP(jit));
4089 			ir_TAILCALL(IR_VOID, ref);
4090 		}
4091 	} else {
4092 		handler = opline->handler;
4093 		if (GCC_GLOBAL_REGS) {
4094 			ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4095 		} else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4096 		 && (opline->opcode == ZEND_CATCH
4097 		  || opline->opcode == ZEND_FAST_CALL
4098 		  || opline->opcode == ZEND_FAST_RET
4099 		  || opline->opcode == ZEND_MATCH_ERROR
4100 		  || opline->opcode == ZEND_THROW
4101 		  || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4102 			ref = jit_FP(jit);
4103 			ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4104 			ir_RETURN(ir_CONST_I32(1));
4105 		} else {
4106 			ref = jit_FP(jit);
4107 			ir_TAILCALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4108 		}
4109 	}
4110 	if (jit->b >= 0) {
4111 		bb = &jit->ssa->cfg.blocks[jit->b];
4112 		if (bb->successors_count > 0
4113 		 && (opline->opcode == ZEND_DO_FCALL
4114 		  || opline->opcode == ZEND_DO_UCALL
4115 		  || opline->opcode == ZEND_DO_FCALL_BY_NAME
4116 		  || opline->opcode == ZEND_INCLUDE_OR_EVAL
4117 		  || opline->opcode == ZEND_GENERATOR_CREATE
4118 		  || opline->opcode == ZEND_YIELD
4119 		  || opline->opcode == ZEND_YIELD_FROM
4120 		  || opline->opcode == ZEND_FAST_CALL)) {
4121 			/* Add a fake control edge from UNREACHABLE to the following ENTRY */
4122 			int succ;
4123 
4124 			if (bb->successors_count == 1) {
4125 				succ = bb->successors[0];
4126 				ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
4127 			} else {
4128 				/* Use only the following successor of FAST_CALL */
4129 				ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4130 				succ = jit->b + 1;
4131 				/* we need an entry */
4132 				jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4133 			}
4134 			ref = jit->ctx.insns_count - 1;
4135 			ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4136 			ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4137 			_zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4138 		}
4139 		jit->b = -1;
4140 		zend_jit_reset_last_valid_opline(jit);
4141 	}
4142 	return 1;
4143 }
4144 
zend_jit_call(zend_jit_ctx * jit,const zend_op * opline,unsigned int next_block)4145 static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4146 {
4147 	return zend_jit_tail_handler(jit, opline);
4148 }
4149 
zend_jit_spill_store(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info,bool set_type)4150 static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4151 {
4152 	ZEND_ASSERT(Z_MODE(src) == IS_REG);
4153 	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4154 
4155 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4156 		jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4157 		if (set_type &&
4158 		    (Z_REG(dst) != ZREG_FP ||
4159 		     !JIT_G(current_frame) ||
4160 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4161 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4162 		}
4163 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4164 		jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4165 		if (set_type &&
4166 		    (Z_REG(dst) != ZREG_FP ||
4167 		     !JIT_G(current_frame) ||
4168 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4169 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4170 		}
4171 	} else {
4172 		ZEND_UNREACHABLE();
4173 	}
4174 	return 1;
4175 }
4176 
zend_jit_spill_store_inv(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4177 static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4178 {
4179 	ZEND_ASSERT(Z_MODE(src) == IS_REG);
4180 	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4181 
4182 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4183 		jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4184 		if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4185 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4186 		} else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4187 			/* invalidate memory type */
4188 			STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4189 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4190 		}
4191 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4192 		jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4193 		if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4194 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4195 		} else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4196 			/* invalidate memory type */
4197 			STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4198 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4199 		}
4200 	} else {
4201 		ZEND_UNREACHABLE();
4202 	}
4203 	return 1;
4204 }
4205 
zend_jit_load_reg(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4206 static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4207 {
4208 	ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
4209 	ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4210 
4211 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4212 		zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4213 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4214 		zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4215 	} else {
4216 		ZEND_UNREACHABLE();
4217 	}
4218 	return 1;
4219 }
4220 
zend_jit_store_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var,bool set_type)4221 static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4222 {
4223 	zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4224 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4225 
4226 	return zend_jit_spill_store(jit, src, dst, info, set_type);
4227 }
4228 
zend_jit_store_ref(zend_jit_ctx * jit,uint32_t info,int var,int32_t src,bool set_type)4229 static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4230 {
4231 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4232 
4233 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4234 		jit_set_Z_LVAL(jit, dst, src);
4235 		if (set_type &&
4236 		    (Z_REG(dst) != ZREG_FP ||
4237 		     !JIT_G(current_frame) ||
4238 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4239 			jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4240 		}
4241 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4242 		jit_set_Z_DVAL(jit, dst, src);
4243 		if (set_type &&
4244 		    (Z_REG(dst) != ZREG_FP ||
4245 		     !JIT_G(current_frame) ||
4246 		     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4247 			jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4248 		}
4249 	} else {
4250 		ZEND_UNREACHABLE();
4251 	}
4252 	return 1;
4253 }
4254 
zend_jit_deopt_rload(zend_jit_ctx * jit,ir_type type,int32_t reg)4255 static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4256 {
4257 	ir_ref ref = jit->ctx.control;
4258 	ir_insn *insn;
4259 
4260 	while (1) {
4261 		insn = &jit->ctx.ir_base[ref];
4262 		if (insn->op == IR_RLOAD && insn->op2 == reg) {
4263 			ZEND_ASSERT(insn->type == type);
4264 			return ref;
4265 		} else if (insn->op == IR_START) {
4266 			break;
4267 		}
4268 		ref = insn->op1;
4269 	}
4270 	return ir_RLOAD(type, reg);
4271 }
4272 
zend_jit_store_const_long(zend_jit_ctx * jit,int var,zend_long val)4273 static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4274 {
4275 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4276 	ir_ref src = ir_CONST_LONG(val);
4277 
4278 	if (jit->ra && jit->ra[var].ref == IR_NULL) {
4279 		zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4280 	}
4281 	jit_set_Z_LVAL(jit, dst, src);
4282 	jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4283 	return 1;
4284 }
4285 
zend_jit_store_const_double(zend_jit_ctx * jit,int var,double val)4286 static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4287 {
4288 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4289 	ir_ref src = ir_CONST_DOUBLE(val);
4290 
4291 	if (jit->ra && jit->ra[var].ref == IR_NULL) {
4292 		zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4293 	}
4294 	jit_set_Z_DVAL(jit, dst, src);
4295 	jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4296 	return 1;
4297 }
4298 
zend_jit_store_type(zend_jit_ctx * jit,int var,uint8_t type)4299 static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4300 {
4301 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4302 
4303 	ZEND_ASSERT(type <= IS_DOUBLE);
4304 	jit_set_Z_TYPE_INFO(jit, dst, type);
4305 	return 1;
4306 }
4307 
zend_jit_store_reg(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,bool in_mem,bool set_type)4308 static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4309 {
4310 	zend_jit_addr src;
4311 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4312 	ir_type type;
4313 
4314 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4315 		type = IR_LONG;
4316 		src = zend_jit_deopt_rload(jit, type, reg);
4317 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4318 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4319 		} else if (!in_mem) {
4320 			jit_set_Z_LVAL(jit, dst, src);
4321 			if (set_type &&
4322 			    (Z_REG(dst) != ZREG_FP ||
4323 			     !JIT_G(current_frame) ||
4324 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4325 				jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4326 			}
4327 		}
4328 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4329 		type = IR_DOUBLE;
4330 		src = zend_jit_deopt_rload(jit, type, reg);
4331 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4332 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4333 		} else if (!in_mem) {
4334 			jit_set_Z_DVAL(jit, dst, src);
4335 			if (set_type &&
4336 			    (Z_REG(dst) != ZREG_FP ||
4337 			     !JIT_G(current_frame) ||
4338 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4339 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4340 			}
4341 		}
4342 	} else {
4343 		ZEND_UNREACHABLE();
4344 	}
4345 	return 1;
4346 }
4347 
zend_jit_store_spill_slot(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,int32_t offset,bool set_type)4348 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)
4349 {
4350 	zend_jit_addr src;
4351 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4352 
4353 	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4354 		src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4355 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4356 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4357 		} else {
4358 			jit_set_Z_LVAL(jit, dst, src);
4359 			if (set_type &&
4360 			    (Z_REG(dst) != ZREG_FP ||
4361 			     !JIT_G(current_frame) ||
4362 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4363 				jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4364 			}
4365 		}
4366 	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4367 		src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4368 		if (jit->ra && jit->ra[var].ref == IR_NULL) {
4369 			zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4370 		} else {
4371 			jit_set_Z_DVAL(jit, dst, src);
4372 			if (set_type &&
4373 			    (Z_REG(dst) != ZREG_FP ||
4374 			     !JIT_G(current_frame) ||
4375 			     STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4376 				jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4377 			}
4378 		}
4379 	} else {
4380 		ZEND_UNREACHABLE();
4381 	}
4382 	return 1;
4383 }
4384 
zend_jit_store_var_type(zend_jit_ctx * jit,int var,uint32_t type)4385 static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4386 {
4387 	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4388 
4389 	jit_set_Z_TYPE_INFO(jit, dst, type);
4390 	return 1;
4391 }
4392 
zend_jit_zval_try_addref(zend_jit_ctx * jit,zend_jit_addr var_addr)4393 static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4394 {
4395 	ir_ref if_refcounted, end1;
4396 
4397 	if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4398 	ir_IF_FALSE(if_refcounted);
4399 	end1 = ir_END();
4400 	ir_IF_TRUE(if_refcounted);
4401 	jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4402 	ir_MERGE_WITH(end1);
4403 	return 1;
4404 }
4405 
zend_jit_store_var_if_necessary(zend_jit_ctx * jit,int var,zend_jit_addr src,uint32_t info)4406 static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4407 {
4408 	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4409 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4410 		return zend_jit_spill_store(jit, src, dst, info, 1);
4411 	}
4412 	return 1;
4413 }
4414 
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)4415 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)
4416 {
4417 	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4418 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4419 		bool set_type = 1;
4420 
4421 		if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4422 		    (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4423 			if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4424 				if (JIT_G(current_frame)) {
4425 					uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4426 
4427 					if (mem_type != IS_UNKNOWN
4428 					 && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4429 						set_type = 0;
4430 					}
4431 				} else {
4432 					set_type = 0;
4433 				}
4434 			}
4435 		}
4436 		return zend_jit_spill_store(jit, src, dst, info, set_type);
4437 	}
4438 	return 1;
4439 }
4440 
zend_jit_load_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var)4441 static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4442 {
4443 	zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4444 	zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4445 
4446 	return zend_jit_load_reg(jit, src, dst, info);
4447 }
4448 
zend_jit_invalidate_var_if_necessary(zend_jit_ctx * jit,uint8_t op_type,zend_jit_addr addr,znode_op op)4449 static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4450 {
4451 	if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4452 		/* Invalidate operand type to prevent incorrect destuction by exception_handler_free_op1_op2() */
4453 		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4454 		jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4455 	}
4456 	return 1;
4457 }
4458 
zend_jit_update_regs(zend_jit_ctx * jit,uint32_t var,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4459 static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4460 {
4461 	if (!zend_jit_same_addr(src, dst)) {
4462 		if (Z_MODE(src) == IS_REG) {
4463 			if (Z_MODE(dst) == IS_REG) {
4464 				zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4465 				if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4466 					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4467 
4468 					if (!zend_jit_spill_store(jit, dst, var_addr, info,
4469 							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4470 							JIT_G(current_frame) == NULL ||
4471 							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4472 							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4473 					)) {
4474 						return 0;
4475 					}
4476 				}
4477 			} else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4478 				if (!Z_LOAD(src) && !Z_STORE(src)) {
4479 					if (!zend_jit_spill_store(jit, src, dst, info,
4480 							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4481 							JIT_G(current_frame) == NULL ||
4482 							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4483 							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4484 					)) {
4485 						return 0;
4486 					}
4487 				}
4488 			} else {
4489 				ZEND_UNREACHABLE();
4490 			}
4491 		} else if (Z_MODE(src) == IS_MEM_ZVAL) {
4492 			if (Z_MODE(dst) == IS_REG) {
4493 				if (!zend_jit_load_reg(jit, src, dst, info)) {
4494 					return 0;
4495 				}
4496 			} else {
4497 				ZEND_UNREACHABLE();
4498 			}
4499 		} else {
4500 			ZEND_UNREACHABLE();
4501 		}
4502 	} else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4503 		dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4504 		if (!zend_jit_spill_store(jit, src, dst, info,
4505 				JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4506 				JIT_G(current_frame) == NULL ||
4507 				STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4508 				(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4509 		)) {
4510 			return 0;
4511 		}
4512 	}
4513 	return 1;
4514 }
4515 
4516 struct jit_observer_fcall_is_unobserved_data {
4517 	ir_ref if_unobserved;
4518 	ir_ref ir_end_inputs;
4519 };
4520 
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)4521 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) {
4522 	ir_ref run_time_cache;
4523 	struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4524 	if (func) {
4525 		ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4526 	} else {
4527 		// JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4528 		ZEND_ASSERT(rx != IR_UNUSED);
4529 		ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4530 			ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4531 			ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4532 		ir_IF_TRUE(if_trampoline_or_generator);
4533 		ir_END_list(data.ir_end_inputs);
4534 		ir_IF_FALSE(if_trampoline_or_generator);
4535 	}
4536 	if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4537 		// JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4538 		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)));
4539 	} else {
4540 		ZEND_ASSERT(rx != IR_UNUSED);
4541 		// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4542 		if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4543 			run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4544 		} else {
4545 			// JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4546 			run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4547 			ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4548 			ir_IF_TRUE(if_odd);
4549 
4550 			ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4551 
4552 			ir_ref if_odd_end = ir_END();
4553 			ir_IF_FALSE(if_odd);
4554 
4555 			// JIT: if (func->common.runtime_cache != NULL) {
4556 			ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4557 			ir_IF_TRUE(if_rt_cache);
4558 			ir_END_list(data.ir_end_inputs);
4559 			ir_IF_FALSE(if_rt_cache);
4560 
4561 			ir_MERGE_WITH(if_odd_end);
4562 			run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4563 		}
4564 	}
4565 	// JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4566 	if (func) {
4567 		*observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4568 	} else {
4569 		// JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4570 		ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4571 		ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4572 		ir_IF_TRUE(if_internal_func);
4573 
4574 		ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4575 
4576 		ir_ref if_internal_func_end = ir_END();
4577 		ir_IF_FALSE(if_internal_func);
4578 
4579 		ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4580 
4581 		ir_MERGE_WITH(if_internal_func_end);
4582 		*observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
4583 	}
4584 
4585 	// JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4586 	data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4587 	ir_IF_FALSE(data.if_unobserved);
4588 	return data;
4589 }
4590 
4591 /* 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)4592 static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4593 	ir_END_list(data->ir_end_inputs);
4594 	ir_IF_TRUE(data->if_unobserved);
4595 	ir_END_list(data->ir_end_inputs);
4596 	ir_MERGE_list(data->ir_end_inputs);
4597 }
4598 
jit_observer_fcall_begin(zend_jit_ctx * jit,ir_ref rx,ir_ref observer_handler)4599 static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4600 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4601 }
4602 
jit_observer_fcall_end(zend_jit_ctx * jit,ir_ref rx,ir_ref res_ref)4603 static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4604 	// JIT: if (execute_data == EG(current_observed_frame)) {
4605 	ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4606 	ir_IF_TRUE(has_end_observer);
4607 	ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4608 		rx, res_ref);
4609 	ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4610 }
4611 
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)4612 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)
4613 {
4614 	ir_ref if_long = IR_UNUSED;
4615 	ir_ref op1_lval_ref = IR_UNUSED;
4616 	ir_ref ref;
4617 	ir_op op;
4618 
4619 	if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4620 		if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4621 		ir_IF_TRUE(if_long);
4622 	}
4623 	if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4624 		op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4625 		jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4626 		if (Z_MODE(res_addr) != IS_REG) {
4627 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4628 		}
4629 	}
4630 	if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4631 	 && Z_MODE(op1_addr) == IS_REG
4632 	 && !Z_LOAD(op1_addr)
4633 	 && !Z_STORE(op1_addr)) {
4634 		jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4635 	}
4636 	if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4637 		op = may_overflow ? IR_ADD_OV : IR_ADD;
4638 	} else {
4639 		op = may_overflow ? IR_SUB_OV : IR_SUB;
4640 	}
4641 	if (!op1_lval_ref) {
4642 		op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4643 	}
4644 	ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4645 	if (op1_def_info & MAY_BE_LONG) {
4646 		jit_set_Z_LVAL(jit, op1_def_addr, ref);
4647 	}
4648 	if (may_overflow &&
4649 	    (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4650 	     ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4651 		int32_t exit_point;
4652 		const void *exit_addr;
4653 		zend_jit_trace_stack *stack;
4654 		uint32_t old_op1_info, old_res_info = 0;
4655 
4656 		stack = JIT_G(current_frame)->stack;
4657 		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4658 		SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4659 		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4660 			SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4661 		} else {
4662 			SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4663 		}
4664 		if (opline->result_type != IS_UNUSED) {
4665 			old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4666 			if (opline->opcode == ZEND_PRE_INC) {
4667 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4668 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4669 			} else if (opline->opcode == ZEND_PRE_DEC) {
4670 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4671 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4672 			} else if (opline->opcode == ZEND_POST_INC) {
4673 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4674 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MAX));
4675 			} else if (opline->opcode == ZEND_POST_DEC) {
4676 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4677 				SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MIN));
4678 			}
4679 		}
4680 
4681 		exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4682 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4683 		ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4684 
4685 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4686 		    opline->result_type != IS_UNUSED) {
4687 			jit_set_Z_LVAL(jit, res_addr, ref);
4688 			if (Z_MODE(res_addr) != IS_REG) {
4689 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4690 			}
4691 		}
4692 
4693 		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4694 		if (opline->result_type != IS_UNUSED) {
4695 			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4696 		}
4697 	} else if (may_overflow) {
4698 		ir_ref if_overflow;
4699 		ir_ref merge_inputs = IR_UNUSED;
4700 
4701 		if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4702 		 || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) ==  (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4703 			int32_t exit_point;
4704 			const void *exit_addr;
4705 			zend_jit_trace_stack *stack;
4706 			uint32_t old_res_info = 0;
4707 
4708 			stack = JIT_G(current_frame)->stack;
4709 			if (opline->result_type != IS_UNUSED) {
4710 				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4711 				if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4712 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4713 				}
4714 			}
4715 			exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4716 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4717 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4718 			    opline->result_type != IS_UNUSED) {
4719 				if_overflow = ir_IF(ir_OVERFLOW(ref));
4720 				ir_IF_FALSE_cold(if_overflow);
4721 				jit_set_Z_LVAL(jit, res_addr, ref);
4722 				if (Z_MODE(res_addr) != IS_REG) {
4723 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4724 				}
4725 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
4726 				ir_IF_TRUE(if_overflow);
4727 			} else {
4728 				ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4729 			}
4730 			if (opline->result_type != IS_UNUSED) {
4731 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4732 			}
4733 		} else {
4734 			if_overflow = ir_IF(ir_OVERFLOW(ref));
4735 			ir_IF_FALSE(if_overflow);
4736 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4737 			    opline->result_type != IS_UNUSED) {
4738 				jit_set_Z_LVAL(jit, res_addr, ref);
4739 				if (Z_MODE(res_addr) != IS_REG) {
4740 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4741 				}
4742 			}
4743 			ir_END_list(merge_inputs);
4744 
4745 			/* overflow => cold path */
4746 			ir_IF_TRUE_cold(if_overflow);
4747 		}
4748 
4749 		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4750 			if (Z_MODE(op1_def_addr) == IS_REG) {
4751 				jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4752 			} else {
4753 #if SIZEOF_ZEND_LONG == 4
4754 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0));
4755 				jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0x41e00000));
4756 #else
4757 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4758 #endif
4759 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4760 			}
4761 		} else {
4762 			if (Z_MODE(op1_def_addr) == IS_REG) {
4763 				jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4764 			} else {
4765 #if SIZEOF_ZEND_LONG == 4
4766 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x00200000));
4767 				jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0xc1e00000));
4768 #else
4769 				jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4770 #endif
4771 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4772 			}
4773 		}
4774 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4775 		    opline->result_type != IS_UNUSED) {
4776 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4777 				if (Z_MODE(res_addr) == IS_REG) {
4778 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4779 				} else {
4780 #if SIZEOF_ZEND_LONG == 4
4781 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
4782 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
4783 #else
4784 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4785 #endif
4786 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4787 				}
4788 			} else {
4789 				if (Z_MODE(res_addr) == IS_REG) {
4790 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4791 				} else {
4792 #if SIZEOF_ZEND_LONG == 4
4793 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
4794 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
4795 #else
4796 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
4797 #endif
4798 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4799 				}
4800 			}
4801 		}
4802 
4803 		if (merge_inputs) {
4804 			ir_END_list(merge_inputs);
4805 			ir_MERGE_list(merge_inputs);
4806 		}
4807 	} else {
4808 		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4809 		    opline->result_type != IS_UNUSED) {
4810 			jit_set_Z_LVAL(jit, res_addr, ref);
4811 			if (Z_MODE(res_addr) != IS_REG) {
4812 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4813 			}
4814 		}
4815 	}
4816 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4817 		ir_ref merge_inputs = ir_END();
4818 
4819 		/* !is_long => cold path */
4820 		ir_IF_FALSE_cold(if_long);
4821 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4822 			jit_SET_EX_OPLINE(jit, opline);
4823 			if (op1_info & MAY_BE_UNDEF) {
4824 				ir_ref if_def;
4825 
4826 				if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
4827 				ir_IF_FALSE_cold(if_def);
4828 
4829 				// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
4830 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
4831 
4832 				jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
4833 				ir_MERGE_WITH_EMPTY_TRUE(if_def);
4834 
4835 				op1_info |= MAY_BE_NULL;
4836 			}
4837 
4838 			ref = jit_ZVAL_ADDR(jit, op1_addr);
4839 
4840 			if (op1_info & MAY_BE_REF) {
4841 				ir_ref if_ref, if_typed, func, ref2, arg2;
4842 
4843 				if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
4844 				ir_IF_TRUE(if_ref);
4845 				ref2 = jit_Z_PTR_ref(jit, ref);
4846 
4847 				if_typed = jit_if_TYPED_REF(jit, ref2);
4848 				ir_IF_TRUE(if_typed);
4849 
4850 				if (RETURN_VALUE_USED(opline)) {
4851 					ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
4852 					arg2 = jit_ZVAL_ADDR(jit, res_addr);
4853 				} else {
4854 					arg2 = IR_NULL;
4855 				}
4856 				if (opline->opcode == ZEND_PRE_INC) {
4857 					func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
4858 				} else if (opline->opcode == ZEND_PRE_DEC) {
4859 					func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
4860 				} else if (opline->opcode == ZEND_POST_INC) {
4861 					func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
4862 				} else if (opline->opcode == ZEND_POST_DEC) {
4863 					func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
4864 				} else {
4865 					ZEND_UNREACHABLE();
4866 				}
4867 
4868 				ir_CALL_2(IR_VOID, func, ref2, arg2);
4869 				zend_jit_check_exception(jit);
4870 				ir_END_list(merge_inputs);
4871 
4872 				ir_IF_FALSE(if_typed);
4873 				ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
4874 				ir_MERGE_WITH_EMPTY_FALSE(if_ref);
4875 				ref = ir_PHI_2(IR_ADDR, ref2, ref);
4876 			}
4877 
4878 			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4879 				jit_ZVAL_COPY(jit,
4880 					res_addr,
4881 					res_use_info,
4882 					ZEND_ADDR_REF_ZVAL(ref), op1_info, 1);
4883 			}
4884 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4885 				if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
4886 					ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4887 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
4888 				} else {
4889 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function), ref);
4890 				}
4891 			} else {
4892 				if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
4893 					ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4894 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec), ref, arg2);
4895 				} else {
4896 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function), ref);
4897 				}
4898 			}
4899 			if (may_throw) {
4900 				zend_jit_check_exception(jit);
4901 			}
4902 		} else {
4903 			ref = jit_Z_DVAL(jit, op1_addr);
4904 			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4905 				jit_set_Z_DVAL(jit, res_addr, ref);
4906 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4907 			}
4908 			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4909 				op = IR_ADD;
4910 			} else {
4911 				op = IR_SUB;
4912 			}
4913 			ref = ir_BINARY_OP_D(op, ref, ir_CONST_DOUBLE(1.0));
4914 			jit_set_Z_DVAL(jit, op1_def_addr, ref);
4915 			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4916 			    opline->result_type != IS_UNUSED) {
4917 				jit_set_Z_DVAL(jit, res_addr, ref);
4918 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4919 			}
4920 		}
4921 		ir_END_list(merge_inputs);
4922 		ir_MERGE_list(merge_inputs);
4923 	}
4924 	if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
4925 		return 0;
4926 	}
4927 	if (opline->result_type != IS_UNUSED) {
4928 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
4929 			return 0;
4930 		}
4931 	}
4932 	return 1;
4933 }
4934 
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)4935 static int zend_jit_math_long_long(zend_jit_ctx   *jit,
4936                                    const zend_op  *opline,
4937                                    uint8_t         opcode,
4938                                    zend_jit_addr   op1_addr,
4939                                    zend_jit_addr   op2_addr,
4940                                    zend_jit_addr   res_addr,
4941                                    uint32_t        res_info,
4942                                    uint32_t        res_use_info,
4943                                    int             may_overflow)
4944 {
4945 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4946 	ir_op op;
4947 	ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
4948 
4949 	if (opcode == ZEND_ADD) {
4950 		op = may_overflow ? IR_ADD_OV : IR_ADD;
4951 	} else if (opcode == ZEND_SUB) {
4952 		op = may_overflow ? IR_SUB_OV : IR_SUB;
4953 	} else if (opcode == ZEND_MUL) {
4954 		op = may_overflow ? IR_MUL_OV : IR_MUL;
4955 	} else {
4956 		ZEND_UNREACHABLE();
4957 	}
4958 	op1 = jit_Z_LVAL(jit, op1_addr);
4959 	op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
4960 	ref = ir_BINARY_OP_L(op, op1, op2);
4961 
4962 	if (may_overflow) {
4963 		if (res_info & MAY_BE_GUARD) {
4964 			if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
4965 				zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
4966 				uint32_t old_res_info;
4967 				int32_t exit_point;
4968 				const void *exit_addr;
4969 
4970 				if (opline->opcode == ZEND_ADD
4971 				 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
4972 					old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4973 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4974 					SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4975 					exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4976 					SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4977 				} else if (opline->opcode == ZEND_SUB
4978 				 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
4979 					old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4980 					SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4981 					SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4982 					exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4983 					SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4984 				} else {
4985 					exit_point = zend_jit_trace_get_exit_point(opline, 0);
4986 				}
4987 
4988 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4989 				if (!exit_addr) {
4990 					return 0;
4991 				}
4992 				ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4993 				may_overflow = 0;
4994 			} else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4995 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
4996 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4997 
4998 				if (!exit_addr) {
4999 					return 0;
5000 				}
5001 				ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5002 			} else {
5003 				ZEND_UNREACHABLE();
5004 			}
5005 		} else {
5006 			if_overflow = ir_IF(ir_OVERFLOW(ref));
5007 			ir_IF_FALSE(if_overflow);
5008 		}
5009 	}
5010 
5011 	if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5012 		jit_set_Z_LVAL(jit, res_addr, ref);
5013 
5014 		if (Z_MODE(res_addr) != IS_REG) {
5015 			if (!zend_jit_same_addr(op1_addr, res_addr)) {
5016 				if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5017 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5018 				}
5019 			}
5020 		}
5021 	}
5022 
5023 	if (may_overflow) {
5024 		ir_ref fast_path = IR_UNUSED;
5025 
5026 		if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5027 			fast_path = ir_END();
5028 			ir_IF_TRUE_cold(if_overflow);
5029 		}
5030 		if (opcode == ZEND_ADD) {
5031 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5032 				if (Z_MODE(res_addr) == IS_REG) {
5033 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5034 				} else {
5035 #if SIZEOF_ZEND_LONG == 4
5036 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
5037 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
5038 #else
5039 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5040 #endif
5041 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5042 				}
5043 				if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5044 					ir_MERGE_WITH(fast_path);
5045 				}
5046 				return 1;
5047 			}
5048 			op = IR_ADD;
5049 		} else if (opcode == ZEND_SUB) {
5050 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5051 				if (Z_MODE(res_addr) == IS_REG) {
5052 					jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5053 				} else {
5054 #if SIZEOF_ZEND_LONG == 4
5055 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
5056 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
5057 #else
5058 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
5059 #endif
5060 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5061 				}
5062 				if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5063 					ir_MERGE_WITH(fast_path);
5064 				}
5065 				return 1;
5066 			}
5067 			op = IR_SUB;
5068 		} else if (opcode == ZEND_MUL) {
5069 			op = IR_MUL;
5070 		} else {
5071 			ZEND_UNREACHABLE();
5072 		}
5073 #if 1
5074 		/* reload */
5075 		op1 = jit_Z_LVAL(jit, op1_addr);
5076 		op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5077 #endif
5078 #if 1
5079 		/* disable CSE */
5080 		ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5081 		jit->ctx.fold_cse_limit = 0x7fffffff;
5082 #endif
5083 		op1 = ir_INT2D(op1);
5084 		op2 = ir_INT2D(op2);
5085 #if 1
5086 		jit->ctx.fold_cse_limit = old_cse_limit;
5087 #endif
5088 		ref = ir_BINARY_OP_D(op, op1, op2);
5089 		jit_set_Z_DVAL(jit, res_addr, ref);
5090 		if (Z_MODE(res_addr) != IS_REG) {
5091 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5092 		}
5093 		if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5094 			ir_MERGE_WITH(fast_path);
5095 		}
5096 	}
5097 
5098 	return 1;
5099 }
5100 
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)5101 static int zend_jit_math_long_double(zend_jit_ctx   *jit,
5102                                      uint8_t         opcode,
5103                                      zend_jit_addr   op1_addr,
5104                                      zend_jit_addr   op2_addr,
5105                                      zend_jit_addr   res_addr,
5106                                      uint32_t        res_use_info)
5107 {
5108 	ir_op op;
5109 	ir_ref op1, op2, ref;
5110 
5111 	if (opcode == ZEND_ADD) {
5112 		op = IR_ADD;
5113 	} else if (opcode == ZEND_SUB) {
5114 		op = IR_SUB;
5115 	} else if (opcode == ZEND_MUL) {
5116 		op = IR_MUL;
5117 	} else if (opcode == ZEND_DIV) {
5118 		op = IR_DIV;
5119 	} else {
5120 		ZEND_UNREACHABLE();
5121 	}
5122 	op1 = jit_Z_LVAL(jit, op1_addr);
5123 	op2 = jit_Z_DVAL(jit, op2_addr);
5124 	ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5125 	jit_set_Z_DVAL(jit, res_addr, ref);
5126 
5127 	if (Z_MODE(res_addr) != IS_REG) {
5128 		if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5129 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5130 		}
5131 	}
5132 	return 1;
5133 }
5134 
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)5135 static int zend_jit_math_double_long(zend_jit_ctx   *jit,
5136                                      uint8_t         opcode,
5137                                      zend_jit_addr   op1_addr,
5138                                      zend_jit_addr   op2_addr,
5139                                      zend_jit_addr   res_addr,
5140                                      uint32_t        res_use_info)
5141 {
5142 	ir_op op;
5143 	ir_ref op1, op2, ref;
5144 
5145 	if (opcode == ZEND_ADD) {
5146 		op = IR_ADD;
5147 	} else if (opcode == ZEND_SUB) {
5148 		op = IR_SUB;
5149 	} else if (opcode == ZEND_MUL) {
5150 		op = IR_MUL;
5151 	} else if (opcode == ZEND_DIV) {
5152 		op = IR_DIV;
5153 	} else {
5154 		ZEND_UNREACHABLE();
5155 	}
5156 	op1 = jit_Z_DVAL(jit, op1_addr);
5157 	op2 = jit_Z_LVAL(jit, op2_addr);
5158 	ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5159 	jit_set_Z_DVAL(jit, res_addr, ref);
5160 
5161 	if (Z_MODE(res_addr) != IS_REG) {
5162 		if (!zend_jit_same_addr(op1_addr, res_addr)) {
5163 			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5164 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5165 			}
5166 		}
5167 	}
5168 	return 1;
5169 }
5170 
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)5171 static int zend_jit_math_double_double(zend_jit_ctx   *jit,
5172                                        uint8_t         opcode,
5173                                        zend_jit_addr   op1_addr,
5174                                        zend_jit_addr   op2_addr,
5175                                        zend_jit_addr   res_addr,
5176                                        uint32_t        res_use_info)
5177 {
5178 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5179 	ir_op op;
5180 	ir_ref op1, op2, ref;
5181 
5182 	if (opcode == ZEND_ADD) {
5183 		op = IR_ADD;
5184 	} else if (opcode == ZEND_SUB) {
5185 		op = IR_SUB;
5186 	} else if (opcode == ZEND_MUL) {
5187 		op = IR_MUL;
5188 	} else if (opcode == ZEND_DIV) {
5189 		op = IR_DIV;
5190 	} else {
5191 		ZEND_UNREACHABLE();
5192 	}
5193 	op1 = jit_Z_DVAL(jit, op1_addr);
5194 	op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5195 	ref = ir_BINARY_OP_D(op, op1, op2);
5196 	jit_set_Z_DVAL(jit, res_addr, ref);
5197 
5198 	if (Z_MODE(res_addr) != IS_REG) {
5199 		if (!zend_jit_same_addr(op1_addr, res_addr)) {
5200 			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5201 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5202 			}
5203 		}
5204 	}
5205 	return 1;
5206 }
5207 
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)5208 static int zend_jit_math_helper(zend_jit_ctx   *jit,
5209                                 const zend_op  *opline,
5210                                 uint8_t         opcode,
5211                                 uint8_t         op1_type,
5212                                 znode_op        op1,
5213                                 zend_jit_addr   op1_addr,
5214                                 uint32_t        op1_info,
5215                                 uint8_t         op2_type,
5216                                 znode_op        op2,
5217                                 zend_jit_addr   op2_addr,
5218                                 uint32_t        op2_info,
5219                                 uint32_t        res_var,
5220                                 zend_jit_addr   res_addr,
5221                                 uint32_t        res_info,
5222                                 uint32_t        res_use_info,
5223                                 int             may_overflow,
5224                                 int             may_throw)
5225 {
5226 	ir_ref if_op1_long = IR_UNUSED;
5227 	ir_ref if_op1_double = IR_UNUSED;
5228 	ir_ref if_op2_double = IR_UNUSED;
5229 	ir_ref if_op1_long_op2_long = IR_UNUSED;
5230 	ir_ref if_op1_long_op2_double = IR_UNUSED;
5231 	ir_ref if_op1_double_op2_double = IR_UNUSED;
5232 	ir_ref if_op1_double_op2_long = IR_UNUSED;
5233 	ir_ref slow_inputs = IR_UNUSED;
5234 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5235 	ir_refs *end_inputs;
5236 	ir_refs *res_inputs;
5237 
5238 	ir_refs_init(end_inputs, 6);
5239 	ir_refs_init(res_inputs, 6);
5240 
5241 	if (Z_MODE(op1_addr) == IS_REG) {
5242 		if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5243 			/* Force load */
5244 			zend_jit_use_reg(jit, op1_addr);
5245 		}
5246 	} else if (Z_MODE(op2_addr) == IS_REG) {
5247 		if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5248 			/* Force load */
5249 			zend_jit_use_reg(jit, op2_addr);
5250 		}
5251 	}
5252 
5253 	if (Z_MODE(res_addr) == IS_REG) {
5254 		jit->delay_var = Z_SSA_VAR(res_addr);
5255 		jit->delay_refs = res_inputs;
5256 	}
5257 
5258 	if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5259 		if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5260 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5261 			ir_IF_TRUE(if_op1_long);
5262 		}
5263 		if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5264 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5265 			ir_IF_TRUE(if_op1_long_op2_long);
5266 		}
5267 		if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5268 			return 0;
5269 		}
5270 		ir_refs_add(end_inputs, ir_END());
5271 		if (if_op1_long) {
5272 			ir_IF_FALSE_cold(if_op1_long);
5273 			ir_END_list(slow_inputs);
5274 		}
5275 		if (if_op1_long_op2_long) {
5276 			ir_IF_FALSE_cold(if_op1_long_op2_long);
5277 			ir_END_list(slow_inputs);
5278 		}
5279 	} else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
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_FALSE_cold(if_op1_long_op2_long);
5287 			if (op2_info & MAY_BE_DOUBLE) {
5288 				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5289 					if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5290 					ir_IF_FALSE_cold(if_op1_long_op2_double);
5291 					ir_END_list(slow_inputs);
5292 					ir_IF_TRUE(if_op1_long_op2_double);
5293 				}
5294 				if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5295 					return 0;
5296 				}
5297 				ir_refs_add(end_inputs, ir_END());
5298 			} else {
5299 				ir_END_list(slow_inputs);
5300 			}
5301 			ir_IF_TRUE(if_op1_long_op2_long);
5302 		}
5303 		if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5304 			return 0;
5305 		}
5306 		ir_refs_add(end_inputs, ir_END());
5307 
5308 		if (if_op1_long) {
5309 			ir_IF_FALSE_cold(if_op1_long);
5310 		}
5311 
5312 		if (op1_info & MAY_BE_DOUBLE) {
5313 			if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5314 				if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5315 				ir_IF_FALSE_cold(if_op1_double);
5316 				ir_END_list(slow_inputs);
5317 				ir_IF_TRUE(if_op1_double);
5318 			}
5319 			if (op2_info & MAY_BE_DOUBLE) {
5320 				if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5321 					if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5322 					ir_IF_TRUE(if_op1_double_op2_double);
5323 				}
5324 				if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5325 					return 0;
5326 				}
5327 				ir_refs_add(end_inputs, ir_END());
5328 				if (if_op1_double_op2_double) {
5329 					ir_IF_FALSE_cold(if_op1_double_op2_double);
5330 				}
5331 			}
5332 			if (!same_ops) {
5333 				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5334 					if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5335 					ir_IF_FALSE_cold(if_op1_double_op2_long);
5336 					ir_END_list(slow_inputs);
5337 					ir_IF_TRUE(if_op1_double_op2_long);
5338 				}
5339 				if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5340 					return 0;
5341 				}
5342 				ir_refs_add(end_inputs, ir_END());
5343 			} else if (if_op1_double_op2_double) {
5344 				ir_END_list(slow_inputs);
5345 			}
5346 		} else if (if_op1_long) {
5347 			ir_END_list(slow_inputs);
5348 		}
5349 	} else if ((op1_info & MAY_BE_DOUBLE) &&
5350 	           !(op1_info & MAY_BE_LONG) &&
5351 	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5352 	           (res_info & MAY_BE_DOUBLE)) {
5353 		if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5354 			if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5355 			ir_IF_FALSE_cold(if_op1_double);
5356 			ir_END_list(slow_inputs);
5357 			ir_IF_TRUE(if_op1_double);
5358 		}
5359 		if (op2_info & MAY_BE_DOUBLE) {
5360 			if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5361 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5362 				ir_IF_TRUE(if_op1_double_op2_double);
5363 			}
5364 			if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5365 				return 0;
5366 			}
5367 			ir_refs_add(end_inputs, ir_END());
5368 			if (if_op1_double_op2_double) {
5369 				ir_IF_FALSE_cold(if_op1_double_op2_double);
5370 			}
5371 		}
5372 		if (!same_ops && (op2_info & MAY_BE_LONG)) {
5373 			if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5374 				if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5375 				ir_IF_FALSE_cold(if_op1_double_op2_long);
5376 				ir_END_list(slow_inputs);
5377 				ir_IF_TRUE(if_op1_double_op2_long);
5378 			}
5379 			if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5380 				return 0;
5381 			}
5382 			ir_refs_add(end_inputs, ir_END());
5383 		} else if (if_op1_double_op2_double) {
5384 			ir_END_list(slow_inputs);
5385 		}
5386 	} else if ((op2_info & MAY_BE_DOUBLE) &&
5387 	           !(op2_info & MAY_BE_LONG) &&
5388 	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5389 	           (res_info & MAY_BE_DOUBLE)) {
5390 		if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5391 			if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5392 			ir_IF_FALSE_cold(if_op2_double);
5393 			ir_END_list(slow_inputs);
5394 			ir_IF_TRUE(if_op2_double);
5395 		}
5396 		if (op1_info & MAY_BE_DOUBLE) {
5397 			if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5398 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5399 				ir_IF_TRUE(if_op1_double_op2_double);
5400 			}
5401 			if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5402 				return 0;
5403 			}
5404 			ir_refs_add(end_inputs, ir_END());
5405 			if (if_op1_double_op2_double) {
5406 				ir_IF_FALSE_cold(if_op1_double_op2_double);
5407 			}
5408 		}
5409 		if (!same_ops && (op1_info & MAY_BE_LONG)) {
5410 			if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5411 				if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5412 				ir_IF_FALSE_cold(if_op1_long_op2_double);
5413 				ir_END_list(slow_inputs);
5414 				ir_IF_TRUE(if_op1_long_op2_double);
5415 			}
5416 			if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5417 				return 0;
5418 			}
5419 			ir_refs_add(end_inputs, ir_END());
5420 		} else if (if_op1_double_op2_double) {
5421 			ir_END_list(slow_inputs);
5422 		}
5423 	}
5424 
5425 	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5426 		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5427 		ir_ref func, arg1, arg2, arg3;
5428 
5429 		if (slow_inputs) {
5430 			ir_MERGE_list(slow_inputs);
5431 		}
5432 
5433 		if (Z_MODE(op1_addr) == IS_REG) {
5434 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5435 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5436 				return 0;
5437 			}
5438 			op1_addr = real_addr;
5439 		}
5440 		if (Z_MODE(op2_addr) == IS_REG) {
5441 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5442 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5443 				return 0;
5444 			}
5445 			op2_addr = real_addr;
5446 		}
5447 		if (Z_MODE(res_addr) == IS_REG) {
5448 			arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5449 		} else {
5450 			arg1 = jit_ZVAL_ADDR(jit, res_addr);
5451 		}
5452 		arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5453 		arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5454 		jit_SET_EX_OPLINE(jit, opline);
5455 		if (opcode == ZEND_ADD) {
5456 			func = ir_CONST_FC_FUNC(add_function);
5457 		} else if (opcode == ZEND_SUB) {
5458 			func = ir_CONST_FC_FUNC(sub_function);
5459 		} else if (opcode == ZEND_MUL) {
5460 			func = ir_CONST_FC_FUNC(mul_function);
5461 		} else if (opcode == ZEND_DIV) {
5462 			func = ir_CONST_FC_FUNC(div_function);
5463 		} else {
5464 			ZEND_UNREACHABLE();
5465 		}
5466 		ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5467 
5468 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5469 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5470 
5471 		if (may_throw) {
5472 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5473 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5474 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5475 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5476 				zend_jit_check_exception_undef_result(jit, opline);
5477 			} else {
5478 				zend_jit_check_exception(jit);
5479 			}
5480 		}
5481 		if (Z_MODE(res_addr) == IS_REG) {
5482 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5483 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5484 				return 0;
5485 			}
5486 		}
5487 		ir_refs_add(end_inputs, ir_END());
5488 	}
5489 
5490 	if (end_inputs->count) {
5491 		ir_MERGE_N(end_inputs->count, end_inputs->refs);
5492 	}
5493 
5494 	if (Z_MODE(res_addr) == IS_REG) {
5495 		ZEND_ASSERT(jit->delay_refs == res_inputs);
5496 		ZEND_ASSERT(end_inputs->count == res_inputs->count);
5497 		jit->delay_var = -1;
5498 		jit->delay_refs = NULL;
5499 		if (res_inputs->count == 1) {
5500 			zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5501 		} else {
5502 			ir_ref phi = ir_PHI_N((res_info & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE, res_inputs->count, res_inputs->refs);
5503 			zend_jit_def_reg(jit, res_addr, phi);
5504 		}
5505 	}
5506 
5507 	return 1;
5508 }
5509 
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)5510 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)
5511 {
5512 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5513 
5514 	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)) {
5515 		return 0;
5516 	}
5517 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5518 		return 0;
5519 	}
5520 	return 1;
5521 }
5522 
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)5523 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)
5524 {
5525 	ir_ref ref;
5526 	ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5527 	ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5528 
5529 	ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5530 	jit_set_Z_PTR(jit, res_addr, ref);
5531 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5532 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5533 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5534 	return 1;
5535 }
5536 
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)5537 static int zend_jit_long_math_helper(zend_jit_ctx   *jit,
5538                                      const zend_op  *opline,
5539                                      uint8_t         opcode,
5540                                      uint8_t         op1_type,
5541                                      znode_op        op1,
5542                                      zend_jit_addr   op1_addr,
5543                                      uint32_t        op1_info,
5544                                      zend_ssa_range *op1_range,
5545                                      uint8_t         op2_type,
5546                                      znode_op        op2,
5547                                      zend_jit_addr   op2_addr,
5548                                      uint32_t        op2_info,
5549                                      zend_ssa_range *op2_range,
5550                                      uint32_t        res_var,
5551                                      zend_jit_addr   res_addr,
5552                                      uint32_t        res_info,
5553                                      uint32_t        res_use_info,
5554                                      int             may_throw)
5555 {
5556 	ir_ref ref = IR_UNUSED;
5557 	ir_ref if_long1 = IR_UNUSED;
5558 	ir_ref if_long2 = IR_UNUSED;
5559 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5560 	ir_refs *res_inputs;
5561 
5562 	ir_refs_init(res_inputs, 2);
5563 
5564 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5565 		if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5566 		ir_IF_TRUE(if_long1);
5567 	}
5568 	if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5569 		if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5570 		ir_IF_TRUE(if_long2);
5571 	}
5572 
5573 	if (opcode == ZEND_SL) {
5574 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5575 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5576 
5577 			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5578 				if (EXPECTED(op2_lval > 0)) {
5579 					ref = ir_CONST_LONG(0);
5580 				} else {
5581 					zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5582 					zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5583 					jit_SET_EX_OPLINE(jit, opline);
5584 					ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5585 					if (Z_MODE(res_addr) == IS_REG) {
5586 						ref = ir_CONST_LONG(0); // dead code
5587 					}
5588 				}
5589 			} else {
5590 				ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5591 			}
5592 		} else {
5593 			ref = jit_Z_LVAL(jit, op2_addr);
5594 			if (!op2_range ||
5595 			     op2_range->min < 0 ||
5596 			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5597 
5598 				ir_ref if_wrong, cold_path, ref2, if_ok;
5599 				ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5600 
5601 				if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5602 				ir_IF_TRUE_cold(if_wrong);
5603 				if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5604 				ir_IF_FALSE(if_ok);
5605 				jit_SET_EX_OPLINE(jit, opline);
5606 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5607 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5608 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5609 				ir_IF_TRUE(if_ok);
5610 				ref2 = ir_CONST_LONG(0);
5611 				cold_path = ir_END();
5612 				ir_IF_FALSE(if_wrong);
5613 				ref = ir_SHL_L(op1_ref, ref);
5614 				ir_MERGE_WITH(cold_path);
5615 				ref = ir_PHI_2(IR_LONG, ref, ref2);
5616 			} else {
5617 				ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5618 			}
5619 		}
5620 	} else if (opcode == ZEND_SR) {
5621 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5622 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5623 
5624 			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5625 				if (EXPECTED(op2_lval > 0)) {
5626 					ref = ir_SAR_L(
5627 						jit_Z_LVAL(jit, op1_addr),
5628 						ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5629 				} else {
5630 					zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5631 					zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5632 					jit_SET_EX_OPLINE(jit, opline);
5633 					ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5634 					if (Z_MODE(res_addr) == IS_REG) {
5635 						ref = ir_CONST_LONG(0); // dead code
5636 					}
5637 				}
5638 			} else {
5639 				ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5640 			}
5641 		} else {
5642 			ref = jit_Z_LVAL(jit, op2_addr);
5643 			if (!op2_range ||
5644 			     op2_range->min < 0 ||
5645 			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5646 
5647 				ir_ref if_wrong, cold_path, ref2, if_ok;
5648 
5649 				if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5650 				ir_IF_TRUE_cold(if_wrong);
5651 				if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5652 				ir_IF_FALSE(if_ok);
5653 				jit_SET_EX_OPLINE(jit, opline);
5654 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5655 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5656 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5657 				ir_IF_TRUE(if_ok);
5658 				ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5659 				cold_path = ir_END();
5660 				ir_IF_FALSE(if_wrong);
5661 				ir_MERGE_WITH(cold_path);
5662 				ref = ir_PHI_2(IR_LONG, ref, ref2);
5663 			}
5664 			ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5665 		}
5666 	} else if (opcode == ZEND_MOD) {
5667 		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5668 			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5669 
5670 			if (op2_lval == 0) {
5671 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5672 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5673 				jit_SET_EX_OPLINE(jit, opline);
5674 				ir_GUARD(IR_FALSE,	jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5675 				if (Z_MODE(res_addr) == IS_REG) {
5676 					ref = ir_CONST_LONG(0); // dead code
5677 				}
5678 			} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5679 				ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5680 			} else {
5681 				ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5682 			}
5683 		} else {
5684 			ir_ref zero_path = 0;
5685 			ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5686 
5687 			ref = jit_Z_LVAL(jit, op2_addr);
5688 			if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5689 				ir_ref if_ok = ir_IF(ref);
5690 				ir_IF_FALSE(if_ok);
5691 				jit_SET_EX_OPLINE(jit, opline);
5692 				zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5693 				zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5694 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5695 				ir_IF_TRUE(if_ok);
5696 			}
5697 
5698 			/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5699 			if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5700 				ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5701 				ir_IF_TRUE_cold(if_minus_one);
5702 				zero_path = ir_END();
5703 				ir_IF_FALSE(if_minus_one);
5704 			}
5705 			ref = ir_MOD_L(op1_ref, ref);
5706 
5707 			if (zero_path) {
5708 				ir_MERGE_WITH(zero_path);
5709 				ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5710 			}
5711 		}
5712 	} else {
5713 		ir_op op;
5714 		ir_ref op1, op2;
5715 
5716 		if (opcode == ZEND_BW_OR) {
5717 			op = IR_OR;
5718 		} else if (opcode == ZEND_BW_AND) {
5719 			op = IR_AND;
5720 		} else if (opcode == ZEND_BW_XOR) {
5721 			op = IR_XOR;
5722 		} else {
5723 			ZEND_UNREACHABLE();
5724 		}
5725 		op1 = jit_Z_LVAL(jit, op1_addr);
5726 		op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5727 		ref = ir_BINARY_OP_L(op, op1, op2);
5728 	}
5729 
5730 	if (ref) {
5731 		if (Z_MODE(res_addr) == IS_REG
5732 		 && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5733 		  || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5734 			jit->delay_var = Z_SSA_VAR(res_addr);
5735 			jit->delay_refs = res_inputs;
5736 		}
5737 		jit_set_Z_LVAL(jit, res_addr, ref);
5738 		if (Z_MODE(res_addr) != IS_REG) {
5739 			if (!zend_jit_same_addr(op1_addr, res_addr)) {
5740 				if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5741 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5742 				}
5743 			}
5744 		}
5745 	}
5746 
5747 	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5748 		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5749 		ir_ref fast_path = ir_END();
5750 		ir_ref func, arg1, arg2, arg3;
5751 
5752 		if (if_long2 && if_long1) {
5753 			ir_ref ref;
5754 			ir_IF_FALSE_cold(if_long2);
5755 			ref = ir_END();
5756 			ir_IF_FALSE_cold(if_long1);
5757 			ir_MERGE_2(ref, ir_END());
5758 		} else if (if_long1) {
5759 			ir_IF_FALSE_cold(if_long1);
5760 		} else if (if_long2) {
5761 			ir_IF_FALSE_cold(if_long2);
5762 		}
5763 
5764 		if (op1_info & MAY_BE_UNDEF) {
5765 			ir_ref if_def, ref, ref2;
5766 
5767 			ref = jit_ZVAL_ADDR(jit, op1_addr);
5768 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5769 			ir_IF_FALSE_cold(if_def);
5770 
5771 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5772 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5773 
5774 			ref2 = jit_EG(uninitialized_zval);
5775 			ir_MERGE_WITH_EMPTY_TRUE(if_def);
5776 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
5777 			op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5778 		}
5779 
5780 		if (op2_info & MAY_BE_UNDEF) {
5781 			ir_ref if_def, ref, ref2;
5782 
5783 			ref = jit_ZVAL_ADDR(jit, op2_addr);
5784 			if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5785 			ir_IF_FALSE_cold(if_def);
5786 
5787 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
5788 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
5789 
5790 			ref2 = jit_EG(uninitialized_zval);
5791 			ir_MERGE_WITH_EMPTY_TRUE(if_def);
5792 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
5793 			op2_addr = ZEND_ADDR_REF_ZVAL(ref);
5794 		}
5795 
5796 		if (Z_MODE(op1_addr) == IS_REG) {
5797 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5798 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5799 				return 0;
5800 			}
5801 			op1_addr = real_addr;
5802 		}
5803 		if (Z_MODE(op2_addr) == IS_REG) {
5804 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5805 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5806 				return 0;
5807 			}
5808 			op2_addr = real_addr;
5809 		}
5810 		if (Z_MODE(res_addr) == IS_REG) {
5811 			arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5812 		} else {
5813 			arg1 = jit_ZVAL_ADDR(jit, res_addr);
5814 		}
5815 		arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5816 		arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5817 		jit_SET_EX_OPLINE(jit, opline);
5818 		if (opcode == ZEND_BW_OR) {
5819 			func = ir_CONST_FC_FUNC(bitwise_or_function);
5820 		} else if (opcode == ZEND_BW_AND) {
5821 			func = ir_CONST_FC_FUNC(bitwise_and_function);
5822 		} else if (opcode == ZEND_BW_XOR) {
5823 			func = ir_CONST_FC_FUNC(bitwise_xor_function);
5824 		} else if (opcode == ZEND_SL) {
5825 			func = ir_CONST_FC_FUNC(shift_left_function);
5826 		} else if (opcode == ZEND_SR) {
5827 			func = ir_CONST_FC_FUNC(shift_right_function);
5828 		} else if (opcode == ZEND_MOD) {
5829 			func = ir_CONST_FC_FUNC(mod_function);
5830 		} else {
5831 			ZEND_UNREACHABLE();
5832 		}
5833 		ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5834 
5835 		if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5836 			/* compound assignment may decrement "op2" refcount */
5837 			op2_info |= MAY_BE_RC1;
5838 		}
5839 
5840 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5841 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5842 
5843 		if (may_throw) {
5844 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5845 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5846 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5847 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5848 				zend_jit_check_exception_undef_result(jit, opline);
5849 			} else {
5850 				zend_jit_check_exception(jit);
5851 			}
5852 		}
5853 
5854 		if (Z_MODE(res_addr) == IS_REG) {
5855 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5856 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5857 				return 0;
5858 			}
5859 		}
5860 
5861 		ir_MERGE_2(fast_path, ir_END());
5862 
5863 		if (Z_MODE(res_addr) == IS_REG) {
5864 			ZEND_ASSERT(jit->delay_refs == res_inputs);
5865 			ZEND_ASSERT(res_inputs->count == 2);
5866 			jit->delay_var = -1;
5867 			jit->delay_refs = NULL;
5868 			if (res_inputs->count == 1) {
5869 				zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5870 			} else {
5871 				ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
5872 				zend_jit_def_reg(jit, res_addr, phi);
5873 			}
5874 		}
5875 	}
5876 
5877 	return 1;
5878 }
5879 
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)5880 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)
5881 {
5882 	ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
5883 
5884 	if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
5885 			opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
5886 			opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
5887 			opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
5888 		return 0;
5889 	}
5890 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5891 		return 0;
5892 	}
5893 	return 1;
5894 }
5895 
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)5896 static int zend_jit_concat_helper(zend_jit_ctx   *jit,
5897                                   const zend_op  *opline,
5898                                   uint8_t         op1_type,
5899                                   znode_op        op1,
5900                                   zend_jit_addr   op1_addr,
5901                                   uint32_t        op1_info,
5902                                   uint8_t         op2_type,
5903                                   znode_op        op2,
5904                                   zend_jit_addr   op2_addr,
5905                                   uint32_t        op2_info,
5906                                   zend_jit_addr   res_addr,
5907                                   int             may_throw)
5908 {
5909 	ir_ref if_op1_string = IR_UNUSED;
5910 	ir_ref if_op2_string = IR_UNUSED;
5911 	ir_ref fast_path = IR_UNUSED;
5912 
5913 	if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5914 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5915 			if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
5916 			ir_IF_TRUE(if_op1_string);
5917 		}
5918 		if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5919 			if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
5920 			ir_IF_TRUE(if_op2_string);
5921 		}
5922 		if (zend_jit_same_addr(op1_addr, res_addr)) {
5923 			ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5924 			ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
5925 
5926 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
5927 			/* concatenation with itself may reduce refcount */
5928 			op2_info |= MAY_BE_RC1;
5929 		} else {
5930 			ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5931 			ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5932 			ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5933 
5934 			if (op1_type == IS_CV || op1_type == IS_CONST) {
5935 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
5936 			} else {
5937 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
5938 			}
5939 		}
5940 		/* concatenation with empty string may increase refcount */
5941 		op2_info |= MAY_BE_RCN;
5942 		jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
5943 		if (if_op1_string || if_op2_string) {
5944 			fast_path = ir_END();
5945 		}
5946 	}
5947 	if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
5948 	    (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
5949 		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5950 			if (if_op1_string && if_op2_string) {
5951 				ir_IF_FALSE(if_op1_string);
5952 				ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
5953 			} else if (if_op1_string) {
5954 				ir_IF_FALSE_cold(if_op1_string);
5955 			} else if (if_op2_string) {
5956 				ir_IF_FALSE_cold(if_op2_string);
5957 			}
5958 		}
5959 		ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5960 		ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5961 		ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5962 
5963 		jit_SET_EX_OPLINE(jit, opline);
5964 		ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(concat_function), arg1, arg2, arg3);
5965 		/* concatenation with empty string may increase refcount */
5966 		op1_info |= MAY_BE_RCN;
5967 		op2_info |= MAY_BE_RCN;
5968 		jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5969 		jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5970 		if (may_throw) {
5971 			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5972 				ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5973 					jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5974 			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5975 				zend_jit_check_exception_undef_result(jit, opline);
5976 			} else {
5977 				zend_jit_check_exception(jit);
5978 			}
5979 		}
5980 		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5981 			ir_MERGE_WITH(fast_path);
5982 		}
5983 	}
5984 	return 1;
5985 }
5986 
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)5987 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)
5988 {
5989 	zend_jit_addr op1_addr, op2_addr;
5990 
5991 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5992 	ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
5993 
5994 	op1_addr = OP1_ADDR();
5995 	op2_addr = OP2_ADDR();
5996 
5997 	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);
5998 }
5999 
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)6000 static int zend_jit_assign_op(zend_jit_ctx   *jit,
6001                               const zend_op  *opline,
6002                               uint32_t        op1_info,
6003                               zend_jit_addr   op1_addr,
6004                               zend_ssa_range *op1_range,
6005                               uint32_t        op1_def_info,
6006                               zend_jit_addr   op1_def_addr,
6007                               uint32_t        op1_mem_info,
6008                               uint32_t        op2_info,
6009                               zend_jit_addr   op2_addr,
6010                               zend_ssa_range *op2_range,
6011                               int             may_overflow,
6012                               int             may_throw)
6013 {
6014 	int result = 1;
6015 	ir_ref slow_path = IR_UNUSED;
6016 
6017 	ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6018 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6019 
6020 	if (op1_info & MAY_BE_REF) {
6021 		ir_ref ref, ref2, arg2, op1_noref_path;
6022 		ir_ref if_op1_ref = IR_UNUSED;
6023 		ir_ref if_op1_typed = IR_UNUSED;
6024 		binary_op_type binary_op = get_binary_op(opline->extended_value);
6025 
6026 		ref = jit_ZVAL_ADDR(jit, op1_addr);
6027 		if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6028 		ir_IF_FALSE(if_op1_ref);
6029 		op1_noref_path = ir_END();
6030 		ir_IF_TRUE(if_op1_ref);
6031 		ref2 = jit_Z_PTR_ref(jit, ref);
6032 
6033 		if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6034 		ir_IF_TRUE_cold(if_op1_typed);
6035 
6036 		if (Z_MODE(op2_addr) == IS_REG) {
6037 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6038 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6039 				return 0;
6040 			}
6041 			arg2 = jit_ZVAL_ADDR(jit, real_addr);
6042 		} else {
6043 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6044 		}
6045 		jit_SET_EX_OPLINE(jit, opline);
6046 		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6047 		 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6048 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6049 				ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6050 		} else {
6051 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6052 				ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6053 		}
6054 		zend_jit_check_exception(jit);
6055 		slow_path = ir_END();
6056 
6057 		ir_IF_FALSE(if_op1_typed);
6058 		ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6059 
6060 		ir_MERGE_WITH(op1_noref_path);
6061 		ref = ir_PHI_2(IR_ADDR, ref2, ref);
6062 		ZEND_ASSERT(op1_addr == op1_def_addr);
6063 		op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6064 	}
6065 
6066 	switch (opline->extended_value) {
6067 		case ZEND_ADD:
6068 		case ZEND_SUB:
6069 		case ZEND_MUL:
6070 		case ZEND_DIV:
6071 			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);
6072 			break;
6073 		case ZEND_BW_OR:
6074 		case ZEND_BW_AND:
6075 		case ZEND_BW_XOR:
6076 		case ZEND_SL:
6077 		case ZEND_SR:
6078 		case ZEND_MOD:
6079 			result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6080 				opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6081 				opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6082 				opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6083 			break;
6084 		case ZEND_CONCAT:
6085 			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);
6086 			break;
6087 		default:
6088 			ZEND_UNREACHABLE();
6089 	}
6090 
6091 	if (op1_info & MAY_BE_REF) {
6092 		ir_MERGE_WITH(slow_path);
6093 	}
6094 
6095 	return result;
6096 }
6097 
jit_ZVAL_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6098 static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6099 {
6100 	ir_ref if_ref, ref2;
6101 
6102 	if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6103 	ir_IF_TRUE(if_ref);
6104 	ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6105 	ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6106 	return ir_PHI_2(IR_ADDR, ref2, ref);
6107 }
6108 
jit_ZVAL_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6109 static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6110 {
6111 	ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6112 	ref = jit_ZVAL_DEREF_ref(jit, ref);
6113 	return ZEND_ADDR_REF_ZVAL(ref);
6114 }
6115 
jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6116 static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6117 {
6118 	ir_ref if_ref, ref2;
6119 
6120 	if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6121 	ir_IF_TRUE(if_ref);
6122 	ref2 = jit_Z_PTR_ref(jit, ref);
6123 	ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6124 	return ir_PHI_2(IR_ADDR, ref2, ref);
6125 }
6126 
jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6127 static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6128 {
6129 	ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6130 	ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6131 	return ZEND_ADDR_REF_ZVAL(ref);
6132 }
6133 
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)6134 static int zend_jit_simple_assign(zend_jit_ctx   *jit,
6135                                   const zend_op  *opline,
6136                                   zend_jit_addr   var_addr,
6137                                   uint32_t        var_info,
6138                                   uint32_t        var_def_info,
6139                                   uint8_t         val_type,
6140                                   zend_jit_addr   val_addr,
6141                                   uint32_t        val_info,
6142                                   zend_jit_addr   res_addr,
6143                                   bool            check_exception)
6144 {
6145 	ir_ref end_inputs = IR_UNUSED;
6146 
6147 	if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6148 		zval *zv = Z_ZV(val_addr);
6149 
6150 		if (!res_addr) {
6151 			jit_ZVAL_COPY_CONST(jit,
6152 				var_addr,
6153 				var_info, var_def_info,
6154 				zv, 1);
6155 		} else {
6156 			jit_ZVAL_COPY_CONST(jit,
6157 				var_addr,
6158 				var_info, var_def_info,
6159 				zv, 1);
6160 			jit_ZVAL_COPY_CONST(jit,
6161 				res_addr,
6162 				-1, var_def_info,
6163 				zv, 1);
6164 		}
6165 	} else {
6166 		if (val_info & MAY_BE_UNDEF) {
6167 			ir_ref if_def, ret;
6168 
6169 			if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6170 			ir_IF_FALSE_cold(if_def);
6171 
6172 			jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6173 			if (res_addr) {
6174 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6175 			}
6176 			jit_SET_EX_OPLINE(jit, opline);
6177 
6178 			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6179 			// zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6180 			ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6181 
6182 			if (check_exception) {
6183 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6184 			}
6185 
6186 			ir_END_list(end_inputs);
6187 			ir_IF_TRUE(if_def);
6188 		}
6189 		if (val_info & MAY_BE_REF) {
6190 			if (val_type == IS_CV) {
6191 				ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6192 				ref = jit_ZVAL_DEREF_ref(jit, ref);
6193 				val_addr = ZEND_ADDR_REF_ZVAL(ref);
6194 			} else {
6195 				ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6196 
6197 				ref = jit_ZVAL_ADDR(jit, val_addr);
6198 				type = jit_Z_TYPE_ref(jit, ref);
6199 				if_ref = ir_IF(ir_EQ(type, ir_CONST_U8(IS_REFERENCE)));
6200 
6201 				ir_IF_TRUE_cold(if_ref);
6202 				ref = jit_Z_PTR_ref(jit, ref);
6203 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
6204 				if (!res_addr) {
6205 					jit_ZVAL_COPY(jit,
6206 						var_addr,
6207 						var_info,
6208 						ZEND_ADDR_REF_ZVAL(ref2), val_info, 1);
6209 				} else {
6210 					jit_ZVAL_COPY_2(jit,
6211 						res_addr,
6212 						var_addr,
6213 						var_info,
6214 						ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6215 				}
6216 
6217 				refcount = jit_GC_DELREF(jit, ref);
6218 				if_not_zero = ir_IF(refcount);
6219 				ir_IF_FALSE(if_not_zero);
6220 				// TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6221 				// This is related to GH-10168 (keep this before GH-10168 is completely closed)
6222 				// jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6223 				jit_ZVAL_DTOR(jit, ref, val_info, opline);
6224 				ir_END_list(end_inputs);
6225 				ir_IF_TRUE(if_not_zero);
6226 				ir_END_list(end_inputs);
6227 
6228 				ir_IF_FALSE(if_ref);
6229 			}
6230 		}
6231 
6232 		if (!res_addr) {
6233 			jit_ZVAL_COPY(jit,
6234 				var_addr,
6235 				var_info,
6236 				val_addr, val_info, val_type == IS_CV);
6237 		} else {
6238 			jit_ZVAL_COPY_2(jit,
6239 				res_addr,
6240 				var_addr,
6241 				var_info,
6242 				val_addr, val_info, val_type == IS_CV ? 2 : 1);
6243 		}
6244 	}
6245 
6246 	if (end_inputs) {
6247 		ir_END_list(end_inputs);
6248 		ir_MERGE_list(end_inputs);
6249 	}
6250 
6251 	return 1;
6252 }
6253 
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)6254 static int zend_jit_assign_to_variable_call(zend_jit_ctx   *jit,
6255                                             const zend_op  *opline,
6256                                             zend_jit_addr   __var_use_addr,
6257                                             zend_jit_addr   var_addr,
6258                                             uint32_t        __var_info,
6259                                             uint32_t        __var_def_info,
6260                                             uint8_t         val_type,
6261                                             zend_jit_addr   val_addr,
6262                                             uint32_t        val_info,
6263                                             zend_jit_addr   __res_addr,
6264                                             bool       __check_exception)
6265 {
6266 	jit_stub_id func;
6267 	ir_ref undef_path = IR_UNUSED;
6268 
6269 	if (val_info & MAY_BE_UNDEF) {
6270 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6271 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6272 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6273 
6274 			if (!exit_addr) {
6275 				return 0;
6276 			}
6277 
6278 			jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6279 		} else {
6280 			ir_ref if_def;
6281 
6282 			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6283 			if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6284 			ir_IF_FALSE_cold(if_def);
6285 			jit_SET_EX_OPLINE(jit, opline);
6286 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6287 
6288 			ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6289 				jit_ZVAL_ADDR(jit, var_addr),
6290 				jit_EG(uninitialized_zval));
6291 
6292 			undef_path = ir_END();
6293 			ir_IF_TRUE(if_def);
6294 		}
6295 	}
6296 
6297 	if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6298 		func = jit_stub_assign_tmp;
6299 	} else if (val_type == IS_CONST) {
6300 		func = jit_stub_assign_const;
6301 	} else if (val_type == IS_TMP_VAR) {
6302 		func = jit_stub_assign_tmp;
6303 	} else if (val_type == IS_VAR) {
6304 		if (!(val_info & MAY_BE_REF)) {
6305 			func = jit_stub_assign_tmp;
6306 		} else {
6307 			func = jit_stub_assign_var;
6308 		}
6309 	} else if (val_type == IS_CV) {
6310 		if (!(val_info & MAY_BE_REF)) {
6311 			func = jit_stub_assign_cv_noref;
6312 		} else {
6313 			func = jit_stub_assign_cv;
6314 		}
6315 	} else {
6316 		ZEND_UNREACHABLE();
6317 	}
6318 
6319 	if (opline) {
6320 		jit_SET_EX_OPLINE(jit, opline);
6321 	}
6322 
6323 	ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6324 		jit_ZVAL_ADDR(jit, var_addr),
6325 		jit_ZVAL_ADDR(jit, val_addr));
6326 
6327 	if (undef_path) {
6328 		ir_MERGE_WITH(undef_path);
6329 	}
6330 
6331 	return 1;
6332 }
6333 
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)6334 static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
6335                                        const zend_op  *opline,
6336                                        zend_jit_addr   var_use_addr,
6337                                        zend_jit_addr   var_addr,
6338                                        uint32_t        var_info,
6339                                        uint32_t        var_def_info,
6340                                        uint8_t         val_type,
6341                                        zend_jit_addr   val_addr,
6342                                        uint32_t        val_info,
6343                                        zend_jit_addr   res_addr,
6344                                        zend_jit_addr   ref_addr,
6345                                        bool       check_exception)
6346 {
6347 	ir_ref if_refcounted = IR_UNUSED;
6348 	ir_ref simple_inputs = IR_UNUSED;
6349 	bool done = 0;
6350 	zend_jit_addr real_res_addr = 0;
6351 	ir_refs *end_inputs;
6352 	ir_refs *res_inputs;
6353 
6354 	ir_refs_init(end_inputs, 6);
6355 	ir_refs_init(res_inputs, 6);
6356 
6357 	if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6358 		/* Force load */
6359 		zend_jit_use_reg(jit, val_addr);
6360 	}
6361 
6362 	if (Z_MODE(var_addr) == IS_REG) {
6363 		jit->delay_var = Z_SSA_VAR(var_addr);
6364 		jit->delay_refs = res_inputs;
6365 		if (Z_MODE(res_addr) == IS_REG) {
6366 			real_res_addr = res_addr;
6367 			res_addr = 0;
6368 		}
6369 	} else if (Z_MODE(res_addr) == IS_REG) {
6370 		jit->delay_var = Z_SSA_VAR(res_addr);
6371 		jit->delay_refs = res_inputs;
6372 	}
6373 
6374 	if ((var_info & MAY_BE_REF) || ref_addr) {
6375 		ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6376 		uintptr_t func;
6377 
6378 		if (!ref_addr) {
6379 			ref = jit_ZVAL_ADDR(jit, var_use_addr);
6380 			if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6381 			ir_IF_TRUE(if_ref);
6382 			ref2 = jit_Z_PTR_ref(jit, ref);
6383 		} else {
6384 			ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6385 		}
6386 		if_typed = jit_if_TYPED_REF(jit, ref2);
6387 		ir_IF_TRUE_cold(if_typed);
6388 		jit_SET_EX_OPLINE(jit, opline);
6389 		if (Z_MODE(val_addr) == IS_REG) {
6390 			zend_jit_addr real_addr;
6391 
6392 			if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6393 				real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6394 			} else {
6395 				ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6396 				real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6397 			}
6398 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6399 				return 0;
6400 			}
6401 			arg2 = jit_ZVAL_ADDR(jit, real_addr);
6402 		} else {
6403 			arg2 = jit_ZVAL_ADDR(jit, val_addr);
6404 		}
6405 		if (!res_addr) {
6406 			if (val_type == IS_CONST) {
6407 				func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6408 			} else if (val_type == IS_TMP_VAR) {
6409 				func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6410 			} else if (val_type == IS_VAR) {
6411 				func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6412 			} else if (val_type == IS_CV) {
6413 				func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6414 			} else {
6415 				ZEND_UNREACHABLE();
6416 			}
6417 			ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6418 		} else {
6419 			if (val_type == IS_CONST) {
6420 				func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6421 			} else if (val_type == IS_TMP_VAR) {
6422 				func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6423 			} else if (val_type == IS_VAR) {
6424 				func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6425 			} else if (val_type == IS_CV) {
6426 				func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6427 			} else {
6428 				ZEND_UNREACHABLE();
6429 			}
6430 			ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6431 		}
6432 		if (check_exception) {
6433 			zend_jit_check_exception(jit);
6434 		}
6435 		ir_refs_add(end_inputs, ir_END());
6436 
6437 		if (!ref_addr) {
6438 			ir_IF_FALSE(if_ref);
6439 			non_ref_path = ir_END();
6440 			ir_IF_FALSE(if_typed);
6441 			ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6442 			ir_MERGE_WITH(non_ref_path);
6443 			ref = ir_PHI_2(IR_ADDR, ref2, ref);
6444 			var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6445 		} else {
6446 			ir_IF_FALSE(if_typed);
6447 		}
6448 	}
6449 
6450 	if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6451 		ir_ref ref, counter, if_not_zero;
6452 
6453 		if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6454 			if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6455 			ir_IF_FALSE(if_refcounted);
6456 			ir_END_list(simple_inputs);
6457 			ir_IF_TRUE_cold(if_refcounted);
6458 		} else if (RC_MAY_BE_1(var_info)) {
6459 			done = 1;
6460 		}
6461 		ref = jit_Z_PTR(jit, var_use_addr);
6462 		if (RC_MAY_BE_1(var_info)) {
6463 			if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0)) {
6464 				return 0;
6465 			}
6466 			counter = jit_GC_DELREF(jit, ref);
6467 
6468 			if_not_zero = ir_IF(counter);
6469 			ir_IF_FALSE(if_not_zero);
6470 			jit_ZVAL_DTOR(jit, ref, var_info, opline);
6471 			if (check_exception) {
6472 				zend_jit_check_exception(jit);
6473 			}
6474 			ir_refs_add(end_inputs, ir_END());
6475 			ir_IF_TRUE(if_not_zero);
6476 			if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6477 				ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6478 				ir_IF_FALSE(if_may_leak);
6479 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6480 
6481 				if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6482 					ZEND_ASSERT(jit->delay_refs == res_inputs);
6483 					ZEND_ASSERT(res_inputs->count > 0);
6484 					ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6485 				}
6486 				if (check_exception && (val_info & MAY_BE_UNDEF)) {
6487 					zend_jit_check_exception(jit);
6488 				}
6489 				ir_refs_add(end_inputs, ir_END());
6490 				ir_IF_TRUE(if_may_leak);
6491 			}
6492 			if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6493 				ZEND_ASSERT(jit->delay_refs == res_inputs);
6494 				ZEND_ASSERT(res_inputs->count > 0);
6495 				ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6496 			}
6497 			if (check_exception && (val_info & MAY_BE_UNDEF)) {
6498 				zend_jit_check_exception(jit);
6499 			}
6500 			ir_refs_add(end_inputs, ir_END());
6501 		} else /* if (RC_MAY_BE_N(var_info)) */ {
6502 			jit_GC_DELREF(jit, ref);
6503 			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6504 				ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6505 				ir_IF_FALSE(if_may_leak);
6506 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6507 				ir_END_list(simple_inputs);
6508 				ir_IF_TRUE(if_may_leak);
6509 			}
6510 			ir_END_list(simple_inputs);
6511 		}
6512 	}
6513 
6514 	if (simple_inputs) {
6515 		ir_MERGE_list(simple_inputs);
6516 	}
6517 
6518 	if (!done) {
6519 		if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6520 			return 0;
6521 		}
6522 		if (end_inputs->count) {
6523 			ir_refs_add(end_inputs, ir_END());
6524 		}
6525 	}
6526 
6527 	if (end_inputs->count) {
6528 		ir_MERGE_N(end_inputs->count, end_inputs->refs);
6529 	}
6530 
6531 	if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6532 		ir_ref phi;
6533 
6534 		ZEND_ASSERT(jit->delay_refs == res_inputs);
6535 		ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6536 		jit->delay_var = -1;
6537 		jit->delay_refs = NULL;
6538 		if (res_inputs->count == 1) {
6539 			phi = res_inputs->refs[0];
6540 		} else {
6541 			phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6542 				res_inputs->count, res_inputs->refs);
6543 		}
6544 		if (Z_MODE(var_addr) == IS_REG) {
6545 			if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6546 				phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6547 			}
6548 			zend_jit_def_reg(jit, var_addr, phi);
6549 			if (real_res_addr) {
6550 				if (var_def_info & MAY_BE_LONG) {
6551 					jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6552 				} else {
6553 					jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6554 				}
6555 			}
6556 		} else {
6557 			zend_jit_def_reg(jit, res_addr, phi);
6558 		}
6559 	}
6560 
6561 	return 1;
6562 }
6563 
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)6564 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)
6565 {
6566 	if (op1_addr != op1_def_addr) {
6567 		if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6568 			return 0;
6569 		}
6570 		if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6571 			op1_addr = op1_def_addr;
6572 		}
6573 	}
6574 
6575 	if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 1)) {
6576 		return 0;
6577 	}
6578 	if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6579 		return 0;
6580 	}
6581 	return 1;
6582 }
6583 
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)6584 static int zend_jit_assign(zend_jit_ctx  *jit,
6585                            const zend_op *opline,
6586                            uint32_t       op1_info,
6587                            zend_jit_addr  op1_use_addr,
6588                            uint32_t       op1_def_info,
6589                            zend_jit_addr  op1_addr,
6590                            uint32_t       op2_info,
6591                            zend_jit_addr  op2_addr,
6592                            zend_jit_addr  op2_def_addr,
6593                            uint32_t       res_info,
6594                            zend_jit_addr  res_addr,
6595                            zend_jit_addr  ref_addr,
6596                            int            may_throw)
6597 {
6598 	ZEND_ASSERT(opline->op1_type == IS_CV);
6599 
6600 	if (op2_addr != op2_def_addr) {
6601 		if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6602 			return 0;
6603 		}
6604 		if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6605 			op2_addr = op2_def_addr;
6606 		}
6607 	}
6608 
6609 	if (Z_MODE(op1_addr) != IS_REG
6610 	 && Z_MODE(op1_use_addr) == IS_REG
6611 	 && !Z_LOAD(op1_use_addr)
6612 	 && !Z_STORE(op1_use_addr)) {
6613 		/* Force type update */
6614 		op1_info |= MAY_BE_UNDEF;
6615 	}
6616 	if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6617 			opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6618 		return 0;
6619 	}
6620 	if (Z_MODE(op1_addr) == IS_REG) {
6621 		if (Z_STORE(op1_addr)) {
6622 			if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6623 				return 0;
6624 			}
6625 		} else if ((op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
6626 			&& Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6627 			&& Z_REG(op1_use_addr) == ZREG_FP
6628 			&& EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6629 			/* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6630 			if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6631 				jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6632 				if (JIT_G(current_frame)) {
6633 					SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6634 				}
6635 			} else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6636 				jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6637 				if (JIT_G(current_frame)) {
6638 					SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6639 				}
6640 			} else {
6641 				ZEND_UNREACHABLE();
6642 			}
6643 		}
6644 	}
6645 	if (opline->result_type != IS_UNUSED) {
6646 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6647 			return 0;
6648 		}
6649 	}
6650 
6651 	return 1;
6652 }
6653 
zend_jit_cmp_op(const zend_op * opline)6654 static ir_op zend_jit_cmp_op(const zend_op *opline)
6655 {
6656 	ir_op op;
6657 
6658 	switch (opline->opcode) {
6659 		case ZEND_IS_EQUAL:
6660 		case ZEND_IS_IDENTICAL:
6661 		case ZEND_CASE:
6662 		case ZEND_CASE_STRICT:
6663 			op = IR_EQ;
6664 			break;
6665 		case ZEND_IS_NOT_EQUAL:
6666 		case ZEND_IS_NOT_IDENTICAL:
6667 			op = IR_NE;
6668 			break;
6669 		case ZEND_IS_SMALLER:
6670 			op = IR_LT;
6671 			break;
6672 		case ZEND_IS_SMALLER_OR_EQUAL:
6673 			op = IR_LE;
6674 			break;
6675 		default:
6676 			ZEND_UNREACHABLE();
6677 	}
6678 	return op;
6679 }
6680 
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)6681 static ir_ref zend_jit_cmp_long_long(zend_jit_ctx   *jit,
6682                                      const zend_op  *opline,
6683                                      zend_ssa_range *op1_range,
6684                                      zend_jit_addr   op1_addr,
6685                                      zend_ssa_range *op2_range,
6686                                      zend_jit_addr   op2_addr,
6687                                      zend_jit_addr   res_addr,
6688                                      uint8_t         smart_branch_opcode,
6689                                      uint32_t        target_label,
6690                                      uint32_t        target_label2,
6691                                      const void     *exit_addr,
6692                                      bool       skip_comparison)
6693 {
6694 	ir_ref ref;
6695 	bool result;
6696 
6697 	if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6698 		if (!smart_branch_opcode ||
6699 		    smart_branch_opcode == ZEND_JMPZ_EX ||
6700 		    smart_branch_opcode == ZEND_JMPNZ_EX) {
6701 			jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6702 		}
6703 		if (smart_branch_opcode && !exit_addr) {
6704 			if (smart_branch_opcode == ZEND_JMPZ ||
6705 			    smart_branch_opcode == ZEND_JMPZ_EX) {
6706 				return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6707 			} else if (smart_branch_opcode == ZEND_JMPNZ ||
6708 			           smart_branch_opcode == ZEND_JMPNZ_EX) {
6709 				return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6710 			} else {
6711 				ZEND_UNREACHABLE();
6712 			}
6713 		}
6714 		if (opline->opcode != ZEND_IS_IDENTICAL
6715 		 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6716 		 && opline->opcode != ZEND_CASE_STRICT) {
6717 			return ir_END();
6718 		} else {
6719 			return IR_NULL; /* success */
6720 		}
6721 	}
6722 
6723 	ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6724 
6725 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6726 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6727 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6728 	}
6729 	if (exit_addr) {
6730 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6731 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6732 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6733 			} else {
6734 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6735 			}
6736 		} else {
6737 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6738 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6739 			} else {
6740 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6741 			}
6742 		}
6743 	} else if (smart_branch_opcode) {
6744 		return jit_IF_ex(jit, ref,
6745 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6746 	}
6747 
6748 	if (opline->opcode != ZEND_IS_IDENTICAL
6749 	 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6750 	 && opline->opcode != ZEND_CASE_STRICT) {
6751 		return ir_END();
6752 	} else {
6753 		return IR_NULL; /* success */
6754 	}
6755 }
6756 
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)6757 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)
6758 {
6759 	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));
6760 
6761 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6762 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6763 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6764 	}
6765 	if (exit_addr) {
6766 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6767 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6768 		} else {
6769 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6770 		}
6771 	} else if (smart_branch_opcode) {
6772 		return jit_IF_ex(jit, ref,
6773 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6774 	}
6775 	return ir_END();
6776 }
6777 
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)6778 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)
6779 {
6780 	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)));
6781 
6782 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6783 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6784 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6785 	}
6786 	if (exit_addr) {
6787 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6788 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6789 		} else {
6790 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6791 		}
6792 	} else if (smart_branch_opcode) {
6793 		return jit_IF_ex(jit, ref,
6794 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6795 	}
6796 	return ir_END();
6797 }
6798 
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)6799 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)
6800 {
6801 	ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
6802 
6803 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6804 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6805 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6806 	}
6807 	if (exit_addr) {
6808 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6809 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6810 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6811 			} else {
6812 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6813 			}
6814 		} else {
6815 			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6816 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6817 			} else {
6818 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6819 			}
6820 		}
6821 	} else if (smart_branch_opcode) {
6822 		return jit_IF_ex(jit, ref,
6823 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6824 	}
6825 	if (opline->opcode != ZEND_IS_IDENTICAL
6826 	 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6827 	 && opline->opcode != ZEND_CASE_STRICT) {
6828 		return ir_END();
6829 	} else {
6830 		return IR_NULL; /* success */
6831 	}
6832 }
6833 
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)6834 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)
6835 {
6836 	ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
6837 
6838 	if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6839 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6840 			ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6841 	}
6842 	if (exit_addr) {
6843 		if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6844 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6845 		} else {
6846 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6847 		}
6848 	} else if (smart_branch_opcode) {
6849 		return jit_IF_ex(jit, ref,
6850 			(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6851 	}
6852 
6853 	return ir_END();
6854 }
6855 
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)6856 static int zend_jit_cmp(zend_jit_ctx   *jit,
6857                         const zend_op  *opline,
6858                         uint32_t        op1_info,
6859                         zend_ssa_range *op1_range,
6860                         zend_jit_addr   op1_addr,
6861                         uint32_t        op2_info,
6862                         zend_ssa_range *op2_range,
6863                         zend_jit_addr   op2_addr,
6864                         zend_jit_addr   res_addr,
6865                         int             may_throw,
6866                         uint8_t         smart_branch_opcode,
6867                         uint32_t        target_label,
6868                         uint32_t        target_label2,
6869                         const void     *exit_addr,
6870                         bool       skip_comparison)
6871 {
6872 	ir_ref ref = IR_UNUSED;
6873 	ir_ref if_op1_long = IR_UNUSED;
6874 	ir_ref if_op1_double = IR_UNUSED;
6875 	ir_ref if_op2_double = IR_UNUSED;
6876 	ir_ref if_op1_long_op2_long = IR_UNUSED;
6877 	ir_ref if_op1_long_op2_double = IR_UNUSED;
6878 	ir_ref if_op1_double_op2_double = IR_UNUSED;
6879 	ir_ref if_op1_double_op2_long = IR_UNUSED;
6880 	ir_ref slow_inputs = IR_UNUSED;
6881 	bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
6882 	bool has_slow =
6883 		(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6884 		(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6885 		((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
6886 		 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
6887 	ir_refs *end_inputs;
6888 
6889 	ir_refs_init(end_inputs, 8);
6890 
6891 	if (Z_MODE(op1_addr) == IS_REG) {
6892 		if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
6893 			/* Force load */
6894 			zend_jit_use_reg(jit, op1_addr);
6895 		}
6896 	} else if (Z_MODE(op2_addr) == IS_REG) {
6897 		if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
6898 			/* Force load */
6899 			zend_jit_use_reg(jit, op2_addr);
6900 		}
6901 	}
6902 
6903 	if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
6904 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
6905 			if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
6906 			ir_IF_TRUE(if_op1_long);
6907 		}
6908 		if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
6909 			if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
6910 			ir_IF_FALSE_cold(if_op1_long_op2_long);
6911 			if (op2_info & MAY_BE_DOUBLE) {
6912 				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6913 					if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6914 					ir_IF_FALSE_cold(if_op1_long_op2_double);
6915 					ir_END_list(slow_inputs);
6916 					ir_IF_TRUE(if_op1_long_op2_double);
6917 				}
6918 				ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6919 				if (!ref) {
6920 					return 0;
6921 				}
6922 				ir_refs_add(end_inputs, ref);
6923 			} else {
6924 				ir_END_list(slow_inputs);
6925 			}
6926 			ir_IF_TRUE(if_op1_long_op2_long);
6927 		}
6928 		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);
6929 		if (!ref) {
6930 			return 0;
6931 		}
6932 		ir_refs_add(end_inputs, ref);
6933 
6934 		if (if_op1_long) {
6935 			ir_IF_FALSE_cold(if_op1_long);
6936 		}
6937 		if (op1_info & MAY_BE_DOUBLE) {
6938 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6939 				if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
6940 				ir_IF_FALSE_cold(if_op1_double);
6941 				ir_END_list(slow_inputs);
6942 				ir_IF_TRUE(if_op1_double);
6943 			}
6944 			if (op2_info & MAY_BE_DOUBLE) {
6945 				if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
6946 					if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6947 					ir_IF_TRUE(if_op1_double_op2_double);
6948 				}
6949 				ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6950 				if (!ref) {
6951 					return 0;
6952 				}
6953 				ir_refs_add(end_inputs, ref);
6954 				if (if_op1_double_op2_double) {
6955 					ir_IF_FALSE_cold(if_op1_double_op2_double);
6956 				}
6957 			}
6958 			if (!same_ops) {
6959 				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6960 					if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
6961 					ir_IF_FALSE_cold(if_op1_double_op2_long);
6962 					ir_END_list(slow_inputs);
6963 					ir_IF_TRUE(if_op1_double_op2_long);
6964 				}
6965 				ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6966 				if (!ref) {
6967 					return 0;
6968 				}
6969 				ir_refs_add(end_inputs, ref);
6970 			} else if (if_op1_double_op2_double) {
6971 				ir_END_list(slow_inputs);
6972 			}
6973 		} else if (if_op1_long) {
6974 			ir_END_list(slow_inputs);
6975 		}
6976 	} else if ((op1_info & MAY_BE_DOUBLE) &&
6977 	           !(op1_info & MAY_BE_LONG) &&
6978 	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
6979 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
6980 			if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
6981 			ir_IF_FALSE_cold(if_op1_double);
6982 			ir_END_list(slow_inputs);
6983 			ir_IF_TRUE(if_op1_double);
6984 		}
6985 		if (op2_info & MAY_BE_DOUBLE) {
6986 			if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
6987 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6988 				ir_IF_TRUE(if_op1_double_op2_double);
6989 			}
6990 			ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6991 			if (!ref) {
6992 				return 0;
6993 			}
6994 			ir_refs_add(end_inputs, ref);
6995 			if (if_op1_double_op2_double) {
6996 				ir_IF_FALSE_cold(if_op1_double_op2_double);
6997 			}
6998 		}
6999 		if (!same_ops && (op2_info & MAY_BE_LONG)) {
7000 			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7001 				if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7002 				ir_IF_FALSE_cold(if_op1_double_op2_long);
7003 				ir_END_list(slow_inputs);
7004 				ir_IF_TRUE(if_op1_double_op2_long);
7005 			}
7006 			ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7007 			if (!ref) {
7008 				return 0;
7009 			}
7010 			ir_refs_add(end_inputs, ref);
7011 		} else if (if_op1_double_op2_double) {
7012 			ir_END_list(slow_inputs);
7013 		}
7014 	} else if ((op2_info & MAY_BE_DOUBLE) &&
7015 	           !(op2_info & MAY_BE_LONG) &&
7016 	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7017 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7018 			if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7019 			ir_IF_FALSE_cold(if_op2_double);
7020 			ir_END_list(slow_inputs);
7021 			ir_IF_TRUE(if_op2_double);
7022 		}
7023 		if (op1_info & MAY_BE_DOUBLE) {
7024 			if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7025 				if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_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 && (op1_info & MAY_BE_LONG)) {
7038 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7039 				if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7040 				ir_IF_FALSE_cold(if_op1_long_op2_double);
7041 				ir_END_list(slow_inputs);
7042 				ir_IF_TRUE(if_op1_long_op2_double);
7043 			}
7044 			ref = zend_jit_cmp_long_double(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 	}
7053 
7054 	if (has_slow ||
7055 	    (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7056 	    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7057 	    ir_ref op1, op2, ref;
7058 
7059 		if (slow_inputs) {
7060 			ir_MERGE_list(slow_inputs);
7061 		}
7062 		jit_SET_EX_OPLINE(jit, opline);
7063 
7064 		if (Z_MODE(op1_addr) == IS_REG) {
7065 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7066 			if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7067 				return 0;
7068 			}
7069 			op1_addr = real_addr;
7070 		}
7071 		if (Z_MODE(op2_addr) == IS_REG) {
7072 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7073 			if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7074 				return 0;
7075 			}
7076 			op2_addr = real_addr;
7077 		}
7078 
7079 		op1 = jit_ZVAL_ADDR(jit, op1_addr);
7080 		if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7081 			op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, 0);
7082 		}
7083 		op2 = jit_ZVAL_ADDR(jit, op2_addr);
7084 		if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7085 			op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, 0);
7086 		}
7087 		ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7088 		if (opline->opcode != ZEND_CASE) {
7089 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7090 		}
7091 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7092 		if (may_throw) {
7093 			zend_jit_check_exception_undef_result(jit, opline);
7094 		}
7095 
7096 		ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7097 		if (!ref) {
7098 			return 0;
7099 		}
7100 		ir_refs_add(end_inputs, ref);
7101 	}
7102 
7103 	if (end_inputs->count) {
7104 		uint32_t n = end_inputs->count;
7105 
7106 		if (smart_branch_opcode && !exit_addr) {
7107 			zend_basic_block *bb;
7108 			ir_ref ref;
7109 			uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7110 				target_label2 : target_label;
7111 			uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7112 				target_label : target_label2;
7113 
7114 			ZEND_ASSERT(jit->b >= 0);
7115 			bb = &jit->ssa->cfg.blocks[jit->b];
7116 			ZEND_ASSERT(bb->successors_count == 2);
7117 
7118 			if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7119 				ir_ref merge_inputs = IR_UNUSED;
7120 
7121 				while (n) {
7122 					n--;
7123 					ir_IF_TRUE(end_inputs->refs[n]);
7124 					ir_END_list(merge_inputs);
7125 					ir_IF_FALSE(end_inputs->refs[n]);
7126 					ir_END_list(merge_inputs);
7127 				}
7128 				ir_MERGE_list(merge_inputs);
7129 				_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7130 			} else if (n == 1) {
7131 				ref = end_inputs->refs[0];
7132 				_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7133 				_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7134 			} else {
7135 				ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7136 
7137 				while (n) {
7138 					n--;
7139 					ir_IF_TRUE(end_inputs->refs[n]);
7140 					ir_END_list(true_inputs);
7141 					ir_IF_FALSE(end_inputs->refs[n]);
7142 					ir_END_list(false_inputs);
7143 				}
7144 				ir_MERGE_list(true_inputs);
7145 				_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7146 				ir_MERGE_list(false_inputs);
7147 				_zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7148 			}
7149 			jit->b = -1;
7150 		} else {
7151 			ir_MERGE_N(n, end_inputs->refs);
7152 		}
7153 	} else if (smart_branch_opcode && !exit_addr) {
7154 		/* dead code */
7155 		_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7156 		jit->b = -1;
7157 	}
7158 
7159 	return 1;
7160 }
7161 
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)7162 static int zend_jit_identical(zend_jit_ctx   *jit,
7163                               const zend_op  *opline,
7164                               uint32_t        op1_info,
7165                               zend_ssa_range *op1_range,
7166                               zend_jit_addr   op1_addr,
7167                               uint32_t        op2_info,
7168                               zend_ssa_range *op2_range,
7169                               zend_jit_addr   op2_addr,
7170                               zend_jit_addr   res_addr,
7171                               int             may_throw,
7172                               uint8_t         smart_branch_opcode,
7173                               uint32_t        target_label,
7174                               uint32_t        target_label2,
7175                               const void     *exit_addr,
7176                               bool       skip_comparison)
7177 {
7178 	bool always_false = 0, always_true = 0;
7179 	ir_ref ref = IR_UNUSED;
7180 
7181 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7182 		ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7183 		op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, 0);
7184 		op1_info |= MAY_BE_NULL;
7185 		op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7186 	}
7187 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7188 		ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7189 		op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, 0);
7190 		op2_info |= MAY_BE_NULL;
7191 		op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7192 	}
7193 
7194 	if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7195 		always_false = 1;
7196 	} else if (has_concrete_type(op1_info)
7197 	 && has_concrete_type(op2_info)
7198 	 && concrete_type(op1_info) == concrete_type(op2_info)
7199 	 && concrete_type(op1_info) <= IS_TRUE) {
7200 		always_true = 1;
7201 	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7202 		if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7203 			always_true = 1;
7204 		} else {
7205 			always_false = 1;
7206 		}
7207 	}
7208 
7209 	if (always_true) {
7210 		if (opline->opcode != ZEND_CASE_STRICT) {
7211 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7212 		}
7213 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7214 		if (!smart_branch_opcode
7215 		 || smart_branch_opcode == ZEND_JMPZ_EX
7216 		 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7217 			jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7218 		}
7219 		if (may_throw) {
7220 			zend_jit_check_exception(jit);
7221 		}
7222 		if (exit_addr) {
7223 			if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7224 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7225 			}
7226 		} else if (smart_branch_opcode) {
7227 			uint32_t label;
7228 
7229 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7230 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7231 					target_label : target_label2;
7232 			} else {
7233 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7234 					target_label2 : target_label;
7235 			}
7236 			_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7237 			jit->b = -1;
7238 		}
7239 		return 1;
7240 	} else if (always_false) {
7241 		if (opline->opcode != ZEND_CASE_STRICT) {
7242 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7243 		}
7244 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7245 		if (!smart_branch_opcode
7246 		 || smart_branch_opcode == ZEND_JMPZ_EX
7247 		 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7248 			jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7249 		}
7250 		if (may_throw) {
7251 			zend_jit_check_exception(jit);
7252 		}
7253 		if (exit_addr) {
7254 			if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7255 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7256 			}
7257 		} else if (smart_branch_opcode) {
7258 			uint32_t label;
7259 
7260 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7261 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7262 					target_label2 : target_label;
7263 			} else {
7264 				label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7265 					target_label : target_label2;
7266 			}
7267 			_zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7268 			jit->b = -1;
7269 		}
7270 		return 1;
7271 	}
7272 
7273 	if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7274 		ref = jit_ZVAL_ADDR(jit, op1_addr);
7275 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7276 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7277 	}
7278 	if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7279 		ref = jit_ZVAL_ADDR(jit, op2_addr);
7280 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7281 		op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7282 	}
7283 
7284 	if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7285 	    (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7286 		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);
7287 		if (!ref) {
7288 			return 0;
7289 		}
7290 	} else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7291 	           (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7292 		ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7293 		if (!ref) {
7294 			return 0;
7295 		}
7296 	} else {
7297 		if (opline->op1_type != IS_CONST) {
7298 			if (Z_MODE(op1_addr) == IS_REG) {
7299 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7300 				if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7301 					return 0;
7302 				}
7303 				op1_addr = real_addr;
7304 			}
7305 		}
7306 		if (opline->op2_type != IS_CONST) {
7307 			if (Z_MODE(op2_addr) == IS_REG) {
7308 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7309 				if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7310 					return 0;
7311 				}
7312 			}
7313 		}
7314 
7315 		if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7316 			zval *val = Z_ZV(op1_addr);
7317 
7318 			ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7319 		} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7320 			zval *val = Z_ZV(op2_addr);
7321 
7322 			ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7323 		} else {
7324 			if (Z_MODE(op1_addr) == IS_REG) {
7325 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7326 				if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7327 					return 0;
7328 				}
7329 				op1_addr = real_addr;
7330 			}
7331 			if (Z_MODE(op2_addr) == IS_REG) {
7332 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7333 				if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7334 					return 0;
7335 				}
7336 				op2_addr = real_addr;
7337 			}
7338 
7339 			ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_is_identical),
7340 				jit_ZVAL_ADDR(jit, op1_addr),
7341 				jit_ZVAL_ADDR(jit, op2_addr));
7342 		}
7343 
7344 		if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7345 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7346 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7347 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7348 			} else {
7349 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7350 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7351 			}
7352 		}
7353 		if (opline->opcode != ZEND_CASE_STRICT) {
7354 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7355 		}
7356 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7357 		if (may_throw) {
7358 			zend_jit_check_exception_undef_result(jit, opline);
7359 		}
7360 		if (exit_addr) {
7361 			if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7362 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7363 			} else {
7364 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7365 			}
7366 		} else if (smart_branch_opcode) {
7367 			if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7368 				/* swap labels */
7369 				uint32_t tmp = target_label;
7370 				target_label = target_label2;
7371 				target_label2 = tmp;
7372 			}
7373 			ref = jit_IF_ex(jit, ref,
7374 				(smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7375 		}
7376 	}
7377 
7378 	if (smart_branch_opcode && !exit_addr) {
7379 		zend_basic_block *bb;
7380 
7381 		ZEND_ASSERT(jit->b >= 0);
7382 		bb = &jit->ssa->cfg.blocks[jit->b];
7383 		ZEND_ASSERT(bb->successors_count == 2);
7384 
7385 		if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7386 			ir_IF_TRUE(ref);
7387 			ir_MERGE_WITH_EMPTY_FALSE(ref);
7388 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7389 		} else {
7390 			ZEND_ASSERT(bb->successors_count == 2);
7391 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7392 			_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7393 		}
7394 		jit->b = -1;
7395 	}
7396 
7397 	return 1;
7398 }
7399 
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)7400 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)
7401 {
7402 	uint32_t true_label = -1;
7403 	uint32_t false_label = -1;
7404 	bool set_bool = 0;
7405 	bool set_bool_not = 0;
7406 	bool always_true = 0, always_false = 0;
7407 	ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7408 	ir_type type = IR_UNUSED;
7409 
7410 	if (branch_opcode == ZEND_BOOL) {
7411 		set_bool = 1;
7412 	} else if (branch_opcode == ZEND_BOOL_NOT) {
7413 		set_bool = 1;
7414 		set_bool_not = 1;
7415 	} else if (branch_opcode == ZEND_JMPZ) {
7416 		true_label = target_label2;
7417 		false_label = target_label;
7418 	} else if (branch_opcode == ZEND_JMPNZ) {
7419 		true_label = target_label;
7420 		false_label = target_label2;
7421 	} else if (branch_opcode == ZEND_JMPZ_EX) {
7422 		set_bool = 1;
7423 		true_label = target_label2;
7424 		false_label = target_label;
7425 	} else if (branch_opcode == ZEND_JMPNZ_EX) {
7426 		set_bool = 1;
7427 		true_label = target_label;
7428 		false_label = target_label2;
7429 	} else {
7430 		ZEND_UNREACHABLE();
7431 	}
7432 
7433 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7434 		ref = jit_ZVAL_ADDR(jit, op1_addr);
7435 		ref = jit_ZVAL_DEREF_ref(jit, ref);
7436 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7437 	}
7438 
7439 	if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
7440 		if (zend_is_true(Z_ZV(op1_addr))) {
7441 			always_true = 1;
7442 		} else {
7443 			always_false = 1;
7444 		}
7445 	} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7446 		if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7447 			always_true = 1;
7448 		} else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7449 			if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7450 				ref = jit_ZVAL_ADDR(jit, op1_addr);
7451 				zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, 0);
7452 			}
7453 			always_false = 1;
7454 		}
7455 	}
7456 
7457 	if (always_true) {
7458 		if (set_bool) {
7459 			jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7460 		}
7461 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7462 		if (may_throw) {
7463 			zend_jit_check_exception(jit);
7464 		}
7465 		if (true_label != (uint32_t)-1) {
7466 			ZEND_ASSERT(exit_addr == NULL);
7467 			_zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7468 			jit->b = -1;
7469 		}
7470 		return 1;
7471 	} else if (always_false) {
7472 		if (set_bool) {
7473 			jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7474 		}
7475 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7476 		if (may_throw) {
7477 			zend_jit_check_exception(jit);
7478 		}
7479 		if (false_label != (uint32_t)-1) {
7480 			ZEND_ASSERT(exit_addr == NULL);
7481 			_zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7482 			jit->b = -1;
7483 		}
7484 		return 1;
7485 	}
7486 
7487 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7488 		type = jit_Z_TYPE(jit, op1_addr);
7489 		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7490 			ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7491 
7492 			ir_IF_TRUE_cold(if_type);
7493 
7494 			if (op1_info & MAY_BE_UNDEF) {
7495 				zend_jit_type_check_undef(jit,
7496 					type,
7497 					opline->op1.var,
7498 					opline, 1, 0, 1);
7499 			}
7500 			if (set_bool) {
7501 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7502 			}
7503 			if (exit_addr) {
7504 				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
7505 					ir_END_list(end_inputs);
7506 				} else {
7507 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7508 				}
7509 			} else if (false_label != (uint32_t)-1) {
7510 				ir_END_list(false_inputs);
7511 			} else {
7512 				ir_END_list(end_inputs);
7513 			}
7514 			ir_IF_FALSE(if_type);
7515 		}
7516 
7517 		if (op1_info & MAY_BE_TRUE) {
7518 			ir_ref if_type = IR_UNUSED;
7519 
7520 			if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7521 				if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7522 
7523 				ir_IF_TRUE(if_type);
7524 			}
7525 			if (set_bool) {
7526 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7527 			}
7528 			if (exit_addr) {
7529 				if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7530 					ir_END_list(end_inputs);
7531 				} else {
7532 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7533 				}
7534 			} else if (true_label != (uint32_t)-1) {
7535 				ir_END_list(true_inputs);
7536 			} else {
7537 				ir_END_list(end_inputs);
7538 			}
7539 			if (if_type) {
7540 				ir_IF_FALSE(if_type);
7541 			}
7542 		}
7543 	}
7544 
7545 	if (op1_info & MAY_BE_LONG) {
7546 		ir_ref if_long = IR_UNUSED;
7547 		ir_ref ref;
7548 
7549 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
7550 			if (!type) {
7551 				type = jit_Z_TYPE(jit, op1_addr);
7552 			}
7553 			if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7554 			ir_IF_TRUE(if_long);
7555 		}
7556 		ref = jit_Z_LVAL(jit, op1_addr);
7557 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7558 			ref = ir_NE(ref, ir_CONST_LONG(0));
7559 			if (set_bool_not) {
7560 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7561 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7562 			} else {
7563 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7564 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7565 			}
7566 			ir_END_list(end_inputs);
7567 		} else if (exit_addr) {
7568 			if (set_bool) {
7569 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7570 					ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, ir_CONST_LONG(0))), ir_CONST_U32(IS_FALSE)));
7571 			}
7572 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7573 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7574 			} else {
7575 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7576 			}
7577 			ir_END_list(end_inputs);
7578 		} else {
7579 			ir_ref if_val = ir_IF(ref);
7580 			ir_IF_TRUE(if_val);
7581 			if (set_bool) {
7582 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7583 			}
7584 			ir_END_list(true_inputs);
7585 			ir_IF_FALSE(if_val);
7586 			if (set_bool) {
7587 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7588 			}
7589 			ir_END_list(false_inputs);
7590 		}
7591 		if (if_long) {
7592 			ir_IF_FALSE(if_long);
7593 		}
7594 	}
7595 
7596 	if (op1_info & MAY_BE_DOUBLE) {
7597 		ir_ref if_double = IR_UNUSED;
7598 		ir_ref ref;
7599 
7600 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7601 			if (!type) {
7602 				type = jit_Z_TYPE(jit, op1_addr);
7603 			}
7604 			if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7605 			ir_IF_TRUE(if_double);
7606 		}
7607 		ref = ir_NE(jit_Z_DVAL(jit, op1_addr), ir_CONST_DOUBLE(0.0));
7608 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7609 			if (set_bool_not) {
7610 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7611 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7612 			} else {
7613 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7614 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7615 			}
7616 			ir_END_list(end_inputs);
7617 		} else if (exit_addr) {
7618 		    if (set_bool) {
7619 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7620 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7621 		    }
7622 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7623 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7624 			} else {
7625 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7626 			}
7627 			ir_END_list(end_inputs);
7628 		} else {
7629 			ir_ref if_val = ir_IF(ref);
7630 			ir_IF_TRUE(if_val);
7631 			if (set_bool) {
7632 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7633 			}
7634 			ir_END_list(true_inputs);
7635 			ir_IF_FALSE(if_val);
7636 			if (set_bool) {
7637 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7638 			}
7639 			ir_END_list(false_inputs);
7640 		}
7641 		if (if_double) {
7642 			ir_IF_FALSE(if_double);
7643 		}
7644 	}
7645 
7646 	if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7647 		jit_SET_EX_OPLINE(jit, opline);
7648 		ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7649 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7650 		if (may_throw) {
7651 			zend_jit_check_exception_undef_result(jit, opline);
7652 		}
7653 		if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7654 			if (set_bool_not) {
7655 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7656 					ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7657 			} else {
7658 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7659 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7660 			}
7661 			if (end_inputs) {
7662 				ir_END_list(end_inputs);
7663 			}
7664 		} else if (exit_addr) {
7665 			if (set_bool) {
7666 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7667 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7668 			}
7669 			if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7670 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7671 			} else {
7672 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7673 			}
7674 			if (end_inputs) {
7675 				ir_END_list(end_inputs);
7676 			}
7677 		} else {
7678 			ir_ref if_val = ir_IF(ref);
7679 			ir_IF_TRUE(if_val);
7680 			if (set_bool) {
7681 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7682 			}
7683 			ir_END_list(true_inputs);
7684 			ir_IF_FALSE(if_val);
7685 			if (set_bool) {
7686 				jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7687 			}
7688 			ir_END_list(false_inputs);
7689 		}
7690 	}
7691 
7692 	if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7693 		if (end_inputs) {
7694 			ir_MERGE_list(end_inputs);
7695 		}
7696 	} else {
7697 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7698 	}
7699 
7700 	return 1;
7701 }
7702 
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)7703 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)
7704 {
7705 	uint32_t defined_label = (uint32_t)-1;
7706 	uint32_t undefined_label = (uint32_t)-1;
7707 	zval *zv = RT_CONSTANT(opline, opline->op1);
7708 	zend_jit_addr res_addr = 0;
7709 	ir_ref ref, ref2, if_set, if_zero, if_set2;
7710 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7711 
7712 	if (smart_branch_opcode && !exit_addr) {
7713 		if (smart_branch_opcode == ZEND_JMPZ) {
7714 			defined_label = target_label2;
7715 			undefined_label = target_label;
7716 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
7717 			defined_label = target_label;
7718 			undefined_label = target_label2;
7719 		} else {
7720 			ZEND_UNREACHABLE();
7721 		}
7722 	} else {
7723 		res_addr = RES_ADDR();
7724 	}
7725 
7726 	// if (CACHED_PTR(opline->extended_value)) {
7727 	ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7728 
7729 	if_set = ir_IF(ref);
7730 
7731 	ir_IF_FALSE_cold(if_set);
7732 	if_zero = ir_END();
7733 
7734 	ir_IF_TRUE(if_set);
7735 	if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7736 	ir_IF_FALSE(if_set2);
7737 
7738 	if (exit_addr) {
7739 		if (smart_branch_opcode == ZEND_JMPNZ) {
7740 			jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7741 		} else {
7742 			ir_END_list(end_inputs);
7743 		}
7744 	} else if (smart_branch_opcode) {
7745 		ir_END_list(true_inputs);
7746 	} else {
7747 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7748 		ir_END_list(end_inputs);
7749 	}
7750 
7751 	ir_IF_TRUE_cold(if_set2);
7752 
7753 	ref2 = jit_EG(zend_constants);
7754 	ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7755 	if (sizeof(void*) == 8) {
7756 		ref = ir_TRUNC_U32(ref);
7757 	}
7758 	ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7759 	ref2 = ir_IF(ref2);
7760 	ir_IF_TRUE(ref2);
7761 
7762 	if (exit_addr) {
7763 		if (smart_branch_opcode == ZEND_JMPZ) {
7764 			jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7765 		} else {
7766 			ir_END_list(end_inputs);
7767 		}
7768 	} else if (smart_branch_opcode) {
7769 		ir_END_list(false_inputs);
7770 	} else {
7771 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7772 		ir_END_list(end_inputs);
7773 	}
7774 
7775 	ir_IF_FALSE(ref2);
7776 	ir_MERGE_2(if_zero, ir_END());
7777 
7778 	jit_SET_EX_OPLINE(jit, opline);
7779 	ref2 = ir_NE(ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_check_constant), ir_CONST_ADDR(zv)), IR_NULL);
7780 	if (exit_addr) {
7781 		if (smart_branch_opcode == ZEND_JMPZ) {
7782 			ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
7783 		} else {
7784 			ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
7785 		}
7786 		ir_END_list(end_inputs);
7787 	} else if (smart_branch_opcode) {
7788 		ref2 = ir_IF(ref2);
7789 		ir_IF_TRUE(ref2);
7790 		ir_END_list(true_inputs);
7791 		ir_IF_FALSE(ref2);
7792 		ir_END_list(false_inputs);
7793 	} else {
7794 		jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7795 			ir_ADD_U32(ir_ZEXT_U32(ref2), ir_CONST_U32(IS_FALSE)));
7796 		ir_END_list(end_inputs);
7797 	}
7798 
7799 	if (!smart_branch_opcode || exit_addr) {
7800 		if (end_inputs) {
7801 			ir_MERGE_list(end_inputs);
7802 		}
7803 	} else {
7804 		_zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
7805 	}
7806 
7807 	return 1;
7808 }
7809 
zend_jit_escape_if_undef(zend_jit_ctx * jit,int var,uint32_t flags,const zend_op * opline,int8_t reg)7810 static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
7811 {
7812 	zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7813 	ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
7814 
7815 	ir_IF_FALSE_cold(if_def);
7816 
7817 	if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7818 		if (!zend_jit_save_call_chain(jit, -1)) {
7819 			return 0;
7820 		}
7821 	}
7822 
7823 	if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
7824 	 && (opline-1)->opcode != ZEND_FETCH_LIST_R
7825 	 && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
7826 	 && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
7827 		zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
7828 
7829 		zend_jit_zval_try_addref(jit, val_addr);
7830 	}
7831 
7832 	jit_LOAD_IP_ADDR(jit, opline - 1);
7833 	ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
7834 
7835 	ir_IF_TRUE(if_def);
7836 
7837 	return 1;
7838 }
7839 
zend_jit_restore_zval(zend_jit_ctx * jit,int var,int8_t reg)7840 static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
7841 {
7842 	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
7843 	zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7844 
7845 	// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
7846 	jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, 1);
7847 	return 1;
7848 }
7849 
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)7850 static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx         *jit,
7851                                                       const zend_op        *opline,
7852                                                       zend_jit_addr         val_addr,
7853                                                       uint8_t               type,
7854                                                       bool                  deref,
7855                                                       uint32_t              flags,
7856                                                       bool                  op1_avoid_refcounting)
7857 {
7858 	zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
7859 	int32_t exit_point;
7860 	const void *res_exit_addr = NULL;
7861 	ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
7862 	ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
7863 	uint32_t old_op1_info = 0;
7864 	uint32_t old_info;
7865 	ir_ref old_ref;
7866 
7867 
7868 	if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7869 		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
7870 		if (op1_avoid_refcounting
7871 		 || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
7872 		  && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
7873 			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
7874 		}
7875 	}
7876 	old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
7877 	old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7878 	CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7879 	SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
7880 
7881 	if (deref) {
7882 		ir_ref if_type;
7883 
7884 		if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7885 			if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
7886 		} else {
7887 			if_type = jit_if_Z_TYPE(jit, val_addr, type);
7888 		}
7889 		ir_IF_TRUE(if_type);
7890 		end1 = ir_END();
7891 		ref1 = ref;
7892 		ir_IF_FALSE_cold(if_type);
7893 
7894 		SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7895 		exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7896 		res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7897 		if (!res_exit_addr) {
7898 			return 0;
7899 		}
7900 
7901 		jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
7902 		ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
7903 		val_addr = ZEND_ADDR_REF_ZVAL(ref);
7904 	}
7905 
7906 	SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7907 	exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7908 	res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7909 	if (!res_exit_addr) {
7910 		return 0;
7911 	}
7912 
7913 	if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7914 		ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
7915 	} else {
7916 		jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
7917 	}
7918 
7919 	if (deref) {
7920 		ir_MERGE_WITH(end1);
7921 		ref = ir_PHI_2(IR_ADDR, ref, ref1);
7922 	}
7923 
7924 	val_addr = ZEND_ADDR_REF_ZVAL(ref);
7925 
7926 	SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
7927 	SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
7928 	if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7929 		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
7930 	}
7931 
7932 	return val_addr;
7933 }
7934 
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)7935 static int zend_jit_fetch_constant(zend_jit_ctx         *jit,
7936                                    const zend_op        *opline,
7937                                    const zend_op_array  *op_array,
7938                                    zend_ssa             *ssa,
7939                                    const zend_ssa_op    *ssa_op,
7940                                    zend_jit_addr         res_addr)
7941 {
7942 	zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
7943 	uint32_t res_info = RES_INFO();
7944 	ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
7945 
7946 	// JIT: c = CACHED_PTR(opline->extended_value);
7947 	ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7948 
7949 	// JIT: if (c != NULL)
7950 	if_set = ir_IF(ref);
7951 
7952 	if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
7953 		// JIT: if (!IS_SPECIAL_CACHE_VAL(c))
7954 		ir_IF_FALSE_cold(if_set);
7955 		not_set_path = ir_END();
7956 		ir_IF_TRUE(if_set);
7957 		if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7958 		ir_IF_TRUE_cold(if_special);
7959 		special_path = ir_END();
7960 		ir_IF_FALSE(if_special);
7961 		fast_path = ir_END();
7962 		ir_MERGE_2(not_set_path, special_path);
7963 	} else {
7964 		ir_IF_TRUE(if_set);
7965 		fast_path = ir_END();
7966 		ir_IF_FALSE_cold(if_set);
7967 	}
7968 
7969 	// JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
7970 	jit_SET_EX_OPLINE(jit, opline);
7971 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_constant),
7972 		ir_CONST_ADDR(zv),
7973 		ir_CONST_U32(opline->op1.num));
7974 	ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
7975 
7976 	ir_MERGE_WITH(fast_path);
7977 	ref = ir_PHI_2(IR_ADDR, ref2, ref);
7978 
7979 	if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
7980 		uint8_t type = concrete_type(res_info);
7981 		zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
7982 
7983 		const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, 0, 0, 0);
7984 		if (!const_addr) {
7985 			return 0;
7986 		}
7987 
7988 		res_info &= ~MAY_BE_GUARD;
7989 		ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
7990 
7991 		// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
7992 		jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, 1);
7993 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
7994 			return 0;
7995 		}
7996 	} else {
7997 		ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
7998 
7999 		// JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8000 		jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, 1);
8001 	}
8002 
8003 
8004 	return 1;
8005 }
8006 
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)8007 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)
8008 {
8009 	uint32_t  mask;
8010 	zend_jit_addr op1_addr = OP1_ADDR();
8011 	zend_jit_addr res_addr = 0;
8012 	uint32_t true_label = -1, false_label = -1;
8013 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8014 
8015 	// TODO: support for is_resource() ???
8016 	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8017 
8018 	if (smart_branch_opcode && !exit_addr) {
8019 		if (smart_branch_opcode == ZEND_JMPZ) {
8020 			true_label = target_label2;
8021 			false_label = target_label;
8022 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
8023 			true_label = target_label;
8024 			false_label = target_label2;
8025 		} else {
8026 			ZEND_UNREACHABLE();
8027 		}
8028 	} else {
8029 		res_addr = RES_ADDR();
8030 	}
8031 
8032 	if (op1_info & MAY_BE_UNDEF) {
8033 		ir_ref if_def = IR_UNUSED;
8034 
8035 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8036 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8037 			ir_IF_FALSE_cold(if_def);
8038 		}
8039 
8040 		jit_SET_EX_OPLINE(jit, opline);
8041 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8042 		zend_jit_check_exception_undef_result(jit, opline);
8043 		if (opline->extended_value & MAY_BE_NULL) {
8044 			if (exit_addr) {
8045 				if (smart_branch_opcode == ZEND_JMPNZ) {
8046 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8047 				} else {
8048 					ir_END_list(end_inputs);
8049 				}
8050 			} else if (smart_branch_opcode) {
8051 				ir_END_list(true_inputs);
8052 			} else {
8053 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8054 				ir_END_list(end_inputs);
8055 			}
8056 		} else {
8057 			if (exit_addr) {
8058 				if (smart_branch_opcode == ZEND_JMPZ) {
8059 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8060 				} else {
8061 					ir_END_list(end_inputs);
8062 				}
8063 			} else if (smart_branch_opcode) {
8064 				ir_END_list(false_inputs);
8065 			} else {
8066 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8067 				if (if_def) {
8068 					ir_END_list(end_inputs);
8069 				}
8070 			}
8071 		}
8072 
8073 		if (if_def) {
8074 			ir_IF_TRUE(if_def);
8075 			op1_info |= MAY_BE_NULL;
8076 		}
8077 	}
8078 
8079 	if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8080 		mask = opline->extended_value;
8081 		if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8082 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8083 			if (exit_addr) {
8084 				if (smart_branch_opcode == ZEND_JMPNZ) {
8085 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8086 				} else if (end_inputs) {
8087 					ir_END_list(end_inputs);
8088 				}
8089 			} else if (smart_branch_opcode) {
8090 				ir_END_list(true_inputs);
8091 			} else {
8092 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8093 				ir_END_list(end_inputs);
8094 			}
8095 	    } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8096 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8097 			if (exit_addr) {
8098 				if (smart_branch_opcode == ZEND_JMPZ) {
8099 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8100 				} else if (end_inputs) {
8101 					ir_END_list(end_inputs);
8102 				}
8103 			} else if (smart_branch_opcode) {
8104 				ir_END_list(false_inputs);
8105 			} else {
8106 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8107 				ir_END_list(end_inputs);
8108 			}
8109 		} else {
8110 			ir_ref ref;
8111 			bool invert = 0;
8112 			uint8_t type;
8113 
8114 			switch (mask) {
8115 				case MAY_BE_NULL:   type = IS_NULL;   break;
8116 				case MAY_BE_FALSE:  type = IS_FALSE;  break;
8117 				case MAY_BE_TRUE:   type = IS_TRUE;   break;
8118 				case MAY_BE_LONG:   type = IS_LONG;   break;
8119 				case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8120 				case MAY_BE_STRING: type = IS_STRING; break;
8121 				case MAY_BE_ARRAY:  type = IS_ARRAY;  break;
8122 				case MAY_BE_OBJECT: type = IS_OBJECT; break;
8123 				case MAY_BE_ANY - MAY_BE_NULL:     type = IS_NULL;   invert = 1; break;
8124 				case MAY_BE_ANY - MAY_BE_FALSE:    type = IS_FALSE;  invert = 1; break;
8125 				case MAY_BE_ANY - MAY_BE_TRUE:     type = IS_TRUE;   invert = 1; break;
8126 				case MAY_BE_ANY - MAY_BE_LONG:     type = IS_LONG;   invert = 1; break;
8127 				case MAY_BE_ANY - MAY_BE_DOUBLE:   type = IS_DOUBLE; invert = 1; break;
8128 				case MAY_BE_ANY - MAY_BE_STRING:   type = IS_STRING; invert = 1; break;
8129 				case MAY_BE_ANY - MAY_BE_ARRAY:    type = IS_ARRAY;  invert = 1; break;
8130 				case MAY_BE_ANY - MAY_BE_OBJECT:   type = IS_OBJECT; invert = 1; break;
8131 				case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break;
8132 				default:
8133 					type = 0;
8134 			}
8135 
8136 			if (op1_info & MAY_BE_REF) {
8137 				ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8138 				ref = jit_ZVAL_DEREF_ref(jit, ref);
8139 				op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8140 			}
8141 			if (type == 0) {
8142 				ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8143 				if (!smart_branch_opcode) {
8144 					ref = ir_NE(ref, ir_CONST_U32(0));
8145 				}
8146 			} else if (invert) {
8147 				ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8148 			} else {
8149 				ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8150 			}
8151 
8152 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8153 
8154 			if (exit_addr) {
8155 				if (smart_branch_opcode == ZEND_JMPZ) {
8156 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8157 				} else {
8158 					ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8159 				}
8160 				if (end_inputs) {
8161 					ir_END_list(end_inputs);
8162 				}
8163 			} else if (smart_branch_opcode) {
8164 				ir_ref if_val = ir_IF(ref);
8165 				ir_IF_TRUE(if_val);
8166 				ir_END_list(true_inputs);
8167 				ir_IF_FALSE(if_val);
8168 				ir_END_list(false_inputs);
8169 			} else {
8170 				jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8171 					ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8172 				ir_END_list(end_inputs);
8173 			}
8174 	    }
8175 	}
8176 
8177 	if (!smart_branch_opcode || exit_addr) {
8178 		if (end_inputs) {
8179 			ir_MERGE_list(end_inputs);
8180 		}
8181 	} else {
8182 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8183 	}
8184 
8185 	return 1;
8186 }
8187 
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)8188 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)
8189 {
8190 	zend_jit_addr res_addr = RES_ADDR();
8191 	uint32_t true_label = -1, false_label = -1;
8192 	ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8193 
8194 	// TODO: support for empty() ???
8195 	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8196 
8197 	if (smart_branch_opcode && !exit_addr) {
8198 		if (smart_branch_opcode == ZEND_JMPZ) {
8199 			true_label = target_label2;
8200 			false_label = target_label;
8201 		} else if (smart_branch_opcode == ZEND_JMPNZ) {
8202 			true_label = target_label;
8203 			false_label = target_label2;
8204 		} else {
8205 			ZEND_UNREACHABLE();
8206 		}
8207 	} else {
8208 		res_addr = RES_ADDR();
8209 	}
8210 
8211 	if (op1_info & MAY_BE_REF) {
8212 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8213 		ref = jit_ZVAL_DEREF_ref(jit, ref);
8214 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8215 	}
8216 
8217 	if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8218 		if (exit_addr) {
8219 			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8220 		} else if (smart_branch_opcode) {
8221 			ir_END_list(true_inputs);
8222 		} else {
8223 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8224 			ir_END_list(end_inputs);
8225 		}
8226 	} else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8227 		if (exit_addr) {
8228 			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8229 		} else if (smart_branch_opcode) {
8230 			ir_END_list(false_inputs);
8231 		} else {
8232 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8233 			ir_END_list(end_inputs);
8234 		}
8235 	} else {
8236 		ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8237 		if (exit_addr) {
8238 			if (smart_branch_opcode == ZEND_JMPNZ) {
8239 				ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8240 			} else {
8241 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8242 			}
8243 		} else if (smart_branch_opcode) {
8244 			ir_ref if_val = ir_IF(ref);
8245 			ir_IF_TRUE(if_val);
8246 			ir_END_list(true_inputs);
8247 			ir_IF_FALSE(if_val);
8248 			ir_END_list(false_inputs);
8249 		} else {
8250 			jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8251 				ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8252 			ir_END_list(end_inputs);
8253 		}
8254 	}
8255 
8256 	if (!smart_branch_opcode || exit_addr) {
8257 		if (end_inputs) {
8258 			ir_MERGE_list(end_inputs);
8259 		}
8260 	} else {
8261 		_zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8262 	}
8263 
8264 	return 1;
8265 }
8266 
8267 /* copy of hidden zend_closure */
8268 typedef struct _zend_closure {
8269 	zend_object       std;
8270 	zend_function     func;
8271 	zval              this_ptr;
8272 	zend_class_entry *called_scope;
8273 	zif_handler       orig_internal_handler;
8274 } zend_closure;
8275 
zend_jit_stack_check(zend_jit_ctx * jit,const zend_op * opline,uint32_t used_stack)8276 static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8277 {
8278 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8279 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8280 
8281 	if (!exit_addr) {
8282 		return 0;
8283 	}
8284 
8285 	// JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8286 	ir_GUARD(
8287 		ir_UGE(
8288 			ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8289 			ir_CONST_ADDR(used_stack)),
8290 		ir_CONST_ADDR(exit_addr));
8291 
8292 	return 1;
8293 }
8294 
zend_jit_free_trampoline(zend_jit_ctx * jit,int8_t func_reg)8295 static int zend_jit_free_trampoline(zend_jit_ctx *jit, int8_t func_reg)
8296 {
8297 	// JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8298 	ir_ref func = ir_RLOAD_A(func_reg);
8299 	ir_ref if_trampoline = ir_IF(ir_AND_U32(
8300 		ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8301 		ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
8302 
8303 	ir_IF_TRUE(if_trampoline);
8304 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8305 	ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8306 
8307 	return 1;
8308 }
8309 
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)8310 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)
8311 {
8312 	uint32_t used_stack;
8313 	ir_ref used_stack_ref = IR_UNUSED;
8314 	bool stack_check = 1;
8315 	ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8316 
8317 	ZEND_ASSERT(func_ref != IR_NULL);
8318 	if (func) {
8319 		used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8320 		if ((int)used_stack <= checked_stack) {
8321 			stack_check = 0;
8322 		}
8323 		used_stack_ref = ir_CONST_ADDR(used_stack);
8324 	} else {
8325 		ir_ref num_args_ref;
8326 		ir_ref if_internal_func = IR_UNUSED;
8327 
8328 		used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8329 		used_stack_ref = ir_CONST_ADDR(used_stack);
8330 
8331 		if (!is_closure) {
8332 			used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8333 
8334 			// JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8335 			ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
8336 			if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8337 			ir_IF_FALSE(if_internal_func);
8338 		}
8339 
8340 		// JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8341 		num_args_ref = ir_CONST_U32(opline->extended_value);
8342 		if (!is_closure) {
8343 			ref = ir_SUB_U32(
8344 				ir_SUB_U32(
8345 					ir_MIN_U32(
8346 						num_args_ref,
8347 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.num_args)))),
8348 					ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.last_var)))),
8349 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8350 		} else {
8351 			ref = ir_SUB_U32(
8352 				ir_SUB_U32(
8353 					ir_MIN_U32(
8354 						num_args_ref,
8355 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8356 					ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8357 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8358 		}
8359 		ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8360 		if (sizeof(void*) == 8) {
8361 			ref = ir_SEXT_A(ref);
8362 		}
8363 		ref = ir_SUB_A(used_stack_ref, ref);
8364 
8365 		if (is_closure) {
8366 			used_stack_ref = ref;
8367 		} else {
8368 			ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8369 			used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8370 		}
8371 	}
8372 
8373 	zend_jit_start_reuse_ip(jit);
8374 
8375 	// JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8376 	jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8377 
8378 	if (stack_check) {
8379 		// JIT: Check Stack Overflow
8380 		ref = ir_UGE(
8381 			ir_SUB_A(
8382 				ir_LOAD_A(jit_EG(vm_stack_end)),
8383 				jit_IP(jit)),
8384 			used_stack_ref);
8385 
8386 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8387 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8388 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8389 
8390 			if (!exit_addr) {
8391 				return 0;
8392 			}
8393 
8394 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8395 		} else {
8396 			if_enough_stack = ir_IF(ref);
8397 			ir_IF_FALSE_cold(if_enough_stack);
8398 
8399 #ifdef _WIN32
8400 			if (0) {
8401 #else
8402 			if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8403 #endif
8404 				jit_SET_EX_OPLINE(jit, opline);
8405 				ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8406 			} else {
8407 				if (!is_closure) {
8408 					ref = func_ref;
8409 				} else {
8410 					ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8411 				}
8412 				jit_SET_EX_OPLINE(jit, opline);
8413 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8414 					used_stack_ref, ref);
8415 			}
8416 			jit_STORE_IP(jit, ref);
8417 
8418 			cold_path = ir_END();
8419 			ir_IF_TRUE(if_enough_stack);
8420 		}
8421 	}
8422 
8423 	ref = jit_EG(vm_stack_top);
8424 	rx = jit_IP(jit);
8425 #if !OPTIMIZE_FOR_SIZE
8426 	/* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8427 	 * This vesions is longer but faster
8428 	 *    mov EG(vm_stack_top), %CALL
8429 	 *    lea size(%call), %tmp
8430 	 *    mov %tmp, EG(vm_stack_top)
8431 	 */
8432 	top = rx;
8433 #else
8434 	/* JIT: EG(vm_stack_top) += used_stack;
8435 	 * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8436 	 *    mov EG(vm_stack_top), %CALL
8437 	 *    add $size, EG(vm_stack_top)
8438 	 */
8439 	top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8440 #endif
8441 	ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8442 
8443 	// JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8444 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8445 		// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8446 		ir_STORE(jit_CALL(rx, This.u1.type_info), ir_CONST_U32(IS_UNDEF | ZEND_CALL_NESTED_FUNCTION));
8447 	}
8448 #ifdef _WIN32
8449 	if (0) {
8450 #else
8451 	if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8452 #endif
8453 		if (cold_path) {
8454 			ir_MERGE_WITH(cold_path);
8455 			rx = jit_IP(jit);
8456 		}
8457 
8458 		// JIT: call->func = func;
8459 		ir_STORE(jit_CALL(rx, func), func_ref);
8460 	} else {
8461 		if (!is_closure) {
8462 			// JIT: call->func = func;
8463 			ir_STORE(jit_CALL(rx, func), func_ref);
8464 		} else {
8465 			// JIT: call->func = &closure->func;
8466 			ir_STORE(jit_CALL(rx, func), ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8467 		}
8468 		if (cold_path) {
8469 			ir_MERGE_WITH(cold_path);
8470 			rx = jit_IP(jit);
8471 		}
8472 	}
8473 	if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8474 		// JIT: Z_PTR(call->This) = obj;
8475 		ZEND_ASSERT(this_ref != IR_NULL);
8476 		ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8477 	    if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8478 			// JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8479 			ref = jit_CALL(rx, This.u1.type_info);
8480 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8481 				ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS));
8482 			} else {
8483 				ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_HAS_THIS)));
8484 			}
8485 	    } else {
8486 			if (opline->op1_type == IS_CV) {
8487 				// JIT: GC_ADDREF(obj);
8488 				jit_GC_ADDREF(jit, this_ref);
8489 			}
8490 
8491 			// JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8492 			ref = jit_CALL(rx, This.u1.type_info);
8493 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8494 				ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS));
8495 			} else {
8496 				ir_STORE(ref,
8497 					ir_OR_U32(ir_LOAD_U32(ref),
8498 						ir_CONST_U32(ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)));
8499 			}
8500 	    }
8501 	} else if (!is_closure) {
8502 		// JIT: Z_CE(call->This) = called_scope;
8503 		ir_STORE(jit_CALL(rx, This), IR_NULL);
8504 	} else {
8505 		ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8506 
8507 		if (opline->op2_type == IS_CV) {
8508 			// JIT: GC_ADDREF(closure);
8509 			jit_GC_ADDREF(jit, func_ref);
8510 		}
8511 
8512 		// JIT: RX(object_or_called_scope) = closure->called_scope;
8513 		object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8514 
8515 		// JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8516 		//      (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8517 		call_info = ir_OR_U32(
8518 			ir_AND_U32(
8519 				ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8520 				ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
8521 			ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
8522 		// JIT: if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
8523 		if_cond = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.u1.v.type))));
8524 		ir_IF_TRUE(if_cond);
8525 
8526 		// JIT: call_info |= ZEND_CALL_HAS_THIS;
8527 		call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
8528 
8529 		// JIT: object_or_called_scope = Z_OBJ(closure->this_ptr);
8530 		object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.value.ptr)));
8531 
8532 		ir_MERGE_WITH_EMPTY_FALSE(if_cond);
8533 		call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8534 		object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8535 
8536 		// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8537 		ref = jit_CALL(rx, This.u1.type_info);
8538 		ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), call_info));
8539 
8540 		// JIT: Z_PTR(call->This) = object_or_called_scope;
8541 		ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8542 
8543 		// JIT: if (closure->func.op_array.run_time_cache__ptr)
8544 		if_cond = ir_IF(ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.run_time_cache__ptr))));
8545 		ir_IF_FALSE(if_cond);
8546 
8547 		// JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8548 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8549 			ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8550 
8551 		ir_MERGE_WITH_EMPTY_TRUE(if_cond);
8552 	}
8553 
8554 	// JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8555 	ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8556 
8557 	return 1;
8558 }
8559 
8560 static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8561 {
8562 	int32_t exit_point;
8563 	const void *exit_addr;
8564 	ir_ref call;
8565 
8566 	if (func->type == ZEND_INTERNAL_FUNCTION) {
8567 #ifdef ZEND_WIN32
8568 		// TODO: ASLR may cause different addresses in different workers ???
8569 		return 0;
8570 #endif
8571 	} else if (func->type == ZEND_USER_FUNCTION) {
8572 		if (!zend_accel_in_shm(func->op_array.opcodes)) {
8573 			/* op_array and op_array->opcodes are not persistent. We can't link. */
8574 			return 0;
8575 		}
8576 	} else {
8577 		ZEND_UNREACHABLE();
8578 		return 0;
8579 	}
8580 
8581 	exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8582 	exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8583 	if (!exit_addr) {
8584 		return 0;
8585 	}
8586 
8587 	// call = EX(call);
8588 	call = ir_LOAD_A(jit_EX(call));
8589 	while (level > 0) {
8590 		// call = call->prev_execute_data
8591 		call = ir_LOAD_A(jit_CALL(call, prev_execute_data));
8592 		level--;
8593 	}
8594 
8595 	if (func->type == ZEND_USER_FUNCTION &&
8596 	    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8597 	     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8598 	     !func->common.function_name)) {
8599 		const zend_op *opcodes = func->op_array.opcodes;
8600 
8601 		// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8602 		ir_GUARD(
8603 			ir_EQ(
8604 				ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(call, func)), offsetof(zend_op_array, opcodes))),
8605 				ir_CONST_ADDR(opcodes)),
8606 			ir_CONST_ADDR(exit_addr));
8607 	} else {
8608 		// JIT: if (call->func != func) goto exit_addr;
8609 		ir_GUARD(ir_EQ(ir_LOAD_A(jit_CALL(call, func)), ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8610 	}
8611 
8612 	return 1;
8613 }
8614 
8615 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)
8616 {
8617 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
8618 	zend_call_info *call_info = NULL;
8619 	zend_function *func = NULL;
8620 	ir_ref func_ref = IR_UNUSED;
8621 
8622 	if (jit->delayed_call_level) {
8623 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8624 			return 0;
8625 		}
8626 	}
8627 
8628 	if (info) {
8629 		call_info = info->callee_info;
8630 		while (call_info && call_info->caller_init_opline != opline) {
8631 			call_info = call_info->next_callee;
8632 		}
8633 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
8634 			func = call_info->callee_func;
8635 		}
8636 	}
8637 
8638 	if (!func
8639 	 && trace
8640 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8641 #ifdef _WIN32
8642 		/* ASLR */
8643 		if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8644 			func = (zend_function*)trace->func;
8645 		}
8646 #else
8647 		func = (zend_function*)trace->func;
8648 #endif
8649 	}
8650 
8651 #ifdef _WIN32
8652 	if (0) {
8653 #else
8654 	if (opline->opcode == ZEND_INIT_FCALL
8655 	 && func
8656 	 && func->type == ZEND_INTERNAL_FUNCTION) {
8657 #endif
8658 		/* load constant address later */
8659 		func_ref = ir_CONST_ADDR(func);
8660 	} else if (func && op_array == &func->op_array) {
8661 		/* recursive call */
8662 		if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8663 		 || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8664 			func_ref = ir_LOAD_A(jit_EX(func));
8665 		} else {
8666 			func_ref = ir_CONST_ADDR(func);
8667 		}
8668 	} else {
8669 		ir_ref if_func, cache_slot_ref, ref;
8670 
8671 		// JIT: if (CACHED_PTR(opline->result.num))
8672 		cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8673 		func_ref = ir_LOAD_A(cache_slot_ref);
8674 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8675 		 && func
8676 		 && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8677 		 && opline->opcode != ZEND_INIT_FCALL) {
8678 			/* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8679 			if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8680 		} else {
8681 			if_func = ir_IF(func_ref);
8682 		}
8683 		ir_IF_FALSE_cold(if_func);
8684 		if (opline->opcode == ZEND_INIT_FCALL
8685 		 && func
8686 		 && func->type == ZEND_USER_FUNCTION
8687 		 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8688 			ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8689 		    ir_STORE(cache_slot_ref, ref);
8690 			ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8691 		} else {
8692 			zval *zv = RT_CONSTANT(opline, opline->op2);
8693 
8694 			if (opline->opcode == ZEND_INIT_FCALL) {
8695 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8696 					ir_CONST_ADDR(Z_STR_P(zv)),
8697 					cache_slot_ref);
8698 			} else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8699 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8700 					ir_CONST_ADDR(Z_STR_P(zv + 1)),
8701 					cache_slot_ref);
8702 			} else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8703 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8704 					ir_CONST_ADDR(zv),
8705 					cache_slot_ref);
8706 			} else {
8707 				ZEND_UNREACHABLE();
8708 			}
8709 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8710 				int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8711 					func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8712 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8713 
8714 				if (!exit_addr) {
8715 					return 0;
8716 				}
8717 				if (!func || opline->opcode == ZEND_INIT_FCALL) {
8718 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8719 				} else if (func->type == ZEND_USER_FUNCTION
8720 					 && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
8721 					const zend_op *opcodes = func->op_array.opcodes;
8722 
8723 					ir_GUARD(
8724 						ir_EQ(
8725 							ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_op_array, opcodes))),
8726 							ir_CONST_ADDR(opcodes)),
8727 						ir_CONST_ADDR(exit_addr));
8728 				} else {
8729 					ir_GUARD(ir_EQ(ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8730 				}
8731 			} else {
8732 jit_SET_EX_OPLINE(jit, opline);
8733 				ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8734 			}
8735 		}
8736 		ir_MERGE_WITH_EMPTY_TRUE(if_func);
8737 		func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8738 	}
8739 
8740 	if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, IR_UNUSED)) {
8741 		return 0;
8742 	}
8743 
8744 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8745 		if (!zend_jit_save_call_chain(jit, call_level)) {
8746 			return 0;
8747 		}
8748 	} else {
8749 		ZEND_ASSERT(call_level > 0);
8750 		jit->delayed_call_level = call_level;
8751 		delayed_call_chain = 1;
8752 	}
8753 
8754 	return 1;
8755 }
8756 
8757 static int zend_jit_init_method_call(zend_jit_ctx         *jit,
8758                                      const zend_op        *opline,
8759                                      uint32_t              b,
8760                                      const zend_op_array  *op_array,
8761                                      zend_ssa             *ssa,
8762                                      const zend_ssa_op    *ssa_op,
8763                                      int                   call_level,
8764                                      uint32_t              op1_info,
8765                                      zend_jit_addr         op1_addr,
8766                                      zend_class_entry     *ce,
8767                                      bool                  ce_is_instanceof,
8768                                      bool                  on_this,
8769                                      bool                  delayed_fetch_this,
8770                                      zend_class_entry     *trace_ce,
8771                                      zend_jit_trace_rec   *trace,
8772                                      int                   checked_stack,
8773                                      int8_t                func_reg,
8774                                      int8_t                this_reg,
8775                                      bool                  polymorphic_side_trace)
8776 {
8777 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
8778 	zend_call_info *call_info = NULL;
8779 	zend_function *func = NULL;
8780 	zval *function_name;
8781 	ir_ref if_static = IR_UNUSED, cold_path, this_ref = IR_NULL, func_ref = IR_NULL;
8782 
8783 	ZEND_ASSERT(opline->op2_type == IS_CONST);
8784 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
8785 
8786 	function_name = RT_CONSTANT(opline, opline->op2);
8787 
8788 	if (info) {
8789 		call_info = info->callee_info;
8790 		while (call_info && call_info->caller_init_opline != opline) {
8791 			call_info = call_info->next_callee;
8792 		}
8793 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
8794 			func = call_info->callee_func;
8795 		}
8796 	}
8797 
8798 	if (polymorphic_side_trace) {
8799 		/* function is passed in r0 from parent_trace */
8800 		ZEND_ASSERT(func_reg >= 0 && this_reg >= 0);
8801 		func_ref = zend_jit_deopt_rload(jit, IR_ADDR, func_reg);
8802 		this_ref = zend_jit_deopt_rload(jit, IR_ADDR, this_reg);
8803 	} else {
8804 		ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
8805 
8806 		if (on_this) {
8807 			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
8808 			this_ref = jit_Z_PTR(jit, this_addr);
8809 		} else {
8810 		    if (op1_info & MAY_BE_REF) {
8811 				if (opline->op1_type == IS_CV) {
8812 					// JIT: ZVAL_DEREF(op1)
8813 					ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8814 					ref = jit_ZVAL_DEREF_ref(jit, ref);
8815 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8816 				} else {
8817 					ir_ref if_ref;
8818 
8819 					/* Hack: Convert reference to regular value to simplify JIT code */
8820 					ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
8821 
8822 					if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
8823 					ir_IF_TRUE(if_ref);
8824 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
8825 
8826 					ir_MERGE_WITH_EMPTY_FALSE(if_ref);
8827 				}
8828 			}
8829 			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
8830 				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8831 					int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8832 					const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8833 
8834 					if (!exit_addr) {
8835 						return 0;
8836 					}
8837 					ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
8838 						ir_CONST_ADDR(exit_addr));
8839 				} else {
8840 					ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
8841 
8842 					ir_IF_FALSE_cold(if_object);
8843 
8844 					jit_SET_EX_OPLINE(jit, opline);
8845 					if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8846 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
8847 							jit_ZVAL_ADDR(jit, op1_addr));
8848 					} else {
8849 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
8850 							jit_ZVAL_ADDR(jit, op1_addr));
8851 					}
8852 					ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
8853 					ir_IF_TRUE(if_object);
8854 				}
8855 			}
8856 
8857 			this_ref = jit_Z_PTR(jit, op1_addr);
8858 		}
8859 
8860 		if (jit->delayed_call_level) {
8861 			if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8862 				return 0;
8863 			}
8864 		}
8865 
8866 		if (func) {
8867 			// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8868 			ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
8869 
8870 			if_found = ir_IF(ref);
8871 			ir_IF_TRUE(if_found);
8872 			fast_path = ir_END();
8873 		} else {
8874 			// JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
8875 			run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
8876 			ref = ir_EQ(
8877 				ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
8878 				ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
8879 			if_found = ir_IF(ref);
8880 			ir_IF_TRUE(if_found);
8881 
8882 			// JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8883 			ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
8884 			fast_path = ir_END();
8885 
8886 		}
8887 
8888 		ir_IF_FALSE_cold(if_found);
8889 		jit_SET_EX_OPLINE(jit, opline);
8890 
8891 		if (!jit->ctx.fixed_call_stack_size) {
8892 			// JIT: alloca(sizeof(void*));
8893 			this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
8894 		} else {
8895 			this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
8896 		}
8897 		ir_STORE(this_ref2, this_ref);
8898 
8899 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8900 			ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
8901 					this_ref,
8902 					ir_CONST_ADDR(function_name),
8903 					this_ref2);
8904 		} else {
8905 			ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
8906 					this_ref,
8907 					ir_CONST_ADDR(function_name),
8908 					this_ref2);
8909 		}
8910 
8911 		this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
8912 		if (!jit->ctx.fixed_call_stack_size) {
8913 			// JIT: revert alloca
8914 			ir_AFREE(ir_CONST_ADDR(0x10));
8915 		}
8916 
8917 		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8918 
8919 		ir_MERGE_WITH(fast_path);
8920 		func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
8921 		this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
8922 	}
8923 
8924 	if ((!func || zend_jit_may_be_modified(func, op_array))
8925 	 && trace
8926 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
8927 	 && trace->func
8928 #ifdef _WIN32
8929 	 && trace->func->type != ZEND_INTERNAL_FUNCTION
8930 #endif
8931 	) {
8932 		int32_t exit_point;
8933 		const void *exit_addr;
8934 
8935 		exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
8936 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8937 		if (!exit_addr) {
8938 			return 0;
8939 		}
8940 
8941 		jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
8942 		jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
8943 
8944 		func = (zend_function*)trace->func;
8945 
8946 		if (func->type == ZEND_USER_FUNCTION &&
8947 		    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8948 		     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8949 		     !func->common.function_name)) {
8950 			const zend_op *opcodes = func->op_array.opcodes;
8951 
8952 			ir_GUARD(
8953 				ir_EQ(
8954 					ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8955 					ir_CONST_ADDR(opcodes)),
8956 				ir_CONST_ADDR(exit_addr));
8957 		} else {
8958 			ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8959 		}
8960 	}
8961 
8962 	if (!func) {
8963 		// JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
8964 		if_static = ir_IF(ir_AND_U32(
8965 			ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
8966 			ir_CONST_U32(ZEND_ACC_STATIC)));
8967 		ir_IF_TRUE_cold(if_static);
8968 	}
8969 
8970 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
8971 		ir_ref ret;
8972 
8973 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8974 			ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_metod_call_frame_tmp),
8975 					this_ref,
8976 					func_ref,
8977 					ir_CONST_U32(opline->extended_value));
8978 		} else {
8979 			ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_metod_call_frame),
8980 					this_ref,
8981 					func_ref,
8982 					ir_CONST_U32(opline->extended_value));
8983 		}
8984 
8985 		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
8986 			ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8987 		}
8988 		jit_STORE_IP(jit, ret);
8989 	}
8990 
8991 	if (!func) {
8992 		cold_path = ir_END();
8993 		ir_IF_FALSE(if_static);
8994 	}
8995 
8996 	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
8997 		if (!zend_jit_push_call_frame(jit, opline, NULL, func, 0, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
8998 			return 0;
8999 		}
9000 	}
9001 
9002 	if (!func) {
9003 		ir_MERGE_WITH(cold_path);
9004 	}
9005 	zend_jit_start_reuse_ip(jit);
9006 
9007 	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9008 		if (!zend_jit_save_call_chain(jit, call_level)) {
9009 			return 0;
9010 		}
9011 	} else {
9012 		ZEND_ASSERT(call_level > 0);
9013 		delayed_call_chain = 1;
9014 		jit->delayed_call_level = call_level;
9015 	}
9016 
9017 	return 1;
9018 }
9019 
9020 static int zend_jit_init_closure_call(zend_jit_ctx         *jit,
9021                                       const zend_op        *opline,
9022                                       uint32_t              b,
9023                                       const zend_op_array  *op_array,
9024                                       zend_ssa             *ssa,
9025                                       const zend_ssa_op    *ssa_op,
9026                                       int                   call_level,
9027                                       zend_jit_trace_rec   *trace,
9028                                       int                   checked_stack)
9029 {
9030 	zend_function *func = NULL;
9031 	zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9032 	ir_ref ref;
9033 
9034 	ref = jit_Z_PTR(jit, op2_addr);
9035 
9036 	if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9037 	 && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9038 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9039 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9040 
9041 		if (!exit_addr) {
9042 			return 0;
9043 		}
9044 
9045 		ir_GUARD(
9046 			ir_EQ(
9047 				ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_object, ce))),
9048 				ir_CONST_ADDR(zend_ce_closure)),
9049 			ir_CONST_ADDR(exit_addr));
9050 
9051 		if (ssa->var_info && ssa_op->op2_use >= 0) {
9052 			ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9053 			ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9054 			ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9055 		}
9056 	}
9057 
9058 	if (trace
9059 	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9060 	 && trace->func
9061 	 && trace->func->type == ZEND_USER_FUNCTION) {
9062 		const zend_op *opcodes;
9063 		int32_t exit_point;
9064 		const void *exit_addr;
9065 
9066 		func = (zend_function*)trace->func;
9067 		opcodes = func->op_array.opcodes;
9068 		exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9069 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9070 		if (!exit_addr) {
9071 			return 0;
9072 		}
9073 
9074 		ir_GUARD(
9075 			ir_EQ(
9076 				ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9077 				ir_CONST_ADDR(opcodes)),
9078 			ir_CONST_ADDR(exit_addr));
9079 	}
9080 
9081 	if (jit->delayed_call_level) {
9082 		if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9083 			return 0;
9084 		}
9085 	}
9086 
9087 	if (!zend_jit_push_call_frame(jit, opline, NULL, func, 1, 0, checked_stack, ref, IR_UNUSED)) {
9088 		return 0;
9089 	}
9090 
9091 	if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9092 		if (!zend_jit_save_call_chain(jit, call_level)) {
9093 			return 0;
9094 		}
9095 	} else {
9096 		ZEND_ASSERT(call_level > 0);
9097 		delayed_call_chain = 1;
9098 		jit->delayed_call_level = call_level;
9099 	}
9100 
9101 	if (trace
9102 	 && trace->op == ZEND_JIT_TRACE_END
9103 	 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
9104 		if (!zend_jit_set_ip(jit, opline + 1)) {
9105 			return 0;
9106 		}
9107 	}
9108 
9109 	return 1;
9110 }
9111 
9112 static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9113 {
9114 	uint32_t arg_num = opline->op2.num;
9115 	zend_jit_addr arg_addr;
9116 
9117 	ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
9118 
9119 	if (!zend_jit_reuse_ip(jit)) {
9120 		return 0;
9121 	}
9122 
9123 	if (opline->opcode == ZEND_SEND_VAL_EX) {
9124 		uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9125 
9126 		ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
9127 
9128 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9129 		 && JIT_G(current_frame)
9130 		 && JIT_G(current_frame)->call
9131 		 && JIT_G(current_frame)->call->func) {
9132 			if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9133 				/* Don't generate code that always throws exception */
9134 				return 0;
9135 			}
9136 		} else {
9137 			ir_ref cond = ir_AND_U32(
9138 				ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9139 				ir_CONST_U32(mask));
9140 
9141 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9142 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9143 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9144 				if (!exit_addr) {
9145 					return 0;
9146 				}
9147 				ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9148 			} else {
9149 				ir_ref if_pass_by_ref;
9150 
9151 				if_pass_by_ref = ir_IF(cond);
9152 
9153 				ir_IF_TRUE_cold(if_pass_by_ref);
9154 				if (Z_MODE(op1_addr) == IS_REG) {
9155 					/* set type to avoid zval_ptr_dtor() on uninitialized value */
9156 					zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9157 					jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9158 				}
9159 				jit_SET_EX_OPLINE(jit, opline);
9160 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9161 
9162 				ir_IF_FALSE(if_pass_by_ref);
9163 			}
9164 		}
9165 	}
9166 
9167 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9168 
9169 	if (opline->op1_type == IS_CONST) {
9170 		zval *zv = RT_CONSTANT(opline, opline->op1);
9171 
9172 		jit_ZVAL_COPY_CONST(jit,
9173 			arg_addr,
9174 			MAY_BE_ANY, MAY_BE_ANY,
9175 			zv, 1);
9176 	} else {
9177 		jit_ZVAL_COPY(jit,
9178 			arg_addr,
9179 			MAY_BE_ANY,
9180 			op1_addr, op1_info, 0);
9181 	}
9182 
9183 	return 1;
9184 }
9185 
9186 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)
9187 {
9188 	zend_jit_addr op1_addr, arg_addr, ref_addr;
9189 	ir_ref ref_path = IR_UNUSED;
9190 
9191 	op1_addr = OP1_ADDR();
9192 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9193 
9194 	if (!zend_jit_reuse_ip(jit)) {
9195 		return 0;
9196 	}
9197 
9198 	if (opline->op1_type == IS_VAR) {
9199 		if (op1_info & MAY_BE_INDIRECT) {
9200 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9201 		}
9202 	} else if (opline->op1_type == IS_CV) {
9203 		if (op1_info & MAY_BE_UNDEF) {
9204 			if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9205 				// JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9206 				ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9207 				ir_IF_FALSE(if_def);
9208 				// JIT: ZVAL_NULL(op1)
9209 				jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9210 				ir_MERGE_WITH_EMPTY_TRUE(if_def);
9211 			}
9212 			op1_info &= ~MAY_BE_UNDEF;
9213 			op1_info |= MAY_BE_NULL;
9214 		}
9215 	} else {
9216 		ZEND_UNREACHABLE();
9217 	}
9218 
9219 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9220 		ir_ref ref, ref2;
9221 
9222 		if (op1_info & MAY_BE_REF) {
9223 			ir_ref if_ref;
9224 
9225 			// JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9226 			if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9227 			ir_IF_TRUE(if_ref);
9228 			// JIT: ref = Z_PTR_P(op1)
9229 			ref = jit_Z_PTR(jit, op1_addr);
9230 			// JIT: GC_ADDREF(ref)
9231 			jit_GC_ADDREF(jit, ref);
9232 			// JIT: ZVAL_REFERENCE(arg, ref)
9233 			jit_set_Z_PTR(jit, arg_addr, ref);
9234 			jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9235 			ref_path = ir_END();
9236 			ir_IF_FALSE(if_ref);
9237 		}
9238 
9239 		// JIT: ZVAL_NEW_REF(arg, varptr);
9240 		// JIT: ref = emalloc(sizeof(zend_reference));
9241 		ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9242 		// JIT: GC_REFCOUNT(ref) = 2
9243 		jit_set_GC_REFCOUNT(jit, ref, 2);
9244 		// JIT: GC_TYPE(ref) = GC_REFERENCE
9245 		ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, gc.u.type_info)), ir_CONST_U32(GC_REFERENCE));
9246 		ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr)), IR_NULL);
9247 		ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9248 		ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9249 
9250         // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9251 		jit_ZVAL_COPY(jit,
9252 			ref_addr,
9253 			MAY_BE_ANY,
9254 			op1_addr, op1_info, 0);
9255 
9256 		// JIT: ZVAL_REFERENCE(arg, ref)
9257 		jit_set_Z_PTR(jit, op1_addr, ref);
9258 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9259 
9260 		// JIT: ZVAL_REFERENCE(arg, ref)
9261 		jit_set_Z_PTR(jit, arg_addr, ref);
9262 		jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9263 	}
9264 
9265 	if (ref_path) {
9266 		ir_MERGE_WITH(ref_path);
9267 	}
9268 
9269 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9270 
9271 	return 1;
9272 }
9273 
9274 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)
9275 {
9276 	uint32_t arg_num = opline->op2.num;
9277 	zend_jit_addr arg_addr;
9278 	ir_ref end_inputs = IR_UNUSED;
9279 
9280 	ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9281 	     opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9282 	    arg_num <= MAX_ARG_FLAG_NUM);
9283 
9284 	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9285 
9286 	if (!zend_jit_reuse_ip(jit)) {
9287 		return 0;
9288 	}
9289 
9290 	if (opline->opcode == ZEND_SEND_VAR_EX) {
9291 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9292 		 && JIT_G(current_frame)
9293 		 && JIT_G(current_frame)->call
9294 		 && JIT_G(current_frame)->call->func) {
9295 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9296 				if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9297 					return 0;
9298 				}
9299 				return 1;
9300 			}
9301 		} else {
9302 			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9303 
9304 			// JIT: if (RX->func->quick_arg_flags & mask)
9305 			ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9306 				ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9307 				ir_CONST_U32(mask)));
9308 			ir_IF_TRUE_cold(if_send_by_ref);
9309 
9310 			if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9311 				return 0;
9312 			}
9313 
9314 			ir_END_list(end_inputs);
9315 			ir_IF_FALSE(if_send_by_ref);
9316 		}
9317 	} else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9318 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9319 		 && JIT_G(current_frame)
9320 		 && JIT_G(current_frame)->call
9321 		 && JIT_G(current_frame)->call->func) {
9322 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9323 
9324 		        // JIT: ZVAL_COPY_VALUE(arg, op1)
9325 				jit_ZVAL_COPY(jit,
9326 					arg_addr,
9327 					MAY_BE_ANY,
9328 					op1_addr, op1_info, 0);
9329 
9330 				if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9331 					if (!(op1_info & MAY_BE_REF)) {
9332 						/* Don't generate code that always throws exception */
9333 						return 0;
9334 					} else {
9335 						int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9336 						const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9337 						if (!exit_addr) {
9338 							return 0;
9339 						}
9340 
9341 						// JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9342 						ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9343 							ir_CONST_ADDR(exit_addr));
9344 					}
9345 				}
9346 				return 1;
9347 			}
9348 		} else {
9349 			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9350 			ir_ref func, if_send_by_ref, if_prefer_ref;
9351 
9352 			// JIT: if (RX->func->quick_arg_flags & mask)
9353 			func = ir_LOAD_A(jit_RX(func));
9354 			if_send_by_ref = ir_IF(ir_AND_U32(
9355 				ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9356 				ir_CONST_U32(mask)));
9357 			ir_IF_TRUE_cold(if_send_by_ref);
9358 
9359 			mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9360 
9361 	        // JIT: ZVAL_COPY_VALUE(arg, op1)
9362 			jit_ZVAL_COPY(jit,
9363 				arg_addr,
9364 				MAY_BE_ANY,
9365 				op1_addr, op1_info, 0);
9366 
9367 			if (op1_info & MAY_BE_REF) {
9368 				ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9369 				ir_IF_TRUE(if_ref);
9370 				ir_END_list(end_inputs);
9371 				ir_IF_FALSE(if_ref);
9372 			}
9373 
9374 			// JIT: if (RX->func->quick_arg_flags & mask)
9375 			if_prefer_ref = ir_IF(ir_AND_U32(
9376 				ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9377 				ir_CONST_U32(mask)));
9378 			ir_IF_TRUE(if_prefer_ref);
9379 			ir_END_list(end_inputs);
9380 			ir_IF_FALSE(if_prefer_ref);
9381 
9382 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9383 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9384 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9385 				if (!exit_addr) {
9386 					return 0;
9387 				}
9388 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9389 			} else {
9390 				jit_SET_EX_OPLINE(jit, opline);
9391 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9392 					jit_ZVAL_ADDR(jit, arg_addr));
9393 				zend_jit_check_exception(jit);
9394 				ir_END_list(end_inputs);
9395 			}
9396 
9397 			ir_IF_FALSE(if_send_by_ref);
9398 		}
9399 	} else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9400 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9401 		 && JIT_G(current_frame)
9402 		 && JIT_G(current_frame)->call
9403 		 && JIT_G(current_frame)->call->func) {
9404 			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9405 				if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9406 					return 0;
9407 				}
9408 				return 1;
9409 			}
9410 		} else {
9411 			// JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9412 			ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9413 				ir_LOAD_U32(jit_RX(This.u1.type_info)),
9414 				ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9415 			ir_IF_TRUE_cold(if_send_by_ref);
9416 
9417 			if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9418 				return 0;
9419 			}
9420 
9421 			ir_END_list(end_inputs);
9422 			ir_IF_FALSE(if_send_by_ref);
9423 		}
9424 	}
9425 
9426 	if (op1_info & MAY_BE_UNDEF) {
9427 		ir_ref ref, if_def = IR_UNUSED;
9428 
9429 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9430 			if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9431 			ir_IF_FALSE_cold(if_def);
9432 		}
9433 
9434 		// JIT: zend_jit_undefined_op_helper(opline->op1.var)
9435 		jit_SET_EX_OPLINE(jit, opline);
9436 		ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9437 			ir_CONST_U32(opline->op1.var));
9438 
9439 		// JIT: ZVAL_NULL(arg)
9440 		jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9441 
9442 		// JIT: check_exception
9443 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9444 
9445 		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9446 			ir_END_list(end_inputs);
9447 			ir_IF_TRUE(if_def);
9448 		} else {
9449 			if (end_inputs) {
9450 				ir_END_list(end_inputs);
9451 				ir_MERGE_list(end_inputs);
9452 			}
9453 			return 1;
9454 		}
9455 	}
9456 
9457 	if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9458         // JIT: ZVAL_COPY_VALUE(arg, op1)
9459 		jit_ZVAL_COPY(jit,
9460 			arg_addr,
9461 			MAY_BE_ANY,
9462 			op1_addr, op1_info, 0);
9463 		if (op1_info & MAY_BE_REF) {
9464 				// JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9465 				ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9466 				ir_IF_TRUE(if_ref);
9467 				ir_END_list(end_inputs);
9468 				ir_IF_FALSE(if_ref);
9469 		}
9470 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9471 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9472 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9473 			if (!exit_addr) {
9474 				return 0;
9475 			}
9476 			ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9477 		} else {
9478 			jit_SET_EX_OPLINE(jit, opline);
9479 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9480 				jit_ZVAL_ADDR(jit, arg_addr));
9481 			zend_jit_check_exception(jit);
9482 		}
9483 	} else {
9484 		if (op1_info & MAY_BE_REF) {
9485 			if (opline->op1_type == IS_CV) {
9486 				ir_ref ref;
9487 
9488 				// JIT: ZVAL_DEREF(op1)
9489 				ref = jit_ZVAL_ADDR(jit, op1_addr);
9490 				ref = jit_ZVAL_DEREF_ref(jit, ref);
9491 				op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9492 
9493 		        // JIT: ZVAL_COPY(arg, op1)
9494 				jit_ZVAL_COPY(jit,
9495 					arg_addr,
9496 					MAY_BE_ANY,
9497 					op1_addr, op1_info, 1);
9498 			} else {
9499 				ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9500 				zend_jit_addr ref_addr;
9501 
9502 				// JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9503 				if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9504 				ir_IF_TRUE_cold(if_ref);
9505 
9506 				// JIT: ref = Z_COUNTED_P(op1);
9507 				ref = jit_Z_PTR(jit, op1_addr);
9508 				ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9509 				ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9510 
9511 				// JIT: ZVAL_COPY_VALUE(arg, op1);
9512 				jit_ZVAL_COPY(jit,
9513 					arg_addr,
9514 					MAY_BE_ANY,
9515 					ref_addr, op1_info, 0);
9516 
9517 				// JIT: if (GC_DELREF(ref) != 0)
9518 				refcount = jit_GC_DELREF(jit, ref);
9519 				if_not_zero = ir_IF(refcount);
9520 				ir_IF_TRUE(if_not_zero);
9521 
9522                 // JIT: if (Z_REFCOUNTED_P(arg)
9523 				if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9524 				ir_IF_TRUE(if_refcounted);
9525 				// JIT: Z_ADDREF_P(arg)
9526 				jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9527 				ir_END_list(end_inputs);
9528 				ir_IF_FALSE(if_refcounted);
9529 				ir_END_list(end_inputs);
9530 
9531 				ir_IF_FALSE(if_not_zero);
9532 
9533 				// JIT: efree(ref)
9534 				jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9535 				ir_END_list(end_inputs);
9536 
9537 				ir_IF_FALSE(if_ref);
9538 
9539 				// JIT: ZVAL_COPY_VALUE(arg, op1);
9540 				jit_ZVAL_COPY(jit,
9541 					arg_addr,
9542 					MAY_BE_ANY,
9543 					op1_addr, op1_info, 0);
9544 			}
9545 		} else {
9546 			if (op1_addr != op1_def_addr) {
9547 				if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9548 					return 0;
9549 				}
9550 				if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9551 					op1_addr = op1_def_addr;
9552 				}
9553 			}
9554 
9555 	        // JIT: ZVAL_COPY_VALUE(arg, op1)
9556 			jit_ZVAL_COPY(jit,
9557 				arg_addr,
9558 				MAY_BE_ANY,
9559 				op1_addr, op1_info, opline->op1_type == IS_CV);
9560 		}
9561 	}
9562 
9563 	if (end_inputs) {
9564 		ir_END_list(end_inputs);
9565 		ir_MERGE_list(end_inputs);
9566 	}
9567 
9568 	return 1;
9569 }
9570 
9571 static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
9572 {
9573 	uint32_t arg_num = opline->op2.num;
9574 	ir_ref ref;
9575 
9576 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9577 	 && JIT_G(current_frame)
9578 	 && JIT_G(current_frame)->call
9579 	 && JIT_G(current_frame)->call->func) {
9580 		if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9581 			if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
9582 				TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
9583 				// JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9584 				if (jit->reuse_ip) {
9585 					ref = jit_IP(jit);
9586 				} else {
9587 					ref = ir_LOAD_A(jit_EX(call));
9588 				}
9589 				ref = jit_CALL(ref, This.u1.type_info);
9590 				ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9591 			}
9592 		} else {
9593 			if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
9594 				TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
9595 				// JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9596 				if (jit->reuse_ip) {
9597 					ref = jit_IP(jit);
9598 				} else {
9599 					ref = ir_LOAD_A(jit_EX(call));
9600 				}
9601 				ref = jit_CALL(ref, This.u1.type_info);
9602 				ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9603 			}
9604 		}
9605 	} else {
9606 		// JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
9607 		uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9608 		ir_ref rx, if_ref, cold_path;
9609 
9610 		if (!zend_jit_reuse_ip(jit)) {
9611 			return 0;
9612 		}
9613 
9614 		rx = jit_IP(jit);
9615 
9616 		ref = ir_AND_U32(
9617 			ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_function, quick_arg_flags))),
9618 			ir_CONST_U32(mask));
9619 		if_ref = ir_IF(ref);
9620 		ir_IF_TRUE_cold(if_ref);
9621 
9622 		// JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9623 		ref = jit_CALL(rx, This.u1.type_info);
9624 		ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9625 
9626 		cold_path = ir_END();
9627 		ir_IF_FALSE(if_ref);
9628 
9629 		// JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9630 		ref = jit_CALL(rx, This.u1.type_info);
9631 		ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9632 
9633 		ir_MERGE_WITH(cold_path);
9634 	}
9635 
9636 	return 1;
9637 }
9638 
9639 static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
9640 {
9641 	ir_ref call, if_may_have_undef, ret;
9642 
9643 	if (jit->reuse_ip) {
9644 		call = jit_IP(jit);
9645 	} else {
9646 		call = ir_LOAD_A(jit_EX(call));
9647 	}
9648 
9649 	if_may_have_undef = ir_IF(ir_AND_U8(
9650 		ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
9651 		ir_CONST_U8(ZEND_CALL_MAY_HAVE_UNDEF >> 24)));
9652 
9653 	ir_IF_TRUE_cold(if_may_have_undef);
9654 	jit_SET_EX_OPLINE(jit, opline);
9655 	ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_handle_undef_args), call);
9656 	ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9657 	ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
9658 
9659 	return 1;
9660 }
9661 
9662 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)
9663 {
9664 	zend_func_info *info = ZEND_FUNC_INFO(op_array);
9665 	zend_call_info *call_info = NULL;
9666 	const zend_function *func = NULL;
9667 	uint32_t i;
9668 	uint32_t call_num_args = 0;
9669 	bool unknown_num_args = 0;
9670 	const void *exit_addr = NULL;
9671 	const zend_op *prev_opline;
9672 	ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
9673 
9674 	prev_opline = opline - 1;
9675 	while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
9676 		prev_opline--;
9677 	}
9678 	if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
9679 			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
9680 		unknown_num_args = 1;
9681 	}
9682 
9683 	if (info) {
9684 		call_info = info->callee_info;
9685 		while (call_info && call_info->caller_call_opline != opline) {
9686 			call_info = call_info->next_callee;
9687 		}
9688 		if (call_info && call_info->callee_func && !call_info->is_prototype) {
9689 			func = call_info->callee_func;
9690 		}
9691 		if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
9692 		 && JIT_G(current_frame)
9693 		 && JIT_G(current_frame)->call
9694 		 && !JIT_G(current_frame)->call->func) {
9695 			call_info = NULL; func = NULL; /* megamorphic call from trait */
9696 		}
9697 	}
9698 	if (!func) {
9699 		/* resolve function at run time */
9700 	} else if (func->type == ZEND_USER_FUNCTION) {
9701 		ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
9702 		call_num_args = call_info->num_args;
9703 	} else if (func->type == ZEND_INTERNAL_FUNCTION) {
9704 		ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
9705 		call_num_args = call_info->num_args;
9706 	} else {
9707 		ZEND_UNREACHABLE();
9708 	}
9709 
9710 	if (trace && !func) {
9711 		if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
9712 			ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION);
9713 #ifndef ZEND_WIN32
9714 			// TODO: ASLR may cause different addresses in different workers ???
9715 			func = trace->func;
9716 			if (JIT_G(current_frame) &&
9717 			    JIT_G(current_frame)->call &&
9718 			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9719 				call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9720 			} else {
9721 				unknown_num_args = 1;
9722 			}
9723 #endif
9724 		} else if (trace->op == ZEND_JIT_TRACE_ENTER) {
9725 			ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
9726 			if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
9727 				func = trace->func;
9728 				if (JIT_G(current_frame) &&
9729 				    JIT_G(current_frame)->call &&
9730 				    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9731 					call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9732 				} else {
9733 					unknown_num_args = 1;
9734 				}
9735 			}
9736 		}
9737 	}
9738 
9739 	bool may_have_extra_named_params =
9740 		opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS &&
9741 		(!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
9742 
9743 	if (!jit->reuse_ip) {
9744 		zend_jit_start_reuse_ip(jit);
9745 		// JIT: call = EX(call);
9746 		jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
9747 	}
9748 	rx = jit_IP(jit);
9749 	zend_jit_stop_reuse_ip(jit);
9750 
9751 	jit_SET_EX_OPLINE(jit, opline);
9752 
9753 	if (opline->opcode == ZEND_DO_FCALL) {
9754 		if (!func) {
9755 			if (trace) {
9756 				uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9757 
9758 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9759 				if (!exit_addr) {
9760 					return 0;
9761 				}
9762 
9763 				func_ref = ir_LOAD_A(jit_CALL(rx, func));
9764 				ir_GUARD_NOT(
9765 					ir_AND_U32(
9766 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
9767 						ir_CONST_U32(ZEND_ACC_DEPRECATED)),
9768 					ir_CONST_ADDR(exit_addr));
9769 			}
9770 		}
9771 	}
9772 
9773 	if (!jit->delayed_call_level) {
9774 		// JIT: EX(call) = call->prev_execute_data;
9775 		ir_STORE(jit_EX(call),
9776 			(call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
9777 	}
9778 	delayed_call_chain = 0;
9779 	jit->delayed_call_level = 0;
9780 
9781 	// JIT: call->prev_execute_data = execute_data;
9782 	ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
9783 
9784 	if (!func) {
9785 		if (!func_ref) {
9786 			func_ref = ir_LOAD_A(jit_CALL(rx, func));
9787 		}
9788 	}
9789 
9790 	if (opline->opcode == ZEND_DO_FCALL) {
9791 		if (!func) {
9792 			if (!trace) {
9793 				ir_ref if_deprecated, ret;
9794 
9795 				if_deprecated = ir_IF(ir_AND_U32(
9796 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
9797 						ir_CONST_U32(ZEND_ACC_DEPRECATED)));
9798 				ir_IF_TRUE_cold(if_deprecated);
9799 
9800 				if (GCC_GLOBAL_REGS) {
9801 					ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
9802 				} else {
9803 					ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
9804 				}
9805 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9806 				ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
9807 			}
9808 		} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
9809 			ir_ref ret;
9810 
9811 			if (GCC_GLOBAL_REGS) {
9812 				ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
9813 			} else {
9814 				ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
9815 			}
9816 			ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9817 		}
9818 	}
9819 
9820 	if (!func
9821 	 && opline->opcode != ZEND_DO_UCALL
9822 	 && opline->opcode != ZEND_DO_ICALL) {
9823 		ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
9824 		if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
9825 		ir_IF_TRUE(if_user);
9826 	}
9827 
9828 	if ((!func || func->type == ZEND_USER_FUNCTION)
9829 	 && opline->opcode != ZEND_DO_ICALL) {
9830 		bool recursive_call_through_jmp = 0;
9831 
9832 		// JIT: EX(call) = NULL;
9833 		ir_STORE(jit_CALL(rx, call), IR_NULL);
9834 
9835 		// JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
9836 		ir_STORE(jit_CALL(rx, return_value),
9837 			RETURN_VALUE_USED(opline) ?
9838 				jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
9839 				IR_NULL);
9840 
9841 		// JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
9842 		if (!func || func->op_array.cache_size) {
9843 			ir_ref run_time_cache;
9844 
9845 			if (func && op_array == &func->op_array) {
9846 				/* recursive call */
9847 				run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
9848 			} else if (func
9849 			 && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
9850 			 && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
9851 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
9852 					(uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
9853 			} else if ((func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) ||
9854 					(JIT_G(current_frame) &&
9855 					 JIT_G(current_frame)->call &&
9856 					 TRACE_FRAME_IS_CLOSURE_CALL(JIT_G(current_frame)->call))) {
9857 				/* Closures always use direct pointers */
9858 				ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
9859 
9860 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
9861 			} else {
9862 				ir_ref if_odd, run_time_cache2;
9863 				ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
9864 
9865 				run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
9866 				if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
9867 				ir_IF_TRUE(if_odd);
9868 
9869 				run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
9870 
9871 				ir_MERGE_WITH_EMPTY_FALSE(if_odd);
9872 				run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
9873 			}
9874 
9875 			ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
9876 		}
9877 
9878 		// JIT: EG(current_execute_data) = execute_data = call;
9879 		ir_STORE(jit_EG(current_execute_data), rx);
9880 		jit_STORE_FP(jit, rx);
9881 
9882 		// JIT: opline = op_array->opcodes;
9883 		if (func && !unknown_num_args) {
9884 
9885 			for (i = call_num_args; i < func->op_array.last_var; i++) {
9886 				uint32_t n = EX_NUM_TO_VAR(i);
9887 				zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
9888 
9889 				jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
9890 			}
9891 
9892 			if (call_num_args <= func->op_array.num_args) {
9893 				if (!trace || (trace->op == ZEND_JIT_TRACE_END
9894 				 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
9895 					uint32_t num_args;
9896 
9897 					if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
9898 						if (trace) {
9899 							num_args = 0;
9900 						} else if (call_info) {
9901 							num_args = skip_valid_arguments(op_array, ssa, call_info);
9902 						} else {
9903 							num_args = call_num_args;
9904 						}
9905 					} else {
9906 						num_args = call_num_args;
9907 					}
9908 					if (zend_accel_in_shm(func->op_array.opcodes)) {
9909 						jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
9910 					} else {
9911 						if (!func_ref) {
9912 							func_ref = ir_LOAD_A(jit_CALL(rx, func));
9913 						}
9914 						ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
9915 						if (num_args) {
9916 							ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
9917 						}
9918 						jit_LOAD_IP(jit, ip);
9919 					}
9920 
9921 					if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
9922 						/* recursive call */
9923 						recursive_call_through_jmp = 1;
9924 					}
9925 				}
9926 			} else {
9927 				if (!trace || (trace->op == ZEND_JIT_TRACE_END
9928 				 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
9929 					ir_ref ip;
9930 
9931 					if (zend_accel_in_shm(func->op_array.opcodes)) {
9932 						ip = ir_CONST_ADDR(func->op_array.opcodes);
9933 					} else {
9934 						if (!func_ref) {
9935 							func_ref = ir_LOAD_A(jit_CALL(rx, func));
9936 						}
9937 						ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
9938 					}
9939 					jit_LOAD_IP(jit, ip);
9940 				}
9941 				if (GCC_GLOBAL_REGS) {
9942 					ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
9943 				} else {
9944 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
9945 				}
9946 			}
9947 		} else {
9948 			ir_ref ip;
9949 			ir_ref merge_inputs = IR_UNUSED;
9950 
9951 			// JIT: opline = op_array->opcodes
9952 			if (func && zend_accel_in_shm(func->op_array.opcodes)) {
9953 				ip = ir_CONST_ADDR(func->op_array.opcodes);
9954 			} else {
9955 				if (!func_ref) {
9956 					func_ref = ir_LOAD_A(jit_CALL(rx, func));
9957 				}
9958 				ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
9959 			}
9960 			jit_LOAD_IP(jit, ip);
9961 
9962 			// JIT: num_args = EX_NUM_ARGS();
9963 			ir_ref num_args, first_extra_arg;
9964 
9965 			num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
9966 			if (func) {
9967 				first_extra_arg = ir_CONST_U32(func->op_array.num_args);
9968 			} else {
9969 				// JIT: first_extra_arg = op_array->num_args;
9970 				ZEND_ASSERT(func_ref);
9971 				first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
9972 			}
9973 
9974 			// JIT: if (UNEXPECTED(num_args > first_extra_arg))
9975 			ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
9976 			ir_IF_TRUE_cold(if_extra_args);
9977 			if (GCC_GLOBAL_REGS) {
9978 				ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
9979 			} else {
9980 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
9981 			}
9982 			ir_END_list(merge_inputs);
9983 			ir_IF_FALSE(if_extra_args);
9984 			if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
9985 				if (!func) {
9986 					// JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
9987 					ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
9988 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
9989 						ir_CONST_U32(ZEND_ACC_HAS_TYPE_HINTS)));
9990 					ir_IF_TRUE(if_has_type_hints);
9991 					ir_END_list(merge_inputs);
9992 					ir_IF_FALSE(if_has_type_hints);
9993 				}
9994 				// JIT: opline += num_args;
9995 
9996 				ir_ref ref = ir_MUL_U32(num_args, ir_CONST_U32(sizeof(zend_op)));
9997 
9998 				if (sizeof(void*) == 8) {
9999 					ref = ir_ZEXT_A(ref);
10000 				}
10001 
10002 				if (GCC_GLOBAL_REGS) {
10003 					jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10004 				} else {
10005 					ir_ref addr = jit_EX(opline);
10006 
10007 					ir_STORE(addr, ir_ADD_A(ir_LOAD_A(addr), ref));
10008 				}
10009 			}
10010 
10011 			ir_END_list(merge_inputs);
10012 			ir_MERGE_list(merge_inputs);
10013 
10014 			// JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10015 			ir_ref last_var;
10016 
10017 			if (func) {
10018 				last_var = ir_CONST_U32(func->op_array.last_var);
10019 			} else {
10020 				ZEND_ASSERT(func_ref);
10021 				last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10022 			}
10023 
10024 			ir_ref idx = ir_SUB_U32(last_var, num_args);
10025 			ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10026 			ir_IF_TRUE(if_need);
10027 
10028 			// JIT: zval *var = EX_VAR_NUM(num_args);
10029 			if (sizeof(void*) == 8) {
10030 				num_args = ir_ZEXT_A(num_args);
10031 			}
10032 			ir_ref var_ref = ir_ADD_OFFSET(
10033 				ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10034 				(ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10035 
10036 			ir_ref loop = ir_LOOP_BEGIN(ir_END());
10037 			var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10038 			idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10039 			ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10040 			ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10041 			ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10042 			ir_PHI_SET_OP(idx, 2, idx2);
10043 			ir_ref if_not_zero = ir_IF(idx2);
10044 			ir_IF_TRUE(if_not_zero);
10045 			ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10046 			ir_IF_FALSE(if_not_zero);
10047 			ir_MERGE_WITH_EMPTY_FALSE(if_need);
10048 		}
10049 
10050 		if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10051 			ir_ref observer_handler;
10052 			ir_ref rx = jit_FP(jit);
10053 			struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10054 			if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10055 				ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10056 				jit_SET_EX_OPLINE(jit, trace[1].opline);
10057 			} else if (GCC_GLOBAL_REGS) {
10058 				// EX(opline) = opline
10059 				ir_STORE(jit_EX(opline), jit_IP(jit));
10060 			}
10061 			jit_observer_fcall_begin(jit, rx, observer_handler);
10062 			jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10063 		}
10064 
10065 		if (trace) {
10066 			if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10067 				user_path = ir_END();
10068 			}
10069 		} else {
10070 			zend_basic_block *bb;
10071 
10072 			do {
10073 				if (recursive_call_through_jmp) {
10074 					ir_ref begin, end;
10075 					ir_insn *insn;
10076 
10077 					/* attempt to convert direct recursive call into loop */
10078 					begin = jit->bb_start_ref[call_num_args];
10079 					ZEND_ASSERT(begin != IR_UNUSED);
10080 					insn = &jit->ctx.ir_base[begin];
10081 					if (insn->op == IR_BEGIN) {
10082 						end = ir_LOOP_END();
10083 						insn = &jit->ctx.ir_base[begin];
10084 						insn->op = IR_LOOP_BEGIN;
10085 						insn->inputs_count = 2;
10086 						insn->op2 = end;
10087 						break;
10088 					} else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10089 							&& insn->inputs_count == 2) {
10090 						end = ir_LOOP_END();
10091 						insn = &jit->ctx.ir_base[begin];
10092 						insn->op = IR_LOOP_BEGIN;
10093 						insn->inputs_count = 3;
10094 						insn->op3 = end;
10095 						break;
10096 					} else if (insn->op == IR_LOOP_BEGIN && insn->inputs_count == 3) {
10097 						ZEND_ASSERT(jit->ctx.ir_base[insn->op3].op == IR_LOOP_END);
10098 						jit->ctx.ir_base[insn->op3].op = IR_END;
10099 						ir_MERGE_2(insn->op3, ir_END());
10100 						end = ir_LOOP_END();
10101 						insn = &jit->ctx.ir_base[begin];
10102 						insn->op3 = end;
10103 						break;
10104 					}
10105 				}
10106 				/* fallback to indirect JMP or RETURN */
10107 				if (GCC_GLOBAL_REGS) {
10108 					ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10109 				} else {
10110 					ir_RETURN(ir_CONST_I32(1));
10111 				}
10112 			} while (0);
10113 
10114 			bb = &jit->ssa->cfg.blocks[jit->b];
10115 			if (bb->successors_count > 0) {
10116 				int succ;
10117 				ir_ref ref;
10118 
10119 				ZEND_ASSERT(bb->successors_count == 1);
10120 				succ = bb->successors[0];
10121 				/* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10122 				ref = jit->ctx.insns_count - 1;
10123 				ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10124 					|| jit->ctx.ir_base[ref].op == IR_RETURN
10125 					|| jit->ctx.ir_base[ref].op == IR_LOOP_END);
10126 				ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
10127 				ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10128 				if (func || (opline->opcode == ZEND_DO_UCALL)) {
10129 					_zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10130 					jit->b = -1;
10131 				} else {
10132 					user_path = ref;
10133 				}
10134 			}
10135 		}
10136 	}
10137 
10138 	if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10139 	 && (opline->opcode != ZEND_DO_UCALL)) {
10140 		if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10141 			ir_IF_FALSE(if_user);
10142 		}
10143 		if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10144 			if (!func) {
10145 				if (trace) {
10146 					uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10147 
10148 					exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10149 					if (!exit_addr) {
10150 						return 0;
10151 					}
10152 					ZEND_ASSERT(func_ref);
10153 					ir_GUARD_NOT(
10154 						ir_AND_U32(
10155 							ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10156 							ir_CONST_U32(ZEND_ACC_DEPRECATED)),
10157 						ir_CONST_ADDR(exit_addr));
10158 				} else {
10159 					ir_ref if_deprecated, ret;
10160 
10161 					if_deprecated = ir_IF(ir_AND_U32(
10162 						ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10163 						ir_CONST_U32(ZEND_ACC_DEPRECATED)));
10164 					ir_IF_TRUE_cold(if_deprecated);
10165 
10166 					if (GCC_GLOBAL_REGS) {
10167 						ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10168 					} else {
10169 						ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10170 					}
10171 					ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10172 					ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
10173 				}
10174 			} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10175 				ir_ref ret;
10176 
10177 				if (GCC_GLOBAL_REGS) {
10178 					ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10179 				} else {
10180 					ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10181 				}
10182 				ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10183 			}
10184 		}
10185 
10186 		// JIT: EG(current_execute_data) = execute_data;
10187 		ir_STORE(jit_EG(current_execute_data), rx);
10188 
10189 		bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10190 		if (may_have_observer) {
10191 			ir_ref observer_handler;
10192 			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)));
10193 			jit_observer_fcall_begin(jit, rx, observer_handler);
10194 			jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10195 		}
10196 
10197 		// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10198 		ir_ref res_addr = IR_UNUSED, func_ptr;
10199 
10200 		if (RETURN_VALUE_USED(opline)) {
10201 			res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10202 		} else {
10203 			/* CPU stack allocated temporary zval */
10204 			ir_ref ptr;
10205 
10206 			if (!jit->ctx.fixed_call_stack_size) {
10207 				// JIT: alloca(sizeof(void*));
10208 				ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10209 			} else {
10210 				ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10211 			}
10212 			res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10213 		}
10214 
10215 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10216 
10217 		zend_jit_reset_last_valid_opline(jit);
10218 
10219 		// JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10220 		ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10221 		if (zend_execute_internal) {
10222 			ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
10223 		} else {
10224 			if (func) {
10225 				func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10226 			} else {
10227 				func_ptr = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler)));
10228 #if defined(IR_TARGET_X86)
10229 				func_ptr = ir_CAST_FC_FUNC(func_ptr);
10230 #endif
10231 			}
10232 			ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10233 		}
10234 
10235 		if (may_have_observer) {
10236 			jit_observer_fcall_end(jit, rx, res_ref);
10237 		}
10238 
10239 		// JIT: EG(current_execute_data) = execute_data;
10240 		ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10241 
10242 		// JIT: zend_vm_stack_free_args(call);
10243 		if (func && !unknown_num_args) {
10244 			for (i = 0; i < call_num_args; i++ ) {
10245 				if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10246 					uint32_t offset = EX_NUM_TO_VAR(i);
10247 					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
10248 
10249 					jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, opline);
10250 				}
10251 			}
10252 		} else {
10253 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10254 		}
10255 
10256 		if (may_have_extra_named_params) {
10257 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10258 			ir_ref if_has_named = ir_IF(ir_AND_U8(
10259 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10260 				ir_CONST_U8(ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)));
10261 			ir_IF_TRUE_cold(if_has_named);
10262 
10263 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_extra_named_params),
10264 				ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10265 
10266 			ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10267 		}
10268 
10269 		if (opline->opcode == ZEND_DO_FCALL) {
10270 			// TODO: optimize ???
10271 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10272 			ir_ref if_release_this = ir_IF(ir_AND_U8(
10273 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10274 				ir_CONST_U8(ZEND_CALL_RELEASE_THIS >> 16)));
10275 			ir_IF_TRUE_cold(if_release_this);
10276 
10277 			// JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10278 			jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10279 
10280 			ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10281 		}
10282 
10283 
10284 		ir_ref allocated_path = IR_UNUSED;
10285 
10286 		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10287 		    !JIT_G(current_frame) ||
10288 		    !JIT_G(current_frame)->call ||
10289 		    !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10290 		    prev_opline->opcode == ZEND_SEND_UNPACK ||
10291 		    prev_opline->opcode == ZEND_SEND_ARRAY ||
10292 			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10293 
10294 			// JIT: zend_vm_stack_free_call_frame(call);
10295 			// JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10296 			ir_ref if_allocated = ir_IF(ir_AND_U8(
10297 				ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10298 				ir_CONST_U8(ZEND_CALL_ALLOCATED >> 16)));
10299 			ir_IF_TRUE_cold(if_allocated);
10300 
10301 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10302 
10303 			allocated_path = ir_END();
10304 			ir_IF_FALSE(if_allocated);
10305 		}
10306 
10307 		ir_STORE(jit_EG(vm_stack_top), rx);
10308 
10309 		if (allocated_path) {
10310 			ir_MERGE_WITH(allocated_path);
10311 		}
10312 
10313 		if (!RETURN_VALUE_USED(opline)) {
10314 			zend_class_entry *ce;
10315 			bool ce_is_instanceof;
10316 			uint32_t func_info = call_info ?
10317 				zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10318 				(MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10319 
10320 			/* If an exception is thrown, the return_value may stay at the
10321 			 * original value of null. */
10322 			func_info |= MAY_BE_NULL;
10323 
10324 			if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10325 				ir_ref sp = ir_RLOAD_A(IR_REG_SP);
10326 				res_addr = ZEND_ADDR_REF_ZVAL(sp);
10327 				jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
10328 			}
10329 			if (!jit->ctx.fixed_call_stack_size) {
10330 				// JIT: revert alloca
10331 				ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10332 			}
10333 		}
10334 
10335 		// JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10336 		ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10337 			jit_STUB_ADDR(jit, jit_stub_icall_throw));
10338 
10339 		// TODO: Can we avoid checking for interrupts after each call ???
10340 		if (trace && jit->last_valid_opline != opline) {
10341 			int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10342 
10343 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10344 			if (!exit_addr) {
10345 				return 0;
10346 			}
10347 		} else {
10348 			exit_addr = NULL;
10349 		}
10350 
10351 		if (!zend_jit_check_timeout(jit, opline + 1, exit_addr)) {
10352 			return 0;
10353 		}
10354 
10355 		if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10356 			jit_LOAD_IP_ADDR(jit, opline + 1);
10357 		} else if (trace
10358 		 && trace->op == ZEND_JIT_TRACE_END
10359 		 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
10360 			jit_LOAD_IP_ADDR(jit, opline + 1);
10361 		}
10362 	}
10363 
10364 	if (user_path) {
10365 		ir_MERGE_WITH(user_path);
10366 	}
10367 
10368 	return 1;
10369 }
10370 
10371 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)
10372 {
10373 	ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10374 
10375 	ir_IF_FALSE(if_skip_constructor);
10376 
10377 	if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10378 		if (!zend_jit_tail_handler(jit, opline)) {
10379 			return 0;
10380 		}
10381 	} else {
10382 		if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10383 			return 0;
10384 		}
10385 	}
10386 
10387     /* override predecessors of the next block */
10388 	ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10389 	if (!jit->ctx.control) {
10390 		ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10391 		ir_IF_TRUE(if_skip_constructor);
10392 		ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10393 		jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10394 	} else {
10395 		ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10396 		/* merge current control path with the true branch of constructor skip condition */
10397 		ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10398 		jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10399 
10400 		jit->b = -1;
10401 	}
10402 
10403 	return 1;
10404 }
10405 
10406 static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
10407 {
10408 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10409 	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10410 	ir_ref ref, fast_path = IR_UNUSED;
10411 
10412 	ref = jit_ZVAL_ADDR(jit, res_addr);
10413 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10414 	 && JIT_G(current_frame)
10415 	 && JIT_G(current_frame)->prev) {
10416 		zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10417 		uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10418 
10419 		if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10420 			return 1;
10421 		}
10422 	}
10423 
10424 	if (ZEND_ARG_SEND_MODE(arg_info)) {
10425 		if (opline->opcode == ZEND_RECV_INIT) {
10426 			ref = jit_ZVAL_DEREF_ref(jit, ref);
10427 		} else {
10428 			ref = jit_Z_PTR_ref(jit, ref);
10429 			ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
10430 		}
10431 	}
10432 
10433 	if (type_mask != 0) {
10434 		if (is_power_of_two(type_mask)) {
10435 			uint32_t type_code = concrete_type(type_mask);
10436 			ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10437 			ir_IF_TRUE(if_ok);
10438 			fast_path = ir_END();
10439 			ir_IF_FALSE_cold(if_ok);
10440 		} else {
10441 			ir_ref if_ok = ir_IF(ir_AND_U32(
10442 				ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10443 				ir_CONST_U32(type_mask)));
10444 			ir_IF_TRUE(if_ok);
10445 			fast_path = ir_END();
10446 			ir_IF_FALSE_cold(if_ok);
10447 		}
10448 	}
10449 
10450 	jit_SET_EX_OPLINE(jit, opline);
10451 	ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10452 		ref, ir_CONST_ADDR(arg_info));
10453 
10454 	if (check_exception) {
10455 		ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10456 	}
10457 
10458 	if (fast_path) {
10459 		ir_MERGE_WITH(fast_path);
10460 	}
10461 
10462 	return 1;
10463 }
10464 
10465 static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
10466 {
10467 	uint32_t arg_num = opline->op1.num;
10468 	zend_arg_info *arg_info = NULL;
10469 
10470 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10471 		if (EXPECTED(arg_num <= op_array->num_args)) {
10472 			arg_info = &op_array->arg_info[arg_num-1];
10473 		} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10474 			arg_info = &op_array->arg_info[op_array->num_args];
10475 		}
10476 		if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10477 			arg_info = NULL;
10478 		}
10479 	}
10480 
10481 	if (arg_info || (opline+1)->opcode != ZEND_RECV) {
10482 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10483 			if (!JIT_G(current_frame) ||
10484 			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
10485 			    arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10486 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10487 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10488 
10489 				if (!exit_addr) {
10490 					return 0;
10491 				}
10492 				ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
10493 					ir_CONST_ADDR(exit_addr));
10494 			}
10495 		} else {
10496 			ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10497 			ir_IF_FALSE_cold(if_ok);
10498 
10499 			jit_SET_EX_OPLINE(jit, opline);
10500 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_missing_arg_error), jit_FP(jit));
10501 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10502 			ir_IF_TRUE(if_ok);
10503 		}
10504 	}
10505 
10506 	if (arg_info) {
10507 		if (!zend_jit_verify_arg_type(jit, opline, arg_info, 1)) {
10508 			return 0;
10509 		}
10510 	}
10511 
10512 	return 1;
10513 }
10514 
10515 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)
10516 {
10517 	uint32_t arg_num = opline->op1.num;
10518 	zval *zv = RT_CONSTANT(opline, opline->op2);
10519 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10520 	ir_ref ref, if_fail, skip_path = IR_UNUSED;
10521 
10522 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10523 	 && JIT_G(current_frame)
10524 	 && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
10525 		if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10526 			jit_ZVAL_COPY_CONST(jit,
10527 				res_addr,
10528 				-1, -1,
10529 				zv, 1);
10530 		}
10531 	} else {
10532 		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10533 		    (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
10534 			ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10535 			ir_IF_TRUE(if_skip);
10536 			skip_path = ir_END();
10537 			ir_IF_FALSE(if_skip);
10538 		}
10539 		jit_ZVAL_COPY_CONST(jit,
10540 			res_addr,
10541 			-1, -1,
10542 			zv, 1);
10543 	}
10544 
10545 	if (Z_CONSTANT_P(zv)) {
10546 		jit_SET_EX_OPLINE(jit, opline);
10547 		ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zval_update_constant_ex),
10548 			jit_ZVAL_ADDR(jit, res_addr),
10549 			ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), offsetof(zend_op_array, scope))));
10550 
10551 		if_fail = ir_IF(ref);
10552 		ir_IF_TRUE_cold(if_fail);
10553 		jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, opline);
10554 		ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10555 		ir_IF_FALSE(if_fail);
10556 	}
10557 
10558 	if (skip_path) {
10559 		ir_MERGE_WITH(skip_path);
10560 	}
10561 
10562 	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10563 		do {
10564 			zend_arg_info *arg_info;
10565 
10566 			if (arg_num <= op_array->num_args) {
10567 				arg_info = &op_array->arg_info[arg_num-1];
10568 			} else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
10569 				arg_info = &op_array->arg_info[op_array->num_args];
10570 			} else {
10571 				break;
10572 			}
10573 			if (!ZEND_TYPE_IS_SET(arg_info->type)) {
10574 				break;
10575 			}
10576 			if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw)) {
10577 				return 0;
10578 			}
10579 		} while (0);
10580 	}
10581 
10582 	return 1;
10583 }
10584 
10585 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)
10586 {
10587 	zend_arg_info *arg_info = &op_array->arg_info[-1];
10588 	ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
10589 	zend_jit_addr op1_addr = OP1_ADDR();
10590 	bool needs_slow_check = 1;
10591 	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10592 	ir_ref fast_path = IR_UNUSED;
10593 
10594 	if (type_mask != 0) {
10595 		if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
10596 			/* pass */
10597 		} else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
10598 			needs_slow_check = 0;
10599 		} else if (is_power_of_two(type_mask)) {
10600 			uint32_t type_code = concrete_type(type_mask);
10601 			ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
10602 
10603 			ir_IF_TRUE(if_ok);
10604 			fast_path = ir_END();
10605 			ir_IF_FALSE_cold(if_ok);
10606 		} else {
10607 			ir_ref if_ok = ir_IF(ir_AND_U32(
10608 				ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
10609 				ir_CONST_U32(type_mask)));
10610 
10611 			ir_IF_TRUE(if_ok);
10612 			fast_path = ir_END();
10613 			ir_IF_FALSE_cold(if_ok);
10614 		}
10615 	}
10616 	if (needs_slow_check) {
10617 		ir_ref ref;
10618 
10619 		jit_SET_EX_OPLINE(jit, opline);
10620 		ref = jit_ZVAL_ADDR(jit, op1_addr);
10621 		if (op1_info & MAY_BE_UNDEF) {
10622 			ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1);
10623 		}
10624 
10625 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
10626 			ref,
10627 			ir_LOAD_A(jit_EX(func)),
10628 			ir_CONST_ADDR(arg_info),
10629 			ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num));
10630 
10631 		zend_jit_check_exception(jit);
10632 
10633 		if (fast_path) {
10634 			ir_MERGE_WITH(fast_path);
10635 		}
10636 	}
10637 
10638 	return 1;
10639 }
10640 
10641 static int zend_jit_leave_frame(zend_jit_ctx *jit)
10642 {
10643 	// JIT: EG(current_execute_data) = EX(prev_execute_data);
10644 	ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10645 	return 1;
10646 }
10647 
10648 static int zend_jit_free_cvs(zend_jit_ctx *jit)
10649 {
10650 	// JIT: EG(current_execute_data) = EX(prev_execute_data);
10651 	ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10652 
10653 	// JIT: zend_free_compiled_variables(execute_data);
10654 	ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_compiled_variables), jit_FP(jit));
10655 	return 1;
10656 }
10657 
10658 static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
10659 {
10660 	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10661 		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
10662 
10663 		jit_ZVAL_PTR_DTOR(jit, var_addr, info, 1, NULL);
10664 	}
10665 	return 1;
10666 }
10667 
10668 static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
10669 {
10670 	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10671 		jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, opline);
10672 	}
10673 	return 1;
10674 }
10675 
10676 static int zend_jit_leave_func(zend_jit_ctx         *jit,
10677                                const zend_op_array  *op_array,
10678                                const zend_op        *opline,
10679                                uint32_t              op1_info,
10680                                bool             left_frame,
10681                                zend_jit_trace_rec   *trace,
10682                                zend_jit_trace_info  *trace_info,
10683                                int                   indirect_var_access,
10684                                int                   may_throw)
10685 {
10686 	bool may_be_top_frame =
10687 		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10688 		!JIT_G(current_frame) ||
10689 		!TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
10690 	bool may_need_call_helper =
10691 		indirect_var_access || /* may have symbol table */
10692 		!op_array->function_name || /* may have symbol table */
10693 		may_be_top_frame ||
10694 		(op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
10695 		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10696 		!JIT_G(current_frame) ||
10697 		TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
10698 		(uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
10699 	bool may_need_release_this =
10700 		!(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
10701 		op_array->scope &&
10702 		!(op_array->fn_flags & ZEND_ACC_STATIC) &&
10703 		(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10704 		 !JIT_G(current_frame) ||
10705 		 !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
10706 	ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
10707 
10708 	if (may_need_call_helper) {
10709 		if (!left_frame) {
10710 			left_frame = 1;
10711 		    if (!zend_jit_leave_frame(jit)) {
10712 				return 0;
10713 		    }
10714 		}
10715 		/* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
10716 		call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10717 		ref = ir_AND_U32(call_info,
10718 			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));
10719 		if (trace && trace->op != ZEND_JIT_TRACE_END) {
10720 			ir_ref if_slow = ir_IF(ref);
10721 
10722 			ir_IF_TRUE_cold(if_slow);
10723 			if (!GCC_GLOBAL_REGS) {
10724 				ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit));
10725 			} else {
10726 				ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper));
10727 			}
10728 
10729 			if (may_be_top_frame) {
10730 				// TODO: try to avoid this check ???
10731 				if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
10732 #if 0
10733 					/* this check should be handled by the following OPLINE guard */
10734 					|	cmp IP, zend_jit_halt_op
10735 					|	je ->trace_halt
10736 #endif
10737 				} else if (GCC_GLOBAL_REGS) {
10738 					ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10739 				} else {
10740 					ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10741 				}
10742 			}
10743 
10744 			if (!GCC_GLOBAL_REGS) {
10745 				// execute_data = EG(current_execute_data)
10746 				jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
10747 			}
10748 			cold_path = ir_END();
10749 			ir_IF_FALSE(if_slow);
10750 		} else {
10751 			ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
10752 		}
10753 	}
10754 
10755 	if ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
10756 		if (!left_frame) {
10757 			left_frame = 1;
10758 		    if (!zend_jit_leave_frame(jit)) {
10759 				return 0;
10760 		    }
10761 		}
10762 		// JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
10763 		jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
10764 	} else if (may_need_release_this) {
10765 		ir_ref if_release, fast_path = IR_UNUSED;
10766 
10767 		if (!left_frame) {
10768 			left_frame = 1;
10769 		    if (!zend_jit_leave_frame(jit)) {
10770 				return 0;
10771 		    }
10772 		}
10773 		if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
10774 			// JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
10775 			if (!call_info) {
10776 				call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10777 			}
10778 			if_release = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_RELEASE_THIS)));
10779 			ir_IF_FALSE(if_release);
10780 			fast_path = ir_END();
10781 			ir_IF_TRUE(if_release);
10782 		}
10783 		// JIT: OBJ_RELEASE(execute_data->This))
10784 		jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
10785 		if (fast_path) {
10786 			ir_MERGE_WITH(fast_path);
10787 		}
10788 		// TODO: avoid EG(excption) check for $this->foo() calls
10789 		may_throw = 1;
10790 	}
10791 
10792 	// JIT: EG(vm_stack_top) = (zval*)execute_data
10793 	ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
10794 
10795 	// JITL execute_data = EX(prev_execute_data)
10796 	jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
10797 
10798 	if (!left_frame) {
10799 		// JIT: EG(current_execute_data) = execute_data
10800 		ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10801 	}
10802 
10803 	if (trace) {
10804 		if (trace->op != ZEND_JIT_TRACE_END
10805 		 && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
10806 			zend_jit_reset_last_valid_opline(jit);
10807 		} else {
10808 			if (GCC_GLOBAL_REGS) {
10809 				/* We add extra RLOAD and RSTORE to make fusion for persistent register
10810 				 *     mov (%FP), %IP
10811 				 *     add $0x1c, %IP
10812 				 * The naive (commented) code leads to extra register allocation and move.
10813 				 *     mov (%FP), %tmp
10814 				 *     add $0x1c, %tmp
10815 				 *     mov %tmp, %FP
10816 				 */
10817 #if 0
10818 				jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
10819 #else
10820 				jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
10821 				jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
10822 #endif
10823 			} else {
10824 				ir_ref ref = jit_EX(opline);
10825 
10826 				ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
10827 			}
10828 		}
10829 
10830 		if (cold_path) {
10831 			ir_MERGE_WITH(cold_path);
10832 		}
10833 
10834 		if (trace->op == ZEND_JIT_TRACE_BACK
10835 		 && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
10836 			const zend_op *next_opline = trace->opline;
10837 
10838 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
10839 			 && (op1_info & MAY_BE_RC1)
10840 			 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
10841 				/* exception might be thrown during destruction of unused return value */
10842 				// JIT: if (EG(exception))
10843 				ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
10844 			}
10845 			do {
10846 				trace++;
10847 			} while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
10848 			ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
10849 			next_opline = trace->opline;
10850 			ZEND_ASSERT(next_opline != NULL);
10851 
10852 			if (trace->op == ZEND_JIT_TRACE_END
10853 			 && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
10854 				trace_info->flags |= ZEND_JIT_TRACE_LOOP;
10855 
10856 				ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
10857 
10858 				ir_IF_TRUE(if_eq);
10859 				ZEND_ASSERT(jit->trace_loop_ref);
10860 				ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
10861 				ir_MERGE_SET_OP(jit->trace_loop_ref, 2, ir_END());
10862 				ir_IF_FALSE(if_eq);
10863 
10864 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
10865 				ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10866 #else
10867 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
10868 #endif
10869 			} else {
10870 				ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
10871 			}
10872 
10873 			zend_jit_set_last_valid_opline(jit, trace->opline);
10874 
10875 			return 1;
10876 		} else if (may_throw ||
10877 				(((opline->op1_type & (IS_VAR|IS_TMP_VAR))
10878 				  && (op1_info & MAY_BE_RC1)
10879 				  && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
10880 				 && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
10881 			// JIT: if (EG(exception))
10882 			ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
10883 		}
10884 
10885 		return 1;
10886 	} else {
10887 		// JIT: if (EG(exception))
10888 		ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
10889 		// JIT: opline = EX(opline) + 1
10890 		if (GCC_GLOBAL_REGS) {
10891 			jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
10892 			jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
10893 		} else {
10894 			ir_ref ref = jit_EX(opline);
10895 
10896 			ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
10897 		}
10898 	}
10899 
10900 	if (GCC_GLOBAL_REGS) {
10901 		ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10902 	} else {
10903 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
10904 	}
10905 
10906 	jit->b = -1;
10907 
10908 	return 1;
10909 }
10910 
10911 static void zend_jit_common_return(zend_jit_ctx *jit)
10912 {
10913 	ZEND_ASSERT(jit->return_inputs);
10914 	ir_MERGE_list(jit->return_inputs);
10915 }
10916 
10917 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)
10918 {
10919 	zend_jit_addr ret_addr;
10920 	int8_t return_value_used = -1;
10921 	ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
10922 
10923 	ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
10924 	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
10925 
10926 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10927 		jit->return_inputs = IR_UNUSED;
10928 		if (JIT_G(current_frame)) {
10929 			if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
10930 				return_value_used = 1;
10931 			} else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
10932 				return_value_used = 0;
10933 			} else {
10934 				return_value_used = -1;
10935 			}
10936 		}
10937 	}
10938 
10939 	if (ZEND_OBSERVER_ENABLED) {
10940 		if (Z_MODE(op1_addr) == IS_REG) {
10941 			zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
10942 
10943 			if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
10944 				return 0;
10945 			}
10946 			op1_addr = dst;
10947 		}
10948 		jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
10949 	}
10950 
10951 	// JIT: if (!EX(return_value))
10952 	return_value = ir_LOAD_A(jit_EX(return_value));
10953 	ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
10954 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
10955 	    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
10956 		if (return_value_used == -1) {
10957 			if_return_value_used = ir_IF(return_value);
10958 			ir_IF_FALSE_cold(if_return_value_used);
10959 		}
10960 		if (return_value_used != 1) {
10961 			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
10962 				ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
10963 				ir_IF_FALSE(if_refcounted);
10964 				ir_END_list(jit->return_inputs);
10965 				ir_IF_TRUE(if_refcounted);
10966 			}
10967 			ref = jit_Z_PTR(jit, op1_addr);
10968 			refcount = jit_GC_DELREF(jit, ref);
10969 
10970 			if (RC_MAY_BE_1(op1_info)) {
10971 				if (RC_MAY_BE_N(op1_info)) {
10972 					ir_ref if_non_zero = ir_IF(refcount);
10973 					ir_IF_TRUE(if_non_zero);
10974 					ir_END_list(jit->return_inputs);
10975 					ir_IF_FALSE(if_non_zero);
10976 				}
10977 				jit_ZVAL_DTOR(jit, ref, op1_info, opline);
10978 			}
10979 			if (return_value_used == -1) {
10980 				ir_END_list(jit->return_inputs);
10981 			}
10982 		}
10983 	} else if (return_value_used == -1) {
10984 		if_return_value_used = ir_IF(return_value);
10985 		ir_IF_FALSE_cold(if_return_value_used);
10986 		ir_END_list(jit->return_inputs);
10987 	}
10988 
10989 	if (if_return_value_used) {
10990 		ir_IF_TRUE(if_return_value_used);
10991 	}
10992 
10993 	if (return_value_used == 0) {
10994 		if (jit->return_inputs) {
10995 			ZEND_ASSERT(JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE);
10996 			ir_END_list(jit->return_inputs);
10997 			ir_MERGE_list(jit->return_inputs);
10998 			jit->return_inputs = IR_UNUSED;
10999 		}
11000 		return 1;
11001 	}
11002 
11003 	if (opline->op1_type == IS_CONST) {
11004 		zval *zv = RT_CONSTANT(opline, opline->op1);
11005 
11006 		jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
11007 	} else if (opline->op1_type == IS_TMP_VAR) {
11008 		jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11009 	} else if (opline->op1_type == IS_CV) {
11010 		if (op1_info & MAY_BE_REF) {
11011 			ref = jit_ZVAL_ADDR(jit, op1_addr);
11012 			ref = jit_ZVAL_DEREF_ref(jit, ref);
11013 			op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11014 		}
11015 
11016 		if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11017 			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11018 			    (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11019 			    !op_array->function_name) {
11020 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 1);
11021 			} else if (return_value_used != 1) {
11022 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11023 				// JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11024 				jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11025 			} else {
11026 				jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11027 			}
11028 		} else {
11029 			jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11030 		}
11031 	} else {
11032 		if (op1_info & MAY_BE_REF) {
11033 			ir_ref if_ref, ref2, if_non_zero;
11034 			zend_jit_addr ref_addr;
11035 
11036 			if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11037 			ir_IF_TRUE_cold(if_ref);
11038 
11039 			// JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11040 			ref = jit_Z_PTR(jit, op1_addr);
11041 
11042 			// JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11043 			ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
11044 			ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11045 			jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, 0);
11046 			ref2 = jit_GC_DELREF(jit, ref);
11047 			if_non_zero = ir_IF(ref2);
11048 			ir_IF_TRUE(if_non_zero);
11049 
11050 			// JIT: if (IS_REFCOUNTED())
11051 			ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11052 			ir_IF_FALSE(if_refcounted);
11053 			ir_END_list(jit->return_inputs);
11054 			ir_IF_TRUE(if_refcounted);
11055 
11056 			// JIT: ADDREF
11057 			ref2 = jit_Z_PTR(jit, ret_addr);
11058 			jit_GC_ADDREF(jit, ref2);
11059 			ir_END_list(jit->return_inputs);
11060 
11061 			ir_IF_FALSE(if_non_zero);
11062 
11063 			jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11064 			ir_END_list(jit->return_inputs);
11065 
11066 			ir_IF_FALSE(if_ref);
11067 		}
11068 		jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11069 	}
11070 
11071 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11072 		if (jit->return_inputs) {
11073 			ir_END_list(jit->return_inputs);
11074 			ir_MERGE_list(jit->return_inputs);
11075 			jit->return_inputs = IR_UNUSED;
11076 		}
11077 	} else {
11078 		ir_END_list(jit->return_inputs);
11079 		jit->b = -1;
11080 	}
11081 
11082 	return 1;
11083 }
11084 
11085 static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11086 {
11087 	zend_jit_addr op1_addr = OP1_ADDR();
11088 	zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11089 	ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11090 	ir_ref if_fit, if_reference, if_same_key, fast_path;
11091 	ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11092 
11093 	// JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11094 	cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11095 	idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11096 
11097 	// JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11098 	num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11099 		ir_CONST_U32(sizeof(Bucket)));
11100 	if (sizeof(void*) == 8) {
11101 		num_used_ref = ir_ZEXT_A(num_used_ref);
11102 	}
11103 	if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11104 	ir_IF_FALSE_cold(if_fit);
11105 	ir_END_list(slow_inputs);
11106 	ir_IF_TRUE(if_fit);
11107 
11108 	// JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11109 	bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11110 	if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11111 	ir_IF_FALSE_cold(if_reference);
11112 	ir_END_list(slow_inputs);
11113 	ir_IF_TRUE(if_reference);
11114 
11115 	// JIT: (EXPECTED(p->key == varname))
11116 	if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11117 	ir_IF_FALSE_cold(if_same_key);
11118 	ir_END_list(slow_inputs);
11119 	ir_IF_TRUE(if_same_key);
11120 
11121 	// JIT: GC_ADDREF(Z_PTR(p->val))
11122 	ref = jit_Z_PTR_ref(jit, bucket_ref);
11123 	jit_GC_ADDREF(jit, ref);
11124 
11125 	fast_path = ir_END();
11126 	ir_MERGE_list(slow_inputs);
11127 
11128 	ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11129 		ir_CONST_ADDR(varname),
11130 		cache_slot_ref);
11131 
11132 	ir_MERGE_WITH(fast_path);
11133 	ref = ir_PHI_2(IR_ADDR, ref2, ref);
11134 
11135 	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11136 		ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11137 
11138 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11139 			// JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11140 			if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11141 			ir_IF_TRUE_cold(if_refcounted);
11142 		}
11143 
11144 		// JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11145 		ref2 = jit_Z_PTR(jit, op1_addr);
11146 
11147 		// JIT: ZVAL_REF(variable_ptr, ref)
11148 		jit_set_Z_PTR(jit, op1_addr, ref);
11149 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11150 
11151 		// JIT: if (GC_DELREF(garbage) == 0)
11152 		refcount = jit_GC_DELREF(jit, ref2);
11153 		if_non_zero = ir_IF(refcount);
11154 		if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11155 			ir_IF_TRUE(if_non_zero);
11156 			ir_END_list(end_inputs);
11157 		}
11158 		ir_IF_FALSE(if_non_zero);
11159 
11160 		jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11161 		if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11162 			ir_END_list(end_inputs);
11163 			ir_IF_TRUE(if_non_zero);
11164 
11165 			// JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11166 			if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11167 			ir_IF_TRUE(if_may_not_leak);
11168 			ir_END_list(end_inputs);
11169 			ir_IF_FALSE(if_may_not_leak);
11170 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref2);
11171 		}
11172 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11173 			ir_END_list(end_inputs);
11174 			ir_IF_FALSE(if_refcounted);
11175 		}
11176 	}
11177 
11178 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11179 		// JIT: ZVAL_REF(variable_ptr, ref)
11180 		jit_set_Z_PTR(jit, op1_addr, ref);
11181 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11182 	}
11183 
11184 	if (end_inputs) {
11185 		ir_END_list(end_inputs);
11186 		ir_MERGE_list(end_inputs);
11187 	}
11188 
11189 	return 1;
11190 }
11191 
11192 static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11193 {
11194 	zend_jit_addr op1_addr = OP1_ADDR();
11195 
11196 	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11197 		if (may_throw) {
11198 			jit_SET_EX_OPLINE(jit, opline);
11199 		}
11200 		if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11201 			ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11202 
11203 			if (op1_info & MAY_BE_ARRAY) {
11204 				if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11205 				ir_IF_TRUE(if_array);
11206 				ir_END_list(end_inputs);
11207 				ir_IF_FALSE(if_array);
11208 			}
11209 			ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11210 			if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11211 			ir_IF_TRUE(if_exists);
11212 			ir_END_list(end_inputs);
11213 			ir_IF_FALSE(if_exists);
11214 
11215 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_hash_iterator_del), ref);
11216 
11217 			ir_END_list(end_inputs);
11218 			ir_MERGE_list(end_inputs);
11219 		}
11220 
11221 		jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11222 
11223 		if (may_throw) {
11224 			zend_jit_check_exception(jit);
11225 		}
11226 	}
11227 
11228 	return 1;
11229 }
11230 
11231 static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11232 {
11233 	if (opline->op1_type == IS_CONST) {
11234 		zval *zv;
11235 		size_t len;
11236 
11237 		zv = RT_CONSTANT(opline, opline->op1);
11238 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11239 		len = Z_STRLEN_P(zv);
11240 
11241 		if (len > 0) {
11242 			const char *str = Z_STRVAL_P(zv);
11243 
11244 			jit_SET_EX_OPLINE(jit, opline);
11245 			ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11246 				ir_CONST_ADDR(str), ir_CONST_ADDR(len));
11247 
11248 			zend_jit_check_exception(jit);
11249 		}
11250 	} else {
11251 		zend_jit_addr op1_addr = OP1_ADDR();
11252 		ir_ref ref;
11253 
11254 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11255 
11256 		jit_SET_EX_OPLINE(jit, opline);
11257 
11258 		ref = jit_Z_PTR(jit, op1_addr);
11259 		ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11260 			ir_ADD_OFFSET(ref, offsetof(zend_string, val)),
11261 			ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_string, len))));
11262 
11263 		if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11264 			jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11265 		}
11266 
11267 		zend_jit_check_exception(jit);
11268 	}
11269 	return 1;
11270 }
11271 
11272 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)
11273 {
11274 	if (opline->op1_type == IS_CONST) {
11275 		zval *zv;
11276 		size_t len;
11277 
11278 		zv = RT_CONSTANT(opline, opline->op1);
11279 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11280 		len = Z_STRLEN_P(zv);
11281 
11282 		jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11283 		if (Z_MODE(res_addr) != IS_REG) {
11284 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11285 		} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11286 			return 0;
11287 		}
11288 	} else {
11289 		ir_ref ref;
11290 
11291 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11292 
11293 		ref = jit_Z_PTR(jit, op1_addr);
11294 		ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(zend_string, len)));
11295 		jit_set_Z_LVAL(jit, res_addr, ref);
11296 
11297 		if (Z_MODE(res_addr) == IS_REG) {
11298 			if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11299 				return 0;
11300 			}
11301 		} else {
11302 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11303 		}
11304 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11305 	}
11306 	return 1;
11307 }
11308 
11309 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)
11310 {
11311 	if (opline->op1_type == IS_CONST) {
11312 		zval *zv;
11313 		zend_long count;
11314 
11315 		zv = RT_CONSTANT(opline, opline->op1);
11316 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
11317 		count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11318 
11319 		jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11320 		if (Z_MODE(res_addr) != IS_REG) {
11321 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11322 		} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11323 			return 0;
11324 		}
11325 	} else {
11326 		ir_ref ref;
11327 
11328 		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
11329 		// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11330 
11331 		ref = jit_Z_PTR(jit, op1_addr);
11332 		if (sizeof(void*) == 8) {
11333 			ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11334 			ref = ir_ZEXT_L(ref);
11335 		} else {
11336 			ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11337 		}
11338 		jit_set_Z_LVAL(jit, res_addr, ref);
11339 
11340 		if (Z_MODE(res_addr) == IS_REG) {
11341 			if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11342 				return 0;
11343 			}
11344 		} else {
11345 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11346 		}
11347 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11348 	}
11349 
11350 	if (may_throw) {
11351 		zend_jit_check_exception(jit);
11352 	}
11353 	return 1;
11354 }
11355 
11356 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)
11357 {
11358 	HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11359 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11360 	ir_ref ref;
11361 
11362 	ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11363 	ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
11364 
11365 	// JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11366 	if (opline->op1_type != IS_CONST) {
11367 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find),
11368 			ir_CONST_ADDR(ht),
11369 			jit_Z_PTR(jit, op1_addr));
11370 	} else {
11371 		zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11372 
11373 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash),
11374 			ir_CONST_ADDR(ht), ir_CONST_ADDR(str));
11375 	}
11376 
11377 	if (exit_addr) {
11378 		if (smart_branch_opcode == ZEND_JMPZ) {
11379 			ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11380 		} else {
11381 			ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11382 		}
11383 	} else if (smart_branch_opcode) {
11384 		zend_basic_block *bb;
11385 
11386 		ZEND_ASSERT(jit->b >= 0);
11387 		bb = &jit->ssa->cfg.blocks[jit->b];
11388 		ZEND_ASSERT(bb->successors_count == 2);
11389 		ref = jit_IF_ex(jit, ref,
11390 			(smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11391 		_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11392 		_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11393 		jit->b = -1;
11394 	} else {
11395 		jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11396 			ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, IR_NULL)), ir_CONST_U32(IS_FALSE)));
11397 	}
11398 
11399 	return 1;
11400 }
11401 
11402 static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11403 {
11404 	uint32_t offset;
11405 
11406 	offset = (opline->opcode == ZEND_ROPE_INIT) ?
11407 		opline->result.var :
11408 		opline->op1.var + opline->extended_value * sizeof(zend_string*);
11409 
11410 	if (opline->op2_type == IS_CONST) {
11411 		zval *zv = RT_CONSTANT(opline, opline->op2);
11412 		zend_string *str;
11413 
11414 		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11415 		str = Z_STR_P(zv);
11416 
11417 		ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11418 	} else {
11419 		zend_jit_addr op2_addr = OP2_ADDR();
11420 		ir_ref ref;
11421 
11422 		ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11423 
11424 		ref = jit_Z_PTR(jit, op2_addr);
11425 		ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11426 		if (opline->op2_type == IS_CV) {
11427 			ir_ref if_refcounted, long_path;
11428 
11429 			if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11430 			ir_IF_TRUE(if_refcounted);
11431 			jit_GC_ADDREF(jit, ref);
11432 			long_path = ir_END();
11433 
11434 			ir_IF_FALSE(if_refcounted);
11435 			ir_MERGE_WITH(long_path);
11436 		}
11437 	}
11438 
11439 	if (opline->opcode == ZEND_ROPE_END) {
11440 		zend_jit_addr res_addr = RES_ADDR();
11441 		ir_ref ref;
11442 
11443 		ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11444 			ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11445 			ir_CONST_U32(opline->extended_value));
11446 
11447 		jit_set_Z_PTR(jit, res_addr, ref);
11448 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11449 	}
11450 
11451 	return 1;
11452 }
11453 
11454 static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
11455 {
11456 	ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
11457 	ir_refs *merge_inputs, *types, *ptrs;
11458 #if SIZEOF_ZEND_LONG == 4
11459 	ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
11460 	ir_refs *values; /* we need this only for zval.w2 copy */
11461 #endif
11462 
11463 	ir_refs_init(merge_inputs, 4);
11464 	ir_refs_init(types, 4);
11465 	ir_refs_init(ptrs, 4);
11466 #if SIZEOF_ZEND_LONG == 4
11467 	ir_refs_init(values, 4);
11468 #endif
11469 
11470 	// JIT: ptr = Z_PTR_P(val);
11471 	ptr = jit_Z_PTR(jit, val_addr);
11472 
11473 	// JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11474 	if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11475 	ir_IF_FALSE_cold(if_refcounted);
11476 	ir_refs_add(merge_inputs, ir_END());
11477 	ir_refs_add(types, type);
11478 	ir_refs_add(ptrs, ptr);
11479 #if SIZEOF_ZEND_LONG == 4
11480 	ir_refs_add(values, val);
11481 #endif
11482 
11483 	ir_IF_TRUE(if_refcounted);
11484 
11485 	// JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
11486 	if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
11487 //	if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
11488 	ir_IF_TRUE(if_reference);
11489 
11490 	// JIT:	val = Z_REFVAL_P(val);
11491 	val2 = ir_ADD_OFFSET(ptr, offsetof(zend_reference, val));
11492 	type2 = jit_Z_TYPE_INFO_ref(jit, val2);
11493 	ptr2 = jit_Z_PTR_ref(jit, val2);
11494 
11495 	// JIT:	if (Z_OPT_REFCOUNTED_P(val)) {
11496 	if_refcounted2 = ir_IF(ir_AND_U32(type2, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11497 	ir_IF_FALSE_cold(if_refcounted2);
11498 	ir_refs_add(merge_inputs, ir_END());
11499 	ir_refs_add(types, type2);
11500 	ir_refs_add(ptrs, ptr2);
11501 #if SIZEOF_ZEND_LONG == 4
11502 	ir_refs_add(values, val2);
11503 #endif
11504 
11505 	ir_IF_TRUE(if_refcounted2);
11506 	ir_MERGE_WITH_EMPTY_FALSE(if_reference);
11507 	type = ir_PHI_2(IR_U32, type2, type);
11508 	ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
11509 #if SIZEOF_ZEND_LONG == 4
11510 	val = ir_PHI_2(IR_ADDR, val2, val);
11511 #endif
11512 
11513 	// JIT:	Z_ADDREF_P(val);
11514 	jit_GC_ADDREF(jit, ptr);
11515 	ir_refs_add(merge_inputs, ir_END());
11516 	ir_refs_add(types, type);
11517 	ir_refs_add(ptrs, ptr);
11518 #if SIZEOF_ZEND_LONG == 4
11519 	ir_refs_add(values, val);
11520 #endif
11521 
11522 	ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
11523 	type = ir_PHI_N(IR_U32, types->count, types->refs);
11524 	ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
11525 #if SIZEOF_ZEND_LONG == 4
11526 	val = ir_PHI_N(IR_ADDR, values->count, values->refs);
11527 	val_addr = ZEND_ADDR_REF_ZVAL(val);
11528 #endif
11529 
11530 	// JIT: Z_PTR_P(res) = ptr;
11531 	jit_set_Z_PTR(jit, res_addr, ptr);
11532 #if SIZEOF_ZEND_LONG == 4
11533 	jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
11534 #endif
11535 	jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
11536 
11537 	return 1;
11538 }
11539 
11540 static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx  *jit,
11541                                                   const zend_op *opline,
11542                                                   uint32_t       type,
11543                                                   uint32_t       op1_info,
11544                                                   uint32_t       op2_info,
11545                                                   zend_jit_addr  op2_addr,
11546                                                   zend_ssa_range *op2_range,
11547                                                   uint8_t        dim_type,
11548                                                   const void    *found_exit_addr,
11549                                                   const void    *not_found_exit_addr,
11550                                                   const void    *exit_addr,
11551                                                   bool           result_type_guard,
11552                                                   ir_ref         ht_ref,
11553                                                   ir_refs       *found_inputs,
11554                                                   ir_refs       *found_vals,
11555                                                   ir_ref        *end_inputs,
11556                                                   ir_ref        *not_found_inputs)
11557 {
11558 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11559 	ir_ref ref = IR_UNUSED, cond, if_found;
11560 	ir_ref if_type = IS_UNUSED;
11561 	ir_refs *test_zval_inputs, *test_zval_values;
11562 
11563 	ir_refs_init(test_zval_inputs, 4);
11564 	ir_refs_init(test_zval_values, 4);
11565 
11566 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11567 	 && type == BP_VAR_R
11568 	 && !exit_addr) {
11569 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11570 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11571 		if (!exit_addr) {
11572 			return 0;
11573 		}
11574 	}
11575 
11576 	if (op2_info & MAY_BE_LONG) {
11577 		bool op2_loaded = 0;
11578 		bool packed_loaded = 0;
11579 		bool bad_packed_key = 0;
11580 		ir_ref if_packed = IS_UNDEF;
11581 		ir_ref h = IR_UNUSED;
11582 		ir_ref idx_not_found_inputs = IR_UNUSED;
11583 
11584 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
11585 			// JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
11586 			if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
11587 			ir_IF_TRUE(if_type);
11588 		}
11589 		if (op1_info & MAY_BE_PACKED_GUARD) {
11590 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
11591 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11592 
11593 			if (!exit_addr) {
11594 				return 0;
11595 			}
11596 			cond = ir_AND_U32(
11597 				ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11598 				ir_CONST_U32(HASH_FLAG_PACKED));
11599 			if (op1_info & MAY_BE_ARRAY_PACKED) {
11600 				ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11601 			} else {
11602 				ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
11603 			}
11604 		}
11605 		if (type == BP_VAR_W) {
11606 			// JIT: hval = Z_LVAL_P(dim);
11607 			h = jit_Z_LVAL(jit, op2_addr);
11608 			op2_loaded = 1;
11609 		}
11610 		if (op1_info & MAY_BE_ARRAY_PACKED) {
11611 			zend_long val = -1;
11612 
11613 			if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
11614 				val = Z_LVAL_P(Z_ZV(op2_addr));
11615 				if (val >= 0 && val < HT_MAX_SIZE) {
11616 					packed_loaded = 1;
11617 				} else {
11618 					bad_packed_key = 1;
11619 				}
11620 				h = ir_CONST_LONG(val);
11621 			} else {
11622 				if (!op2_loaded) {
11623 					// JIT: hval = Z_LVAL_P(dim);
11624 					h = jit_Z_LVAL(jit, op2_addr);
11625 					op2_loaded = 1;
11626 				}
11627 				packed_loaded = 1;
11628 			}
11629 
11630 			if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
11631 				/* don't generate "fast" code for packed array */
11632 				packed_loaded = 0;
11633 			}
11634 
11635 			if (packed_loaded) {
11636 				// JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
11637 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11638 					if_packed = ir_IF(
11639 						ir_AND_U32(
11640 							ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11641 							ir_CONST_U32(HASH_FLAG_PACKED)));
11642 					ir_IF_TRUE(if_packed);
11643 				}
11644 				// JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
11645 				ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
11646 #if SIZEOF_ZEND_LONG == 8
11647 				if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
11648 				 || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
11649 					/* comapre only the lower 32-bits to allow load fusion on x86_64 */
11650 					cond = ir_ULT(ir_TRUNC_U32(h), ref);
11651 				} else {
11652 					cond = ir_ULT(h, ir_ZEXT_L(ref));
11653 				}
11654 #else
11655 				cond = ir_ULT(h, ref);
11656 #endif
11657 				if (type == BP_JIT_IS) {
11658 					if (not_found_exit_addr) {
11659 						ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11660 					} else {
11661 						ir_ref if_fit = ir_IF(cond);
11662 						ir_IF_FALSE(if_fit);
11663 						ir_END_list(*end_inputs);
11664 						ir_IF_TRUE(if_fit);
11665 					}
11666 				} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11667 					ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11668 				} else if (type == BP_VAR_IS && not_found_exit_addr) {
11669 					ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11670 				} else if (type == BP_VAR_RW && not_found_exit_addr) {
11671 					ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11672 				} else if (type == BP_VAR_IS && result_type_guard) {
11673 					ir_ref if_fit = ir_IF(cond);
11674 					ir_IF_FALSE(if_fit);
11675 					ir_END_list(*not_found_inputs);
11676 					ir_IF_TRUE(if_fit);
11677 				} else {
11678 					ir_ref if_fit = ir_IF(cond);
11679 					ir_IF_FALSE(if_fit);
11680 					ir_END_list(idx_not_found_inputs);
11681 					ir_IF_TRUE(if_fit);
11682 				}
11683 				// JIT: _ret = &_ht->arPacked[h];
11684 				ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
11685 				ref = ir_BITCAST_A(ref);
11686 				ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
11687 				if (type == BP_JIT_IS) {
11688 					ir_refs_add(test_zval_values, ref);
11689 					ir_refs_add(test_zval_inputs, ir_END());
11690 				}
11691 			}
11692 		}
11693 		switch (type) {
11694 			case BP_JIT_IS:
11695 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11696 					if (if_packed) {
11697 						ir_IF_FALSE(if_packed);
11698 						if_packed = IR_UNUSED;
11699 					}
11700 					if (!op2_loaded) {
11701 						// JIT: hval = Z_LVAL_P(dim);
11702 						h = jit_Z_LVAL(jit, op2_addr);
11703 					}
11704 					if (packed_loaded) {
11705 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11706 					} else {
11707 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11708 					}
11709 					if (not_found_exit_addr) {
11710 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11711 					} else {
11712 						if_found = ir_IF(ref);
11713 						ir_IF_FALSE(if_found);
11714 						ir_END_list(*end_inputs);
11715 						ir_IF_TRUE(if_found);
11716 					}
11717 					ir_refs_add(test_zval_values, ref);
11718 					ir_refs_add(test_zval_inputs, ir_END());
11719 				} else if (!not_found_exit_addr && !packed_loaded) {
11720 					ir_END_list(*end_inputs);
11721 				}
11722 				break;
11723 			case BP_VAR_R:
11724 			case BP_VAR_IS:
11725 			case BP_VAR_UNSET:
11726 				if (packed_loaded) {
11727 					ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
11728 
11729 					if (result_type_guard) {
11730 						/* perform IS_UNDEF check only after result type guard (during deoptimization) */
11731 					} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11732 						ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
11733 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11734 						ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
11735 					} else {
11736 						ir_ref if_def = ir_IF(type_ref);
11737 						ir_IF_FALSE(if_def);
11738 						ir_END_list(idx_not_found_inputs);
11739 						ir_IF_TRUE(if_def);
11740 					}
11741 					ir_refs_add(found_inputs, ir_END());
11742 					ir_refs_add(found_vals, ref);
11743 				}
11744 				if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11745 					if (if_packed) {
11746 						ir_IF_FALSE(if_packed);
11747 						if_packed = IR_UNUSED;
11748 					}
11749 					if (!op2_loaded) {
11750 						// JIT: hval = Z_LVAL_P(dim);
11751 						h = jit_Z_LVAL(jit, op2_addr);
11752 					}
11753 					if (packed_loaded) {
11754 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11755 					} else {
11756 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11757 					}
11758 					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11759 						ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11760 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11761 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11762 					} else if (type == BP_VAR_IS && result_type_guard) {
11763 						if_found = ir_IF(ref);
11764 						ir_IF_FALSE(if_found);
11765 						ir_END_list(*not_found_inputs);
11766 						ir_IF_TRUE(if_found);
11767 					} else {
11768 						if_found = ir_IF(ref);
11769 						ir_IF_FALSE(if_found);
11770 						ir_END_list(idx_not_found_inputs);
11771 						ir_IF_TRUE(if_found);
11772 					}
11773 					ir_refs_add(found_inputs, ir_END());
11774 					ir_refs_add(found_vals, ref);
11775 				} else if (!packed_loaded) {
11776 					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11777 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
11778 					} else if (type == BP_VAR_IS && not_found_exit_addr) {
11779 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
11780 					} else if (type == BP_VAR_IS && result_type_guard) {
11781 						ir_END_list(*not_found_inputs);
11782 					} else {
11783 						ir_END_list(idx_not_found_inputs);
11784 					}
11785 				}
11786 
11787 				if (idx_not_found_inputs) {
11788 					ir_MERGE_list(idx_not_found_inputs);
11789 					switch (type) {
11790 						case BP_VAR_R:
11791 							ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
11792 							// JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
11793 							// JIT: retval = &EG(uninitialized_zval);
11794 							jit_SET_EX_OPLINE(jit, opline);
11795 							ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
11796 							ir_END_list(*end_inputs);
11797 							break;
11798 						case BP_VAR_IS:
11799 						case BP_VAR_UNSET:
11800 							if (!not_found_exit_addr) {
11801 								// JIT: retval = &EG(uninitialized_zval);
11802 								jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
11803 								ir_END_list(*end_inputs);
11804 							}
11805 							break;
11806 						default:
11807 							ZEND_UNREACHABLE();
11808 					}
11809                 }
11810 				break;
11811 			case BP_VAR_RW:
11812 				if (packed_loaded) {
11813 					if (not_found_exit_addr) {
11814 						ir_refs_add(found_inputs, ir_END());
11815 						ir_refs_add(found_vals, ref);
11816 					} else {
11817 						ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
11818 						ir_IF_TRUE(if_def);
11819 						ir_refs_add(found_inputs, ir_END());
11820 						ir_refs_add(found_vals, ref);
11821 						ir_IF_FALSE_cold(if_def);
11822 						ir_END_list(idx_not_found_inputs);
11823 					}
11824 				}
11825 				if (!packed_loaded ||
11826 						!not_found_exit_addr ||
11827 						(op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
11828 					if (if_packed) {
11829 						ir_IF_FALSE(if_packed);
11830 						if_packed = IR_UNUSED;
11831 						ir_END_list(idx_not_found_inputs);
11832 					} else if (!packed_loaded) {
11833 						ir_END_list(idx_not_found_inputs);
11834 					}
11835 
11836 					ir_MERGE_list(idx_not_found_inputs);
11837 					if (!op2_loaded) {
11838 						// JIT: hval = Z_LVAL_P(dim);
11839 						h = jit_Z_LVAL(jit, op2_addr);
11840 					}
11841 					if (packed_loaded) {
11842 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
11843 							ht_ref, h);
11844 					} else {
11845 						ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
11846 					}
11847 					if (not_found_exit_addr) {
11848 						ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11849 					} else {
11850 						if_found = ir_IF(ref);
11851 						ir_IF_FALSE(if_found);
11852 						ir_END_list(*end_inputs);
11853 						ir_IF_TRUE(if_found);
11854 					}
11855 					ir_refs_add(found_inputs, ir_END());
11856 					ir_refs_add(found_vals, ref);
11857 				}
11858 				break;
11859 			case BP_VAR_W:
11860 				if (packed_loaded) {
11861 					ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
11862 					ir_IF_TRUE_cold(if_def);
11863 					ir_refs_add(found_inputs, ir_END());
11864 					ir_refs_add(found_vals, ref);
11865 					ir_IF_FALSE(if_def);
11866 					ir_END_list(idx_not_found_inputs);
11867 				}
11868 				if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
11869 					if (if_packed) {
11870 						ir_IF_FALSE(if_packed);
11871 						if_packed = IR_UNUSED;
11872 						ir_END_list(idx_not_found_inputs);
11873 					} else if (!packed_loaded) {
11874 						ir_END_list(idx_not_found_inputs);
11875 					}
11876 					ir_MERGE_list(idx_not_found_inputs);
11877 					if (!op2_loaded) {
11878 						// JIT: hval = Z_LVAL_P(dim);
11879 						h = jit_Z_LVAL(jit, op2_addr);
11880 					}
11881 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
11882 					ir_refs_add(found_inputs, ir_END());
11883 					ir_refs_add(found_vals, ref);
11884 				}
11885 				break;
11886 			default:
11887 				ZEND_UNREACHABLE();
11888 		}
11889 	}
11890 
11891 	if (op2_info & MAY_BE_STRING) {
11892 		ir_ref key;
11893 
11894 		if (if_type) {
11895 			ir_IF_FALSE(if_type);
11896 			if_type = IS_UNUSED;
11897 		}
11898 
11899 		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
11900 			// JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
11901 			if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
11902 			ir_IF_TRUE(if_type);
11903 		}
11904 
11905 		// JIT: offset_key = Z_STR_P(dim);
11906 		key = jit_Z_PTR(jit, op2_addr);
11907 
11908 		// JIT: retval = zend_hash_find(ht, offset_key);
11909 		switch (type) {
11910 			case BP_JIT_IS:
11911 				if (opline->op2_type != IS_CONST) {
11912 					ir_ref if_num, end1, ref2;
11913 
11914 					if_num = ir_IF(
11915 						ir_ULE(
11916 							ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
11917 							ir_CONST_CHAR('9')));
11918 					ir_IF_TRUE_cold(if_num);
11919 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
11920 					end1 = ir_END();
11921 					ir_IF_FALSE(if_num);
11922 					ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
11923 					ir_MERGE_WITH(end1);
11924 					ref = ir_PHI_2(IR_ADDR, ref2, ref);
11925 				} else {
11926 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
11927 				}
11928 				if (not_found_exit_addr) {
11929 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11930 				} else {
11931 					if_found = ir_IF(ref);
11932 					ir_IF_FALSE(if_found);
11933 					ir_END_list(*end_inputs);
11934 					ir_IF_TRUE(if_found);
11935 				}
11936 				ir_refs_add(test_zval_values, ref);
11937 				ir_refs_add(test_zval_inputs, ir_END());
11938 				break;
11939 			case BP_VAR_R:
11940 			case BP_VAR_IS:
11941 			case BP_VAR_UNSET:
11942 				if (opline->op2_type != IS_CONST) {
11943 					ir_ref if_num, end1, ref2;
11944 
11945 					if_num = ir_IF(
11946 						ir_ULE(
11947 							ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
11948 							ir_CONST_CHAR('9')));
11949 					ir_IF_TRUE_cold(if_num);
11950 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
11951 					end1 = ir_END();
11952 					ir_IF_FALSE(if_num);
11953 					ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
11954 					ir_MERGE_WITH(end1);
11955 					ref = ir_PHI_2(IR_ADDR, ref2, ref);
11956 				} else {
11957 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
11958 				}
11959 				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11960 					ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11961 				} else if (type == BP_VAR_IS && not_found_exit_addr) {
11962 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11963 				} else if (type == BP_VAR_IS && result_type_guard) {
11964 					if_found = ir_IF(ref);
11965 					ir_IF_FALSE(if_found);
11966 					ir_END_list(*not_found_inputs);
11967 					ir_IF_TRUE(if_found);
11968 				} else {
11969 					if_found = ir_IF(ref);
11970 					switch (type) {
11971 						case BP_VAR_R:
11972 							ir_IF_FALSE_cold(if_found);
11973 							// JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
11974 							jit_SET_EX_OPLINE(jit, opline);
11975 							ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
11976 							ir_END_list(*end_inputs);
11977 							break;
11978 						case BP_VAR_IS:
11979 						case BP_VAR_UNSET:
11980 							ir_IF_FALSE(if_found);
11981 							// JIT: retval = &EG(uninitialized_zval);
11982 							jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
11983 							ir_END_list(*end_inputs);
11984 							break;
11985 						default:
11986 							ZEND_UNREACHABLE();
11987 					}
11988 					ir_IF_TRUE(if_found);
11989 				}
11990 				ir_refs_add(found_inputs, ir_END());
11991 				ir_refs_add(found_vals, ref);
11992 				break;
11993 			case BP_VAR_RW:
11994 				if (opline->op2_type != IS_CONST) {
11995 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
11996 				} else {
11997 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
11998 				}
11999 				if (not_found_exit_addr) {
12000 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12001 				} else {
12002 					if_found = ir_IF(ref);
12003 					ir_IF_FALSE(if_found);
12004 					ir_END_list(*end_inputs);
12005 					ir_IF_TRUE(if_found);
12006 				}
12007 				ir_refs_add(found_inputs, ir_END());
12008 				ir_refs_add(found_vals, ref);
12009 				break;
12010 			case BP_VAR_W:
12011 				if (opline->op2_type != IS_CONST) {
12012 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12013 				} else {
12014 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12015 				}
12016 				ir_refs_add(found_inputs, ir_END());
12017 				ir_refs_add(found_vals, ref);
12018 				break;
12019 			default:
12020 				ZEND_UNREACHABLE();
12021 		}
12022 	}
12023 
12024 	if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12025 	    if (if_type) {
12026 			ir_IF_FALSE_cold(if_type);
12027 			if_type = IS_UNDEF;
12028 		}
12029 		if (type != BP_VAR_RW) {
12030 			jit_SET_EX_OPLINE(jit, opline);
12031 		}
12032 		ref = jit_ZVAL_ADDR(jit, op2_addr);
12033 		switch (type) {
12034 			case BP_VAR_R:
12035 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12036 					ht_ref,
12037 					ref,
12038 					jit_ZVAL_ADDR(jit, res_addr));
12039 				ir_END_list(*end_inputs);
12040 				break;
12041 			case BP_JIT_IS:
12042 				ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12043 				if (not_found_exit_addr) {
12044 					ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12045 					ir_refs_add(found_inputs, ir_END());
12046 				} else if (found_exit_addr) {
12047 					ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12048 					ir_END_list(*end_inputs);
12049 				} else {
12050 					if_found = ir_IF(ref);
12051 					ir_IF_TRUE(if_found);
12052 					ir_refs_add(found_inputs, ir_END());
12053 					ir_IF_FALSE(if_found);
12054 					ir_END_list(*end_inputs);
12055 				}
12056 				break;
12057 			case BP_VAR_IS:
12058 			case BP_VAR_UNSET:
12059 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12060 					ht_ref,
12061 					ref,
12062 					jit_ZVAL_ADDR(jit, res_addr));
12063 				ir_END_list(*end_inputs);
12064 				break;
12065 			case BP_VAR_RW:
12066 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12067 				if_found = ir_IF(ref);
12068 				ir_IF_TRUE(if_found);
12069 				ir_refs_add(found_inputs, ir_END());
12070 				ir_refs_add(found_vals, ref);
12071 				ir_IF_FALSE(if_found);
12072 				ir_END_list(*end_inputs);
12073 				break;
12074 			case BP_VAR_W:
12075 				ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12076 				if_found = ir_IF(ref);
12077 				ir_IF_TRUE(if_found);
12078 				ir_refs_add(found_inputs, ir_END());
12079 				ir_refs_add(found_vals, ref);
12080 				ir_IF_FALSE(if_found);
12081 				ir_END_list(*end_inputs);
12082 				break;
12083 			default:
12084 				ZEND_UNREACHABLE();
12085 		}
12086 	}
12087 
12088 	if (type == BP_JIT_IS
12089 	 && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12090 	 	/* dead code */
12091 		ir_END_list(*end_inputs);
12092 	} else if (type == BP_JIT_IS
12093 	 && (op1_info & MAY_BE_ARRAY)
12094 	 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12095 	 && test_zval_inputs->count) {
12096 
12097 		ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12098 		ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12099 
12100 		if (op1_info & MAY_BE_ARRAY_OF_REF) {
12101 			ref = jit_ZVAL_DEREF_ref(jit, ref);
12102 		}
12103 		cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12104 		if (not_found_exit_addr) {
12105 			ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12106 			ir_refs_add(found_inputs, ir_END());
12107 		} else if (found_exit_addr) {
12108 			ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12109 			ir_END_list(*end_inputs);
12110 		} else {
12111 			ir_ref if_set = ir_IF(cond);
12112 			ir_IF_FALSE(if_set);
12113 			ir_END_list(*end_inputs);
12114 			ir_IF_TRUE(if_set);
12115 			ir_refs_add(found_inputs, ir_END());
12116 		}
12117 	}
12118 
12119 	return 1;
12120 }
12121 
12122 static int zend_jit_fetch_dim_read(zend_jit_ctx       *jit,
12123                                    const zend_op      *opline,
12124                                    zend_ssa           *ssa,
12125                                    const zend_ssa_op  *ssa_op,
12126                                    uint32_t            op1_info,
12127                                    zend_jit_addr       op1_addr,
12128                                    bool           op1_avoid_refcounting,
12129                                    uint32_t            op2_info,
12130                                    zend_jit_addr       op2_addr,
12131                                    zend_ssa_range     *op2_range,
12132                                    uint32_t            res_info,
12133                                    zend_jit_addr       res_addr,
12134                                    uint8_t             dim_type)
12135 {
12136 	zend_jit_addr orig_op1_addr;
12137 	const void *exit_addr = NULL;
12138 	const void *not_found_exit_addr = NULL;
12139 	bool result_type_guard = 0;
12140 	bool result_avoid_refcounting = 0;
12141 	uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12142 	int may_throw = 0;
12143 	ir_ref if_type = IR_UNUSED;
12144 	ir_ref end_inputs = IR_UNUSED;
12145 	ir_ref not_found_inputs = IR_UNUSED;
12146 
12147 	orig_op1_addr = OP1_ADDR();
12148 
12149 	if (opline->opcode != ZEND_FETCH_DIM_IS
12150 	 && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12151 	 && !has_concrete_type(op1_info)) {
12152 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12153 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12154 		if (!exit_addr) {
12155 			return 0;
12156 		}
12157 	}
12158 
12159 	if ((res_info & MAY_BE_GUARD)
12160 	 && JIT_G(current_frame)
12161 	 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12162 
12163 		if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12164 			result_type_guard = 1;
12165 			res_info &= ~MAY_BE_GUARD;
12166 			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12167 		}
12168 
12169 		if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12170 		 && (opline->opcode == ZEND_FETCH_LIST_R
12171 		  || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12172 		  || op1_avoid_refcounting)
12173 		 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12174 		 && (ssa_op+1)->op1_use == ssa_op->result_def
12175 		 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12176 		 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12177 			result_avoid_refcounting = 1;
12178 			ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12179 		}
12180 
12181 		if (opline->opcode == ZEND_FETCH_DIM_IS
12182 		 && !(res_info & MAY_BE_NULL)) {
12183 			uint32_t flags = 0;
12184 			uint32_t old_op1_info = 0;
12185 			uint32_t old_info;
12186 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12187 			int32_t exit_point;
12188 
12189 			if (opline->opcode != ZEND_FETCH_LIST_R
12190 			 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12191 			 && !op1_avoid_refcounting) {
12192 				flags |= ZEND_JIT_EXIT_FREE_OP1;
12193 			}
12194 			if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12195 			 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12196 				flags |= ZEND_JIT_EXIT_FREE_OP2;
12197 			}
12198 
12199 			if (op1_avoid_refcounting) {
12200 				old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12201 				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12202 			}
12203 
12204 			old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12205 			SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12206 			SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_TYPE_ONLY);
12207 			exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12208 			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12209 			not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12210 			if (!not_found_exit_addr) {
12211 				return 0;
12212 			}
12213 
12214 			if (op1_avoid_refcounting) {
12215 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12216 			}
12217 		}
12218 	}
12219 
12220 	if (op1_info & MAY_BE_REF) {
12221 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12222 		ref = jit_ZVAL_DEREF_ref(jit, ref);
12223 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12224 	}
12225 
12226 	if (op1_info & MAY_BE_ARRAY) {
12227 		ir_ref ht_ref, ref;
12228 		zend_jit_addr val_addr;
12229 		ir_refs *found_inputs, *found_vals;
12230 
12231 		ir_refs_init(found_inputs, 10);
12232 		ir_refs_init(found_vals, 10);
12233 
12234 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12235 			if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12236 				jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12237 			} else {
12238 				if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12239 				ir_IF_TRUE(if_type);
12240 			}
12241 		}
12242 
12243 		ht_ref = jit_Z_PTR(jit, op1_addr);
12244 
12245 		if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12246 		    (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12247 			may_throw = 1;
12248 		}
12249 
12250 		if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12251 				(opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12252 				op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12253 				result_type_guard, ht_ref, found_inputs, found_vals,
12254 				&end_inputs, &not_found_inputs)) {
12255 			return 0;
12256 		}
12257 
12258 		if (found_inputs->count) {
12259 			ir_MERGE_N(found_inputs->count, found_inputs->refs);
12260 			ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12261 			val_addr = ZEND_ADDR_REF_ZVAL(ref);
12262 
12263 			if (result_type_guard) {
12264 				uint8_t type = concrete_type(res_info);
12265 				uint32_t flags = 0;
12266 
12267 				if (opline->opcode != ZEND_FETCH_LIST_R
12268 				 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12269 				 && !op1_avoid_refcounting) {
12270 					flags |= ZEND_JIT_EXIT_FREE_OP1;
12271 				}
12272 				if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12273 				 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12274 					flags |= ZEND_JIT_EXIT_FREE_OP2;
12275 				}
12276 
12277 				val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12278 					(op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12279 				if (!val_addr) {
12280 					return 0;
12281 				}
12282 
12283 				if (not_found_inputs) {
12284 					ir_END_list(not_found_inputs);
12285 					ir_MERGE_list(not_found_inputs);
12286 				}
12287 
12288 				// ZVAL_COPY
12289 				jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12290 				if (Z_MODE(res_addr) != IS_REG) {
12291 				} else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12292 					return 0;
12293 				}
12294 			} else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12295 				// ZVAL_COPY_DEREF
12296 				ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12297 				if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12298 					return 0;
12299 				}
12300 			} else  {
12301 				// ZVAL_COPY
12302 				jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, 1);
12303 			}
12304 
12305 			ir_END_list(end_inputs);
12306 		} else if (not_found_inputs) {
12307 			ir_MERGE_list(not_found_inputs);
12308 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12309 			ir_END_list(end_inputs);
12310 		} else if (!end_inputs && jit->ctx.control) {
12311 			ir_END_list(end_inputs); /* dead code */
12312 		}
12313 	}
12314 
12315 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12316 		if (if_type) {
12317 			ir_IF_FALSE_cold(if_type);
12318 			if_type = IS_UNDEF;
12319 		}
12320 
12321 		if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12322 			ir_ref str_ref;
12323 
12324 			may_throw = 1;
12325 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12326 				if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12327 					jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12328 				} else {
12329 					if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12330 					ir_IF_TRUE(if_type);
12331 				}
12332 			}
12333 			jit_SET_EX_OPLINE(jit, opline);
12334 			str_ref = jit_Z_PTR(jit, op1_addr);
12335 			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12336 				ir_ref ref;
12337 
12338 				if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12339 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12340 						str_ref, jit_Z_LVAL(jit, op2_addr));
12341 				} else {
12342 					ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12343 						str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12344 				}
12345 				jit_set_Z_PTR(jit, res_addr, ref);
12346 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12347 			} else {
12348 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12349 					str_ref,
12350 					jit_ZVAL_ADDR(jit, op2_addr),
12351 					jit_ZVAL_ADDR(jit, res_addr));
12352 			}
12353 			ir_END_list(end_inputs);
12354 		}
12355 
12356 		if (op1_info & MAY_BE_OBJECT) {
12357 			ir_ref arg2;
12358 
12359 			if (if_type) {
12360 				ir_IF_FALSE_cold(if_type);
12361 				if_type = IS_UNDEF;
12362 			}
12363 
12364 			may_throw = 1;
12365 			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12366 				if (exit_addr) {
12367 					jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12368 				} else {
12369 					if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12370 					ir_IF_TRUE(if_type);
12371 				}
12372 			}
12373 
12374 			jit_SET_EX_OPLINE(jit, opline);
12375 			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12376 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12377 				arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12378 			} else {
12379 				arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12380 			}
12381 
12382 			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12383 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12384 					jit_ZVAL_ADDR(jit, op1_addr),
12385 					arg2,
12386 					jit_ZVAL_ADDR(jit, res_addr));
12387 			} else {
12388 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12389 					jit_ZVAL_ADDR(jit, op1_addr),
12390 					arg2,
12391 					jit_ZVAL_ADDR(jit, res_addr));
12392 			}
12393 
12394 			ir_END_list(end_inputs);
12395 		}
12396 
12397 		if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12398 		 && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12399 
12400 			if (if_type) {
12401 				ir_IF_FALSE_cold(if_type);
12402 				if_type = IS_UNDEF;
12403 			}
12404 
12405 			if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12406 				jit_SET_EX_OPLINE(jit, opline);
12407 				if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12408 					may_throw = 1;
12409 					zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL, 0, 1, 0);
12410 				}
12411 
12412 				if (op2_info & MAY_BE_UNDEF) {
12413 					may_throw = 1;
12414 					zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL, 0, 1, 0);
12415 				}
12416 			}
12417 
12418 			if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
12419 				ir_ref ref;
12420 
12421 				may_throw = 1;
12422 				if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12423 					ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
12424 				} else {
12425 					jit_SET_EX_OPLINE(jit, opline);
12426 					ref = jit_ZVAL_ADDR(jit, op1_addr);
12427 				}
12428 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
12429 			}
12430 
12431 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12432 			ir_END_list(end_inputs);
12433 		}
12434 	}
12435 
12436 	if (end_inputs) {
12437 		ir_MERGE_list(end_inputs);
12438 
12439 #ifdef ZEND_JIT_USE_RC_INFERENCE
12440 		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12441 			/* Magic offsetGet() may increase refcount of the key */
12442 			op2_info |= MAY_BE_RCN;
12443 		}
12444 #endif
12445 
12446 		if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
12447 			if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
12448 				may_throw = 1;
12449 			}
12450 			jit_FREE_OP(jit,  opline->op2_type, opline->op2, op2_info, opline);
12451 		}
12452 		if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12453 			if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
12454 				if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
12455 					may_throw = 1;
12456 				}
12457 				jit_FREE_OP(jit,  opline->op1_type, opline->op1, op1_info, opline);
12458 			}
12459 		}
12460 
12461 		if (may_throw) {
12462 			zend_jit_check_exception(jit);
12463 		}
12464 	} else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
12465 		ir_BEGIN(IR_UNUSED); /* unreachable tail */
12466 	}
12467 
12468 	return 1;
12469 }
12470 
12471 static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx   *jit,
12472                                                    const zend_op  *opline,
12473                                                    uint32_t        op1_info,
12474                                                    zend_jit_addr   op1_addr,
12475                                                    ir_ref         *if_type,
12476                                                    ir_ref         *ht_ref,
12477                                                    int            *may_throw)
12478 {
12479 	ir_ref ref = IR_UNUSED;
12480 	ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
12481 	ir_refs *array_inputs, *array_values;
12482 
12483 	ir_refs_init(array_inputs, 4);
12484 	ir_refs_init(array_values, 4);
12485 
12486 	ref = jit_ZVAL_ADDR(jit, op1_addr);
12487 	if (op1_info & MAY_BE_REF) {
12488 		ir_ref if_reference, if_array, end1, ref2;
12489 
12490 		*may_throw = 1;
12491 		if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
12492 		ir_IF_FALSE(if_reference);
12493 		end1 = ir_END();
12494 		ir_IF_TRUE_cold(if_reference);
12495 		array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
12496 		if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
12497 		ir_IF_TRUE(if_array);
12498 		array_reference_end = ir_END();
12499 		ir_IF_FALSE_cold(if_array);
12500 		if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
12501 			jit_SET_EX_OPLINE(jit, opline);
12502 		}
12503 		ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
12504 		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
12505 
12506 		ir_MERGE_WITH(end1);
12507 		ref = ir_PHI_2(IR_ADDR, ref2, ref);
12508 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12509 	}
12510 
12511 	if (op1_info & MAY_BE_ARRAY) {
12512 		ir_ref op1_ref = ref;
12513 
12514 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12515 			*if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12516 			ir_IF_TRUE(*if_type);
12517 		}
12518 		if (array_reference_end) {
12519 			ir_MERGE_WITH(array_reference_end);
12520 			op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
12521 		}
12522 		// JIT: SEPARATE_ARRAY()
12523 		ref = jit_Z_PTR_ref(jit, op1_ref);
12524 		if (RC_MAY_BE_N(op1_info)) {
12525 			if (RC_MAY_BE_1(op1_info)) {
12526 				ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
12527 				ir_IF_TRUE(if_refcount_1);
12528 				ir_refs_add(array_inputs, ir_END());
12529 				ir_refs_add(array_values, ref);
12530 				ir_IF_FALSE(if_refcount_1);
12531 			}
12532 			ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
12533 		}
12534 		if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
12535 			ir_refs_add(array_inputs, ir_END());
12536 			ir_refs_add(array_values, ref);
12537 		}
12538 	}
12539 
12540 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
12541 		if (*if_type) {
12542 			ir_IF_FALSE_cold(*if_type);
12543 			*if_type = IR_UNUSED;
12544 		}
12545 		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12546 			*if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
12547 			ir_IF_TRUE(*if_type);
12548 		}
12549 		if ((op1_info & MAY_BE_UNDEF)
12550 		 && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
12551 			ir_ref end1 = IR_UNUSED;
12552 
12553 			*may_throw = 1;
12554 			if (op1_info & MAY_BE_NULL) {
12555 				ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
12556 				ir_IF_TRUE(if_def);
12557 				end1 = ir_END();
12558 				ir_IF_FALSE(if_def);
12559 			}
12560 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
12561 			if (end1) {
12562 				ir_MERGE_WITH(end1);
12563 			}
12564 		}
12565 		// JIT: ZVAL_ARR(container, zend_new_array(8));
12566 		ref = ir_CALL_1(IR_ADDR,
12567 			jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
12568 			jit_ZVAL_ADDR(jit, op1_addr));
12569 		if (array_inputs->count) {
12570 			ir_refs_add(array_inputs, ir_END());
12571 			ir_refs_add(array_values, ref);
12572 		}
12573 	}
12574 
12575 	if (array_inputs->count) {
12576 		ir_MERGE_N(array_inputs->count, array_inputs->refs);
12577 		ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
12578 	}
12579 
12580 	*ht_ref = ref;
12581 	return op1_addr;
12582 }
12583 
12584 static int zend_jit_fetch_dim(zend_jit_ctx   *jit,
12585                               const zend_op  *opline,
12586                               uint32_t        op1_info,
12587                               zend_jit_addr   op1_addr,
12588                               uint32_t        op2_info,
12589                               zend_jit_addr   op2_addr,
12590                               zend_ssa_range *op2_range,
12591                               zend_jit_addr   res_addr,
12592                               uint8_t         dim_type)
12593 {
12594 	int may_throw = 0;
12595 	ir_ref end_inputs = IR_UNUSED;
12596 	ir_ref ref, if_type = IR_UNUSED, ht_ref;
12597 
12598 	if (opline->opcode == ZEND_FETCH_DIM_RW) {
12599 		jit_SET_EX_OPLINE(jit, opline);
12600 	}
12601 
12602 	op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
12603 
12604 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12605 		ir_refs *found_inputs, *found_vals;
12606 
12607 		ir_refs_init(found_inputs, 8);
12608 		ir_refs_init(found_vals, 8);
12609 
12610 		if (opline->op2_type == IS_UNUSED) {
12611 			ir_ref if_ok;
12612 
12613 			may_throw = 1;
12614 			// JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
12615 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
12616 				ht_ref, jit_EG(uninitialized_zval));
12617 
12618 			// JIT: if (UNEXPECTED(!var_ptr)) {
12619 			if_ok = ir_IF(ref);
12620 			ir_IF_FALSE_cold(if_ok);
12621 			if (opline->opcode != ZEND_FETCH_DIM_RW) {
12622 				jit_SET_EX_OPLINE(jit, opline);
12623 			}
12624 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
12625 			ir_END_list(end_inputs);
12626 
12627 			ir_IF_TRUE(if_ok);
12628 			jit_set_Z_PTR(jit, res_addr, ref);
12629 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12630 
12631 			ir_END_list(end_inputs);
12632 		} else {
12633 			uint32_t type;
12634 
12635 			switch (opline->opcode) {
12636 				case ZEND_FETCH_DIM_W:
12637 				case ZEND_FETCH_LIST_W:
12638 					type = BP_VAR_W;
12639 					break;
12640 				case ZEND_FETCH_DIM_RW:
12641 					may_throw = 1;
12642 					type = BP_VAR_RW;
12643 					break;
12644 				case ZEND_FETCH_DIM_UNSET:
12645 					type = BP_VAR_UNSET;
12646 					break;
12647 				default:
12648 					ZEND_UNREACHABLE();
12649 			}
12650 
12651 			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12652 				may_throw = 1;
12653 			}
12654 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
12655 					op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
12656 					0, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
12657 				return 0;
12658 			}
12659 
12660 			if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
12661 				if (end_inputs) {
12662 					ir_MERGE_list(end_inputs);
12663 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12664 					end_inputs = ir_END();
12665 				}
12666 			} else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12667 				/* impossible dead path */
12668 				end_inputs = ir_END();
12669 			} else {
12670 				ZEND_ASSERT(end_inputs == IR_UNUSED);
12671 			}
12672 
12673 			if (found_inputs->count) {
12674 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
12675 				ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12676 				jit_set_Z_PTR(jit, res_addr, ref);
12677 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12678 				ir_END_list(end_inputs);
12679 			}
12680 
12681 		}
12682 	}
12683 
12684 	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12685 		ir_ref arg2;
12686 
12687 		may_throw = 1;
12688 
12689 		if (if_type) {
12690 			ir_IF_FALSE(if_type);
12691 			if_type = IR_UNUSED;
12692 		}
12693 
12694 		if (opline->opcode != ZEND_FETCH_DIM_RW) {
12695 			jit_SET_EX_OPLINE(jit, opline);
12696 		}
12697 
12698 	    if (opline->op2_type == IS_UNUSED) {
12699 			arg2 = IR_NULL;
12700 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12701 			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12702 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
12703 		} else {
12704 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12705 		}
12706 
12707 		switch (opline->opcode) {
12708 			case ZEND_FETCH_DIM_W:
12709 			case ZEND_FETCH_LIST_W:
12710 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
12711 					jit_ZVAL_ADDR(jit, op1_addr),
12712 					arg2,
12713 					jit_ZVAL_ADDR(jit, res_addr));
12714 				break;
12715 			case ZEND_FETCH_DIM_RW:
12716 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
12717 					jit_ZVAL_ADDR(jit, op1_addr),
12718 					arg2,
12719 					jit_ZVAL_ADDR(jit, res_addr));
12720 				break;
12721 //			case ZEND_FETCH_DIM_UNSET:
12722 //				|	EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
12723 //				break;
12724 			default:
12725 				ZEND_UNREACHABLE();
12726 			}
12727 
12728 		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12729 			ir_END_list(end_inputs);
12730 		}
12731 	}
12732 
12733 #ifdef ZEND_JIT_USE_RC_INFERENCE
12734 	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))) {
12735 		/* ASSIGN_DIM may increase refcount of the key */
12736 		op2_info |= MAY_BE_RCN;
12737 	}
12738 #endif
12739 
12740 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
12741 	 && (op2_info & MAY_HAVE_DTOR)
12742 	 && (op2_info & MAY_BE_RC1)) {
12743 		may_throw = 1;
12744 	}
12745 
12746 	if (end_inputs) {
12747 		ir_MERGE_list(end_inputs);
12748 	}
12749 
12750 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12751 
12752 	if (may_throw) {
12753 		zend_jit_check_exception(jit);
12754 	}
12755 
12756 	return 1;
12757 }
12758 
12759 static int zend_jit_isset_isempty_dim(zend_jit_ctx   *jit,
12760                                       const zend_op  *opline,
12761                                       uint32_t        op1_info,
12762                                       zend_jit_addr   op1_addr,
12763                                       bool       op1_avoid_refcounting,
12764                                       uint32_t        op2_info,
12765                                       zend_jit_addr   op2_addr,
12766                                       zend_ssa_range *op2_range,
12767                                       uint8_t         dim_type,
12768                                       int             may_throw,
12769                                       uint8_t         smart_branch_opcode,
12770                                       uint32_t        target_label,
12771                                       uint32_t        target_label2,
12772                                       const void     *exit_addr)
12773 {
12774 	zend_jit_addr res_addr;
12775 	ir_ref if_type = IR_UNUSED;
12776 	ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
12777 	ir_refs *true_inputs;
12778 
12779 	ir_refs_init(true_inputs, 8);
12780 
12781 	// TODO: support for empty() ???
12782 	ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
12783 
12784 	res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
12785 
12786 	if (op1_info & MAY_BE_REF) {
12787 		ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12788 		ref = jit_ZVAL_DEREF_ref(jit, ref);
12789 		op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12790 	}
12791 
12792 	if (op1_info & MAY_BE_ARRAY) {
12793 		const void *found_exit_addr = NULL;
12794 		const void *not_found_exit_addr = NULL;
12795 		ir_ref ht_ref;
12796 
12797 		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12798 			if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12799 			ir_IF_TRUE(if_type);
12800 		}
12801 
12802 		ht_ref = jit_Z_PTR(jit, op1_addr);
12803 
12804 		if (exit_addr
12805 		 && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
12806 		 && !may_throw
12807 		 && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
12808 		 && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
12809 			if (smart_branch_opcode == ZEND_JMPNZ) {
12810 				found_exit_addr = exit_addr;
12811 			} else {
12812 				not_found_exit_addr = exit_addr;
12813 			}
12814 		}
12815 		if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
12816 				op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
12817 				0, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
12818 			return 0;
12819 		}
12820 
12821 		if (found_exit_addr) {
12822 			ir_MERGE_list(false_inputs);
12823 			return 1;
12824 		} else if (not_found_exit_addr) {
12825 			ir_MERGE_N(true_inputs->count, true_inputs->refs);
12826 			return 1;
12827 		}
12828 	}
12829 
12830 	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12831 		if (if_type) {
12832 			ir_IF_FALSE(if_type);
12833 			if_type = IR_UNUSED;
12834 		}
12835 
12836 		if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
12837 			ir_ref ref, arg1, arg2, if_true;
12838 
12839 			jit_SET_EX_OPLINE(jit, opline);
12840 			arg1 = jit_ZVAL_ADDR(jit, op1_addr);
12841 			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12842 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12843 				arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12844 			} else {
12845 				arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12846 			}
12847 			ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
12848 			if_true = ir_IF(ref);
12849 			ir_IF_TRUE(if_true);
12850 			ir_refs_add(true_inputs, ir_END());
12851 			ir_IF_FALSE(if_true);
12852 			ir_END_list(false_inputs);
12853 		} else {
12854 			if (op2_info & MAY_BE_UNDEF) {
12855 				ir_ref end1 = IR_UNUSED;
12856 
12857 				if (op2_info & MAY_BE_ANY) {
12858 					ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
12859 					ir_IF_TRUE(if_def);
12860 					end1 = ir_END();
12861 					ir_IF_FALSE(if_def);
12862 				}
12863 				jit_SET_EX_OPLINE(jit, opline);
12864 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
12865 				if (end1) {
12866 					ir_MERGE_WITH(end1);
12867 				}
12868 			}
12869 			ir_END_list(false_inputs);
12870 		}
12871 	}
12872 
12873 #ifdef ZEND_JIT_USE_RC_INFERENCE
12874 	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12875 		/* Magic offsetExists() may increase refcount of the key */
12876 		op2_info |= MAY_BE_RCN;
12877 	}
12878 #endif
12879 
12880 	if (true_inputs->count) {
12881 		ir_MERGE_N(true_inputs->count, true_inputs->refs);
12882 
12883 		jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12884 		if (!op1_avoid_refcounting) {
12885 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
12886 		}
12887 		if (may_throw) {
12888 			zend_jit_check_exception_undef_result(jit, opline);
12889 		}
12890 		if (!(opline->extended_value & ZEND_ISEMPTY)) {
12891 			if (exit_addr) {
12892 				if (smart_branch_opcode == ZEND_JMPNZ) {
12893 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12894 				} else {
12895 					ir_END_list(end_inputs);
12896 				}
12897 			} else if (smart_branch_opcode) {
12898 				if (smart_branch_opcode == ZEND_JMPZ) {
12899 					_zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
12900 				} else if (smart_branch_opcode == ZEND_JMPNZ) {
12901 					_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
12902 				} else {
12903 					ZEND_UNREACHABLE();
12904 				}
12905 			} else {
12906 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
12907 				ir_END_list(end_inputs);
12908 			}
12909 		} else {
12910 			ZEND_UNREACHABLE(); // TODO: support for empty()
12911 		}
12912 	}
12913 
12914 	ir_MERGE_list(false_inputs);
12915 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12916 	if (!op1_avoid_refcounting) {
12917 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
12918 	}
12919 	if (may_throw) {
12920 		zend_jit_check_exception_undef_result(jit, opline);
12921 	}
12922 	if (!(opline->extended_value & ZEND_ISEMPTY)) {
12923 		if (exit_addr) {
12924 			if (smart_branch_opcode == ZEND_JMPZ) {
12925 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12926 			} else {
12927 				ir_END_list(end_inputs);
12928 			}
12929 		} else if (smart_branch_opcode) {
12930 			if (smart_branch_opcode == ZEND_JMPZ) {
12931 				_zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
12932 			} else if (smart_branch_opcode == ZEND_JMPNZ) {
12933 				_zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
12934 			} else {
12935 				ZEND_UNREACHABLE();
12936 			}
12937 		} else {
12938 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
12939 			ir_END_list(end_inputs);
12940 		}
12941 	} else {
12942 		ZEND_UNREACHABLE(); // TODO: support for empty()
12943 	}
12944 
12945     if (!exit_addr && smart_branch_opcode) {
12946 		jit->b = -1;
12947     } else {
12948 		ir_MERGE_list(end_inputs);
12949     }
12950 
12951 	return 1;
12952 }
12953 
12954 static int zend_jit_assign_dim(zend_jit_ctx  *jit,
12955                                const zend_op *opline,
12956                                uint32_t       op1_info,
12957                                zend_jit_addr  op1_addr,
12958                                uint32_t       op2_info,
12959                                zend_jit_addr  op2_addr,
12960                                zend_ssa_range *op2_range,
12961                                uint32_t       val_info,
12962                                zend_jit_addr  op3_addr,
12963                                zend_jit_addr  op3_def_addr,
12964                                zend_jit_addr  res_addr,
12965                                uint8_t        dim_type,
12966                                int            may_throw)
12967 {
12968 	ir_ref if_type = IR_UNUSED;
12969 	ir_ref end_inputs = IR_UNUSED, ht_ref;
12970 
12971 	if (op3_addr != op3_def_addr && op3_def_addr) {
12972 		if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
12973 			return 0;
12974 		}
12975 		if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
12976 			op3_addr = op3_def_addr;
12977 		}
12978 	}
12979 
12980 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
12981 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12982 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12983 
12984 		if (!exit_addr) {
12985 			return 0;
12986 		}
12987 
12988 		jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
12989 
12990 		val_info &= ~MAY_BE_UNDEF;
12991 	}
12992 
12993 	op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
12994 
12995 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12996 		if (opline->op2_type == IS_UNUSED) {
12997 			uint32_t var_info = MAY_BE_NULL;
12998 			ir_ref if_ok, ref;
12999 			zend_jit_addr var_addr;
13000 
13001 			// JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13002 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13003 				ht_ref, jit_EG(uninitialized_zval));
13004 
13005 			// JIT: if (UNEXPECTED(!var_ptr)) {
13006 			if_ok = ir_IF(ref);
13007 			ir_IF_FALSE_cold(if_ok);
13008 
13009 			// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13010 			jit_SET_EX_OPLINE(jit, opline);
13011 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13012 
13013 			ir_END_list(end_inputs);
13014 
13015 			ir_IF_TRUE(if_ok);
13016 			var_addr = ZEND_ADDR_REF_ZVAL(ref);
13017 			if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13018 				return 0;
13019 			}
13020 		} else {
13021 			uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13022 			zend_jit_addr var_addr;
13023 			ir_ref ref;
13024 			ir_refs *found_inputs, *found_values;
13025 
13026 			ir_refs_init(found_inputs, 8);
13027 			ir_refs_init(found_values, 8);
13028 
13029 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13030 					op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13031 					0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13032 				return 0;
13033 			}
13034 
13035 			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13036 				var_info |= MAY_BE_REF;
13037 			}
13038 			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13039 				var_info |= MAY_BE_RC1;
13040 			}
13041 
13042 			if (found_inputs->count) {
13043 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
13044 				ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13045 				var_addr = ZEND_ADDR_REF_ZVAL(ref);
13046 
13047 				// JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13048 				if (opline->op1_type == IS_VAR
13049 				 && Z_MODE(op3_addr) != IS_REG
13050 				 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13051 					ZEND_ASSERT(opline->result_type == IS_UNUSED);
13052 					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)) {
13053 						return 0;
13054 					}
13055 				} else {
13056 					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)) {
13057 						return 0;
13058 					}
13059 				}
13060 			}
13061 		}
13062 
13063 		ir_END_list(end_inputs);
13064 	}
13065 
13066 	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13067 		ir_ref arg2, arg4;
13068 
13069 		if (if_type) {
13070 			ir_IF_FALSE_cold(if_type);
13071 			if_type = IR_UNUSED;
13072 		}
13073 
13074 		jit_SET_EX_OPLINE(jit, opline);
13075 
13076 	    if (opline->op2_type == IS_UNUSED) {
13077 			arg2 = IR_NULL;
13078 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13079 				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13080 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13081 		} else {
13082 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13083 		}
13084 
13085 		if (opline->result_type == IS_UNUSED) {
13086 			arg4 = IR_NULL;
13087 		} else {
13088 			arg4 = jit_ZVAL_ADDR(jit, res_addr);
13089 		}
13090 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13091 			jit_ZVAL_ADDR(jit, op1_addr),
13092 			arg2,
13093 			jit_ZVAL_ADDR(jit, op3_addr),
13094 			arg4);
13095 
13096 #ifdef ZEND_JIT_USE_RC_INFERENCE
13097 		if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13098 			/* ASSIGN_DIM may increase refcount of the value */
13099 			val_info |= MAY_BE_RCN;
13100 		}
13101 #endif
13102 
13103 		jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13104 
13105 		ir_END_list(end_inputs);
13106 	}
13107 
13108 #ifdef ZEND_JIT_USE_RC_INFERENCE
13109 	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))) {
13110 		/* ASSIGN_DIM may increase refcount of the key */
13111 		op2_info |= MAY_BE_RCN;
13112 	}
13113 #endif
13114 
13115 	ir_MERGE_list(end_inputs);
13116 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13117 
13118 	if (may_throw) {
13119 		zend_jit_check_exception(jit);
13120 	}
13121 
13122 	return 1;
13123 }
13124 
13125 static int zend_jit_assign_dim_op(zend_jit_ctx   *jit,
13126                                   const zend_op  *opline,
13127                                   uint32_t        op1_info,
13128                                   uint32_t        op1_def_info,
13129                                   zend_jit_addr   op1_addr,
13130                                   uint32_t        op2_info,
13131                                   zend_jit_addr   op2_addr,
13132                                   zend_ssa_range *op2_range,
13133                                   uint32_t        op1_data_info,
13134                                   zend_jit_addr   op3_addr,
13135                                   zend_ssa_range *op1_data_range,
13136                                   uint8_t         dim_type,
13137                                   int             may_throw)
13138 {
13139 	zend_jit_addr var_addr = IS_UNUSED;
13140 	const void *not_found_exit_addr = NULL;
13141 	uint32_t var_info = MAY_BE_NULL;
13142 	ir_ref if_type = IS_UNUSED;
13143 	ir_ref end_inputs = IR_UNUSED, ht_ref;
13144 	bool emit_fast_path = 1;
13145 
13146 	ZEND_ASSERT(opline->result_type == IS_UNUSED);
13147 
13148 	if (may_throw) {
13149 		jit_SET_EX_OPLINE(jit, opline);
13150 	}
13151 
13152 	op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13153 
13154 	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13155 		uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13156 
13157 		if (opline->op2_type == IS_UNUSED) {
13158 			var_info = MAY_BE_NULL;
13159 			ir_ref if_ok, ref;
13160 
13161 			// JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13162 			ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13163 				ht_ref, jit_EG(uninitialized_zval));
13164 
13165 			// JIT: if (UNEXPECTED(!var_ptr)) {
13166 			if_ok = ir_IF(ref);
13167 			ir_IF_FALSE_cold(if_ok);
13168 
13169 			// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13170 			ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13171 
13172 			ir_END_list(end_inputs);
13173 
13174 			ir_IF_TRUE(if_ok);
13175 			var_addr = ZEND_ADDR_REF_ZVAL(ref);
13176 		} else {
13177 			ir_ref ref;
13178 			ir_refs *found_inputs, *found_values;
13179 
13180 			ir_refs_init(found_inputs, 8);
13181 			ir_refs_init(found_values, 8);
13182 
13183 			var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13184 			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13185 				var_info |= MAY_BE_REF;
13186 			}
13187 			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13188 				var_info |= MAY_BE_RC1;
13189 			}
13190 
13191 			if (dim_type != IS_UNKNOWN
13192 			 && dim_type != IS_UNDEF
13193 			 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13194 			 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13195 			 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13196 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13197 				not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13198 				if (!not_found_exit_addr) {
13199 					return 0;
13200 				}
13201 			}
13202 
13203 			if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13204 					op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13205 					0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13206 				return 0;
13207 			}
13208 
13209 			if (found_inputs->count) {
13210 				ir_MERGE_N(found_inputs->count, found_inputs->refs);
13211 				ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13212 				var_addr = ZEND_ADDR_REF_ZVAL(ref);
13213 
13214 				if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13215 					jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13216 					var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13217 				}
13218 				if (var_info & MAY_BE_REF) {
13219 					binary_op_type binary_op = get_binary_op(opline->extended_value);
13220 					ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13221 
13222 					ref = jit_ZVAL_ADDR(jit, var_addr);
13223 					if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13224 					ir_IF_FALSE(if_ref);
13225 					noref_path = ir_END();
13226 					ir_IF_TRUE(if_ref);
13227 
13228 					reference = jit_Z_PTR_ref(jit, ref);
13229 					ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13230 					if_typed = jit_if_TYPED_REF(jit, reference);
13231 					ir_IF_FALSE(if_typed);
13232 					ref_path = ir_END();
13233 					ir_IF_TRUE_cold(if_typed);
13234 
13235 					arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13236 					ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13237 						reference, arg2, ir_CONST_FC_FUNC(binary_op));
13238 
13239 					ir_END_list(end_inputs);
13240 
13241 					ir_MERGE_2(noref_path, ref_path);
13242 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
13243 					var_addr = ZEND_ADDR_REF_ZVAL(ref);
13244 				}
13245 			} else {
13246 				emit_fast_path = 0;
13247 			}
13248 		}
13249 
13250 		if (emit_fast_path) {
13251 			uint8_t val_op_type = (opline+1)->op1_type;
13252 
13253 			if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13254 				/* prevent FREE_OP in the helpers */
13255 				val_op_type = IS_CV;
13256 			}
13257 
13258 			switch (opline->extended_value) {
13259 				case ZEND_ADD:
13260 				case ZEND_SUB:
13261 				case ZEND_MUL:
13262 				case ZEND_DIV:
13263 					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,
13264 							1 /* may overflow */, may_throw)) {
13265 						return 0;
13266 					}
13267 					break;
13268 				case ZEND_BW_OR:
13269 				case ZEND_BW_AND:
13270 				case ZEND_BW_XOR:
13271 				case ZEND_SL:
13272 				case ZEND_SR:
13273 				case ZEND_MOD:
13274 					if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13275 							IS_CV, opline->op1, var_addr, var_info, NULL,
13276 							val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13277 							op1_data_range,
13278 							0, var_addr, var_def_info, var_info, may_throw)) {
13279 						return 0;
13280 					}
13281 					break;
13282 				case ZEND_CONCAT:
13283 					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,
13284 							may_throw)) {
13285 						return 0;
13286 					}
13287 					break;
13288 				default:
13289 					ZEND_UNREACHABLE();
13290 			}
13291 
13292 			ir_END_list(end_inputs);
13293 		}
13294 	}
13295 
13296 	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13297 		binary_op_type binary_op;
13298 		ir_ref arg2;
13299 
13300 		if (if_type) {
13301 			ir_IF_FALSE_cold(if_type);
13302 			if_type = IS_UNUSED;
13303 		}
13304 
13305 	    if (opline->op2_type == IS_UNUSED) {
13306 			arg2 = IR_NULL;
13307 		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13308 			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13309 			arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13310 		} else {
13311 			arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13312 		}
13313 		binary_op = get_binary_op(opline->extended_value);
13314 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13315 			jit_ZVAL_ADDR(jit, op1_addr),
13316 			arg2,
13317 			jit_ZVAL_ADDR(jit, op3_addr),
13318 			ir_CONST_FC_FUNC(binary_op));
13319 		ir_END_list(end_inputs);
13320 	}
13321 
13322 	if (end_inputs) {
13323 		ir_MERGE_list(end_inputs);
13324 	}
13325 
13326 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13327 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13328 	if (may_throw) {
13329 		zend_jit_check_exception(jit);
13330 	}
13331 
13332 	return 1;
13333 }
13334 
13335 static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13336 {
13337 	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13338 
13339 	// JIT: ZVAL_COPY(res, value);
13340 	if (opline->op1_type == IS_CONST) {
13341 		zval *zv = RT_CONSTANT(opline, opline->op1);
13342 
13343 		jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
13344 	} else {
13345 		zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13346 
13347 		jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13348 	}
13349 
13350 	// JIT: Z_FE_POS_P(res) = 0;
13351 	ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13352 
13353 	return 1;
13354 }
13355 
13356 static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13357 {
13358 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13359 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13360 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13361 	ir_ref ref;
13362 
13363 	if (!exit_addr) {
13364 		return 0;
13365 	}
13366 
13367 	ref = ir_AND_U32(
13368 		ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
13369 		ir_CONST_U32(HASH_FLAG_PACKED));
13370 	if (op_info & MAY_BE_ARRAY_PACKED) {
13371 		ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13372 	} else {
13373 		ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
13374 	}
13375 
13376 	return 1;
13377 }
13378 
13379 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)
13380 {
13381 	zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13382 	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;
13383 	ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
13384 	ir_ref exit_inputs = IR_UNUSED;
13385 
13386 	if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
13387 		/* empty array */
13388 		if (exit_addr) {
13389 			if (exit_opcode == ZEND_JMP) {
13390 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13391 			}
13392 		} else {
13393 			zend_basic_block *bb;
13394 
13395 			ZEND_ASSERT(jit->b >= 0);
13396 			bb = &jit->ssa->cfg.blocks[jit->b];
13397 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
13398 			jit->b = -1;
13399 		}
13400 		return 1;
13401 	}
13402 
13403 	// JIT: array = EX_VAR(opline->op1.var);
13404 	// JIT: fe_ht = Z_ARRVAL_P(array);
13405 	ht_ref = jit_Z_PTR(jit, op1_addr);
13406 
13407 	if (op1_info & MAY_BE_PACKED_GUARD) {
13408 		if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
13409 			return 0;
13410 		}
13411 	}
13412 
13413 	// JIT: pos = Z_FE_POS_P(array);
13414 	hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
13415 
13416 	if (MAY_BE_HASH(op1_info)) {
13417 		ir_ref loop_ref, pos2_ref, p2_ref;
13418 
13419 		if (MAY_BE_PACKED(op1_info)) {
13420 			ref = ir_AND_U32(
13421 				ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
13422 				ir_CONST_U32(HASH_FLAG_PACKED));
13423 			if_packed = ir_IF(ref);
13424 			ir_IF_FALSE(if_packed);
13425 		}
13426 
13427 		// JIT: p = fe_ht->arData + pos;
13428 		if (sizeof(void*) == 8) {
13429 			ref = ir_ZEXT_A(hash_pos_ref);
13430 		} else {
13431 			ref = ir_BITCAST_A(hash_pos_ref);
13432 		}
13433 		hash_p_ref = ir_ADD_A(
13434 			ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
13435 			ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
13436 
13437 		loop_ref = ir_LOOP_BEGIN(ir_END());
13438 		hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
13439 		hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
13440 
13441 		// JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13442 		ref = ir_ULT(hash_pos_ref,
13443 			ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13444 
13445 		// JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13446 		// JIT: ZEND_VM_CONTINUE();
13447 
13448 		if (exit_addr) {
13449 			if (exit_opcode == ZEND_JMP) {
13450 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13451 			} else {
13452 				ir_ref if_fit = ir_IF(ref);
13453 				ir_IF_FALSE(if_fit);
13454 				ir_END_list(exit_inputs);
13455 				ir_IF_TRUE(if_fit);
13456 			}
13457 		} else {
13458 			ir_ref if_fit = ir_IF(ref);
13459 			ir_IF_FALSE(if_fit);
13460 			ir_END_list(exit_inputs);
13461 			ir_IF_TRUE(if_fit);
13462 		}
13463 
13464 		// JIT: pos++;
13465 		pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
13466 
13467 		// JIT: value_type = Z_TYPE_INFO_P(value);
13468 		// JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13469 		if (!exit_addr || exit_opcode == ZEND_JMP) {
13470 			if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
13471 			ir_IF_FALSE(if_def_hash);
13472 		} else {
13473 			ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
13474 		}
13475 
13476 		// JIT: p++;
13477 		p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
13478 
13479 		ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13480 		ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
13481 		ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
13482 
13483 		if (MAY_BE_PACKED(op1_info)) {
13484 			ir_IF_TRUE(if_packed);
13485 		}
13486 	}
13487 	if (MAY_BE_PACKED(op1_info)) {
13488 		ir_ref loop_ref, pos2_ref, p2_ref;
13489 
13490 		// JIT: p = fe_ht->arPacked + pos;
13491 		if (sizeof(void*) == 8) {
13492 			ref = ir_ZEXT_A(packed_pos_ref);
13493 		} else {
13494 			ref = ir_BITCAST_A(packed_pos_ref);
13495 		}
13496 		packed_p_ref = ir_ADD_A(
13497 			ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
13498 			ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
13499 
13500 		loop_ref = ir_LOOP_BEGIN(ir_END());
13501 		packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
13502 		packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
13503 
13504 		// JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13505 		ref = ir_ULT(packed_pos_ref,
13506 			ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13507 
13508 		// JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13509 		// JIT: ZEND_VM_CONTINUE();
13510 		if (exit_addr) {
13511 			if (exit_opcode == ZEND_JMP) {
13512 				ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13513 			} else {
13514 				ir_ref if_fit = ir_IF(ref);
13515 				ir_IF_FALSE(if_fit);
13516 				ir_END_list(exit_inputs);
13517 				ir_IF_TRUE(if_fit);
13518 			}
13519 		} else {
13520 			ir_ref if_fit = ir_IF(ref);
13521 			ir_IF_FALSE(if_fit);
13522 			ir_END_list(exit_inputs);
13523 			ir_IF_TRUE(if_fit);
13524 		}
13525 
13526 		// JIT: pos++;
13527 		pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
13528 
13529 		// JIT: value_type = Z_TYPE_INFO_P(value);
13530 		// JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13531 		if (!exit_addr || exit_opcode == ZEND_JMP) {
13532 			if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
13533 			ir_IF_FALSE(if_def_packed);
13534 		} else {
13535 			ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
13536 		}
13537 
13538 		// JIT: p++;
13539 		p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
13540 
13541 		ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13542 		ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
13543 		ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
13544 	}
13545 
13546 	if (!exit_addr || exit_opcode == ZEND_JMP) {
13547 		zend_jit_addr val_addr;
13548 		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
13549 		uint32_t val_info;
13550 		ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
13551 
13552 		if (RETURN_VALUE_USED(opline)) {
13553 			zend_jit_addr res_addr = RES_ADDR();
13554 
13555 			if (MAY_BE_HASH(op1_info)) {
13556 				ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
13557 
13558 				ZEND_ASSERT(if_def_hash);
13559 				ir_IF_TRUE(if_def_hash);
13560 
13561 				// JIT: Z_FE_POS_P(array) = pos + 1;
13562 				ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13563 					ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
13564 
13565 				if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13566 					key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
13567 				}
13568 				if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
13569 				 && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
13570 					// JIT: if (!p->key) {
13571 					if_key = ir_IF(key_ref);
13572 					ir_IF_TRUE(if_key);
13573 				}
13574 				if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13575 					ir_ref if_interned, interned_path;
13576 
13577 					// JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
13578 					jit_set_Z_PTR(jit, res_addr, key_ref);
13579 					ref = ir_AND_U32(
13580 						ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
13581 						ir_CONST_U32(IS_STR_INTERNED));
13582 					if_interned = ir_IF(ref);
13583 					ir_IF_TRUE(if_interned);
13584 
13585 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
13586 
13587 					interned_path = ir_END();
13588 					ir_IF_FALSE(if_interned);
13589 
13590 					jit_GC_ADDREF(jit, key_ref);
13591 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
13592 
13593 					ir_MERGE_WITH(interned_path);
13594 
13595 					if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13596 						key_path = ir_END();
13597 					}
13598 				}
13599 				if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13600 					if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13601 						ir_IF_FALSE(if_key);
13602 					}
13603 					// JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
13604 					ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
13605 					jit_set_Z_LVAL(jit, res_addr, ref);
13606 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13607 
13608 					if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13609 						ir_MERGE_WITH(key_path);
13610 					}
13611 				}
13612 				if (MAY_BE_PACKED(op1_info)) {
13613 					hash_path = ir_END();
13614 				} else {
13615 					p_ref = hash_p_ref;
13616 				}
13617 			}
13618 			if (MAY_BE_PACKED(op1_info)) {
13619 				ZEND_ASSERT(if_def_packed);
13620 				ir_IF_TRUE(if_def_packed);
13621 
13622 				// JIT: Z_FE_POS_P(array) = pos + 1;
13623 				ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13624 					ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
13625 
13626 				// JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
13627 				if (sizeof(zend_long) == 8) {
13628 					packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
13629 				} else {
13630 					packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
13631 				}
13632 				jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
13633 				jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13634 
13635 				if (MAY_BE_HASH(op1_info)) {
13636 					ir_MERGE_WITH(hash_path);
13637 					p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
13638 				} else {
13639 					p_ref = packed_p_ref;
13640 				}
13641 			}
13642 		} else {
13643 			ir_ref pos_ref = IR_UNUSED;
13644 
13645 			if (if_def_hash && if_def_packed) {
13646 				ir_IF_TRUE(if_def_hash);
13647 				ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
13648 				pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
13649 				p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
13650 			} else if (if_def_hash) {
13651 				ir_IF_TRUE(if_def_hash);
13652 				pos_ref = hash_pos_ref;
13653 				p_ref = hash_p_ref;
13654 			} else if (if_def_packed) {
13655 				ir_IF_TRUE(if_def_packed);
13656 				pos_ref = packed_pos_ref;
13657 				p_ref = packed_p_ref;
13658 			} else {
13659 				ZEND_UNREACHABLE();
13660 			}
13661 
13662 			// JIT: Z_FE_POS_P(array) = pos + 1;
13663 			ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13664 				ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
13665 		}
13666 
13667 		val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
13668 		if (val_info & MAY_BE_ARRAY) {
13669 			val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13670 		}
13671 		if (op1_info & MAY_BE_ARRAY_OF_REF) {
13672 			val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
13673 				MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13674 		} else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13675 			val_info |= MAY_BE_RC1 | MAY_BE_RCN;
13676 		}
13677 
13678 		val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
13679 		if (opline->op2_type == IS_CV) {
13680 			// JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
13681 			if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, 1)) {
13682 				return 0;
13683 			}
13684 		} else {
13685 			// JIT: ZVAL_COPY(res, value);
13686 			jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, 1);
13687 		}
13688 
13689 		if (!exit_addr) {
13690 			zend_basic_block *bb;
13691 
13692 			ZEND_ASSERT(jit->b >= 0);
13693 			bb = &jit->ssa->cfg.blocks[jit->b];
13694 			_zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
13695 			ZEND_ASSERT(exit_inputs);
13696 			if (!jit->ctx.ir_base[exit_inputs].op2) {
13697 				ref = exit_inputs;
13698 			} else {
13699 				ir_MERGE_list(exit_inputs);
13700 				ref = ir_END();
13701 			}
13702 			_zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
13703 			jit->b = -1;
13704 		}
13705 	} else {
13706 		ZEND_ASSERT(exit_inputs);
13707 		ir_MERGE_list(exit_inputs);
13708 	}
13709 
13710 	return 1;
13711 }
13712 
13713 static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
13714 {
13715 	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13716 	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13717 	ir_ref ref = jit_Z_PTR(jit, this_addr);
13718 
13719 	jit_set_Z_PTR(jit, var_addr, ref);
13720 	jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
13721 	jit_GC_ADDREF(jit, ref);
13722 
13723 	return 1;
13724 }
13725 
13726 static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
13727 {
13728 	if (!op_array->scope || (op_array->fn_flags & ZEND_ACC_STATIC)) {
13729 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13730 			if (!JIT_G(current_frame) ||
13731 			    !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
13732 
13733 				zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13734 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13735 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13736 
13737 				if (!exit_addr) {
13738 					return 0;
13739 				}
13740 
13741 				jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
13742 
13743 				if (JIT_G(current_frame)) {
13744 					TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
13745 				}
13746 			}
13747 		} else {
13748 			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13749 			ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
13750 
13751 			ir_IF_FALSE_cold(if_object);
13752 			jit_SET_EX_OPLINE(jit, opline);
13753 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
13754 
13755 			ir_IF_TRUE(if_object);
13756 		}
13757 	}
13758 
13759 	if (!check_only) {
13760 		if (!zend_jit_load_this(jit, opline->result.var)) {
13761 			return 0;
13762 		}
13763 	}
13764 
13765 	return 1;
13766 }
13767 
13768 static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
13769 {
13770 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13771 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13772 
13773 	if (!exit_addr) {
13774 		return 0;
13775 	}
13776 
13777 	ir_GUARD(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce))), ir_CONST_ADDR(ce)),
13778 		ir_CONST_ADDR(exit_addr));
13779 
13780 	return 1;
13781 }
13782 
13783 static int zend_jit_fetch_obj(zend_jit_ctx         *jit,
13784                               const zend_op        *opline,
13785                               const zend_op_array  *op_array,
13786                               zend_ssa             *ssa,
13787                               const zend_ssa_op    *ssa_op,
13788                               uint32_t              op1_info,
13789                               zend_jit_addr         op1_addr,
13790                               bool                  op1_indirect,
13791                               zend_class_entry     *ce,
13792                               bool                  ce_is_instanceof,
13793                               bool                  on_this,
13794                               bool                  delayed_fetch_this,
13795                               bool                  op1_avoid_refcounting,
13796                               zend_class_entry     *trace_ce,
13797                               zend_jit_addr         res_addr,
13798                               uint8_t               prop_type,
13799                               int                   may_throw)
13800 {
13801 	zval *member;
13802 	zend_property_info *prop_info;
13803 	bool may_be_dynamic = 1;
13804 	zend_jit_addr prop_addr;
13805 	uint32_t res_info = RES_INFO();
13806 	ir_ref prop_type_ref = IR_UNUSED;
13807 	ir_ref obj_ref = IR_UNUSED;
13808 	ir_ref prop_ref = IR_UNUSED;
13809 	ir_ref end_inputs = IR_UNUSED;
13810 	ir_ref slow_inputs = IR_UNUSED;
13811 	ir_ref end_values = IR_UNUSED;
13812 
13813 	ZEND_ASSERT(opline->op2_type == IS_CONST);
13814 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
13815 
13816 	member = RT_CONSTANT(opline, opline->op2);
13817 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
13818 	prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
13819 
13820 	if (on_this) {
13821 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13822 		obj_ref = jit_Z_PTR(jit, this_addr);
13823 	} else {
13824 		if (opline->op1_type == IS_VAR
13825 		 && opline->opcode == ZEND_FETCH_OBJ_W
13826 		 && (op1_info & MAY_BE_INDIRECT)
13827 		 && Z_REG(op1_addr) == ZREG_FP) {
13828 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
13829 		}
13830 		if (op1_info & MAY_BE_REF) {
13831 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
13832 		}
13833 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
13834 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13835 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13836 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13837 
13838 				if (!exit_addr) {
13839 					return 0;
13840 				}
13841 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
13842 			} else {
13843 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
13844 
13845 				ir_IF_FALSE_cold(if_obj);
13846 				if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13847 					ir_ref op1_ref = IR_UNUSED;
13848 
13849 					jit_SET_EX_OPLINE(jit, opline);
13850 					if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
13851 						zend_jit_addr orig_op1_addr = OP1_ADDR();
13852 						ir_ref fast_path = IR_UNUSED;
13853 
13854 						if (op1_info & MAY_BE_ANY) {
13855 							ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
13856 							ir_IF_TRUE(if_def);
13857 							fast_path = ir_END();
13858 							ir_IF_FALSE_cold(if_def);
13859 						}
13860 						ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
13861 							ir_CONST_U32(opline->op1.var));
13862 						if (fast_path) {
13863 							ir_MERGE_WITH(fast_path);
13864 						}
13865 						op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
13866 					} else {
13867 						op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
13868 					}
13869 					if (opline->opcode == ZEND_FETCH_OBJ_W) {
13870 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
13871 							op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
13872 						jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
13873 					} else {
13874 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
13875 							op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
13876 						jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13877 					}
13878 				} else {
13879 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13880 				}
13881 				ir_END_list(end_inputs);
13882 
13883 				ir_IF_TRUE(if_obj);
13884 			}
13885 		}
13886 		obj_ref = jit_Z_PTR(jit, op1_addr);
13887 	}
13888 
13889 	ZEND_ASSERT(obj_ref);
13890 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
13891 		prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
13892 		if (prop_info) {
13893 			ce = trace_ce;
13894 			ce_is_instanceof = 0;
13895 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
13896 				if (on_this && JIT_G(current_frame)
13897 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
13898 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
13899 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
13900 					if (on_this && JIT_G(current_frame)) {
13901 						JIT_G(current_frame)->ce = ce;
13902 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
13903 					}
13904 				} else {
13905 					return 0;
13906 				}
13907 				if (ssa->var_info && ssa_op->op1_use >= 0) {
13908 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
13909 					ssa->var_info[ssa_op->op1_use].ce = ce;
13910 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
13911 				}
13912 			}
13913 		}
13914 	}
13915 
13916 	if (!prop_info) {
13917 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
13918 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
13919 		ir_ref if_same = ir_IF(ir_EQ(ref,
13920 			ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
13921 
13922 		ir_IF_FALSE_cold(if_same);
13923 		ir_END_list(slow_inputs);
13924 
13925 		ir_IF_TRUE(if_same);
13926 		ir_ref offset_ref = ir_LOAD_A(
13927 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
13928 
13929 		may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
13930 		if (may_be_dynamic) {
13931 			ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, IR_NULL));
13932 			if (opline->opcode == ZEND_FETCH_OBJ_W) {
13933 				ir_IF_TRUE_cold(if_dynamic);
13934 				ir_END_list(slow_inputs);
13935 			} else {
13936 				ir_IF_TRUE_cold(if_dynamic);
13937 				jit_SET_EX_OPLINE(jit, opline);
13938 
13939 				if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13940 					if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
13941 							|| Z_MODE(res_addr) == IS_REG) {
13942 						ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
13943 							obj_ref, offset_ref);
13944 						ir_END_PHI_list(end_values, val_addr);
13945 					} else {
13946 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
13947 							obj_ref, offset_ref);
13948 						ir_END_list(end_inputs);
13949 					}
13950 				} else {
13951 					if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
13952 							|| Z_MODE(res_addr) == IS_REG) {
13953 						ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
13954 							obj_ref, offset_ref);
13955 						ir_END_PHI_list(end_values, val_addr);
13956 					} else {
13957 						ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
13958 							obj_ref, offset_ref);
13959 						ir_END_list(end_inputs);
13960 					}
13961 				}
13962 			}
13963 			ir_IF_FALSE(if_dynamic);
13964 		}
13965 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
13966 		prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
13967 		ir_ref if_def = ir_IF(prop_type_ref);
13968 		ir_IF_FALSE_cold(if_def);
13969 		ir_END_list(slow_inputs);
13970 		ir_IF_TRUE(if_def);
13971 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
13972 		if (opline->opcode == ZEND_FETCH_OBJ_W
13973 		 && (!ce ||	ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
13974 			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
13975 
13976 			ir_ref prop_info_ref = ir_LOAD_A(
13977 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
13978 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
13979 
13980 			ir_IF_TRUE_cold(if_has_prop_info);
13981 
13982 			ir_ref if_readonly = ir_IF(
13983 				ir_AND_U32(ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags))),
13984 					ir_CONST_U32(ZEND_ACC_READONLY)));
13985 			ir_IF_TRUE(if_readonly);
13986 
13987 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
13988 			ir_IF_TRUE(if_prop_obj);
13989 			ref = jit_Z_PTR(jit, prop_addr);
13990 			jit_GC_ADDREF(jit, ref);
13991 			jit_set_Z_PTR(jit, res_addr, ref);
13992 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
13993 			ir_END_list(end_inputs);
13994 
13995 			ir_IF_FALSE_cold(if_prop_obj);
13996 
13997 			ir_ref extra_addr = ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, prop_addr), offsetof(zval, u2.extra));
13998 			ir_ref extra = ir_LOAD_U32(extra_addr);
13999 			ir_ref if_reinitable = ir_IF(ir_AND_U32(extra, ir_CONST_U32(IS_PROP_REINITABLE)));
14000 			ir_IF_TRUE(if_reinitable);
14001 			ir_STORE(extra_addr, ir_AND_U32(extra, ir_CONST_U32(~IS_PROP_REINITABLE)));
14002 			ir_ref reinit_path = ir_END();
14003 
14004 			ir_IF_FALSE(if_reinitable);
14005 
14006 			jit_SET_EX_OPLINE(jit, opline);
14007 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_modification_error), prop_info_ref);
14008 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14009 			ir_END_list(end_inputs);
14010 
14011 			if (flags == ZEND_FETCH_DIM_WRITE) {
14012 				ir_IF_FALSE_cold(if_readonly);
14013 				ir_MERGE_WITH(reinit_path);
14014 				jit_SET_EX_OPLINE(jit, opline);
14015 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14016 					prop_ref, prop_info_ref);
14017 				ir_END_list(end_inputs);
14018 				ir_IF_FALSE(if_has_prop_info);
14019 			} else if (flags == ZEND_FETCH_REF) {
14020 				ir_IF_FALSE_cold(if_readonly);
14021 				ir_MERGE_WITH(reinit_path);
14022 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14023 					prop_ref,
14024 					prop_info_ref,
14025 					jit_ZVAL_ADDR(jit, res_addr));
14026 				ir_END_list(end_inputs);
14027 				ir_IF_FALSE(if_has_prop_info);
14028 			} else {
14029 				ir_ref list = reinit_path;
14030 
14031 				ZEND_ASSERT(flags == 0);
14032 				ir_IF_FALSE(if_has_prop_info);
14033 				ir_END_list(list);
14034 				ir_IF_FALSE(if_readonly);
14035 				ir_END_list(list);
14036 				ir_MERGE_list(list);
14037 			}
14038 		}
14039 	} else {
14040 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14041 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14042 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14043 			if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14044 				/* perform IS_UNDEF check only after result type guard (during deoptimization) */
14045 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14046 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14047 
14048 				if (!exit_addr) {
14049 					return 0;
14050 				}
14051 				prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14052 				ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14053 			}
14054 		} else {
14055 			prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14056 			ir_ref if_def = ir_IF(prop_type_ref);
14057 			ir_IF_FALSE_cold(if_def);
14058 			ir_END_list(slow_inputs);
14059 			ir_IF_TRUE(if_def);
14060 		}
14061 		if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14062 			if (!prop_type_ref) {
14063 				prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14064 			}
14065 			ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14066 			ir_IF_TRUE(if_prop_obj);
14067 			ir_ref ref = jit_Z_PTR(jit, prop_addr);
14068 			jit_GC_ADDREF(jit, ref);
14069 			jit_set_Z_PTR(jit, res_addr, ref);
14070 			jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14071 			ir_END_list(end_inputs);
14072 
14073 			ir_IF_FALSE_cold(if_prop_obj);
14074 
14075 			ir_ref extra_addr = ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, prop_addr), offsetof(zval, u2.extra));
14076 			ir_ref extra = ir_LOAD_U32(extra_addr);
14077 			ir_ref if_reinitable = ir_IF(ir_AND_U32(extra, ir_CONST_U32(IS_PROP_REINITABLE)));
14078 
14079 			ir_IF_FALSE(if_reinitable);
14080 			jit_SET_EX_OPLINE(jit, opline);
14081 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_modification_error), ir_CONST_ADDR(prop_info));
14082 			jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14083 			ir_END_list(end_inputs);
14084 
14085 			ir_IF_TRUE(if_reinitable);
14086 			ir_STORE(extra_addr, ir_AND_U32(extra, ir_CONST_U32(~IS_PROP_REINITABLE)));
14087 		}
14088 
14089 		if (opline->opcode == ZEND_FETCH_OBJ_W
14090 		 && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
14091 		 && ZEND_TYPE_IS_SET(prop_info->type)) {
14092 			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14093 
14094 			if (flags == ZEND_FETCH_DIM_WRITE) {
14095 				if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14096 					if (!prop_type_ref) {
14097 						prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14098 					}
14099 					ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14100 					ir_IF_TRUE_cold(if_null_or_flase);
14101 					jit_SET_EX_OPLINE(jit, opline);
14102 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14103 						prop_ref, ir_CONST_ADDR(prop_info));
14104 					ir_END_list(end_inputs);
14105 					ir_IF_FALSE(if_null_or_flase);
14106 				}
14107 			} else if (flags == ZEND_FETCH_REF) {
14108 				ir_ref ref;
14109 
14110 				if (!prop_type_ref) {
14111 					prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14112 				}
14113 
14114 				ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14115 				ir_IF_FALSE(if_reference);
14116 				if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14117 					ref = ir_CONST_ADDR(prop_info);
14118 				} else {
14119 					int prop_info_offset =
14120 						(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14121 
14122 					ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14123 					ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14124 					ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14125 				}
14126 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14127 					prop_ref,
14128 					ref,
14129 					jit_ZVAL_ADDR(jit, res_addr));
14130 				ir_END_list(end_inputs);
14131 				ir_IF_TRUE(if_reference);
14132 			} else {
14133 				ZEND_UNREACHABLE();
14134 			}
14135 		}
14136 	}
14137 
14138 	if (opline->opcode == ZEND_FETCH_OBJ_W) {
14139 		ZEND_ASSERT(prop_ref);
14140 		jit_set_Z_PTR(jit, res_addr, prop_ref);
14141 		jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14142 		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14143 			ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14144 		}
14145 		ir_END_list(end_inputs);
14146 	} else {
14147 		if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
14148 		 || Z_MODE(res_addr) == IS_REG) {
14149 			ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14150 		} else {
14151 			prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14152 
14153 			if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14154 				return 0;
14155 			}
14156 			ir_END_list(end_inputs);
14157 		}
14158 	}
14159 
14160 	if (op1_avoid_refcounting) {
14161 		SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14162 	}
14163 
14164 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14165 		ir_MERGE_list(slow_inputs);
14166 		jit_SET_EX_OPLINE(jit, opline);
14167 
14168 		if (opline->opcode == ZEND_FETCH_OBJ_W) {
14169 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14170 			ir_END_list(end_inputs);
14171 		} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14172 			if (Z_MODE(res_addr) == IS_REG) {
14173 				ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14174 				ir_END_PHI_list(end_values, val_ref);
14175 			} else {
14176 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14177 				ir_END_list(end_inputs);
14178 			}
14179 		} else {
14180 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14181 			ir_END_list(end_inputs);
14182 		}
14183 	}
14184 
14185 	if (end_values) {
14186 		ir_ref val_ref = ir_PHI_list(end_values);
14187 		zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14188 		bool result_avoid_refcounting = 0;
14189 
14190 		ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14191 			|| opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14192 			|| opline->opcode == ZEND_FETCH_OBJ_IS);
14193 		ZEND_ASSERT(end_inputs == IR_UNUSED);
14194 		if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14195 			uint8_t type = concrete_type(res_info);
14196 			uint32_t flags = 0;
14197 
14198 			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14199 			 && !delayed_fetch_this
14200 			 && !op1_avoid_refcounting) {
14201 				flags = ZEND_JIT_EXIT_FREE_OP1;
14202 			}
14203 
14204 			if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14205 			 && !(flags & ZEND_JIT_EXIT_FREE_OP1)
14206 			 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
14207 			 && (ssa_op+1)->op1_use == ssa_op->result_def
14208 			 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14209 				result_avoid_refcounting = 1;
14210 				ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14211 			}
14212 
14213 			val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14214 				1, flags, op1_avoid_refcounting);
14215 			if (!val_addr) {
14216 				return 0;
14217 			}
14218 
14219 			res_info &= ~MAY_BE_GUARD;
14220 			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14221 		}
14222 
14223 		// ZVAL_COPY
14224 		jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14225 
14226 		if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14227 			return 0;
14228 		}
14229 	} else {
14230 		ir_MERGE_list(end_inputs);
14231 	}
14232 
14233 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14234 		if (opline->op1_type == IS_VAR
14235 		 && opline->opcode == ZEND_FETCH_OBJ_W
14236 		 && (op1_info & MAY_BE_RC1)) {
14237 			zend_jit_addr orig_op1_addr = OP1_ADDR();
14238 			ir_ref if_refcounted, ptr, refcount, if_non_zero;
14239 			ir_ref merge_inputs = IR_UNUSED;
14240 
14241 			if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14242 			ir_IF_FALSE( if_refcounted);
14243 			ir_END_list(merge_inputs);
14244 			ir_IF_TRUE( if_refcounted);
14245 			ptr = jit_Z_PTR(jit, orig_op1_addr);
14246 			refcount = jit_GC_DELREF(jit, ptr);
14247 			if_non_zero = ir_IF(refcount);
14248 			ir_IF_TRUE( if_non_zero);
14249 			ir_END_list(merge_inputs);
14250 			ir_IF_FALSE( if_non_zero);
14251 			jit_SET_EX_OPLINE(jit, opline);
14252 			ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14253 			ir_END_list(merge_inputs);
14254 			ir_MERGE_list(merge_inputs);
14255 		} else if (!op1_avoid_refcounting) {
14256 			if (on_this) {
14257 				op1_info &= ~MAY_BE_RC1;
14258 			}
14259 			jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14260 		}
14261 	}
14262 
14263 	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14264 	 && prop_info
14265 	 && (opline->opcode != ZEND_FETCH_OBJ_W ||
14266 	     !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14267 	     !ZEND_TYPE_IS_SET(prop_info->type))
14268 	 && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14269 		may_throw = 0;
14270 	}
14271 
14272 	if (may_throw) {
14273 		zend_jit_check_exception(jit);
14274 	}
14275 
14276 	return 1;
14277 }
14278 
14279 static int zend_jit_assign_obj(zend_jit_ctx         *jit,
14280                                const zend_op        *opline,
14281                                const zend_op_array  *op_array,
14282                                zend_ssa             *ssa,
14283                                const zend_ssa_op    *ssa_op,
14284                                uint32_t              op1_info,
14285                                zend_jit_addr         op1_addr,
14286                                uint32_t              val_info,
14287                                zend_jit_addr         val_addr,
14288                                zend_jit_addr         val_def_addr,
14289                                zend_jit_addr         res_addr,
14290                                bool                  op1_indirect,
14291                                zend_class_entry     *ce,
14292                                bool                  ce_is_instanceof,
14293                                bool                  on_this,
14294                                bool                  delayed_fetch_this,
14295                                zend_class_entry     *trace_ce,
14296                                uint8_t               prop_type,
14297                                int                   may_throw)
14298 {
14299 	zval *member;
14300 	zend_string *name;
14301 	zend_property_info *prop_info;
14302 	zend_jit_addr prop_addr;
14303 	ir_ref obj_ref = IR_UNUSED;
14304 	ir_ref prop_ref = IR_UNUSED;
14305 	ir_ref delayed_end_input = IR_UNUSED;
14306 	ir_ref end_inputs = IR_UNUSED;
14307 	ir_ref slow_inputs = IR_UNUSED;
14308 	uint32_t res_info = RES_INFO();
14309 
14310 	if (val_addr != val_def_addr && val_def_addr) {
14311 		if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14312 			return 0;
14313 		}
14314 		if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14315 			val_addr = val_def_addr;
14316 		}
14317 	}
14318 
14319 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14320 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14321 
14322 	member = RT_CONSTANT(opline, opline->op2);
14323 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14324 	name = Z_STR_P(member);
14325 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14326 
14327 	if (on_this) {
14328 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14329 		obj_ref = jit_Z_PTR(jit, this_addr);
14330 	} else {
14331 		if (opline->op1_type == IS_VAR
14332 		 && (op1_info & MAY_BE_INDIRECT)
14333 		 && Z_REG(op1_addr) == ZREG_FP) {
14334 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14335 		}
14336 		if (op1_info & MAY_BE_REF) {
14337 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14338 		}
14339 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14340 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14341 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14342 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14343 
14344 				if (!exit_addr) {
14345 					return 0;
14346 				}
14347 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14348 			} else {
14349 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14350 				ir_IF_FALSE_cold(if_obj);
14351 
14352 				jit_SET_EX_OPLINE(jit, opline);
14353 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14354 					jit_ZVAL_ADDR(jit, op1_addr),
14355 					ir_CONST_ADDR(ZSTR_VAL(name)));
14356 
14357 				if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
14358 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14359 				}
14360 
14361 				ir_END_list(end_inputs);
14362 
14363 				ir_IF_TRUE(if_obj);
14364 			}
14365 		}
14366 		obj_ref = jit_Z_PTR(jit, op1_addr);
14367 	}
14368 
14369 	ZEND_ASSERT(obj_ref);
14370 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14371 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14372 		if (prop_info) {
14373 			ce = trace_ce;
14374 			ce_is_instanceof = 0;
14375 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14376 				if (on_this && JIT_G(current_frame)
14377 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14378 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14379 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14380 					if (on_this && JIT_G(current_frame)) {
14381 						JIT_G(current_frame)->ce = ce;
14382 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14383 					}
14384 				} else {
14385 					return 0;
14386 				}
14387 				if (ssa->var_info && ssa_op->op1_use >= 0) {
14388 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14389 					ssa->var_info[ssa_op->op1_use].ce = ce;
14390 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14391 				}
14392 				if (ssa->var_info && ssa_op->op1_def >= 0) {
14393 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14394 					ssa->var_info[ssa_op->op1_def].ce = ce;
14395 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14396 				}
14397 			}
14398 		}
14399 	}
14400 
14401 	if (!prop_info) {
14402 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14403 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14404 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14405 
14406 		ir_IF_FALSE_cold(if_same);
14407 		ir_END_list(slow_inputs);
14408 
14409 		ir_IF_TRUE(if_same);
14410 		ir_ref offset_ref = ir_LOAD_A(
14411 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14412 
14413 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, IR_NULL));
14414 		ir_IF_TRUE_cold(if_dynamic);
14415 		ir_END_list(slow_inputs);
14416 
14417 		ir_IF_FALSE(if_dynamic);
14418 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14419 		ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14420 		ir_IF_FALSE_cold(if_def);
14421 		ir_END_list(slow_inputs);
14422 
14423 		ir_IF_TRUE(if_def);
14424 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14425 
14426 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14427 			ir_ref arg3, arg4;
14428 			ir_ref prop_info_ref = ir_LOAD_A(
14429 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14430 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14431 			ir_IF_TRUE_cold(if_has_prop_info);
14432 
14433 			if (Z_MODE(val_addr) == IS_REG) {
14434 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14435 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14436 					return 0;
14437 				}
14438 				arg3 = jit_ZVAL_ADDR(jit, real_addr);
14439 			} else {
14440 				arg3 = jit_ZVAL_ADDR(jit, val_addr);
14441 			}
14442 
14443 			if (!RETURN_VALUE_USED(opline)) {
14444 				arg4 = IR_NULL;
14445 			} else if (Z_MODE(res_addr) == IS_REG) {
14446 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14447 				arg4 = jit_ZVAL_ADDR(jit, real_addr);
14448 			} else {
14449 				arg4 = jit_ZVAL_ADDR(jit, res_addr);
14450 			}
14451 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14452 			jit_SET_EX_OPLINE(jit, opline);
14453 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14454 				prop_ref,
14455 				prop_info_ref,
14456 				arg3,
14457 				arg4);
14458 
14459 			if ((opline+1)->op1_type == IS_CONST) {
14460 				// TODO: ???
14461 				// if (Z_TYPE_P(value) == orig_type) {
14462 				// CACHE_PTR_EX(cache_slot + 2, NULL);
14463 			}
14464 
14465 			if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14466 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14467 				if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14468 					return 0;
14469 				}
14470 			}
14471 
14472 			ir_END_list(end_inputs);
14473 			ir_IF_FALSE(if_has_prop_info);
14474 		}
14475 	} else {
14476 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14477 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14478 		if (!ce || ce_is_instanceof || !(ce->ce_flags & ZEND_ACC_IMMUTABLE) || ce->__get || ce->__set || (prop_info->flags & ZEND_ACC_READONLY)) {
14479 			// Undefined property with magic __get()/__set()
14480 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14481 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14482 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14483 
14484 				if (!exit_addr) {
14485 					return 0;
14486 				}
14487 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14488 			} else {
14489 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14490 				ir_IF_FALSE_cold(if_def);
14491 				ir_END_list(slow_inputs);
14492 				ir_IF_TRUE(if_def);
14493 			}
14494 		}
14495 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14496 			ir_ref ref, arg3, arg4;
14497 
14498 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14499 			jit_SET_EX_OPLINE(jit, opline);
14500 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14501 				ref = ir_CONST_ADDR(prop_info);
14502 			} else {
14503 				int prop_info_offset =
14504 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14505 
14506 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14507 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14508 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14509 			}
14510 			if (Z_MODE(val_addr) == IS_REG) {
14511 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14512 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14513 					return 0;
14514 				}
14515 				arg3 = jit_ZVAL_ADDR(jit, real_addr);
14516 			} else {
14517 				arg3 = jit_ZVAL_ADDR(jit, val_addr);
14518 			}
14519 			if (!RETURN_VALUE_USED(opline)) {
14520 				arg4 = IR_NULL;
14521 			} else if (Z_MODE(res_addr) == IS_REG) {
14522 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14523 				arg4 = jit_ZVAL_ADDR(jit, real_addr);
14524 			} else {
14525 				arg4 = jit_ZVAL_ADDR(jit, res_addr);
14526 			}
14527 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14528 				prop_ref,
14529 				ref,
14530 				arg3,
14531 				arg4);
14532 
14533 			if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14534 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14535 				if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14536 					return 0;
14537 				}
14538 			}
14539 			ir_END_list(end_inputs);
14540 		}
14541 	}
14542 
14543 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14544 		if (Z_MODE(val_addr) != IS_REG
14545 		 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
14546 		 && opline->result_type == IS_UNUSED) {
14547 			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)) {
14548 				return 0;
14549 			}
14550 		} else {
14551 			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)) {
14552 				return 0;
14553 			}
14554 		}
14555 		if (end_inputs || slow_inputs) {
14556 			if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14557 			 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14558 				/* skip FREE_OP_DATA() */
14559 				delayed_end_input = ir_END();
14560 			} else {
14561 				ir_END_list(end_inputs);
14562 			}
14563 		}
14564 	}
14565 
14566 	if (slow_inputs) {
14567 		ir_ref arg3, arg5;
14568 
14569 		ir_MERGE_list(slow_inputs);
14570 		jit_SET_EX_OPLINE(jit, opline);
14571 
14572 		if (Z_MODE(val_addr) == IS_REG) {
14573 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14574 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14575 				return 0;
14576 			}
14577 			arg3 = jit_ZVAL_ADDR(jit, real_addr);
14578 		} else {
14579 			arg3 = jit_ZVAL_ADDR(jit, val_addr);
14580 		}
14581 		if (!RETURN_VALUE_USED(opline)) {
14582 			arg5 = IR_NULL;
14583 		} else if (Z_MODE(res_addr) == IS_REG) {
14584 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14585 			arg5 = jit_ZVAL_ADDR(jit, real_addr);
14586 		} else {
14587 			arg5 = jit_ZVAL_ADDR(jit, res_addr);
14588 		}
14589 
14590 		// JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14591 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14592 		ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
14593 			obj_ref,
14594 			ir_CONST_ADDR(name),
14595 			arg3,
14596 			ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
14597 			arg5);
14598 
14599 		if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14600 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14601 			if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14602 				return 0;
14603 			}
14604 		}
14605 		ir_END_list(end_inputs);
14606 	}
14607 
14608 	if (end_inputs) {
14609 		ir_MERGE_list(end_inputs);
14610 
14611 		if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14612 			val_info |= MAY_BE_RC1|MAY_BE_RCN;
14613 		}
14614 		jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
14615 
14616 		if (delayed_end_input) {
14617 			ir_MERGE_WITH(delayed_end_input);
14618 		}
14619 	}
14620 
14621 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14622 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14623 	}
14624 
14625 	if (may_throw) {
14626 		zend_jit_check_exception(jit);
14627 	}
14628 
14629 	return 1;
14630 }
14631 
14632 static int zend_jit_assign_obj_op(zend_jit_ctx         *jit,
14633                                   const zend_op        *opline,
14634                                   const zend_op_array  *op_array,
14635                                   zend_ssa             *ssa,
14636                                   const zend_ssa_op    *ssa_op,
14637                                   uint32_t              op1_info,
14638                                   zend_jit_addr         op1_addr,
14639                                   uint32_t              val_info,
14640                                   zend_jit_addr         val_addr,
14641                                   zend_ssa_range       *val_range,
14642                                   bool                  op1_indirect,
14643                                   zend_class_entry     *ce,
14644                                   bool                  ce_is_instanceof,
14645                                   bool                  on_this,
14646                                   bool                  delayed_fetch_this,
14647                                   zend_class_entry     *trace_ce,
14648                                   uint8_t               prop_type)
14649 {
14650 	zval *member;
14651 	zend_string *name;
14652 	zend_property_info *prop_info;
14653 	zend_jit_addr prop_addr;
14654 	bool use_prop_guard = 0;
14655 	bool may_throw = 0;
14656 	binary_op_type binary_op = get_binary_op(opline->extended_value);
14657 	ir_ref obj_ref = IR_UNUSED;
14658 	ir_ref prop_ref = IR_UNUSED;
14659 	ir_ref end_inputs = IR_UNUSED;
14660 	ir_ref slow_inputs = IR_UNUSED;
14661 
14662 	ZEND_ASSERT(opline->op2_type == IS_CONST);
14663 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14664 	ZEND_ASSERT(opline->result_type == IS_UNUSED);
14665 
14666 	member = RT_CONSTANT(opline, opline->op2);
14667 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14668 	name = Z_STR_P(member);
14669 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14670 
14671 	if (on_this) {
14672 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14673 		obj_ref = jit_Z_PTR(jit, this_addr);
14674 	} else {
14675 		if (opline->op1_type == IS_VAR
14676 		 && (op1_info & MAY_BE_INDIRECT)
14677 		 && Z_REG(op1_addr) == ZREG_FP) {
14678 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14679 		}
14680 		if (op1_info & MAY_BE_REF) {
14681 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14682 		}
14683 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14684 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14685 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14686 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14687 
14688 				if (!exit_addr) {
14689 					return 0;
14690 				}
14691 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14692 			} else {
14693 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14694 				ir_IF_FALSE_cold(if_obj);
14695 
14696 				jit_SET_EX_OPLINE(jit, opline);
14697 				ir_CALL_2(IR_VOID,
14698 					(op1_info & MAY_BE_UNDEF) ?
14699 						ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
14700 						ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14701 					jit_ZVAL_ADDR(jit, op1_addr),
14702 					ir_CONST_ADDR(ZSTR_VAL(name)));
14703 
14704 				may_throw = 1;
14705 
14706 				ir_END_list(end_inputs);
14707 				ir_IF_TRUE(if_obj);
14708 			}
14709 		}
14710 		obj_ref = jit_Z_PTR(jit, op1_addr);
14711 	}
14712 
14713 	ZEND_ASSERT(obj_ref);
14714 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14715 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14716 		if (prop_info) {
14717 			ce = trace_ce;
14718 			ce_is_instanceof = 0;
14719 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14720 				if (on_this && JIT_G(current_frame)
14721 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14722 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14723 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14724 					if (on_this && JIT_G(current_frame)) {
14725 						JIT_G(current_frame)->ce = ce;
14726 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14727 					}
14728 				} else {
14729 					return 0;
14730 				}
14731 				if (ssa->var_info && ssa_op->op1_use >= 0) {
14732 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14733 					ssa->var_info[ssa_op->op1_use].ce = ce;
14734 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14735 				}
14736 				if (ssa->var_info && ssa_op->op1_def >= 0) {
14737 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14738 					ssa->var_info[ssa_op->op1_def].ce = ce;
14739 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14740 				}
14741 			}
14742 		}
14743 	}
14744 
14745 	use_prop_guard = (prop_type != IS_UNKNOWN
14746 		&& prop_type != IS_UNDEF
14747 		&& prop_type != IS_REFERENCE
14748 		&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
14749 
14750 	if (!prop_info) {
14751 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14752 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14753 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14754 
14755 		ir_IF_FALSE_cold(if_same);
14756 		ir_END_list(slow_inputs);
14757 
14758 		ir_IF_TRUE(if_same);
14759 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14760 			ir_ref prop_info_ref = ir_LOAD_A(
14761 				ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14762 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14763 			ir_IF_TRUE_cold(if_has_prop_info);
14764 			ir_END_list(slow_inputs);
14765 
14766 			ir_IF_FALSE(if_has_prop_info);
14767 		}
14768 		ir_ref offset_ref = ir_LOAD_A(
14769 			ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14770 
14771 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, IR_NULL));
14772 		ir_IF_TRUE_cold(if_dynamic);
14773 		ir_END_list(slow_inputs);
14774 
14775 		ir_IF_FALSE(if_dynamic);
14776 
14777 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
14778 		if (!use_prop_guard) {
14779 			ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14780 			ir_IF_FALSE_cold(if_def);
14781 			ir_END_list(slow_inputs);
14782 
14783 			ir_IF_TRUE(if_def);
14784 		}
14785 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14786 	} else {
14787 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14788 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14789 
14790 		if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
14791 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14792 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14793 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14794 
14795 				if (!exit_addr) {
14796 					return 0;
14797 				}
14798 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14799 			} else {
14800 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14801 				ir_IF_FALSE_cold(if_def);
14802 				ir_END_list(slow_inputs);
14803 				ir_IF_TRUE(if_def);
14804 			}
14805 		}
14806 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14807 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
14808 
14809 			may_throw = 1;
14810 
14811 			jit_SET_EX_OPLINE(jit, opline);
14812 
14813 			if (Z_MODE(val_addr) == IS_REG) {
14814 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14815 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14816 					return 0;
14817 				}
14818 				arg2 = jit_ZVAL_ADDR(jit, real_addr);
14819 			} else {
14820 				arg2 = jit_ZVAL_ADDR(jit, val_addr);
14821 			}
14822 
14823 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
14824 			ir_IF_FALSE(if_ref);
14825 			noref_path = ir_END();
14826 			ir_IF_TRUE(if_ref);
14827 
14828 			reference = jit_Z_PTR(jit, prop_addr);
14829 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
14830 			if_typed = jit_if_TYPED_REF(jit, reference);
14831 			ir_IF_FALSE(if_typed);
14832 			ref_path = ir_END();
14833 			ir_IF_TRUE_cold(if_typed);
14834 
14835 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
14836 				reference,
14837 				arg2,
14838 				ir_CONST_FC_FUNC(binary_op));
14839 
14840 			ir_END_list(end_inputs);
14841 
14842 			ir_MERGE_2(noref_path, ref_path);
14843 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
14844 			prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14845 
14846 			// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14847 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14848 				ref = ir_CONST_ADDR(prop_info);
14849 			} else {
14850 				int prop_info_offset =
14851 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14852 
14853 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14854 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14855 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14856 			}
14857 
14858 			ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
14859 				prop_ref,
14860 				ref,
14861 				arg2,
14862 				ir_CONST_FC_FUNC(binary_op));
14863 
14864 			ir_END_list(end_inputs);
14865 		}
14866 	}
14867 
14868 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14869 		zend_jit_addr var_addr = prop_addr;
14870 		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
14871 		uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
14872 
14873 		if (use_prop_guard) {
14874 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14875 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14876 			if (!exit_addr) {
14877 				return 0;
14878 			}
14879 
14880 			jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
14881 			var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
14882 		}
14883 
14884 		if (var_info & MAY_BE_REF) {
14885 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
14886 
14887 			may_throw = 1;
14888 
14889 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
14890 			ir_IF_FALSE(if_ref);
14891 			noref_path = ir_END();
14892 			ir_IF_TRUE(if_ref);
14893 
14894 			reference = jit_Z_PTR(jit, var_addr);
14895 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
14896 			if_typed = jit_if_TYPED_REF(jit, reference);
14897 			ir_IF_FALSE(if_typed);
14898 			ref_path = ir_END();
14899 			ir_IF_TRUE_cold(if_typed);
14900 
14901 			jit_SET_EX_OPLINE(jit, opline);
14902 
14903 			if (Z_MODE(val_addr) == IS_REG) {
14904 				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14905 				if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14906 					return 0;
14907 				}
14908 				arg2 = jit_ZVAL_ADDR(jit, real_addr);
14909 			} else {
14910 				arg2 = jit_ZVAL_ADDR(jit, val_addr);
14911 			}
14912 			ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
14913 				reference,
14914 				arg2,
14915 				ir_CONST_FC_FUNC(binary_op));
14916 
14917 			ir_END_list(end_inputs);
14918 
14919 			ir_MERGE_2(noref_path, ref_path);
14920 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
14921 			var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14922 
14923 			var_info &= ~MAY_BE_REF;
14924 		}
14925 
14926 		uint8_t val_op_type = (opline+1)->op1_type;
14927 		if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
14928 			/* prevent FREE_OP in the helpers */
14929 			val_op_type = IS_CV;
14930 		}
14931 
14932 		switch (opline->extended_value) {
14933 			case ZEND_ADD:
14934 			case ZEND_SUB:
14935 			case ZEND_MUL:
14936 				if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
14937 				    (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14938 					if (opline->extended_value != ZEND_ADD ||
14939 					    (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
14940 					    (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
14941 						may_throw = 1;
14942 					}
14943 				}
14944 				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,
14945 						1 /* may overflow */, 0)) {
14946 					return 0;
14947 				}
14948 				break;
14949 			case ZEND_BW_OR:
14950 			case ZEND_BW_AND:
14951 			case ZEND_BW_XOR:
14952 				if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
14953 				    (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14954 					if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
14955 					    (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
14956 						may_throw = 1;
14957 					}
14958 				}
14959 				goto long_math;
14960 			case ZEND_SL:
14961 			case ZEND_SR:
14962 				if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
14963 				    (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14964 					may_throw = 1;
14965 				}
14966 				if (val_op_type != IS_CONST ||
14967 				    Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
14968 				    Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
14969 					may_throw = 1;
14970 				}
14971 				goto long_math;
14972 			case ZEND_MOD:
14973 				if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
14974 				    (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14975 					may_throw = 1;
14976 				}
14977 				if (val_op_type != IS_CONST ||
14978 				    Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
14979 				    Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
14980 					may_throw = 1;
14981 				}
14982 long_math:
14983 				if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
14984 						IS_CV, opline->op1, var_addr, var_info, NULL,
14985 						val_op_type, (opline+1)->op1, val_addr, val_info,
14986 						val_range,
14987 						0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
14988 					return 0;
14989 				}
14990 				break;
14991 			case ZEND_CONCAT:
14992 				may_throw = 1;
14993 				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,
14994 						0)) {
14995 					return 0;
14996 				}
14997 				break;
14998 			default:
14999 				ZEND_UNREACHABLE();
15000 		}
15001 		if (end_inputs || slow_inputs) {
15002 			ir_END_list(end_inputs);
15003 		}
15004 	}
15005 
15006 	if (slow_inputs) {
15007 		ir_ref arg3;
15008 
15009 		ir_MERGE_list(slow_inputs);
15010 
15011 		may_throw = 1;
15012 
15013 		if (Z_MODE(val_addr) == IS_REG) {
15014 			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15015 			if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15016 				return 0;
15017 			}
15018 			arg3 = jit_ZVAL_ADDR(jit, real_addr);
15019 		} else {
15020 			arg3 = jit_ZVAL_ADDR(jit, val_addr);
15021 		}
15022 		jit_SET_EX_OPLINE(jit, opline);
15023 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15024 		ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15025 			obj_ref,
15026 			ir_CONST_ADDR(name),
15027 			arg3,
15028 			ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15029 			ir_CONST_FC_FUNC(binary_op));
15030 
15031 		ir_END_list(end_inputs);
15032 	}
15033 
15034 	if (end_inputs) {
15035 		ir_MERGE_list(end_inputs);
15036 	}
15037 
15038 	if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15039 		val_info |= MAY_BE_RC1|MAY_BE_RCN;
15040 	}
15041 
15042 	// JIT: FREE_OP_DATA();
15043 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15044 
15045 	if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15046 		if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15047 			may_throw = 1;
15048 		}
15049 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15050 	}
15051 
15052 	if (may_throw) {
15053 		zend_jit_check_exception(jit);
15054 	}
15055 
15056 	return 1;
15057 }
15058 
15059 static int zend_jit_incdec_obj(zend_jit_ctx         *jit,
15060                                const zend_op        *opline,
15061                                const zend_op_array  *op_array,
15062                                zend_ssa             *ssa,
15063                                const zend_ssa_op    *ssa_op,
15064                                uint32_t              op1_info,
15065                                zend_jit_addr         op1_addr,
15066                                bool                  op1_indirect,
15067                                zend_class_entry     *ce,
15068                                bool                  ce_is_instanceof,
15069                                bool                  on_this,
15070                                bool                  delayed_fetch_this,
15071                                zend_class_entry     *trace_ce,
15072                                uint8_t               prop_type)
15073 {
15074 	zval *member;
15075 	zend_string *name;
15076 	zend_property_info *prop_info;
15077 	zend_jit_addr res_addr = 0;
15078 	zend_jit_addr prop_addr;
15079 	bool use_prop_guard = 0;
15080 	bool may_throw = 0;
15081 	uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15082 	ir_ref obj_ref = IR_UNUSED;
15083 	ir_ref prop_ref = IR_UNUSED;
15084 	ir_ref end_inputs = IR_UNUSED;
15085 	ir_ref slow_inputs = IR_UNUSED;
15086 
15087 	ZEND_ASSERT(opline->op2_type == IS_CONST);
15088 	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15089 
15090 	if (opline->result_type != IS_UNUSED) {
15091 		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15092 	}
15093 
15094 	member = RT_CONSTANT(opline, opline->op2);
15095 	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15096 	name = Z_STR_P(member);
15097 	prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15098 
15099 	if (on_this) {
15100 		zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15101 		obj_ref = jit_Z_PTR(jit, this_addr);
15102 	} else {
15103 		if (opline->op1_type == IS_VAR
15104 		 && (op1_info & MAY_BE_INDIRECT)
15105 		 && Z_REG(op1_addr) == ZREG_FP) {
15106 			op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15107 		}
15108 		if (op1_info & MAY_BE_REF) {
15109 			op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15110 		}
15111 		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15112 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15113 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15114 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15115 
15116 				if (!exit_addr) {
15117 					return 0;
15118 				}
15119 				jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15120 			} else {
15121 				ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15122 				ir_IF_FALSE_cold(if_obj);
15123 
15124 				jit_SET_EX_OPLINE(jit, opline);
15125 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15126 					jit_ZVAL_ADDR(jit, op1_addr),
15127 					ir_CONST_ADDR(ZSTR_VAL(name)));
15128 
15129 				ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15130 				ir_IF_TRUE(if_obj);
15131 			}
15132 		}
15133 		obj_ref = jit_Z_PTR(jit, op1_addr);
15134 	}
15135 
15136 	ZEND_ASSERT(obj_ref);
15137 	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15138 		prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15139 		if (prop_info) {
15140 			ce = trace_ce;
15141 			ce_is_instanceof = 0;
15142 			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15143 				if (on_this && JIT_G(current_frame)
15144 				 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15145 					ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15146 				} else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15147 					if (on_this && JIT_G(current_frame)) {
15148 						JIT_G(current_frame)->ce = ce;
15149 						TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15150 					}
15151 				} else {
15152 					return 0;
15153 				}
15154 				if (ssa->var_info && ssa_op->op1_use >= 0) {
15155 					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15156 					ssa->var_info[ssa_op->op1_use].ce = ce;
15157 					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15158 				}
15159 				if (ssa->var_info && ssa_op->op1_def >= 0) {
15160 					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15161 					ssa->var_info[ssa_op->op1_def].ce = ce;
15162 					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15163 				}
15164 			}
15165 		}
15166 	}
15167 
15168 	use_prop_guard = (prop_type != IS_UNKNOWN
15169 		&& prop_type != IS_UNDEF
15170 		&& prop_type != IS_REFERENCE
15171 		&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15172 
15173 	if (!prop_info) {
15174 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15175 		ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15176 		ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15177 
15178 		ir_IF_FALSE_cold(if_same);
15179 		ir_END_list(slow_inputs);
15180 
15181 		ir_IF_TRUE(if_same);
15182 		if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15183 			ir_ref prop_info_ref = ir_LOAD_A(
15184 				ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15185 			ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15186 			ir_IF_TRUE_cold(if_has_prop_info);
15187 			ir_END_list(slow_inputs);
15188 
15189 			ir_IF_FALSE(if_has_prop_info);
15190 		}
15191 		ir_ref offset_ref = ir_LOAD_A(
15192 			ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15193 
15194 		ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, IR_NULL));
15195 		ir_IF_TRUE_cold(if_dynamic);
15196 		ir_END_list(slow_inputs);
15197 
15198 		ir_IF_FALSE(if_dynamic);
15199 
15200 		prop_ref = ir_ADD_A(obj_ref, offset_ref);
15201 		if (!use_prop_guard) {
15202 			ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15203 			ir_IF_FALSE_cold(if_def);
15204 			ir_END_list(slow_inputs);
15205 
15206 			ir_IF_TRUE(if_def);
15207 		}
15208 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15209 	} else {
15210 		prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15211 		prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15212 
15213 		if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15214 			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15215 				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15216 				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15217 
15218 				if (!exit_addr) {
15219 					return 0;
15220 				}
15221 				ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15222 			} else {
15223 				ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15224 				ir_IF_FALSE_cold(if_def);
15225 				ir_END_list(slow_inputs);
15226 				ir_IF_TRUE(if_def);
15227 			}
15228 		}
15229 
15230 		if (ZEND_TYPE_IS_SET(prop_info->type)) {
15231 			const void *func;
15232 			ir_ref ref;
15233 
15234 			may_throw = 1;
15235 			jit_SET_EX_OPLINE(jit, opline);
15236 
15237 			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15238 				ref = ir_CONST_ADDR(prop_info);
15239 			} else {
15240 				int prop_info_offset =
15241 					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15242 
15243 				ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15244 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15245 				ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15246 			}
15247 
15248 			if (opline->result_type == IS_UNUSED) {
15249 				switch (opline->opcode) {
15250 					case ZEND_PRE_INC_OBJ:
15251 					case ZEND_POST_INC_OBJ:
15252 						func = zend_jit_inc_typed_prop;
15253 						break;
15254 					case ZEND_PRE_DEC_OBJ:
15255 					case ZEND_POST_DEC_OBJ:
15256 						func = zend_jit_dec_typed_prop;
15257 						break;
15258 					default:
15259 						ZEND_UNREACHABLE();
15260 				}
15261 
15262 				ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
15263 			} else {
15264 				switch (opline->opcode) {
15265 					case ZEND_PRE_INC_OBJ:
15266 						func = zend_jit_pre_inc_typed_prop;
15267 						break;
15268 					case ZEND_PRE_DEC_OBJ:
15269 						func = zend_jit_pre_dec_typed_prop;
15270 						break;
15271 					case ZEND_POST_INC_OBJ:
15272 						func = zend_jit_post_inc_typed_prop;
15273 						break;
15274 					case ZEND_POST_DEC_OBJ:
15275 						func = zend_jit_post_dec_typed_prop;
15276 						break;
15277 					default:
15278 						ZEND_UNREACHABLE();
15279 				}
15280 				ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func),
15281 					prop_ref,
15282 					ref,
15283 					jit_ZVAL_ADDR(jit, res_addr));
15284 			}
15285 			ir_END_list(end_inputs);
15286 		}
15287 	}
15288 
15289 	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15290 		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15291 		zend_jit_addr var_addr = prop_addr;
15292 		ir_ref if_long = IR_UNUSED;
15293 		ir_ref if_overflow = IR_UNUSED;
15294 
15295 		if (use_prop_guard) {
15296 			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15297 			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15298 			if (!exit_addr) {
15299 				return 0;
15300 			}
15301 
15302 			jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15303 			var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15304 		}
15305 
15306 		if (var_info & MAY_BE_REF) {
15307 			const void *func;
15308 			ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
15309 
15310 			if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15311 			ir_IF_FALSE(if_ref);
15312 			noref_path = ir_END();
15313 			ir_IF_TRUE(if_ref);
15314 
15315 			reference = jit_Z_PTR(jit, var_addr);
15316 			ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15317 			if_typed = jit_if_TYPED_REF(jit, reference);
15318 			ir_IF_FALSE(if_typed);
15319 			ref_path = ir_END();
15320 			ir_IF_TRUE_cold(if_typed);
15321 
15322 			switch (opline->opcode) {
15323 				case ZEND_PRE_INC_OBJ:
15324 					func = zend_jit_pre_inc_typed_ref;
15325 					break;
15326 				case ZEND_PRE_DEC_OBJ:
15327 					func = zend_jit_pre_dec_typed_ref;
15328 					break;
15329 				case ZEND_POST_INC_OBJ:
15330 					func = zend_jit_post_inc_typed_ref;
15331 					break;
15332 				case ZEND_POST_DEC_OBJ:
15333 					func = zend_jit_post_dec_typed_ref;
15334 					break;
15335 				default:
15336 					ZEND_UNREACHABLE();
15337 			}
15338 
15339 			may_throw = 1;
15340 			jit_SET_EX_OPLINE(jit, opline);
15341 			ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func),
15342 				reference,
15343 				(opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15344 
15345 			ir_END_list(end_inputs);
15346 
15347 			ir_MERGE_2(noref_path, ref_path);
15348 			prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15349 			var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15350 
15351 			var_info &= ~MAY_BE_REF;
15352 		}
15353 
15354 		if (var_info & MAY_BE_LONG) {
15355 			ir_ref addr, ref;
15356 
15357 			if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15358 				if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
15359 				ir_IF_TRUE(if_long);
15360 			}
15361 
15362 			addr = jit_ZVAL_ADDR(jit, var_addr);
15363 			ref = ir_LOAD_L(addr);
15364 			if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15365 				if (opline->result_type != IS_UNUSED) {
15366 					jit_set_Z_LVAL(jit, res_addr, ref);
15367 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15368 				}
15369 			}
15370 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15371 				ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
15372 			} else {
15373 				ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
15374 			}
15375 
15376 			ir_STORE(addr, ref);
15377 			if_overflow = ir_IF(ir_OVERFLOW(ref));
15378 			ir_IF_FALSE(if_overflow);
15379 
15380 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
15381 				if (opline->result_type != IS_UNUSED) {
15382 					jit_set_Z_LVAL(jit, res_addr, ref);
15383 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15384 				}
15385 			}
15386 			ir_END_list(end_inputs);
15387 		}
15388 
15389 		if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15390 			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15391 				may_throw = 1;
15392 			}
15393 			if (if_long) {
15394 				ir_IF_FALSE_cold(if_long);
15395 			}
15396 			if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15397 				jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, 1);
15398 			}
15399 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15400 				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15401 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
15402 						jit_ZVAL_ADDR(jit, var_addr),
15403 						jit_ZVAL_ADDR(jit, res_addr));
15404 				} else {
15405 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function),
15406 						jit_ZVAL_ADDR(jit, var_addr));
15407 				}
15408 			} else {
15409 				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15410 					ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
15411 						jit_ZVAL_ADDR(jit, var_addr),
15412 						jit_ZVAL_ADDR(jit, res_addr));
15413 				} else {
15414 					ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function),
15415 						jit_ZVAL_ADDR(jit, var_addr));
15416 				}
15417 			}
15418 
15419 			ir_END_list(end_inputs);
15420 		}
15421 		if (var_info & MAY_BE_LONG) {
15422 			ir_IF_TRUE_cold(if_overflow);
15423 			if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15424 #if SIZEOF_ZEND_LONG == 4
15425 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
15426 				jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
15427 #else
15428 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
15429 #endif
15430 				jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15431 				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15432 #if SIZEOF_ZEND_LONG == 4
15433 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
15434 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
15435 #else
15436 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
15437 #endif
15438 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15439 				}
15440 			} else {
15441 #if SIZEOF_ZEND_LONG == 4
15442 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
15443 				jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
15444 #else
15445 				jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
15446 #endif
15447 				jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15448 				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15449 #if SIZEOF_ZEND_LONG == 4
15450 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
15451 					jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
15452 #else
15453 					jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
15454 #endif
15455 					jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15456 				}
15457 			}
15458 			if (opline->result_type != IS_UNUSED
15459 			 && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
15460 			 && prop_info
15461 			 && !ZEND_TYPE_IS_SET(prop_info->type)
15462 			 && (res_info & MAY_BE_GUARD)
15463 			 && (res_info & MAY_BE_LONG)) {
15464 				zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
15465 				uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
15466 				int32_t exit_point;
15467 				const void *exit_addr;
15468 
15469 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
15470 				exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15471 				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15472 				if (!exit_addr) {
15473 					return 0;
15474 				}
15475 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
15476 				ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
15477 				jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15478 			} else {
15479 				ir_END_list(end_inputs);
15480 			}
15481 		}
15482 	}
15483 
15484 	if (slow_inputs) {
15485 		const void *func;
15486 
15487 		ir_MERGE_list(slow_inputs);
15488 
15489 		// JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
15490 		switch (opline->opcode) {
15491 			case ZEND_PRE_INC_OBJ:
15492 				func = zend_jit_pre_inc_obj_helper;
15493 				break;
15494 			case ZEND_PRE_DEC_OBJ:
15495 				func = zend_jit_pre_dec_obj_helper;
15496 				break;
15497 			case ZEND_POST_INC_OBJ:
15498 				func = zend_jit_post_inc_obj_helper;
15499 				break;
15500 			case ZEND_POST_DEC_OBJ:
15501 				func = zend_jit_post_dec_obj_helper;
15502 				break;
15503 			default:
15504 				ZEND_UNREACHABLE();
15505 		}
15506 
15507 		may_throw = 1;
15508 		jit_SET_EX_OPLINE(jit, opline);
15509 		ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15510 		ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func),
15511 			obj_ref,
15512 			ir_CONST_ADDR(name),
15513 			ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15514 			(opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15515 
15516 		ir_END_list(end_inputs);
15517 	}
15518 
15519 	if (end_inputs) {
15520 		ir_MERGE_list(end_inputs);
15521 	}
15522 
15523 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
15524 		if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15525 			may_throw = 1;
15526 		}
15527 		jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15528 	}
15529 
15530 	if (may_throw) {
15531 		zend_jit_check_exception(jit);
15532 	}
15533 
15534 	return 1;
15535 }
15536 
15537 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)
15538 {
15539 	HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
15540 	const zend_op *next_opline = NULL;
15541 	ir_refs *slow_inputs;
15542 
15543 	ir_refs_init(slow_inputs, 8);
15544 
15545 	if (trace) {
15546 		ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
15547 		ZEND_ASSERT(trace->opline != NULL);
15548 		next_opline = trace->opline;
15549 	}
15550 
15551 	if (opline->op1_type == IS_CONST) {
15552 		zval *zv = RT_CONSTANT(opline, opline->op1);
15553 		zval *jump_zv = NULL;
15554 		int b;
15555 
15556 		if (opline->opcode == ZEND_SWITCH_LONG) {
15557 			if (Z_TYPE_P(zv) == IS_LONG) {
15558 				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
15559 			}
15560 		} else if (opline->opcode == ZEND_SWITCH_STRING) {
15561 			if (Z_TYPE_P(zv) == IS_STRING) {
15562 				jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
15563 			}
15564 		} else if (opline->opcode == ZEND_MATCH) {
15565 			if (Z_TYPE_P(zv) == IS_LONG) {
15566 				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
15567 			} else if (Z_TYPE_P(zv) == IS_STRING) {
15568 				jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
15569 			}
15570 		} else {
15571 			ZEND_UNREACHABLE();
15572 		}
15573 		if (next_opline) {
15574 			const zend_op *target;
15575 
15576 			if (jump_zv != NULL) {
15577 				target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
15578 			} else {
15579 				target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
15580 			}
15581 			ZEND_ASSERT(target == next_opline);
15582 		} else {
15583 			if (jump_zv != NULL) {
15584 				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
15585 			} else {
15586 				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
15587 			}
15588 			_zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
15589 			jit->b = -1;
15590 		}
15591 	} else {
15592 		zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
15593 		uint32_t op1_info = OP1_INFO();
15594 		zend_jit_addr op1_addr = OP1_ADDR();
15595 		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
15596 		const zend_op *target;
15597 		int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
15598 		int b;
15599 		int32_t exit_point;
15600 		const void *exit_addr;
15601 		const void *default_label = NULL;
15602 		zval *zv;
15603 
15604 		if (next_opline) {
15605 			if (next_opline != default_opline) {
15606 				exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
15607 				default_label = zend_jit_trace_get_exit_addr(exit_point);
15608 				if (!default_label) {
15609 					return 0;
15610 				}
15611 			}
15612 		}
15613 
15614 		if (opline->opcode == ZEND_SWITCH_LONG) {
15615 			if (op1_info & MAY_BE_LONG) {
15616 				const void *fallback_label = NULL;
15617 
15618 				if (next_opline) {
15619 					if (next_opline != opline + 1) {
15620 						exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15621 						fallback_label = zend_jit_trace_get_exit_addr(exit_point);
15622 						if (!fallback_label) {
15623 							return 0;
15624 						}
15625 					}
15626 				}
15627 				if (op1_info & MAY_BE_REF) {
15628 					ir_ref ref, if_long, fast_path, ref2;
15629 
15630 					ref = jit_ZVAL_ADDR(jit, op1_addr);
15631 					if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15632 					ir_IF_TRUE(if_long);
15633 					fast_path = ir_END();
15634 					ir_IF_FALSE_cold(if_long);
15635 
15636 					// JIT: ZVAL_DEREF(op)
15637 					if (fallback_label) {
15638 						jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
15639 					} else {
15640 						ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
15641 						ir_IF_FALSE_cold(if_ref);
15642 						ir_refs_add(slow_inputs, ir_END());
15643 						ir_IF_TRUE(if_ref);
15644 					}
15645 
15646 					ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
15647 					op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
15648 
15649 					if (fallback_label) {
15650 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15651 					} else {
15652 						if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15653 						ir_IF_FALSE_cold(if_long);
15654 						ir_refs_add(slow_inputs, ir_END());
15655 						ir_IF_TRUE(if_long);
15656 					}
15657 
15658 					ir_MERGE_2(fast_path, ir_END());
15659 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
15660 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
15661 				} else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
15662 					if (fallback_label) {
15663 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15664 					} else {
15665 						ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15666 						ir_IF_FALSE_cold(if_long);
15667 						ir_refs_add(slow_inputs, ir_END());
15668 						ir_IF_TRUE(if_long);
15669 					}
15670 				}
15671 				ir_ref ref = jit_Z_LVAL(jit, op1_addr);
15672 
15673 				if (!HT_IS_PACKED(jumptable)) {
15674 					ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
15675 						ir_CONST_ADDR(jumptable), ref);
15676 					ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
15677 					/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
15678 					if (sizeof(Bucket) == 32) {
15679 						ref = ir_SHR_L(ref, ir_CONST_LONG(5));
15680 					} else {
15681 						ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
15682 					}
15683 				}
15684 				ref = ir_SWITCH(ref);
15685 
15686 				if (next_opline) {
15687 					ir_ref continue_list = IR_UNUSED;
15688 
15689 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15690 						ir_ref idx;
15691 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15692 
15693 						if (HT_IS_PACKED(jumptable)) {
15694 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
15695 						} else {
15696 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
15697 						}
15698 						ir_CASE_VAL(ref, idx);
15699 						if (target == next_opline) {
15700 							ir_END_list(continue_list);
15701 						} else {
15702 							exit_point = zend_jit_trace_get_exit_point(target, 0);
15703 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15704 							if (!exit_addr) {
15705 								return 0;
15706 							}
15707 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15708 						}
15709 					} ZEND_HASH_FOREACH_END();
15710 
15711 					ir_CASE_DEFAULT(ref);
15712 					if (next_opline == default_opline) {
15713 						ir_END_list(continue_list);
15714 					} else {
15715 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
15716 					}
15717 					if (continue_list) {
15718 						ir_MERGE_list(continue_list);
15719 					} else {
15720 						ZEND_ASSERT(slow_inputs->count);
15721 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15722 					}
15723 				} else {
15724 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15725 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15726 						b = ssa->cfg.map[target - op_array->opcodes];
15727 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
15728 					} ZEND_HASH_FOREACH_END();
15729 
15730 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
15731 					if (slow_inputs->count) {
15732 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15733 						_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15734 					}
15735 					jit->b = -1;
15736 				}
15737 			} else if (!next_opline) {
15738 				_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15739 				jit->b = -1;
15740 			}
15741 		} else if (opline->opcode == ZEND_SWITCH_STRING) {
15742 			if (op1_info & MAY_BE_STRING) {
15743 				const void *fallback_label = NULL;
15744 
15745 				if (next_opline) {
15746 					if (next_opline != opline + 1) {
15747 						exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15748 						fallback_label = zend_jit_trace_get_exit_addr(exit_point);
15749 						if (!fallback_label) {
15750 							return 0;
15751 						}
15752 					}
15753 				}
15754 				if (op1_info & MAY_BE_REF) {
15755 					ir_ref ref, if_string, fast_path, ref2;
15756 
15757 					ref = jit_ZVAL_ADDR(jit, op1_addr);
15758 					if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15759 					ir_IF_TRUE(if_string);
15760 					fast_path = ir_END();
15761 					ir_IF_FALSE_cold(if_string);
15762 
15763 					// JIT: ZVAL_DEREF(op)
15764 					if (fallback_label) {
15765 						jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
15766 					} else {
15767 						ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15768 						ir_IF_FALSE_cold(if_ref);
15769 						ir_refs_add(slow_inputs, ir_END());
15770 						ir_IF_TRUE(if_ref);
15771 					}
15772 
15773 					ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
15774 					op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
15775 
15776 					if (fallback_label) {
15777 						jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15778 					} else {
15779 						if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15780 						ir_IF_FALSE_cold(if_string);
15781 						ir_refs_add(slow_inputs, ir_END());
15782 						ir_IF_TRUE(if_string);
15783 					}
15784 
15785 					ir_MERGE_2(fast_path, ir_END());
15786 					ref = ir_PHI_2(IR_ADDR, ref, ref2);
15787 					op1_addr = ZEND_ADDR_REF_ZVAL(ref);
15788 				} else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
15789 					if (fallback_label) {
15790 						jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
15791 					} else {
15792 						ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15793 						ir_IF_FALSE_cold(if_string);
15794 						ir_refs_add(slow_inputs, ir_END());
15795 						ir_IF_TRUE(if_string);
15796 					}
15797 				}
15798 
15799 				ir_ref ref = jit_Z_PTR(jit, op1_addr);
15800 				ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
15801 					ir_CONST_ADDR(jumptable), ref);
15802 				ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
15803 				/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
15804 				if (sizeof(Bucket) == 32) {
15805 					ref = ir_SHR_L(ref, ir_CONST_LONG(5));
15806 				} else {
15807 					ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
15808 				}
15809 				ref = ir_SWITCH(ref);
15810 
15811 				if (next_opline) {
15812 					ir_ref continue_list = IR_UNUSED;
15813 
15814 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15815 						ir_ref idx;
15816 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15817 
15818 						if (HT_IS_PACKED(jumptable)) {
15819 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
15820 						} else {
15821 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
15822 						}
15823 						ir_CASE_VAL(ref, idx);
15824 						if (target == next_opline) {
15825 							ir_END_list(continue_list);
15826 						} else {
15827 							exit_point = zend_jit_trace_get_exit_point(target, 0);
15828 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15829 							if (!exit_addr) {
15830 								return 0;
15831 							}
15832 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15833 						}
15834 					} ZEND_HASH_FOREACH_END();
15835 
15836 					ir_CASE_DEFAULT(ref);
15837 					if (next_opline == default_opline) {
15838 						ir_END_list(continue_list);
15839 					} else {
15840 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
15841 					}
15842 					if (continue_list) {
15843 						ir_MERGE_list(continue_list);
15844 					} else {
15845 						ZEND_ASSERT(slow_inputs->count);
15846 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15847 					}
15848 				} else {
15849 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15850 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15851 						b = ssa->cfg.map[target - op_array->opcodes];
15852 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
15853 					} ZEND_HASH_FOREACH_END();
15854 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
15855 					if (slow_inputs->count) {
15856 						ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
15857 						_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15858 					}
15859 					jit->b = -1;
15860 				}
15861 			} else if (!next_opline) {
15862 				_zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
15863 				jit->b = -1;
15864 			}
15865 		} else if (opline->opcode == ZEND_MATCH) {
15866 			ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
15867 			ir_ref continue_list = IR_UNUSED;
15868 
15869 			if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
15870 				ir_ref long_path = IR_UNUSED;
15871 
15872 				if (op1_info & MAY_BE_REF) {
15873 					op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15874 				}
15875 				if (op1_info & MAY_BE_LONG) {
15876 					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
15877 						if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
15878 							if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15879 							ir_IF_TRUE(if_type);
15880 						} else if (default_label) {
15881 							jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
15882 						} else if (next_opline) {
15883 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15884 							ir_IF_FALSE(if_type);
15885 							ir_END_list(continue_list);
15886 							ir_IF_TRUE(if_type);
15887 						} else {
15888 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15889 							ir_IF_FALSE(if_type);
15890 							ir_END_list(default_input_list);
15891 							ir_IF_TRUE(if_type);
15892 						}
15893 					}
15894 					ref = jit_Z_LVAL(jit, op1_addr);
15895 					ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
15896 						ir_CONST_ADDR(jumptable), ref);
15897 					if (op1_info & MAY_BE_STRING) {
15898 						long_path = ir_END();
15899 					}
15900 				}
15901 				if (op1_info & MAY_BE_STRING) {
15902 					if (if_type) {
15903 						ir_IF_FALSE(if_type);
15904 						if_type = IS_UNUSED;
15905 					}
15906 					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
15907 						if (op1_info & MAY_BE_UNDEF) {
15908 							if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15909 							ir_IF_TRUE(if_type);
15910 						} else if (default_label) {
15911 							jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
15912 						} else if (next_opline) {
15913 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15914 							ir_IF_FALSE(if_type);
15915 							ir_END_list(continue_list);
15916 							ir_IF_TRUE(if_type);
15917 						} else {
15918 							ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
15919 							ir_IF_FALSE(if_type);
15920 							ir_END_list(default_input_list);
15921 							ir_IF_TRUE(if_type);
15922 						}
15923 					}
15924 					ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
15925 					ref2 = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
15926 						ir_CONST_ADDR(jumptable), ref2);
15927 					if (op1_info & MAY_BE_LONG) {
15928 						ir_MERGE_WITH(long_path);
15929 						ref = ir_PHI_2(IR_LONG, ref2, ref);
15930 					} else {
15931 						ref = ref2;
15932 					}
15933 				}
15934 
15935 				ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
15936 				/* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
15937 				if (HT_IS_PACKED(jumptable)) {
15938 					ZEND_ASSERT(sizeof(zval) == 16);
15939 					ref = ir_SHR_L(ref, ir_CONST_LONG(4));
15940 				} else {
15941 					if (sizeof(Bucket) == 32) {
15942 						ref = ir_SHR_L(ref, ir_CONST_LONG(5));
15943 					} else {
15944 						ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
15945 					}
15946 				}
15947 				ref = ir_SWITCH(ref);
15948 
15949 				if (next_opline) {
15950 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15951 						ir_ref idx;
15952 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15953 
15954 						if (HT_IS_PACKED(jumptable)) {
15955 							idx = ir_CONST_LONG(zv - jumptable->arPacked);
15956 						} else {
15957 							idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
15958 						}
15959 						ir_CASE_VAL(ref, idx);
15960 						if (target == next_opline) {
15961 							ir_END_list(continue_list);
15962 						} else {
15963 							exit_point = zend_jit_trace_get_exit_point(target, 0);
15964 							exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15965 							if (!exit_addr) {
15966 								return 0;
15967 							}
15968 							jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15969 						}
15970 					} ZEND_HASH_FOREACH_END();
15971 
15972 					ir_CASE_DEFAULT(ref);
15973 					if (next_opline == default_opline) {
15974 						ir_END_list(continue_list);
15975 					} else {
15976 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
15977 					}
15978 				} else {
15979 					ZEND_HASH_FOREACH_VAL(jumptable, zv) {
15980 						target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
15981 						b = ssa->cfg.map[target - op_array->opcodes];
15982 						_zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
15983 					} ZEND_HASH_FOREACH_END();
15984 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
15985 				}
15986 			} else if (!(op1_info & MAY_BE_UNDEF)) {
15987 				if (next_opline) {
15988 					if (next_opline == default_opline) {
15989 						ir_END_list(continue_list);
15990 					} else {
15991 						jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
15992 					}
15993 				} else {
15994 					_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
15995 				}
15996 			}
15997 
15998 			if (op1_info & MAY_BE_UNDEF) {
15999 				if (if_type) {
16000 					ir_IF_FALSE(if_type);
16001 					if_type = IS_UNUSED;
16002 				}
16003 				if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16004 					if (default_label) {
16005 						jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16006 					} else if (next_opline) {
16007 						ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16008 						ir_IF_TRUE(if_def);
16009 						ir_END_list(continue_list);
16010 						ir_IF_FALSE_cold(if_def);
16011 					} else {
16012 						ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16013 						ir_IF_TRUE(if_def);
16014 						ir_END_list(default_input_list);
16015 						ir_IF_FALSE_cold(if_def);
16016 					}
16017 				}
16018 
16019 				jit_SET_EX_OPLINE(jit, opline);
16020 				ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16021 					ir_CONST_U32(opline->op1.var));
16022 				zend_jit_check_exception_undef_result(jit, opline);
16023 				if (default_label) {
16024 					jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16025 				} else if (next_opline) {
16026 					ir_END_list(continue_list);
16027 				} else {
16028 					ir_END_list(default_input_list);
16029 				}
16030 			}
16031 			if (next_opline) {
16032 				ZEND_ASSERT(continue_list);
16033 				ir_MERGE_list(continue_list);
16034 			} else {
16035 				if (default_input_list) {
16036 					if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16037 						ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16038 						jit->ctx.ir_base[ref].op3 = default_input_list;
16039 					} else {
16040 						ir_MERGE_list(default_input_list);
16041 						_zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16042 					}
16043 				}
16044 				jit->b = -1;
16045 			}
16046 		} else {
16047 			ZEND_UNREACHABLE();
16048 		}
16049 	}
16050 	return 1;
16051 }
16052 
16053 static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16054 {
16055 	int i, count;
16056 	zend_basic_block *bb;
16057 
16058 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : (IR_START_BR_TARGET|IR_ENTRY_BR_TARGET));
16059 
16060 	jit->ctx.spill_base = ZREG_FP;
16061 
16062 	jit->op_array = jit->current_op_array = op_array;
16063 	jit->ssa = ssa;
16064 	jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16065 	jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16066 
16067 	count = 0;
16068 	for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
16069 		jit->bb_predecessors[i] = count;
16070 		count += bb->predecessors_count;
16071 	}
16072 	jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
16073 
16074 	if (!GCC_GLOBAL_REGS) {
16075 		ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16076 		jit_STORE_FP(jit, ref);
16077 		jit->ctx.flags |= IR_FASTCALL_FUNC;
16078 	}
16079 
16080 	return 1;
16081 }
16082 
16083 static void *zend_jit_finish(zend_jit_ctx *jit)
16084 {
16085 	void *entry;
16086 	size_t size;
16087 	zend_string *str = NULL;
16088 
16089 	if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP|
16090 			ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_SCCP|
16091 			ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS|ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
16092 		if (jit->name) {
16093 			str = zend_string_copy(jit->name);
16094 		} else {
16095 			str = zend_jit_func_name(jit->op_array);
16096 		}
16097 	}
16098 
16099 	if (jit->op_array) {
16100 		/* Only for function JIT */
16101 		_zend_jit_fix_merges(jit);
16102 #if defined(IR_TARGET_AARCH64)
16103 	} else if (jit->trace) {
16104 		jit->ctx.deoptimization_exits = jit->trace->exit_count;
16105 		jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
16106 #endif
16107 	} else {
16108 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
16109 		jit->ctx.flags |= IR_GEN_CACHE_DEMOTE;
16110 #endif
16111 	}
16112 
16113 	entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
16114 	if (entry) {
16115 		if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16116 #ifdef HAVE_CAPSTONE
16117 			if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16118 				if (str) {
16119 					ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
16120 				}
16121 				ir_disasm(str ? ZSTR_VAL(str) : "unknown",
16122 					entry, size,
16123 					(JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0,
16124 					&jit->ctx, stderr);
16125 			}
16126 #endif
16127 #ifndef _WIN32
16128 			if (str) {
16129 				if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
16130 					uintptr_t sp_offset = 0;
16131 
16132 //					ir_mem_unprotect(entry, size);
16133 					if (!(jit->ctx.flags & IR_FUNCTION)
16134 					 && zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16135 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
16136 						sp_offset = zend_jit_hybrid_vm_sp_adj;
16137 #else
16138 						sp_offset = sizeof(void*);
16139 #endif
16140 					} else {
16141 						sp_offset = sizeof(void*);
16142 					}
16143 					ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
16144 //					ir_mem_protect(entry, size);
16145 				}
16146 
16147 				if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16148 					ir_perf_map_register(ZSTR_VAL(str), entry, size);
16149 					if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
16150 						ir_perf_jitdump_register(ZSTR_VAL(str), entry, size);
16151 					}
16152 				}
16153 			}
16154 #endif
16155 		}
16156 
16157 		if (jit->op_array) {
16158 			/* Only for function JIT */
16159 			const zend_op_array *op_array = jit->op_array;
16160 			zend_op *opline = (zend_op*)op_array->opcodes;
16161 
16162 			if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
16163 				while (opline->opcode == ZEND_RECV) {
16164 					opline++;
16165 				}
16166 			}
16167 			opline->handler = entry;
16168 
16169 			if (jit->ctx.entries_count) {
16170 				/* For all entries */
16171 				int i = jit->ctx.entries_count;
16172 				do {
16173 					ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
16174 					op_array->opcodes[insn->op2].handler = (char*)entry + insn->op3;
16175 				} while (i != 0);
16176 			}
16177 		} else {
16178 			/* Only for tracing JIT */
16179 			zend_jit_trace_info *t = jit->trace;
16180 			zend_jit_trace_stack *stack;
16181 			uint32_t i;
16182 
16183 			if (t) {
16184 				for (i = 0; i < t->stack_map_size; i++) {
16185 					stack = t->stack_map + i;
16186 					if (stack->flags & ZREG_SPILL_SLOT) {
16187 						stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
16188 						stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
16189 					}
16190 				}
16191 			}
16192 
16193 			zend_jit_trace_add_code(entry, size);
16194 		}
16195 	}
16196 
16197 	if (str) {
16198 		zend_string_release(str);
16199 	}
16200 
16201 	return entry;
16202 }
16203 
16204 static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
16205 {
16206 	const void *entry;
16207 	size_t size;
16208 	ir_code_buffer code_buffer;
16209 
16210 	code_buffer.start = dasm_buf;
16211 	code_buffer.end = dasm_end;
16212 	code_buffer.pos = *dasm_ptr;
16213 
16214 	entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
16215 		&code_buffer, &size);
16216 
16217 	*dasm_ptr = code_buffer.pos;
16218 
16219 	if (entry) {
16220 #ifdef HAVE_CAPSTONE
16221 		if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16222 			uint32_t i;
16223 			char name[32];
16224 
16225 			for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
16226 				snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
16227 				ir_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
16228 			}
16229 		}
16230 #endif
16231 	}
16232 
16233 	return entry;
16234 }
16235 
16236 static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
16237 {
16238 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16239 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16240 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16241 
16242 	if (!exit_addr) {
16243 		return 0;
16244 	}
16245 	ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
16246 
16247 	return 1;
16248 }
16249 
16250 static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
16251 {
16252 	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16253 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16254 	zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16255 
16256 	if (!exit_addr) {
16257 		return 0;
16258 	}
16259 	ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
16260 
16261 	return 1;
16262 }
16263 
16264 static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
16265 {
16266 	uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16267 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16268 
16269 	if (!exit_addr) {
16270 		return 0;
16271 	}
16272 	ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16273 
16274 	return 1;
16275 }
16276 
16277 static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
16278 {
16279 	uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
16280 	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16281 
16282 	if (!exit_addr) {
16283 		return 0;
16284 	}
16285 
16286 	ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
16287 	zend_jit_set_last_valid_opline(jit, opline);
16288 
16289 	return 1;
16290 }
16291 
16292 static bool zend_jit_guard_reference(zend_jit_ctx  *jit,
16293                                      const zend_op *opline,
16294                                      zend_jit_addr *var_addr_ptr,
16295                                      zend_jit_addr *ref_addr_ptr,
16296                                      bool           add_ref_guard)
16297 {
16298 	zend_jit_addr var_addr = *var_addr_ptr;
16299 	const void *exit_addr = NULL;
16300 	ir_ref ref;
16301 
16302 	if (add_ref_guard) {
16303 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16304 
16305 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16306 		if (!exit_addr) {
16307 			return 0;
16308 		}
16309 
16310 		ref = jit_Z_TYPE(jit, var_addr);
16311 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16312 	}
16313 
16314 	ref = jit_Z_PTR(jit, var_addr);
16315 	*ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
16316 	ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16317 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
16318 	*var_addr_ptr = var_addr;
16319 
16320 	return 1;
16321 }
16322 
16323 static bool zend_jit_fetch_reference(zend_jit_ctx  *jit,
16324                                      const zend_op *opline,
16325                                      uint8_t        var_type,
16326                                      uint32_t      *var_info_ptr,
16327                                      zend_jit_addr *var_addr_ptr,
16328                                      bool           add_ref_guard,
16329                                      bool           add_type_guard)
16330 {
16331 	zend_jit_addr var_addr = *var_addr_ptr;
16332 	uint32_t var_info = *var_info_ptr;
16333 	const void *exit_addr = NULL;
16334 	ir_ref ref;
16335 
16336 	if (add_ref_guard || add_type_guard) {
16337 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16338 
16339 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16340 		if (!exit_addr) {
16341 			return 0;
16342 		}
16343 	}
16344 
16345 	if (add_ref_guard) {
16346 		ref = jit_Z_TYPE(jit, var_addr);
16347 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16348 	}
16349 	if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
16350 		/* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
16351 		ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
16352 			jit_ZVAL_ADDR(jit, var_addr));
16353 		*var_addr_ptr = var_addr;
16354 	} else {
16355 		ref = jit_Z_PTR(jit, var_addr);
16356 		ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16357 		var_addr = ZEND_ADDR_REF_ZVAL(ref);
16358 		*var_addr_ptr = var_addr;
16359 	}
16360 
16361 	if (var_type != IS_UNKNOWN) {
16362 		var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16363 	}
16364 	if (add_type_guard
16365 	 && var_type != IS_UNKNOWN
16366 	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16367 		ref = jit_Z_TYPE(jit, var_addr);
16368 		ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
16369 
16370 		ZEND_ASSERT(var_info & (1 << var_type));
16371 		if (var_type < IS_STRING) {
16372 			var_info = (1 << var_type);
16373 		} else if (var_type != IS_ARRAY) {
16374 			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16375 		} else {
16376 			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));
16377 		}
16378 
16379 		*var_info_ptr = var_info;
16380 	} else {
16381 		var_info &= ~MAY_BE_REF;
16382 		*var_info_ptr = var_info;
16383 	}
16384 	*var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
16385 
16386 	return 1;
16387 }
16388 
16389 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)
16390 {
16391 	zend_jit_addr var_addr = *var_addr_ptr;
16392 	uint32_t var_info = *var_info_ptr;
16393 	int32_t exit_point;
16394 	const void *exit_addr;
16395 	ir_ref ref = IR_UNUSED;
16396 
16397 	if (add_indirect_guard) {
16398 		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16399 		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16400 
16401 		if (!exit_addr) {
16402 			return 0;
16403 		}
16404 		jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
16405 		ref = jit_Z_PTR(jit, var_addr);
16406 	} else {
16407 		/* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
16408 		 * is eliminated by store forwarding (S2L) */
16409 		ref = jit_Z_PTR(jit, var_addr);
16410 	}
16411 	*var_info_ptr &= ~MAY_BE_INDIRECT;
16412 	var_addr = ZEND_ADDR_REF_ZVAL(ref);
16413 	*var_addr_ptr = var_addr;
16414 
16415 	if (var_type != IS_UNKNOWN) {
16416 		var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16417 	}
16418 	if (!(var_type & IS_TRACE_REFERENCE)
16419 	 && var_type != IS_UNKNOWN
16420 	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16421 		exit_point = zend_jit_trace_get_exit_point(opline, 0);
16422 		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16423 
16424 		if (!exit_addr) {
16425 			return 0;
16426 		}
16427 
16428 		jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
16429 
16430 		//var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
16431 		ZEND_ASSERT(var_info & (1 << var_type));
16432 		if (var_type < IS_STRING) {
16433 			var_info = (1 << var_type);
16434 		} else if (var_type != IS_ARRAY) {
16435 			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16436 		} else {
16437 			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));
16438 		}
16439 
16440 		*var_info_ptr = var_info;
16441 	}
16442 
16443 	return 1;
16444 }
16445 
16446 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)
16447 {
16448 	zend_jit_op_array_trace_extension *jit_extension =
16449 		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
16450 	size_t offset = jit_extension->offset;
16451 	const void *handler =
16452 		(zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
16453 	ir_ref ref;
16454 
16455 	zend_jit_set_ip(jit, opline);
16456 	if (GCC_GLOBAL_REGS) {
16457 		ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
16458 	} else {
16459 		ref = jit_FP(jit);
16460 		ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
16461 	}
16462 	if (may_throw
16463 	 && opline->opcode != ZEND_RETURN
16464 	 && opline->opcode != ZEND_RETURN_BY_REF) {
16465 		zend_jit_check_exception(jit);
16466 	}
16467 
16468 	while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
16469 		trace++;
16470 	}
16471 
16472 	if (!GCC_GLOBAL_REGS
16473 	 && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
16474 		if (opline->opcode == ZEND_RETURN ||
16475 		    opline->opcode == ZEND_RETURN_BY_REF ||
16476 		    opline->opcode == ZEND_DO_UCALL ||
16477 		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
16478 		    opline->opcode == ZEND_DO_FCALL ||
16479 		    opline->opcode == ZEND_GENERATOR_CREATE) {
16480 
16481 			ir_ref addr = jit_EG(current_execute_data);
16482 
16483 			jit_STORE_FP(jit, ir_LOAD_A(addr));
16484 		}
16485 	}
16486 
16487 	if (zend_jit_trace_may_exit(op_array, opline)) {
16488 		if (opline->opcode == ZEND_RETURN ||
16489 		    opline->opcode == ZEND_RETURN_BY_REF ||
16490 		    opline->opcode == ZEND_GENERATOR_CREATE) {
16491 
16492 			if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16493 				if (trace->op != ZEND_JIT_TRACE_END ||
16494 				    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16495 				     trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16496 					/* this check may be handled by the following OPLINE guard or jmp [IP] */
16497 					ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
16498 						jit_STUB_ADDR(jit, jit_stub_trace_halt));
16499 				}
16500 			} else if (GCC_GLOBAL_REGS) {
16501 				ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16502 			} else {
16503 				ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16504 			}
16505 		} else if (opline->opcode == ZEND_EXIT ||
16506 		           opline->opcode == ZEND_GENERATOR_RETURN ||
16507 		           opline->opcode == ZEND_YIELD ||
16508 		           opline->opcode == ZEND_YIELD_FROM) {
16509 			ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
16510 			ir_BEGIN(IR_UNUSED); /* unreachable block */
16511 		}
16512 		if (trace->op != ZEND_JIT_TRACE_END ||
16513 		    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16514 		     trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16515 
16516 			const zend_op *next_opline = trace->opline;
16517 			const zend_op *exit_opline = NULL;
16518 			uint32_t exit_point;
16519 			const void *exit_addr;
16520 			uint32_t old_info = 0;
16521 			uint32_t old_res_info = 0;
16522 			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16523 
16524 			if (zend_is_smart_branch(opline)) {
16525 				bool exit_if_true = 0;
16526 				exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
16527 			} else {
16528 				switch (opline->opcode) {
16529 					case ZEND_JMPZ:
16530 					case ZEND_JMPNZ:
16531 					case ZEND_JMPZ_EX:
16532 					case ZEND_JMPNZ_EX:
16533 					case ZEND_JMP_SET:
16534 					case ZEND_COALESCE:
16535 					case ZEND_JMP_NULL:
16536 					case ZEND_FE_RESET_R:
16537 					case ZEND_FE_RESET_RW:
16538 						exit_opline = (trace->opline == opline + 1) ?
16539 							OP_JMP_ADDR(opline, opline->op2) :
16540 							opline + 1;
16541 						break;
16542 					case ZEND_FE_FETCH_R:
16543 					case ZEND_FE_FETCH_RW:
16544 						exit_opline = (trace->opline == opline + 1) ?
16545 							ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
16546 							opline + 1;
16547 						break;
16548 
16549 				}
16550 			}
16551 
16552 			switch (opline->opcode) {
16553 				case ZEND_FE_FETCH_R:
16554 				case ZEND_FE_FETCH_RW:
16555 					if (opline->op2_type != IS_UNUSED) {
16556 						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
16557 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
16558 					}
16559 					break;
16560 				case ZEND_BIND_INIT_STATIC_OR_JMP:
16561 					if (opline->op1_type == IS_CV) {
16562 						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
16563 						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
16564 					}
16565 					break;
16566 			}
16567 			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
16568 				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
16569 				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
16570 			}
16571 			exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
16572 			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16573 
16574 			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
16575 				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
16576 			}
16577 			switch (opline->opcode) {
16578 				case ZEND_FE_FETCH_R:
16579 				case ZEND_FE_FETCH_RW:
16580 					if (opline->op2_type != IS_UNUSED) {
16581 						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
16582 					}
16583 					break;
16584 				case ZEND_BIND_INIT_STATIC_OR_JMP:
16585 					if (opline->op1_type == IS_CV) {
16586 						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
16587 					}
16588 					break;
16589 			}
16590 
16591 			if (!exit_addr) {
16592 				return 0;
16593 			}
16594 			ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
16595 		}
16596 	}
16597 
16598 	zend_jit_set_last_valid_opline(jit, trace->opline);
16599 
16600 	return 1;
16601 }
16602 
16603 static int zend_jit_deoptimizer_start(zend_jit_ctx        *jit,
16604                                       zend_string         *name,
16605                                       uint32_t             trace_num,
16606                                       uint32_t             exit_num)
16607 {
16608 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
16609 
16610 	jit->ctx.spill_base = ZREG_FP;
16611 
16612 	jit->op_array = NULL;
16613 	jit->ssa = NULL;
16614 	jit->name = zend_string_copy(name);
16615 
16616 	jit->ctx.flags |= IR_SKIP_PROLOGUE;
16617 
16618 	return 1;
16619 }
16620 
16621 static int zend_jit_trace_start(zend_jit_ctx        *jit,
16622                                 const zend_op_array *op_array,
16623                                 zend_ssa            *ssa,
16624                                 zend_string         *name,
16625                                 uint32_t             trace_num,
16626                                 zend_jit_trace_info *parent,
16627                                 uint32_t             exit_num)
16628 {
16629 	zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
16630 
16631 	jit->ctx.spill_base = ZREG_FP;
16632 
16633 	jit->op_array = NULL;
16634 	jit->current_op_array = op_array;
16635 	jit->ssa = ssa;
16636 	jit->name = zend_string_copy(name);
16637 
16638 	if (!GCC_GLOBAL_REGS) {
16639 		if (!parent) {
16640 			ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16641 			jit_STORE_FP(jit, ref);
16642 			jit->ctx.flags |= IR_FASTCALL_FUNC;
16643 		}
16644 	}
16645 
16646 	if (parent) {
16647 		jit->ctx.flags |= IR_SKIP_PROLOGUE;
16648 	}
16649 
16650 	if (parent) {
16651 		int i;
16652 		int parent_vars_count = parent->exit_info[exit_num].stack_size;
16653 		zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
16654 			parent->stack_map +
16655 			parent->exit_info[exit_num].stack_offset;
16656 
16657 		/* prevent clobbering of registers used for deoptimization */
16658 		for (i = 0; i < parent_vars_count; i++) {
16659 			if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
16660 			 && STACK_REG(parent_stack, i) != ZREG_NONE) {
16661 				int32_t reg = STACK_REG(parent_stack, i);
16662 				ir_type type;
16663 
16664 				if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
16665 					type = IR_ADDR;
16666 				} else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
16667 					type = IR_LONG;
16668 				} else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
16669 					type = IR_DOUBLE;
16670 				} else {
16671 					ZEND_UNREACHABLE();
16672 				}
16673 				if (ssa && ssa->vars[i].no_val) {
16674 					/* pass */
16675 				} else {
16676 					ir_ref ref = ir_RLOAD(type, reg);
16677 
16678 					if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
16679 						/* op3 is used as a flag that the value is already stored in memory.
16680 						 * In case the IR framework decides to spill the result of IR_LOAD,
16681 						 * it doesn't have to store the value once again.
16682 						 *
16683 						 * See: insn->op3 check in ir_emit_rload()
16684 						 */
16685 						ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
16686 					}
16687 				}
16688 			}
16689 		}
16690 	}
16691 
16692 	if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
16693 		ZEND_ASSERT(parent->exit_info[exit_num].poly_func_reg >= 0 && parent->exit_info[exit_num].poly_this_reg >= 0);
16694 		ir_RLOAD_A(parent->exit_info[exit_num].poly_func_reg);
16695 		ir_RLOAD_A(parent->exit_info[exit_num].poly_this_reg);
16696 	}
16697 
16698 	ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
16699 
16700 	return 1;
16701 }
16702 
16703 static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
16704 {
16705 	return ir_LOOP_BEGIN(ir_END());
16706 }
16707 
16708 static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
16709 {
16710 	int dst_var = phi->ssa_var;
16711 	int src_var = phi->sources[0];
16712 	ir_ref ref;
16713 
16714 	ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
16715 	ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
16716 
16717 	ref = ir_PHI_2(
16718 		(jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
16719 		zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
16720 
16721 	src_var = phi->sources[1];
16722 	ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
16723 	jit->ra[src_var].flags |= ZREG_FORWARD;
16724 
16725 	zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
16726 }
16727 
16728 static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
16729 {
16730 	if (timeout_exit_addr) {
16731 		zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
16732 	}
16733 	ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
16734 	ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
16735 	return 1;
16736 }
16737 
16738 static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
16739 {
16740 	if (GCC_GLOBAL_REGS) {
16741 		if (!original_handler) {
16742 			ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
16743 		} else {
16744 			ir_TAILCALL(IR_VOID, zend_jit_orig_opline_handler(jit));
16745 		}
16746 	} else {
16747 		if (original_handler) {
16748 			ir_ref ref;
16749 			ir_ref addr = zend_jit_orig_opline_handler(jit);
16750 
16751 #if defined(IR_TARGET_X86)
16752 			addr = ir_CAST_FC_FUNC(addr);
16753 #endif
16754 			ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
16755 			if (opline &&
16756 			    (opline->opcode == ZEND_RETURN
16757 			  || opline->opcode == ZEND_RETURN_BY_REF
16758 			  || opline->opcode == ZEND_GENERATOR_RETURN
16759 			  || opline->opcode == ZEND_GENERATOR_CREATE
16760 			  || opline->opcode == ZEND_YIELD
16761 			  || opline->opcode == ZEND_YIELD_FROM)) {
16762 				ir_RETURN(ref);
16763 				return 1;
16764 			}
16765 		}
16766 		ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
16767 	}
16768 	return 1;
16769 }
16770 
16771 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)
16772 {
16773 	return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
16774 }
16775 
16776 static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
16777 {
16778 	const void *link_addr;
16779 
16780 	/* Skip prologue. */
16781 	ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
16782 	link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
16783 
16784 	if (timeout_exit_addr) {
16785 		zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
16786 	}
16787 	ir_IJMP(ir_CONST_ADDR(link_addr));
16788 
16789 	return 1;
16790 }
16791 
16792 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)
16793 {
16794 	uint32_t op1_info, op2_info;
16795 
16796 	switch (opline->opcode) {
16797 		case ZEND_SEND_VAR:
16798 		case ZEND_SEND_VAL:
16799 		case ZEND_SEND_VAL_EX:
16800 			return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
16801 		case ZEND_QM_ASSIGN:
16802 		case ZEND_IS_SMALLER:
16803 		case ZEND_IS_SMALLER_OR_EQUAL:
16804 		case ZEND_IS_EQUAL:
16805 		case ZEND_IS_NOT_EQUAL:
16806 		case ZEND_IS_IDENTICAL:
16807 		case ZEND_IS_NOT_IDENTICAL:
16808 		case ZEND_CASE:
16809 			return 1;
16810 		case ZEND_RETURN:
16811 			return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
16812 		case ZEND_ASSIGN:
16813 			return (opline->op1_type == IS_CV);
16814 		case ZEND_ASSIGN_OP:
16815 			if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
16816 				return 0;
16817 			}
16818 			op1_info = OP1_INFO();
16819 			op2_info = OP2_INFO();
16820 			return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
16821 		case ZEND_ADD:
16822 		case ZEND_SUB:
16823 		case ZEND_MUL:
16824 			op1_info = OP1_INFO();
16825 			op2_info = OP2_INFO();
16826 			if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
16827 				return 0;
16828 			}
16829 			if (trace && trace->op1_type != IS_UNKNOWN) {
16830 				op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16831 			}
16832 			if (trace && trace->op2_type != IS_UNKNOWN) {
16833 				op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16834 			}
16835 			return !(op1_info & MAY_BE_UNDEF)
16836 				&& !(op2_info & MAY_BE_UNDEF)
16837 				&& (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
16838 				&& (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
16839 		case ZEND_BW_OR:
16840 		case ZEND_BW_AND:
16841 		case ZEND_BW_XOR:
16842 		case ZEND_SL:
16843 		case ZEND_SR:
16844 		case ZEND_MOD:
16845 			op1_info = OP1_INFO();
16846 			op2_info = OP2_INFO();
16847 			if (trace && trace->op1_type != IS_UNKNOWN) {
16848 				op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16849 			}
16850 			if (trace && trace->op2_type != IS_UNKNOWN) {
16851 				op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
16852 			}
16853 			return (op1_info & MAY_BE_LONG)
16854 				&& (op2_info & MAY_BE_LONG);
16855 		case ZEND_PRE_INC:
16856 		case ZEND_PRE_DEC:
16857 		case ZEND_POST_INC:
16858 		case ZEND_POST_DEC:
16859 			op1_info = OP1_INFO();
16860 			return opline->op1_type == IS_CV
16861 				&& (op1_info & MAY_BE_LONG)
16862 				&& !(op1_info & MAY_BE_REF);
16863 		case ZEND_STRLEN:
16864 			op1_info = OP1_INFO();
16865 			return (opline->op1_type & (IS_CV|IS_CONST))
16866 				&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
16867 		case ZEND_COUNT:
16868 			op1_info = OP1_INFO();
16869 			return (opline->op1_type & (IS_CV|IS_CONST))
16870 				&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
16871 		case ZEND_JMPZ:
16872 		case ZEND_JMPNZ:
16873 			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
16874 				if (!ssa->cfg.map) {
16875 					return 0;
16876 				}
16877 				if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
16878 				    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
16879 					return 0;
16880 				}
16881 			}
16882 			ZEND_FALLTHROUGH;
16883 		case ZEND_BOOL:
16884 		case ZEND_BOOL_NOT:
16885 		case ZEND_JMPZ_EX:
16886 		case ZEND_JMPNZ_EX:
16887 			return 1;
16888 		case ZEND_FETCH_CONSTANT:
16889 			return 1;
16890 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
16891 			if ((opline->extended_value & ZEND_ISEMPTY)) {
16892 				return 0;
16893 			}
16894 			ZEND_FALLTHROUGH;
16895 		case ZEND_FETCH_DIM_R:
16896 		case ZEND_FETCH_DIM_IS:
16897 		case ZEND_FETCH_LIST_R:
16898 			op1_info = OP1_INFO();
16899 			op2_info = OP2_INFO();
16900 			if (trace
16901 			 && trace->op1_type != IS_UNKNOWN
16902 			 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
16903 				op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
16904 			}
16905 			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
16906 					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
16907 					 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
16908 		case ZEND_ASSIGN_DIM_OP:
16909 			if (opline->result_type != IS_UNUSED) {
16910 				return 0;
16911 			}
16912 			if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
16913 				return 0;
16914 			}
16915 			ZEND_FALLTHROUGH;
16916 		case ZEND_ASSIGN_DIM:
16917 		case ZEND_FETCH_DIM_W:
16918 		case ZEND_FETCH_DIM_RW:
16919 		case ZEND_FETCH_LIST_W:
16920 			op1_info = OP1_INFO();
16921 			op2_info = OP2_INFO();
16922 			if (trace) {
16923 				if (opline->op1_type == IS_CV) {
16924 					if ((opline->opcode == ZEND_ASSIGN_DIM
16925 					  || opline->opcode == ZEND_ASSIGN_DIM_OP)
16926 					 && (opline+1)->op1_type == IS_CV
16927 					 && (opline+1)->op1.var == opline->op1.var) {
16928 						/* skip $a[x] = $a; */
16929 						return 0;
16930 					}
16931 				} else if (opline->op1_type == IS_VAR) {
16932 					if (trace->op1_type == IS_UNKNOWN
16933 					 || !(trace->op1_type & IS_TRACE_INDIRECT)
16934 					 || opline->result_type != IS_UNUSED) {
16935 						return 0;
16936 					}
16937 				}
16938 				if (trace->op1_type != IS_UNKNOWN
16939 				 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
16940 					op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
16941 				}
16942 			} else {
16943 				if (opline->op1_type != IS_CV) {
16944 					return 0;
16945 				}
16946 			}
16947 			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
16948 					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
16949 					 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
16950 		case ZEND_ASSIGN_OBJ_OP:
16951 			if (opline->result_type != IS_UNUSED) {
16952 				return 0;
16953 			}
16954 			if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
16955 				return 0;
16956 			}
16957 			ZEND_FALLTHROUGH;
16958 		case ZEND_FETCH_OBJ_R:
16959 		case ZEND_ASSIGN_OBJ:
16960 			if (opline->op2_type != IS_CONST
16961 			 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
16962 			 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
16963 				return 0;
16964 			}
16965 			op1_info = OP1_INFO();
16966 			return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
16967 	}
16968 	return 0;
16969 }
16970 
16971 static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
16972 {
16973 	if (ssa->vars[var].no_val) {
16974 		/* we don't need the value */
16975 		return 0;
16976 	}
16977 
16978 	if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
16979 		/* Disable global register allocation,
16980 		 * register allocation for SSA variables connected through Phi functions
16981 		 */
16982 		if (ssa->vars[var].definition_phi) {
16983 			return 0;
16984 		}
16985 		if (ssa->vars[var].phi_use_chain) {
16986 			zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
16987 			do {
16988 				if (!ssa->vars[phi->ssa_var].no_val) {
16989 					return 0;
16990 				}
16991 				phi = zend_ssa_next_use_phi(ssa, var, phi);
16992 			} while (phi);
16993 		}
16994 	}
16995 
16996 	if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
16997 	    ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
16998 	    /* bad type */
16999 		return 0;
17000 	}
17001 
17002 	return 1;
17003 }
17004 
17005 static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17006 {
17007 	if (!zend_jit_var_supports_reg(ssa, var)) {
17008 		return 0;
17009 	}
17010 
17011 	if (ssa->vars[var].definition >= 0) {
17012 		uint32_t def = ssa->vars[var].definition;
17013 		if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17014 			return 0;
17015 		}
17016 	}
17017 
17018 	if (ssa->vars[var].use_chain >= 0) {
17019 		int use = ssa->vars[var].use_chain;
17020 
17021 		do {
17022 			if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17023 			    !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17024 				return 0;
17025 			}
17026 			use = zend_ssa_next_use(ssa->ops, var, use);
17027 		} while (use >= 0);
17028 	}
17029 
17030 	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17031 		int def_block, use_block, b, use, j;
17032 		zend_basic_block *bb;
17033 		zend_ssa_phi *p;
17034 		bool ret = 1;
17035 		zend_worklist worklist;
17036 		ALLOCA_FLAG(use_heap)
17037 
17038 		/* Check if live range is split by ENTRY block */
17039 		if (ssa->vars[var].definition >= 0) {
17040 			def_block =ssa->cfg.map[ssa->vars[var].definition];
17041 		} else {
17042 			ZEND_ASSERT(ssa->vars[var].definition_phi);
17043 			def_block = ssa->vars[var].definition_phi->block;
17044 		}
17045 
17046 		ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
17047 
17048 		if (ssa->vars[var].use_chain >= 0) {
17049 			use = ssa->vars[var].use_chain;
17050 			do {
17051 				use_block = ssa->cfg.map[use];
17052 				if (use_block != def_block) {
17053 					zend_worklist_push(&worklist, use_block);
17054 				}
17055 				use = zend_ssa_next_use(ssa->ops, var, use);
17056 			} while (use >= 0);
17057 		}
17058 
17059 		p = ssa->vars[var].phi_use_chain;
17060 		while (p) {
17061 			use_block = p->block;
17062 			if (use_block != def_block) {
17063 				bb = &ssa->cfg.blocks[use_block];
17064 				for (j = 0; j < bb->predecessors_count; j++) {
17065 					if (p->sources[j] == var) {
17066 						use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
17067 						if (use_block != def_block) {
17068 							zend_worklist_push(&worklist, use_block);
17069 						}
17070 					}
17071 				}
17072 			}
17073 			p = zend_ssa_next_use_phi(ssa, var, p);
17074 		}
17075 
17076 		while (zend_worklist_len(&worklist) != 0) {
17077 			b = zend_worklist_pop(&worklist);
17078 			bb = &ssa->cfg.blocks[b];
17079 			if (bb->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
17080 				ret = 0;
17081 				break;
17082 			}
17083 			for (j = 0; j < bb->predecessors_count; j++) {
17084 				b = ssa->cfg.predecessors[bb->predecessor_offset + j];
17085 				if (b != def_block) {
17086 					zend_worklist_push(&worklist, b);
17087 				}
17088 			}
17089 		}
17090 
17091 		ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
17092 
17093 		return ret;
17094 	}
17095 
17096 	return 1;
17097 }
17098 
17099 static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
17100 	// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
17101 	ir_ref observer_handler;
17102 	zend_function *fbc = ZEND_FLF_FUNC(opline);
17103 	// Not need for runtime cache or generator checks here, we just need if_unobserved
17104 	ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17105 
17106 	// Call zend_frameless_observed_call for the main logic.
17107 	ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
17108 
17109 	ir_ref skip = ir_END();
17110 	ir_IF_TRUE(if_unobserved);
17111 	return skip;
17112 }
17113 
17114 static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
17115 {
17116 	jit_SET_EX_OPLINE(jit, opline);
17117 
17118 	void *function = ZEND_FLF_HANDLER(opline);
17119 	zend_jit_addr res_addr = RES_ADDR();
17120 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17121 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17122 
17123 	ir_ref skip_observer = IR_UNUSED;
17124 	if (ZEND_OBSERVER_ENABLED) {
17125 		skip_observer = jit_frameless_observer(jit, opline);
17126 	}
17127 
17128 	ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17129 
17130 	if (skip_observer != IR_UNUSED) {
17131 		ir_MERGE_WITH(skip_observer);
17132 	}
17133 
17134 	zend_jit_check_exception(jit);
17135 }
17136 
17137 static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
17138 {
17139 	jit_SET_EX_OPLINE(jit, opline);
17140 
17141 	/* Avoid dropping RC check in case op escapes. */
17142 	if (op1_info & MAY_BE_RC1) {
17143 		op1_info |= MAY_BE_RCN;
17144 	}
17145 
17146 	void *function = ZEND_FLF_HANDLER(opline);
17147 	zend_jit_addr res_addr = RES_ADDR();
17148 	zend_jit_addr op1_addr = OP1_ADDR();
17149 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17150 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17151 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17152 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17153 		zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17154 	}
17155 	if (op1_info & MAY_BE_REF) {
17156 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17157 	}
17158 
17159 	ir_ref skip_observer = IR_UNUSED;
17160 	if (ZEND_OBSERVER_ENABLED) {
17161 		skip_observer = jit_frameless_observer(jit, opline);
17162 	}
17163 
17164 	ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17165 
17166 	if (skip_observer != IR_UNUSED) {
17167 		ir_MERGE_WITH(skip_observer);
17168 	}
17169 
17170 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17171 	zend_jit_check_exception(jit);
17172 }
17173 
17174 static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
17175 {
17176 	jit_SET_EX_OPLINE(jit, opline);
17177 
17178 	/* Avoid dropping RC check in case op escapes. */
17179 	if (op1_info & MAY_BE_RC1) {
17180 		op1_info |= MAY_BE_RCN;
17181 	}
17182 	if (op2_info & MAY_BE_RC1) {
17183 		op2_info |= MAY_BE_RCN;
17184 	}
17185 
17186 	void *function = ZEND_FLF_HANDLER(opline);
17187 	zend_jit_addr res_addr = RES_ADDR();
17188 	zend_jit_addr op1_addr = OP1_ADDR();
17189 	zend_jit_addr op2_addr = OP2_ADDR();
17190 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17191 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17192 	ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17193 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17194 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17195 		zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17196 	}
17197 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17198 		zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17199 	}
17200 	if (op1_info & MAY_BE_REF) {
17201 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17202 	}
17203 	if (op2_info & MAY_BE_REF) {
17204 		op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17205 	}
17206 
17207 	ir_ref skip_observer = IR_UNUSED;
17208 	if (ZEND_OBSERVER_ENABLED) {
17209 		skip_observer = jit_frameless_observer(jit, opline);
17210 	}
17211 
17212 	ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17213 
17214 	if (skip_observer != IR_UNUSED) {
17215 		ir_MERGE_WITH(skip_observer);
17216 	}
17217 
17218 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17219 	/* Set OP1 to UNDEF in case FREE_OP2() throws. */
17220 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17221 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17222 	}
17223 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17224 	zend_jit_check_exception(jit);
17225 }
17226 
17227 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)
17228 {
17229 	jit_SET_EX_OPLINE(jit, opline);
17230 
17231 	/* Avoid dropping RC check in case op escapes. */
17232 	if (op1_info & MAY_BE_RC1) {
17233 		op1_info |= MAY_BE_RCN;
17234 	}
17235 	if (op2_info & MAY_BE_RC1) {
17236 		op2_info |= MAY_BE_RCN;
17237 	}
17238 	if (op1_data_info & MAY_BE_RC1) {
17239 		op1_data_info |= MAY_BE_RCN;
17240 	}
17241 
17242 	void *function = ZEND_FLF_HANDLER(opline);
17243 	uint8_t op_data_type = (opline + 1)->op1_type;
17244 	zend_jit_addr res_addr = RES_ADDR();
17245 	zend_jit_addr op1_addr = OP1_ADDR();
17246 	zend_jit_addr op2_addr = OP2_ADDR();
17247 	zend_jit_addr op3_addr = OP1_DATA_ADDR();
17248 	ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17249 	ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17250 	ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17251 	ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
17252 	jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17253 	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17254 		zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17255 	}
17256 	if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17257 		zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17258 	}
17259 	if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
17260 		zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17261 	}
17262 	if (op1_info & MAY_BE_REF) {
17263 		op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17264 	}
17265 	if (op2_info & MAY_BE_REF) {
17266 		op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17267 	}
17268 	if (op1_data_info & MAY_BE_REF) {
17269 		op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
17270 	}
17271 
17272 	ir_ref skip_observer = IR_UNUSED;
17273 	if (ZEND_OBSERVER_ENABLED) {
17274 		skip_observer = jit_frameless_observer(jit, opline);
17275 	}
17276 
17277 	ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17278 
17279 	if (skip_observer != IR_UNUSED) {
17280 		ir_MERGE_WITH(skip_observer);
17281 	}
17282 
17283 	jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17284 	/* Set OP1 to UNDEF in case FREE_OP2() throws. */
17285 	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
17286 	 && ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
17287 	  || (op_data_type & (IS_VAR|IS_TMP_VAR)))) {
17288 		jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17289 	}
17290 	jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17291 	/* If OP1 is a TMP|VAR, we don't need to set OP2 to UNDEF on free because
17292 	 * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
17293 	if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR))
17294 	 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17295 	 && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17296 		jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
17297 	}
17298 	jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
17299 	zend_jit_check_exception(jit);
17300 }
17301 
17302 /*
17303  * Local variables:
17304  * tab-width: 4
17305  * c-basic-offset: 4
17306  * indent-tabs-mode: t
17307  * End:
17308  */
17309