1 /*
2 * +----------------------------------------------------------------------+
3 * | Zend JIT |
4 * +----------------------------------------------------------------------+
5 * | Copyright (c) The PHP Group |
6 * +----------------------------------------------------------------------+
7 * | This source file is subject to version 3.01 of the PHP license, |
8 * | that is bundled with this package in the file LICENSE, and is |
9 * | available through the world-wide-web at the following url: |
10 * | https://www.php.net/license/3_01.txt |
11 * | If you did not receive a copy of the PHP license and are unable to |
12 * | obtain it through the world-wide-web, please send a note to |
13 * | license@php.net so we can mail you a copy immediately. |
14 * +----------------------------------------------------------------------+
15 * | Authors: Dmitry Stogov <dmitry@php.net> |
16 * +----------------------------------------------------------------------+
17 */
18
19 #include "jit/ir/ir.h"
20 #include "jit/ir/ir_builder.h"
21
22 #if defined(IR_TARGET_X86)
23 # define IR_REG_SP 4 /* IR_REG_RSP */
24 # define IR_REG_FP 5 /* IR_REG_RBP */
25 # define ZREG_FP 6 /* IR_REG_RSI */
26 # define ZREG_IP 7 /* IR_REG_RDI */
27 # define ZREG_FIRST_FPR 8
28 # define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7)) /* all preserved registers */
29 #elif defined(IR_TARGET_X64)
30 # define IR_REG_SP 4 /* IR_REG_RSP */
31 # define IR_REG_FP 5 /* IR_REG_RBP */
32 # define ZREG_FP 14 /* IR_REG_R14 */
33 # define ZREG_IP 15 /* IR_REG_R15 */
34 # define ZREG_FIRST_FPR 16
35 # if defined(_WIN64)
36 # define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7) | (1<<12) | (1<<13) | (1<<14) | (1<<15))
37 /*
38 # define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7) | (1<<12) | (1<<13) | (1<<14) | (1<<15) | \
39 (1<<(16+6)) | (1<<(16+7)) | (1<<(16+8)) | (1<<(16+9)) | (1<<(16+10)) | \
40 (1<<(16+11)) | (1<<(16+12)) | (1<<(16+13)) | (1<<(16+14)) | (1<<(16+15)))
41 */
42 # else
43 # define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<12) | (1<<13) | (1<<14) | (1<<15)) /* all preserved registers */
44 # endif
45 #elif defined(IR_TARGET_AARCH64)
46 # define IR_REG_SP 31 /* IR_REG_RSP */
47 # define IR_REG_FP 29 /* IR_REG_X29 */
48 # define ZREG_FP 27 /* IR_REG_X27 */
49 # define ZREG_IP 28 /* IR_REG_X28 */
50 # define ZREG_FIRST_FPR 32
51 # define IR_REGSET_PRESERVED ((1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23) | \
52 (1<<24) | (1<<25) | (1<<26) | (1<<27) | (1<<28)) /* all preserved registers */
53 #else
54 # error "Unknown IR target"
55 #endif
56
57 #define ZREG_RX ZREG_IP
58
59 #define OPTIMIZE_FOR_SIZE 0
60
61 /* IR builder defines */
62 #undef _ir_CTX
63 #define _ir_CTX (&jit->ctx)
64
65 #undef ir_CONST_ADDR
66 #define ir_CONST_ADDR(_addr) jit_CONST_ADDR(jit, (uintptr_t)(_addr))
67 #define ir_CONST_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), 0)
68 #define ir_CONST_FC_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), IR_FASTCALL_FUNC)
69 #define ir_CAST_FC_FUNC(_addr) ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
70 ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_I32))
71
72 #define ir_CONST_FUNC_PROTO(_addr, _proto) \
73 jit_CONST_FUNC_PROTO(jit, (uintptr_t)(_addr), (_proto))
74
75 #undef ir_ADD_OFFSET
76 #define ir_ADD_OFFSET(_addr, _offset) \
77 jit_ADD_OFFSET(jit, _addr, _offset)
78
79 #ifdef ZEND_ENABLE_ZVAL_LONG64
80 # define IR_LONG IR_I64
81 # define ir_CONST_LONG ir_CONST_I64
82 # define ir_UNARY_OP_L ir_UNARY_OP_I64
83 # define ir_BINARY_OP_L ir_BINARY_OP_I64
84 # define ir_ADD_L ir_ADD_I64
85 # define ir_SUB_L ir_SUB_I64
86 # define ir_MUL_L ir_MUL_I64
87 # define ir_DIV_L ir_DIV_I64
88 # define ir_MOD_L ir_MOD_I64
89 # define ir_NEG_L ir_NEG_I64
90 # define ir_ABS_L ir_ABS_I64
91 # define ir_SEXT_L ir_SEXT_I64
92 # define ir_ZEXT_L ir_ZEXT_I64
93 # define ir_TRUNC_L ir_TRUNC_I64
94 # define ir_BITCAST_L ir_BITCAST_I64
95 # define ir_FP2L ir_FP2I64
96 # define ir_ADD_OV_L ir_ADD_OV_I64
97 # define ir_SUB_OV_L ir_SUB_OV_I64
98 # define ir_MUL_OV_L ir_MUL_OV_I64
99 # define ir_NOT_L ir_NOT_I64
100 # define ir_OR_L ir_OR_I64
101 # define ir_AND_L ir_AND_I64
102 # define ir_XOR_L ir_XOR_I64
103 # define ir_SHL_L ir_SHL_I64
104 # define ir_SHR_L ir_SHR_I64
105 # define ir_SAR_L ir_SAR_I64
106 # define ir_ROL_L ir_ROL_I64
107 # define ir_ROR_L ir_ROR_I64
108 # define ir_MIN_L ir_MIN_I64
109 # define ir_MAX_L ir_MAX_I64
110 # define ir_LOAD_L ir_LOAD_I64
111 #else
112 # define IR_LONG IR_I32
113 # define ir_CONST_LONG ir_CONST_I32
114 # define ir_UNARY_OP_L ir_UNARY_OP_I32
115 # define ir_BINARY_OP_L ir_BINARY_OP_I32
116 # define ir_ADD_L ir_ADD_I32
117 # define ir_SUB_L ir_SUB_I32
118 # define ir_MUL_L ir_MUL_I32
119 # define ir_DIV_L ir_DIV_I32
120 # define ir_MOD_L ir_MOD_I32
121 # define ir_NEG_L ir_NEG_I32
122 # define ir_ABS_L ir_ABS_I32
123 # define ir_SEXT_L ir_SEXT_I32
124 # define ir_ZEXT_L ir_ZEXT_I32
125 # define ir_TRUNC_L ir_TRUNC_I32
126 # define ir_BITCAST_L ir_BITCAST_I32
127 # define ir_FP2L ir_FP2I32
128 # define ir_ADD_OV_L ir_ADD_OV_I32
129 # define ir_SUB_OV_L ir_SUB_OV_I32
130 # define ir_MUL_OV_L ir_MUL_OV_I32
131 # define ir_NOT_L ir_NOT_I32
132 # define ir_OR_L ir_OR_I32
133 # define ir_AND_L ir_AND_I32
134 # define ir_XOR_L ir_XOR_I32
135 # define ir_SHL_L ir_SHL_I32
136 # define ir_SHR_L ir_SHR_I32
137 # define ir_SAR_L ir_SAR_I32
138 # define ir_ROL_L ir_ROL_I32
139 # define ir_ROR_L ir_ROR_I32
140 # define ir_MIN_L ir_MIN_I32
141 # define ir_MAX_L ir_MAX_I32
142 # define ir_LOAD_L ir_LOAD_I32
143 #endif
144
145 /* A helper structure to collect IT rers for the following use in (MERGE/PHI)_N */
146 typedef struct _ir_refs {
147 uint32_t count;
148 uint32_t limit;
149 ir_ref refs[] ZEND_ELEMENT_COUNT(count);
150 } ir_refs;
151
152 #define ir_refs_size(_n) (offsetof(ir_refs, refs) + sizeof(ir_ref) * (_n))
153 #define ir_refs_init(_name, _n) _name = alloca(ir_refs_size(_n)); \
154 do {_name->count = 0; _name->limit = (_n);} while (0)
155
ir_refs_add(ir_refs * refs,ir_ref ref)156 static void ir_refs_add(ir_refs *refs, ir_ref ref)
157 {
158 ir_ref *ptr;
159
160 ZEND_ASSERT(refs->count < refs->limit);
161 ptr = refs->refs;
162 ptr[refs->count++] = ref;
163 }
164
165 static size_t zend_jit_trace_prologue_size = (size_t)-1;
166 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
167 static uint32_t allowed_opt_flags = 0;
168 static uint32_t default_mflags = 0;
169 #endif
170 static bool delayed_call_chain = 0; // TODO: remove this var (use jit->delayed_call_level) ???
171
172 #ifdef ZTS
173 # ifdef _WIN32
174 extern uint32_t _tls_index;
175 extern char *_tls_start;
176 extern char *_tls_end;
177 # endif
178
179 static size_t tsrm_ls_cache_tcb_offset = 0;
180 static size_t tsrm_tls_index = 0;
181 static size_t tsrm_tls_offset = 0;
182
183 # define EG_TLS_OFFSET(field) \
184 (executor_globals_offset + offsetof(zend_executor_globals, field))
185
186 # define CG_TLS_OFFSET(field) \
187 (compiler_globals_offset + offsetof(zend_compiler_globals, field))
188
189 # define jit_EG(_field) \
190 ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
191
192 # define jit_CG(_field) \
193 ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
194
195 #else
196
197 # define jit_EG(_field) \
198 ir_CONST_ADDR(&EG(_field))
199
200 # define jit_CG(_field) \
201 ir_CONST_ADDR(&CG(_field))
202
203 #endif
204
205 #define jit_CALL(_call, _field) \
206 ir_ADD_OFFSET(_call, offsetof(zend_execute_data, _field))
207
208 #define jit_EX(_field) \
209 jit_CALL(jit_FP(jit), _field)
210
211 #define jit_RX(_field) \
212 jit_CALL(jit_IP(jit), _field)
213
214 #define JIT_STUBS(_) \
215 _(exception_handler, IR_SKIP_PROLOGUE) \
216 _(exception_handler_undef, IR_SKIP_PROLOGUE) \
217 _(exception_handler_free_op2, IR_SKIP_PROLOGUE) \
218 _(exception_handler_free_op1_op2, IR_SKIP_PROLOGUE) \
219 _(interrupt_handler, IR_SKIP_PROLOGUE) \
220 _(leave_function_handler, IR_SKIP_PROLOGUE) \
221 _(negative_shift, IR_SKIP_PROLOGUE) \
222 _(mod_by_zero, IR_SKIP_PROLOGUE) \
223 _(invalid_this, IR_SKIP_PROLOGUE) \
224 _(undefined_function, IR_SKIP_PROLOGUE) \
225 _(throw_cannot_pass_by_ref, IR_SKIP_PROLOGUE) \
226 _(icall_throw, IR_SKIP_PROLOGUE) \
227 _(leave_throw, IR_SKIP_PROLOGUE) \
228 _(hybrid_runtime_jit, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
229 _(hybrid_profile_jit, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
230 _(hybrid_func_hot_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
231 _(hybrid_loop_hot_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
232 _(hybrid_func_trace_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
233 _(hybrid_ret_trace_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
234 _(hybrid_loop_trace_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
235 _(trace_halt, IR_SKIP_PROLOGUE) \
236 _(trace_escape, IR_SKIP_PROLOGUE) \
237 _(trace_exit, IR_SKIP_PROLOGUE) \
238 _(undefined_offset, IR_FUNCTION | IR_FASTCALL_FUNC) \
239 _(undefined_key, IR_FUNCTION | IR_FASTCALL_FUNC) \
240 _(cannot_add_element, IR_FUNCTION | IR_FASTCALL_FUNC) \
241 _(assign_const, IR_FUNCTION | IR_FASTCALL_FUNC) \
242 _(assign_tmp, IR_FUNCTION | IR_FASTCALL_FUNC) \
243 _(assign_var, IR_FUNCTION | IR_FASTCALL_FUNC) \
244 _(assign_cv_noref, IR_FUNCTION | IR_FASTCALL_FUNC) \
245 _(assign_cv, IR_FUNCTION | IR_FASTCALL_FUNC) \
246 _(new_array, IR_FUNCTION | IR_FASTCALL_FUNC) \
247
248 #define JIT_STUB_ID(name, flags) \
249 jit_stub_ ## name,
250
251 #define JIT_STUB_FORWARD(name, flags) \
252 static int zend_jit_ ## name ## _stub(zend_jit_ctx *jit);
253
254 #define JIT_STUB(name, flags) \
255 {JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, flags},
256
257 typedef enum _jit_stub_id {
258 JIT_STUBS(JIT_STUB_ID)
259 jit_last_stub
260 } jit_stub_id;
261
262 typedef struct _zend_jit_reg_var {
263 ir_ref ref;
264 uint32_t flags;
265 } zend_jit_reg_var;
266
267 typedef struct _zend_jit_ctx {
268 ir_ctx ctx;
269 const zend_op *last_valid_opline;
270 bool use_last_valid_opline;
271 bool track_last_valid_opline;
272 bool reuse_ip;
273 uint32_t delayed_call_level;
274 int b; /* current basic block number or -1 */
275 #ifdef ZTS
276 ir_ref tls;
277 #endif
278 ir_ref fp;
279 ir_ref trace_loop_ref;
280 ir_ref return_inputs;
281 const zend_op_array *op_array;
282 const zend_op_array *current_op_array;
283 zend_ssa *ssa;
284 zend_string *name;
285 ir_ref *bb_start_ref; /* PHP BB -> IR ref mapping */
286 ir_ref *bb_predecessors; /* PHP BB -> index in bb_edges -> IR refs of predessors */
287 ir_ref *bb_edges;
288 zend_jit_trace_info *trace;
289 zend_jit_reg_var *ra;
290 int delay_var;
291 ir_refs *delay_refs;
292 ir_ref eg_exception_addr;
293 HashTable addr_hash;
294 ir_ref stub_addr[jit_last_stub];
295 } zend_jit_ctx;
296
297 typedef int8_t zend_reg;
298
299 typedef struct _zend_jit_registers_buf {
300 #if defined(IR_TARGET_X64)
301 uint64_t gpr[16]; /* general purpose integer register */
302 double fpr[16]; /* floating point registers */
303 #elif defined(IR_TARGET_X86)
304 uint32_t gpr[8]; /* general purpose integer register */
305 double fpr[8]; /* floating point registers */
306 #elif defined (IR_TARGET_AARCH64)
307 uint64_t gpr[32]; /* general purpose integer register */
308 double fpr[32]; /* floating point registers */
309 #else
310 # error "Unknown IR target"
311 #endif
312 } zend_jit_registers_buf;
313
314 /* Keep 32 exit points in a single code block */
315 #define ZEND_JIT_EXIT_POINTS_SPACING 4 // push byte + short jmp = bytes
316 #define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
317
318 static uint32_t zend_jit_exit_point_by_addr(const void *addr);
319 int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
320
321 static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
322 const zend_op *opline,
323 zend_jit_addr var_use_addr,
324 zend_jit_addr var_addr,
325 uint32_t var_info,
326 uint32_t var_def_info,
327 uint8_t val_type,
328 zend_jit_addr val_addr,
329 uint32_t val_info,
330 zend_jit_addr res_addr,
331 zend_jit_addr ref_addr,
332 bool check_exception);
333
334 typedef struct _zend_jit_stub {
335 const char *name;
336 int (*stub)(zend_jit_ctx *jit);
337 uint32_t flags;
338 } zend_jit_stub;
339
340 JIT_STUBS(JIT_STUB_FORWARD)
341
342 static const zend_jit_stub zend_jit_stubs[] = {
343 JIT_STUBS(JIT_STUB)
344 };
345
346 #if defined(_WIN32) || defined(IR_TARGET_AARCH64)
347 /* We keep addresses in SHM to share them between sepaeate processes (on Windows) or to support veneers (on AArch64) */
348 static void** zend_jit_stub_handlers = NULL;
349 #else
350 static void* zend_jit_stub_handlers[sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])];
351 #endif
352
353 #if defined(IR_TARGET_AARCH64)
354
355 # ifdef __FreeBSD__
356 /* https://github.com/freebsd/freebsd-src/blob/c52ca7dd09066648b1cc40f758289404d68ab886/libexec/rtld-elf/aarch64/reloc.c#L180-L184 */
357 typedef struct TLSDescriptor {
358 void* thunk;
359 int index;
360 size_t offset;
361 } TLSDescriptor;
362 # endif
363
364 #define IR_HAS_VENEERS (1U<<31) /* IR_RESERVED_FLAG_1 */
365
zend_jit_get_veneer(ir_ctx * ctx,const void * addr)366 static const void *zend_jit_get_veneer(ir_ctx *ctx, const void *addr)
367 {
368 int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
369
370 for (i = 0; i < count; i++) {
371 if (zend_jit_stub_handlers[i] == addr) {
372 return zend_jit_stub_handlers[count + i];
373 }
374 }
375
376 if (((zend_jit_ctx*)ctx)->trace
377 && (void*)addr >= dasm_buf && (void*)addr < dasm_end) {
378 uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
379
380 if (exit_point != (uint32_t)-1) {
381 zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
382
383 ZEND_ASSERT(exit_point < t->exit_count);
384 return (const void*)((char*)ctx->deoptimization_exits_base + (exit_point * 4));
385 }
386 }
387
388 return NULL;
389 }
390
zend_jit_set_veneer(ir_ctx * ctx,const void * addr,const void * veneer)391 static bool zend_jit_set_veneer(ir_ctx *ctx, const void *addr, const void *veneer)
392 {
393 int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
394 uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
395
396 if (exit_point != (uint32_t)-1) {
397 return 1;
398 }
399 for (i = 0; i < count; i++) {
400 if (zend_jit_stub_handlers[i] == addr) {
401 const void **ptr = (const void**)&zend_jit_stub_handlers[count + i];
402 *ptr = veneer;
403 ctx->flags2 |= IR_HAS_VENEERS;
404 #ifdef HAVE_CAPSTONE
405 int64_t offset;
406 if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
407 const char *name = ir_disasm_find_symbol((uint64_t)(uintptr_t)addr, &offset);
408
409 if (name && !offset) {
410 if (strstr(name, "@veneer") == NULL) {
411 char *new_name;
412
413 zend_spprintf(&new_name, 0, "%s@veneer", name);
414 ir_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
415 efree(new_name);
416 } else {
417 ir_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
418 }
419 }
420 }
421 #endif
422 return 1;
423 }
424 }
425
426 return 0;
427 }
428
zend_jit_commit_veneers(void)429 static void zend_jit_commit_veneers(void)
430 {
431 int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
432
433 for (i = 0; i < count; i++) {
434 if (zend_jit_stub_handlers[count + i]) {
435 zend_jit_stub_handlers[i] = zend_jit_stub_handlers[count + i];
436 zend_jit_stub_handlers[count + i] = NULL;
437 }
438 }
439 }
440 #endif
441
zend_jit_prefer_const_addr_load(zend_jit_ctx * jit,uintptr_t addr)442 static bool zend_jit_prefer_const_addr_load(zend_jit_ctx *jit, uintptr_t addr)
443 {
444 #if defined(IR_TARGET_X86)
445 return 0; /* always use immediate value */
446 #elif defined(IR_TARGET_X64)
447 return addr > 0xffffffff; /* prefer loading long constant from memery */
448 #elif defined(IR_TARGET_AARCH64)
449 return addr > 0xffff;
450 #else
451 # error "Unknown IR target"
452 #endif
453 }
454
zend_reg_name(int8_t reg)455 static const char* zend_reg_name(int8_t reg)
456 {
457 return ir_reg_name(reg, ir_reg_is_int(reg) ? IR_LONG : IR_DOUBLE);
458 }
459
460 /* IR helpers */
461
462 #ifdef ZTS
jit_TLS(zend_jit_ctx * jit)463 static ir_ref jit_TLS(zend_jit_ctx *jit)
464 {
465 ZEND_ASSERT(jit->ctx.control);
466 if (jit->tls) {
467 /* Emit "TLS" once for basic block */
468 ir_insn *insn;
469 ir_ref ref = jit->ctx.control;
470
471 while (1) {
472 if (ref == jit->tls) {
473 return jit->tls;
474 }
475 insn = &jit->ctx.ir_base[ref];
476 if (insn->op >= IR_START || insn->op == IR_CALL) {
477 break;
478 }
479 ref = insn->op1;
480 }
481 }
482 jit->tls = ir_TLS(
483 tsrm_ls_cache_tcb_offset ? tsrm_ls_cache_tcb_offset : tsrm_tls_index,
484 tsrm_ls_cache_tcb_offset ? IR_NULL : tsrm_tls_offset);
485 return jit->tls;
486 }
487 #endif
488
jit_CONST_ADDR(zend_jit_ctx * jit,uintptr_t addr)489 static ir_ref jit_CONST_ADDR(zend_jit_ctx *jit, uintptr_t addr)
490 {
491 ir_ref ref;
492 zval *zv;
493
494 if (addr == 0) {
495 return IR_NULL;
496 }
497 zv = zend_hash_index_lookup(&jit->addr_hash, addr);
498 if (Z_TYPE_P(zv) == IS_LONG) {
499 ref = Z_LVAL_P(zv);
500 ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_ADDR, IR_ADDR));
501 } else {
502 ref = ir_unique_const_addr(&jit->ctx, addr);
503 ZVAL_LONG(zv, ref);
504 }
505 return ref;
506 }
507
jit_CONST_FUNC_PROTO(zend_jit_ctx * jit,uintptr_t addr,ir_ref proto)508 static ir_ref jit_CONST_FUNC_PROTO(zend_jit_ctx *jit, uintptr_t addr, ir_ref proto)
509 {
510 ir_ref ref;
511 ir_insn *insn;
512 zval *zv;
513
514 ZEND_ASSERT(addr != 0);
515 zv = zend_hash_index_lookup(&jit->addr_hash, addr);
516 if (Z_TYPE_P(zv) == IS_LONG) {
517 ref = Z_LVAL_P(zv);
518 ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_FUNC_ADDR, IR_ADDR) && jit->ctx.ir_base[ref].proto == proto);
519 } else {
520 ref = ir_unique_const_addr(&jit->ctx, addr);
521 insn = &jit->ctx.ir_base[ref];
522 insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
523 insn->proto = proto;
524 ZVAL_LONG(zv, ref);
525 }
526 return ref;
527 }
528
jit_CONST_FUNC(zend_jit_ctx * jit,uintptr_t addr,uint16_t flags)529 static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags)
530 {
531 #if defined(IR_TARGET_X86)
532 /* TODO: dummy prototype (only flags matter) ??? */
533 ir_ref proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
534 #else
535 ir_ref proto = 0;
536 #endif
537
538 return jit_CONST_FUNC_PROTO(jit, addr, proto);
539 }
540
jit_ADD_OFFSET(zend_jit_ctx * jit,ir_ref addr,uintptr_t offset)541 static ir_ref jit_ADD_OFFSET(zend_jit_ctx *jit, ir_ref addr, uintptr_t offset)
542 {
543 if (offset) {
544 addr = ir_ADD_A(addr, ir_CONST_ADDR(offset));
545 }
546 return addr;
547 }
548
jit_EG_exception(zend_jit_ctx * jit)549 static ir_ref jit_EG_exception(zend_jit_ctx *jit)
550 {
551 #ifdef ZTS
552 return jit_EG(exception);
553 #else
554 ir_ref ref = jit->eg_exception_addr;
555
556 if (UNEXPECTED(!ref)) {
557 ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)&EG(exception));
558 jit->eg_exception_addr = ref;
559 }
560 return ref;
561 #endif
562 }
563
jit_STUB_ADDR(zend_jit_ctx * jit,jit_stub_id id)564 static ir_ref jit_STUB_ADDR(zend_jit_ctx *jit, jit_stub_id id)
565 {
566 ir_ref ref = jit->stub_addr[id];
567
568 if (UNEXPECTED(!ref)) {
569 ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
570 jit->stub_addr[id] = ref;
571 }
572 return ref;
573 }
574
jit_STUB_FUNC_ADDR(zend_jit_ctx * jit,jit_stub_id id,uint16_t flags)575 static ir_ref jit_STUB_FUNC_ADDR(zend_jit_ctx *jit, jit_stub_id id, uint16_t flags)
576 {
577 ir_ref ref = jit->stub_addr[id];
578 ir_insn *insn;
579
580 if (UNEXPECTED(!ref)) {
581 ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
582 insn = &jit->ctx.ir_base[ref];
583 insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
584 #if defined(IR_TARGET_X86)
585 /* TODO: dummy prototype (only flags matter) ??? */
586 insn->proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
587 #else
588 insn->proto = 0;
589 #endif
590 jit->stub_addr[id] = ref;
591 }
592 return ref;
593 }
594
jit_SNAPSHOT(zend_jit_ctx * jit,ir_ref addr)595 static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
596 {
597 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
598 const void *ptr = (const void*)jit->ctx.ir_base[addr].val.addr;
599 const zend_op_array *op_array = &JIT_G(current_frame)->func->op_array;
600 uint32_t stack_size = op_array->last_var + op_array->T;
601
602 if (ptr == zend_jit_stub_handlers[jit_stub_exception_handler]
603 || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_undef]
604 || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op1_op2]
605 || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op2]
606 || ptr == zend_jit_stub_handlers[jit_stub_interrupt_handler]
607 || ptr == zend_jit_stub_handlers[jit_stub_leave_function_handler]
608 || ptr == zend_jit_stub_handlers[jit_stub_negative_shift]
609 || ptr == zend_jit_stub_handlers[jit_stub_mod_by_zero]
610 || ptr == zend_jit_stub_handlers[jit_stub_invalid_this]
611 || ptr == zend_jit_stub_handlers[jit_stub_undefined_function]
612 || ptr == zend_jit_stub_handlers[jit_stub_throw_cannot_pass_by_ref]
613 || ptr == zend_jit_stub_handlers[jit_stub_icall_throw]
614 || ptr == zend_jit_stub_handlers[jit_stub_leave_throw]
615 || ptr == zend_jit_stub_handlers[jit_stub_trace_halt]
616 || ptr == zend_jit_stub_handlers[jit_stub_trace_escape]) {
617 /* This is a GUARD that trigger exit through a stub code (without deoptimization) */
618 return;
619 }
620
621 /* Check if we need snapshot entries for polymorphic method call */
622 zend_jit_trace_info *t = jit->trace;
623 uint32_t exit_point = 0, n = 0;
624
625 if (addr < 0) {
626 if (t->exit_count > 0
627 && jit->ctx.ir_base[addr].val.u64 == (uintptr_t)zend_jit_trace_get_exit_addr(t->exit_count - 1)) {
628 exit_point = t->exit_count - 1;
629 if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
630 n = 2;
631 }
632 }
633 }
634
635 if (stack_size || n) {
636 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
637 uint32_t snapshot_size, i;
638
639 snapshot_size = stack_size;
640 while (snapshot_size > 0) {
641 ir_ref ref = STACK_REF(stack, snapshot_size - 1);
642
643 if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, snapshot_size - 1) & (/*ZREG_LOAD|*/ZREG_STORE))) {
644 snapshot_size--;
645 } else {
646 break;
647 }
648 }
649 if (snapshot_size || n) {
650 ir_ref snapshot;
651
652 snapshot = ir_SNAPSHOT(snapshot_size + n);
653 for (i = 0; i < snapshot_size; i++) {
654 ir_ref ref = STACK_REF(stack, i);
655
656 if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, i) & (/*ZREG_LOAD|*/ZREG_STORE))) {
657 ref = IR_UNUSED;
658 }
659 ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
660 }
661 if (n) {
662 ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func_ref);
663 ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this_ref);
664 }
665 }
666 }
667 }
668 }
669
_add_trace_const(zend_jit_trace_info * t,int64_t val)670 static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
671 {
672 int32_t i;
673
674 for (i = 0; i < t->consts_count; i++) {
675 if (t->constants[i].i == val) {
676 return i;
677 }
678 }
679 ZEND_ASSERT(i < 0x7fffffff);
680 t->consts_count = i + 1;
681 t->constants = erealloc(t->constants, (i + 1) * sizeof(zend_jit_exit_const));
682 t->constants[i].i = val;
683 return i;
684 }
685
zend_jit_duplicate_exit_point(ir_ctx * ctx,zend_jit_trace_info * t,uint32_t exit_point,ir_ref snapshot_ref)686 uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
687 {
688 uint32_t stack_size, stack_offset;
689 uint32_t new_exit_point = t->exit_count;
690
691 if (new_exit_point >= ZEND_JIT_TRACE_MAX_EXITS) {
692 ctx->status = -ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
693 return exit_point;
694 }
695
696 t->exit_count++;
697 memcpy(&t->exit_info[new_exit_point], &t->exit_info[exit_point], sizeof(zend_jit_trace_exit_info));
698 stack_size = t->exit_info[new_exit_point].stack_size;
699 if (stack_size != 0) {
700 stack_offset = t->stack_map_size;
701 t->stack_map_size += stack_size;
702 // TODO: reduce number of reallocations ???
703 t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
704 memcpy(t->stack_map + stack_offset, t->stack_map + t->exit_info[new_exit_point].stack_offset, stack_size * sizeof(zend_jit_trace_stack));
705 t->exit_info[new_exit_point].stack_offset = stack_offset;
706 }
707 t->exit_info[new_exit_point].flags &= ~ZEND_JIT_EXIT_FIXED;
708
709 return new_exit_point;
710 }
711
zend_jit_snapshot_handler(ir_ctx * ctx,ir_ref snapshot_ref,ir_insn * snapshot,void * addr)712 void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
713 {
714 zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
715 uint32_t exit_point, exit_flags;
716 ir_ref n = snapshot->inputs_count;
717 ir_ref i;
718
719 exit_point = zend_jit_exit_point_by_addr(addr);
720 ZEND_ASSERT(exit_point < t->exit_count);
721 exit_flags = t->exit_info[exit_point].flags;
722
723 if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
724 int8_t *reg_ops = ctx->regs[snapshot_ref];
725
726 ZEND_ASSERT(reg_ops[n - 1] != -1 && reg_ops[n] != -1);
727 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
728 && (t->exit_info[exit_point].poly_func_reg != reg_ops[n - 1]
729 || t->exit_info[exit_point].poly_this_reg != reg_ops[n])) {
730 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
731 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
732 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
733 }
734 t->exit_info[exit_point].poly_func_reg = reg_ops[n - 1];
735 t->exit_info[exit_point].poly_this_reg = reg_ops[n];
736 n -= 2;
737 }
738
739 for (i = 2; i <= n; i++) {
740 ir_ref ref = ir_insn_op(snapshot, i);
741
742 if (ref) {
743 int8_t *reg_ops = ctx->regs[snapshot_ref];
744 int8_t reg = reg_ops[i];
745 ir_ref var = i - 2;
746
747 ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
748 if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
749 ZEND_ASSERT(reg != ZREG_NONE);
750 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
751 && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
752 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
753 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
754 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
755 }
756 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
757 } else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
758 ZEND_ASSERT(t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_LONG ||
759 t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_DOUBLE);
760
761 if (ref > 0) {
762 if (reg != ZREG_NONE) {
763 if (reg & IR_REG_SPILL_LOAD) {
764 ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
765 /* spill slot on a CPU stack */
766 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
767 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].ref != ref
768 || t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
769 || !(t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ZREG_SPILL_SLOT))) {
770 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
771 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
772 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
773 }
774 t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
775 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
776 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
777 } else if (reg & IR_REG_SPILL_SPECIAL) {
778 /* spill slot on a VM stack */
779 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
780 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
781 || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
782 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
783 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
784 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
785 }
786 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
787 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
788 } else {
789 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
790 && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
791 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
792 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
793 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
794 }
795 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
796 }
797 } else {
798 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
799 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
800 || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
801 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
802 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
803 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
804 }
805 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
806 }
807 } else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
808 int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
809 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
810 t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
811 }
812 }
813 }
814 }
815 t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
816 return addr;
817 }
818
jit_SIDE_EXIT(zend_jit_ctx * jit,ir_ref addr)819 static void jit_SIDE_EXIT(zend_jit_ctx *jit, ir_ref addr)
820 {
821 jit_SNAPSHOT(jit, addr);
822 ir_IJMP(addr);
823 }
824
825 /* PHP JIT helpers */
826
jit_EMALLOC(zend_jit_ctx * jit,size_t size,const zend_op_array * op_array,const zend_op * opline)827 static ir_ref jit_EMALLOC(zend_jit_ctx *jit, size_t size, const zend_op_array *op_array, const zend_op *opline)
828 {
829 #if ZEND_DEBUG
830 return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_emalloc),
831 ir_CONST_ADDR(size),
832 op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
833 ir_CONST_U32(opline ? opline->lineno : 0),
834 IR_NULL,
835 ir_CONST_U32(0));
836 #elif defined(HAVE_BUILTIN_CONSTANT_P)
837 if (size > 24 && size <= 32) {
838 return ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_emalloc_32));
839 } else {
840 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
841 }
842 #else
843 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
844 #endif
845 }
846
jit_EFREE(zend_jit_ctx * jit,ir_ref ptr,size_t size,const zend_op_array * op_array,const zend_op * opline)847 static ir_ref jit_EFREE(zend_jit_ctx *jit, ir_ref ptr, size_t size, const zend_op_array *op_array, const zend_op *opline)
848 {
849 #if ZEND_DEBUG
850 return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_efree),
851 ptr,
852 op_array && op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
853 ir_CONST_U32(opline ? opline->lineno : 0),
854 IR_NULL,
855 ir_CONST_U32(0));
856 #elif defined(HAVE_BUILTIN_CONSTANT_P)
857 if (size > 24 && size <= 32) {
858 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree_32), ptr);
859 } else {
860 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
861 }
862 #else
863 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
864 #endif
865 }
866
jit_FP(zend_jit_ctx * jit)867 static ir_ref jit_FP(zend_jit_ctx *jit)
868 {
869 ZEND_ASSERT(jit->ctx.control);
870 if (jit->fp == IR_UNUSED) {
871 /* Emit "RLOAD FP" once for basic block */
872 jit->fp = ir_RLOAD_A(ZREG_FP);
873 } else {
874 ir_insn *insn;
875 ir_ref ref = jit->ctx.control;
876
877 while (1) {
878 if (ref == jit->fp) {
879 break;
880 }
881 insn = &jit->ctx.ir_base[ref];
882 if (insn->op >= IR_START || insn->op == IR_CALL) {
883 jit->fp = ir_RLOAD_A(ZREG_FP);
884 break;
885 }
886 ref = insn->op1;
887 }
888 }
889 return jit->fp;
890 }
891
jit_STORE_FP(zend_jit_ctx * jit,ir_ref ref)892 static void jit_STORE_FP(zend_jit_ctx *jit, ir_ref ref)
893 {
894 ir_RSTORE(ZREG_FP, ref);
895 jit->fp = IR_UNUSED;
896 }
897
jit_IP(zend_jit_ctx * jit)898 static ir_ref jit_IP(zend_jit_ctx *jit)
899 {
900 return ir_RLOAD_A(ZREG_IP);
901 }
902
jit_STORE_IP(zend_jit_ctx * jit,ir_ref ref)903 static void jit_STORE_IP(zend_jit_ctx *jit, ir_ref ref)
904 {
905 ir_RSTORE(ZREG_IP, ref);
906 }
907
jit_IP32(zend_jit_ctx * jit)908 static ir_ref jit_IP32(zend_jit_ctx *jit)
909 {
910 return ir_RLOAD_U32(ZREG_IP);
911 }
912
jit_LOAD_IP(zend_jit_ctx * jit,ir_ref ref)913 static void jit_LOAD_IP(zend_jit_ctx *jit, ir_ref ref)
914 {
915 if (GCC_GLOBAL_REGS) {
916 jit_STORE_IP(jit, ref);
917 } else {
918 ir_STORE(jit_EX(opline), ref);
919 }
920 }
921
jit_LOAD_IP_ADDR(zend_jit_ctx * jit,const zend_op * target)922 static void jit_LOAD_IP_ADDR(zend_jit_ctx *jit, const zend_op *target)
923 {
924 jit_LOAD_IP(jit, ir_CONST_ADDR(target));
925 }
926
zend_jit_track_last_valid_opline(zend_jit_ctx * jit)927 static void zend_jit_track_last_valid_opline(zend_jit_ctx *jit)
928 {
929 jit->use_last_valid_opline = 0;
930 jit->track_last_valid_opline = 1;
931 }
932
zend_jit_use_last_valid_opline(zend_jit_ctx * jit)933 static void zend_jit_use_last_valid_opline(zend_jit_ctx *jit)
934 {
935 if (jit->track_last_valid_opline) {
936 jit->use_last_valid_opline = 1;
937 jit->track_last_valid_opline = 0;
938 }
939 }
940
zend_jit_trace_uses_initial_ip(zend_jit_ctx * jit)941 static bool zend_jit_trace_uses_initial_ip(zend_jit_ctx *jit)
942 {
943 return jit->use_last_valid_opline;
944 }
945
zend_jit_set_last_valid_opline(zend_jit_ctx * jit,const zend_op * opline)946 static void zend_jit_set_last_valid_opline(zend_jit_ctx *jit, const zend_op *opline)
947 {
948 if (!jit->reuse_ip) {
949 jit->track_last_valid_opline = 1;
950 jit->last_valid_opline = opline;
951 }
952 }
953
zend_jit_reset_last_valid_opline(zend_jit_ctx * jit)954 static void zend_jit_reset_last_valid_opline(zend_jit_ctx *jit)
955 {
956 jit->track_last_valid_opline = 0;
957 jit->last_valid_opline = NULL;
958 }
959
zend_jit_start_reuse_ip(zend_jit_ctx * jit)960 static void zend_jit_start_reuse_ip(zend_jit_ctx *jit)
961 {
962 zend_jit_reset_last_valid_opline(jit);
963 jit->reuse_ip = 1;
964 }
965
zend_jit_reuse_ip(zend_jit_ctx * jit)966 static int zend_jit_reuse_ip(zend_jit_ctx *jit)
967 {
968 if (!jit->reuse_ip) {
969 zend_jit_start_reuse_ip(jit);
970 // RX = EX(call);
971 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
972 }
973 return 1;
974 }
975
zend_jit_stop_reuse_ip(zend_jit_ctx * jit)976 static void zend_jit_stop_reuse_ip(zend_jit_ctx *jit)
977 {
978 jit->reuse_ip = 0;
979 }
980
zend_jit_save_call_chain(zend_jit_ctx * jit,uint32_t call_level)981 static int zend_jit_save_call_chain(zend_jit_ctx *jit, uint32_t call_level)
982 {
983 ir_ref rx, call;
984
985 if (call_level == 1) {
986 // JIT: call = NULL;
987 call = IR_NULL;
988 } else {
989 // JIT: call = EX(call);
990 call = ir_LOAD_A(jit_EX(call));
991 }
992
993 rx = jit_IP(jit);
994
995 // JIT: call->prev_execute_data = call;
996 ir_STORE(jit_CALL(rx, prev_execute_data), call);
997
998 // JIT: EX(call) = call;
999 ir_STORE(jit_EX(call), rx);
1000
1001 jit->delayed_call_level = 0;
1002 delayed_call_chain = 0;
1003
1004 return 1;
1005 }
1006
zend_jit_set_ip(zend_jit_ctx * jit,const zend_op * target)1007 static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target)
1008 {
1009 ir_ref ref;
1010 ir_ref addr = IR_UNUSED;
1011
1012 if (jit->delayed_call_level) {
1013 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
1014 return 0;
1015 }
1016 }
1017
1018 if (jit->last_valid_opline) {
1019 zend_jit_use_last_valid_opline(jit);
1020 if (jit->last_valid_opline != target) {
1021 if (GCC_GLOBAL_REGS) {
1022 ref = jit_IP(jit);
1023 } else {
1024 addr = jit_EX(opline);
1025 ref = ir_LOAD_A(addr);
1026 }
1027 if (target > jit->last_valid_opline) {
1028 ref = ir_ADD_OFFSET(ref, (uintptr_t)target - (uintptr_t)jit->last_valid_opline);
1029 } else {
1030 ref = ir_SUB_A(ref, ir_CONST_ADDR((uintptr_t)jit->last_valid_opline - (uintptr_t)target));
1031 }
1032 if (GCC_GLOBAL_REGS) {
1033 jit_STORE_IP(jit, ref);
1034 } else {
1035 ir_STORE(addr, ref);
1036 }
1037 }
1038 } else {
1039 if (GCC_GLOBAL_REGS) {
1040 jit_STORE_IP(jit, ir_CONST_ADDR(target));
1041 } else {
1042 ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1043 }
1044 }
1045 jit->reuse_ip = 0;
1046 zend_jit_set_last_valid_opline(jit, target);
1047 return 1;
1048 }
1049
zend_jit_set_ip_ex(zend_jit_ctx * jit,const zend_op * target,bool set_ip_reg)1050 static int zend_jit_set_ip_ex(zend_jit_ctx *jit, const zend_op *target, bool set_ip_reg)
1051 {
1052 if (!GCC_GLOBAL_REGS && set_ip_reg && !jit->last_valid_opline) {
1053 /* Optimization to avoid duplicate constant load */
1054 ir_STORE(jit_EX(opline), ir_HARD_COPY_A(ir_CONST_ADDR(target)));
1055 return 1;
1056 }
1057 return zend_jit_set_ip(jit, target);
1058 }
1059
jit_SET_EX_OPLINE(zend_jit_ctx * jit,const zend_op * target)1060 static void jit_SET_EX_OPLINE(zend_jit_ctx *jit, const zend_op *target)
1061 {
1062 if (jit->last_valid_opline == target) {
1063 zend_jit_use_last_valid_opline(jit);
1064 if (GCC_GLOBAL_REGS) {
1065 // EX(opline) = opline
1066 ir_STORE(jit_EX(opline), jit_IP(jit));
1067 }
1068 } else {
1069 ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1070 if (!GCC_GLOBAL_REGS) {
1071 zend_jit_reset_last_valid_opline(jit);
1072 }
1073 }
1074 }
1075
jit_ZVAL_ADDR(zend_jit_ctx * jit,zend_jit_addr addr)1076 static ir_ref jit_ZVAL_ADDR(zend_jit_ctx *jit, zend_jit_addr addr)
1077 {
1078 if (Z_MODE(addr) == IS_MEM_ZVAL) {
1079 ir_ref reg;
1080
1081 if (Z_REG(addr) == ZREG_FP) {
1082 reg = jit_FP(jit);
1083 } else if (Z_REG(addr) == ZREG_RX) {
1084 reg = jit_IP(jit);
1085 } else {
1086 ZEND_UNREACHABLE();
1087 }
1088 return ir_ADD_OFFSET(reg, Z_OFFSET(addr));
1089 } else if (Z_MODE(addr) == IS_REF_ZVAL) {
1090 return Z_IR_REF(addr);
1091 } else {
1092 ZEND_ASSERT(Z_MODE(addr) == IS_CONST_ZVAL);
1093 return ir_CONST_ADDR(Z_ZV(addr));
1094 }
1095 }
1096
jit_Z_TYPE_ref(zend_jit_ctx * jit,ir_ref ref)1097 static ir_ref jit_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref)
1098 {
1099 return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type)));
1100 }
1101
jit_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr)1102 static ir_ref jit_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr)
1103 {
1104 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1105 return ir_CONST_U8(Z_TYPE_P(Z_ZV(addr)));
1106 } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1107 ir_ref reg;
1108
1109 ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1110 if (Z_REG(addr) == ZREG_FP) {
1111 reg = jit_FP(jit);
1112 } else if (Z_REG(addr) == ZREG_RX) {
1113 reg = jit_IP(jit);
1114 } else {
1115 ZEND_UNREACHABLE();
1116 }
1117 return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type)));
1118 } else {
1119 return jit_Z_TYPE_ref(jit, jit_ZVAL_ADDR(jit, addr));
1120 }
1121 }
1122
jit_Z_TYPE_FLAGS_ref(zend_jit_ctx * jit,ir_ref ref)1123 static ir_ref jit_Z_TYPE_FLAGS_ref(zend_jit_ctx *jit, ir_ref ref)
1124 {
1125 return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type_flags)));
1126 }
1127
jit_Z_TYPE_FLAGS(zend_jit_ctx * jit,zend_jit_addr addr)1128 static ir_ref jit_Z_TYPE_FLAGS(zend_jit_ctx *jit, zend_jit_addr addr)
1129 {
1130 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1131 return ir_CONST_U8(Z_TYPE_FLAGS_P(Z_ZV(addr)));
1132 } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1133 ir_ref reg;
1134
1135 ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1136 if (Z_REG(addr) == ZREG_FP) {
1137 reg = jit_FP(jit);
1138 } else if (Z_REG(addr) == ZREG_RX) {
1139 reg = jit_IP(jit);
1140 } else {
1141 ZEND_UNREACHABLE();
1142 }
1143 return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type_flags)));
1144 } else {
1145 return jit_Z_TYPE_FLAGS_ref(jit, jit_ZVAL_ADDR(jit, addr));
1146 }
1147 }
1148
jit_Z_TYPE_INFO_ref(zend_jit_ctx * jit,ir_ref ref)1149 static ir_ref jit_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref)
1150 {
1151 return ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)));
1152 }
1153
jit_Z_TYPE_INFO(zend_jit_ctx * jit,zend_jit_addr addr)1154 static ir_ref jit_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr)
1155 {
1156 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1157 return ir_CONST_U32(Z_TYPE_INFO_P(Z_ZV(addr)));
1158 } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1159 ir_ref reg;
1160
1161 ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1162 if (Z_REG(addr) == ZREG_FP) {
1163 reg = jit_FP(jit);
1164 } else if (Z_REG(addr) == ZREG_RX) {
1165 reg = jit_IP(jit);
1166 } else {
1167 ZEND_UNREACHABLE();
1168 }
1169 return ir_LOAD_U32(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)));
1170 } else {
1171 return jit_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr));
1172 }
1173 }
1174
jit_set_Z_TYPE_INFO_ref(zend_jit_ctx * jit,ir_ref ref,ir_ref type_info)1175 static void jit_set_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type_info)
1176 {
1177 ir_STORE(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)), type_info);
1178 }
1179
jit_set_Z_TYPE_INFO_ex(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref type_info)1180 static void jit_set_Z_TYPE_INFO_ex(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref type_info)
1181 {
1182 if (Z_MODE(addr) == IS_MEM_ZVAL) {
1183 ir_ref reg;
1184
1185 ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1186 if (Z_REG(addr) == ZREG_FP) {
1187 reg = jit_FP(jit);
1188 } else if (Z_REG(addr) == ZREG_RX) {
1189 reg = jit_IP(jit);
1190 } else {
1191 ZEND_UNREACHABLE();
1192 }
1193 ir_STORE(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)), type_info);
1194 } else {
1195 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr), type_info);
1196 }
1197 }
1198
jit_set_Z_TYPE_INFO(zend_jit_ctx * jit,zend_jit_addr addr,uint32_t type_info)1199 static void jit_set_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr, uint32_t type_info)
1200 {
1201 if (type_info < IS_STRING
1202 && Z_MODE(addr) == IS_MEM_ZVAL
1203 && Z_REG(addr) == ZREG_FP
1204 && JIT_G(current_frame)
1205 && STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(addr))) == type_info) {
1206 /* type is already set */
1207 return;
1208 }
1209 jit_set_Z_TYPE_INFO_ex(jit, addr, ir_CONST_U32(type_info));
1210 }
1211
jit_if_Z_TYPE_ref(zend_jit_ctx * jit,ir_ref ref,ir_ref type)1212 static ir_ref jit_if_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type)
1213 {
1214 return ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), type));
1215 }
1216
jit_if_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type)1217 static ir_ref jit_if_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1218 {
1219 ZEND_ASSERT(type != IS_UNDEF);
1220 return ir_IF(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)));
1221 }
1222
jit_if_not_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type)1223 static ir_ref jit_if_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1224 {
1225 ir_ref ref = jit_Z_TYPE(jit, addr);
1226
1227 if (type != IS_UNDEF) {
1228 ref = ir_NE(ref, ir_CONST_U8(type));
1229 }
1230 return ir_IF(ref);
1231 }
1232
jit_guard_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type,const void * exit_addr)1233 static void jit_guard_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1234 {
1235 ir_ref ref = jit_Z_TYPE(jit, addr);
1236
1237 if (type != IS_UNDEF) {
1238 ir_GUARD(ir_EQ(ref, ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
1239 } else {
1240 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1241 }
1242 }
1243
jit_guard_not_Z_TYPE(zend_jit_ctx * jit,zend_jit_addr addr,uint8_t type,const void * exit_addr)1244 static void jit_guard_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1245 {
1246 ir_ref ref = jit_Z_TYPE(jit, addr);
1247
1248 if (type != IS_UNDEF) {
1249 ref = ir_NE(ref, ir_CONST_U8(type));
1250 }
1251 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
1252 }
1253
jit_if_REFCOUNTED(zend_jit_ctx * jit,zend_jit_addr addr)1254 static ir_ref jit_if_REFCOUNTED(zend_jit_ctx *jit, zend_jit_addr addr)
1255 {
1256 return ir_IF(jit_Z_TYPE_FLAGS(jit, addr));
1257 }
1258
jit_if_COLLECTABLE_ref(zend_jit_ctx * jit,ir_ref addr_ref)1259 static ir_ref jit_if_COLLECTABLE_ref(zend_jit_ctx *jit, ir_ref addr_ref)
1260 {
1261 return ir_IF(ir_AND_U8(jit_Z_TYPE_FLAGS_ref(jit, addr_ref), ir_CONST_U8(IS_TYPE_COLLECTABLE)));
1262 }
1263
jit_Z_LVAL_ref(zend_jit_ctx * jit,ir_ref ref)1264 static ir_ref jit_Z_LVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1265 {
1266 return ir_LOAD_L(ref);
1267 }
1268
jit_Z_DVAL_ref(zend_jit_ctx * jit,ir_ref ref)1269 static ir_ref jit_Z_DVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1270 {
1271 return ir_LOAD_D(ref);
1272 }
1273
zend_jit_spilling_may_cause_conflict(zend_jit_ctx * jit,int var,ir_ref val)1274 static bool zend_jit_spilling_may_cause_conflict(zend_jit_ctx *jit, int var, ir_ref val)
1275 {
1276 if (jit->ctx.ir_base[val].op == IR_RLOAD) {
1277 /* Deoptimization */
1278 return 0;
1279 }
1280 // if (jit->ctx.ir_base[val].op == IR_LOAD
1281 // && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1282 // && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1283 // && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1284 // && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1285 // && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr == (uintptr_t)EX_NUM_TO_VAR(jit->ssa->vars[var].var)) {
1286 // /* LOAD from the same location (the LOAD is pinned) */
1287 // // TODO: should be anti-dependent with the following stores ???
1288 // return 0;
1289 // }
1290 if (jit->ssa->vars[var].var < jit->current_op_array->last_var) {
1291 /* IS_CV */
1292 if (jit->ctx.ir_base[val].op == IR_LOAD
1293 && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1294 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1295 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1296 && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1297 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr != (uintptr_t)EX_NUM_TO_VAR(jit->ssa->vars[var].var)
1298 && EX_VAR_TO_NUM(jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2].val.addr) < jit->current_op_array->last_var) {
1299 /* binding between different CVs may cause spill conflict */
1300 return 1;
1301 } else if (jit->ssa->vars[var].definition >= 0
1302 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1303 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1304 && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].no_val
1305 && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi
1306 && (jit->ssa->cfg.blocks[jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi->block].flags & ZEND_BB_LOOP_HEADER)) {
1307 /* Avoid moving spill store out of loop */
1308 return 1;
1309 }
1310 return 0;
1311 }
1312 return 1;
1313 }
1314
zend_jit_def_reg(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref val)1315 static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
1316 {
1317 int var;
1318
1319 ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1320 var = Z_SSA_VAR(addr);
1321 if (var == jit->delay_var) {
1322 ir_refs_add(jit->delay_refs, val);
1323 return;
1324 }
1325 ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
1326
1327 /* Negative "var" has special meaning for IR */
1328 if (val > 0 && !zend_jit_spilling_may_cause_conflict(jit, var, val)) {
1329 val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
1330 }
1331 jit->ra[var].ref = val;
1332
1333 if (jit->ra[var].flags & ZREG_FORWARD) {
1334 zend_ssa_phi *phi = jit->ssa->vars[var].phi_use_chain;
1335 zend_basic_block *bb;
1336 int n, j, *p;
1337 ir_ref *q;
1338
1339 jit->ra[var].flags &= ~ZREG_FORWARD;
1340 while (phi != NULL) {
1341 zend_ssa_phi *dst_phi = phi;
1342 int src_var = var;
1343
1344 if (dst_phi->pi >= 0) {
1345 jit->ra[src_var].ref = val;
1346 src_var = dst_phi->ssa_var;
1347 if (!(jit->ra[src_var].flags & ZREG_FORWARD)) {
1348 phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1349 continue;
1350 }
1351 dst_phi = jit->ssa->vars[src_var].phi_use_chain;
1352 ZEND_ASSERT(dst_phi != NULL && "reg forwarding");
1353 ZEND_ASSERT(!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding");
1354 jit->ra[src_var].flags &= ~ZREG_FORWARD;
1355 }
1356
1357 if (jit->ra[dst_phi->ssa_var].ref > 0) {
1358 ir_insn *phi_insn = &jit->ctx.ir_base[jit->ra[dst_phi->ssa_var].ref];
1359 if (phi_insn->op == IR_PHI) {
1360 // ZEND_ASSERT(ir_operands_count(ctx, phi_insn) == n + 1);
1361 bb = &jit->ssa->cfg.blocks[dst_phi->block];
1362 n = bb->predecessors_count;
1363 for (j = 0, p = &dst_phi->sources[0], q = phi_insn->ops + 2; j < n; j++, p++, q++) {
1364 if (*p == src_var) {
1365 *q = val;
1366 }
1367 }
1368 }
1369 }
1370
1371 phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1372 }
1373 }
1374 }
1375
zend_jit_use_reg(zend_jit_ctx * jit,zend_jit_addr addr)1376 static ir_ref zend_jit_use_reg(zend_jit_ctx *jit, zend_jit_addr addr)
1377 {
1378 int var = Z_SSA_VAR(addr);
1379
1380 ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1381 ZEND_ASSERT(jit->ra && jit->ra[var].ref);
1382 if (jit->ra[var].ref == IR_NULL) {
1383 zend_jit_addr mem_addr;
1384 ir_ref ref;
1385
1386 ZEND_ASSERT(jit->ra[var].flags & ZREG_LOAD);
1387 mem_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(jit->ssa->vars[var].var));
1388 if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_LONG) {
1389 ref = jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1390 } else if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1391 ref = jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1392 } else {
1393 ZEND_UNREACHABLE();
1394 }
1395 zend_jit_def_reg(jit, addr, ref);
1396 return ref;
1397 }
1398 return jit->ra[Z_SSA_VAR(addr)].ref;
1399 }
1400
zend_jit_gen_pi(zend_jit_ctx * jit,zend_ssa_phi * phi)1401 static void zend_jit_gen_pi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1402 {
1403 int src_var = phi->sources[0];
1404 int dst_var = phi->ssa_var;
1405
1406 ZEND_ASSERT(phi->pi >= 0);
1407 ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1408 ZEND_ASSERT(jit->ra[src_var].ref);
1409
1410 if (jit->ra[src_var].ref == IR_NULL) {
1411 /* Not defined yet */
1412 if (jit->ssa->vars[dst_var].use_chain < 0
1413 && jit->ssa->vars[dst_var].phi_use_chain) {
1414 zend_ssa_phi *phi = jit->ssa->vars[dst_var].phi_use_chain;
1415 if (!zend_ssa_next_use_phi(jit->ssa, dst_var, phi)) {
1416 /* This is a Pi forwarded to Phi */
1417 jit->ra[src_var].flags |= ZREG_FORWARD;
1418 return;
1419 }
1420 }
1421 ZEND_ASSERT(0 && "Not defined Pi source");
1422 }
1423 /* Reuse register */
1424 zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var),
1425 zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)));
1426 }
1427
zend_jit_gen_phi(zend_jit_ctx * jit,zend_ssa_phi * phi)1428 static void zend_jit_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1429 {
1430 int dst_var = phi->ssa_var;
1431 zend_basic_block *bb = &jit->ssa->cfg.blocks[phi->block];
1432 int n = bb->predecessors_count;
1433 int i;
1434 ir_type type = (jit->ssa->var_info[phi->ssa_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE;
1435 ir_ref merge = jit->bb_start_ref[phi->block];
1436 ir_ref ref;
1437 ir_ref old_insns_count = jit->ctx.insns_count;
1438 ir_ref same_src_ref = IR_UNUSED;
1439 bool phi_inputs_are_the_same = 1;
1440
1441 ZEND_ASSERT(phi->pi < 0);
1442 ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1443 ZEND_ASSERT(merge);
1444 ZEND_ASSERT(jit->ctx.ir_base[merge].op == IR_MERGE || jit->ctx.ir_base[merge].op == IR_LOOP_BEGIN);
1445 ZEND_ASSERT(n == jit->ctx.ir_base[merge].inputs_count);
1446
1447 ref = ir_emit_N(&jit->ctx, IR_OPT(IR_PHI, type), n + 1);
1448 ir_set_op(&jit->ctx, ref, 1, merge);
1449
1450 for (i = 0; i < n; i++) {
1451 int src_var = phi->sources[i];
1452
1453 ZEND_ASSERT(jit->ra[src_var].ref);
1454 if (jit->ra[src_var].ref == IR_NULL) {
1455 jit->ra[src_var].flags |= ZREG_FORWARD;
1456 phi_inputs_are_the_same = 0;
1457 } else {
1458 ir_ref src_ref = zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var));
1459 if (i == 0) {
1460 same_src_ref = src_ref;
1461 } else if (same_src_ref != src_ref) {
1462 phi_inputs_are_the_same = 0;
1463 }
1464 ir_set_op(&jit->ctx, ref, i + 2, src_ref);
1465 }
1466 }
1467 if (phi_inputs_are_the_same) {
1468 ref = same_src_ref;
1469 jit->ctx.insns_count = old_insns_count;
1470 }
1471
1472 zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
1473 }
1474
jit_Z_LVAL(zend_jit_ctx * jit,zend_jit_addr addr)1475 static ir_ref jit_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1476 {
1477 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1478 return ir_CONST_LONG(Z_LVAL_P(Z_ZV(addr)));
1479 } else if (Z_MODE(addr) == IS_REG) {
1480 return zend_jit_use_reg(jit, addr);
1481 } else {
1482 return jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1483 }
1484 }
1485
jit_set_Z_LVAL(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref lval)1486 static void jit_set_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1487 {
1488 if (Z_MODE(addr) == IS_REG) {
1489 zend_jit_def_reg(jit, addr, lval);
1490 } else {
1491 ir_STORE(jit_ZVAL_ADDR(jit, addr), lval);
1492 }
1493 }
1494
1495 #if SIZEOF_ZEND_LONG == 4
jit_Z_W2(zend_jit_ctx * jit,zend_jit_addr addr)1496 static ir_ref jit_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr)
1497 {
1498 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1499 return ir_CONST_U32((Z_ZV(addr))->value.ww.w2);
1500 } else {
1501 return ir_LOAD_L(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)));
1502 }
1503 }
1504
jit_set_Z_W2(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref lval)1505 static void jit_set_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1506 {
1507 ir_STORE(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)), lval);
1508 }
1509 #endif
1510
jit_Z_DVAL(zend_jit_ctx * jit,zend_jit_addr addr)1511 static ir_ref jit_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1512 {
1513 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1514 return ir_CONST_DOUBLE(Z_DVAL_P(Z_ZV(addr)));
1515 } else if (Z_MODE(addr) == IS_REG) {
1516 return zend_jit_use_reg(jit, addr);
1517 } else {
1518 return jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1519 }
1520 }
1521
jit_set_Z_DVAL(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref dval)1522 static void jit_set_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref dval)
1523 {
1524 if (Z_MODE(addr) == IS_REG) {
1525 zend_jit_def_reg(jit, addr, dval);
1526 } else {
1527 ir_STORE(jit_ZVAL_ADDR(jit, addr), dval);
1528 }
1529 }
1530
jit_Z_PTR_ref(zend_jit_ctx * jit,ir_ref ref)1531 static ir_ref jit_Z_PTR_ref(zend_jit_ctx *jit, ir_ref ref)
1532 {
1533 return ir_LOAD_A(ref);
1534 }
1535
jit_Z_PTR(zend_jit_ctx * jit,zend_jit_addr addr)1536 static ir_ref jit_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr)
1537 {
1538 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1539 return ir_CONST_ADDR(Z_PTR_P(Z_ZV(addr)));
1540 } else {
1541 return jit_Z_PTR_ref(jit, jit_ZVAL_ADDR(jit, addr));
1542 }
1543 }
1544
jit_set_Z_PTR(zend_jit_ctx * jit,zend_jit_addr addr,ir_ref ptr)1545 static void jit_set_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref ptr)
1546 {
1547 ir_STORE(jit_ZVAL_ADDR(jit, addr), ptr);
1548 }
1549
jit_GC_REFCOUNT(zend_jit_ctx * jit,ir_ref ref)1550 static ir_ref jit_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref)
1551 {
1552 return ir_LOAD_U32(ref);
1553 }
1554
jit_set_GC_REFCOUNT(zend_jit_ctx * jit,ir_ref ref,uint32_t refcount)1555 static void jit_set_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref, uint32_t refcount)
1556 {
1557 ir_STORE(ref, ir_CONST_U32(refcount));
1558 }
1559
jit_GC_ADDREF(zend_jit_ctx * jit,ir_ref ref)1560 static void jit_GC_ADDREF(zend_jit_ctx *jit, ir_ref ref)
1561 {
1562 ir_STORE(ref, ir_ADD_U32(ir_LOAD_U32(ref), ir_CONST_U32(1)));
1563 }
1564
jit_GC_ADDREF2(zend_jit_ctx * jit,ir_ref ref)1565 static void jit_GC_ADDREF2(zend_jit_ctx *jit, ir_ref ref)
1566 {
1567 ir_ref counter = ir_LOAD_U32(ref);
1568 ir_STORE(ref, ir_ADD_U32(counter, ir_CONST_U32(2)));
1569 }
1570
jit_GC_DELREF(zend_jit_ctx * jit,ir_ref ref)1571 static ir_ref jit_GC_DELREF(zend_jit_ctx *jit, ir_ref ref)
1572 {
1573 ir_ref counter = ir_LOAD_U32(ref);
1574 counter = ir_SUB_U32(counter, ir_CONST_U32(1));
1575 ir_STORE(ref, counter);
1576 return counter;
1577 }
1578
jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx * jit,ir_ref ref)1579 static ir_ref jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx *jit, ir_ref ref)
1580 {
1581 return ir_IF(
1582 ir_AND_U32(
1583 ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_refcounted, gc.u.type_info))),
1584 ir_CONST_U32(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))));
1585 }
1586
jit_ZVAL_COPY_CONST(zend_jit_ctx * jit,zend_jit_addr dst,uint32_t dst_info,uint32_t dst_def_info,zval * zv,bool addref)1587 static void jit_ZVAL_COPY_CONST(zend_jit_ctx *jit, zend_jit_addr dst, uint32_t dst_info, uint32_t dst_def_info, zval *zv, bool addref)
1588 {
1589 ir_ref ref = IR_UNUSED;
1590
1591 if (Z_TYPE_P(zv) > IS_TRUE) {
1592 if (Z_TYPE_P(zv) == IS_DOUBLE) {
1593 jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE(Z_DVAL_P(zv)));
1594 } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
1595 jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE((double)Z_LVAL_P(zv)));
1596 } else if (Z_TYPE_P(zv) == IS_LONG) {
1597 jit_set_Z_LVAL(jit, dst, ir_CONST_LONG(Z_LVAL_P(zv)));
1598 } else {
1599 ref = ir_CONST_ADDR(Z_PTR_P(zv));
1600 jit_set_Z_PTR(jit, dst, ref);
1601 if (addref && Z_REFCOUNTED_P(zv)) {
1602 jit_GC_ADDREF(jit, ref);
1603 }
1604 }
1605 }
1606 if (Z_MODE(dst) != IS_REG) {
1607 if (dst_def_info == MAY_BE_DOUBLE) {
1608 if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1609 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
1610 }
1611 } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
1612 jit_set_Z_TYPE_INFO(jit, dst, Z_TYPE_INFO_P(zv));
1613 }
1614 }
1615 }
1616
jit_if_TYPED_REF(zend_jit_ctx * jit,ir_ref ref)1617 static ir_ref jit_if_TYPED_REF(zend_jit_ctx *jit, ir_ref ref)
1618 {
1619 return ir_IF(ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr))));
1620 }
1621
jit_ZVAL_COPY(zend_jit_ctx * jit,zend_jit_addr dst,uint32_t dst_info,zend_jit_addr src,uint32_t src_info,bool addref)1622 static void jit_ZVAL_COPY(zend_jit_ctx *jit, zend_jit_addr dst, uint32_t dst_info, zend_jit_addr src, uint32_t src_info, bool addref)
1623 {
1624 ir_ref ref = IR_UNUSED;
1625
1626 if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1627 if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1628 jit_set_Z_LVAL(jit, dst, jit_Z_LVAL(jit, src));
1629 } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1630 jit_set_Z_DVAL(jit, dst, jit_Z_DVAL(jit, src));
1631 } else {
1632 #if SIZEOF_ZEND_LONG == 4
1633 if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1634 jit_set_Z_W2(jit, dst, jit_Z_W2(jit, src));
1635 }
1636 #endif
1637 ref = jit_Z_PTR(jit, src);
1638 jit_set_Z_PTR(jit, dst, ref);
1639 }
1640 }
1641 if (has_concrete_type(src_info & MAY_BE_ANY)
1642 && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1643 && !(src_info & MAY_BE_GUARD)) {
1644 if (Z_MODE(dst) != IS_REG
1645 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1646 uint8_t type = concrete_type(src_info);
1647 jit_set_Z_TYPE_INFO(jit, dst, type);
1648 }
1649 } else {
1650 ir_ref type = jit_Z_TYPE_INFO(jit, src);
1651 jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1652 if (addref) {
1653 if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1654 ir_ref if_refcounted = IR_UNUSED;
1655
1656 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1657 if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1658 ir_IF_TRUE(if_refcounted);
1659 }
1660
1661 jit_GC_ADDREF(jit, ref);
1662
1663 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1664 ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1665 }
1666 }
1667 }
1668 }
1669 }
1670
jit_ZVAL_COPY_2(zend_jit_ctx * jit,zend_jit_addr dst2,zend_jit_addr dst,uint32_t dst_info,zend_jit_addr src,uint32_t src_info,int addref)1671 static void jit_ZVAL_COPY_2(zend_jit_ctx *jit, zend_jit_addr dst2, zend_jit_addr dst, uint32_t dst_info, zend_jit_addr src, uint32_t src_info, int addref)
1672 {
1673 ir_ref ref = IR_UNUSED;
1674
1675 if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1676 if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1677 ref = jit_Z_LVAL(jit, src);
1678 jit_set_Z_LVAL(jit, dst, ref);
1679 jit_set_Z_LVAL(jit, dst2, ref);
1680 } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1681 ref = jit_Z_DVAL(jit, src);
1682 jit_set_Z_DVAL(jit, dst, ref);
1683 jit_set_Z_DVAL(jit, dst2, ref);
1684 } else {
1685 #if SIZEOF_ZEND_LONG == 4
1686 if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1687 ref = jit_Z_W2(jit, src);
1688 jit_set_Z_W2(jit, dst, ref);
1689 jit_set_Z_W2(jit, dst2, ref);
1690 }
1691 #endif
1692 ref = jit_Z_PTR(jit, src);
1693 jit_set_Z_PTR(jit, dst, ref);
1694 jit_set_Z_PTR(jit, dst2, ref);
1695 }
1696 }
1697 if (has_concrete_type(src_info & MAY_BE_ANY)
1698 && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1699 && !(src_info & MAY_BE_GUARD)) {
1700 uint8_t type = concrete_type(src_info);
1701 ir_ref type_ref = ir_CONST_U32(type);
1702
1703 if (Z_MODE(dst) != IS_REG
1704 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1705 jit_set_Z_TYPE_INFO_ex(jit, dst, type_ref);
1706 }
1707 if (Z_MODE(dst2) != IS_REG) {
1708 jit_set_Z_TYPE_INFO_ex(jit, dst2, type_ref);
1709 }
1710 } else {
1711 ir_ref type = jit_Z_TYPE_INFO(jit, src);
1712 jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1713 jit_set_Z_TYPE_INFO_ex(jit, dst2, type);
1714 if (addref) {
1715 if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1716 ir_ref if_refcounted = IR_UNUSED;
1717
1718 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1719 if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1720 ir_IF_TRUE(if_refcounted);
1721 }
1722
1723 if (addref == 2) {
1724 jit_GC_ADDREF2(jit, ref);
1725 } else {
1726 jit_GC_ADDREF(jit, ref);
1727 }
1728
1729 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1730 ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1731 }
1732 }
1733 }
1734 }
1735 }
1736
jit_ZVAL_DTOR(zend_jit_ctx * jit,ir_ref ref,uint32_t op_info,const zend_op * opline)1737 static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const zend_op *opline)
1738 {
1739 if (!((op_info) & MAY_BE_GUARD)
1740 && has_concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1741 uint8_t type = concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1742 if (type == IS_STRING && !ZEND_DEBUG) {
1743 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(_efree), ref);
1744 return;
1745 } else if (type == IS_ARRAY) {
1746 if ((op_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) {
1747 if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1748 jit_SET_EX_OPLINE(jit, opline);
1749 }
1750 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_array_destroy), ref);
1751 } else {
1752 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_array_free), ref);
1753 }
1754 return;
1755 } else if (type == IS_OBJECT) {
1756 if (opline) {
1757 jit_SET_EX_OPLINE(jit, opline);
1758 }
1759 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1760 return;
1761 }
1762 }
1763 if (opline) {
1764 jit_SET_EX_OPLINE(jit, opline);
1765 }
1766 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(rc_dtor_func), ref);
1767 }
1768
jit_ZVAL_PTR_DTOR(zend_jit_ctx * jit,zend_jit_addr addr,uint32_t op_info,bool gc,const zend_op * opline)1769 static void jit_ZVAL_PTR_DTOR(zend_jit_ctx *jit,
1770 zend_jit_addr addr,
1771 uint32_t op_info,
1772 bool gc,
1773 const zend_op *opline)
1774 {
1775 ir_ref ref, ref2;
1776 ir_ref if_refcounted = IR_UNUSED;
1777 ir_ref if_not_zero = IR_UNUSED;
1778 ir_ref end_inputs = IR_UNUSED;
1779
1780 if (op_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
1781 if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1782 if_refcounted = jit_if_REFCOUNTED(jit, addr);
1783 ir_IF_FALSE(if_refcounted);
1784 ir_END_list(end_inputs);
1785 ir_IF_TRUE(if_refcounted);
1786 }
1787 ref = jit_Z_PTR(jit, addr);
1788 ref2 = jit_GC_DELREF(jit, ref);
1789
1790 if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1791 if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1792 if_not_zero = ir_IF(ref2);
1793 ir_IF_FALSE(if_not_zero);
1794 }
1795 // zval_dtor_func(r);
1796 jit_ZVAL_DTOR(jit, ref, op_info, opline);
1797 if (if_not_zero) {
1798 ir_END_list(end_inputs);
1799 ir_IF_TRUE(if_not_zero);
1800 }
1801 }
1802 if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
1803 ir_ref if_may_not_leak;
1804
1805 if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1806 ir_ref if_ref, if_collectable;
1807
1808 if_ref = jit_if_Z_TYPE(jit, addr, IS_REFERENCE);
1809 ir_IF_TRUE(if_ref);
1810
1811 ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
1812
1813 if_collectable = jit_if_COLLECTABLE_ref(jit, ref2);
1814 ir_IF_FALSE(if_collectable);
1815 ir_END_list(end_inputs);
1816 ir_IF_TRUE(if_collectable);
1817
1818 ref2 = jit_Z_PTR_ref(jit, ref2);
1819
1820 ir_MERGE_WITH_EMPTY_FALSE(if_ref);
1821 ref = ir_PHI_2(IR_ADDR, ref2, ref);
1822 }
1823
1824 if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1825 ir_IF_TRUE(if_may_not_leak);
1826 ir_END_list(end_inputs);
1827 ir_IF_FALSE(if_may_not_leak);
1828
1829 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1830 }
1831
1832 if (end_inputs) {
1833 ir_END_list(end_inputs);
1834 ir_MERGE_list(end_inputs);
1835 }
1836 }
1837 }
1838
jit_FREE_OP(zend_jit_ctx * jit,uint8_t op_type,znode_op op,uint32_t op_info,const zend_op * opline)1839 static void jit_FREE_OP(zend_jit_ctx *jit,
1840 uint8_t op_type,
1841 znode_op op,
1842 uint32_t op_info,
1843 const zend_op *opline)
1844 {
1845 if (op_type & (IS_VAR|IS_TMP_VAR)) {
1846 jit_ZVAL_PTR_DTOR(jit,
1847 ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var),
1848 op_info, 0, opline);
1849 }
1850 }
1851
jit_OBJ_RELEASE(zend_jit_ctx * jit,ir_ref ref)1852 static void jit_OBJ_RELEASE(zend_jit_ctx *jit, ir_ref ref)
1853 {
1854 ir_ref end_inputs = IR_UNUSED;
1855 ir_ref if_not_zero, if_may_not_leak;
1856
1857 // JIT: if (GC_DELREF(obj) == 0) {
1858 if_not_zero = ir_IF(jit_GC_DELREF(jit, ref));
1859 ir_IF_FALSE(if_not_zero);
1860
1861 // JIT: zend_objects_store_del(obj)
1862 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1863 ir_END_list(end_inputs);
1864
1865 ir_IF_TRUE(if_not_zero);
1866 if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1867
1868 ir_IF_TRUE(if_may_not_leak);
1869 ir_END_list(end_inputs);
1870
1871 ir_IF_FALSE(if_may_not_leak);
1872 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1873 ir_END_list(end_inputs);
1874
1875 ir_MERGE_list(end_inputs);
1876 }
1877
zend_jit_check_timeout(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr)1878 static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
1879 {
1880 ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
1881
1882 if (exit_addr) {
1883 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1884 } else if (!opline || jit->last_valid_opline == opline) {
1885 ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1886 } else {
1887 ir_ref if_timeout = ir_IF(ref);
1888
1889 ir_IF_TRUE_cold(if_timeout);
1890 jit_LOAD_IP_ADDR(jit, opline);
1891 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1892 ir_IF_FALSE(if_timeout);
1893 }
1894 }
1895
1896 /* stubs */
1897
zend_jit_exception_handler_stub(zend_jit_ctx * jit)1898 static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
1899 {
1900 const void *handler;
1901
1902 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1903 handler = zend_get_opcode_handler_func(EG(exception_op));
1904
1905 ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
1906 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
1907 } else {
1908 handler = EG(exception_op)->handler;
1909
1910 if (GCC_GLOBAL_REGS) {
1911 ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
1912 } else {
1913 ir_ref ref, if_negative;
1914
1915 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), jit_FP(jit));
1916 if_negative = ir_IF(ir_LT(ref, ir_CONST_U32(0)));
1917 ir_IF_TRUE(if_negative);
1918 ir_MERGE_WITH_EMPTY_FALSE(if_negative);
1919 ref = ir_PHI_2(IR_I32, ref, ir_CONST_I32(1));
1920 ir_RETURN(ref);
1921 }
1922 }
1923 return 1;
1924 }
1925
zend_jit_exception_handler_undef_stub(zend_jit_ctx * jit)1926 static int zend_jit_exception_handler_undef_stub(zend_jit_ctx *jit)
1927 {
1928 ir_ref ref, result_type, if_result_used;
1929
1930 ref = jit_EG(opline_before_exception);
1931 result_type = ir_LOAD_U8(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result_type)));
1932
1933 if_result_used = ir_IF(ir_AND_U8(result_type, ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1934 ir_IF_TRUE(if_result_used);
1935
1936 ref = ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result.var)));
1937 if (sizeof(void*) == 8) {
1938 ref = ir_ZEXT_A(ref);
1939 }
1940 ir_STORE(ir_ADD_OFFSET(ir_ADD_A(jit_FP(jit), ref), offsetof(zval, u1.type_info)), ir_CONST_U32(IS_UNDEF));
1941 ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
1942
1943 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
1944
1945 return 1;
1946 }
1947
zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx * jit)1948 static int zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx *jit)
1949 {
1950 ir_ref ref, if_dtor;
1951 zend_jit_addr var_addr;
1952
1953 ref = ir_LOAD_A(jit_EG(opline_before_exception));
1954 if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op1_type))),
1955 ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1956 ir_IF_TRUE(if_dtor);
1957 ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op1.var)));
1958 if (sizeof(void*) == 8) {
1959 ref = ir_ZEXT_A(ref);
1960 }
1961 ref = ir_ADD_A(jit_FP(jit), ref);
1962 var_addr = ZEND_ADDR_REF_ZVAL(ref);
1963 jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
1964 ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
1965
1966 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
1967
1968 return 1;
1969 }
1970
zend_jit_exception_handler_free_op2_stub(zend_jit_ctx * jit)1971 static int zend_jit_exception_handler_free_op2_stub(zend_jit_ctx *jit)
1972 {
1973 ir_ref ref, if_dtor;
1974 zend_jit_addr var_addr;
1975
1976 ref = ir_LOAD_A(jit_EG(opline_before_exception));
1977 if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op2_type))),
1978 ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1979 ir_IF_TRUE(if_dtor);
1980 ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.var)));
1981 if (sizeof(void*) == 8) {
1982 ref = ir_ZEXT_A(ref);
1983 }
1984 ref = ir_ADD_A(jit_FP(jit), ref);
1985 var_addr = ZEND_ADDR_REF_ZVAL(ref);
1986 jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
1987 ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
1988
1989 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
1990
1991 return 1;
1992 }
1993
zend_jit_interrupt_handler_stub(zend_jit_ctx * jit)1994 static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit)
1995 {
1996 ir_ref if_timeout, if_exception;
1997
1998 if (GCC_GLOBAL_REGS) {
1999 // EX(opline) = opline
2000 ir_STORE(jit_EX(opline), jit_IP(jit));
2001 }
2002
2003 ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0));
2004 if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0)));
2005 ir_IF_FALSE(if_timeout);
2006 ir_CALL(IR_VOID, ir_CONST_FUNC(zend_timeout));
2007 ir_MERGE_WITH_EMPTY_TRUE(if_timeout);
2008
2009 if (zend_interrupt_function) {
2010 ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_interrupt_function), jit_FP(jit));
2011 if_exception = ir_IF(ir_LOAD_A(jit_EG(exception)));
2012 ir_IF_TRUE(if_exception);
2013 ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper));
2014 ir_MERGE_WITH_EMPTY_FALSE(if_exception);
2015
2016 jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
2017 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2018 }
2019
2020 if (GCC_GLOBAL_REGS) {
2021 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2022 } else {
2023 ir_RETURN(ir_CONST_I32(1));
2024 }
2025 return 1;
2026 }
2027
zend_jit_leave_function_handler_stub(zend_jit_ctx * jit)2028 static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit)
2029 {
2030 ir_ref call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
2031 ir_ref if_top = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_TOP)));
2032
2033 ir_IF_FALSE(if_top);
2034
2035 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2036 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2037 jit_STORE_IP(jit,
2038 ir_LOAD_A(jit_EX(opline)));
2039 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2040 } else if (GCC_GLOBAL_REGS) {
2041 ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2042 } else {
2043 ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info, jit_FP(jit));
2044 }
2045
2046 ir_IF_TRUE(if_top);
2047
2048 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2049 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2050 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2051 } else if (GCC_GLOBAL_REGS) {
2052 ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2053 } else {
2054 ir_TAILCALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info, jit_FP(jit));
2055 }
2056
2057 return 1;
2058 }
2059
zend_jit_negative_shift_stub(zend_jit_ctx * jit)2060 static int zend_jit_negative_shift_stub(zend_jit_ctx *jit)
2061 {
2062 ir_CALL_2(IR_VOID,
2063 ir_CONST_FUNC_PROTO(zend_throw_error,
2064 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2065 ir_CONST_ADDR(zend_ce_arithmetic_error),
2066 ir_CONST_ADDR("Bit shift by negative number"));
2067 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2068 return 1;
2069 }
2070
zend_jit_mod_by_zero_stub(zend_jit_ctx * jit)2071 static int zend_jit_mod_by_zero_stub(zend_jit_ctx *jit)
2072 {
2073 ir_CALL_2(IR_VOID,
2074 ir_CONST_FUNC_PROTO(zend_throw_error,
2075 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2076 ir_CONST_ADDR(zend_ce_division_by_zero_error),
2077 ir_CONST_ADDR("Modulo by zero"));
2078 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2079 return 1;
2080 }
2081
zend_jit_invalid_this_stub(zend_jit_ctx * jit)2082 static int zend_jit_invalid_this_stub(zend_jit_ctx *jit)
2083 {
2084 ir_CALL_2(IR_VOID,
2085 ir_CONST_FUNC_PROTO(zend_throw_error,
2086 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2087 IR_NULL,
2088 ir_CONST_ADDR("Using $this when not in object context"));
2089 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2090 return 1;
2091 }
2092
zend_jit_undefined_function_stub(zend_jit_ctx * jit)2093 static int zend_jit_undefined_function_stub(zend_jit_ctx *jit)
2094 {
2095 // JIT: load EX(opline)
2096 ir_ref ref = ir_LOAD_A(jit_FP(jit));
2097 ir_ref arg3 = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.constant)));
2098
2099 if (sizeof(void*) == 8) {
2100 arg3 = ir_LOAD_A(ir_ADD_A(ref, ir_SEXT_A(arg3)));
2101 } else {
2102 arg3 = ir_LOAD_A(arg3);
2103 }
2104 arg3 = ir_ADD_OFFSET(arg3, offsetof(zend_string, val));
2105
2106 ir_CALL_3(IR_VOID,
2107 ir_CONST_FUNC_PROTO(zend_throw_error,
2108 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2109 IR_NULL,
2110 ir_CONST_ADDR("Call to undefined function %s()"),
2111 arg3);
2112
2113 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2114
2115 return 1;
2116 }
2117
zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx * jit)2118 static int zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx *jit)
2119 {
2120 ir_ref opline, ref, rx, if_eq, if_tmp;
2121
2122 // JIT: opline = EX(opline)
2123 opline = ir_LOAD_A(jit_FP(jit));
2124
2125 // JIT: ZVAL_UNDEF(ZEND_CALL_VAR(RX, opline->result.var))
2126 ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2127 if (sizeof(void*) == 8) {
2128 ref = ir_ZEXT_A(ref);
2129 }
2130 rx = jit_IP(jit);
2131 jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(rx, ref), ir_CONST_U32(IS_UNDEF));
2132
2133 // last EX(call) frame may be delayed
2134 // JIT: if (EX(call) == RX)
2135 ref = ir_LOAD_A(jit_EX(call));
2136 if_eq = ir_IF(ir_EQ(rx, ref));
2137 ir_IF_FALSE(if_eq);
2138
2139 // JIT: RX->prev_execute_data == EX(call)
2140 ir_STORE(jit_CALL(rx, prev_execute_data), ref);
2141
2142 // JIT: EX(call) = RX
2143 ir_STORE(jit_EX(call), rx);
2144 ir_MERGE_WITH_EMPTY_TRUE(if_eq);
2145
2146 // JIT: IP = opline
2147 jit_STORE_IP(jit, opline);
2148
2149 // JIT: zend_cannot_pass_by_reference(opline->op2.num)
2150 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_cannot_pass_by_reference),
2151 ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.num))));
2152
2153 // JIT: if (IP->op1_type == IS_TMP_VAR)
2154 ref = ir_LOAD_U8(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1_type)));
2155 if_tmp = ir_IF(ir_EQ(ref, ir_CONST_U8(IS_TMP_VAR)));
2156 ir_IF_TRUE(if_tmp);
2157
2158 // JIT: zval_ptr_dtor(EX_VAR(IP->op1.var))
2159 ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1.var)));
2160 if (sizeof(void*) == 8) {
2161 ref = ir_ZEXT_A(ref);
2162 }
2163 ref = ir_ADD_A(jit_FP(jit), ref);
2164 jit_ZVAL_PTR_DTOR(jit,
2165 ZEND_ADDR_REF_ZVAL(ref),
2166 MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
2167 ir_MERGE_WITH_EMPTY_FALSE(if_tmp);
2168
2169 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2170
2171 return 1;
2172 }
2173
zend_jit_icall_throw_stub(zend_jit_ctx * jit)2174 static int zend_jit_icall_throw_stub(zend_jit_ctx *jit)
2175 {
2176 ir_ref ip, if_set;
2177
2178 // JIT: zend_rethrow_exception(zend_execute_data *execute_data)
2179 // JIT: if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
2180 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2181 ip = jit_IP(jit);
2182 if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2183 ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2184 ir_IF_FALSE(if_set);
2185
2186 // JIT: EG(opline_before_exception) = opline;
2187 ir_STORE(jit_EG(opline_before_exception), ip);
2188 ir_MERGE_WITH_EMPTY_TRUE(if_set);
2189
2190 // JIT: opline = EG(exception_op);
2191 jit_STORE_IP(jit, jit_EG(exception_op));
2192
2193 if (GCC_GLOBAL_REGS) {
2194 ir_STORE(jit_EX(opline), jit_IP(jit));
2195 }
2196
2197 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2198
2199 return 1;
2200 }
2201
zend_jit_leave_throw_stub(zend_jit_ctx * jit)2202 static int zend_jit_leave_throw_stub(zend_jit_ctx *jit)
2203 {
2204 ir_ref ip, if_set;
2205
2206 // JIT: if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
2207 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2208 ip = jit_IP(jit);
2209 if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2210 ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2211 ir_IF_FALSE(if_set);
2212
2213 // JIT: EG(opline_before_exception) = opline;
2214 ir_STORE(jit_EG(opline_before_exception), ip);
2215 ir_MERGE_WITH_EMPTY_TRUE(if_set);
2216
2217 // JIT: opline = EG(exception_op);
2218 jit_LOAD_IP(jit, jit_EG(exception_op));
2219
2220 if (GCC_GLOBAL_REGS) {
2221 ir_STORE(jit_EX(opline), jit_IP(jit));
2222
2223 // JIT: HANDLE_EXCEPTION()
2224 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2225 } else {
2226 ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
2227 }
2228
2229 return 1;
2230 }
2231
zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx * jit)2232 static int zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx *jit)
2233 {
2234 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2235 return 0;
2236 }
2237
2238 ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_runtime_jit));
2239 ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2240 return 1;
2241 }
2242
zend_jit_hybrid_profile_jit_stub(zend_jit_ctx * jit)2243 static int zend_jit_hybrid_profile_jit_stub(zend_jit_ctx *jit)
2244 {
2245 ir_ref addr, func, run_time_cache, jit_extension;
2246
2247 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2248 return 0;
2249 }
2250
2251 addr = ir_CONST_ADDR(&zend_jit_profile_counter),
2252 ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2253
2254 func = ir_LOAD_A(jit_EX(func));
2255 run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
2256 jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2257
2258 if (zend_jit_profile_counter_rid) {
2259 addr = ir_ADD_OFFSET(run_time_cache, zend_jit_profile_counter_rid * sizeof(void*));
2260 } else {
2261 addr = run_time_cache;
2262 }
2263 ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2264
2265 addr = ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_extension, orig_handler));
2266 ir_IJMP(ir_LOAD_A(addr));
2267
2268 return 1;
2269 }
2270
_zend_jit_hybrid_hot_counter_stub(zend_jit_ctx * jit,uint32_t cost)2271 static int _zend_jit_hybrid_hot_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2272 {
2273 ir_ref func, jit_extension, addr, ref, if_overflow;
2274
2275 func = ir_LOAD_A(jit_EX(func));
2276 jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2277 addr = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, counter)));
2278 ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2279 ir_STORE(addr, ref);
2280 if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2281
2282 ir_IF_TRUE_cold(if_overflow);
2283 ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2284 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_hot_func),
2285 jit_FP(jit),
2286 jit_IP(jit));
2287 ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2288
2289 ir_IF_FALSE(if_overflow);
2290 ref = ir_SUB_A(jit_IP(jit),
2291 ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, opcodes))));
2292 ref = ir_DIV_A(ref, ir_CONST_ADDR(sizeof(zend_op) / sizeof(void*)));
2293
2294 addr = ir_ADD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, orig_handlers)),
2295 ref);
2296 ir_IJMP(ir_LOAD_A(addr));
2297
2298 return 1;
2299 }
2300
zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx * jit)2301 static int zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx *jit)
2302 {
2303 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2304 return 0;
2305 }
2306
2307 return _zend_jit_hybrid_hot_counter_stub(jit,
2308 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2309 }
2310
zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx * jit)2311 static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit)
2312 {
2313 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2314 return 0;
2315 }
2316
2317 return _zend_jit_hybrid_hot_counter_stub(jit,
2318 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2319 }
2320
_zend_jit_orig_opline_handler(zend_jit_ctx * jit,ir_ref offset)2321 static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset)
2322 {
2323 ir_ref addr;
2324
2325 if (GCC_GLOBAL_REGS) {
2326 addr = ir_ADD_A(offset, jit_IP(jit));
2327 } else {
2328 addr = ir_ADD_A(offset, ir_LOAD_A(jit_EX(opline)));
2329 }
2330
2331 return ir_LOAD_A(addr);
2332 }
2333
zend_jit_orig_opline_handler(zend_jit_ctx * jit)2334 static ir_ref zend_jit_orig_opline_handler(zend_jit_ctx *jit)
2335 {
2336 ir_ref func, jit_extension, offset;
2337
2338 func = ir_LOAD_A(jit_EX(func));
2339 jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2340 offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2341 return _zend_jit_orig_opline_handler(jit, offset);
2342 }
2343
_zend_jit_hybrid_trace_counter_stub(zend_jit_ctx * jit,uint32_t cost)2344 static int _zend_jit_hybrid_trace_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2345 {
2346 ir_ref func, jit_extension, offset, addr, ref, if_overflow, ret, if_halt;
2347
2348 func = ir_LOAD_A(jit_EX(func));
2349 jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2350 offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2351 addr = ir_LOAD_A(ir_ADD_OFFSET(ir_ADD_A(offset, jit_IP(jit)), offsetof(zend_op_trace_info, counter)));
2352 ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2353 ir_STORE(addr, ref);
2354 if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2355
2356 ir_IF_TRUE_cold(if_overflow);
2357 ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2358 ret = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_trace_hot_root),
2359 jit_FP(jit),
2360 jit_IP(jit));
2361 if_halt = ir_IF(ir_LT(ret, ir_CONST_I32(0)));
2362 ir_IF_FALSE(if_halt);
2363
2364 ref = jit_EG(current_execute_data);
2365 jit_STORE_FP(jit, ir_LOAD_A(ref));
2366 ref = ir_LOAD_A(jit_EX(opline));
2367 jit_STORE_IP(jit, ref);
2368 ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2369
2370 ir_IF_FALSE(if_overflow);
2371 ir_IJMP(_zend_jit_orig_opline_handler(jit, offset));
2372
2373 ir_IF_TRUE(if_halt);
2374 ir_IJMP(ir_CONST_FC_FUNC(zend_jit_halt_op->handler));
2375
2376 return 1;
2377 }
2378
zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx * jit)2379 static int zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx *jit)
2380 {
2381 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2382 return 0;
2383 }
2384
2385 return _zend_jit_hybrid_trace_counter_stub(jit,
2386 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2387 }
2388
zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx * jit)2389 static int zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx *jit)
2390 {
2391 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2392 return 0;
2393 }
2394
2395 return _zend_jit_hybrid_trace_counter_stub(jit,
2396 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2397 }
2398
zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx * jit)2399 static int zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx *jit)
2400 {
2401 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2402 return 0;
2403 }
2404
2405 return _zend_jit_hybrid_trace_counter_stub(jit,
2406 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2407 }
2408
zend_jit_trace_halt_stub(zend_jit_ctx * jit)2409 static int zend_jit_trace_halt_stub(zend_jit_ctx *jit)
2410 {
2411 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2412 ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_halt_op->handler));
2413 } else if (GCC_GLOBAL_REGS) {
2414 jit_STORE_IP(jit, IR_NULL);
2415 ir_RETURN(IR_VOID);
2416 } else {
2417 ir_RETURN(ir_CONST_I32(-1)); // ZEND_VM_RETURN
2418 }
2419 return 1;
2420 }
2421
zend_jit_trace_escape_stub(zend_jit_ctx * jit)2422 static int zend_jit_trace_escape_stub(zend_jit_ctx *jit)
2423 {
2424 if (GCC_GLOBAL_REGS) {
2425 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2426 } else {
2427 ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2428 }
2429
2430 return 1;
2431 }
2432
zend_jit_trace_exit_stub(zend_jit_ctx * jit)2433 static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
2434 {
2435 ir_ref ref, ret, if_zero, addr;
2436
2437 if (GCC_GLOBAL_REGS) {
2438 // EX(opline) = opline
2439 ir_STORE(jit_EX(opline), jit_IP(jit));
2440 }
2441
2442 ret = ir_EXITCALL(ir_CONST_FC_FUNC(zend_jit_trace_exit));
2443
2444 if_zero = ir_IF(ir_EQ(ret, ir_CONST_I32(0)));
2445
2446 ir_IF_TRUE(if_zero);
2447
2448 if (GCC_GLOBAL_REGS) {
2449 ref = jit_EG(current_execute_data);
2450 jit_STORE_FP(jit, ir_LOAD_A(ref));
2451 ref = ir_LOAD_A(jit_EX(opline));
2452 jit_STORE_IP(jit, ref);
2453 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2454 } else {
2455 ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2456 }
2457
2458 ir_IF_FALSE(if_zero);
2459
2460 ir_GUARD(ir_GE(ret, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2461
2462 ref = jit_EG(current_execute_data);
2463 jit_STORE_FP(jit, ir_LOAD_A(ref));
2464
2465 if (GCC_GLOBAL_REGS) {
2466 ref = ir_LOAD_A(jit_EX(opline));
2467 jit_STORE_IP(jit, ref);
2468 }
2469
2470 // check for interrupt (try to avoid this ???)
2471 zend_jit_check_timeout(jit, NULL, NULL);
2472
2473 addr = zend_jit_orig_opline_handler(jit);
2474 if (GCC_GLOBAL_REGS) {
2475 ir_TAILCALL(IR_VOID, addr);
2476 } else {
2477 #if defined(IR_TARGET_X86)
2478 addr = ir_CAST_FC_FUNC(addr);
2479 #endif
2480 ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
2481 ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2482 ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2483 }
2484
2485 return 1;
2486 }
2487
zend_jit_undefined_offset_stub(zend_jit_ctx * jit)2488 static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit)
2489 {
2490 if (GCC_GLOBAL_REGS) {
2491 ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key));
2492 } else {
2493 ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit));
2494 }
2495
2496 return 1;
2497 }
2498
zend_jit_undefined_key_stub(zend_jit_ctx * jit)2499 static int zend_jit_undefined_key_stub(zend_jit_ctx *jit)
2500 {
2501 if (GCC_GLOBAL_REGS) {
2502 ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key));
2503 } else {
2504 ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit));
2505 }
2506
2507 return 1;
2508 }
2509
zend_jit_cannot_add_element_stub(zend_jit_ctx * jit)2510 static int zend_jit_cannot_add_element_stub(zend_jit_ctx *jit)
2511 {
2512 ir_ref opline = ir_LOAD_A(jit_EX(opline));
2513 ir_ref ref, if_result_used;
2514
2515 if_result_used = ir_IF(ir_AND_U8(
2516 ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, result_type))),
2517 ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2518 ir_IF_TRUE(if_result_used);
2519
2520 ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2521 if (sizeof(void*) == 8) {
2522 ref = ir_ZEXT_A(ref);
2523 }
2524 jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_UNDEF));
2525 ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2526
2527 ir_CALL_2(IR_VOID,
2528 ir_CONST_FUNC_PROTO(zend_throw_error,
2529 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2530 IR_NULL,
2531 ir_CONST_ADDR("Cannot add element to the array as the next element is already occupied"));
2532 ir_RETURN(IR_VOID);
2533
2534 return 1;
2535 }
2536
zend_jit_assign_const_stub(zend_jit_ctx * jit)2537 static int zend_jit_assign_const_stub(zend_jit_ctx *jit)
2538 {
2539 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2540 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2541
2542 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2543 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2544 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2545
2546 if (!zend_jit_assign_to_variable(
2547 jit, NULL,
2548 var_addr, var_addr, -1, -1,
2549 IS_CONST, val_addr, val_info,
2550 0, 0, 0)) {
2551 return 0;
2552 }
2553 ir_RETURN(IR_VOID);
2554 return 1;
2555 }
2556
zend_jit_assign_tmp_stub(zend_jit_ctx * jit)2557 static int zend_jit_assign_tmp_stub(zend_jit_ctx *jit)
2558 {
2559 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2560 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2561
2562 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2563 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2564 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2565
2566 if (!zend_jit_assign_to_variable(
2567 jit, NULL,
2568 var_addr, var_addr, -1, -1,
2569 IS_TMP_VAR, val_addr, val_info,
2570 0, 0, 0)) {
2571 return 0;
2572 }
2573 ir_RETURN(IR_VOID);
2574 return 1;
2575 }
2576
zend_jit_assign_var_stub(zend_jit_ctx * jit)2577 static int zend_jit_assign_var_stub(zend_jit_ctx *jit)
2578 {
2579 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2580 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2581
2582 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2583 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2584 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2585
2586 if (!zend_jit_assign_to_variable(
2587 jit, NULL,
2588 var_addr, var_addr, -1, -1,
2589 IS_VAR, val_addr, val_info,
2590 0, 0, 0)) {
2591 return 0;
2592 }
2593 ir_RETURN(IR_VOID);
2594 return 1;
2595 }
2596
zend_jit_assign_cv_noref_stub(zend_jit_ctx * jit)2597 static int zend_jit_assign_cv_noref_stub(zend_jit_ctx *jit)
2598 {
2599 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2600 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2601
2602 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2603 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2604 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2605
2606 if (!zend_jit_assign_to_variable(
2607 jit, NULL,
2608 var_addr, var_addr, -1, -1,
2609 IS_CV, val_addr, val_info,
2610 0, 0, 0)) {
2611 return 0;
2612 }
2613 ir_RETURN(IR_VOID);
2614 return 1;
2615 }
2616
zend_jit_new_array_stub(zend_jit_ctx * jit)2617 static int zend_jit_new_array_stub(zend_jit_ctx *jit)
2618 {
2619 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2620 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2621 ir_ref ref = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_zend_new_array_0));
2622
2623 jit_set_Z_PTR(jit, var_addr, ref);
2624 jit_set_Z_TYPE_INFO(jit, var_addr, IS_ARRAY_EX);
2625 ir_RETURN(ref);
2626 return 1;
2627 }
2628
zend_jit_assign_cv_stub(zend_jit_ctx * jit)2629 static int zend_jit_assign_cv_stub(zend_jit_ctx *jit)
2630 {
2631 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2632 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2633
2634 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2635 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2636 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2637
2638 if (!zend_jit_assign_to_variable(
2639 jit, NULL,
2640 var_addr, var_addr, -1, -1,
2641 IS_CV, val_addr, val_info,
2642 0, 0, 0)) {
2643 return 0;
2644 }
2645 ir_RETURN(IR_VOID);
2646 return 1;
2647 }
2648
zend_jit_init_ctx(zend_jit_ctx * jit,uint32_t flags)2649 static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2650 {
2651 #if defined (__CET__) && (__CET__ & 1) != 0
2652 flags |= IR_GEN_ENDBR;
2653 #endif
2654 flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
2655
2656 ir_init(&jit->ctx, flags, 256, 1024);
2657 jit->ctx.ret_type = -1;
2658
2659 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2660 jit->ctx.mflags |= default_mflags;
2661 if (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX) {
2662 jit->ctx.mflags |= IR_X86_AVX;
2663 }
2664 #elif defined(IR_TARGET_AARCH64)
2665 jit->ctx.get_veneer = zend_jit_get_veneer;
2666 jit->ctx.set_veneer = zend_jit_set_veneer;
2667 #endif
2668
2669 jit->ctx.fixed_regset = (1<<ZREG_FP) | (1<<ZREG_IP);
2670 if (!(flags & IR_FUNCTION)) {
2671 jit->ctx.flags |= IR_NO_STACK_COMBINE;
2672 if (zend_jit_vm_kind == ZEND_VM_KIND_CALL) {
2673 jit->ctx.flags |= IR_FUNCTION;
2674 /* Stack must be 16 byte aligned */
2675 /* TODO: select stack size ??? */
2676 #if defined(IR_TARGET_AARCH64)
2677 jit->ctx.flags |= IR_USE_FRAME_POINTER;
2678 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 16; /* 10 saved registers and 6 spill slots (8 bytes) */
2679 #elif defined(_WIN64)
2680 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 8 saved registers and 3 spill slots (8 bytes) */
2681 #elif defined(IR_TARGET_X86_64)
2682 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 9; /* 6 saved registers and 3 spill slots (8 bytes) */
2683 #else /* IR_TARGET_x86 */
2684 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */
2685 #endif
2686 if (GCC_GLOBAL_REGS) {
2687 jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<<ZREG_FP) | (1<<ZREG_IP));
2688 } else {
2689 jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED;
2690 //#ifdef _WIN64
2691 // jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
2692 //#endif
2693 }
2694 jit->ctx.fixed_call_stack_size = 16;
2695 } else {
2696 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2697 jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
2698 if (jit->ctx.fixed_stack_red_zone > 16) {
2699 jit->ctx.fixed_stack_frame_size = jit->ctx.fixed_stack_red_zone - 16;
2700 jit->ctx.fixed_call_stack_size = 16;
2701 }
2702 jit->ctx.flags |= IR_MERGE_EMPTY_ENTRIES;
2703 #else
2704 jit->ctx.fixed_stack_red_zone = 0;
2705 jit->ctx.fixed_stack_frame_size = 32; /* 4 spill slots (8 bytes) or 8 spill slots (4 bytes) */
2706 jit->ctx.fixed_call_stack_size = 16;
2707 #endif
2708 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2709 jit->ctx.fixed_regset |= (1<<IR_REG_FP); /* prevent %rbp (%r5) usage */
2710 #endif
2711 }
2712 }
2713
2714 jit->ctx.snapshot_create = (ir_snapshot_create_t)jit_SNAPSHOT;
2715
2716 jit->op_array = NULL;
2717 jit->current_op_array = NULL;
2718 jit->ssa = NULL;
2719 jit->name = NULL;
2720 jit->last_valid_opline = NULL;
2721 jit->use_last_valid_opline = 0;
2722 jit->track_last_valid_opline = 0;
2723 jit->reuse_ip = 0;
2724 jit->delayed_call_level = 0;
2725 delayed_call_chain = 0;
2726 jit->b = -1;
2727 #ifdef ZTS
2728 jit->tls = IR_UNUSED;
2729 #endif
2730 jit->fp = IR_UNUSED;
2731 jit->trace_loop_ref = IR_UNUSED;
2732 jit->return_inputs = IR_UNUSED;
2733 jit->bb_start_ref = NULL;
2734 jit->bb_predecessors = NULL;
2735 jit->bb_edges = NULL;
2736 jit->trace = NULL;
2737 jit->ra = NULL;
2738 jit->delay_var = -1;
2739 jit->delay_refs = NULL;
2740 jit->eg_exception_addr = 0;
2741 zend_hash_init(&jit->addr_hash, 64, NULL, NULL, 0);
2742 memset(jit->stub_addr, 0, sizeof(jit->stub_addr));
2743
2744 ir_START();
2745 }
2746
zend_jit_free_ctx(zend_jit_ctx * jit)2747 static int zend_jit_free_ctx(zend_jit_ctx *jit)
2748 {
2749 if (jit->name) {
2750 zend_string_release(jit->name);
2751 }
2752 zend_hash_destroy(&jit->addr_hash);
2753 ir_free(&jit->ctx);
2754 return 1;
2755 }
2756
zend_jit_ir_compile(ir_ctx * ctx,size_t * size,const char * name)2757 static void *zend_jit_ir_compile(ir_ctx *ctx, size_t *size, const char *name)
2758 {
2759 void *entry;
2760 ir_code_buffer code_buffer;
2761
2762 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_SRC) {
2763 if (name) fprintf(stderr, "%s: ; after folding\n", name);
2764 ir_save(ctx, 0, stderr);
2765 }
2766
2767 #if ZEND_DEBUG
2768 ir_check(ctx);
2769 #endif
2770
2771 ir_build_def_use_lists(ctx);
2772
2773 #if ZEND_DEBUG
2774 ir_check(ctx);
2775 #endif
2776
2777 #if 1
2778 ir_sccp(ctx);
2779 #endif
2780
2781 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCCP) {
2782 if (name) fprintf(stderr, "%s: ; after SCCP\n", name);
2783 ir_save(ctx, 0, stderr);
2784 }
2785
2786 ir_build_cfg(ctx);
2787 ir_build_dominators_tree(ctx);
2788 ir_find_loops(ctx);
2789
2790 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_CFG) {
2791 if (name) fprintf(stderr, "%s: ; after CFG\n", name);
2792 ir_save(ctx, IR_SAVE_CFG, stderr);
2793 }
2794
2795 ir_gcm(ctx);
2796
2797 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_GCM) {
2798 if (name) fprintf(stderr, "%s: ; after GCM\n", name);
2799 ir_save(ctx, IR_SAVE_CFG|IR_SAVE_CFG_MAP, stderr);
2800 }
2801
2802 ir_schedule(ctx);
2803
2804 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE) {
2805 if (name) fprintf(stderr, "%s: ; after schedule\n", name);
2806 ir_save(ctx, IR_SAVE_CFG, stderr);
2807 }
2808
2809 ir_match(ctx);
2810 #if !defined(IR_TARGET_AARCH64)
2811 ctx->flags &= ~IR_USE_FRAME_POINTER; /* don't use FRAME_POINTER even with ALLOCA, TODO: cleanup this ??? */
2812 #endif
2813 ir_assign_virtual_registers(ctx);
2814 ir_compute_live_ranges(ctx);
2815 ir_coalesce(ctx);
2816 ir_reg_alloc(ctx);
2817
2818 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_REGS) {
2819 if (name) fprintf(stderr, "%s: ; after register allocation\n", name);
2820 ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2821 ir_dump_live_ranges(ctx, stderr);
2822 }
2823
2824 ir_schedule_blocks(ctx);
2825
2826 if (JIT_G(debug) & (ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
2827 if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_CODEGEN) {
2828 if (name) fprintf(stderr, "%s: ; codegen\n", name);
2829 ir_dump_codegen(ctx, stderr);
2830 } else {
2831 if (name) fprintf(stderr, "%s: ; final\n", name);
2832 ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2833 }
2834 }
2835
2836 #if ZEND_DEBUG
2837 ir_check(ctx);
2838 #endif
2839
2840 code_buffer.start = dasm_buf;
2841 code_buffer.end = dasm_end;
2842 code_buffer.pos = *dasm_ptr;
2843 ctx->code_buffer = &code_buffer;
2844
2845 entry = ir_emit_code(ctx, size);
2846
2847 *dasm_ptr = code_buffer.pos;
2848
2849 #if defined(IR_TARGET_AARCH64)
2850 if (ctx->flags2 & IR_HAS_VENEERS) {
2851 zend_jit_commit_veneers();
2852 }
2853 #endif
2854
2855 return entry;
2856 }
2857
zend_jit_setup_stubs(void)2858 static void zend_jit_setup_stubs(void)
2859 {
2860 zend_jit_ctx jit;
2861 void *entry;
2862 size_t size;
2863 uint32_t i;
2864
2865 for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
2866 zend_jit_init_ctx(&jit, zend_jit_stubs[i].flags);
2867
2868 if (!zend_jit_stubs[i].stub(&jit)) {
2869 zend_jit_free_ctx(&jit);
2870 zend_jit_stub_handlers[i] = NULL;
2871 continue;
2872 }
2873
2874 entry = zend_jit_ir_compile(&jit.ctx, &size, zend_jit_stubs[i].name);
2875 if (!entry) {
2876 zend_jit_free_ctx(&jit);
2877 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile stub");
2878 }
2879
2880 zend_jit_stub_handlers[i] = entry;
2881
2882 if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2883 #ifdef HAVE_CAPSTONE
2884 if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
2885 ir_disasm_add_symbol(zend_jit_stubs[i].name, (uintptr_t)entry, size);
2886 }
2887 if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_STUBS) {
2888 ir_disasm(zend_jit_stubs[i].name,
2889 entry, size, (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0, &jit.ctx, stderr);
2890 }
2891 #endif
2892 #ifndef _WIN32
2893 if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
2894 // ir_mem_unprotect(entry, size);
2895 ir_gdb_register(zend_jit_stubs[i].name, entry, size, 0, 0);
2896 // ir_mem_protect(entry, size);
2897 }
2898
2899 if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2900 ir_perf_map_register(zend_jit_stubs[i].name, entry, size);
2901 if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
2902 ir_perf_jitdump_register(zend_jit_stubs[i].name, entry, size);
2903 }
2904 }
2905 #endif
2906 }
2907 zend_jit_free_ctx(&jit);
2908 }
2909 }
2910
2911 #define REGISTER_HELPER(n) \
2912 ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)n, sizeof(void*));
2913 #define REGISTER_DATA(n) \
2914 ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)&n, sizeof(n));
2915
zend_jit_setup_disasm(void)2916 static void zend_jit_setup_disasm(void)
2917 {
2918 #ifdef HAVE_CAPSTONE
2919 ir_disasm_init();
2920
2921 if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
2922 zend_op opline;
2923
2924 memset(&opline, 0, sizeof(opline));
2925
2926 opline.opcode = ZEND_DO_UCALL;
2927 opline.result_type = IS_UNUSED;
2928 zend_vm_set_opcode_handler(&opline);
2929 ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2930
2931 opline.opcode = ZEND_DO_UCALL;
2932 opline.result_type = IS_VAR;
2933 zend_vm_set_opcode_handler(&opline);
2934 ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2935
2936 opline.opcode = ZEND_DO_FCALL_BY_NAME;
2937 opline.result_type = IS_UNUSED;
2938 zend_vm_set_opcode_handler(&opline);
2939 ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2940
2941 opline.opcode = ZEND_DO_FCALL_BY_NAME;
2942 opline.result_type = IS_VAR;
2943 zend_vm_set_opcode_handler(&opline);
2944 ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2945
2946 opline.opcode = ZEND_DO_FCALL;
2947 opline.result_type = IS_UNUSED;
2948 zend_vm_set_opcode_handler(&opline);
2949 ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2950
2951 opline.opcode = ZEND_DO_FCALL;
2952 opline.result_type = IS_VAR;
2953 zend_vm_set_opcode_handler(&opline);
2954 ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2955
2956 opline.opcode = ZEND_RETURN;
2957 opline.op1_type = IS_CONST;
2958 zend_vm_set_opcode_handler(&opline);
2959 ir_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2960
2961 opline.opcode = ZEND_RETURN;
2962 opline.op1_type = IS_TMP_VAR;
2963 zend_vm_set_opcode_handler(&opline);
2964 ir_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2965
2966 opline.opcode = ZEND_RETURN;
2967 opline.op1_type = IS_VAR;
2968 zend_vm_set_opcode_handler(&opline);
2969 ir_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2970
2971 opline.opcode = ZEND_RETURN;
2972 opline.op1_type = IS_CV;
2973 zend_vm_set_opcode_handler(&opline);
2974 ir_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2975
2976 ir_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
2977 }
2978
2979 REGISTER_DATA(zend_jit_profile_counter);
2980
2981 REGISTER_HELPER(zend_runtime_jit);
2982 REGISTER_HELPER(zend_jit_hot_func);
2983 REGISTER_HELPER(zend_jit_trace_hot_root);
2984 REGISTER_HELPER(zend_jit_trace_exit);
2985
2986 REGISTER_HELPER(zend_jit_array_free);
2987 REGISTER_HELPER(zend_jit_undefined_op_helper);
2988 REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
2989 REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
2990 REGISTER_HELPER(zend_jit_post_inc_typed_ref);
2991 REGISTER_HELPER(zend_jit_post_dec_typed_ref);
2992 REGISTER_HELPER(zend_jit_pre_inc);
2993 REGISTER_HELPER(zend_jit_pre_dec);
2994 REGISTER_HELPER(zend_jit_add_arrays_helper);
2995 REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
2996 REGISTER_HELPER(zend_jit_fast_concat_helper);
2997 REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
2998 REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
2999 REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
3000 REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
3001 REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
3002 REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
3003 REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
3004 REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
3005 REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
3006 REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
3007 REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
3008 REGISTER_HELPER(zend_jit_check_constant);
3009 REGISTER_HELPER(zend_jit_get_constant);
3010 REGISTER_HELPER(zend_jit_int_extend_stack_helper);
3011 REGISTER_HELPER(zend_jit_extend_stack_helper);
3012 REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
3013 REGISTER_HELPER(zend_jit_find_func_helper);
3014 REGISTER_HELPER(zend_jit_find_ns_func_helper);
3015 REGISTER_HELPER(zend_jit_jmp_frameless_helper);
3016 REGISTER_HELPER(zend_jit_unref_helper);
3017 REGISTER_HELPER(zend_jit_invalid_method_call);
3018 REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
3019 REGISTER_HELPER(zend_jit_find_method_helper);
3020 REGISTER_HELPER(zend_jit_find_method_tmp_helper);
3021 REGISTER_HELPER(zend_jit_push_static_method_call_frame);
3022 REGISTER_HELPER(zend_jit_push_static_method_call_frame_tmp);
3023 REGISTER_HELPER(zend_jit_find_class_helper);
3024 REGISTER_HELPER(zend_jit_find_static_method_helper);
3025 REGISTER_HELPER(zend_jit_push_this_method_call_frame);
3026 REGISTER_HELPER(zend_jit_free_trampoline_helper);
3027 REGISTER_HELPER(zend_jit_verify_return_slow);
3028 REGISTER_HELPER(zend_jit_deprecated_helper);
3029 REGISTER_HELPER(zend_jit_undefined_long_key);
3030 REGISTER_HELPER(zend_jit_undefined_long_key_ex);
3031 REGISTER_HELPER(zend_jit_undefined_string_key);
3032 REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3033 REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3034 REGISTER_HELPER(zend_free_extra_named_params);
3035 REGISTER_HELPER(zend_jit_free_call_frame);
3036 REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3037 REGISTER_HELPER(zend_jit_verify_arg_slow);
3038 REGISTER_HELPER(zend_missing_arg_error);
3039 REGISTER_HELPER(zend_jit_only_vars_by_reference);
3040 REGISTER_HELPER(zend_jit_leave_func_helper);
3041 REGISTER_HELPER(zend_jit_leave_nested_func_helper);
3042 REGISTER_HELPER(zend_jit_leave_top_func_helper);
3043 REGISTER_HELPER(zend_jit_fetch_global_helper);
3044 REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3045 REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3046 REGISTER_HELPER(zend_jit_hash_lookup_rw);
3047 REGISTER_HELPER(zend_jit_symtable_find);
3048 REGISTER_HELPER(zend_jit_symtable_lookup_w);
3049 REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3050 REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3051 REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3052 REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3053 REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3054 REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3055 REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3056 REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3057 REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3058 REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3059 REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3060 REGISTER_HELPER(zend_jit_invalid_array_access);
3061 REGISTER_HELPER(zend_jit_zval_array_dup);
3062 REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3063 REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3064 REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3065 REGISTER_HELPER(zend_jit_isset_dim_helper);
3066 REGISTER_HELPER(zend_jit_assign_dim_helper);
3067 REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3068 REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3069 REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3070 REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3071 REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3072 REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3073 REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3074 REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3075 REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3076 REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3077 REGISTER_HELPER(zend_jit_check_array_promotion);
3078 REGISTER_HELPER(zend_jit_create_typed_ref);
3079 REGISTER_HELPER(zend_jit_invalid_property_write);
3080 REGISTER_HELPER(zend_jit_invalid_property_read);
3081 REGISTER_HELPER(zend_jit_extract_helper);
3082 REGISTER_HELPER(zend_jit_invalid_property_assign);
3083 REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3084 REGISTER_HELPER(zend_jit_assign_obj_helper);
3085 REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3086 REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3087 REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3088 REGISTER_HELPER(zend_jit_invalid_property_incdec);
3089 REGISTER_HELPER(zend_jit_inc_typed_prop);
3090 REGISTER_HELPER(zend_jit_dec_typed_prop);
3091 REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3092 REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3093 REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3094 REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3095 REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3096 REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3097 REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3098 REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3099 REGISTER_HELPER(zend_jit_uninit_static_prop);
3100 REGISTER_HELPER(zend_jit_rope_end);
3101 REGISTER_HELPER(zend_fcall_interrupt);
3102
3103 #ifndef ZTS
3104 REGISTER_DATA(EG(current_execute_data));
3105 REGISTER_DATA(EG(exception));
3106 REGISTER_DATA(EG(opline_before_exception));
3107 REGISTER_DATA(EG(vm_interrupt));
3108 REGISTER_DATA(EG(timed_out));
3109 REGISTER_DATA(EG(uninitialized_zval));
3110 REGISTER_DATA(EG(zend_constants));
3111 REGISTER_DATA(EG(jit_trace_num));
3112 REGISTER_DATA(EG(vm_stack_top));
3113 REGISTER_DATA(EG(vm_stack_end));
3114 REGISTER_DATA(EG(exception_op));
3115 REGISTER_DATA(EG(symbol_table));
3116
3117 REGISTER_DATA(CG(map_ptr_base));
3118 #endif
3119 #endif
3120 }
3121
zend_jit_calc_trace_prologue_size(void)3122 static void zend_jit_calc_trace_prologue_size(void)
3123 {
3124 zend_jit_ctx jit_ctx;
3125 zend_jit_ctx *jit = &jit_ctx;
3126 void *entry;
3127 size_t size;
3128
3129 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
3130
3131 if (!GCC_GLOBAL_REGS) {
3132 ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3133 jit_STORE_FP(jit, ref);
3134 jit->ctx.flags |= IR_FASTCALL_FUNC;
3135 }
3136
3137 ir_UNREACHABLE();
3138
3139 entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3140 zend_jit_free_ctx(jit);
3141
3142 if (!entry) {
3143 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3144 }
3145
3146 zend_jit_trace_prologue_size = size;
3147 }
3148
3149 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3150 static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3151
3152 typedef struct _Unwind_Context _Unwind_Context;
3153 typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3154 extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
3155 extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
3156
3157 typedef struct _zend_jit_unwind_arg {
3158 int cnt;
3159 uintptr_t cfa[3];
3160 } zend_jit_unwind_arg;
3161
zend_jit_unwind_cb(_Unwind_Context * ctx,void * a)3162 static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3163 {
3164 zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
3165 arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3166 arg->cnt++;
3167 if (arg->cnt == 3) {
3168 return 5; // _URC_END_OF_STACK
3169 }
3170 return 0; // _URC_NO_REASON;
3171 }
3172
zend_jit_touch_vm_stack_data(void * vm_stack_data)3173 static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3174 {
3175 zend_jit_unwind_arg arg;
3176
3177 memset(&arg, 0, sizeof(arg));
3178 _Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3179 if (arg.cnt == 3) {
3180 zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3181 }
3182 }
3183
3184 extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3185
zend_jit_set_sp_adj_vm(void)3186 static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3187 {
3188 void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3189
3190 orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3191 zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3192 execute_ex(NULL); // set sp_adj[SP_ADJ_VM]
3193 zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3194 }
3195 #endif
3196
zend_jit_setup(void)3197 static void zend_jit_setup(void)
3198 {
3199 #if defined(IR_TARGET_X86)
3200 if (!zend_cpu_supports_sse2()) {
3201 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3202 }
3203 #endif
3204 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3205 allowed_opt_flags = 0;
3206 if (zend_cpu_supports_avx()) {
3207 allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3208 }
3209 # if defined(PHP_HAVE_BUILTIN_CPU_SUPPORTS) && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
3210 if (zend_cpu_supports_cldemote()) {
3211 default_mflags |= IR_X86_CLDEMOTE;
3212 }
3213 # endif
3214 #endif
3215 #ifdef ZTS
3216 #if defined(IR_TARGET_AARCH64)
3217 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3218
3219 # ifdef __FreeBSD__
3220 if (tsrm_ls_cache_tcb_offset == 0) {
3221 TLSDescriptor **where;
3222
3223 __asm__(
3224 "adrp %0, :tlsdesc:_tsrm_ls_cache\n"
3225 "add %0, %0, :tlsdesc_lo12:_tsrm_ls_cache\n"
3226 : "=r" (where));
3227 /* See https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst
3228 * section "Relocations for thread-local storage".
3229 * The first entry holds a pointer to the variable's TLS descriptor resolver function and the second entry holds
3230 * a platform-specific offset or pointer. */
3231 TLSDescriptor *tlsdesc = where[1];
3232
3233 tsrm_tls_offset = tlsdesc->offset;
3234 /* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/22ca6db50f4e6bd75a141f57cf953d8de6531a06/lib/libc/gen/tls.c#L88) */
3235 tsrm_tls_index = (tlsdesc->index + 1) * 8;
3236 }
3237 # else
3238 ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0);
3239 # endif
3240 # elif defined(_WIN64)
3241 tsrm_tls_index = _tls_index * sizeof(void*);
3242
3243 /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3244 /* Probably, it might be better solution */
3245 do {
3246 void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
3247 void *val = _tsrm_ls_cache;
3248 size_t offset = 0;
3249 size_t size = (char*)&_tls_end - (char*)&_tls_start;
3250
3251 while (offset < size) {
3252 if (*tls_mem == val) {
3253 tsrm_tls_offset = offset;
3254 break;
3255 }
3256 tls_mem++;
3257 offset += sizeof(void*);
3258 }
3259 if (offset >= size) {
3260 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3261 }
3262 } while(0);
3263 # elif defined(ZEND_WIN32)
3264 tsrm_tls_index = _tls_index * sizeof(void*);
3265
3266 /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3267 /* Probably, it might be better solution */
3268 do {
3269 void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
3270 void *val = _tsrm_ls_cache;
3271 size_t offset = 0;
3272 size_t size = (char*)&_tls_end - (char*)&_tls_start;
3273
3274 while (offset < size) {
3275 if (*tls_mem == val) {
3276 tsrm_tls_offset = offset;
3277 break;
3278 }
3279 tls_mem++;
3280 offset += sizeof(void*);
3281 }
3282 if (offset >= size) {
3283 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3284 }
3285 } while(0);
3286 # elif defined(__APPLE__) && defined(__x86_64__)
3287 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3288 if (tsrm_ls_cache_tcb_offset == 0) {
3289 size_t *ti;
3290 __asm__(
3291 "leaq __tsrm_ls_cache(%%rip),%0"
3292 : "=r" (ti));
3293 tsrm_tls_offset = ti[2];
3294 tsrm_tls_index = ti[1] * 8;
3295 }
3296 # elif defined(__GNUC__) && defined(__x86_64__)
3297 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3298 if (tsrm_ls_cache_tcb_offset == 0) {
3299 #if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && \
3300 !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3301 size_t ret;
3302
3303 asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
3304 : "=r" (ret));
3305 tsrm_ls_cache_tcb_offset = ret;
3306 #elif defined(__MUSL__)
3307 size_t *ti;
3308
3309 __asm__(
3310 "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3311 : "=a" (ti));
3312 tsrm_tls_offset = ti[1];
3313 tsrm_tls_index = ti[0] * 8;
3314 #elif defined(__FreeBSD__)
3315 size_t *ti;
3316
3317 __asm__(
3318 "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3319 : "=a" (ti));
3320 tsrm_tls_offset = ti[1];
3321 /* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/bf56e8b9c8639ac4447d223b83cdc128107cc3cd/libexec/rtld-elf/rtld.c#L5260) */
3322 tsrm_tls_index = (ti[0] + 1) * 8;
3323 #else
3324 size_t *ti;
3325
3326 __asm__(
3327 "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3328 : "=a" (ti));
3329 tsrm_tls_offset = ti[1];
3330 tsrm_tls_index = ti[0] * 16;
3331 #endif
3332 }
3333 # elif defined(__GNUC__) && defined(__i386__)
3334 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3335 if (tsrm_ls_cache_tcb_offset == 0) {
3336 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3337 size_t ret;
3338
3339 asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
3340 : "=a" (ret));
3341 tsrm_ls_cache_tcb_offset = ret;
3342 #else
3343 size_t *ti, _ebx, _ecx, _edx;
3344
3345 __asm__(
3346 "call 1f\n"
3347 ".subsection 1\n"
3348 "1:\tmovl (%%esp), %%ebx\n\t"
3349 "ret\n"
3350 ".previous\n\t"
3351 "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
3352 "leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
3353 "call ___tls_get_addr@plt\n\t"
3354 "leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
3355 : "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
3356 tsrm_tls_offset = ti[1];
3357 tsrm_tls_index = ti[0] * 8;
3358 #endif
3359 }
3360 # endif
3361 #endif
3362
3363 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3364 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3365 zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3366 }
3367 #endif
3368
3369 if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3370 zend_jit_setup_disasm();
3371 }
3372
3373 #ifndef _WIN32
3374 if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3375 ir_perf_jitdump_open();
3376 }
3377
3378 #endif
3379 zend_long debug = JIT_G(debug);
3380 if (!(debug & ZEND_JIT_DEBUG_ASM_STUBS)) {
3381 JIT_G(debug) &= ~(ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_FINAL|
3382 ZEND_JIT_DEBUG_IR_CODEGEN|
3383 ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_CFG|ZEND_JIT_DEBUG_IR_AFTER_GCM|
3384 ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS);
3385 }
3386
3387 zend_jit_calc_trace_prologue_size();
3388 zend_jit_setup_stubs();
3389 JIT_G(debug) = debug;
3390 }
3391
zend_jit_shutdown_ir(void)3392 static void zend_jit_shutdown_ir(void)
3393 {
3394 #ifndef _WIN32
3395 if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3396 ir_perf_jitdump_close();
3397 }
3398 if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
3399 ir_gdb_unregister_all();
3400 }
3401 #endif
3402 #ifdef HAVE_CAPSTONE
3403 if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3404 ir_disasm_free();
3405 }
3406 #endif
3407 }
3408
3409 /* PHP control flow reconstruction helpers */
jit_IF_ex(zend_jit_ctx * jit,ir_ref condition,ir_ref true_block)3410 static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3411 {
3412 ir_ref ref = ir_IF(condition);
3413 /* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3414 *
3415 * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3416 * to start target block
3417 */
3418 ir_set_op(&jit->ctx, ref, 3, true_block);
3419 return ref;
3420 }
3421
jit_IF_TRUE_FALSE_ex(zend_jit_ctx * jit,ir_ref if_ref,ir_ref true_block)3422 static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3423 {
3424 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3425 ZEND_ASSERT(if_ref);
3426 ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3427 ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3428 if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3429 ir_IF_TRUE(if_ref);
3430 } else {
3431 ir_IF_FALSE(if_ref);
3432 }
3433 }
3434
_zend_jit_add_predecessor_ref(zend_jit_ctx * jit,int b,int pred,ir_ref ref)3435 static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3436 {
3437 int i, *p;
3438 zend_basic_block *bb;
3439 ir_ref *r, header;
3440
3441 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3442 bb = &jit->ssa->cfg.blocks[b];
3443 p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3444 r = &jit->bb_edges[jit->bb_predecessors[b]];
3445 for (i = 0; i < bb->predecessors_count; i++, p++, r++) {
3446 if (*p == pred) {
3447 ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3448 header = jit->bb_start_ref[b];
3449 if (header) {
3450 /* this is back edge */
3451 ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3452 if (jit->ctx.ir_base[ref].op == IR_END) {
3453 jit->ctx.ir_base[ref].op = IR_LOOP_END;
3454 } else if (jit->ctx.ir_base[ref].op == IR_IF) {
3455 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3456 ref = ir_LOOP_END();
3457 } else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3458 ir_BEGIN(ref);
3459 ref = ir_LOOP_END();
3460 } else {
3461 ZEND_UNREACHABLE();
3462 }
3463 ir_MERGE_SET_OP(header, i + 1, ref);
3464 }
3465 *r = ref;
3466 return;
3467 }
3468 }
3469 ZEND_UNREACHABLE();
3470 }
3471
_zend_jit_merge_smart_branch_inputs(zend_jit_ctx * jit,uint32_t true_label,uint32_t false_label,ir_ref true_inputs,ir_ref false_inputs)3472 static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3473 uint32_t true_label,
3474 uint32_t false_label,
3475 ir_ref true_inputs,
3476 ir_ref false_inputs)
3477 {
3478 ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3479
3480 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3481 if (true_inputs) {
3482 ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3483 if (!jit->ctx.ir_base[true_inputs].op2) {
3484 true_path = true_inputs;
3485 } else {
3486 ir_MERGE_list(true_inputs);
3487 true_path = ir_END();
3488 }
3489 }
3490 if (false_inputs) {
3491 ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3492 if (!jit->ctx.ir_base[false_inputs].op2) {
3493 false_path = false_inputs;
3494 } else {
3495 ir_MERGE_list(false_inputs);
3496 false_path = ir_END();
3497 }
3498 }
3499
3500 if (true_label == false_label && true_path && false_path) {
3501 ir_MERGE_2(true_path, false_path);
3502 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3503 } else if (!true_path && !false_path) {
3504 /* dead code */
3505 true_path = ir_END();
3506 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3507 } else {
3508 if (true_path) {
3509 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3510 }
3511 if (false_path) {
3512 _zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3513 }
3514 }
3515
3516 jit->b = -1;
3517 }
3518
_zend_jit_fix_merges(zend_jit_ctx * jit)3519 static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3520 {
3521 int i, count;
3522 ir_ref j, k, n, *p, *q, *r;
3523 ir_ref ref;
3524 ir_insn *insn, *phi;
3525
3526 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3527 count = jit->ssa->cfg.blocks_count;
3528 for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3529 ref = *p;
3530 if (ref) {
3531 insn = &jit->ctx.ir_base[ref];
3532 if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3533 n = insn->inputs_count;
3534 /* Remove IS_UNUSED inputs */
3535 for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3536 if (*q) {
3537 if (q != r) {
3538 *r = *q;
3539 phi = insn + 1 + (n >> 2);
3540 while (phi->op == IR_PI) {
3541 phi++;
3542 }
3543 while (phi->op == IR_PHI) {
3544 ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3545 phi += 1 + ((n + 1) >> 2);
3546 }
3547 }
3548 k++;
3549 r++;
3550 }
3551 }
3552 if (k != n) {
3553 ir_ref n2, k2;
3554
3555 if (k <= 1) {
3556 insn->op = IR_BEGIN;
3557 insn->inputs_count = 0;
3558 } else {
3559 insn->inputs_count = k;
3560 }
3561 n2 = 1 + (n >> 2);
3562 k2 = 1 + (k >> 2);
3563 while (k2 != n2) {
3564 (insn+k2)->optx = IR_NOP;
3565 k2++;
3566 }
3567 phi = insn + 1 + (n >> 2);
3568 while (phi->op == IR_PI) {
3569 phi++;
3570 }
3571 while (phi->op == IR_PHI) {
3572 if (k <= 1) {
3573 phi->op = IR_COPY;
3574 phi->op1 = phi->op2;
3575 phi->op2 = 1;
3576 phi->inputs_count = 0;
3577 } else {
3578 phi->inputs_count = k + 1;
3579 }
3580 n2 = 1 + ((n + 1) >> 2);
3581 k2 = 1 + ((k + 1) >> 2);
3582 while (k2 != n2) {
3583 (phi+k2)->optx = IR_NOP;
3584 k2++;
3585 }
3586 phi += 1 + ((n + 1) >> 2);
3587 }
3588 }
3589 }
3590 }
3591 }
3592 }
3593
zend_jit_case_start(zend_jit_ctx * jit,int switch_b,int case_b,ir_ref switch_ref)3594 static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3595 {
3596 zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3597 const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3598
3599 if (opline->opcode == ZEND_SWITCH_LONG
3600 || opline->opcode == ZEND_SWITCH_STRING
3601 || opline->opcode == ZEND_MATCH) {
3602 HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3603 const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3604 int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3605 zval *zv;
3606 ir_ref list = IR_UNUSED, idx;
3607 bool first = 1;
3608
3609 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3610 const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3611 int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3612
3613 if (b == case_b) {
3614 if (!first) {
3615 ir_END_list(list);
3616 }
3617 if (HT_IS_PACKED(jumptable)) {
3618 idx = ir_CONST_LONG(zv - jumptable->arPacked);
3619 } else {
3620 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3621 }
3622 ir_CASE_VAL(switch_ref, idx);
3623 first = 0;
3624 }
3625 } ZEND_HASH_FOREACH_END();
3626 if (default_b == case_b) {
3627 if (!first) {
3628 ir_END_list(list);
3629 }
3630 if (jit->ctx.ir_base[switch_ref].op3) {
3631 /* op3 may contain a list of additional "default" path inputs for MATCH */
3632 ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3633 jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3634 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3635 ir_ref end = ref;
3636 while (jit->ctx.ir_base[end].op2) {
3637 ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3638 end = jit->ctx.ir_base[end].op2;
3639 }
3640 jit->ctx.ir_base[end].op2 = list;
3641 list = ref;
3642 }
3643 ir_CASE_DEFAULT(switch_ref);
3644 }
3645 if (list) {
3646 ir_END_list(list);
3647 ir_MERGE_list(list);
3648 }
3649 } else {
3650 ZEND_UNREACHABLE();
3651 }
3652 }
3653
zend_jit_bb_start(zend_jit_ctx * jit,int b)3654 static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3655 {
3656 zend_basic_block *bb;
3657 int i, n, *p, pred;
3658 ir_ref ref, bb_start;
3659
3660 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3661 ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3662 bb = &jit->ssa->cfg.blocks[b];
3663 ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3664 n = bb->predecessors_count;
3665
3666 if (n == 0) {
3667 /* pass */
3668 ZEND_ASSERT(jit->ctx.control);
3669 #if ZEND_DEBUG
3670 ref = jit->ctx.control;
3671 ir_insn *insn = &jit->ctx.ir_base[ref];
3672 while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3673 ref = insn->op1;
3674 insn = &jit->ctx.ir_base[ref];
3675 }
3676 ZEND_ASSERT(insn->op == IR_START);
3677 ZEND_ASSERT(ref == 1);
3678 #endif
3679 bb_start = 1;
3680 if (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
3681 /* prvent END/BEGIN merging */
3682 jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3683 bb_start = jit->ctx.control;
3684 }
3685 } else if (n == 1) {
3686 ZEND_ASSERT(!jit->ctx.control);
3687 pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3688 ref = jit->bb_edges[jit->bb_predecessors[b]];
3689 if (ref == IR_UNUSED) {
3690 if (!jit->ctx.control) {
3691 ir_BEGIN(IR_UNUSED); /* unreachable block */
3692 }
3693 } else {
3694 ir_op op = jit->ctx.ir_base[ref].op;
3695
3696 if (op == IR_IF) {
3697 if (!jit->ctx.control) {
3698 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3699 } else {
3700 ir_ref entry_path = ir_END();
3701 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3702 ir_MERGE_WITH(entry_path);
3703 }
3704 } else if (op == IR_SWITCH) {
3705 zend_jit_case_start(jit, pred, b, ref);
3706 } else {
3707 if (!jit->ctx.control) {
3708 ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3709 if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3710 && (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)) {
3711 /* prvent END/BEGIN merging */
3712 jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3713 } else {
3714 ir_BEGIN(ref);
3715 }
3716 } else {
3717 ir_MERGE_WITH(ref);
3718 }
3719 }
3720 }
3721 bb_start = jit->ctx.control;
3722 } else {
3723 int forward_edges_count = 0;
3724 int back_edges_count = 0;
3725 ir_ref *pred_refs;
3726 ir_ref entry_path = IR_UNUSED;
3727 ALLOCA_FLAG(use_heap);
3728
3729 ZEND_ASSERT(!jit->ctx.control);
3730 if (jit->ctx.control) {
3731 entry_path = ir_END();
3732 }
3733 pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3734 for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3735 pred = *p;
3736 if (jit->bb_start_ref[pred]) {
3737 /* forward edge */
3738 forward_edges_count++;
3739 ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3740 if (ref == IR_UNUSED) {
3741 /* dead edge */
3742 pred_refs[i] = IR_UNUSED;
3743 } else {
3744 ir_op op = jit->ctx.ir_base[ref].op;
3745
3746 if (op == IR_IF) {
3747 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3748 pred_refs[i] = ir_END();
3749 } else if (op == IR_SWITCH) {
3750 zend_jit_case_start(jit, pred, b, ref);
3751 pred_refs[i] = ir_END();
3752 } else {
3753 ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3754 pred_refs[i] = ref;
3755 }
3756 }
3757 } else {
3758 /* backward edge */
3759 back_edges_count++;
3760 pred_refs[i] = IR_UNUSED;
3761 }
3762 }
3763
3764 if (bb->flags & ZEND_BB_LOOP_HEADER) {
3765 ZEND_ASSERT(back_edges_count != 0);
3766 ZEND_ASSERT(forward_edges_count != 0);
3767 ir_MERGE_N(n, pred_refs);
3768 jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3769 bb_start = jit->ctx.control;
3770 if (entry_path) {
3771 ir_MERGE_WITH(entry_path);
3772 }
3773 } else {
3774 // ZEND_ASSERT(back_edges_count != 0);
3775 /* edges from exceptional blocks may be counted as back edges */
3776 ir_MERGE_N(n, pred_refs);
3777 bb_start = jit->ctx.control;
3778 if (entry_path) {
3779 ir_MERGE_WITH(entry_path);
3780 }
3781 }
3782 free_alloca(pred_refs, use_heap);
3783 }
3784 jit->b = b;
3785 jit->bb_start_ref[b] = bb_start;
3786
3787 if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3788 jit->ctx.fold_cse_limit = bb_start;
3789 }
3790
3791 return 1;
3792 }
3793
zend_jit_bb_end(zend_jit_ctx * jit,int b)3794 static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3795 {
3796 int succ;
3797 zend_basic_block *bb;
3798
3799 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3800 if (jit->b != b) {
3801 return 1;
3802 }
3803
3804 bb = &jit->ssa->cfg.blocks[b];
3805 ZEND_ASSERT(bb->successors_count != 0);
3806 if (bb->successors_count == 1) {
3807 succ = bb->successors[0];
3808 } else {
3809 const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3810
3811 /* Use only the following successor of SWITCH and FE_RESET_R */
3812 ZEND_ASSERT(opline->opcode == ZEND_SWITCH_LONG
3813 || opline->opcode == ZEND_SWITCH_STRING
3814 || opline->opcode == ZEND_MATCH
3815 || opline->opcode == ZEND_FE_RESET_R);
3816 succ = b + 1;
3817 }
3818 _zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3819 jit->b = -1;
3820 return 1;
3821 }
3822
jit_CMP_IP(zend_jit_ctx * jit,ir_op op,const zend_op * next_opline)3823 static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3824 {
3825 ir_ref ref;
3826
3827 #if 1
3828 if (GCC_GLOBAL_REGS) {
3829 ref = jit_IP32(jit);
3830 } else {
3831 ref = ir_LOAD_U32(jit_EX(opline));
3832 }
3833 ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3834 #else
3835 if (GCC_GLOBAL_REGS) {
3836 ref = jit_IP(jit);
3837 } else {
3838 ref = ir_LOAD_A(jit_EX(opline));
3839 }
3840 ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
3841 #endif
3842 return ref;
3843 }
3844
zend_jit_jmp_frameless(zend_jit_ctx * jit,const zend_op * opline,const void * exit_addr,zend_jmp_fl_result guard)3845 static int zend_jit_jmp_frameless(
3846 zend_jit_ctx *jit,
3847 const zend_op *opline,
3848 const void *exit_addr,
3849 zend_jmp_fl_result guard
3850 ) {
3851 ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
3852 zend_basic_block *bb;
3853
3854 // JIT: CACHED_PTR(opline->extended_value)
3855 cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
3856 cache_result = ir_LOAD_L(cache_slot_ref);
3857
3858 // JIT: if (UNEXPECTED(!result))
3859 if_ref = ir_IF(cache_result);
3860 ir_IF_FALSE_cold(if_ref);
3861 zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3862 function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3863 ir_CONST_ADDR(func_name_zv),
3864 cache_slot_ref);
3865 ir_MERGE_WITH_EMPTY_TRUE(if_ref);
3866
3867 phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
3868
3869 if (exit_addr) {
3870 ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3871 } else {
3872 ZEND_ASSERT(jit->b >= 0);
3873 bb = &jit->ssa->cfg.blocks[jit->b];
3874 // JIT: if (result == ZEND_JMP_FL_HIT)
3875 ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3876 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3877 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3878 jit->b = -1;
3879 }
3880
3881 return 1;
3882 }
3883
zend_jit_cond_jmp(zend_jit_ctx * jit,const zend_op * next_opline,int target_block)3884 static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
3885 {
3886 ir_ref ref;
3887 zend_basic_block *bb;
3888
3889 ZEND_ASSERT(jit->b >= 0);
3890 bb = &jit->ssa->cfg.blocks[jit->b];
3891
3892 ZEND_ASSERT(bb->successors_count == 2);
3893 if (bb->successors[0] == bb->successors[1]) {
3894 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
3895 jit->b = -1;
3896 zend_jit_set_last_valid_opline(jit, next_opline);
3897 return 1;
3898 }
3899
3900 ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
3901
3902 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3903 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3904
3905 jit->b = -1;
3906 zend_jit_set_last_valid_opline(jit, next_opline);
3907
3908 return 1;
3909 }
3910
zend_jit_set_cond(zend_jit_ctx * jit,const zend_op * next_opline,uint32_t var)3911 static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *next_opline, uint32_t var)
3912 {
3913 ir_ref ref;
3914
3915 ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, IR_EQ, next_opline)), ir_CONST_U32(IS_FALSE));
3916
3917 // EX_VAR(var) = ...
3918 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
3919
3920 zend_jit_reset_last_valid_opline(jit);
3921 return zend_jit_set_ip(jit, next_opline - 1);
3922 }
3923
3924 /* PHP JIT handlers */
zend_jit_check_exception(zend_jit_ctx * jit)3925 static void zend_jit_check_exception(zend_jit_ctx *jit)
3926 {
3927 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3928 jit_STUB_ADDR(jit, jit_stub_exception_handler));
3929 }
3930
zend_jit_check_exception_undef_result(zend_jit_ctx * jit,const zend_op * opline)3931 static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
3932 {
3933 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
3934 jit_STUB_ADDR(jit,
3935 (opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
3936 }
3937
zend_jit_type_check_undef(zend_jit_ctx * jit,ir_ref type,uint32_t var,const zend_op * opline,bool check_exception,bool in_cold_path,bool undef_result)3938 static void zend_jit_type_check_undef(zend_jit_ctx *jit,
3939 ir_ref type,
3940 uint32_t var,
3941 const zend_op *opline,
3942 bool check_exception,
3943 bool in_cold_path,
3944 bool undef_result)
3945 {
3946 ir_ref if_def = ir_IF(type);
3947
3948 if (!in_cold_path) {
3949 ir_IF_FALSE_cold(if_def);
3950 } else {
3951 ir_IF_FALSE(if_def);
3952 }
3953 if (opline) {
3954 jit_SET_EX_OPLINE(jit, opline);
3955 }
3956 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3957 if (check_exception) {
3958 if (undef_result) {
3959 zend_jit_check_exception_undef_result(jit, opline);
3960 } else {
3961 zend_jit_check_exception(jit);
3962 }
3963 }
3964 ir_MERGE_WITH_EMPTY_TRUE(if_def);
3965 }
3966
zend_jit_zval_check_undef(zend_jit_ctx * jit,ir_ref ref,uint32_t var,const zend_op * opline,bool check_exception)3967 static ir_ref zend_jit_zval_check_undef(zend_jit_ctx *jit,
3968 ir_ref ref,
3969 uint32_t var,
3970 const zend_op *opline,
3971 bool check_exception)
3972 {
3973 ir_ref if_def, ref2;
3974
3975 if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
3976 ir_IF_FALSE_cold(if_def);
3977
3978 if (opline) {
3979 jit_SET_EX_OPLINE(jit, opline);
3980 }
3981
3982 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
3983
3984 if (check_exception) {
3985 zend_jit_check_exception(jit);
3986 }
3987
3988 ref2 = jit_EG(uninitialized_zval);
3989
3990 ir_MERGE_WITH_EMPTY_TRUE(if_def);
3991
3992 return ir_PHI_2(IR_ADDR, ref2, ref);
3993 }
3994
zend_jit_recv_entry(zend_jit_ctx * jit,int b)3995 static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
3996 {
3997 zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
3998 int pred;
3999 ir_ref ref;
4000
4001 ZEND_ASSERT(bb->predecessors_count > 0);
4002
4003 pred = jit->bb_predecessors[b];
4004 ref = jit->bb_edges[pred];
4005
4006 ZEND_ASSERT(ref);
4007 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
4008
4009 /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4010 ir_ENTRY(ref, bb->start);
4011 if (!GCC_GLOBAL_REGS) {
4012 /* 2 is hardcoded reference to IR_PARAM */
4013 ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4014 ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4015 jit_STORE_FP(jit, 2);
4016 }
4017
4018 ir_MERGE_WITH(ref);
4019 jit->bb_edges[pred] = ir_END();
4020 }
4021
zend_jit_osr_entry(zend_jit_ctx * jit,int b)4022 static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4023 {
4024 zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4025 ir_ref ref = ir_END();
4026
4027 /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4028 ir_ENTRY(ref, bb->start);
4029 if (!GCC_GLOBAL_REGS) {
4030 /* 2 is hardcoded reference to IR_PARAM */
4031 ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4032 ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4033 jit_STORE_FP(jit, 2);
4034 }
4035
4036 ir_MERGE_WITH(ref);
4037 }
4038
zend_jit_continue_entry(zend_jit_ctx * jit,ir_ref src,unsigned int label)4039 static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4040 {
4041 ir_ENTRY(src, label);
4042 if (!GCC_GLOBAL_REGS) {
4043 /* 2 is hardcoded reference to IR_PARAM */
4044 ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4045 ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4046 jit_STORE_FP(jit, 2);
4047 }
4048 return ir_END();
4049 }
4050
zend_jit_handler(zend_jit_ctx * jit,const zend_op * opline,int may_throw)4051 static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4052 {
4053 ir_ref ref;
4054 const void *handler;
4055
4056 zend_jit_set_ip(jit, opline);
4057 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4058 handler = zend_get_opcode_handler_func(opline);
4059 } else {
4060 handler = opline->handler;
4061 }
4062 if (GCC_GLOBAL_REGS) {
4063 ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4064 } else {
4065 ref = jit_FP(jit);
4066 ref = ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(handler), ref);
4067 }
4068 if (may_throw) {
4069 zend_jit_check_exception(jit);
4070 }
4071 /* Skip the following OP_DATA */
4072 switch (opline->opcode) {
4073 case ZEND_ASSIGN_DIM:
4074 case ZEND_ASSIGN_OBJ:
4075 case ZEND_ASSIGN_STATIC_PROP:
4076 case ZEND_ASSIGN_DIM_OP:
4077 case ZEND_ASSIGN_OBJ_OP:
4078 case ZEND_ASSIGN_STATIC_PROP_OP:
4079 case ZEND_ASSIGN_STATIC_PROP_REF:
4080 case ZEND_ASSIGN_OBJ_REF:
4081 zend_jit_set_last_valid_opline(jit, opline + 2);
4082 break;
4083 default:
4084 zend_jit_set_last_valid_opline(jit, opline + 1);
4085 break;
4086 }
4087 return 1;
4088 }
4089
zend_jit_tail_handler(zend_jit_ctx * jit,const zend_op * opline)4090 static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4091 {
4092 const void *handler;
4093 ir_ref ref;
4094 zend_basic_block *bb;
4095
4096 zend_jit_set_ip(jit, opline);
4097 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4098 if (opline->opcode == ZEND_DO_UCALL ||
4099 opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4100 opline->opcode == ZEND_DO_FCALL ||
4101 opline->opcode == ZEND_RETURN) {
4102
4103 /* Use inlined HYBRID VM handler */
4104 handler = opline->handler;
4105 ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4106 } else {
4107 handler = zend_get_opcode_handler_func(opline);
4108 ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4109 ref = ir_LOAD_A(jit_IP(jit));
4110 ir_TAILCALL(IR_VOID, ref);
4111 }
4112 } else {
4113 handler = opline->handler;
4114 if (GCC_GLOBAL_REGS) {
4115 ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4116 } else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4117 && (opline->opcode == ZEND_CATCH
4118 || opline->opcode == ZEND_FAST_CALL
4119 || opline->opcode == ZEND_FAST_RET
4120 || opline->opcode == ZEND_MATCH_ERROR
4121 || opline->opcode == ZEND_THROW
4122 || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4123 ref = jit_FP(jit);
4124 ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4125 ir_RETURN(ir_CONST_I32(1));
4126 } else {
4127 ref = jit_FP(jit);
4128 ir_TAILCALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4129 }
4130 }
4131 if (jit->b >= 0) {
4132 bb = &jit->ssa->cfg.blocks[jit->b];
4133 if (bb->successors_count > 0
4134 && (opline->opcode == ZEND_DO_FCALL
4135 || opline->opcode == ZEND_DO_UCALL
4136 || opline->opcode == ZEND_DO_FCALL_BY_NAME
4137 || opline->opcode == ZEND_INCLUDE_OR_EVAL
4138 || opline->opcode == ZEND_GENERATOR_CREATE
4139 || opline->opcode == ZEND_YIELD
4140 || opline->opcode == ZEND_YIELD_FROM
4141 || opline->opcode == ZEND_FAST_CALL)) {
4142 /* Add a fake control edge from UNREACHABLE to the following ENTRY */
4143 int succ;
4144
4145 if (bb->successors_count == 1) {
4146 succ = bb->successors[0];
4147 ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
4148 } else {
4149 /* Use only the following successor of FAST_CALL */
4150 ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4151 succ = jit->b + 1;
4152 /* we need an entry */
4153 jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4154 }
4155 ref = jit->ctx.insns_count - 1;
4156 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4157 ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4158 _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4159 }
4160 jit->b = -1;
4161 zend_jit_reset_last_valid_opline(jit);
4162 }
4163 return 1;
4164 }
4165
zend_jit_call(zend_jit_ctx * jit,const zend_op * opline,unsigned int next_block)4166 static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4167 {
4168 return zend_jit_tail_handler(jit, opline);
4169 }
4170
zend_jit_spill_store(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info,bool set_type)4171 static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4172 {
4173 ZEND_ASSERT(Z_MODE(src) == IS_REG);
4174 ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4175
4176 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4177 jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4178 if (set_type &&
4179 (Z_REG(dst) != ZREG_FP ||
4180 !JIT_G(current_frame) ||
4181 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4182 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4183 }
4184 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4185 jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4186 if (set_type &&
4187 (Z_REG(dst) != ZREG_FP ||
4188 !JIT_G(current_frame) ||
4189 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4190 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4191 }
4192 } else {
4193 ZEND_UNREACHABLE();
4194 }
4195 return 1;
4196 }
4197
zend_jit_spill_store_inv(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4198 static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4199 {
4200 ZEND_ASSERT(Z_MODE(src) == IS_REG);
4201 ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4202
4203 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4204 jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4205 if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4206 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4207 } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4208 /* invalidate memory type */
4209 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4210 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4211 }
4212 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4213 jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4214 if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4215 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4216 } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4217 /* invalidate memory type */
4218 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4219 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4220 }
4221 } else {
4222 ZEND_UNREACHABLE();
4223 }
4224 return 1;
4225 }
4226
zend_jit_load_reg(zend_jit_ctx * jit,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4227 static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4228 {
4229 ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
4230 ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4231
4232 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4233 zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4234 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4235 zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4236 } else {
4237 ZEND_UNREACHABLE();
4238 }
4239 return 1;
4240 }
4241
zend_jit_store_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var,bool set_type)4242 static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4243 {
4244 zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4245 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4246
4247 return zend_jit_spill_store(jit, src, dst, info, set_type);
4248 }
4249
zend_jit_store_ref(zend_jit_ctx * jit,uint32_t info,int var,int32_t src,bool set_type)4250 static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4251 {
4252 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4253
4254 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4255 jit_set_Z_LVAL(jit, dst, src);
4256 if (set_type &&
4257 (Z_REG(dst) != ZREG_FP ||
4258 !JIT_G(current_frame) ||
4259 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4260 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4261 }
4262 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4263 jit_set_Z_DVAL(jit, dst, src);
4264 if (set_type &&
4265 (Z_REG(dst) != ZREG_FP ||
4266 !JIT_G(current_frame) ||
4267 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4268 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4269 }
4270 } else {
4271 ZEND_UNREACHABLE();
4272 }
4273 return 1;
4274 }
4275
zend_jit_deopt_rload(zend_jit_ctx * jit,ir_type type,int32_t reg)4276 static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4277 {
4278 ir_ref ref = jit->ctx.control;
4279 ir_insn *insn;
4280
4281 while (1) {
4282 insn = &jit->ctx.ir_base[ref];
4283 if (insn->op == IR_RLOAD && insn->op2 == reg) {
4284 ZEND_ASSERT(insn->type == type);
4285 return ref;
4286 } else if (insn->op == IR_START) {
4287 break;
4288 }
4289 ref = insn->op1;
4290 }
4291 return ir_RLOAD(type, reg);
4292 }
4293
zend_jit_store_const_long(zend_jit_ctx * jit,int var,zend_long val)4294 static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4295 {
4296 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4297 ir_ref src = ir_CONST_LONG(val);
4298
4299 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4300 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4301 }
4302 jit_set_Z_LVAL(jit, dst, src);
4303 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4304 return 1;
4305 }
4306
zend_jit_store_const_double(zend_jit_ctx * jit,int var,double val)4307 static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4308 {
4309 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4310 ir_ref src = ir_CONST_DOUBLE(val);
4311
4312 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4313 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4314 }
4315 jit_set_Z_DVAL(jit, dst, src);
4316 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4317 return 1;
4318 }
4319
zend_jit_store_type(zend_jit_ctx * jit,int var,uint8_t type)4320 static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4321 {
4322 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4323
4324 ZEND_ASSERT(type <= IS_DOUBLE);
4325 jit_set_Z_TYPE_INFO(jit, dst, type);
4326 return 1;
4327 }
4328
zend_jit_store_reg(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,bool in_mem,bool set_type)4329 static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4330 {
4331 zend_jit_addr src;
4332 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4333 ir_type type;
4334
4335 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4336 type = IR_LONG;
4337 src = zend_jit_deopt_rload(jit, type, reg);
4338 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4339 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4340 } else if (!in_mem) {
4341 jit_set_Z_LVAL(jit, dst, src);
4342 if (set_type &&
4343 (Z_REG(dst) != ZREG_FP ||
4344 !JIT_G(current_frame) ||
4345 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4346 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4347 }
4348 }
4349 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4350 type = IR_DOUBLE;
4351 src = zend_jit_deopt_rload(jit, type, reg);
4352 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4353 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4354 } else if (!in_mem) {
4355 jit_set_Z_DVAL(jit, dst, src);
4356 if (set_type &&
4357 (Z_REG(dst) != ZREG_FP ||
4358 !JIT_G(current_frame) ||
4359 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4360 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4361 }
4362 }
4363 } else {
4364 ZEND_UNREACHABLE();
4365 }
4366 return 1;
4367 }
4368
zend_jit_store_spill_slot(zend_jit_ctx * jit,uint32_t info,int var,int8_t reg,int32_t offset,bool set_type)4369 static int zend_jit_store_spill_slot(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, int32_t offset, bool set_type)
4370 {
4371 zend_jit_addr src;
4372 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4373
4374 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4375 src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4376 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4377 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4378 } else {
4379 jit_set_Z_LVAL(jit, dst, src);
4380 if (set_type &&
4381 (Z_REG(dst) != ZREG_FP ||
4382 !JIT_G(current_frame) ||
4383 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4384 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4385 }
4386 }
4387 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4388 src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4389 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4390 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4391 } else {
4392 jit_set_Z_DVAL(jit, dst, src);
4393 if (set_type &&
4394 (Z_REG(dst) != ZREG_FP ||
4395 !JIT_G(current_frame) ||
4396 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4397 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4398 }
4399 }
4400 } else {
4401 ZEND_UNREACHABLE();
4402 }
4403 return 1;
4404 }
4405
zend_jit_store_var_type(zend_jit_ctx * jit,int var,uint32_t type)4406 static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4407 {
4408 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4409
4410 jit_set_Z_TYPE_INFO(jit, dst, type);
4411 return 1;
4412 }
4413
zend_jit_zval_try_addref(zend_jit_ctx * jit,zend_jit_addr var_addr)4414 static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4415 {
4416 ir_ref if_refcounted, end1;
4417
4418 if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4419 ir_IF_FALSE(if_refcounted);
4420 end1 = ir_END();
4421 ir_IF_TRUE(if_refcounted);
4422 jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4423 ir_MERGE_WITH(end1);
4424 return 1;
4425 }
4426
zend_jit_store_var_if_necessary(zend_jit_ctx * jit,int var,zend_jit_addr src,uint32_t info)4427 static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4428 {
4429 if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4430 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4431 return zend_jit_spill_store(jit, src, dst, info, 1);
4432 }
4433 return 1;
4434 }
4435
zend_jit_store_var_if_necessary_ex(zend_jit_ctx * jit,int var,zend_jit_addr src,uint32_t info,zend_jit_addr old,uint32_t old_info)4436 static int zend_jit_store_var_if_necessary_ex(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info)
4437 {
4438 if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4439 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4440 bool set_type = 1;
4441
4442 if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4443 (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4444 if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4445 if (JIT_G(current_frame)) {
4446 uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4447
4448 if (mem_type != IS_UNKNOWN
4449 && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4450 set_type = 0;
4451 }
4452 } else {
4453 set_type = 0;
4454 }
4455 }
4456 }
4457 return zend_jit_spill_store(jit, src, dst, info, set_type);
4458 }
4459 return 1;
4460 }
4461
zend_jit_load_var(zend_jit_ctx * jit,uint32_t info,int var,int ssa_var)4462 static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4463 {
4464 zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4465 zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4466
4467 return zend_jit_load_reg(jit, src, dst, info);
4468 }
4469
zend_jit_invalidate_var_if_necessary(zend_jit_ctx * jit,uint8_t op_type,zend_jit_addr addr,znode_op op)4470 static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4471 {
4472 if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4473 /* Invalidate operand type to prevent incorrect destuction by exception_handler_free_op1_op2() */
4474 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4475 jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4476 }
4477 return 1;
4478 }
4479
zend_jit_update_regs(zend_jit_ctx * jit,uint32_t var,zend_jit_addr src,zend_jit_addr dst,uint32_t info)4480 static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4481 {
4482 if (!zend_jit_same_addr(src, dst)) {
4483 if (Z_MODE(src) == IS_REG) {
4484 if (Z_MODE(dst) == IS_REG) {
4485 zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4486 if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4487 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4488
4489 if (!zend_jit_spill_store(jit, dst, var_addr, info,
4490 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4491 JIT_G(current_frame) == NULL ||
4492 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4493 (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4494 )) {
4495 return 0;
4496 }
4497 }
4498 } else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4499 if (!Z_LOAD(src) && !Z_STORE(src)) {
4500 if (!zend_jit_spill_store(jit, src, dst, info,
4501 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4502 JIT_G(current_frame) == NULL ||
4503 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4504 (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4505 )) {
4506 return 0;
4507 }
4508 }
4509 } else {
4510 ZEND_UNREACHABLE();
4511 }
4512 } else if (Z_MODE(src) == IS_MEM_ZVAL) {
4513 if (Z_MODE(dst) == IS_REG) {
4514 if (!zend_jit_load_reg(jit, src, dst, info)) {
4515 return 0;
4516 }
4517 } else {
4518 ZEND_UNREACHABLE();
4519 }
4520 } else {
4521 ZEND_UNREACHABLE();
4522 }
4523 } else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4524 dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4525 if (!zend_jit_spill_store(jit, src, dst, info,
4526 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4527 JIT_G(current_frame) == NULL ||
4528 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4529 (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4530 )) {
4531 return 0;
4532 }
4533 }
4534 return 1;
4535 }
4536
4537 struct jit_observer_fcall_is_unobserved_data {
4538 ir_ref if_unobserved;
4539 ir_ref ir_end_inputs;
4540 };
4541
jit_observer_fcall_is_unobserved_start(zend_jit_ctx * jit,const zend_function * func,ir_ref * observer_handler,ir_ref rx,ir_ref func_ref)4542 static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobserved_start(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4543 ir_ref run_time_cache;
4544 struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4545 if (func) {
4546 ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4547 } else {
4548 // JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4549 ZEND_ASSERT(rx != IR_UNUSED);
4550 ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4551 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4552 ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4553 ir_IF_TRUE(if_trampoline_or_generator);
4554 ir_END_list(data.ir_end_inputs);
4555 ir_IF_FALSE(if_trampoline_or_generator);
4556 }
4557 if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4558 // JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4559 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)), (uintptr_t)ZEND_MAP_PTR(func->common.run_time_cache)));
4560 #ifndef ZTS
4561 } else if (func && rx == IS_UNUSED) { // happens for internal functions only
4562 ZEND_ASSERT(!ZEND_USER_CODE(func->type));
4563 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4564 #endif
4565 } else {
4566 // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4567 if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4568 run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4569 } else {
4570 // JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4571 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4572 ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4573 ir_IF_TRUE(if_odd);
4574
4575 ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4576
4577 ir_ref if_odd_end = ir_END();
4578 ir_IF_FALSE(if_odd);
4579
4580 // JIT: if (func->common.runtime_cache != NULL) {
4581 ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4582 ir_IF_TRUE(if_rt_cache);
4583 ir_END_list(data.ir_end_inputs);
4584 ir_IF_FALSE(if_rt_cache);
4585
4586 ir_MERGE_WITH(if_odd_end);
4587 run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4588 }
4589 }
4590 // JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4591 if (func) {
4592 *observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4593 } else {
4594 // JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4595 ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4596 ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4597 ir_IF_TRUE(if_internal_func);
4598
4599 ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4600
4601 ir_ref if_internal_func_end = ir_END();
4602 ir_IF_FALSE(if_internal_func);
4603
4604 ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4605
4606 ir_MERGE_WITH(if_internal_func_end);
4607 *observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
4608 }
4609
4610 // JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4611 data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4612 ir_IF_FALSE(data.if_unobserved);
4613 return data;
4614 }
4615
4616 /* For frameless the true branch of if_unobserved is used and this function not called. */
jit_observer_fcall_is_unobserved_end(zend_jit_ctx * jit,struct jit_observer_fcall_is_unobserved_data * data)4617 static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4618 ir_END_list(data->ir_end_inputs);
4619 ir_IF_TRUE(data->if_unobserved);
4620 ir_END_list(data->ir_end_inputs);
4621 ir_MERGE_list(data->ir_end_inputs);
4622 }
4623
jit_observer_fcall_begin(zend_jit_ctx * jit,ir_ref rx,ir_ref observer_handler)4624 static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4625 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4626 }
4627
jit_observer_fcall_end(zend_jit_ctx * jit,ir_ref rx,ir_ref res_ref)4628 static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4629 // JIT: if (execute_data == EG(current_observed_frame)) {
4630 ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4631 ir_IF_TRUE(has_end_observer);
4632 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4633 rx, res_ref);
4634 ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4635 }
4636
zend_jit_inc_dec(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint32_t op1_def_info,zend_jit_addr op1_def_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr,int may_overflow,int may_throw)4637 static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
4638 {
4639 ir_ref if_long = IR_UNUSED;
4640 ir_ref op1_lval_ref = IR_UNUSED;
4641 ir_ref ref;
4642 ir_op op;
4643
4644 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4645 if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4646 ir_IF_TRUE(if_long);
4647 }
4648 if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4649 op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4650 jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4651 if (Z_MODE(res_addr) != IS_REG) {
4652 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4653 }
4654 }
4655 if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4656 && Z_MODE(op1_addr) == IS_REG
4657 && !Z_LOAD(op1_addr)
4658 && !Z_STORE(op1_addr)) {
4659 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4660 }
4661 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4662 op = may_overflow ? IR_ADD_OV : IR_ADD;
4663 } else {
4664 op = may_overflow ? IR_SUB_OV : IR_SUB;
4665 }
4666 if (!op1_lval_ref) {
4667 op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4668 }
4669 ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4670 if (op1_def_info & MAY_BE_LONG) {
4671 jit_set_Z_LVAL(jit, op1_def_addr, ref);
4672 }
4673 if (may_overflow &&
4674 (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4675 ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4676 int32_t exit_point;
4677 const void *exit_addr;
4678 zend_jit_trace_stack *stack;
4679 uint32_t old_op1_info, old_res_info = 0;
4680
4681 stack = JIT_G(current_frame)->stack;
4682 old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4683 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4684 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4685 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4686 } else {
4687 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4688 }
4689 if (opline->result_type != IS_UNUSED) {
4690 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4691 if (opline->opcode == ZEND_PRE_INC) {
4692 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4693 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4694 } else if (opline->opcode == ZEND_PRE_DEC) {
4695 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4696 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4697 } else if (opline->opcode == ZEND_POST_INC) {
4698 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4699 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MAX));
4700 } else if (opline->opcode == ZEND_POST_DEC) {
4701 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4702 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MIN));
4703 }
4704 }
4705
4706 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4707 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4708 ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4709
4710 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4711 opline->result_type != IS_UNUSED) {
4712 jit_set_Z_LVAL(jit, res_addr, ref);
4713 if (Z_MODE(res_addr) != IS_REG) {
4714 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4715 }
4716 }
4717
4718 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4719 if (opline->result_type != IS_UNUSED) {
4720 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4721 }
4722 } else if (may_overflow) {
4723 ir_ref if_overflow;
4724 ir_ref merge_inputs = IR_UNUSED;
4725
4726 if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4727 || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4728 int32_t exit_point;
4729 const void *exit_addr;
4730 zend_jit_trace_stack *stack;
4731 uint32_t old_res_info = 0;
4732
4733 stack = JIT_G(current_frame)->stack;
4734 if (opline->result_type != IS_UNUSED) {
4735 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4736 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4737 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4738 }
4739 }
4740 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4741 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4742 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4743 opline->result_type != IS_UNUSED) {
4744 if_overflow = ir_IF(ir_OVERFLOW(ref));
4745 ir_IF_FALSE_cold(if_overflow);
4746 jit_set_Z_LVAL(jit, res_addr, ref);
4747 if (Z_MODE(res_addr) != IS_REG) {
4748 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4749 }
4750 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
4751 ir_IF_TRUE(if_overflow);
4752 } else {
4753 ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4754 }
4755 if (opline->result_type != IS_UNUSED) {
4756 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4757 }
4758 } else {
4759 if_overflow = ir_IF(ir_OVERFLOW(ref));
4760 ir_IF_FALSE(if_overflow);
4761 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4762 opline->result_type != IS_UNUSED) {
4763 jit_set_Z_LVAL(jit, res_addr, ref);
4764 if (Z_MODE(res_addr) != IS_REG) {
4765 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4766 }
4767 }
4768 ir_END_list(merge_inputs);
4769
4770 /* overflow => cold path */
4771 ir_IF_TRUE_cold(if_overflow);
4772 }
4773
4774 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4775 if (Z_MODE(op1_def_addr) == IS_REG) {
4776 jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4777 } else {
4778 #if SIZEOF_ZEND_LONG == 4
4779 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0));
4780 jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0x41e00000));
4781 #else
4782 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4783 #endif
4784 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4785 }
4786 } else {
4787 if (Z_MODE(op1_def_addr) == IS_REG) {
4788 jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4789 } else {
4790 #if SIZEOF_ZEND_LONG == 4
4791 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x00200000));
4792 jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0xc1e00000));
4793 #else
4794 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4795 #endif
4796 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4797 }
4798 }
4799 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4800 opline->result_type != IS_UNUSED) {
4801 if (opline->opcode == ZEND_PRE_INC) {
4802 if (Z_MODE(res_addr) == IS_REG) {
4803 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4804 } else {
4805 #if SIZEOF_ZEND_LONG == 4
4806 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
4807 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
4808 #else
4809 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4810 #endif
4811 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4812 }
4813 } else {
4814 if (Z_MODE(res_addr) == IS_REG) {
4815 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4816 } else {
4817 #if SIZEOF_ZEND_LONG == 4
4818 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
4819 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
4820 #else
4821 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
4822 #endif
4823 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4824 }
4825 }
4826 }
4827
4828 if (merge_inputs) {
4829 ir_END_list(merge_inputs);
4830 ir_MERGE_list(merge_inputs);
4831 }
4832 } else {
4833 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4834 opline->result_type != IS_UNUSED) {
4835 jit_set_Z_LVAL(jit, res_addr, ref);
4836 if (Z_MODE(res_addr) != IS_REG) {
4837 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4838 }
4839 }
4840 }
4841 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4842 ir_ref merge_inputs = ir_END();
4843
4844 /* !is_long => cold path */
4845 ir_IF_FALSE_cold(if_long);
4846 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4847 jit_SET_EX_OPLINE(jit, opline);
4848 if (op1_info & MAY_BE_UNDEF) {
4849 ir_ref if_def;
4850
4851 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
4852 ir_IF_FALSE_cold(if_def);
4853
4854 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
4855 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
4856
4857 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
4858 ir_MERGE_WITH_EMPTY_TRUE(if_def);
4859
4860 op1_info |= MAY_BE_NULL;
4861 }
4862
4863 ref = jit_ZVAL_ADDR(jit, op1_addr);
4864
4865 if (op1_info & MAY_BE_REF) {
4866 ir_ref if_ref, if_typed, func, ref2, arg2;
4867
4868 if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
4869 ir_IF_TRUE(if_ref);
4870 ref2 = jit_Z_PTR_ref(jit, ref);
4871
4872 if_typed = jit_if_TYPED_REF(jit, ref2);
4873 ir_IF_TRUE(if_typed);
4874
4875 if (RETURN_VALUE_USED(opline)) {
4876 ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
4877 arg2 = jit_ZVAL_ADDR(jit, res_addr);
4878 } else {
4879 arg2 = IR_NULL;
4880 }
4881 if (opline->opcode == ZEND_PRE_INC) {
4882 func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
4883 } else if (opline->opcode == ZEND_PRE_DEC) {
4884 func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
4885 } else if (opline->opcode == ZEND_POST_INC) {
4886 func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
4887 } else if (opline->opcode == ZEND_POST_DEC) {
4888 func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
4889 } else {
4890 ZEND_UNREACHABLE();
4891 }
4892
4893 ir_CALL_2(IR_VOID, func, ref2, arg2);
4894 zend_jit_check_exception(jit);
4895 ir_END_list(merge_inputs);
4896
4897 ir_IF_FALSE(if_typed);
4898 ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
4899 ir_MERGE_WITH_EMPTY_FALSE(if_ref);
4900 ref = ir_PHI_2(IR_ADDR, ref2, ref);
4901 }
4902
4903 if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4904 jit_ZVAL_COPY(jit,
4905 res_addr,
4906 res_use_info,
4907 ZEND_ADDR_REF_ZVAL(ref), op1_info, 1);
4908 }
4909 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4910 if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
4911 ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4912 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
4913 } else {
4914 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function), ref);
4915 }
4916 } else {
4917 if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
4918 ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
4919 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec), ref, arg2);
4920 } else {
4921 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function), ref);
4922 }
4923 }
4924 if (may_throw) {
4925 zend_jit_check_exception(jit);
4926 }
4927 } else {
4928 ref = jit_Z_DVAL(jit, op1_addr);
4929 if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4930 jit_set_Z_DVAL(jit, res_addr, ref);
4931 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4932 }
4933 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4934 op = IR_ADD;
4935 } else {
4936 op = IR_SUB;
4937 }
4938 ref = ir_BINARY_OP_D(op, ref, ir_CONST_DOUBLE(1.0));
4939 jit_set_Z_DVAL(jit, op1_def_addr, ref);
4940 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4941 opline->result_type != IS_UNUSED) {
4942 jit_set_Z_DVAL(jit, res_addr, ref);
4943 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4944 }
4945 }
4946 ir_END_list(merge_inputs);
4947 ir_MERGE_list(merge_inputs);
4948 }
4949 if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
4950 return 0;
4951 }
4952 if (opline->result_type != IS_UNUSED) {
4953 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
4954 return 0;
4955 }
4956 }
4957 return 1;
4958 }
4959
zend_jit_math_long_long(zend_jit_ctx * jit,const zend_op * opline,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_info,uint32_t res_use_info,int may_overflow)4960 static int zend_jit_math_long_long(zend_jit_ctx *jit,
4961 const zend_op *opline,
4962 uint8_t opcode,
4963 zend_jit_addr op1_addr,
4964 zend_jit_addr op2_addr,
4965 zend_jit_addr res_addr,
4966 uint32_t res_info,
4967 uint32_t res_use_info,
4968 int may_overflow)
4969 {
4970 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4971 ir_op op;
4972 ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
4973
4974 if (opcode == ZEND_ADD) {
4975 op = may_overflow ? IR_ADD_OV : IR_ADD;
4976 } else if (opcode == ZEND_SUB) {
4977 op = may_overflow ? IR_SUB_OV : IR_SUB;
4978 } else if (opcode == ZEND_MUL) {
4979 op = may_overflow ? IR_MUL_OV : IR_MUL;
4980 } else {
4981 ZEND_UNREACHABLE();
4982 }
4983 op1 = jit_Z_LVAL(jit, op1_addr);
4984 op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
4985 ref = ir_BINARY_OP_L(op, op1, op2);
4986
4987 if (may_overflow) {
4988 if (res_info & MAY_BE_GUARD) {
4989 if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
4990 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
4991 uint32_t old_res_info;
4992 int32_t exit_point;
4993 const void *exit_addr;
4994
4995 if (opline->opcode == ZEND_ADD
4996 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
4997 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4998 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4999 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5000 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5001 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5002 } else if (opline->opcode == ZEND_SUB
5003 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5004 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5005 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5006 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5007 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5008 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5009 } else {
5010 exit_point = zend_jit_trace_get_exit_point(opline, 0);
5011 }
5012
5013 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5014 if (!exit_addr) {
5015 return 0;
5016 }
5017 ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5018 may_overflow = 0;
5019 } else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
5020 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
5021 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5022
5023 if (!exit_addr) {
5024 return 0;
5025 }
5026 ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5027 } else {
5028 ZEND_UNREACHABLE();
5029 }
5030 } else {
5031 if_overflow = ir_IF(ir_OVERFLOW(ref));
5032 ir_IF_FALSE(if_overflow);
5033 }
5034 }
5035
5036 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5037 jit_set_Z_LVAL(jit, res_addr, ref);
5038
5039 if (Z_MODE(res_addr) != IS_REG) {
5040 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5041 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5042 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5043 }
5044 }
5045 }
5046 }
5047
5048 if (may_overflow) {
5049 ir_ref fast_path = IR_UNUSED;
5050
5051 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5052 fast_path = ir_END();
5053 ir_IF_TRUE_cold(if_overflow);
5054 }
5055 if (opcode == ZEND_ADD) {
5056 if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5057 if (Z_MODE(res_addr) == IS_REG) {
5058 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5059 } else {
5060 #if SIZEOF_ZEND_LONG == 4
5061 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
5062 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
5063 #else
5064 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5065 #endif
5066 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5067 }
5068 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5069 ir_MERGE_WITH(fast_path);
5070 }
5071 return 1;
5072 }
5073 op = IR_ADD;
5074 } else if (opcode == ZEND_SUB) {
5075 if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5076 if (Z_MODE(res_addr) == IS_REG) {
5077 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5078 } else {
5079 #if SIZEOF_ZEND_LONG == 4
5080 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
5081 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
5082 #else
5083 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
5084 #endif
5085 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5086 }
5087 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5088 ir_MERGE_WITH(fast_path);
5089 }
5090 return 1;
5091 }
5092 op = IR_SUB;
5093 } else if (opcode == ZEND_MUL) {
5094 op = IR_MUL;
5095 } else {
5096 ZEND_UNREACHABLE();
5097 }
5098 #if 1
5099 /* reload */
5100 op1 = jit_Z_LVAL(jit, op1_addr);
5101 op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5102 #endif
5103 #if 1
5104 /* disable CSE */
5105 ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5106 jit->ctx.fold_cse_limit = 0x7fffffff;
5107 #endif
5108 op1 = ir_INT2D(op1);
5109 op2 = ir_INT2D(op2);
5110 #if 1
5111 jit->ctx.fold_cse_limit = old_cse_limit;
5112 #endif
5113 ref = ir_BINARY_OP_D(op, op1, op2);
5114 jit_set_Z_DVAL(jit, res_addr, ref);
5115 if (Z_MODE(res_addr) != IS_REG) {
5116 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5117 }
5118 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5119 ir_MERGE_WITH(fast_path);
5120 }
5121 }
5122
5123 return 1;
5124 }
5125
zend_jit_math_long_double(zend_jit_ctx * jit,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_use_info)5126 static int zend_jit_math_long_double(zend_jit_ctx *jit,
5127 uint8_t opcode,
5128 zend_jit_addr op1_addr,
5129 zend_jit_addr op2_addr,
5130 zend_jit_addr res_addr,
5131 uint32_t res_use_info)
5132 {
5133 ir_op op;
5134 ir_ref op1, op2, ref;
5135
5136 if (opcode == ZEND_ADD) {
5137 op = IR_ADD;
5138 } else if (opcode == ZEND_SUB) {
5139 op = IR_SUB;
5140 } else if (opcode == ZEND_MUL) {
5141 op = IR_MUL;
5142 } else if (opcode == ZEND_DIV) {
5143 op = IR_DIV;
5144 } else {
5145 ZEND_UNREACHABLE();
5146 }
5147 op1 = jit_Z_LVAL(jit, op1_addr);
5148 op2 = jit_Z_DVAL(jit, op2_addr);
5149 ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5150 jit_set_Z_DVAL(jit, res_addr, ref);
5151
5152 if (Z_MODE(res_addr) != IS_REG) {
5153 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5154 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5155 }
5156 }
5157 return 1;
5158 }
5159
zend_jit_math_double_long(zend_jit_ctx * jit,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_use_info)5160 static int zend_jit_math_double_long(zend_jit_ctx *jit,
5161 uint8_t opcode,
5162 zend_jit_addr op1_addr,
5163 zend_jit_addr op2_addr,
5164 zend_jit_addr res_addr,
5165 uint32_t res_use_info)
5166 {
5167 ir_op op;
5168 ir_ref op1, op2, ref;
5169
5170 if (opcode == ZEND_ADD) {
5171 op = IR_ADD;
5172 } else if (opcode == ZEND_SUB) {
5173 op = IR_SUB;
5174 } else if (opcode == ZEND_MUL) {
5175 op = IR_MUL;
5176 } else if (opcode == ZEND_DIV) {
5177 op = IR_DIV;
5178 } else {
5179 ZEND_UNREACHABLE();
5180 }
5181 op1 = jit_Z_DVAL(jit, op1_addr);
5182 op2 = jit_Z_LVAL(jit, op2_addr);
5183 ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5184 jit_set_Z_DVAL(jit, res_addr, ref);
5185
5186 if (Z_MODE(res_addr) != IS_REG) {
5187 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5188 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5189 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5190 }
5191 }
5192 }
5193 return 1;
5194 }
5195
zend_jit_math_double_double(zend_jit_ctx * jit,uint8_t opcode,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint32_t res_use_info)5196 static int zend_jit_math_double_double(zend_jit_ctx *jit,
5197 uint8_t opcode,
5198 zend_jit_addr op1_addr,
5199 zend_jit_addr op2_addr,
5200 zend_jit_addr res_addr,
5201 uint32_t res_use_info)
5202 {
5203 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5204 ir_op op;
5205 ir_ref op1, op2, ref;
5206
5207 if (opcode == ZEND_ADD) {
5208 op = IR_ADD;
5209 } else if (opcode == ZEND_SUB) {
5210 op = IR_SUB;
5211 } else if (opcode == ZEND_MUL) {
5212 op = IR_MUL;
5213 } else if (opcode == ZEND_DIV) {
5214 op = IR_DIV;
5215 } else {
5216 ZEND_UNREACHABLE();
5217 }
5218 op1 = jit_Z_DVAL(jit, op1_addr);
5219 op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5220 ref = ir_BINARY_OP_D(op, op1, op2);
5221 jit_set_Z_DVAL(jit, res_addr, ref);
5222
5223 if (Z_MODE(res_addr) != IS_REG) {
5224 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5225 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5226 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5227 }
5228 }
5229 }
5230 return 1;
5231 }
5232
zend_jit_math_helper(zend_jit_ctx * jit,const zend_op * opline,uint8_t opcode,uint8_t op1_type,znode_op op1,zend_jit_addr op1_addr,uint32_t op1_info,uint8_t op2_type,znode_op op2,zend_jit_addr op2_addr,uint32_t op2_info,uint32_t res_var,zend_jit_addr res_addr,uint32_t res_info,uint32_t res_use_info,int may_overflow,int may_throw)5233 static int zend_jit_math_helper(zend_jit_ctx *jit,
5234 const zend_op *opline,
5235 uint8_t opcode,
5236 uint8_t op1_type,
5237 znode_op op1,
5238 zend_jit_addr op1_addr,
5239 uint32_t op1_info,
5240 uint8_t op2_type,
5241 znode_op op2,
5242 zend_jit_addr op2_addr,
5243 uint32_t op2_info,
5244 uint32_t res_var,
5245 zend_jit_addr res_addr,
5246 uint32_t res_info,
5247 uint32_t res_use_info,
5248 int may_overflow,
5249 int may_throw)
5250 {
5251 ir_ref if_op1_long = IR_UNUSED;
5252 ir_ref if_op1_double = IR_UNUSED;
5253 ir_ref if_op2_double = IR_UNUSED;
5254 ir_ref if_op1_long_op2_long = IR_UNUSED;
5255 ir_ref if_op1_long_op2_double = IR_UNUSED;
5256 ir_ref if_op1_double_op2_double = IR_UNUSED;
5257 ir_ref if_op1_double_op2_long = IR_UNUSED;
5258 ir_ref slow_inputs = IR_UNUSED;
5259 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5260 ir_refs *end_inputs;
5261 ir_refs *res_inputs;
5262
5263 ir_refs_init(end_inputs, 6);
5264 ir_refs_init(res_inputs, 6);
5265
5266 if (Z_MODE(op1_addr) == IS_REG) {
5267 if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5268 /* Force load */
5269 zend_jit_use_reg(jit, op1_addr);
5270 }
5271 } else if (Z_MODE(op2_addr) == IS_REG) {
5272 if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5273 /* Force load */
5274 zend_jit_use_reg(jit, op2_addr);
5275 }
5276 }
5277
5278 if (Z_MODE(res_addr) == IS_REG) {
5279 jit->delay_var = Z_SSA_VAR(res_addr);
5280 jit->delay_refs = res_inputs;
5281 }
5282
5283 if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5284 if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5285 if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5286 ir_IF_TRUE(if_op1_long);
5287 }
5288 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5289 if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5290 ir_IF_TRUE(if_op1_long_op2_long);
5291 }
5292 if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5293 return 0;
5294 }
5295 ir_refs_add(end_inputs, ir_END());
5296 if (if_op1_long) {
5297 ir_IF_FALSE_cold(if_op1_long);
5298 ir_END_list(slow_inputs);
5299 }
5300 if (if_op1_long_op2_long) {
5301 ir_IF_FALSE_cold(if_op1_long_op2_long);
5302 ir_END_list(slow_inputs);
5303 }
5304 } else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
5305 if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5306 if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5307 ir_IF_TRUE(if_op1_long);
5308 }
5309 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5310 if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5311 ir_IF_FALSE_cold(if_op1_long_op2_long);
5312 if (op2_info & MAY_BE_DOUBLE) {
5313 if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5314 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5315 ir_IF_FALSE_cold(if_op1_long_op2_double);
5316 ir_END_list(slow_inputs);
5317 ir_IF_TRUE(if_op1_long_op2_double);
5318 }
5319 if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5320 return 0;
5321 }
5322 ir_refs_add(end_inputs, ir_END());
5323 } else {
5324 ir_END_list(slow_inputs);
5325 }
5326 ir_IF_TRUE(if_op1_long_op2_long);
5327 }
5328 if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5329 return 0;
5330 }
5331 ir_refs_add(end_inputs, ir_END());
5332
5333 if (if_op1_long) {
5334 ir_IF_FALSE_cold(if_op1_long);
5335 }
5336
5337 if (op1_info & MAY_BE_DOUBLE) {
5338 if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5339 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5340 ir_IF_FALSE_cold(if_op1_double);
5341 ir_END_list(slow_inputs);
5342 ir_IF_TRUE(if_op1_double);
5343 }
5344 if (op2_info & MAY_BE_DOUBLE) {
5345 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5346 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5347 ir_IF_TRUE(if_op1_double_op2_double);
5348 }
5349 if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5350 return 0;
5351 }
5352 ir_refs_add(end_inputs, ir_END());
5353 if (if_op1_double_op2_double) {
5354 ir_IF_FALSE_cold(if_op1_double_op2_double);
5355 }
5356 }
5357 if (!same_ops) {
5358 if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5359 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5360 ir_IF_FALSE_cold(if_op1_double_op2_long);
5361 ir_END_list(slow_inputs);
5362 ir_IF_TRUE(if_op1_double_op2_long);
5363 }
5364 if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5365 return 0;
5366 }
5367 ir_refs_add(end_inputs, ir_END());
5368 } else if (if_op1_double_op2_double) {
5369 ir_END_list(slow_inputs);
5370 }
5371 } else if (if_op1_long) {
5372 ir_END_list(slow_inputs);
5373 }
5374 } else if ((op1_info & MAY_BE_DOUBLE) &&
5375 !(op1_info & MAY_BE_LONG) &&
5376 (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5377 (res_info & MAY_BE_DOUBLE)) {
5378 if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5379 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5380 ir_IF_FALSE_cold(if_op1_double);
5381 ir_END_list(slow_inputs);
5382 ir_IF_TRUE(if_op1_double);
5383 }
5384 if (op2_info & MAY_BE_DOUBLE) {
5385 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5386 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5387 ir_IF_TRUE(if_op1_double_op2_double);
5388 }
5389 if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5390 return 0;
5391 }
5392 ir_refs_add(end_inputs, ir_END());
5393 if (if_op1_double_op2_double) {
5394 ir_IF_FALSE_cold(if_op1_double_op2_double);
5395 }
5396 }
5397 if (!same_ops && (op2_info & MAY_BE_LONG)) {
5398 if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5399 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5400 ir_IF_FALSE_cold(if_op1_double_op2_long);
5401 ir_END_list(slow_inputs);
5402 ir_IF_TRUE(if_op1_double_op2_long);
5403 }
5404 if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5405 return 0;
5406 }
5407 ir_refs_add(end_inputs, ir_END());
5408 } else if (if_op1_double_op2_double) {
5409 ir_END_list(slow_inputs);
5410 }
5411 } else if ((op2_info & MAY_BE_DOUBLE) &&
5412 !(op2_info & MAY_BE_LONG) &&
5413 (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5414 (res_info & MAY_BE_DOUBLE)) {
5415 if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5416 if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5417 ir_IF_FALSE_cold(if_op2_double);
5418 ir_END_list(slow_inputs);
5419 ir_IF_TRUE(if_op2_double);
5420 }
5421 if (op1_info & MAY_BE_DOUBLE) {
5422 if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5423 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5424 ir_IF_TRUE(if_op1_double_op2_double);
5425 }
5426 if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5427 return 0;
5428 }
5429 ir_refs_add(end_inputs, ir_END());
5430 if (if_op1_double_op2_double) {
5431 ir_IF_FALSE_cold(if_op1_double_op2_double);
5432 }
5433 }
5434 if (!same_ops && (op1_info & MAY_BE_LONG)) {
5435 if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5436 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5437 ir_IF_FALSE_cold(if_op1_long_op2_double);
5438 ir_END_list(slow_inputs);
5439 ir_IF_TRUE(if_op1_long_op2_double);
5440 }
5441 if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5442 return 0;
5443 }
5444 ir_refs_add(end_inputs, ir_END());
5445 } else if (if_op1_double_op2_double) {
5446 ir_END_list(slow_inputs);
5447 }
5448 }
5449
5450 if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5451 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5452 ir_ref func, arg1, arg2, arg3;
5453
5454 if (slow_inputs) {
5455 ir_MERGE_list(slow_inputs);
5456 }
5457
5458 if (Z_MODE(op1_addr) == IS_REG) {
5459 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5460 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5461 return 0;
5462 }
5463 op1_addr = real_addr;
5464 }
5465 if (Z_MODE(op2_addr) == IS_REG) {
5466 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5467 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5468 return 0;
5469 }
5470 op2_addr = real_addr;
5471 }
5472 if (Z_MODE(res_addr) == IS_REG) {
5473 arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5474 } else {
5475 arg1 = jit_ZVAL_ADDR(jit, res_addr);
5476 }
5477 arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5478 arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5479 jit_SET_EX_OPLINE(jit, opline);
5480 if (opcode == ZEND_ADD) {
5481 func = ir_CONST_FC_FUNC(add_function);
5482 } else if (opcode == ZEND_SUB) {
5483 func = ir_CONST_FC_FUNC(sub_function);
5484 } else if (opcode == ZEND_MUL) {
5485 func = ir_CONST_FC_FUNC(mul_function);
5486 } else if (opcode == ZEND_DIV) {
5487 func = ir_CONST_FC_FUNC(div_function);
5488 } else {
5489 ZEND_UNREACHABLE();
5490 }
5491 ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5492
5493 jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5494 jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5495
5496 if (may_throw) {
5497 if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5498 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5499 jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5500 } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5501 zend_jit_check_exception_undef_result(jit, opline);
5502 } else {
5503 zend_jit_check_exception(jit);
5504 }
5505 }
5506 if (Z_MODE(res_addr) == IS_REG) {
5507 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5508 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5509 return 0;
5510 }
5511 }
5512 ir_refs_add(end_inputs, ir_END());
5513 }
5514
5515 if (end_inputs->count) {
5516 ir_MERGE_N(end_inputs->count, end_inputs->refs);
5517 }
5518
5519 if (Z_MODE(res_addr) == IS_REG) {
5520 ZEND_ASSERT(jit->delay_refs == res_inputs);
5521 ZEND_ASSERT(end_inputs->count == res_inputs->count);
5522 jit->delay_var = -1;
5523 jit->delay_refs = NULL;
5524 if (res_inputs->count == 1) {
5525 zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5526 } else {
5527 ir_ref phi = ir_PHI_N((res_info & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE, res_inputs->count, res_inputs->refs);
5528 zend_jit_def_reg(jit, res_addr, phi);
5529 }
5530 }
5531
5532 return 1;
5533 }
5534
zend_jit_math(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint32_t op2_info,zend_jit_addr op2_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr,int may_overflow,int may_throw)5535 static int zend_jit_math(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
5536 {
5537 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5538
5539 if (!zend_jit_math_helper(jit, opline, opline->opcode, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->result.var, res_addr, res_info, res_use_info, may_overflow, may_throw)) {
5540 return 0;
5541 }
5542 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5543 return 0;
5544 }
5545 return 1;
5546 }
5547
zend_jit_add_arrays(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint32_t op2_info,zend_jit_addr op2_addr,zend_jit_addr res_addr)5548 static int zend_jit_add_arrays(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr)
5549 {
5550 ir_ref ref;
5551 ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5552 ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5553
5554 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5555 jit_set_Z_PTR(jit, res_addr, ref);
5556 jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5557 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5558 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5559 return 1;
5560 }
5561
zend_jit_long_math_helper(zend_jit_ctx * jit,const zend_op * opline,uint8_t opcode,uint8_t op1_type,znode_op op1,zend_jit_addr op1_addr,uint32_t op1_info,zend_ssa_range * op1_range,uint8_t op2_type,znode_op op2,zend_jit_addr op2_addr,uint32_t op2_info,zend_ssa_range * op2_range,uint32_t res_var,zend_jit_addr res_addr,uint32_t res_info,uint32_t res_use_info,int may_throw)5562 static int zend_jit_long_math_helper(zend_jit_ctx *jit,
5563 const zend_op *opline,
5564 uint8_t opcode,
5565 uint8_t op1_type,
5566 znode_op op1,
5567 zend_jit_addr op1_addr,
5568 uint32_t op1_info,
5569 zend_ssa_range *op1_range,
5570 uint8_t op2_type,
5571 znode_op op2,
5572 zend_jit_addr op2_addr,
5573 uint32_t op2_info,
5574 zend_ssa_range *op2_range,
5575 uint32_t res_var,
5576 zend_jit_addr res_addr,
5577 uint32_t res_info,
5578 uint32_t res_use_info,
5579 int may_throw)
5580 {
5581 ir_ref ref = IR_UNUSED;
5582 ir_ref if_long1 = IR_UNUSED;
5583 ir_ref if_long2 = IR_UNUSED;
5584 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5585 ir_refs *res_inputs;
5586
5587 ir_refs_init(res_inputs, 2);
5588
5589 if (Z_MODE(op1_addr) == IS_REG
5590 && Z_LOAD(op1_addr)
5591 && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5592 /* Force load */
5593 zend_jit_use_reg(jit, op1_addr);
5594 }
5595 if (Z_MODE(op2_addr) == IS_REG
5596 && Z_LOAD(op2_addr)
5597 && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5598 /* Force load */
5599 zend_jit_use_reg(jit, op2_addr);
5600 }
5601
5602 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5603 if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5604 ir_IF_TRUE(if_long1);
5605 }
5606 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5607 if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5608 ir_IF_TRUE(if_long2);
5609 }
5610
5611 if (opcode == ZEND_SL) {
5612 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5613 zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5614
5615 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5616 if (EXPECTED(op2_lval > 0)) {
5617 ref = ir_CONST_LONG(0);
5618 } else {
5619 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5620 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5621 jit_SET_EX_OPLINE(jit, opline);
5622 ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5623 if (Z_MODE(res_addr) == IS_REG) {
5624 ref = ir_CONST_LONG(0); // dead code
5625 }
5626 }
5627 } else {
5628 ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5629 }
5630 } else {
5631 ref = jit_Z_LVAL(jit, op2_addr);
5632 if (!op2_range ||
5633 op2_range->min < 0 ||
5634 op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5635
5636 ir_ref if_wrong, cold_path, ref2, if_ok;
5637 ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5638
5639 if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5640 ir_IF_TRUE_cold(if_wrong);
5641 if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5642 ir_IF_FALSE(if_ok);
5643 jit_SET_EX_OPLINE(jit, opline);
5644 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5645 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5646 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5647 ir_IF_TRUE(if_ok);
5648 ref2 = ir_CONST_LONG(0);
5649 cold_path = ir_END();
5650 ir_IF_FALSE(if_wrong);
5651 ref = ir_SHL_L(op1_ref, ref);
5652 ir_MERGE_WITH(cold_path);
5653 ref = ir_PHI_2(IR_LONG, ref, ref2);
5654 } else {
5655 ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5656 }
5657 }
5658 } else if (opcode == ZEND_SR) {
5659 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5660 zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5661
5662 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5663 if (EXPECTED(op2_lval > 0)) {
5664 ref = ir_SAR_L(
5665 jit_Z_LVAL(jit, op1_addr),
5666 ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5667 } else {
5668 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5669 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5670 jit_SET_EX_OPLINE(jit, opline);
5671 ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5672 if (Z_MODE(res_addr) == IS_REG) {
5673 ref = ir_CONST_LONG(0); // dead code
5674 }
5675 }
5676 } else {
5677 ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5678 }
5679 } else {
5680 ref = jit_Z_LVAL(jit, op2_addr);
5681 if (!op2_range ||
5682 op2_range->min < 0 ||
5683 op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5684
5685 ir_ref if_wrong, cold_path, ref2, if_ok;
5686
5687 if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5688 ir_IF_TRUE_cold(if_wrong);
5689 if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5690 ir_IF_FALSE(if_ok);
5691 jit_SET_EX_OPLINE(jit, opline);
5692 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5693 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5694 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5695 ir_IF_TRUE(if_ok);
5696 ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5697 cold_path = ir_END();
5698 ir_IF_FALSE(if_wrong);
5699 ir_MERGE_WITH(cold_path);
5700 ref = ir_PHI_2(IR_LONG, ref, ref2);
5701 }
5702 ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5703 }
5704 } else if (opcode == ZEND_MOD) {
5705 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5706 zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5707
5708 if (op2_lval == 0) {
5709 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5710 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5711 jit_SET_EX_OPLINE(jit, opline);
5712 ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5713 if (Z_MODE(res_addr) == IS_REG) {
5714 ref = ir_CONST_LONG(0); // dead code
5715 }
5716 } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5717 ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5718 } else {
5719 ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5720 }
5721 } else {
5722 ir_ref zero_path = 0;
5723 ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5724
5725 ref = jit_Z_LVAL(jit, op2_addr);
5726 if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5727 ir_ref if_ok = ir_IF(ref);
5728 ir_IF_FALSE(if_ok);
5729 jit_SET_EX_OPLINE(jit, opline);
5730 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5731 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5732 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5733 ir_IF_TRUE(if_ok);
5734 }
5735
5736 /* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5737 if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5738 ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5739 ir_IF_TRUE_cold(if_minus_one);
5740 zero_path = ir_END();
5741 ir_IF_FALSE(if_minus_one);
5742 }
5743 ref = ir_MOD_L(op1_ref, ref);
5744
5745 if (zero_path) {
5746 ir_MERGE_WITH(zero_path);
5747 ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5748 }
5749 }
5750 } else {
5751 ir_op op;
5752 ir_ref op1, op2;
5753
5754 if (opcode == ZEND_BW_OR) {
5755 op = IR_OR;
5756 } else if (opcode == ZEND_BW_AND) {
5757 op = IR_AND;
5758 } else if (opcode == ZEND_BW_XOR) {
5759 op = IR_XOR;
5760 } else {
5761 ZEND_UNREACHABLE();
5762 }
5763 op1 = jit_Z_LVAL(jit, op1_addr);
5764 op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5765 ref = ir_BINARY_OP_L(op, op1, op2);
5766 }
5767
5768 if (ref) {
5769 if (Z_MODE(res_addr) == IS_REG
5770 && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5771 || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5772 jit->delay_var = Z_SSA_VAR(res_addr);
5773 jit->delay_refs = res_inputs;
5774 }
5775 jit_set_Z_LVAL(jit, res_addr, ref);
5776 if (Z_MODE(res_addr) != IS_REG) {
5777 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5778 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5779 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5780 }
5781 }
5782 }
5783 }
5784
5785 if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5786 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5787 ir_ref fast_path = ir_END();
5788 ir_ref func, arg1, arg2, arg3;
5789
5790 if (if_long2 && if_long1) {
5791 ir_ref ref;
5792 ir_IF_FALSE_cold(if_long2);
5793 ref = ir_END();
5794 ir_IF_FALSE_cold(if_long1);
5795 ir_MERGE_2(ref, ir_END());
5796 } else if (if_long1) {
5797 ir_IF_FALSE_cold(if_long1);
5798 } else if (if_long2) {
5799 ir_IF_FALSE_cold(if_long2);
5800 }
5801
5802 if (op1_info & MAY_BE_UNDEF) {
5803 ir_ref if_def, ref, ref2;
5804
5805 ref = jit_ZVAL_ADDR(jit, op1_addr);
5806 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5807 ir_IF_FALSE_cold(if_def);
5808
5809 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5810 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5811
5812 ref2 = jit_EG(uninitialized_zval);
5813 ir_MERGE_WITH_EMPTY_TRUE(if_def);
5814 ref = ir_PHI_2(IR_ADDR, ref2, ref);
5815 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5816 }
5817
5818 if (op2_info & MAY_BE_UNDEF) {
5819 ir_ref if_def, ref, ref2;
5820
5821 ref = jit_ZVAL_ADDR(jit, op2_addr);
5822 if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5823 ir_IF_FALSE_cold(if_def);
5824
5825 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
5826 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
5827
5828 ref2 = jit_EG(uninitialized_zval);
5829 ir_MERGE_WITH_EMPTY_TRUE(if_def);
5830 ref = ir_PHI_2(IR_ADDR, ref2, ref);
5831 op2_addr = ZEND_ADDR_REF_ZVAL(ref);
5832 }
5833
5834 if (Z_MODE(op1_addr) == IS_REG) {
5835 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5836 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5837 return 0;
5838 }
5839 op1_addr = real_addr;
5840 }
5841 if (Z_MODE(op2_addr) == IS_REG) {
5842 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5843 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5844 return 0;
5845 }
5846 op2_addr = real_addr;
5847 }
5848 if (Z_MODE(res_addr) == IS_REG) {
5849 arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5850 } else {
5851 arg1 = jit_ZVAL_ADDR(jit, res_addr);
5852 }
5853 arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5854 arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5855 jit_SET_EX_OPLINE(jit, opline);
5856 if (opcode == ZEND_BW_OR) {
5857 func = ir_CONST_FC_FUNC(bitwise_or_function);
5858 } else if (opcode == ZEND_BW_AND) {
5859 func = ir_CONST_FC_FUNC(bitwise_and_function);
5860 } else if (opcode == ZEND_BW_XOR) {
5861 func = ir_CONST_FC_FUNC(bitwise_xor_function);
5862 } else if (opcode == ZEND_SL) {
5863 func = ir_CONST_FC_FUNC(shift_left_function);
5864 } else if (opcode == ZEND_SR) {
5865 func = ir_CONST_FC_FUNC(shift_right_function);
5866 } else if (opcode == ZEND_MOD) {
5867 func = ir_CONST_FC_FUNC(mod_function);
5868 } else {
5869 ZEND_UNREACHABLE();
5870 }
5871 ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5872
5873 if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5874 /* compound assignment may decrement "op2" refcount */
5875 op2_info |= MAY_BE_RC1;
5876 }
5877
5878 jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5879 jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5880
5881 if (may_throw) {
5882 if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5883 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5884 jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5885 } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5886 zend_jit_check_exception_undef_result(jit, opline);
5887 } else {
5888 zend_jit_check_exception(jit);
5889 }
5890 }
5891
5892 if (Z_MODE(res_addr) == IS_REG) {
5893 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5894 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5895 return 0;
5896 }
5897 }
5898
5899 ir_MERGE_2(fast_path, ir_END());
5900
5901 if (Z_MODE(res_addr) == IS_REG) {
5902 ZEND_ASSERT(jit->delay_refs == res_inputs);
5903 ZEND_ASSERT(res_inputs->count == 2);
5904 jit->delay_var = -1;
5905 jit->delay_refs = NULL;
5906 if (res_inputs->count == 1) {
5907 zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5908 } else {
5909 ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
5910 zend_jit_def_reg(jit, res_addr, phi);
5911 }
5912 }
5913 }
5914
5915 return 1;
5916 }
5917
zend_jit_long_math(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_ssa_range * op1_range,zend_jit_addr op1_addr,uint32_t op2_info,zend_ssa_range * op2_range,zend_jit_addr op2_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr,int may_throw)5918 static int zend_jit_long_math(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
5919 {
5920 ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
5921
5922 if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
5923 opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
5924 opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
5925 opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
5926 return 0;
5927 }
5928 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5929 return 0;
5930 }
5931 return 1;
5932 }
5933
zend_jit_concat_helper(zend_jit_ctx * jit,const zend_op * opline,uint8_t op1_type,znode_op op1,zend_jit_addr op1_addr,uint32_t op1_info,uint8_t op2_type,znode_op op2,zend_jit_addr op2_addr,uint32_t op2_info,zend_jit_addr res_addr,int may_throw)5934 static int zend_jit_concat_helper(zend_jit_ctx *jit,
5935 const zend_op *opline,
5936 uint8_t op1_type,
5937 znode_op op1,
5938 zend_jit_addr op1_addr,
5939 uint32_t op1_info,
5940 uint8_t op2_type,
5941 znode_op op2,
5942 zend_jit_addr op2_addr,
5943 uint32_t op2_info,
5944 zend_jit_addr res_addr,
5945 int may_throw)
5946 {
5947 ir_ref if_op1_string = IR_UNUSED;
5948 ir_ref if_op2_string = IR_UNUSED;
5949 ir_ref fast_path = IR_UNUSED;
5950
5951 if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5952 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5953 if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
5954 ir_IF_TRUE(if_op1_string);
5955 }
5956 if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5957 if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
5958 ir_IF_TRUE(if_op2_string);
5959 }
5960 if (zend_jit_same_addr(op1_addr, res_addr)) {
5961 ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5962 ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
5963
5964 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
5965 /* concatenation with itself may reduce refcount */
5966 op2_info |= MAY_BE_RC1;
5967 } else {
5968 ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5969 ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5970 ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5971
5972 if (op1_type == IS_CV || op1_type == IS_CONST) {
5973 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
5974 } else {
5975 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
5976 }
5977 }
5978 /* concatenation with empty string may increase refcount */
5979 op2_info |= MAY_BE_RCN;
5980 jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
5981 if (if_op1_string || if_op2_string) {
5982 fast_path = ir_END();
5983 }
5984 }
5985 if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
5986 (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
5987 if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5988 if (if_op1_string && if_op2_string) {
5989 ir_IF_FALSE(if_op1_string);
5990 ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
5991 } else if (if_op1_string) {
5992 ir_IF_FALSE_cold(if_op1_string);
5993 } else if (if_op2_string) {
5994 ir_IF_FALSE_cold(if_op2_string);
5995 }
5996 }
5997 ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
5998 ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5999 ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6000
6001 jit_SET_EX_OPLINE(jit, opline);
6002 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(concat_function), arg1, arg2, arg3);
6003 /* concatenation with empty string may increase refcount */
6004 op1_info |= MAY_BE_RCN;
6005 op2_info |= MAY_BE_RCN;
6006 jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6007 jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6008 if (may_throw) {
6009 if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6010 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6011 jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6012 } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6013 zend_jit_check_exception_undef_result(jit, opline);
6014 } else {
6015 zend_jit_check_exception(jit);
6016 }
6017 }
6018 if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6019 ir_MERGE_WITH(fast_path);
6020 }
6021 }
6022 return 1;
6023 }
6024
zend_jit_concat(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,uint32_t op2_info,zend_jit_addr res_addr,int may_throw)6025 static int zend_jit_concat(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr, int may_throw)
6026 {
6027 zend_jit_addr op1_addr, op2_addr;
6028
6029 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6030 ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
6031
6032 op1_addr = OP1_ADDR();
6033 op2_addr = OP2_ADDR();
6034
6035 return zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, may_throw);
6036 }
6037
zend_jit_assign_op(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,zend_ssa_range * op1_range,uint32_t op1_def_info,zend_jit_addr op1_def_addr,uint32_t op1_mem_info,uint32_t op2_info,zend_jit_addr op2_addr,zend_ssa_range * op2_range,int may_overflow,int may_throw)6038 static int zend_jit_assign_op(zend_jit_ctx *jit,
6039 const zend_op *opline,
6040 uint32_t op1_info,
6041 zend_jit_addr op1_addr,
6042 zend_ssa_range *op1_range,
6043 uint32_t op1_def_info,
6044 zend_jit_addr op1_def_addr,
6045 uint32_t op1_mem_info,
6046 uint32_t op2_info,
6047 zend_jit_addr op2_addr,
6048 zend_ssa_range *op2_range,
6049 int may_overflow,
6050 int may_throw)
6051 {
6052 int result = 1;
6053 ir_ref slow_path = IR_UNUSED;
6054
6055 ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6056 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6057
6058 if (op1_info & MAY_BE_REF) {
6059 ir_ref ref, ref2, arg2, op1_noref_path;
6060 ir_ref if_op1_ref = IR_UNUSED;
6061 ir_ref if_op1_typed = IR_UNUSED;
6062 binary_op_type binary_op = get_binary_op(opline->extended_value);
6063
6064 ref = jit_ZVAL_ADDR(jit, op1_addr);
6065 if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6066 ir_IF_FALSE(if_op1_ref);
6067 op1_noref_path = ir_END();
6068 ir_IF_TRUE(if_op1_ref);
6069 ref2 = jit_Z_PTR_ref(jit, ref);
6070
6071 if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6072 ir_IF_TRUE_cold(if_op1_typed);
6073
6074 if (Z_MODE(op2_addr) == IS_REG) {
6075 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6076 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6077 return 0;
6078 }
6079 arg2 = jit_ZVAL_ADDR(jit, real_addr);
6080 } else {
6081 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6082 }
6083 jit_SET_EX_OPLINE(jit, opline);
6084 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6085 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6086 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6087 ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6088 } else {
6089 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6090 ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6091 }
6092 zend_jit_check_exception(jit);
6093 slow_path = ir_END();
6094
6095 ir_IF_FALSE(if_op1_typed);
6096 ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6097
6098 ir_MERGE_WITH(op1_noref_path);
6099 ref = ir_PHI_2(IR_ADDR, ref2, ref);
6100 ZEND_ASSERT(op1_addr == op1_def_addr);
6101 op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6102 }
6103
6104 switch (opline->extended_value) {
6105 case ZEND_ADD:
6106 case ZEND_SUB:
6107 case ZEND_MUL:
6108 case ZEND_DIV:
6109 result = zend_jit_math_helper(jit, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_overflow, may_throw);
6110 break;
6111 case ZEND_BW_OR:
6112 case ZEND_BW_AND:
6113 case ZEND_BW_XOR:
6114 case ZEND_SL:
6115 case ZEND_SR:
6116 case ZEND_MOD:
6117 result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6118 opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6119 opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6120 opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6121 break;
6122 case ZEND_CONCAT:
6123 result = zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_def_addr, may_throw);
6124 break;
6125 default:
6126 ZEND_UNREACHABLE();
6127 }
6128
6129 if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
6130 return 0;
6131 }
6132
6133 if (op1_info & MAY_BE_REF) {
6134 ir_MERGE_WITH(slow_path);
6135 }
6136
6137 return result;
6138 }
6139
jit_ZVAL_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6140 static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6141 {
6142 ir_ref if_ref, ref2;
6143
6144 if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6145 ir_IF_TRUE(if_ref);
6146 ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6147 ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6148 return ir_PHI_2(IR_ADDR, ref2, ref);
6149 }
6150
jit_ZVAL_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6151 static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6152 {
6153 ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6154 ref = jit_ZVAL_DEREF_ref(jit, ref);
6155 return ZEND_ADDR_REF_ZVAL(ref);
6156 }
6157
jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx * jit,ir_ref ref)6158 static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6159 {
6160 ir_ref if_ref, ref2;
6161
6162 if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6163 ir_IF_TRUE(if_ref);
6164 ref2 = jit_Z_PTR_ref(jit, ref);
6165 ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6166 return ir_PHI_2(IR_ADDR, ref2, ref);
6167 }
6168
jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx * jit,zend_jit_addr addr)6169 static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6170 {
6171 ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6172 ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6173 return ZEND_ADDR_REF_ZVAL(ref);
6174 }
6175
zend_jit_simple_assign(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr var_addr,uint32_t var_info,uint32_t var_def_info,uint8_t val_type,zend_jit_addr val_addr,uint32_t val_info,zend_jit_addr res_addr,bool check_exception)6176 static int zend_jit_simple_assign(zend_jit_ctx *jit,
6177 const zend_op *opline,
6178 zend_jit_addr var_addr,
6179 uint32_t var_info,
6180 uint32_t var_def_info,
6181 uint8_t val_type,
6182 zend_jit_addr val_addr,
6183 uint32_t val_info,
6184 zend_jit_addr res_addr,
6185 bool check_exception)
6186 {
6187 ir_ref end_inputs = IR_UNUSED;
6188
6189 if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6190 zval *zv = Z_ZV(val_addr);
6191
6192 if (!res_addr) {
6193 jit_ZVAL_COPY_CONST(jit,
6194 var_addr,
6195 var_info, var_def_info,
6196 zv, 1);
6197 } else {
6198 jit_ZVAL_COPY_CONST(jit,
6199 var_addr,
6200 var_info, var_def_info,
6201 zv, 1);
6202 jit_ZVAL_COPY_CONST(jit,
6203 res_addr,
6204 -1, var_def_info,
6205 zv, 1);
6206 }
6207 } else {
6208 if (val_info & MAY_BE_UNDEF) {
6209 ir_ref if_def, ret;
6210
6211 if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6212 ir_IF_FALSE_cold(if_def);
6213
6214 jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6215 if (res_addr) {
6216 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6217 }
6218 jit_SET_EX_OPLINE(jit, opline);
6219
6220 ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6221 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6222 ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6223
6224 if (check_exception) {
6225 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6226 }
6227
6228 ir_END_list(end_inputs);
6229 ir_IF_TRUE(if_def);
6230 }
6231 if (val_info & MAY_BE_REF) {
6232 if (val_type == IS_CV) {
6233 ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6234 ref = jit_ZVAL_DEREF_ref(jit, ref);
6235 val_addr = ZEND_ADDR_REF_ZVAL(ref);
6236 } else {
6237 ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6238
6239 ref = jit_ZVAL_ADDR(jit, val_addr);
6240 type = jit_Z_TYPE_ref(jit, ref);
6241 if_ref = ir_IF(ir_EQ(type, ir_CONST_U8(IS_REFERENCE)));
6242
6243 ir_IF_TRUE_cold(if_ref);
6244 ref = jit_Z_PTR_ref(jit, ref);
6245 ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
6246 if (!res_addr) {
6247 jit_ZVAL_COPY(jit,
6248 var_addr,
6249 var_info,
6250 ZEND_ADDR_REF_ZVAL(ref2), val_info, 1);
6251 } else {
6252 jit_ZVAL_COPY_2(jit,
6253 res_addr,
6254 var_addr,
6255 var_info,
6256 ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6257 }
6258
6259 refcount = jit_GC_DELREF(jit, ref);
6260 if_not_zero = ir_IF(refcount);
6261 ir_IF_FALSE(if_not_zero);
6262 // TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6263 // This is related to GH-10168 (keep this before GH-10168 is completely closed)
6264 // jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6265 jit_ZVAL_DTOR(jit, ref, val_info, opline);
6266 ir_END_list(end_inputs);
6267 ir_IF_TRUE(if_not_zero);
6268 ir_END_list(end_inputs);
6269
6270 ir_IF_FALSE(if_ref);
6271 }
6272 }
6273
6274 if (!res_addr) {
6275 jit_ZVAL_COPY(jit,
6276 var_addr,
6277 var_info,
6278 val_addr, val_info, val_type == IS_CV);
6279 } else {
6280 jit_ZVAL_COPY_2(jit,
6281 res_addr,
6282 var_addr,
6283 var_info,
6284 val_addr, val_info, val_type == IS_CV ? 2 : 1);
6285 }
6286 }
6287
6288 if (end_inputs) {
6289 ir_END_list(end_inputs);
6290 ir_MERGE_list(end_inputs);
6291 }
6292
6293 return 1;
6294 }
6295
zend_jit_assign_to_variable_call(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr __var_use_addr,zend_jit_addr var_addr,uint32_t __var_info,uint32_t __var_def_info,uint8_t val_type,zend_jit_addr val_addr,uint32_t val_info,zend_jit_addr __res_addr,bool __check_exception)6296 static int zend_jit_assign_to_variable_call(zend_jit_ctx *jit,
6297 const zend_op *opline,
6298 zend_jit_addr __var_use_addr,
6299 zend_jit_addr var_addr,
6300 uint32_t __var_info,
6301 uint32_t __var_def_info,
6302 uint8_t val_type,
6303 zend_jit_addr val_addr,
6304 uint32_t val_info,
6305 zend_jit_addr __res_addr,
6306 bool __check_exception)
6307 {
6308 jit_stub_id func;
6309 ir_ref undef_path = IR_UNUSED;
6310
6311 if (val_info & MAY_BE_UNDEF) {
6312 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6313 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6314 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6315
6316 if (!exit_addr) {
6317 return 0;
6318 }
6319
6320 jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6321 } else {
6322 ir_ref if_def;
6323
6324 ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6325 if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6326 ir_IF_FALSE_cold(if_def);
6327 jit_SET_EX_OPLINE(jit, opline);
6328 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6329
6330 ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6331 jit_ZVAL_ADDR(jit, var_addr),
6332 jit_EG(uninitialized_zval));
6333
6334 undef_path = ir_END();
6335 ir_IF_TRUE(if_def);
6336 }
6337 }
6338
6339 if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6340 func = jit_stub_assign_tmp;
6341 } else if (val_type == IS_CONST) {
6342 func = jit_stub_assign_const;
6343 } else if (val_type == IS_TMP_VAR) {
6344 func = jit_stub_assign_tmp;
6345 } else if (val_type == IS_VAR) {
6346 if (!(val_info & MAY_BE_REF)) {
6347 func = jit_stub_assign_tmp;
6348 } else {
6349 func = jit_stub_assign_var;
6350 }
6351 } else if (val_type == IS_CV) {
6352 if (!(val_info & MAY_BE_REF)) {
6353 func = jit_stub_assign_cv_noref;
6354 } else {
6355 func = jit_stub_assign_cv;
6356 }
6357 } else {
6358 ZEND_UNREACHABLE();
6359 }
6360
6361 if (opline) {
6362 jit_SET_EX_OPLINE(jit, opline);
6363 }
6364
6365 ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6366 jit_ZVAL_ADDR(jit, var_addr),
6367 jit_ZVAL_ADDR(jit, val_addr));
6368
6369 if (undef_path) {
6370 ir_MERGE_WITH(undef_path);
6371 }
6372
6373 return 1;
6374 }
6375
zend_jit_assign_to_variable(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr var_use_addr,zend_jit_addr var_addr,uint32_t var_info,uint32_t var_def_info,uint8_t val_type,zend_jit_addr val_addr,uint32_t val_info,zend_jit_addr res_addr,zend_jit_addr ref_addr,bool check_exception)6376 static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
6377 const zend_op *opline,
6378 zend_jit_addr var_use_addr,
6379 zend_jit_addr var_addr,
6380 uint32_t var_info,
6381 uint32_t var_def_info,
6382 uint8_t val_type,
6383 zend_jit_addr val_addr,
6384 uint32_t val_info,
6385 zend_jit_addr res_addr,
6386 zend_jit_addr ref_addr,
6387 bool check_exception)
6388 {
6389 ir_ref if_refcounted = IR_UNUSED;
6390 ir_ref simple_inputs = IR_UNUSED;
6391 bool done = 0;
6392 zend_jit_addr real_res_addr = 0;
6393 ir_refs *end_inputs;
6394 ir_refs *res_inputs;
6395
6396 ir_refs_init(end_inputs, 6);
6397 ir_refs_init(res_inputs, 6);
6398
6399 if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6400 /* Force load */
6401 zend_jit_use_reg(jit, val_addr);
6402 }
6403
6404 if (Z_MODE(var_addr) == IS_REG) {
6405 jit->delay_var = Z_SSA_VAR(var_addr);
6406 jit->delay_refs = res_inputs;
6407 if (Z_MODE(res_addr) == IS_REG) {
6408 real_res_addr = res_addr;
6409 res_addr = 0;
6410 }
6411 } else if (Z_MODE(res_addr) == IS_REG) {
6412 jit->delay_var = Z_SSA_VAR(res_addr);
6413 jit->delay_refs = res_inputs;
6414 }
6415
6416 if ((var_info & MAY_BE_REF) || ref_addr) {
6417 ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6418 uintptr_t func;
6419
6420 if (!ref_addr) {
6421 ref = jit_ZVAL_ADDR(jit, var_use_addr);
6422 if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6423 ir_IF_TRUE(if_ref);
6424 ref2 = jit_Z_PTR_ref(jit, ref);
6425 } else {
6426 ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6427 }
6428 if_typed = jit_if_TYPED_REF(jit, ref2);
6429 ir_IF_TRUE_cold(if_typed);
6430 jit_SET_EX_OPLINE(jit, opline);
6431 if (Z_MODE(val_addr) == IS_REG) {
6432 zend_jit_addr real_addr;
6433
6434 if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6435 real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6436 } else {
6437 ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6438 real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6439 }
6440 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6441 return 0;
6442 }
6443 arg2 = jit_ZVAL_ADDR(jit, real_addr);
6444 } else {
6445 arg2 = jit_ZVAL_ADDR(jit, val_addr);
6446 }
6447 if (!res_addr) {
6448 if (val_type == IS_CONST) {
6449 func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6450 } else if (val_type == IS_TMP_VAR) {
6451 func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6452 } else if (val_type == IS_VAR) {
6453 func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6454 } else if (val_type == IS_CV) {
6455 func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6456 } else {
6457 ZEND_UNREACHABLE();
6458 }
6459 ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6460 } else {
6461 if (val_type == IS_CONST) {
6462 func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6463 } else if (val_type == IS_TMP_VAR) {
6464 func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6465 } else if (val_type == IS_VAR) {
6466 func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6467 } else if (val_type == IS_CV) {
6468 func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6469 } else {
6470 ZEND_UNREACHABLE();
6471 }
6472 ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6473 }
6474 if (check_exception) {
6475 zend_jit_check_exception(jit);
6476 }
6477 ir_refs_add(end_inputs, ir_END());
6478
6479 if (!ref_addr) {
6480 ir_IF_FALSE(if_ref);
6481 non_ref_path = ir_END();
6482 ir_IF_FALSE(if_typed);
6483 ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6484 ir_MERGE_WITH(non_ref_path);
6485 ref = ir_PHI_2(IR_ADDR, ref2, ref);
6486 var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6487 } else {
6488 ir_IF_FALSE(if_typed);
6489 }
6490 }
6491
6492 if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6493 ir_ref ref, counter, if_not_zero;
6494
6495 if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6496 if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6497 ir_IF_FALSE(if_refcounted);
6498 ir_END_list(simple_inputs);
6499 ir_IF_TRUE_cold(if_refcounted);
6500 } else if (RC_MAY_BE_1(var_info)) {
6501 done = 1;
6502 }
6503 ref = jit_Z_PTR(jit, var_use_addr);
6504 if (RC_MAY_BE_1(var_info)) {
6505 if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0)) {
6506 return 0;
6507 }
6508 counter = jit_GC_DELREF(jit, ref);
6509
6510 if_not_zero = ir_IF(counter);
6511 ir_IF_FALSE(if_not_zero);
6512 jit_ZVAL_DTOR(jit, ref, var_info, opline);
6513 if (check_exception) {
6514 zend_jit_check_exception(jit);
6515 }
6516 ir_refs_add(end_inputs, ir_END());
6517 ir_IF_TRUE(if_not_zero);
6518 if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6519 ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6520 ir_IF_FALSE(if_may_leak);
6521 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6522
6523 if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6524 ZEND_ASSERT(jit->delay_refs == res_inputs);
6525 ZEND_ASSERT(res_inputs->count > 0);
6526 ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6527 }
6528 if (check_exception && (val_info & MAY_BE_UNDEF)) {
6529 zend_jit_check_exception(jit);
6530 }
6531 ir_refs_add(end_inputs, ir_END());
6532 ir_IF_TRUE(if_may_leak);
6533 }
6534 if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6535 ZEND_ASSERT(jit->delay_refs == res_inputs);
6536 ZEND_ASSERT(res_inputs->count > 0);
6537 ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6538 }
6539 if (check_exception && (val_info & MAY_BE_UNDEF)) {
6540 zend_jit_check_exception(jit);
6541 }
6542 ir_refs_add(end_inputs, ir_END());
6543 } else /* if (RC_MAY_BE_N(var_info)) */ {
6544 jit_GC_DELREF(jit, ref);
6545 if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6546 ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6547 ir_IF_FALSE(if_may_leak);
6548 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6549 ir_END_list(simple_inputs);
6550 ir_IF_TRUE(if_may_leak);
6551 }
6552 ir_END_list(simple_inputs);
6553 }
6554 }
6555
6556 if (simple_inputs) {
6557 ir_MERGE_list(simple_inputs);
6558 }
6559
6560 if (!done) {
6561 if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6562 return 0;
6563 }
6564 if (end_inputs->count) {
6565 ir_refs_add(end_inputs, ir_END());
6566 }
6567 }
6568
6569 if (end_inputs->count) {
6570 ir_MERGE_N(end_inputs->count, end_inputs->refs);
6571 }
6572
6573 if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6574 ir_ref phi;
6575
6576 ZEND_ASSERT(jit->delay_refs == res_inputs);
6577 ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6578 jit->delay_var = -1;
6579 jit->delay_refs = NULL;
6580 if (res_inputs->count == 1) {
6581 phi = res_inputs->refs[0];
6582 } else {
6583 phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6584 res_inputs->count, res_inputs->refs);
6585 }
6586 if (Z_MODE(var_addr) == IS_REG) {
6587 if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6588 phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6589 }
6590 zend_jit_def_reg(jit, var_addr, phi);
6591 if (real_res_addr) {
6592 if (var_def_info & MAY_BE_LONG) {
6593 jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6594 } else {
6595 jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6596 }
6597 }
6598 } else {
6599 zend_jit_def_reg(jit, res_addr, phi);
6600 }
6601 }
6602
6603 return 1;
6604 }
6605
zend_jit_qm_assign(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,zend_jit_addr op1_def_addr,uint32_t res_use_info,uint32_t res_info,zend_jit_addr res_addr)6606 static int zend_jit_qm_assign(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr)
6607 {
6608 if (op1_addr != op1_def_addr) {
6609 if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6610 return 0;
6611 }
6612 if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6613 op1_addr = op1_def_addr;
6614 }
6615 }
6616
6617 if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 1)) {
6618 return 0;
6619 }
6620 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6621 return 0;
6622 }
6623 return 1;
6624 }
6625
zend_jit_assign(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_use_addr,uint32_t op1_def_info,zend_jit_addr op1_addr,uint32_t op2_info,zend_jit_addr op2_addr,zend_jit_addr op2_def_addr,uint32_t res_info,zend_jit_addr res_addr,zend_jit_addr ref_addr,int may_throw)6626 static int zend_jit_assign(zend_jit_ctx *jit,
6627 const zend_op *opline,
6628 uint32_t op1_info,
6629 zend_jit_addr op1_use_addr,
6630 uint32_t op1_def_info,
6631 zend_jit_addr op1_addr,
6632 uint32_t op2_info,
6633 zend_jit_addr op2_addr,
6634 zend_jit_addr op2_def_addr,
6635 uint32_t res_info,
6636 zend_jit_addr res_addr,
6637 zend_jit_addr ref_addr,
6638 int may_throw)
6639 {
6640 ZEND_ASSERT(opline->op1_type == IS_CV);
6641
6642 if (op2_addr != op2_def_addr) {
6643 if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6644 return 0;
6645 }
6646 if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6647 op2_addr = op2_def_addr;
6648 }
6649 }
6650
6651 if (Z_MODE(op1_addr) != IS_REG
6652 && Z_MODE(op1_use_addr) == IS_REG
6653 && !Z_LOAD(op1_use_addr)
6654 && !Z_STORE(op1_use_addr)) {
6655 /* Force type update */
6656 op1_info |= MAY_BE_UNDEF;
6657 }
6658 if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6659 opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6660 return 0;
6661 }
6662 if (Z_MODE(op1_addr) == IS_REG) {
6663 if (Z_STORE(op1_addr)) {
6664 if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6665 return 0;
6666 }
6667 } else if ((op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
6668 && Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6669 && Z_REG(op1_use_addr) == ZREG_FP
6670 && EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6671 /* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6672 if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6673 jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6674 if (JIT_G(current_frame)) {
6675 SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6676 }
6677 } else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6678 jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6679 if (JIT_G(current_frame)) {
6680 SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6681 }
6682 } else {
6683 ZEND_UNREACHABLE();
6684 }
6685 }
6686 }
6687 if (opline->result_type != IS_UNUSED) {
6688 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6689 return 0;
6690 }
6691 }
6692
6693 return 1;
6694 }
6695
zend_jit_cmp_op(const zend_op * opline)6696 static ir_op zend_jit_cmp_op(const zend_op *opline)
6697 {
6698 ir_op op;
6699
6700 switch (opline->opcode) {
6701 case ZEND_IS_EQUAL:
6702 case ZEND_IS_IDENTICAL:
6703 case ZEND_CASE:
6704 case ZEND_CASE_STRICT:
6705 op = IR_EQ;
6706 break;
6707 case ZEND_IS_NOT_EQUAL:
6708 case ZEND_IS_NOT_IDENTICAL:
6709 op = IR_NE;
6710 break;
6711 case ZEND_IS_SMALLER:
6712 op = IR_LT;
6713 break;
6714 case ZEND_IS_SMALLER_OR_EQUAL:
6715 op = IR_LE;
6716 break;
6717 default:
6718 ZEND_UNREACHABLE();
6719 }
6720 return op;
6721 }
6722
zend_jit_cmp_long_long(zend_jit_ctx * jit,const zend_op * opline,zend_ssa_range * op1_range,zend_jit_addr op1_addr,zend_ssa_range * op2_range,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr,bool skip_comparison)6723 static ir_ref zend_jit_cmp_long_long(zend_jit_ctx *jit,
6724 const zend_op *opline,
6725 zend_ssa_range *op1_range,
6726 zend_jit_addr op1_addr,
6727 zend_ssa_range *op2_range,
6728 zend_jit_addr op2_addr,
6729 zend_jit_addr res_addr,
6730 uint8_t smart_branch_opcode,
6731 uint32_t target_label,
6732 uint32_t target_label2,
6733 const void *exit_addr,
6734 bool skip_comparison)
6735 {
6736 ir_ref ref;
6737 bool result;
6738
6739 if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6740 if (!smart_branch_opcode ||
6741 smart_branch_opcode == ZEND_JMPZ_EX ||
6742 smart_branch_opcode == ZEND_JMPNZ_EX) {
6743 jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6744 }
6745 if (smart_branch_opcode && !exit_addr) {
6746 if (smart_branch_opcode == ZEND_JMPZ ||
6747 smart_branch_opcode == ZEND_JMPZ_EX) {
6748 return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6749 } else if (smart_branch_opcode == ZEND_JMPNZ ||
6750 smart_branch_opcode == ZEND_JMPNZ_EX) {
6751 return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6752 } else {
6753 ZEND_UNREACHABLE();
6754 }
6755 }
6756 if (opline->opcode != ZEND_IS_IDENTICAL
6757 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6758 && opline->opcode != ZEND_CASE_STRICT) {
6759 return ir_END();
6760 } else {
6761 return IR_NULL; /* success */
6762 }
6763 }
6764
6765 ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6766
6767 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6768 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6769 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6770 }
6771 if (exit_addr) {
6772 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6773 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6774 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6775 } else {
6776 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6777 }
6778 } else {
6779 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6780 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6781 } else {
6782 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6783 }
6784 }
6785 } else if (smart_branch_opcode) {
6786 return jit_IF_ex(jit, ref,
6787 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6788 }
6789
6790 if (opline->opcode != ZEND_IS_IDENTICAL
6791 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6792 && opline->opcode != ZEND_CASE_STRICT) {
6793 return ir_END();
6794 } else {
6795 return IR_NULL; /* success */
6796 }
6797 }
6798
zend_jit_cmp_long_double(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6799 static ir_ref zend_jit_cmp_long_double(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6800 {
6801 ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), ir_INT2D(jit_Z_LVAL(jit, op1_addr)), jit_Z_DVAL(jit, op2_addr));
6802
6803 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6804 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6805 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6806 }
6807 if (exit_addr) {
6808 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6809 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6810 } else {
6811 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6812 }
6813 } else if (smart_branch_opcode) {
6814 return jit_IF_ex(jit, ref,
6815 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6816 }
6817 return ir_END();
6818 }
6819
zend_jit_cmp_double_long(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6820 static ir_ref zend_jit_cmp_double_long(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6821 {
6822 ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), ir_INT2D(jit_Z_LVAL(jit, op2_addr)));
6823
6824 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6825 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6826 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6827 }
6828 if (exit_addr) {
6829 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6830 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6831 } else {
6832 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6833 }
6834 } else if (smart_branch_opcode) {
6835 return jit_IF_ex(jit, ref,
6836 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6837 }
6838 return ir_END();
6839 }
6840
zend_jit_cmp_double_double(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr op1_addr,zend_jit_addr op2_addr,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6841 static ir_ref zend_jit_cmp_double_double(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6842 {
6843 ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
6844
6845 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6846 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6847 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6848 }
6849 if (exit_addr) {
6850 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6851 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6852 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6853 } else {
6854 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6855 }
6856 } else {
6857 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6858 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6859 } else {
6860 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6861 }
6862 }
6863 } else if (smart_branch_opcode) {
6864 return jit_IF_ex(jit, ref,
6865 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6866 }
6867 if (opline->opcode != ZEND_IS_IDENTICAL
6868 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6869 && opline->opcode != ZEND_CASE_STRICT) {
6870 return ir_END();
6871 } else {
6872 return IR_NULL; /* success */
6873 }
6874 }
6875
zend_jit_cmp_slow(zend_jit_ctx * jit,ir_ref ref,const zend_op * opline,zend_jit_addr res_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)6876 static ir_ref zend_jit_cmp_slow(zend_jit_ctx *jit, ir_ref ref, const zend_op *opline, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6877 {
6878 ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
6879
6880 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6881 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6882 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6883 }
6884 if (exit_addr) {
6885 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6886 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6887 } else {
6888 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6889 }
6890 } else if (smart_branch_opcode) {
6891 return jit_IF_ex(jit, ref,
6892 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6893 }
6894
6895 return ir_END();
6896 }
6897
zend_jit_cmp(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_ssa_range * op1_range,zend_jit_addr op1_addr,uint32_t op2_info,zend_ssa_range * op2_range,zend_jit_addr op2_addr,zend_jit_addr res_addr,int may_throw,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr,bool skip_comparison)6898 static int zend_jit_cmp(zend_jit_ctx *jit,
6899 const zend_op *opline,
6900 uint32_t op1_info,
6901 zend_ssa_range *op1_range,
6902 zend_jit_addr op1_addr,
6903 uint32_t op2_info,
6904 zend_ssa_range *op2_range,
6905 zend_jit_addr op2_addr,
6906 zend_jit_addr res_addr,
6907 int may_throw,
6908 uint8_t smart_branch_opcode,
6909 uint32_t target_label,
6910 uint32_t target_label2,
6911 const void *exit_addr,
6912 bool skip_comparison)
6913 {
6914 ir_ref ref = IR_UNUSED;
6915 ir_ref if_op1_long = IR_UNUSED;
6916 ir_ref if_op1_double = IR_UNUSED;
6917 ir_ref if_op2_double = IR_UNUSED;
6918 ir_ref if_op1_long_op2_long = IR_UNUSED;
6919 ir_ref if_op1_long_op2_double = IR_UNUSED;
6920 ir_ref if_op1_double_op2_double = IR_UNUSED;
6921 ir_ref if_op1_double_op2_long = IR_UNUSED;
6922 ir_ref slow_inputs = IR_UNUSED;
6923 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
6924 bool has_slow =
6925 (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6926 (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
6927 ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
6928 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
6929 ir_refs *end_inputs;
6930
6931 ir_refs_init(end_inputs, 8);
6932
6933 if (Z_MODE(op1_addr) == IS_REG) {
6934 if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
6935 /* Force load */
6936 zend_jit_use_reg(jit, op1_addr);
6937 }
6938 } else if (Z_MODE(op2_addr) == IS_REG) {
6939 if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
6940 /* Force load */
6941 zend_jit_use_reg(jit, op2_addr);
6942 }
6943 }
6944
6945 if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
6946 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
6947 if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
6948 ir_IF_TRUE(if_op1_long);
6949 }
6950 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
6951 if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
6952 ir_IF_FALSE_cold(if_op1_long_op2_long);
6953 if (op2_info & MAY_BE_DOUBLE) {
6954 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6955 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6956 ir_IF_FALSE_cold(if_op1_long_op2_double);
6957 ir_END_list(slow_inputs);
6958 ir_IF_TRUE(if_op1_long_op2_double);
6959 }
6960 ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6961 if (!ref) {
6962 return 0;
6963 }
6964 ir_refs_add(end_inputs, ref);
6965 } else {
6966 ir_END_list(slow_inputs);
6967 }
6968 ir_IF_TRUE(if_op1_long_op2_long);
6969 }
6970 ref = zend_jit_cmp_long_long(jit, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison);
6971 if (!ref) {
6972 return 0;
6973 }
6974 ir_refs_add(end_inputs, ref);
6975
6976 if (if_op1_long) {
6977 ir_IF_FALSE_cold(if_op1_long);
6978 }
6979 if (op1_info & MAY_BE_DOUBLE) {
6980 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
6981 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
6982 ir_IF_FALSE_cold(if_op1_double);
6983 ir_END_list(slow_inputs);
6984 ir_IF_TRUE(if_op1_double);
6985 }
6986 if (op2_info & MAY_BE_DOUBLE) {
6987 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
6988 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
6989 ir_IF_TRUE(if_op1_double_op2_double);
6990 }
6991 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
6992 if (!ref) {
6993 return 0;
6994 }
6995 ir_refs_add(end_inputs, ref);
6996 if (if_op1_double_op2_double) {
6997 ir_IF_FALSE_cold(if_op1_double_op2_double);
6998 }
6999 }
7000 if (!same_ops) {
7001 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7002 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7003 ir_IF_FALSE_cold(if_op1_double_op2_long);
7004 ir_END_list(slow_inputs);
7005 ir_IF_TRUE(if_op1_double_op2_long);
7006 }
7007 ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7008 if (!ref) {
7009 return 0;
7010 }
7011 ir_refs_add(end_inputs, ref);
7012 } else if (if_op1_double_op2_double) {
7013 ir_END_list(slow_inputs);
7014 }
7015 } else if (if_op1_long) {
7016 ir_END_list(slow_inputs);
7017 }
7018 } else if ((op1_info & MAY_BE_DOUBLE) &&
7019 !(op1_info & MAY_BE_LONG) &&
7020 (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7021 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7022 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7023 ir_IF_FALSE_cold(if_op1_double);
7024 ir_END_list(slow_inputs);
7025 ir_IF_TRUE(if_op1_double);
7026 }
7027 if (op2_info & MAY_BE_DOUBLE) {
7028 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7029 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7030 ir_IF_TRUE(if_op1_double_op2_double);
7031 }
7032 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7033 if (!ref) {
7034 return 0;
7035 }
7036 ir_refs_add(end_inputs, ref);
7037 if (if_op1_double_op2_double) {
7038 ir_IF_FALSE_cold(if_op1_double_op2_double);
7039 }
7040 }
7041 if (!same_ops && (op2_info & MAY_BE_LONG)) {
7042 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7043 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7044 ir_IF_FALSE_cold(if_op1_double_op2_long);
7045 ir_END_list(slow_inputs);
7046 ir_IF_TRUE(if_op1_double_op2_long);
7047 }
7048 ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7049 if (!ref) {
7050 return 0;
7051 }
7052 ir_refs_add(end_inputs, ref);
7053 } else if (if_op1_double_op2_double) {
7054 ir_END_list(slow_inputs);
7055 }
7056 } else if ((op2_info & MAY_BE_DOUBLE) &&
7057 !(op2_info & MAY_BE_LONG) &&
7058 (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7059 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7060 if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7061 ir_IF_FALSE_cold(if_op2_double);
7062 ir_END_list(slow_inputs);
7063 ir_IF_TRUE(if_op2_double);
7064 }
7065 if (op1_info & MAY_BE_DOUBLE) {
7066 if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7067 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7068 ir_IF_TRUE(if_op1_double_op2_double);
7069 }
7070 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7071 if (!ref) {
7072 return 0;
7073 }
7074 ir_refs_add(end_inputs, ref);
7075 if (if_op1_double_op2_double) {
7076 ir_IF_FALSE_cold(if_op1_double_op2_double);
7077 }
7078 }
7079 if (!same_ops && (op1_info & MAY_BE_LONG)) {
7080 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7081 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7082 ir_IF_FALSE_cold(if_op1_long_op2_double);
7083 ir_END_list(slow_inputs);
7084 ir_IF_TRUE(if_op1_long_op2_double);
7085 }
7086 ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7087 if (!ref) {
7088 return 0;
7089 }
7090 ir_refs_add(end_inputs, ref);
7091 } else if (if_op1_double_op2_double) {
7092 ir_END_list(slow_inputs);
7093 }
7094 }
7095
7096 if (has_slow ||
7097 (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7098 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7099 ir_ref op1, op2, ref;
7100
7101 if (slow_inputs) {
7102 ir_MERGE_list(slow_inputs);
7103 }
7104 jit_SET_EX_OPLINE(jit, opline);
7105
7106 if (Z_MODE(op1_addr) == IS_REG) {
7107 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7108 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7109 return 0;
7110 }
7111 op1_addr = real_addr;
7112 }
7113 if (Z_MODE(op2_addr) == IS_REG) {
7114 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7115 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7116 return 0;
7117 }
7118 op2_addr = real_addr;
7119 }
7120
7121 op1 = jit_ZVAL_ADDR(jit, op1_addr);
7122 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7123 op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, 0);
7124 }
7125 op2 = jit_ZVAL_ADDR(jit, op2_addr);
7126 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7127 op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, 0);
7128 }
7129 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7130 if (opline->opcode != ZEND_CASE) {
7131 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7132 }
7133 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7134 if (may_throw) {
7135 zend_jit_check_exception_undef_result(jit, opline);
7136 }
7137
7138 ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7139 if (!ref) {
7140 return 0;
7141 }
7142 ir_refs_add(end_inputs, ref);
7143 }
7144
7145 if (end_inputs->count) {
7146 uint32_t n = end_inputs->count;
7147
7148 if (smart_branch_opcode && !exit_addr) {
7149 zend_basic_block *bb;
7150 ir_ref ref;
7151 uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7152 target_label2 : target_label;
7153 uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7154 target_label : target_label2;
7155
7156 ZEND_ASSERT(jit->b >= 0);
7157 bb = &jit->ssa->cfg.blocks[jit->b];
7158 ZEND_ASSERT(bb->successors_count == 2);
7159
7160 if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7161 ir_ref merge_inputs = IR_UNUSED;
7162
7163 while (n) {
7164 n--;
7165 ir_IF_TRUE(end_inputs->refs[n]);
7166 ir_END_list(merge_inputs);
7167 ir_IF_FALSE(end_inputs->refs[n]);
7168 ir_END_list(merge_inputs);
7169 }
7170 ir_MERGE_list(merge_inputs);
7171 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7172 } else if (n == 1) {
7173 ref = end_inputs->refs[0];
7174 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7175 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7176 } else {
7177 ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7178
7179 while (n) {
7180 n--;
7181 ir_IF_TRUE(end_inputs->refs[n]);
7182 ir_END_list(true_inputs);
7183 ir_IF_FALSE(end_inputs->refs[n]);
7184 ir_END_list(false_inputs);
7185 }
7186 ir_MERGE_list(true_inputs);
7187 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7188 ir_MERGE_list(false_inputs);
7189 _zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7190 }
7191 jit->b = -1;
7192 } else {
7193 ir_MERGE_N(n, end_inputs->refs);
7194 }
7195 } else if (smart_branch_opcode && !exit_addr) {
7196 /* dead code */
7197 _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7198 jit->b = -1;
7199 }
7200
7201 return 1;
7202 }
7203
zend_jit_identical(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_ssa_range * op1_range,zend_jit_addr op1_addr,uint32_t op2_info,zend_ssa_range * op2_range,zend_jit_addr op2_addr,zend_jit_addr res_addr,int may_throw,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr,bool skip_comparison)7204 static int zend_jit_identical(zend_jit_ctx *jit,
7205 const zend_op *opline,
7206 uint32_t op1_info,
7207 zend_ssa_range *op1_range,
7208 zend_jit_addr op1_addr,
7209 uint32_t op2_info,
7210 zend_ssa_range *op2_range,
7211 zend_jit_addr op2_addr,
7212 zend_jit_addr res_addr,
7213 int may_throw,
7214 uint8_t smart_branch_opcode,
7215 uint32_t target_label,
7216 uint32_t target_label2,
7217 const void *exit_addr,
7218 bool skip_comparison)
7219 {
7220 bool always_false = 0, always_true = 0;
7221 ir_ref ref = IR_UNUSED;
7222
7223 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7224 ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7225 op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, 0);
7226 op1_info |= MAY_BE_NULL;
7227 op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7228 }
7229 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7230 ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7231 op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, 0);
7232 op2_info |= MAY_BE_NULL;
7233 op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7234 }
7235
7236 if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7237 always_false = 1;
7238 } else if (has_concrete_type(op1_info)
7239 && has_concrete_type(op2_info)
7240 && concrete_type(op1_info) == concrete_type(op2_info)
7241 && concrete_type(op1_info) <= IS_TRUE) {
7242 always_true = 1;
7243 } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7244 if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7245 always_true = 1;
7246 } else {
7247 always_false = 1;
7248 }
7249 }
7250
7251 if (always_true) {
7252 if (opline->opcode != ZEND_CASE_STRICT) {
7253 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7254 }
7255 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7256 if (!smart_branch_opcode
7257 || smart_branch_opcode == ZEND_JMPZ_EX
7258 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7259 jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7260 }
7261 if (may_throw) {
7262 zend_jit_check_exception(jit);
7263 }
7264 if (exit_addr) {
7265 if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7266 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7267 }
7268 } else if (smart_branch_opcode) {
7269 uint32_t label;
7270
7271 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7272 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7273 target_label : target_label2;
7274 } else {
7275 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7276 target_label2 : target_label;
7277 }
7278 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7279 jit->b = -1;
7280 }
7281 return 1;
7282 } else if (always_false) {
7283 if (opline->opcode != ZEND_CASE_STRICT) {
7284 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7285 }
7286 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7287 if (!smart_branch_opcode
7288 || smart_branch_opcode == ZEND_JMPZ_EX
7289 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7290 jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7291 }
7292 if (may_throw) {
7293 zend_jit_check_exception(jit);
7294 }
7295 if (exit_addr) {
7296 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7297 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7298 }
7299 } else if (smart_branch_opcode) {
7300 uint32_t label;
7301
7302 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7303 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7304 target_label2 : target_label;
7305 } else {
7306 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7307 target_label : target_label2;
7308 }
7309 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7310 jit->b = -1;
7311 }
7312 return 1;
7313 }
7314
7315 if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7316 ref = jit_ZVAL_ADDR(jit, op1_addr);
7317 ref = jit_ZVAL_DEREF_ref(jit, ref);
7318 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7319 }
7320 if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7321 ref = jit_ZVAL_ADDR(jit, op2_addr);
7322 ref = jit_ZVAL_DEREF_ref(jit, ref);
7323 op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7324 }
7325
7326 if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7327 (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7328 ref = zend_jit_cmp_long_long(jit, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison);
7329 if (!ref) {
7330 return 0;
7331 }
7332 } else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7333 (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7334 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7335 if (!ref) {
7336 return 0;
7337 }
7338 } else {
7339 if (opline->op1_type != IS_CONST) {
7340 if (Z_MODE(op1_addr) == IS_REG) {
7341 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7342 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7343 return 0;
7344 }
7345 op1_addr = real_addr;
7346 }
7347 }
7348 if (opline->op2_type != IS_CONST) {
7349 if (Z_MODE(op2_addr) == IS_REG) {
7350 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7351 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7352 return 0;
7353 }
7354 }
7355 }
7356
7357 if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7358 zval *val = Z_ZV(op1_addr);
7359
7360 ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7361 } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7362 zval *val = Z_ZV(op2_addr);
7363
7364 ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7365 } else {
7366 if (Z_MODE(op1_addr) == IS_REG) {
7367 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7368 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7369 return 0;
7370 }
7371 op1_addr = real_addr;
7372 }
7373 if (Z_MODE(op2_addr) == IS_REG) {
7374 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7375 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7376 return 0;
7377 }
7378 op2_addr = real_addr;
7379 }
7380 if (may_throw) {
7381 jit_SET_EX_OPLINE(jit, opline);
7382 }
7383
7384 ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_is_identical),
7385 jit_ZVAL_ADDR(jit, op1_addr),
7386 jit_ZVAL_ADDR(jit, op2_addr));
7387 }
7388
7389 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7390 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7391 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7392 ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7393 } else {
7394 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7395 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7396 }
7397 }
7398 if (opline->opcode != ZEND_CASE_STRICT) {
7399 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7400 }
7401 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7402 if (may_throw) {
7403 zend_jit_check_exception_undef_result(jit, opline);
7404 }
7405 if (exit_addr) {
7406 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7407 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7408 } else {
7409 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7410 }
7411 } else if (smart_branch_opcode) {
7412 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7413 /* swap labels */
7414 uint32_t tmp = target_label;
7415 target_label = target_label2;
7416 target_label2 = tmp;
7417 }
7418 ref = jit_IF_ex(jit, ref,
7419 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7420 }
7421 }
7422
7423 if (smart_branch_opcode && !exit_addr) {
7424 zend_basic_block *bb;
7425
7426 ZEND_ASSERT(jit->b >= 0);
7427 bb = &jit->ssa->cfg.blocks[jit->b];
7428 ZEND_ASSERT(bb->successors_count == 2);
7429
7430 if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7431 ir_IF_TRUE(ref);
7432 ir_MERGE_WITH_EMPTY_FALSE(ref);
7433 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7434 } else {
7435 ZEND_ASSERT(bb->successors_count == 2);
7436 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7437 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7438 }
7439 jit->b = -1;
7440 }
7441
7442 return 1;
7443 }
7444
zend_jit_bool_jmpznz(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,zend_jit_addr res_addr,uint32_t target_label,uint32_t target_label2,int may_throw,uint8_t branch_opcode,const void * exit_addr)7445 static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr)
7446 {
7447 uint32_t true_label = -1;
7448 uint32_t false_label = -1;
7449 bool set_bool = 0;
7450 bool set_bool_not = 0;
7451 bool always_true = 0, always_false = 0;
7452 ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7453 ir_type type = IR_UNUSED;
7454
7455 if (branch_opcode == ZEND_BOOL) {
7456 set_bool = 1;
7457 } else if (branch_opcode == ZEND_BOOL_NOT) {
7458 set_bool = 1;
7459 set_bool_not = 1;
7460 } else if (branch_opcode == ZEND_JMPZ) {
7461 true_label = target_label2;
7462 false_label = target_label;
7463 } else if (branch_opcode == ZEND_JMPNZ) {
7464 true_label = target_label;
7465 false_label = target_label2;
7466 } else if (branch_opcode == ZEND_JMPZ_EX) {
7467 set_bool = 1;
7468 true_label = target_label2;
7469 false_label = target_label;
7470 } else if (branch_opcode == ZEND_JMPNZ_EX) {
7471 set_bool = 1;
7472 true_label = target_label;
7473 false_label = target_label2;
7474 } else {
7475 ZEND_UNREACHABLE();
7476 }
7477
7478 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7479 ref = jit_ZVAL_ADDR(jit, op1_addr);
7480 ref = jit_ZVAL_DEREF_ref(jit, ref);
7481 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7482 }
7483
7484 if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
7485 if (zend_is_true(Z_ZV(op1_addr))) {
7486 always_true = 1;
7487 } else {
7488 always_false = 1;
7489 }
7490 } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7491 if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7492 always_true = 1;
7493 } else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7494 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7495 ref = jit_ZVAL_ADDR(jit, op1_addr);
7496 zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, 0);
7497 }
7498 always_false = 1;
7499 }
7500 }
7501
7502 if (always_true) {
7503 if (set_bool) {
7504 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7505 }
7506 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7507 if (may_throw) {
7508 zend_jit_check_exception(jit);
7509 }
7510 if (true_label != (uint32_t)-1) {
7511 ZEND_ASSERT(exit_addr == NULL);
7512 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7513 jit->b = -1;
7514 }
7515 return 1;
7516 } else if (always_false) {
7517 if (set_bool) {
7518 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7519 }
7520 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7521 if (may_throw) {
7522 zend_jit_check_exception(jit);
7523 }
7524 if (false_label != (uint32_t)-1) {
7525 ZEND_ASSERT(exit_addr == NULL);
7526 _zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7527 jit->b = -1;
7528 }
7529 return 1;
7530 }
7531
7532 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7533 type = jit_Z_TYPE(jit, op1_addr);
7534 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7535 ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7536
7537 ir_IF_TRUE_cold(if_type);
7538
7539 if (op1_info & MAY_BE_UNDEF) {
7540 zend_jit_type_check_undef(jit,
7541 type,
7542 opline->op1.var,
7543 opline, 1, 0, 1);
7544 }
7545 if (set_bool) {
7546 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7547 }
7548 if (exit_addr) {
7549 if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
7550 ir_END_list(end_inputs);
7551 } else {
7552 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7553 }
7554 } else if (false_label != (uint32_t)-1) {
7555 ir_END_list(false_inputs);
7556 } else {
7557 ir_END_list(end_inputs);
7558 }
7559 ir_IF_FALSE(if_type);
7560 }
7561
7562 if (op1_info & MAY_BE_TRUE) {
7563 ir_ref if_type = IR_UNUSED;
7564
7565 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7566 if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7567
7568 ir_IF_TRUE(if_type);
7569 }
7570 if (set_bool) {
7571 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7572 }
7573 if (exit_addr) {
7574 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7575 ir_END_list(end_inputs);
7576 } else {
7577 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7578 }
7579 } else if (true_label != (uint32_t)-1) {
7580 ir_END_list(true_inputs);
7581 } else {
7582 ir_END_list(end_inputs);
7583 }
7584 if (if_type) {
7585 ir_IF_FALSE(if_type);
7586 }
7587 }
7588 }
7589
7590 if (op1_info & MAY_BE_LONG) {
7591 ir_ref if_long = IR_UNUSED;
7592 ir_ref ref;
7593
7594 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
7595 if (!type) {
7596 type = jit_Z_TYPE(jit, op1_addr);
7597 }
7598 if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7599 ir_IF_TRUE(if_long);
7600 }
7601 ref = jit_Z_LVAL(jit, op1_addr);
7602 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7603 ref = ir_NE(ref, ir_CONST_LONG(0));
7604 if (set_bool_not) {
7605 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7606 ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7607 } else {
7608 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7609 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7610 }
7611 ir_END_list(end_inputs);
7612 } else if (exit_addr) {
7613 if (set_bool) {
7614 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7615 ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, ir_CONST_LONG(0))), ir_CONST_U32(IS_FALSE)));
7616 }
7617 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7618 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7619 } else {
7620 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7621 }
7622 ir_END_list(end_inputs);
7623 } else {
7624 ir_ref if_val = ir_IF(ref);
7625 ir_IF_TRUE(if_val);
7626 if (set_bool) {
7627 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7628 }
7629 ir_END_list(true_inputs);
7630 ir_IF_FALSE(if_val);
7631 if (set_bool) {
7632 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7633 }
7634 ir_END_list(false_inputs);
7635 }
7636 if (if_long) {
7637 ir_IF_FALSE(if_long);
7638 }
7639 }
7640
7641 if (op1_info & MAY_BE_DOUBLE) {
7642 ir_ref if_double = IR_UNUSED;
7643 ir_ref ref;
7644
7645 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7646 if (!type) {
7647 type = jit_Z_TYPE(jit, op1_addr);
7648 }
7649 if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7650 ir_IF_TRUE(if_double);
7651 }
7652 ref = ir_NE(jit_Z_DVAL(jit, op1_addr), ir_CONST_DOUBLE(0.0));
7653 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7654 if (set_bool_not) {
7655 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7656 ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7657 } else {
7658 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7659 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7660 }
7661 ir_END_list(end_inputs);
7662 } else if (exit_addr) {
7663 if (set_bool) {
7664 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7665 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7666 }
7667 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7668 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7669 } else {
7670 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7671 }
7672 ir_END_list(end_inputs);
7673 } else {
7674 ir_ref if_val = ir_IF(ref);
7675 ir_IF_TRUE(if_val);
7676 if (set_bool) {
7677 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7678 }
7679 ir_END_list(true_inputs);
7680 ir_IF_FALSE(if_val);
7681 if (set_bool) {
7682 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7683 }
7684 ir_END_list(false_inputs);
7685 }
7686 if (if_double) {
7687 ir_IF_FALSE(if_double);
7688 }
7689 }
7690
7691 if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7692 jit_SET_EX_OPLINE(jit, opline);
7693 ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7694 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7695 if (may_throw) {
7696 zend_jit_check_exception_undef_result(jit, opline);
7697 }
7698 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7699 if (set_bool_not) {
7700 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7701 ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7702 } else {
7703 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7704 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7705 }
7706 if (end_inputs) {
7707 ir_END_list(end_inputs);
7708 }
7709 } else if (exit_addr) {
7710 if (set_bool) {
7711 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7712 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7713 }
7714 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7715 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7716 } else {
7717 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7718 }
7719 if (end_inputs) {
7720 ir_END_list(end_inputs);
7721 }
7722 } else {
7723 ir_ref if_val = ir_IF(ref);
7724 ir_IF_TRUE(if_val);
7725 if (set_bool) {
7726 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7727 }
7728 ir_END_list(true_inputs);
7729 ir_IF_FALSE(if_val);
7730 if (set_bool) {
7731 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7732 }
7733 ir_END_list(false_inputs);
7734 }
7735 }
7736
7737 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7738 if (end_inputs) {
7739 ir_MERGE_list(end_inputs);
7740 }
7741 } else {
7742 _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7743 }
7744
7745 return 1;
7746 }
7747
zend_jit_defined(zend_jit_ctx * jit,const zend_op * opline,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)7748 static int zend_jit_defined(zend_jit_ctx *jit, const zend_op *opline, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7749 {
7750 uint32_t defined_label = (uint32_t)-1;
7751 uint32_t undefined_label = (uint32_t)-1;
7752 zval *zv = RT_CONSTANT(opline, opline->op1);
7753 zend_jit_addr res_addr = 0;
7754 ir_ref ref, ref2, if_set, if_zero, if_set2;
7755 ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7756
7757 if (smart_branch_opcode && !exit_addr) {
7758 if (smart_branch_opcode == ZEND_JMPZ) {
7759 defined_label = target_label2;
7760 undefined_label = target_label;
7761 } else if (smart_branch_opcode == ZEND_JMPNZ) {
7762 defined_label = target_label;
7763 undefined_label = target_label2;
7764 } else {
7765 ZEND_UNREACHABLE();
7766 }
7767 } else {
7768 res_addr = RES_ADDR();
7769 }
7770
7771 // if (CACHED_PTR(opline->extended_value)) {
7772 ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7773
7774 if_set = ir_IF(ref);
7775
7776 ir_IF_FALSE_cold(if_set);
7777 if_zero = ir_END();
7778
7779 ir_IF_TRUE(if_set);
7780 if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7781 ir_IF_FALSE(if_set2);
7782
7783 if (exit_addr) {
7784 if (smart_branch_opcode == ZEND_JMPNZ) {
7785 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7786 } else {
7787 ir_END_list(end_inputs);
7788 }
7789 } else if (smart_branch_opcode) {
7790 ir_END_list(true_inputs);
7791 } else {
7792 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7793 ir_END_list(end_inputs);
7794 }
7795
7796 ir_IF_TRUE_cold(if_set2);
7797
7798 ref2 = jit_EG(zend_constants);
7799 ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7800 if (sizeof(void*) == 8) {
7801 ref = ir_TRUNC_U32(ref);
7802 }
7803 ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7804 ref2 = ir_IF(ref2);
7805 ir_IF_TRUE(ref2);
7806
7807 if (exit_addr) {
7808 if (smart_branch_opcode == ZEND_JMPZ) {
7809 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7810 } else {
7811 ir_END_list(end_inputs);
7812 }
7813 } else if (smart_branch_opcode) {
7814 ir_END_list(false_inputs);
7815 } else {
7816 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7817 ir_END_list(end_inputs);
7818 }
7819
7820 ir_IF_FALSE(ref2);
7821 ir_MERGE_2(if_zero, ir_END());
7822
7823 jit_SET_EX_OPLINE(jit, opline);
7824 ref2 = ir_NE(ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_check_constant), ir_CONST_ADDR(zv)), IR_NULL);
7825 if (exit_addr) {
7826 if (smart_branch_opcode == ZEND_JMPZ) {
7827 ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
7828 } else {
7829 ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
7830 }
7831 ir_END_list(end_inputs);
7832 } else if (smart_branch_opcode) {
7833 ref2 = ir_IF(ref2);
7834 ir_IF_TRUE(ref2);
7835 ir_END_list(true_inputs);
7836 ir_IF_FALSE(ref2);
7837 ir_END_list(false_inputs);
7838 } else {
7839 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7840 ir_ADD_U32(ir_ZEXT_U32(ref2), ir_CONST_U32(IS_FALSE)));
7841 ir_END_list(end_inputs);
7842 }
7843
7844 if (!smart_branch_opcode || exit_addr) {
7845 if (end_inputs) {
7846 ir_MERGE_list(end_inputs);
7847 }
7848 } else {
7849 _zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
7850 }
7851
7852 return 1;
7853 }
7854
zend_jit_escape_if_undef(zend_jit_ctx * jit,int var,uint32_t flags,const zend_op * opline,int8_t reg)7855 static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
7856 {
7857 zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7858 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
7859
7860 ir_IF_FALSE_cold(if_def);
7861
7862 if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7863 if (!zend_jit_save_call_chain(jit, -1)) {
7864 return 0;
7865 }
7866 }
7867
7868 if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
7869 && (opline-1)->opcode != ZEND_FETCH_LIST_R
7870 && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
7871 && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
7872 zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
7873
7874 zend_jit_zval_try_addref(jit, val_addr);
7875 }
7876
7877 jit_LOAD_IP_ADDR(jit, opline - 1);
7878 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
7879
7880 ir_IF_TRUE(if_def);
7881
7882 return 1;
7883 }
7884
zend_jit_restore_zval(zend_jit_ctx * jit,int var,int8_t reg)7885 static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
7886 {
7887 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
7888 zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7889
7890 // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
7891 jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, 1);
7892 return 1;
7893 }
7894
zend_jit_guard_fetch_result_type(zend_jit_ctx * jit,const zend_op * opline,zend_jit_addr val_addr,uint8_t type,bool deref,uint32_t flags,bool op1_avoid_refcounting)7895 static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx *jit,
7896 const zend_op *opline,
7897 zend_jit_addr val_addr,
7898 uint8_t type,
7899 bool deref,
7900 uint32_t flags,
7901 bool op1_avoid_refcounting)
7902 {
7903 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
7904 int32_t exit_point;
7905 const void *res_exit_addr = NULL;
7906 ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
7907 ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
7908 uint32_t old_op1_info = 0;
7909 uint32_t old_info;
7910 ir_ref old_ref;
7911
7912
7913 if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7914 old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
7915 if (op1_avoid_refcounting
7916 || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
7917 && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
7918 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
7919 }
7920 }
7921 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
7922 old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7923 CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
7924 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
7925
7926 if (deref) {
7927 ir_ref if_type;
7928
7929 if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7930 if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
7931 } else {
7932 if_type = jit_if_Z_TYPE(jit, val_addr, type);
7933 }
7934 ir_IF_TRUE(if_type);
7935 end1 = ir_END();
7936 ref1 = ref;
7937 ir_IF_FALSE_cold(if_type);
7938
7939 SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7940 exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7941 res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7942 if (!res_exit_addr) {
7943 return 0;
7944 }
7945
7946 jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
7947 ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
7948 val_addr = ZEND_ADDR_REF_ZVAL(ref);
7949 }
7950
7951 SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
7952 exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
7953 res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7954 if (!res_exit_addr) {
7955 return 0;
7956 }
7957
7958 if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
7959 ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
7960 } else {
7961 jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
7962 }
7963
7964 if (deref) {
7965 ir_MERGE_WITH(end1);
7966 ref = ir_PHI_2(IR_ADDR, ref, ref1);
7967 }
7968
7969 val_addr = ZEND_ADDR_REF_ZVAL(ref);
7970
7971 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
7972 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
7973 if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
7974 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
7975 }
7976
7977 return val_addr;
7978 }
7979
zend_jit_fetch_constant(zend_jit_ctx * jit,const zend_op * opline,const zend_op_array * op_array,zend_ssa * ssa,const zend_ssa_op * ssa_op,zend_jit_addr res_addr)7980 static int zend_jit_fetch_constant(zend_jit_ctx *jit,
7981 const zend_op *opline,
7982 const zend_op_array *op_array,
7983 zend_ssa *ssa,
7984 const zend_ssa_op *ssa_op,
7985 zend_jit_addr res_addr)
7986 {
7987 zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
7988 uint32_t res_info = RES_INFO();
7989 ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
7990
7991 // JIT: c = CACHED_PTR(opline->extended_value);
7992 ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7993
7994 // JIT: if (c != NULL)
7995 if_set = ir_IF(ref);
7996
7997 if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
7998 // JIT: if (!IS_SPECIAL_CACHE_VAL(c))
7999 ir_IF_FALSE_cold(if_set);
8000 not_set_path = ir_END();
8001 ir_IF_TRUE(if_set);
8002 if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
8003 ir_IF_TRUE_cold(if_special);
8004 special_path = ir_END();
8005 ir_IF_FALSE(if_special);
8006 fast_path = ir_END();
8007 ir_MERGE_2(not_set_path, special_path);
8008 } else {
8009 ir_IF_TRUE(if_set);
8010 fast_path = ir_END();
8011 ir_IF_FALSE_cold(if_set);
8012 }
8013
8014 // JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
8015 jit_SET_EX_OPLINE(jit, opline);
8016 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_constant),
8017 ir_CONST_ADDR(zv),
8018 ir_CONST_U32(opline->op1.num));
8019 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8020
8021 ir_MERGE_WITH(fast_path);
8022 ref = ir_PHI_2(IR_ADDR, ref2, ref);
8023
8024 if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
8025 uint8_t type = concrete_type(res_info);
8026 zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
8027
8028 const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, 0, 0, 0);
8029 if (!const_addr) {
8030 return 0;
8031 }
8032
8033 res_info &= ~MAY_BE_GUARD;
8034 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
8035
8036 // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8037 jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, 1);
8038 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
8039 return 0;
8040 }
8041 } else {
8042 ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
8043
8044 // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8045 jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, 1);
8046 }
8047
8048
8049 return 1;
8050 }
8051
zend_jit_type_check(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)8052 static int zend_jit_type_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
8053 {
8054 uint32_t mask;
8055 zend_jit_addr op1_addr = OP1_ADDR();
8056 zend_jit_addr res_addr = 0;
8057 uint32_t true_label = -1, false_label = -1;
8058 ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8059
8060 // TODO: support for is_resource() ???
8061 ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8062
8063 if (smart_branch_opcode && !exit_addr) {
8064 if (smart_branch_opcode == ZEND_JMPZ) {
8065 true_label = target_label2;
8066 false_label = target_label;
8067 } else if (smart_branch_opcode == ZEND_JMPNZ) {
8068 true_label = target_label;
8069 false_label = target_label2;
8070 } else {
8071 ZEND_UNREACHABLE();
8072 }
8073 } else {
8074 res_addr = RES_ADDR();
8075 }
8076
8077 if (op1_info & MAY_BE_UNDEF) {
8078 ir_ref if_def = IR_UNUSED;
8079
8080 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8081 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8082 ir_IF_FALSE_cold(if_def);
8083 }
8084
8085 jit_SET_EX_OPLINE(jit, opline);
8086 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8087 zend_jit_check_exception_undef_result(jit, opline);
8088 if (opline->extended_value & MAY_BE_NULL) {
8089 if (exit_addr) {
8090 if (smart_branch_opcode == ZEND_JMPNZ) {
8091 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8092 } else {
8093 ir_END_list(end_inputs);
8094 }
8095 } else if (smart_branch_opcode) {
8096 ir_END_list(true_inputs);
8097 } else {
8098 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8099 ir_END_list(end_inputs);
8100 }
8101 } else {
8102 if (exit_addr) {
8103 if (smart_branch_opcode == ZEND_JMPZ) {
8104 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8105 } else {
8106 ir_END_list(end_inputs);
8107 }
8108 } else if (smart_branch_opcode) {
8109 ir_END_list(false_inputs);
8110 } else {
8111 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8112 if (if_def) {
8113 ir_END_list(end_inputs);
8114 }
8115 }
8116 }
8117
8118 if (if_def) {
8119 ir_IF_TRUE(if_def);
8120 op1_info |= MAY_BE_NULL;
8121 }
8122 }
8123
8124 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8125 mask = opline->extended_value;
8126 if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8127 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8128 if (exit_addr) {
8129 if (smart_branch_opcode == ZEND_JMPNZ) {
8130 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8131 } else if (end_inputs) {
8132 ir_END_list(end_inputs);
8133 }
8134 } else if (smart_branch_opcode) {
8135 ir_END_list(true_inputs);
8136 } else {
8137 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8138 ir_END_list(end_inputs);
8139 }
8140 } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8141 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8142 if (exit_addr) {
8143 if (smart_branch_opcode == ZEND_JMPZ) {
8144 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8145 } else if (end_inputs) {
8146 ir_END_list(end_inputs);
8147 }
8148 } else if (smart_branch_opcode) {
8149 ir_END_list(false_inputs);
8150 } else {
8151 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8152 ir_END_list(end_inputs);
8153 }
8154 } else {
8155 ir_ref ref;
8156 bool invert = 0;
8157 uint8_t type;
8158
8159 switch (mask) {
8160 case MAY_BE_NULL: type = IS_NULL; break;
8161 case MAY_BE_FALSE: type = IS_FALSE; break;
8162 case MAY_BE_TRUE: type = IS_TRUE; break;
8163 case MAY_BE_LONG: type = IS_LONG; break;
8164 case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8165 case MAY_BE_STRING: type = IS_STRING; break;
8166 case MAY_BE_ARRAY: type = IS_ARRAY; break;
8167 case MAY_BE_OBJECT: type = IS_OBJECT; break;
8168 case MAY_BE_ANY - MAY_BE_NULL: type = IS_NULL; invert = 1; break;
8169 case MAY_BE_ANY - MAY_BE_FALSE: type = IS_FALSE; invert = 1; break;
8170 case MAY_BE_ANY - MAY_BE_TRUE: type = IS_TRUE; invert = 1; break;
8171 case MAY_BE_ANY - MAY_BE_LONG: type = IS_LONG; invert = 1; break;
8172 case MAY_BE_ANY - MAY_BE_DOUBLE: type = IS_DOUBLE; invert = 1; break;
8173 case MAY_BE_ANY - MAY_BE_STRING: type = IS_STRING; invert = 1; break;
8174 case MAY_BE_ANY - MAY_BE_ARRAY: type = IS_ARRAY; invert = 1; break;
8175 case MAY_BE_ANY - MAY_BE_OBJECT: type = IS_OBJECT; invert = 1; break;
8176 case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break;
8177 default:
8178 type = 0;
8179 }
8180
8181 if (op1_info & MAY_BE_REF) {
8182 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8183 ref = jit_ZVAL_DEREF_ref(jit, ref);
8184 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8185 }
8186 if (type == 0) {
8187 ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8188 if (!smart_branch_opcode) {
8189 ref = ir_NE(ref, ir_CONST_U32(0));
8190 }
8191 } else if (invert) {
8192 ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8193 } else {
8194 ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8195 }
8196
8197 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8198
8199 if (exit_addr) {
8200 if (smart_branch_opcode == ZEND_JMPZ) {
8201 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8202 } else {
8203 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8204 }
8205 if (end_inputs) {
8206 ir_END_list(end_inputs);
8207 }
8208 } else if (smart_branch_opcode) {
8209 ir_ref if_val = ir_IF(ref);
8210 ir_IF_TRUE(if_val);
8211 ir_END_list(true_inputs);
8212 ir_IF_FALSE(if_val);
8213 ir_END_list(false_inputs);
8214 } else {
8215 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8216 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8217 ir_END_list(end_inputs);
8218 }
8219 }
8220 }
8221
8222 if (!smart_branch_opcode || exit_addr) {
8223 if (end_inputs) {
8224 ir_MERGE_list(end_inputs);
8225 } else if (exit_addr && !jit->ctx.control) {
8226 ir_BEGIN(IR_UNUSED); /* unreachable block */
8227 }
8228 } else {
8229 _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8230 }
8231
8232 return 1;
8233 }
8234
zend_jit_isset_isempty_cv(zend_jit_ctx * jit,const zend_op * opline,uint32_t op1_info,zend_jit_addr op1_addr,uint8_t smart_branch_opcode,uint32_t target_label,uint32_t target_label2,const void * exit_addr)8235 static int zend_jit_isset_isempty_cv(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
8236 {
8237 zend_jit_addr res_addr = RES_ADDR();
8238 uint32_t true_label = -1, false_label = -1;
8239 ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8240
8241 // TODO: support for empty() ???
8242 ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8243
8244 if (smart_branch_opcode && !exit_addr) {
8245 if (smart_branch_opcode == ZEND_JMPZ) {
8246 true_label = target_label2;
8247 false_label = target_label;
8248 } else if (smart_branch_opcode == ZEND_JMPNZ) {
8249 true_label = target_label;
8250 false_label = target_label2;
8251 } else {
8252 ZEND_UNREACHABLE();
8253 }
8254 } else {
8255 res_addr = RES_ADDR();
8256 }
8257
8258 if (op1_info & MAY_BE_REF) {
8259 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8260 ref = jit_ZVAL_DEREF_ref(jit, ref);
8261 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8262 }
8263
8264 if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8265 if (exit_addr) {
8266 ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8267 } else if (smart_branch_opcode) {
8268 ir_END_list(true_inputs);
8269 } else {
8270 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8271 ir_END_list(end_inputs);
8272 }
8273 } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8274 if (exit_addr) {
8275 ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8276 } else if (smart_branch_opcode) {
8277 ir_END_list(false_inputs);
8278 } else {
8279 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8280 ir_END_list(end_inputs);
8281 }
8282 } else {
8283 ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8284 if (exit_addr) {
8285 if (smart_branch_opcode == ZEND_JMPNZ) {
8286 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8287 } else {
8288 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8289 }
8290 } else if (smart_branch_opcode) {
8291 ir_ref if_val = ir_IF(ref);
8292 ir_IF_TRUE(if_val);
8293 ir_END_list(true_inputs);
8294 ir_IF_FALSE(if_val);
8295 ir_END_list(false_inputs);
8296 } else {
8297 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8298 ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8299 ir_END_list(end_inputs);
8300 }
8301 }
8302
8303 if (!smart_branch_opcode || exit_addr) {
8304 if (end_inputs) {
8305 ir_MERGE_list(end_inputs);
8306 }
8307 } else {
8308 _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8309 }
8310
8311 return 1;
8312 }
8313
8314 /* copy of hidden zend_closure */
8315 typedef struct _zend_closure {
8316 zend_object std;
8317 zend_function func;
8318 zval this_ptr;
8319 zend_class_entry *called_scope;
8320 zif_handler orig_internal_handler;
8321 } zend_closure;
8322
zend_jit_stack_check(zend_jit_ctx * jit,const zend_op * opline,uint32_t used_stack)8323 static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8324 {
8325 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8326 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8327
8328 if (!exit_addr) {
8329 return 0;
8330 }
8331
8332 // JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8333 ir_GUARD(
8334 ir_UGE(
8335 ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8336 ir_CONST_ADDR(used_stack)),
8337 ir_CONST_ADDR(exit_addr));
8338
8339 return 1;
8340 }
8341
zend_jit_free_trampoline(zend_jit_ctx * jit,int8_t func_reg)8342 static int zend_jit_free_trampoline(zend_jit_ctx *jit, int8_t func_reg)
8343 {
8344 // JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8345 ir_ref func = ir_RLOAD_A(func_reg);
8346 ir_ref if_trampoline = ir_IF(ir_AND_U32(
8347 ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8348 ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
8349
8350 ir_IF_TRUE(if_trampoline);
8351 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8352 ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8353
8354 return 1;
8355 }
8356
zend_jit_push_call_frame(zend_jit_ctx * jit,const zend_op * opline,const zend_op_array * op_array,zend_function * func,bool is_closure,bool delayed_fetch_this,int checked_stack,ir_ref func_ref,ir_ref this_ref)8357 static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool delayed_fetch_this, int checked_stack, ir_ref func_ref, ir_ref this_ref)
8358 {
8359 uint32_t used_stack;
8360 ir_ref used_stack_ref = IR_UNUSED;
8361 bool stack_check = 1;
8362 ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8363
8364 ZEND_ASSERT(func_ref != IR_NULL);
8365 if (func) {
8366 used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8367 if ((int)used_stack <= checked_stack) {
8368 stack_check = 0;
8369 }
8370 used_stack_ref = ir_CONST_ADDR(used_stack);
8371 } else {
8372 ir_ref num_args_ref;
8373 ir_ref if_internal_func = IR_UNUSED;
8374
8375 used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8376 used_stack_ref = ir_CONST_ADDR(used_stack);
8377
8378 if (!is_closure) {
8379 used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8380
8381 // JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8382 ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
8383 if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8384 ir_IF_FALSE(if_internal_func);
8385 }
8386
8387 // JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8388 num_args_ref = ir_CONST_U32(opline->extended_value);
8389 if (!is_closure) {
8390 ref = ir_SUB_U32(
8391 ir_SUB_U32(
8392 ir_MIN_U32(
8393 num_args_ref,
8394 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.num_args)))),
8395 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.last_var)))),
8396 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8397 } else {
8398 ref = ir_SUB_U32(
8399 ir_SUB_U32(
8400 ir_MIN_U32(
8401 num_args_ref,
8402 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8403 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8404 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8405 }
8406 ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8407 if (sizeof(void*) == 8) {
8408 ref = ir_SEXT_A(ref);
8409 }
8410 ref = ir_SUB_A(used_stack_ref, ref);
8411
8412 if (is_closure) {
8413 used_stack_ref = ref;
8414 } else {
8415 ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8416 used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8417 }
8418 }
8419
8420 zend_jit_start_reuse_ip(jit);
8421
8422 // JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8423 jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8424
8425 if (stack_check) {
8426 // JIT: Check Stack Overflow
8427 ref = ir_UGE(
8428 ir_SUB_A(
8429 ir_LOAD_A(jit_EG(vm_stack_end)),
8430 jit_IP(jit)),
8431 used_stack_ref);
8432
8433 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8434 bool may_be_trampoline = !func && (opline->opcode == ZEND_INIT_METHOD_CALL);
8435 int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8436 may_be_trampoline ?
8437 (ZEND_JIT_EXIT_TO_VM | ZEND_JIT_EXIT_METHOD_CALL) : ZEND_JIT_EXIT_TO_VM);
8438 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8439
8440 if (!exit_addr) {
8441 return 0;
8442 }
8443
8444 if (may_be_trampoline) {
8445 jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
8446 jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
8447 }
8448
8449 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8450 } else {
8451 if_enough_stack = ir_IF(ref);
8452 ir_IF_FALSE_cold(if_enough_stack);
8453
8454 #ifdef _WIN32
8455 if (0) {
8456 #else
8457 if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8458 #endif
8459 jit_SET_EX_OPLINE(jit, opline);
8460 ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8461 } else {
8462 if (!is_closure) {
8463 ref = func_ref;
8464 } else {
8465 ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8466 }
8467 jit_SET_EX_OPLINE(jit, opline);
8468 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8469 used_stack_ref, ref);
8470 }
8471 jit_STORE_IP(jit, ref);
8472
8473 cold_path = ir_END();
8474 ir_IF_TRUE(if_enough_stack);
8475 }
8476 }
8477
8478 ref = jit_EG(vm_stack_top);
8479 rx = jit_IP(jit);
8480 #if !OPTIMIZE_FOR_SIZE
8481 /* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8482 * This vesions is longer but faster
8483 * mov EG(vm_stack_top), %CALL
8484 * lea size(%call), %tmp
8485 * mov %tmp, EG(vm_stack_top)
8486 */
8487 top = rx;
8488 #else
8489 /* JIT: EG(vm_stack_top) += used_stack;
8490 * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8491 * mov EG(vm_stack_top), %CALL
8492 * add $size, EG(vm_stack_top)
8493 */
8494 top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8495 #endif
8496 ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8497
8498 // JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8499 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8500 // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8501 ir_STORE(jit_CALL(rx, This.u1.type_info), ir_CONST_U32(IS_UNDEF | ZEND_CALL_NESTED_FUNCTION));
8502 }
8503 #ifdef _WIN32
8504 if (0) {
8505 #else
8506 if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8507 #endif
8508 if (cold_path) {
8509 ir_MERGE_WITH(cold_path);
8510 rx = jit_IP(jit);
8511 }
8512
8513 // JIT: call->func = func;
8514 ir_STORE(jit_CALL(rx, func), func_ref);
8515 } else {
8516 if (!is_closure) {
8517 // JIT: call->func = func;
8518 ir_STORE(jit_CALL(rx, func), func_ref);
8519 } else {
8520 // JIT: call->func = &closure->func;
8521 ir_STORE(jit_CALL(rx, func), ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8522 }
8523 if (cold_path) {
8524 ir_MERGE_WITH(cold_path);
8525 rx = jit_IP(jit);
8526 }
8527 }
8528 if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8529 // JIT: Z_PTR(call->This) = obj;
8530 ZEND_ASSERT(this_ref != IR_NULL);
8531 ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8532 if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8533 // JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8534 ref = jit_CALL(rx, This.u1.type_info);
8535 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8536 ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS));
8537 } else {
8538 ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_HAS_THIS)));
8539 }
8540 } else {
8541 if (opline->op1_type == IS_CV) {
8542 // JIT: GC_ADDREF(obj);
8543 jit_GC_ADDREF(jit, this_ref);
8544 }
8545
8546 // JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8547 ref = jit_CALL(rx, This.u1.type_info);
8548 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8549 ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS));
8550 } else {
8551 ir_STORE(ref,
8552 ir_OR_U32(ir_LOAD_U32(ref),
8553 ir_CONST_U32(ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)));
8554 }
8555 }
8556 } else if (opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
8557 // JIT: Z_CE(call->This) = called_scope;
8558 ir_STORE(jit_CALL(rx, This), this_ref);
8559 } else if (!is_closure) {
8560 // JIT: Z_CE(call->This) = called_scope;
8561 ir_STORE(jit_CALL(rx, This), IR_NULL);
8562 } else {
8563 ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8564
8565 if (opline->op2_type == IS_CV) {
8566 // JIT: GC_ADDREF(closure);
8567 jit_GC_ADDREF(jit, func_ref);
8568 }
8569
8570 // JIT: RX(object_or_called_scope) = closure->called_scope;
8571 object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8572
8573 // JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8574 // (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8575 call_info = ir_OR_U32(
8576 ir_AND_U32(
8577 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8578 ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
8579 ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
8580 // JIT: if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
8581 if_cond = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.u1.v.type))));
8582 ir_IF_TRUE(if_cond);
8583
8584 // JIT: call_info |= ZEND_CALL_HAS_THIS;
8585 call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
8586
8587 // JIT: object_or_called_scope = Z_OBJ(closure->this_ptr);
8588 object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.value.ptr)));
8589
8590 ir_MERGE_WITH_EMPTY_FALSE(if_cond);
8591 call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8592 object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8593
8594 // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8595 ref = jit_CALL(rx, This.u1.type_info);
8596 ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), call_info));
8597
8598 // JIT: Z_PTR(call->This) = object_or_called_scope;
8599 ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8600
8601 // JIT: if (closure->func.op_array.run_time_cache__ptr)
8602 if_cond = ir_IF(ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.run_time_cache__ptr))));
8603 ir_IF_FALSE(if_cond);
8604
8605 // JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8606 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8607 ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8608
8609 ir_MERGE_WITH_EMPTY_TRUE(if_cond);
8610 }
8611
8612 // JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8613 ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8614
8615 return 1;
8616 }
8617
8618 static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8619 {
8620 int32_t exit_point;
8621 const void *exit_addr;
8622 ir_ref call;
8623
8624 if (func->type == ZEND_INTERNAL_FUNCTION) {
8625 #ifdef ZEND_WIN32
8626 // TODO: ASLR may cause different addresses in different workers ???
8627 return 0;
8628 #endif
8629 } else if (func->type == ZEND_USER_FUNCTION) {
8630 if (!zend_accel_in_shm(func->op_array.opcodes)) {
8631 /* op_array and op_array->opcodes are not persistent. We can't link. */
8632 return 0;
8633 }
8634 } else {
8635 ZEND_UNREACHABLE();
8636 return 0;
8637 }
8638
8639 exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8640 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8641 if (!exit_addr) {
8642 return 0;
8643 }
8644
8645 // call = EX(call);
8646 call = ir_LOAD_A(jit_EX(call));
8647 while (level > 0) {
8648 // call = call->prev_execute_data
8649 call = ir_LOAD_A(jit_CALL(call, prev_execute_data));
8650 level--;
8651 }
8652
8653 if (func->type == ZEND_USER_FUNCTION &&
8654 (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8655 (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8656 !func->common.function_name)) {
8657 const zend_op *opcodes = func->op_array.opcodes;
8658
8659 // JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8660 ir_GUARD(
8661 ir_EQ(
8662 ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(call, func)), offsetof(zend_op_array, opcodes))),
8663 ir_CONST_ADDR(opcodes)),
8664 ir_CONST_ADDR(exit_addr));
8665 } else {
8666 // JIT: if (call->func != func) goto exit_addr;
8667 ir_GUARD(ir_EQ(ir_LOAD_A(jit_CALL(call, func)), ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8668 }
8669
8670 return 1;
8671 }
8672
8673 static int zend_jit_init_fcall(zend_jit_ctx *jit, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack)
8674 {
8675 zend_func_info *info = ZEND_FUNC_INFO(op_array);
8676 zend_call_info *call_info = NULL;
8677 zend_function *func = NULL;
8678 ir_ref func_ref = IR_UNUSED;
8679
8680 if (jit->delayed_call_level) {
8681 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8682 return 0;
8683 }
8684 }
8685
8686 if (info) {
8687 call_info = info->callee_info;
8688 while (call_info && call_info->caller_init_opline != opline) {
8689 call_info = call_info->next_callee;
8690 }
8691 if (call_info && call_info->callee_func && !call_info->is_prototype) {
8692 func = call_info->callee_func;
8693 }
8694 }
8695
8696 if (!func
8697 && trace
8698 && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8699 #ifdef _WIN32
8700 /* ASLR */
8701 if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8702 func = (zend_function*)trace->func;
8703 }
8704 #else
8705 func = (zend_function*)trace->func;
8706 #endif
8707 }
8708
8709 #ifdef _WIN32
8710 if (0) {
8711 #else
8712 if (opline->opcode == ZEND_INIT_FCALL
8713 && func
8714 && func->type == ZEND_INTERNAL_FUNCTION) {
8715 #endif
8716 /* load constant address later */
8717 func_ref = ir_CONST_ADDR(func);
8718 } else if (func && op_array == &func->op_array) {
8719 /* recursive call */
8720 if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8721 || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8722 func_ref = ir_LOAD_A(jit_EX(func));
8723 } else {
8724 func_ref = ir_CONST_ADDR(func);
8725 }
8726 } else {
8727 ir_ref if_func, cache_slot_ref, ref;
8728
8729 // JIT: if (CACHED_PTR(opline->result.num))
8730 cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8731 func_ref = ir_LOAD_A(cache_slot_ref);
8732 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8733 && func
8734 && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8735 && opline->opcode != ZEND_INIT_FCALL) {
8736 /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8737 if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8738 } else {
8739 if_func = ir_IF(func_ref);
8740 }
8741 ir_IF_FALSE_cold(if_func);
8742 if (opline->opcode == ZEND_INIT_FCALL
8743 && func
8744 && func->type == ZEND_USER_FUNCTION
8745 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8746 ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8747 ir_STORE(cache_slot_ref, ref);
8748 ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8749 } else {
8750 zval *zv = RT_CONSTANT(opline, opline->op2);
8751
8752 if (opline->opcode == ZEND_INIT_FCALL) {
8753 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8754 ir_CONST_ADDR(Z_STR_P(zv)),
8755 cache_slot_ref);
8756 } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8757 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8758 ir_CONST_ADDR(Z_STR_P(zv + 1)),
8759 cache_slot_ref);
8760 } else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8761 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8762 ir_CONST_ADDR(zv),
8763 cache_slot_ref);
8764 } else {
8765 ZEND_UNREACHABLE();
8766 }
8767 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8768 int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8769 func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8770 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8771
8772 if (!exit_addr) {
8773 return 0;
8774 }
8775 if (!func || opline->opcode == ZEND_INIT_FCALL) {
8776 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8777 } else if (func->type == ZEND_USER_FUNCTION
8778 && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
8779 const zend_op *opcodes = func->op_array.opcodes;
8780
8781 ir_GUARD(
8782 ir_EQ(
8783 ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_op_array, opcodes))),
8784 ir_CONST_ADDR(opcodes)),
8785 ir_CONST_ADDR(exit_addr));
8786 } else {
8787 ir_GUARD(ir_EQ(ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8788 }
8789 } else {
8790 jit_SET_EX_OPLINE(jit, opline);
8791 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8792 }
8793 }
8794 ir_MERGE_WITH_EMPTY_TRUE(if_func);
8795 func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8796 }
8797
8798 if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, IR_UNUSED)) {
8799 return 0;
8800 }
8801
8802 if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8803 if (!zend_jit_save_call_chain(jit, call_level)) {
8804 return 0;
8805 }
8806 } else {
8807 ZEND_ASSERT(call_level > 0);
8808 jit->delayed_call_level = call_level;
8809 delayed_call_chain = 1;
8810 }
8811
8812 if (trace
8813 && trace->op == ZEND_JIT_TRACE_END
8814 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
8815 if (!zend_jit_set_ip(jit, opline + 1)) {
8816 return 0;
8817 }
8818 }
8819
8820 return 1;
8821 }
8822
8823 static int zend_jit_init_method_call(zend_jit_ctx *jit,
8824 const zend_op *opline,
8825 uint32_t b,
8826 const zend_op_array *op_array,
8827 zend_ssa *ssa,
8828 const zend_ssa_op *ssa_op,
8829 int call_level,
8830 uint32_t op1_info,
8831 zend_jit_addr op1_addr,
8832 zend_class_entry *ce,
8833 bool ce_is_instanceof,
8834 bool on_this,
8835 bool delayed_fetch_this,
8836 zend_class_entry *trace_ce,
8837 zend_jit_trace_rec *trace,
8838 int checked_stack,
8839 int8_t func_reg,
8840 int8_t this_reg,
8841 bool polymorphic_side_trace)
8842 {
8843 zend_func_info *info = ZEND_FUNC_INFO(op_array);
8844 zend_call_info *call_info = NULL;
8845 zend_function *func = NULL;
8846 zval *function_name;
8847 ir_ref if_static = IR_UNUSED, cold_path, this_ref = IR_NULL, func_ref = IR_NULL;
8848
8849 ZEND_ASSERT(opline->op2_type == IS_CONST);
8850 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
8851
8852 function_name = RT_CONSTANT(opline, opline->op2);
8853
8854 if (info) {
8855 call_info = info->callee_info;
8856 while (call_info && call_info->caller_init_opline != opline) {
8857 call_info = call_info->next_callee;
8858 }
8859 if (call_info && call_info->callee_func && !call_info->is_prototype) {
8860 func = call_info->callee_func;
8861 }
8862 }
8863
8864 if (polymorphic_side_trace) {
8865 /* function is passed in r0 from parent_trace */
8866 ZEND_ASSERT(func_reg >= 0 && this_reg >= 0);
8867 func_ref = zend_jit_deopt_rload(jit, IR_ADDR, func_reg);
8868 this_ref = zend_jit_deopt_rload(jit, IR_ADDR, this_reg);
8869 } else {
8870 ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
8871
8872 if (on_this) {
8873 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
8874 this_ref = jit_Z_PTR(jit, this_addr);
8875 } else {
8876 if (op1_info & MAY_BE_REF) {
8877 if (opline->op1_type == IS_CV) {
8878 // JIT: ZVAL_DEREF(op1)
8879 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8880 ref = jit_ZVAL_DEREF_ref(jit, ref);
8881 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8882 } else {
8883 ir_ref if_ref;
8884
8885 /* Hack: Convert reference to regular value to simplify JIT code */
8886 ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
8887
8888 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
8889 ir_IF_TRUE(if_ref);
8890 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
8891
8892 ir_MERGE_WITH_EMPTY_FALSE(if_ref);
8893 }
8894 }
8895 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
8896 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8897 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8898 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8899
8900 if (!exit_addr) {
8901 return 0;
8902 }
8903 ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
8904 ir_CONST_ADDR(exit_addr));
8905 } else {
8906 ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
8907
8908 ir_IF_FALSE_cold(if_object);
8909
8910 jit_SET_EX_OPLINE(jit, opline);
8911 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8912 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
8913 jit_ZVAL_ADDR(jit, op1_addr));
8914 } else {
8915 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
8916 jit_ZVAL_ADDR(jit, op1_addr));
8917 }
8918 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
8919 ir_IF_TRUE(if_object);
8920 }
8921 }
8922
8923 this_ref = jit_Z_PTR(jit, op1_addr);
8924 }
8925
8926 if (jit->delayed_call_level) {
8927 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8928 return 0;
8929 }
8930 }
8931
8932 if (func) {
8933 // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8934 ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
8935
8936 if_found = ir_IF(ref);
8937 ir_IF_TRUE(if_found);
8938 fast_path = ir_END();
8939 } else {
8940 // JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
8941 run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
8942 ref = ir_EQ(
8943 ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
8944 ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
8945 if_found = ir_IF(ref);
8946 ir_IF_TRUE(if_found);
8947
8948 // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
8949 ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
8950 fast_path = ir_END();
8951
8952 }
8953
8954 ir_IF_FALSE_cold(if_found);
8955 jit_SET_EX_OPLINE(jit, opline);
8956
8957 if (!jit->ctx.fixed_call_stack_size) {
8958 // JIT: alloca(sizeof(void*));
8959 this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
8960 } else {
8961 this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
8962 }
8963 ir_STORE(this_ref2, this_ref);
8964
8965 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
8966 ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
8967 this_ref,
8968 ir_CONST_ADDR(function_name),
8969 this_ref2);
8970 } else {
8971 ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
8972 this_ref,
8973 ir_CONST_ADDR(function_name),
8974 this_ref2);
8975 }
8976
8977 this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
8978 if (!jit->ctx.fixed_call_stack_size) {
8979 // JIT: revert alloca
8980 ir_AFREE(ir_CONST_ADDR(0x10));
8981 }
8982
8983 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8984
8985 ir_MERGE_WITH(fast_path);
8986 func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
8987 this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
8988 }
8989
8990 if ((!func || zend_jit_may_be_modified(func, op_array))
8991 && trace
8992 && trace->op == ZEND_JIT_TRACE_INIT_CALL
8993 && trace->func
8994 #ifdef _WIN32
8995 && trace->func->type != ZEND_INTERNAL_FUNCTION
8996 #endif
8997 ) {
8998 int32_t exit_point;
8999 const void *exit_addr;
9000
9001 exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
9002 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9003 if (!exit_addr) {
9004 return 0;
9005 }
9006
9007 jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9008 jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
9009
9010 func = (zend_function*)trace->func;
9011
9012 if (func->type == ZEND_USER_FUNCTION &&
9013 (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9014 (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9015 !func->common.function_name)) {
9016 const zend_op *opcodes = func->op_array.opcodes;
9017
9018 ir_GUARD(
9019 ir_EQ(
9020 ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9021 ir_CONST_ADDR(opcodes)),
9022 ir_CONST_ADDR(exit_addr));
9023 } else {
9024 ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9025 }
9026 }
9027
9028 if (!func) {
9029 // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9030 if_static = ir_IF(ir_AND_U32(
9031 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9032 ir_CONST_U32(ZEND_ACC_STATIC)));
9033 ir_IF_TRUE_cold(if_static);
9034 }
9035
9036 if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9037 ir_ref ret;
9038
9039 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9040 ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame_tmp),
9041 this_ref,
9042 func_ref,
9043 ir_CONST_U32(opline->extended_value));
9044 } else {
9045 ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame),
9046 this_ref,
9047 func_ref,
9048 ir_CONST_U32(opline->extended_value));
9049 }
9050
9051 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
9052 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9053 }
9054 jit_STORE_IP(jit, ret);
9055 }
9056
9057 if (!func) {
9058 cold_path = ir_END();
9059 ir_IF_FALSE(if_static);
9060 }
9061
9062 if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9063 if (!zend_jit_push_call_frame(jit, opline, NULL, func, 0, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
9064 return 0;
9065 }
9066 }
9067
9068 if (!func) {
9069 ir_MERGE_WITH(cold_path);
9070 }
9071 zend_jit_start_reuse_ip(jit);
9072
9073 if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9074 if (!zend_jit_save_call_chain(jit, call_level)) {
9075 return 0;
9076 }
9077 } else {
9078 ZEND_ASSERT(call_level > 0);
9079 delayed_call_chain = 1;
9080 jit->delayed_call_level = call_level;
9081 }
9082
9083 if (trace
9084 && trace->op == ZEND_JIT_TRACE_END
9085 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9086 if (!zend_jit_set_ip(jit, opline + 1)) {
9087 return 0;
9088 }
9089 }
9090
9091 return 1;
9092 }
9093
9094 static int zend_jit_init_static_method_call(zend_jit_ctx *jit,
9095 const zend_op *opline,
9096 uint32_t b,
9097 const zend_op_array *op_array,
9098 zend_ssa *ssa,
9099 const zend_ssa_op *ssa_op,
9100 int call_level,
9101 zend_jit_trace_rec *trace,
9102 int checked_stack)
9103 {
9104 zend_func_info *info = ZEND_FUNC_INFO(op_array);
9105 zend_call_info *call_info = NULL;
9106 zend_class_entry *ce;
9107 zend_function *func = NULL;
9108 ir_ref func_ref, func_ref2, scope_ref, scope_ref2, if_cached, cold_path, ref;
9109 ir_ref if_static = IR_UNUSED;
9110
9111 if (info) {
9112 call_info = info->callee_info;
9113 while (call_info && call_info->caller_init_opline != opline) {
9114 call_info = call_info->next_callee;
9115 }
9116 if (call_info && call_info->callee_func && !call_info->is_prototype) {
9117 func = call_info->callee_func;
9118 }
9119 }
9120
9121 ce = zend_get_known_class(op_array, opline, opline->op1_type, opline->op1);
9122 if (!func && ce) {
9123 zval *zv = RT_CONSTANT(opline, opline->op2);
9124 zend_string *method_name;
9125
9126 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
9127 method_name = Z_STR_P(zv);
9128 zv = zend_hash_find(&ce->function_table, method_name);
9129 if (zv) {
9130 zend_function *fn = Z_PTR_P(zv);
9131
9132 if (fn->common.scope == op_array->scope
9133 || (fn->common.fn_flags & ZEND_ACC_PUBLIC)
9134 || ((fn->common.fn_flags & ZEND_ACC_PROTECTED)
9135 && op_array->scope
9136 && instanceof_function_slow(op_array->scope, fn->common.scope))) {
9137 func = fn;
9138 }
9139 }
9140 }
9141
9142 if (jit->delayed_call_level) {
9143 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9144 return 0;
9145 }
9146 }
9147
9148 // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9149 func_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9150
9151 // JIT: if (fbc)
9152 if_cached = ir_IF(func_ref);
9153 ir_IF_FALSE_cold(if_cached);
9154
9155 jit_SET_EX_OPLINE(jit, opline);
9156 scope_ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_class_helper), jit_FP(jit));
9157 ir_GUARD(scope_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9158
9159 func_ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_static_method_helper), jit_FP(jit), scope_ref2);
9160 ir_GUARD(func_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9161
9162 cold_path = ir_END();
9163
9164 ir_IF_TRUE(if_cached);
9165 if (ce && (ce->ce_flags & ZEND_ACC_IMMUTABLE) && (ce->ce_flags & ZEND_ACC_LINKED)) {
9166 scope_ref = ir_CONST_ADDR(ce);
9167 } else {
9168 scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num));
9169 }
9170
9171 ir_MERGE_2(cold_path, ir_END());
9172 func_ref = ir_PHI_2(IR_ADDR, func_ref2, func_ref);
9173 scope_ref = ir_PHI_2(IR_ADDR, scope_ref2, scope_ref);
9174
9175 if ((!func || zend_jit_may_be_modified(func, op_array))
9176 && trace
9177 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9178 && trace->func
9179 #ifdef _WIN32
9180 && trace->func->type != ZEND_INTERNAL_FUNCTION
9181 #endif
9182 ) {
9183 int32_t exit_point;
9184 const void *exit_addr;
9185
9186 exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : 0);
9187 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9188 if (!exit_addr) {
9189 return 0;
9190 }
9191
9192 // jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9193 // jit->trace->exit_info[exit_point].poly_this_ref = scope_ref;
9194
9195 func = (zend_function*)trace->func;
9196
9197 if (func->type == ZEND_USER_FUNCTION &&
9198 (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9199 (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9200 !func->common.function_name)) {
9201 const zend_op *opcodes = func->op_array.opcodes;
9202
9203 ir_GUARD(
9204 ir_EQ(
9205 ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9206 ir_CONST_ADDR(opcodes)),
9207 ir_CONST_ADDR(exit_addr));
9208 } else {
9209 ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9210 }
9211 }
9212
9213 if (!func || !(func->common.fn_flags & ZEND_ACC_STATIC)) {
9214 if (!func) {
9215 // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9216 if_static = ir_IF(ir_AND_U32(
9217 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9218 ir_CONST_U32(ZEND_ACC_STATIC)));
9219 ir_IF_FALSE_cold(if_static);
9220 }
9221
9222 ref = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_this_method_call_frame),
9223 scope_ref,
9224 func_ref,
9225 ir_CONST_U32(opline->extended_value));
9226 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9227 jit_STORE_IP(jit, ref);
9228
9229 if (!func) {
9230 cold_path = ir_END();
9231 ir_IF_TRUE(if_static);
9232 }
9233 }
9234
9235 if (!func || (func->common.fn_flags & ZEND_ACC_STATIC)) {
9236 if (opline->op1_type == IS_UNUSED
9237 && ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
9238 (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) {
9239 if (op_array->fn_flags & ZEND_ACC_STATIC) {
9240 scope_ref = ir_LOAD_A(jit_EX(This.value.ref));
9241 } else {
9242 scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce)));
9243 }
9244 }
9245 if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, scope_ref)) {
9246 return 0;
9247 }
9248
9249 if (!func) {
9250 ir_MERGE_2(cold_path, ir_END());
9251 }
9252 }
9253
9254 zend_jit_start_reuse_ip(jit);
9255 if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9256 if (!zend_jit_save_call_chain(jit, call_level)) {
9257 return 0;
9258 }
9259 } else {
9260 ZEND_ASSERT(call_level > 0);
9261 jit->delayed_call_level = call_level;
9262 delayed_call_chain = 1;
9263 }
9264
9265 if (trace
9266 && trace->op == ZEND_JIT_TRACE_END
9267 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9268 if (!zend_jit_set_ip(jit, opline + 1)) {
9269 return 0;
9270 }
9271 }
9272
9273 return 1;
9274 }
9275
9276 static int zend_jit_init_closure_call(zend_jit_ctx *jit,
9277 const zend_op *opline,
9278 uint32_t b,
9279 const zend_op_array *op_array,
9280 zend_ssa *ssa,
9281 const zend_ssa_op *ssa_op,
9282 int call_level,
9283 zend_jit_trace_rec *trace,
9284 int checked_stack)
9285 {
9286 zend_function *func = NULL;
9287 zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9288 ir_ref ref;
9289
9290 ref = jit_Z_PTR(jit, op2_addr);
9291
9292 if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9293 && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9294 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9295 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9296
9297 if (!exit_addr) {
9298 return 0;
9299 }
9300
9301 ir_GUARD(
9302 ir_EQ(
9303 ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_object, ce))),
9304 ir_CONST_ADDR(zend_ce_closure)),
9305 ir_CONST_ADDR(exit_addr));
9306
9307 if (ssa->var_info && ssa_op->op2_use >= 0) {
9308 ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9309 ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9310 ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9311 }
9312 }
9313
9314 if (trace
9315 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9316 && trace->func
9317 && trace->func->type == ZEND_USER_FUNCTION) {
9318 const zend_op *opcodes;
9319 int32_t exit_point;
9320 const void *exit_addr;
9321
9322 func = (zend_function*)trace->func;
9323 opcodes = func->op_array.opcodes;
9324 exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9325 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9326 if (!exit_addr) {
9327 return 0;
9328 }
9329
9330 ir_GUARD(
9331 ir_EQ(
9332 ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9333 ir_CONST_ADDR(opcodes)),
9334 ir_CONST_ADDR(exit_addr));
9335 }
9336
9337 if (jit->delayed_call_level) {
9338 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9339 return 0;
9340 }
9341 }
9342
9343 if (!zend_jit_push_call_frame(jit, opline, NULL, func, 1, 0, checked_stack, ref, IR_UNUSED)) {
9344 return 0;
9345 }
9346
9347 if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9348 if (!zend_jit_save_call_chain(jit, call_level)) {
9349 return 0;
9350 }
9351 } else {
9352 ZEND_ASSERT(call_level > 0);
9353 delayed_call_chain = 1;
9354 jit->delayed_call_level = call_level;
9355 }
9356
9357 if (trace
9358 && trace->op == ZEND_JIT_TRACE_END
9359 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9360 if (!zend_jit_set_ip(jit, opline + 1)) {
9361 return 0;
9362 }
9363 }
9364
9365 return 1;
9366 }
9367
9368 static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9369 {
9370 uint32_t arg_num = opline->op2.num;
9371 zend_jit_addr arg_addr;
9372
9373 ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
9374
9375 if (!zend_jit_reuse_ip(jit)) {
9376 return 0;
9377 }
9378
9379 if (opline->opcode == ZEND_SEND_VAL_EX) {
9380 uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9381
9382 ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
9383
9384 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9385 && JIT_G(current_frame)
9386 && JIT_G(current_frame)->call
9387 && JIT_G(current_frame)->call->func) {
9388 if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9389 /* Don't generate code that always throws exception */
9390 return 0;
9391 }
9392 } else {
9393 ir_ref cond = ir_AND_U32(
9394 ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9395 ir_CONST_U32(mask));
9396
9397 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9398 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9399 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9400 if (!exit_addr) {
9401 return 0;
9402 }
9403 ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9404 } else {
9405 ir_ref if_pass_by_ref;
9406
9407 if_pass_by_ref = ir_IF(cond);
9408
9409 ir_IF_TRUE_cold(if_pass_by_ref);
9410 if (Z_MODE(op1_addr) == IS_REG) {
9411 /* set type to avoid zval_ptr_dtor() on uninitialized value */
9412 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9413 jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9414 }
9415 jit_SET_EX_OPLINE(jit, opline);
9416 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9417
9418 ir_IF_FALSE(if_pass_by_ref);
9419 }
9420 }
9421 }
9422
9423 arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9424
9425 if (opline->op1_type == IS_CONST) {
9426 zval *zv = RT_CONSTANT(opline, opline->op1);
9427
9428 jit_ZVAL_COPY_CONST(jit,
9429 arg_addr,
9430 MAY_BE_ANY, MAY_BE_ANY,
9431 zv, 1);
9432 } else {
9433 jit_ZVAL_COPY(jit,
9434 arg_addr,
9435 MAY_BE_ANY,
9436 op1_addr, op1_info, 0);
9437 }
9438
9439 return 1;
9440 }
9441
9442 static int zend_jit_send_ref(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold)
9443 {
9444 zend_jit_addr op1_addr, arg_addr, ref_addr;
9445 ir_ref ref_path = IR_UNUSED;
9446
9447 op1_addr = OP1_ADDR();
9448 arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9449
9450 if (!zend_jit_reuse_ip(jit)) {
9451 return 0;
9452 }
9453
9454 if (opline->op1_type == IS_VAR) {
9455 if (op1_info & MAY_BE_INDIRECT) {
9456 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9457 }
9458 } else if (opline->op1_type == IS_CV) {
9459 if (op1_info & MAY_BE_UNDEF) {
9460 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9461 // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9462 ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9463 ir_IF_FALSE(if_def);
9464 // JIT: ZVAL_NULL(op1)
9465 jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9466 ir_MERGE_WITH_EMPTY_TRUE(if_def);
9467 }
9468 op1_info &= ~MAY_BE_UNDEF;
9469 op1_info |= MAY_BE_NULL;
9470 }
9471 } else {
9472 ZEND_UNREACHABLE();
9473 }
9474
9475 if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9476 ir_ref ref, ref2;
9477
9478 if (op1_info & MAY_BE_REF) {
9479 ir_ref if_ref;
9480
9481 // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9482 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9483 ir_IF_TRUE(if_ref);
9484 // JIT: ref = Z_PTR_P(op1)
9485 ref = jit_Z_PTR(jit, op1_addr);
9486 // JIT: GC_ADDREF(ref)
9487 jit_GC_ADDREF(jit, ref);
9488 // JIT: ZVAL_REFERENCE(arg, ref)
9489 jit_set_Z_PTR(jit, arg_addr, ref);
9490 jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9491 ref_path = ir_END();
9492 ir_IF_FALSE(if_ref);
9493 }
9494
9495 // JIT: ZVAL_NEW_REF(arg, varptr);
9496 // JIT: ref = emalloc(sizeof(zend_reference));
9497 ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9498 // JIT: GC_REFCOUNT(ref) = 2
9499 jit_set_GC_REFCOUNT(jit, ref, 2);
9500 // JIT: GC_TYPE(ref) = GC_REFERENCE
9501 ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, gc.u.type_info)), ir_CONST_U32(GC_REFERENCE));
9502 ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr)), IR_NULL);
9503 ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9504 ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9505
9506 // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9507 jit_ZVAL_COPY(jit,
9508 ref_addr,
9509 MAY_BE_ANY,
9510 op1_addr, op1_info, 0);
9511
9512 // JIT: ZVAL_REFERENCE(arg, ref)
9513 jit_set_Z_PTR(jit, op1_addr, ref);
9514 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9515
9516 // JIT: ZVAL_REFERENCE(arg, ref)
9517 jit_set_Z_PTR(jit, arg_addr, ref);
9518 jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9519 }
9520
9521 if (ref_path) {
9522 ir_MERGE_WITH(ref_path);
9523 }
9524
9525 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9526
9527 return 1;
9528 }
9529
9530 static int zend_jit_send_var(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr)
9531 {
9532 uint32_t arg_num = opline->op2.num;
9533 zend_jit_addr arg_addr;
9534 ir_ref end_inputs = IR_UNUSED;
9535
9536 ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9537 opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9538 arg_num <= MAX_ARG_FLAG_NUM);
9539
9540 arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9541
9542 if (!zend_jit_reuse_ip(jit)) {
9543 return 0;
9544 }
9545
9546 if (opline->opcode == ZEND_SEND_VAR_EX) {
9547 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9548 && JIT_G(current_frame)
9549 && JIT_G(current_frame)->call
9550 && JIT_G(current_frame)->call->func) {
9551 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9552 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9553 return 0;
9554 }
9555 return 1;
9556 }
9557 } else {
9558 uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9559
9560 // JIT: if (RX->func->quick_arg_flags & mask)
9561 ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9562 ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9563 ir_CONST_U32(mask)));
9564 ir_IF_TRUE_cold(if_send_by_ref);
9565
9566 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9567 return 0;
9568 }
9569
9570 ir_END_list(end_inputs);
9571 ir_IF_FALSE(if_send_by_ref);
9572 }
9573 } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9574 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9575 && JIT_G(current_frame)
9576 && JIT_G(current_frame)->call
9577 && JIT_G(current_frame)->call->func) {
9578 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9579
9580 // JIT: ZVAL_COPY_VALUE(arg, op1)
9581 jit_ZVAL_COPY(jit,
9582 arg_addr,
9583 MAY_BE_ANY,
9584 op1_addr, op1_info, 0);
9585
9586 if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9587 if (!(op1_info & MAY_BE_REF)) {
9588 /* Don't generate code that always throws exception */
9589 return 0;
9590 } else {
9591 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9592 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9593 if (!exit_addr) {
9594 return 0;
9595 }
9596
9597 // JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9598 ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9599 ir_CONST_ADDR(exit_addr));
9600 }
9601 }
9602 return 1;
9603 }
9604 } else {
9605 uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9606 ir_ref func, if_send_by_ref, if_prefer_ref;
9607
9608 // JIT: if (RX->func->quick_arg_flags & mask)
9609 func = ir_LOAD_A(jit_RX(func));
9610 if_send_by_ref = ir_IF(ir_AND_U32(
9611 ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9612 ir_CONST_U32(mask)));
9613 ir_IF_TRUE_cold(if_send_by_ref);
9614
9615 mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9616
9617 // JIT: ZVAL_COPY_VALUE(arg, op1)
9618 jit_ZVAL_COPY(jit,
9619 arg_addr,
9620 MAY_BE_ANY,
9621 op1_addr, op1_info, 0);
9622
9623 if (op1_info & MAY_BE_REF) {
9624 ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9625 ir_IF_TRUE(if_ref);
9626 ir_END_list(end_inputs);
9627 ir_IF_FALSE(if_ref);
9628 }
9629
9630 // JIT: if (RX->func->quick_arg_flags & mask)
9631 if_prefer_ref = ir_IF(ir_AND_U32(
9632 ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9633 ir_CONST_U32(mask)));
9634 ir_IF_TRUE(if_prefer_ref);
9635 ir_END_list(end_inputs);
9636 ir_IF_FALSE(if_prefer_ref);
9637
9638 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9639 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9640 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9641 if (!exit_addr) {
9642 return 0;
9643 }
9644 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9645 } else {
9646 jit_SET_EX_OPLINE(jit, opline);
9647 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9648 jit_ZVAL_ADDR(jit, arg_addr));
9649 zend_jit_check_exception(jit);
9650 ir_END_list(end_inputs);
9651 }
9652
9653 ir_IF_FALSE(if_send_by_ref);
9654 }
9655 } else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9656 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9657 && JIT_G(current_frame)
9658 && JIT_G(current_frame)->call
9659 && JIT_G(current_frame)->call->func) {
9660 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9661 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9662 return 0;
9663 }
9664 return 1;
9665 }
9666 } else {
9667 // JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9668 ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9669 ir_LOAD_U32(jit_RX(This.u1.type_info)),
9670 ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9671 ir_IF_TRUE_cold(if_send_by_ref);
9672
9673 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9674 return 0;
9675 }
9676
9677 ir_END_list(end_inputs);
9678 ir_IF_FALSE(if_send_by_ref);
9679 }
9680 }
9681
9682 if (op1_info & MAY_BE_UNDEF) {
9683 ir_ref ref, if_def = IR_UNUSED;
9684
9685 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9686 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9687 ir_IF_FALSE_cold(if_def);
9688 }
9689
9690 // JIT: zend_jit_undefined_op_helper(opline->op1.var)
9691 jit_SET_EX_OPLINE(jit, opline);
9692 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9693 ir_CONST_U32(opline->op1.var));
9694
9695 // JIT: ZVAL_NULL(arg)
9696 jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9697
9698 // JIT: check_exception
9699 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9700
9701 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9702 ir_END_list(end_inputs);
9703 ir_IF_TRUE(if_def);
9704 } else {
9705 if (end_inputs) {
9706 ir_END_list(end_inputs);
9707 ir_MERGE_list(end_inputs);
9708 }
9709 return 1;
9710 }
9711 }
9712
9713 if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9714 // JIT: ZVAL_COPY_VALUE(arg, op1)
9715 jit_ZVAL_COPY(jit,
9716 arg_addr,
9717 MAY_BE_ANY,
9718 op1_addr, op1_info, 0);
9719 if (op1_info & MAY_BE_REF) {
9720 // JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9721 ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9722 ir_IF_TRUE(if_ref);
9723 ir_END_list(end_inputs);
9724 ir_IF_FALSE(if_ref);
9725 }
9726 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9727 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9728 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9729 if (!exit_addr) {
9730 return 0;
9731 }
9732 ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9733 } else {
9734 jit_SET_EX_OPLINE(jit, opline);
9735 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9736 jit_ZVAL_ADDR(jit, arg_addr));
9737 zend_jit_check_exception(jit);
9738 }
9739 } else {
9740 if (op1_info & MAY_BE_REF) {
9741 if (opline->op1_type == IS_CV) {
9742 ir_ref ref;
9743
9744 // JIT: ZVAL_DEREF(op1)
9745 ref = jit_ZVAL_ADDR(jit, op1_addr);
9746 ref = jit_ZVAL_DEREF_ref(jit, ref);
9747 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9748
9749 // JIT: ZVAL_COPY(arg, op1)
9750 jit_ZVAL_COPY(jit,
9751 arg_addr,
9752 MAY_BE_ANY,
9753 op1_addr, op1_info, 1);
9754 } else {
9755 ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9756 zend_jit_addr ref_addr;
9757
9758 // JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9759 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9760 ir_IF_TRUE_cold(if_ref);
9761
9762 // JIT: ref = Z_COUNTED_P(op1);
9763 ref = jit_Z_PTR(jit, op1_addr);
9764 ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9765 ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9766
9767 // JIT: ZVAL_COPY_VALUE(arg, op1);
9768 jit_ZVAL_COPY(jit,
9769 arg_addr,
9770 MAY_BE_ANY,
9771 ref_addr, op1_info, 0);
9772
9773 // JIT: if (GC_DELREF(ref) != 0)
9774 refcount = jit_GC_DELREF(jit, ref);
9775 if_not_zero = ir_IF(refcount);
9776 ir_IF_TRUE(if_not_zero);
9777
9778 // JIT: if (Z_REFCOUNTED_P(arg)
9779 if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9780 ir_IF_TRUE(if_refcounted);
9781 // JIT: Z_ADDREF_P(arg)
9782 jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9783 ir_END_list(end_inputs);
9784 ir_IF_FALSE(if_refcounted);
9785 ir_END_list(end_inputs);
9786
9787 ir_IF_FALSE(if_not_zero);
9788
9789 // JIT: efree(ref)
9790 jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9791 ir_END_list(end_inputs);
9792
9793 ir_IF_FALSE(if_ref);
9794
9795 // JIT: ZVAL_COPY_VALUE(arg, op1);
9796 jit_ZVAL_COPY(jit,
9797 arg_addr,
9798 MAY_BE_ANY,
9799 op1_addr, op1_info, 0);
9800 }
9801 } else {
9802 if (op1_addr != op1_def_addr) {
9803 if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9804 return 0;
9805 }
9806 if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9807 op1_addr = op1_def_addr;
9808 }
9809 }
9810
9811 // JIT: ZVAL_COPY_VALUE(arg, op1)
9812 jit_ZVAL_COPY(jit,
9813 arg_addr,
9814 MAY_BE_ANY,
9815 op1_addr, op1_info, opline->op1_type == IS_CV);
9816 }
9817 }
9818
9819 if (end_inputs) {
9820 ir_END_list(end_inputs);
9821 ir_MERGE_list(end_inputs);
9822 }
9823
9824 return 1;
9825 }
9826
9827 static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
9828 {
9829 uint32_t arg_num = opline->op2.num;
9830 ir_ref ref;
9831
9832 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9833 && JIT_G(current_frame)
9834 && JIT_G(current_frame)->call
9835 && JIT_G(current_frame)->call->func) {
9836 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9837 if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
9838 TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
9839 // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9840 if (jit->reuse_ip) {
9841 ref = jit_IP(jit);
9842 } else {
9843 ref = ir_LOAD_A(jit_EX(call));
9844 }
9845 ref = jit_CALL(ref, This.u1.type_info);
9846 ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9847 }
9848 } else {
9849 if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
9850 TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
9851 // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9852 if (jit->reuse_ip) {
9853 ref = jit_IP(jit);
9854 } else {
9855 ref = ir_LOAD_A(jit_EX(call));
9856 }
9857 ref = jit_CALL(ref, This.u1.type_info);
9858 ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9859 }
9860 }
9861 } else {
9862 // JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
9863 uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9864 ir_ref rx, if_ref, cold_path;
9865
9866 if (!zend_jit_reuse_ip(jit)) {
9867 return 0;
9868 }
9869
9870 rx = jit_IP(jit);
9871
9872 ref = ir_AND_U32(
9873 ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_function, quick_arg_flags))),
9874 ir_CONST_U32(mask));
9875 if_ref = ir_IF(ref);
9876 ir_IF_TRUE_cold(if_ref);
9877
9878 // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9879 ref = jit_CALL(rx, This.u1.type_info);
9880 ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9881
9882 cold_path = ir_END();
9883 ir_IF_FALSE(if_ref);
9884
9885 // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9886 ref = jit_CALL(rx, This.u1.type_info);
9887 ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9888
9889 ir_MERGE_WITH(cold_path);
9890 }
9891
9892 return 1;
9893 }
9894
9895 static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
9896 {
9897 ir_ref call, if_may_have_undef, ret;
9898
9899 if (jit->reuse_ip) {
9900 call = jit_IP(jit);
9901 } else {
9902 call = ir_LOAD_A(jit_EX(call));
9903 }
9904
9905 if_may_have_undef = ir_IF(ir_AND_U8(
9906 ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
9907 ir_CONST_U8(ZEND_CALL_MAY_HAVE_UNDEF >> 24)));
9908
9909 ir_IF_TRUE_cold(if_may_have_undef);
9910 jit_SET_EX_OPLINE(jit, opline);
9911 ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_handle_undef_args), call);
9912 ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9913 ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
9914
9915 return 1;
9916 }
9917
9918 static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block, zend_jit_trace_rec *trace)
9919 {
9920 zend_func_info *info = ZEND_FUNC_INFO(op_array);
9921 zend_call_info *call_info = NULL;
9922 const zend_function *func = NULL;
9923 uint32_t i;
9924 uint32_t call_num_args = 0;
9925 bool unknown_num_args = 0;
9926 const void *exit_addr = NULL;
9927 const zend_op *prev_opline;
9928 ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
9929
9930 prev_opline = opline - 1;
9931 while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
9932 prev_opline--;
9933 }
9934 if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
9935 prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
9936 unknown_num_args = 1;
9937 }
9938
9939 if (info) {
9940 call_info = info->callee_info;
9941 while (call_info && call_info->caller_call_opline != opline) {
9942 call_info = call_info->next_callee;
9943 }
9944 if (call_info && call_info->callee_func && !call_info->is_prototype) {
9945 func = call_info->callee_func;
9946 }
9947 if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
9948 && JIT_G(current_frame)
9949 && JIT_G(current_frame)->call
9950 && !JIT_G(current_frame)->call->func) {
9951 call_info = NULL; func = NULL; /* megamorphic call from trait */
9952 }
9953 }
9954 if (!func) {
9955 /* resolve function at run time */
9956 } else if (func->type == ZEND_USER_FUNCTION) {
9957 ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
9958 call_num_args = call_info->num_args;
9959 } else if (func->type == ZEND_INTERNAL_FUNCTION) {
9960 ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
9961 call_num_args = call_info->num_args;
9962 } else {
9963 ZEND_UNREACHABLE();
9964 }
9965
9966 if (trace && !func) {
9967 if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
9968 ZEND_ASSERT(!trace->func || trace->func->type == ZEND_INTERNAL_FUNCTION);
9969 #ifndef ZEND_WIN32
9970 // TODO: ASLR may cause different addresses in different workers ???
9971 func = trace->func;
9972 if (JIT_G(current_frame) &&
9973 JIT_G(current_frame)->call &&
9974 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9975 call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9976 } else {
9977 unknown_num_args = 1;
9978 }
9979 #endif
9980 } else if (trace->op == ZEND_JIT_TRACE_ENTER) {
9981 ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
9982 if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
9983 func = trace->func;
9984 if (JIT_G(current_frame) &&
9985 JIT_G(current_frame)->call &&
9986 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9987 call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9988 } else {
9989 unknown_num_args = 1;
9990 }
9991 }
9992 }
9993 }
9994
9995 bool may_have_extra_named_params =
9996 opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS &&
9997 (!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
9998
9999 if (!jit->reuse_ip) {
10000 zend_jit_start_reuse_ip(jit);
10001 // JIT: call = EX(call);
10002 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
10003 }
10004 rx = jit_IP(jit);
10005 zend_jit_stop_reuse_ip(jit);
10006
10007 jit_SET_EX_OPLINE(jit, opline);
10008
10009 if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10010 if (!func) {
10011 if (trace) {
10012 uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10013
10014 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10015 if (!exit_addr) {
10016 return 0;
10017 }
10018
10019 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10020 ir_GUARD_NOT(
10021 ir_AND_U32(
10022 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10023 ir_CONST_U32(ZEND_ACC_DEPRECATED)),
10024 ir_CONST_ADDR(exit_addr));
10025 }
10026 }
10027 }
10028
10029 if (!jit->delayed_call_level) {
10030 // JIT: EX(call) = call->prev_execute_data;
10031 ir_STORE(jit_EX(call),
10032 (call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
10033 }
10034 delayed_call_chain = 0;
10035 jit->delayed_call_level = 0;
10036
10037 // JIT: call->prev_execute_data = execute_data;
10038 ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
10039
10040 if (!func) {
10041 if (!func_ref) {
10042 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10043 }
10044 }
10045
10046 if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10047 if (!func) {
10048 if (!trace) {
10049 ir_ref if_deprecated, ret;
10050
10051 if_deprecated = ir_IF(ir_AND_U32(
10052 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10053 ir_CONST_U32(ZEND_ACC_DEPRECATED)));
10054 ir_IF_TRUE_cold(if_deprecated);
10055
10056 if (GCC_GLOBAL_REGS) {
10057 ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10058 } else {
10059 ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10060 }
10061 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10062 ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
10063 }
10064 } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10065 ir_ref ret;
10066
10067 if (GCC_GLOBAL_REGS) {
10068 ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10069 } else {
10070 ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10071 }
10072 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10073 }
10074 }
10075
10076 if (!func
10077 && opline->opcode != ZEND_DO_UCALL
10078 && opline->opcode != ZEND_DO_ICALL) {
10079 ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
10080 if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
10081 ir_IF_TRUE(if_user);
10082 }
10083
10084 if ((!func || func->type == ZEND_USER_FUNCTION)
10085 && opline->opcode != ZEND_DO_ICALL) {
10086 bool recursive_call_through_jmp = 0;
10087 uint32_t num_args = 0;
10088
10089 // JIT: EX(call) = NULL;
10090 ir_STORE(jit_CALL(rx, call), IR_NULL);
10091
10092 // JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
10093 ir_STORE(jit_CALL(rx, return_value),
10094 RETURN_VALUE_USED(opline) ?
10095 jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
10096 IR_NULL);
10097
10098 // JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
10099 if (!func || func->op_array.cache_size) {
10100 ir_ref run_time_cache;
10101
10102 if (func && op_array == &func->op_array) {
10103 /* recursive call */
10104 run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
10105 } else if (func
10106 && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
10107 && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
10108 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
10109 (uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
10110 } else if ((func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) ||
10111 (JIT_G(current_frame) &&
10112 JIT_G(current_frame)->call &&
10113 TRACE_FRAME_IS_CLOSURE_CALL(JIT_G(current_frame)->call))) {
10114 /* Closures always use direct pointers */
10115 ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10116
10117 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10118 } else {
10119 ir_ref if_odd, run_time_cache2;
10120 ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10121
10122 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10123 if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
10124 ir_IF_TRUE(if_odd);
10125
10126 run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
10127
10128 ir_MERGE_WITH_EMPTY_FALSE(if_odd);
10129 run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
10130 }
10131
10132 ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
10133 }
10134
10135 // JIT: EG(current_execute_data) = execute_data = call;
10136 ir_STORE(jit_EG(current_execute_data), rx);
10137 jit_STORE_FP(jit, rx);
10138
10139 // JIT: opline = op_array->opcodes;
10140 if (func && !unknown_num_args) {
10141
10142 for (i = call_num_args; i < func->op_array.last_var; i++) {
10143 uint32_t n = EX_NUM_TO_VAR(i);
10144 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
10145
10146 jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
10147 }
10148
10149 if (call_num_args <= func->op_array.num_args) {
10150 if (!trace || (trace->op == ZEND_JIT_TRACE_END
10151 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10152 if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
10153 if (trace) {
10154 num_args = 0;
10155 } else if (call_info) {
10156 num_args = skip_valid_arguments(op_array, ssa, call_info);
10157 } else {
10158 num_args = call_num_args;
10159 }
10160 } else {
10161 num_args = call_num_args;
10162 }
10163 if (zend_accel_in_shm(func->op_array.opcodes)) {
10164 jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
10165 } else {
10166 if (!func_ref) {
10167 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10168 }
10169 ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10170 if (num_args) {
10171 ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
10172 }
10173 jit_LOAD_IP(jit, ip);
10174 }
10175
10176 if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
10177 /* recursive call */
10178 recursive_call_through_jmp = 1;
10179 }
10180 }
10181 } else {
10182 if (!trace || (trace->op == ZEND_JIT_TRACE_END
10183 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10184 ir_ref ip;
10185
10186 if (zend_accel_in_shm(func->op_array.opcodes)) {
10187 ip = ir_CONST_ADDR(func->op_array.opcodes);
10188 } else {
10189 if (!func_ref) {
10190 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10191 }
10192 ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10193 }
10194 jit_LOAD_IP(jit, ip);
10195 }
10196 if (GCC_GLOBAL_REGS) {
10197 ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10198 } else {
10199 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
10200 }
10201 }
10202 } else {
10203 ir_ref ip;
10204 ir_ref merge_inputs = IR_UNUSED;
10205
10206 // JIT: opline = op_array->opcodes
10207 if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10208 ip = ir_CONST_ADDR(func->op_array.opcodes);
10209 } else {
10210 if (!func_ref) {
10211 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10212 }
10213 ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10214 }
10215 jit_LOAD_IP(jit, ip);
10216
10217 // JIT: num_args = EX_NUM_ARGS();
10218 ir_ref num_args, first_extra_arg;
10219
10220 num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
10221 if (func) {
10222 first_extra_arg = ir_CONST_U32(func->op_array.num_args);
10223 } else {
10224 // JIT: first_extra_arg = op_array->num_args;
10225 ZEND_ASSERT(func_ref);
10226 first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
10227 }
10228
10229 // JIT: if (UNEXPECTED(num_args > first_extra_arg))
10230 ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
10231 ir_IF_TRUE_cold(if_extra_args);
10232 if (GCC_GLOBAL_REGS) {
10233 ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10234 } else {
10235 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
10236 }
10237 ir_END_list(merge_inputs);
10238 ir_IF_FALSE(if_extra_args);
10239 if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10240 if (!func) {
10241 // JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10242 ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
10243 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10244 ir_CONST_U32(ZEND_ACC_HAS_TYPE_HINTS)));
10245 ir_IF_TRUE(if_has_type_hints);
10246 ir_END_list(merge_inputs);
10247 ir_IF_FALSE(if_has_type_hints);
10248 }
10249 // JIT: opline += num_args;
10250
10251 ir_ref ref = ir_MUL_U32(num_args, ir_CONST_U32(sizeof(zend_op)));
10252
10253 if (sizeof(void*) == 8) {
10254 ref = ir_ZEXT_A(ref);
10255 }
10256
10257 if (GCC_GLOBAL_REGS) {
10258 jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10259 } else {
10260 ir_ref addr = jit_EX(opline);
10261
10262 ir_STORE(addr, ir_ADD_A(ir_LOAD_A(addr), ref));
10263 }
10264 }
10265
10266 ir_END_list(merge_inputs);
10267 ir_MERGE_list(merge_inputs);
10268
10269 // JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10270 ir_ref last_var;
10271
10272 if (func) {
10273 last_var = ir_CONST_U32(func->op_array.last_var);
10274 } else {
10275 ZEND_ASSERT(func_ref);
10276 last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10277 }
10278
10279 ir_ref idx = ir_SUB_U32(last_var, num_args);
10280 ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10281 ir_IF_TRUE(if_need);
10282
10283 // JIT: zval *var = EX_VAR_NUM(num_args);
10284 if (sizeof(void*) == 8) {
10285 num_args = ir_ZEXT_A(num_args);
10286 }
10287 ir_ref var_ref = ir_ADD_OFFSET(
10288 ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10289 (ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10290
10291 ir_ref loop = ir_LOOP_BEGIN(ir_END());
10292 var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10293 idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10294 ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10295 ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10296 ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10297 ir_PHI_SET_OP(idx, 2, idx2);
10298 ir_ref if_not_zero = ir_IF(idx2);
10299 ir_IF_TRUE(if_not_zero);
10300 ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10301 ir_IF_FALSE(if_not_zero);
10302 ir_MERGE_WITH_EMPTY_FALSE(if_need);
10303 }
10304
10305 if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10306 ir_ref observer_handler;
10307 ir_ref rx = jit_FP(jit);
10308 struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10309 if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10310 ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10311 jit_SET_EX_OPLINE(jit, trace[1].opline);
10312 } else if (GCC_GLOBAL_REGS) {
10313 // EX(opline) = opline
10314 ir_STORE(jit_EX(opline), jit_IP(jit));
10315 }
10316 jit_observer_fcall_begin(jit, rx, observer_handler);
10317
10318 if (trace) {
10319 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10320
10321 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10322 if (!exit_addr) {
10323 return 0;
10324 }
10325 } else {
10326 exit_addr = NULL;
10327 }
10328
10329 zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr);
10330
10331 jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10332 }
10333
10334 if (trace) {
10335 if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10336 user_path = ir_END();
10337 }
10338 } else {
10339 zend_basic_block *bb;
10340
10341 do {
10342 if (recursive_call_through_jmp) {
10343 ir_ref begin, end;
10344 ir_insn *insn;
10345
10346 /* attempt to convert direct recursive call into loop */
10347 begin = jit->bb_start_ref[num_args];
10348 ZEND_ASSERT(begin != IR_UNUSED);
10349 insn = &jit->ctx.ir_base[begin];
10350 if (insn->op == IR_BEGIN) {
10351 end = ir_LOOP_END();
10352 insn = &jit->ctx.ir_base[begin];
10353 insn->op = IR_LOOP_BEGIN;
10354 insn->inputs_count = 2;
10355 insn->op2 = end;
10356 break;
10357 } else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10358 && insn->inputs_count == 2) {
10359 end = ir_LOOP_END();
10360 insn = &jit->ctx.ir_base[begin];
10361 insn->op = IR_LOOP_BEGIN;
10362 insn->inputs_count = 3;
10363 insn->op3 = end;
10364 break;
10365 } else if (insn->op == IR_LOOP_BEGIN && insn->inputs_count == 3) {
10366 ZEND_ASSERT(jit->ctx.ir_base[insn->op3].op == IR_LOOP_END);
10367 jit->ctx.ir_base[insn->op3].op = IR_END;
10368 ir_MERGE_2(insn->op3, ir_END());
10369 end = ir_LOOP_END();
10370 insn = &jit->ctx.ir_base[begin];
10371 insn->op3 = end;
10372 break;
10373 }
10374 }
10375 /* fallback to indirect JMP or RETURN */
10376 if (GCC_GLOBAL_REGS) {
10377 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10378 } else {
10379 ir_RETURN(ir_CONST_I32(1));
10380 }
10381 } while (0);
10382
10383 bb = &jit->ssa->cfg.blocks[jit->b];
10384 if (bb->successors_count > 0) {
10385 int succ;
10386 ir_ref ref;
10387
10388 ZEND_ASSERT(bb->successors_count == 1);
10389 succ = bb->successors[0];
10390 /* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10391 ref = jit->ctx.insns_count - 1;
10392 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10393 || jit->ctx.ir_base[ref].op == IR_RETURN
10394 || jit->ctx.ir_base[ref].op == IR_LOOP_END);
10395 ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
10396 ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10397 if (func || (opline->opcode == ZEND_DO_UCALL)) {
10398 _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10399 jit->b = -1;
10400 } else {
10401 user_path = ref;
10402 }
10403 }
10404 }
10405 }
10406
10407 if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10408 && (opline->opcode != ZEND_DO_UCALL)) {
10409 if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10410 ir_IF_FALSE(if_user);
10411 }
10412
10413 // JIT: EG(current_execute_data) = execute_data;
10414 ir_STORE(jit_EG(current_execute_data), rx);
10415
10416 bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10417 if (may_have_observer) {
10418 ir_ref observer_handler;
10419 struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
10420 jit_observer_fcall_begin(jit, rx, observer_handler);
10421 jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10422 }
10423
10424 // JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10425 ir_ref res_addr = IR_UNUSED, func_ptr;
10426
10427 if (RETURN_VALUE_USED(opline)) {
10428 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10429 } else {
10430 /* CPU stack allocated temporary zval */
10431 ir_ref ptr;
10432
10433 if (!jit->ctx.fixed_call_stack_size) {
10434 // JIT: alloca(sizeof(void*));
10435 ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10436 } else {
10437 ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10438 }
10439 res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10440 }
10441
10442 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10443
10444 zend_jit_reset_last_valid_opline(jit);
10445
10446 // JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10447 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10448 if (zend_execute_internal) {
10449 ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
10450 } else {
10451 if (func) {
10452 func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10453 } else {
10454 func_ptr = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler)));
10455 #if defined(IR_TARGET_X86)
10456 func_ptr = ir_CAST_FC_FUNC(func_ptr);
10457 #endif
10458 }
10459 ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10460 }
10461
10462 if (may_have_observer) {
10463 jit_observer_fcall_end(jit, rx, res_ref);
10464 }
10465
10466 /* When zend_interrupt_function is set, it gets called while
10467 * the frame is still on top. This is less efficient than
10468 * doing it later once it's popped off. There is code further
10469 * down that handles when there isn't an interrupt function.
10470 */
10471 if (zend_interrupt_function) {
10472 // JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
10473 ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
10474 ir_IF_TRUE_cold(if_interrupt);
10475 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), rx);
10476 ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
10477 }
10478
10479 // JIT: EG(current_execute_data) = execute_data;
10480 ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10481
10482 // JIT: zend_vm_stack_free_args(call);
10483 if (func && !unknown_num_args) {
10484 for (i = 0; i < call_num_args; i++ ) {
10485 if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10486 uint32_t offset = EX_NUM_TO_VAR(i);
10487 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
10488
10489 jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, opline);
10490 }
10491 }
10492 } else {
10493 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10494 }
10495
10496 if (may_have_extra_named_params) {
10497 // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10498 ir_ref if_has_named = ir_IF(ir_AND_U8(
10499 ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10500 ir_CONST_U8(ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)));
10501 ir_IF_TRUE_cold(if_has_named);
10502
10503 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_extra_named_params),
10504 ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10505
10506 ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10507 }
10508
10509 if (opline->opcode == ZEND_DO_FCALL) {
10510 // TODO: optimize ???
10511 // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10512 ir_ref if_release_this = ir_IF(ir_AND_U8(
10513 ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10514 ir_CONST_U8(ZEND_CALL_RELEASE_THIS >> 16)));
10515 ir_IF_TRUE_cold(if_release_this);
10516
10517 // JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10518 jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10519
10520 ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10521 }
10522
10523
10524 ir_ref allocated_path = IR_UNUSED;
10525
10526 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10527 !JIT_G(current_frame) ||
10528 !JIT_G(current_frame)->call ||
10529 !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10530 prev_opline->opcode == ZEND_SEND_UNPACK ||
10531 prev_opline->opcode == ZEND_SEND_ARRAY ||
10532 prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10533
10534 // JIT: zend_vm_stack_free_call_frame(call);
10535 // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10536 ir_ref if_allocated = ir_IF(ir_AND_U8(
10537 ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10538 ir_CONST_U8(ZEND_CALL_ALLOCATED >> 16)));
10539 ir_IF_TRUE_cold(if_allocated);
10540
10541 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10542
10543 allocated_path = ir_END();
10544 ir_IF_FALSE(if_allocated);
10545 }
10546
10547 ir_STORE(jit_EG(vm_stack_top), rx);
10548
10549 if (allocated_path) {
10550 ir_MERGE_WITH(allocated_path);
10551 }
10552
10553 if (!RETURN_VALUE_USED(opline)) {
10554 zend_class_entry *ce;
10555 bool ce_is_instanceof;
10556 uint32_t func_info = call_info ?
10557 zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10558 (MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10559
10560 /* If an exception is thrown, the return_value may stay at the
10561 * original value of null. */
10562 func_info |= MAY_BE_NULL;
10563
10564 if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10565 ir_ref sp = ir_RLOAD_A(IR_REG_SP);
10566 res_addr = ZEND_ADDR_REF_ZVAL(sp);
10567 jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
10568 }
10569 if (!jit->ctx.fixed_call_stack_size) {
10570 // JIT: revert alloca
10571 ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10572 }
10573 }
10574
10575 // JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10576 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10577 jit_STUB_ADDR(jit, jit_stub_icall_throw));
10578
10579 /* If there isn't a zend_interrupt_function, the timeout is
10580 * handled here because it's more efficient.
10581 */
10582 if (!zend_interrupt_function) {
10583 // TODO: Can we avoid checking for interrupts after each call ???
10584 if (trace && jit->last_valid_opline != opline) {
10585 int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10586
10587 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10588 if (!exit_addr) {
10589 return 0;
10590 }
10591 } else {
10592 exit_addr = NULL;
10593 }
10594
10595 zend_jit_check_timeout(jit, opline + 1, exit_addr);
10596 }
10597
10598 if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10599 jit_LOAD_IP_ADDR(jit, opline + 1);
10600 } else if (trace
10601 && trace->op == ZEND_JIT_TRACE_END
10602 && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
10603 jit_LOAD_IP_ADDR(jit, opline + 1);
10604 }
10605 }
10606
10607 if (user_path) {
10608 ir_MERGE_WITH(user_path);
10609 }
10610
10611 return 1;
10612 }
10613
10614 static int zend_jit_constructor(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, int next_block)
10615 {
10616 ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10617
10618 ir_IF_FALSE(if_skip_constructor);
10619
10620 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10621 if (!zend_jit_tail_handler(jit, opline)) {
10622 return 0;
10623 }
10624 } else {
10625 if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10626 return 0;
10627 }
10628 }
10629
10630 /* override predecessors of the next block */
10631 ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10632 if (!jit->ctx.control) {
10633 ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10634 ir_IF_TRUE(if_skip_constructor);
10635 ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10636 jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10637 } else {
10638 ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10639 /* merge current control path with the true branch of constructor skip condition */
10640 ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10641 jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10642
10643 jit->b = -1;
10644 }
10645
10646 return 1;
10647 }
10648
10649 static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
10650 {
10651 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10652 uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10653 ir_ref ref, fast_path = IR_UNUSED;
10654
10655 ref = jit_ZVAL_ADDR(jit, res_addr);
10656 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10657 && JIT_G(current_frame)
10658 && JIT_G(current_frame)->prev) {
10659 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10660 uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10661
10662 if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10663 return 1;
10664 }
10665 }
10666
10667 if (ZEND_ARG_SEND_MODE(arg_info)) {
10668 if (opline->opcode == ZEND_RECV_INIT) {
10669 ref = jit_ZVAL_DEREF_ref(jit, ref);
10670 } else {
10671 ref = jit_Z_PTR_ref(jit, ref);
10672 ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
10673 }
10674 }
10675
10676 if (type_mask != 0) {
10677 if (is_power_of_two(type_mask)) {
10678 uint32_t type_code = concrete_type(type_mask);
10679 ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10680 ir_IF_TRUE(if_ok);
10681 fast_path = ir_END();
10682 ir_IF_FALSE_cold(if_ok);
10683 } else {
10684 ir_ref if_ok = ir_IF(ir_AND_U32(
10685 ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10686 ir_CONST_U32(type_mask)));
10687 ir_IF_TRUE(if_ok);
10688 fast_path = ir_END();
10689 ir_IF_FALSE_cold(if_ok);
10690 }
10691 }
10692
10693 jit_SET_EX_OPLINE(jit, opline);
10694 ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10695 ref, ir_CONST_ADDR(arg_info));
10696
10697 if (check_exception) {
10698 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10699 }
10700
10701 if (fast_path) {
10702 ir_MERGE_WITH(fast_path);
10703 }
10704
10705 return 1;
10706 }
10707
10708 static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
10709 {
10710 uint32_t arg_num = opline->op1.num;
10711 zend_arg_info *arg_info = NULL;
10712
10713 if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10714 if (EXPECTED(arg_num <= op_array->num_args)) {
10715 arg_info = &op_array->arg_info[arg_num-1];
10716 } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10717 arg_info = &op_array->arg_info[op_array->num_args];
10718 }
10719 if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10720 arg_info = NULL;
10721 }
10722 }
10723
10724 if (arg_info || (opline+1)->opcode != ZEND_RECV) {
10725 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10726 if (!JIT_G(current_frame) ||
10727 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
10728 arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10729 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10730 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10731
10732 if (!exit_addr) {
10733 return 0;
10734 }
10735 ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
10736 ir_CONST_ADDR(exit_addr));
10737 }
10738 } else {
10739 ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10740 ir_IF_FALSE_cold(if_ok);
10741
10742 jit_SET_EX_OPLINE(jit, opline);
10743 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_missing_arg_error), jit_FP(jit));
10744 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10745 ir_IF_TRUE(if_ok);
10746 }
10747 }
10748
10749 if (arg_info) {
10750 if (!zend_jit_verify_arg_type(jit, opline, arg_info, 1)) {
10751 return 0;
10752 }
10753 }
10754
10755 return 1;
10756 }
10757
10758 static int zend_jit_recv_init(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool is_last, int may_throw)
10759 {
10760 uint32_t arg_num = opline->op1.num;
10761 zval *zv = RT_CONSTANT(opline, opline->op2);
10762 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10763 ir_ref ref, if_fail, skip_path = IR_UNUSED;
10764
10765 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10766 && JIT_G(current_frame)
10767 && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
10768 if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10769 jit_ZVAL_COPY_CONST(jit,
10770 res_addr,
10771 -1, -1,
10772 zv, 1);
10773 }
10774 } else {
10775 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10776 (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
10777 ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10778 ir_IF_TRUE(if_skip);
10779 skip_path = ir_END();
10780 ir_IF_FALSE(if_skip);
10781 }
10782 jit_ZVAL_COPY_CONST(jit,
10783 res_addr,
10784 -1, -1,
10785 zv, 1);
10786 }
10787
10788 if (Z_CONSTANT_P(zv)) {
10789 jit_SET_EX_OPLINE(jit, opline);
10790 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zval_update_constant_ex),
10791 jit_ZVAL_ADDR(jit, res_addr),
10792 ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), offsetof(zend_op_array, scope))));
10793
10794 if_fail = ir_IF(ref);
10795 ir_IF_TRUE_cold(if_fail);
10796 jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, opline);
10797 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10798 ir_IF_FALSE(if_fail);
10799 }
10800
10801 if (skip_path) {
10802 ir_MERGE_WITH(skip_path);
10803 }
10804
10805 if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10806 do {
10807 zend_arg_info *arg_info;
10808
10809 if (arg_num <= op_array->num_args) {
10810 arg_info = &op_array->arg_info[arg_num-1];
10811 } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
10812 arg_info = &op_array->arg_info[op_array->num_args];
10813 } else {
10814 break;
10815 }
10816 if (!ZEND_TYPE_IS_SET(arg_info->type)) {
10817 break;
10818 }
10819 if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw)) {
10820 return 0;
10821 }
10822 } while (0);
10823 }
10824
10825 return 1;
10826 }
10827
10828 static bool zend_jit_verify_return_type(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
10829 {
10830 zend_arg_info *arg_info = &op_array->arg_info[-1];
10831 ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
10832 zend_jit_addr op1_addr = OP1_ADDR();
10833 bool needs_slow_check = 1;
10834 uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10835 ir_ref fast_path = IR_UNUSED;
10836
10837 if (type_mask != 0) {
10838 if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
10839 /* pass */
10840 } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
10841 needs_slow_check = 0;
10842 } else if (is_power_of_two(type_mask)) {
10843 uint32_t type_code = concrete_type(type_mask);
10844 ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
10845
10846 ir_IF_TRUE(if_ok);
10847 fast_path = ir_END();
10848 ir_IF_FALSE_cold(if_ok);
10849 } else {
10850 ir_ref if_ok = ir_IF(ir_AND_U32(
10851 ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
10852 ir_CONST_U32(type_mask)));
10853
10854 ir_IF_TRUE(if_ok);
10855 fast_path = ir_END();
10856 ir_IF_FALSE_cold(if_ok);
10857 }
10858 }
10859 if (needs_slow_check) {
10860 ir_ref ref;
10861
10862 jit_SET_EX_OPLINE(jit, opline);
10863 ref = jit_ZVAL_ADDR(jit, op1_addr);
10864 if (op1_info & MAY_BE_UNDEF) {
10865 ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1);
10866 }
10867
10868 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
10869 ref,
10870 ir_LOAD_A(jit_EX(func)),
10871 ir_CONST_ADDR(arg_info),
10872 ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num));
10873
10874 zend_jit_check_exception(jit);
10875
10876 if (fast_path) {
10877 ir_MERGE_WITH(fast_path);
10878 }
10879 }
10880
10881 return 1;
10882 }
10883
10884 static int zend_jit_leave_frame(zend_jit_ctx *jit)
10885 {
10886 // JIT: EG(current_execute_data) = EX(prev_execute_data);
10887 ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10888 return 1;
10889 }
10890
10891 static int zend_jit_free_cvs(zend_jit_ctx *jit)
10892 {
10893 // JIT: EG(current_execute_data) = EX(prev_execute_data);
10894 ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10895
10896 // JIT: zend_free_compiled_variables(execute_data);
10897 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_compiled_variables), jit_FP(jit));
10898 return 1;
10899 }
10900
10901 static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
10902 {
10903 if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10904 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
10905
10906 jit_ZVAL_PTR_DTOR(jit, var_addr, info, 1, NULL);
10907 }
10908 return 1;
10909 }
10910
10911 static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
10912 {
10913 if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10914 jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, opline);
10915 }
10916 return 1;
10917 }
10918
10919 static int zend_jit_leave_func(zend_jit_ctx *jit,
10920 const zend_op_array *op_array,
10921 const zend_op *opline,
10922 uint32_t op1_info,
10923 bool left_frame,
10924 zend_jit_trace_rec *trace,
10925 zend_jit_trace_info *trace_info,
10926 int indirect_var_access,
10927 int may_throw)
10928 {
10929 bool may_be_top_frame =
10930 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10931 !JIT_G(current_frame) ||
10932 !TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
10933 bool may_need_call_helper =
10934 indirect_var_access || /* may have symbol table */
10935 !op_array->function_name || /* may have symbol table */
10936 may_be_top_frame ||
10937 (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
10938 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10939 !JIT_G(current_frame) ||
10940 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
10941 (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
10942 bool may_need_release_this =
10943 !(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
10944 op_array->scope &&
10945 !(op_array->fn_flags & ZEND_ACC_STATIC) &&
10946 (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10947 !JIT_G(current_frame) ||
10948 !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
10949 ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
10950
10951 if (may_need_call_helper) {
10952 if (!left_frame) {
10953 left_frame = 1;
10954 if (!zend_jit_leave_frame(jit)) {
10955 return 0;
10956 }
10957 }
10958 /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
10959 call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10960 ref = ir_AND_U32(call_info,
10961 ir_CONST_U32(ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE));
10962 if (trace && trace->op != ZEND_JIT_TRACE_END) {
10963 ir_ref if_slow = ir_IF(ref);
10964
10965 ir_IF_TRUE_cold(if_slow);
10966 if (!GCC_GLOBAL_REGS) {
10967 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit));
10968 } else {
10969 ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper));
10970 }
10971
10972 if (may_be_top_frame) {
10973 // TODO: try to avoid this check ???
10974 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
10975 #if 0
10976 /* this check should be handled by the following OPLINE guard */
10977 | cmp IP, zend_jit_halt_op
10978 | je ->trace_halt
10979 #endif
10980 } else if (GCC_GLOBAL_REGS) {
10981 ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10982 } else {
10983 ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10984 }
10985 }
10986
10987 if (!GCC_GLOBAL_REGS) {
10988 // execute_data = EG(current_execute_data)
10989 jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
10990 }
10991 cold_path = ir_END();
10992 ir_IF_FALSE(if_slow);
10993 } else {
10994 ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
10995 }
10996 }
10997
10998 if ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
10999 if (!left_frame) {
11000 left_frame = 1;
11001 if (!zend_jit_leave_frame(jit)) {
11002 return 0;
11003 }
11004 }
11005 // JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
11006 jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
11007 } else if (may_need_release_this) {
11008 ir_ref if_release, fast_path = IR_UNUSED;
11009
11010 if (!left_frame) {
11011 left_frame = 1;
11012 if (!zend_jit_leave_frame(jit)) {
11013 return 0;
11014 }
11015 }
11016 if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
11017 // JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
11018 if (!call_info) {
11019 call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11020 }
11021 if_release = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_RELEASE_THIS)));
11022 ir_IF_FALSE(if_release);
11023 fast_path = ir_END();
11024 ir_IF_TRUE(if_release);
11025 }
11026 // JIT: OBJ_RELEASE(execute_data->This))
11027 jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
11028 if (fast_path) {
11029 ir_MERGE_WITH(fast_path);
11030 }
11031 // TODO: avoid EG(excption) check for $this->foo() calls
11032 may_throw = 1;
11033 }
11034
11035 // JIT: EG(vm_stack_top) = (zval*)execute_data
11036 ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
11037
11038 // JITL execute_data = EX(prev_execute_data)
11039 jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
11040
11041 if (!left_frame) {
11042 // JIT: EG(current_execute_data) = execute_data
11043 ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
11044 }
11045
11046 if (trace) {
11047 if (trace->op != ZEND_JIT_TRACE_END
11048 && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11049 zend_jit_reset_last_valid_opline(jit);
11050 } else {
11051 if (GCC_GLOBAL_REGS) {
11052 /* We add extra RLOAD and RSTORE to make fusion for persistent register
11053 * mov (%FP), %IP
11054 * add $0x1c, %IP
11055 * The naive (commented) code leads to extra register allocation and move.
11056 * mov (%FP), %tmp
11057 * add $0x1c, %tmp
11058 * mov %tmp, %FP
11059 */
11060 #if 0
11061 jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
11062 #else
11063 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11064 jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11065 #endif
11066 } else {
11067 ir_ref ref = jit_EX(opline);
11068
11069 ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
11070 }
11071 }
11072
11073 if (cold_path) {
11074 ir_MERGE_WITH(cold_path);
11075 }
11076
11077 if (trace->op == ZEND_JIT_TRACE_BACK
11078 && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11079 const zend_op *next_opline = trace->opline;
11080
11081 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11082 && (op1_info & MAY_BE_RC1)
11083 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
11084 /* exception might be thrown during destruction of unused return value */
11085 // JIT: if (EG(exception))
11086 ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11087 }
11088 do {
11089 trace++;
11090 } while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
11091 ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11092 next_opline = trace->opline;
11093 ZEND_ASSERT(next_opline != NULL);
11094
11095 if (trace->op == ZEND_JIT_TRACE_END
11096 && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
11097 trace_info->flags |= ZEND_JIT_TRACE_LOOP;
11098
11099 ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
11100
11101 ir_IF_TRUE(if_eq);
11102 ZEND_ASSERT(jit->trace_loop_ref);
11103 ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
11104 ir_MERGE_SET_OP(jit->trace_loop_ref, 2, ir_END());
11105 ir_IF_FALSE(if_eq);
11106
11107 #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
11108 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11109 #else
11110 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
11111 #endif
11112 } else {
11113 ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
11114 }
11115
11116 zend_jit_set_last_valid_opline(jit, trace->opline);
11117
11118 return 1;
11119 } else if (may_throw ||
11120 (((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11121 && (op1_info & MAY_BE_RC1)
11122 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
11123 && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
11124 // JIT: if (EG(exception))
11125 ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11126 }
11127
11128 return 1;
11129 } else {
11130 // JIT: if (EG(exception))
11131 ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11132 // JIT: opline = EX(opline) + 1
11133 if (GCC_GLOBAL_REGS) {
11134 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11135 jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11136 } else {
11137 ir_ref ref = jit_EX(opline);
11138
11139 ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
11140 }
11141 }
11142
11143 if (GCC_GLOBAL_REGS) {
11144 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11145 } else {
11146 ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
11147 }
11148
11149 jit->b = -1;
11150
11151 return 1;
11152 }
11153
11154 static void zend_jit_common_return(zend_jit_ctx *jit)
11155 {
11156 ZEND_ASSERT(jit->return_inputs);
11157 ir_MERGE_list(jit->return_inputs);
11158 }
11159
11160 static int zend_jit_return(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr)
11161 {
11162 zend_jit_addr ret_addr;
11163 int8_t return_value_used = -1;
11164 ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
11165
11166 ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
11167 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
11168
11169 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11170 jit->return_inputs = IR_UNUSED;
11171 if (JIT_G(current_frame)) {
11172 if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
11173 return_value_used = 1;
11174 } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
11175 return_value_used = 0;
11176 } else {
11177 return_value_used = -1;
11178 }
11179 }
11180 }
11181
11182 if (ZEND_OBSERVER_ENABLED) {
11183 if (Z_MODE(op1_addr) == IS_REG) {
11184 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
11185
11186 if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
11187 return 0;
11188 }
11189 op1_addr = dst;
11190 }
11191 jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
11192 }
11193
11194 // JIT: if (!EX(return_value))
11195 return_value = ir_LOAD_A(jit_EX(return_value));
11196 ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
11197 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11198 (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11199 if (return_value_used == -1) {
11200 if_return_value_used = ir_IF(return_value);
11201 ir_IF_FALSE_cold(if_return_value_used);
11202 }
11203 if (return_value_used != 1) {
11204 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11205 ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11206 ir_IF_FALSE(if_refcounted);
11207 ir_END_list(jit->return_inputs);
11208 ir_IF_TRUE(if_refcounted);
11209 }
11210 ref = jit_Z_PTR(jit, op1_addr);
11211 refcount = jit_GC_DELREF(jit, ref);
11212
11213 if (RC_MAY_BE_1(op1_info)) {
11214 if (RC_MAY_BE_N(op1_info)) {
11215 ir_ref if_non_zero = ir_IF(refcount);
11216 ir_IF_TRUE(if_non_zero);
11217 ir_END_list(jit->return_inputs);
11218 ir_IF_FALSE(if_non_zero);
11219 }
11220 jit_ZVAL_DTOR(jit, ref, op1_info, opline);
11221 }
11222 if (return_value_used == -1) {
11223 ir_END_list(jit->return_inputs);
11224 }
11225 }
11226 } else if (return_value_used == -1) {
11227 if_return_value_used = ir_IF(return_value);
11228 ir_IF_FALSE_cold(if_return_value_used);
11229 ir_END_list(jit->return_inputs);
11230 }
11231
11232 if (if_return_value_used) {
11233 ir_IF_TRUE(if_return_value_used);
11234 }
11235
11236 if (return_value_used == 0) {
11237 if (jit->return_inputs) {
11238 ZEND_ASSERT(JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE);
11239 ir_END_list(jit->return_inputs);
11240 ir_MERGE_list(jit->return_inputs);
11241 jit->return_inputs = IR_UNUSED;
11242 }
11243 return 1;
11244 }
11245
11246 if (opline->op1_type == IS_CONST) {
11247 zval *zv = RT_CONSTANT(opline, opline->op1);
11248
11249 jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
11250 } else if (opline->op1_type == IS_TMP_VAR) {
11251 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11252 } else if (opline->op1_type == IS_CV) {
11253 if (op1_info & MAY_BE_REF) {
11254 ref = jit_ZVAL_ADDR(jit, op1_addr);
11255 ref = jit_ZVAL_DEREF_ref(jit, ref);
11256 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11257 }
11258
11259 if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11260 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11261 (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11262 !op_array->function_name) {
11263 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 1);
11264 } else if (return_value_used != 1) {
11265 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11266 // JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11267 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11268 } else {
11269 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11270 }
11271 } else {
11272 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11273 }
11274 } else {
11275 if (op1_info & MAY_BE_REF) {
11276 ir_ref if_ref, ref2, if_non_zero;
11277 zend_jit_addr ref_addr;
11278
11279 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11280 ir_IF_TRUE_cold(if_ref);
11281
11282 // JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11283 ref = jit_Z_PTR(jit, op1_addr);
11284
11285 // JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11286 ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
11287 ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11288 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, 0);
11289 ref2 = jit_GC_DELREF(jit, ref);
11290 if_non_zero = ir_IF(ref2);
11291 ir_IF_TRUE(if_non_zero);
11292
11293 // JIT: if (IS_REFCOUNTED())
11294 ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11295 ir_IF_FALSE(if_refcounted);
11296 ir_END_list(jit->return_inputs);
11297 ir_IF_TRUE(if_refcounted);
11298
11299 // JIT: ADDREF
11300 ref2 = jit_Z_PTR(jit, ret_addr);
11301 jit_GC_ADDREF(jit, ref2);
11302 ir_END_list(jit->return_inputs);
11303
11304 ir_IF_FALSE(if_non_zero);
11305
11306 jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11307 ir_END_list(jit->return_inputs);
11308
11309 ir_IF_FALSE(if_ref);
11310 }
11311 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11312 }
11313
11314 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11315 if (jit->return_inputs) {
11316 ir_END_list(jit->return_inputs);
11317 ir_MERGE_list(jit->return_inputs);
11318 jit->return_inputs = IR_UNUSED;
11319 }
11320 } else {
11321 ir_END_list(jit->return_inputs);
11322 jit->b = -1;
11323 }
11324
11325 return 1;
11326 }
11327
11328 static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11329 {
11330 zend_jit_addr op1_addr = OP1_ADDR();
11331 zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11332 ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11333 ir_ref if_fit, if_reference, if_same_key, fast_path;
11334 ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11335
11336 // JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11337 cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11338 idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11339
11340 // JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11341 num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11342 ir_CONST_U32(sizeof(Bucket)));
11343 if (sizeof(void*) == 8) {
11344 num_used_ref = ir_ZEXT_A(num_used_ref);
11345 }
11346 if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11347 ir_IF_FALSE_cold(if_fit);
11348 ir_END_list(slow_inputs);
11349 ir_IF_TRUE(if_fit);
11350
11351 // JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11352 bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11353 if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11354 ir_IF_FALSE_cold(if_reference);
11355 ir_END_list(slow_inputs);
11356 ir_IF_TRUE(if_reference);
11357
11358 // JIT: (EXPECTED(p->key == varname))
11359 if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11360 ir_IF_FALSE_cold(if_same_key);
11361 ir_END_list(slow_inputs);
11362 ir_IF_TRUE(if_same_key);
11363
11364 // JIT: GC_ADDREF(Z_PTR(p->val))
11365 ref = jit_Z_PTR_ref(jit, bucket_ref);
11366 jit_GC_ADDREF(jit, ref);
11367
11368 fast_path = ir_END();
11369 ir_MERGE_list(slow_inputs);
11370
11371 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11372 ir_CONST_ADDR(varname),
11373 cache_slot_ref);
11374
11375 ir_MERGE_WITH(fast_path);
11376 ref = ir_PHI_2(IR_ADDR, ref2, ref);
11377
11378 if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11379 ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11380
11381 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11382 // JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11383 if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11384 ir_IF_TRUE_cold(if_refcounted);
11385 }
11386
11387 // JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11388 ref2 = jit_Z_PTR(jit, op1_addr);
11389
11390 // JIT: ZVAL_REF(variable_ptr, ref)
11391 jit_set_Z_PTR(jit, op1_addr, ref);
11392 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11393
11394 // JIT: if (GC_DELREF(garbage) == 0)
11395 refcount = jit_GC_DELREF(jit, ref2);
11396 if_non_zero = ir_IF(refcount);
11397 if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11398 ir_IF_TRUE(if_non_zero);
11399 ir_END_list(end_inputs);
11400 }
11401 ir_IF_FALSE(if_non_zero);
11402
11403 jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11404 if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11405 ir_END_list(end_inputs);
11406 ir_IF_TRUE(if_non_zero);
11407
11408 // JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11409 if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11410 ir_IF_TRUE(if_may_not_leak);
11411 ir_END_list(end_inputs);
11412 ir_IF_FALSE(if_may_not_leak);
11413 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref2);
11414 }
11415 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11416 ir_END_list(end_inputs);
11417 ir_IF_FALSE(if_refcounted);
11418 }
11419 }
11420
11421 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11422 // JIT: ZVAL_REF(variable_ptr, ref)
11423 jit_set_Z_PTR(jit, op1_addr, ref);
11424 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11425 }
11426
11427 if (end_inputs) {
11428 ir_END_list(end_inputs);
11429 ir_MERGE_list(end_inputs);
11430 }
11431
11432 return 1;
11433 }
11434
11435 static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11436 {
11437 zend_jit_addr op1_addr = OP1_ADDR();
11438
11439 if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11440 if (may_throw) {
11441 jit_SET_EX_OPLINE(jit, opline);
11442 }
11443 if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11444 ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11445
11446 if (op1_info & MAY_BE_ARRAY) {
11447 if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11448 ir_IF_TRUE(if_array);
11449 ir_END_list(end_inputs);
11450 ir_IF_FALSE(if_array);
11451 }
11452 ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11453 if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11454 ir_IF_TRUE(if_exists);
11455 ir_END_list(end_inputs);
11456 ir_IF_FALSE(if_exists);
11457
11458 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_hash_iterator_del), ref);
11459
11460 ir_END_list(end_inputs);
11461 ir_MERGE_list(end_inputs);
11462 }
11463
11464 jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11465
11466 if (may_throw) {
11467 zend_jit_check_exception(jit);
11468 }
11469 }
11470
11471 return 1;
11472 }
11473
11474 static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11475 {
11476 if (opline->op1_type == IS_CONST) {
11477 zval *zv;
11478 size_t len;
11479
11480 zv = RT_CONSTANT(opline, opline->op1);
11481 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11482 len = Z_STRLEN_P(zv);
11483
11484 if (len > 0) {
11485 const char *str = Z_STRVAL_P(zv);
11486
11487 jit_SET_EX_OPLINE(jit, opline);
11488 ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11489 ir_CONST_ADDR(str), ir_CONST_ADDR(len));
11490
11491 zend_jit_check_exception(jit);
11492 }
11493 } else {
11494 zend_jit_addr op1_addr = OP1_ADDR();
11495 ir_ref ref;
11496
11497 ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11498
11499 jit_SET_EX_OPLINE(jit, opline);
11500
11501 ref = jit_Z_PTR(jit, op1_addr);
11502 ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11503 ir_ADD_OFFSET(ref, offsetof(zend_string, val)),
11504 ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_string, len))));
11505
11506 if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11507 jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11508 }
11509
11510 zend_jit_check_exception(jit);
11511 }
11512 return 1;
11513 }
11514
11515 static int zend_jit_strlen(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr)
11516 {
11517 if (opline->op1_type == IS_CONST) {
11518 zval *zv;
11519 size_t len;
11520
11521 zv = RT_CONSTANT(opline, opline->op1);
11522 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11523 len = Z_STRLEN_P(zv);
11524
11525 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11526 if (Z_MODE(res_addr) != IS_REG) {
11527 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11528 } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11529 return 0;
11530 }
11531 } else {
11532 ir_ref ref;
11533
11534 ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11535
11536 ref = jit_Z_PTR(jit, op1_addr);
11537 ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(zend_string, len)));
11538 jit_set_Z_LVAL(jit, res_addr, ref);
11539
11540 if (Z_MODE(res_addr) == IS_REG) {
11541 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11542 return 0;
11543 }
11544 } else {
11545 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11546 }
11547 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11548 }
11549 return 1;
11550 }
11551
11552 static int zend_jit_count(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw)
11553 {
11554 if (opline->op1_type == IS_CONST) {
11555 zval *zv;
11556 zend_long count;
11557
11558 zv = RT_CONSTANT(opline, opline->op1);
11559 ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
11560 count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11561
11562 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11563 if (Z_MODE(res_addr) != IS_REG) {
11564 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11565 } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11566 return 0;
11567 }
11568 } else {
11569 ir_ref ref;
11570
11571 ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
11572 // Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11573
11574 ref = jit_Z_PTR(jit, op1_addr);
11575 if (sizeof(void*) == 8) {
11576 ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11577 ref = ir_ZEXT_L(ref);
11578 } else {
11579 ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11580 }
11581 jit_set_Z_LVAL(jit, res_addr, ref);
11582
11583 if (Z_MODE(res_addr) == IS_REG) {
11584 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11585 return 0;
11586 }
11587 } else {
11588 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11589 }
11590 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11591 }
11592
11593 if (may_throw) {
11594 zend_jit_check_exception(jit);
11595 }
11596 return 1;
11597 }
11598
11599 static int zend_jit_in_array(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
11600 {
11601 HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11602 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11603 ir_ref ref;
11604
11605 ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11606 ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
11607
11608 // JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11609 if (opline->op1_type != IS_CONST) {
11610 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find),
11611 ir_CONST_ADDR(ht),
11612 jit_Z_PTR(jit, op1_addr));
11613 } else {
11614 zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11615
11616 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash),
11617 ir_CONST_ADDR(ht), ir_CONST_ADDR(str));
11618 }
11619
11620 if (exit_addr) {
11621 if (smart_branch_opcode == ZEND_JMPZ) {
11622 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11623 } else {
11624 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11625 }
11626 } else if (smart_branch_opcode) {
11627 zend_basic_block *bb;
11628
11629 ZEND_ASSERT(jit->b >= 0);
11630 bb = &jit->ssa->cfg.blocks[jit->b];
11631 ZEND_ASSERT(bb->successors_count == 2);
11632 ref = jit_IF_ex(jit, ref,
11633 (smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11634 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11635 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11636 jit->b = -1;
11637 } else {
11638 jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11639 ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, IR_NULL)), ir_CONST_U32(IS_FALSE)));
11640 }
11641
11642 return 1;
11643 }
11644
11645 static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11646 {
11647 uint32_t offset;
11648
11649 offset = (opline->opcode == ZEND_ROPE_INIT) ?
11650 opline->result.var :
11651 opline->op1.var + opline->extended_value * sizeof(zend_string*);
11652
11653 if (opline->op2_type == IS_CONST) {
11654 zval *zv = RT_CONSTANT(opline, opline->op2);
11655 zend_string *str;
11656
11657 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11658 str = Z_STR_P(zv);
11659
11660 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11661 } else {
11662 zend_jit_addr op2_addr = OP2_ADDR();
11663 ir_ref ref;
11664
11665 ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11666
11667 ref = jit_Z_PTR(jit, op2_addr);
11668 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11669 if (opline->op2_type == IS_CV) {
11670 ir_ref if_refcounted, long_path;
11671
11672 if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11673 ir_IF_TRUE(if_refcounted);
11674 jit_GC_ADDREF(jit, ref);
11675 long_path = ir_END();
11676
11677 ir_IF_FALSE(if_refcounted);
11678 ir_MERGE_WITH(long_path);
11679 }
11680 }
11681
11682 if (opline->opcode == ZEND_ROPE_END) {
11683 zend_jit_addr res_addr = RES_ADDR();
11684 ir_ref ref;
11685
11686 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11687 ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11688 ir_CONST_U32(opline->extended_value));
11689
11690 jit_set_Z_PTR(jit, res_addr, ref);
11691 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11692 }
11693
11694 return 1;
11695 }
11696
11697 static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
11698 {
11699 ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
11700 ir_refs *merge_inputs, *types, *ptrs;
11701 #if SIZEOF_ZEND_LONG == 4
11702 ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
11703 ir_refs *values; /* we need this only for zval.w2 copy */
11704 #endif
11705
11706 ir_refs_init(merge_inputs, 4);
11707 ir_refs_init(types, 4);
11708 ir_refs_init(ptrs, 4);
11709 #if SIZEOF_ZEND_LONG == 4
11710 ir_refs_init(values, 4);
11711 #endif
11712
11713 // JIT: ptr = Z_PTR_P(val);
11714 ptr = jit_Z_PTR(jit, val_addr);
11715
11716 // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11717 if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11718 ir_IF_FALSE_cold(if_refcounted);
11719 ir_refs_add(merge_inputs, ir_END());
11720 ir_refs_add(types, type);
11721 ir_refs_add(ptrs, ptr);
11722 #if SIZEOF_ZEND_LONG == 4
11723 ir_refs_add(values, val);
11724 #endif
11725
11726 ir_IF_TRUE(if_refcounted);
11727
11728 // JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
11729 if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
11730 // if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
11731 ir_IF_TRUE(if_reference);
11732
11733 // JIT: val = Z_REFVAL_P(val);
11734 val2 = ir_ADD_OFFSET(ptr, offsetof(zend_reference, val));
11735 type2 = jit_Z_TYPE_INFO_ref(jit, val2);
11736 ptr2 = jit_Z_PTR_ref(jit, val2);
11737
11738 // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11739 if_refcounted2 = ir_IF(ir_AND_U32(type2, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11740 ir_IF_FALSE_cold(if_refcounted2);
11741 ir_refs_add(merge_inputs, ir_END());
11742 ir_refs_add(types, type2);
11743 ir_refs_add(ptrs, ptr2);
11744 #if SIZEOF_ZEND_LONG == 4
11745 ir_refs_add(values, val2);
11746 #endif
11747
11748 ir_IF_TRUE(if_refcounted2);
11749 ir_MERGE_WITH_EMPTY_FALSE(if_reference);
11750 type = ir_PHI_2(IR_U32, type2, type);
11751 ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
11752 #if SIZEOF_ZEND_LONG == 4
11753 val = ir_PHI_2(IR_ADDR, val2, val);
11754 #endif
11755
11756 // JIT: Z_ADDREF_P(val);
11757 jit_GC_ADDREF(jit, ptr);
11758 ir_refs_add(merge_inputs, ir_END());
11759 ir_refs_add(types, type);
11760 ir_refs_add(ptrs, ptr);
11761 #if SIZEOF_ZEND_LONG == 4
11762 ir_refs_add(values, val);
11763 #endif
11764
11765 ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
11766 type = ir_PHI_N(IR_U32, types->count, types->refs);
11767 ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
11768 #if SIZEOF_ZEND_LONG == 4
11769 val = ir_PHI_N(IR_ADDR, values->count, values->refs);
11770 val_addr = ZEND_ADDR_REF_ZVAL(val);
11771 #endif
11772
11773 // JIT: Z_PTR_P(res) = ptr;
11774 jit_set_Z_PTR(jit, res_addr, ptr);
11775 #if SIZEOF_ZEND_LONG == 4
11776 jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
11777 #endif
11778 jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
11779
11780 return 1;
11781 }
11782
11783 static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx *jit,
11784 const zend_op *opline,
11785 uint32_t type,
11786 uint32_t op1_info,
11787 uint32_t op2_info,
11788 zend_jit_addr op2_addr,
11789 zend_ssa_range *op2_range,
11790 uint8_t dim_type,
11791 const void *found_exit_addr,
11792 const void *not_found_exit_addr,
11793 const void *exit_addr,
11794 bool result_type_guard,
11795 ir_ref ht_ref,
11796 ir_refs *found_inputs,
11797 ir_refs *found_vals,
11798 ir_ref *end_inputs,
11799 ir_ref *not_found_inputs)
11800 {
11801 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11802 ir_ref ref = IR_UNUSED, cond, if_found;
11803 ir_ref if_type = IS_UNUSED;
11804 ir_refs *test_zval_inputs, *test_zval_values;
11805
11806 ir_refs_init(test_zval_inputs, 4);
11807 ir_refs_init(test_zval_values, 4);
11808
11809 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11810 && type == BP_VAR_R
11811 && !exit_addr) {
11812 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11813 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11814 if (!exit_addr) {
11815 return 0;
11816 }
11817 }
11818
11819 if (op2_info & MAY_BE_LONG) {
11820 bool op2_loaded = 0;
11821 bool packed_loaded = 0;
11822 bool bad_packed_key = 0;
11823 ir_ref if_packed = IS_UNDEF;
11824 ir_ref h = IR_UNUSED;
11825 ir_ref idx_not_found_inputs = IR_UNUSED;
11826
11827 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
11828 // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
11829 if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
11830 ir_IF_TRUE(if_type);
11831 }
11832 if (op1_info & MAY_BE_PACKED_GUARD) {
11833 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
11834 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11835
11836 if (!exit_addr) {
11837 return 0;
11838 }
11839 cond = ir_AND_U32(
11840 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11841 ir_CONST_U32(HASH_FLAG_PACKED));
11842 if (op1_info & MAY_BE_ARRAY_PACKED) {
11843 ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11844 } else {
11845 ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
11846 }
11847 }
11848 if (type == BP_VAR_W) {
11849 // JIT: hval = Z_LVAL_P(dim);
11850 h = jit_Z_LVAL(jit, op2_addr);
11851 op2_loaded = 1;
11852 }
11853 if (op1_info & MAY_BE_ARRAY_PACKED) {
11854 zend_long val = -1;
11855
11856 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
11857 val = Z_LVAL_P(Z_ZV(op2_addr));
11858 if (val >= 0 && val < HT_MAX_SIZE) {
11859 packed_loaded = 1;
11860 } else {
11861 bad_packed_key = 1;
11862 }
11863 h = ir_CONST_LONG(val);
11864 } else {
11865 if (!op2_loaded) {
11866 // JIT: hval = Z_LVAL_P(dim);
11867 h = jit_Z_LVAL(jit, op2_addr);
11868 op2_loaded = 1;
11869 }
11870 packed_loaded = 1;
11871 }
11872
11873 if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
11874 /* don't generate "fast" code for packed array */
11875 packed_loaded = 0;
11876 }
11877
11878 if (packed_loaded) {
11879 // JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
11880 if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11881 if_packed = ir_IF(
11882 ir_AND_U32(
11883 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11884 ir_CONST_U32(HASH_FLAG_PACKED)));
11885 ir_IF_TRUE(if_packed);
11886 }
11887 // JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
11888 ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
11889 #if SIZEOF_ZEND_LONG == 8
11890 if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
11891 || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
11892 /* comapre only the lower 32-bits to allow load fusion on x86_64 */
11893 cond = ir_ULT(ir_TRUNC_U32(h), ref);
11894 } else {
11895 cond = ir_ULT(h, ir_ZEXT_L(ref));
11896 }
11897 #else
11898 cond = ir_ULT(h, ref);
11899 #endif
11900 if (type == BP_JIT_IS) {
11901 if (not_found_exit_addr) {
11902 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11903 } else {
11904 ir_ref if_fit = ir_IF(cond);
11905 ir_IF_FALSE(if_fit);
11906 ir_END_list(*end_inputs);
11907 ir_IF_TRUE(if_fit);
11908 }
11909 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11910 ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11911 } else if (type == BP_VAR_IS && not_found_exit_addr) {
11912 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11913 } else if (type == BP_VAR_RW && not_found_exit_addr) {
11914 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11915 } else if (type == BP_VAR_IS && result_type_guard) {
11916 ir_ref if_fit = ir_IF(cond);
11917 ir_IF_FALSE(if_fit);
11918 ir_END_list(*not_found_inputs);
11919 ir_IF_TRUE(if_fit);
11920 } else {
11921 ir_ref if_fit = ir_IF(cond);
11922 ir_IF_FALSE(if_fit);
11923 ir_END_list(idx_not_found_inputs);
11924 ir_IF_TRUE(if_fit);
11925 }
11926 // JIT: _ret = &_ht->arPacked[h];
11927 ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
11928 ref = ir_BITCAST_A(ref);
11929 ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
11930 if (type == BP_JIT_IS) {
11931 ir_refs_add(test_zval_values, ref);
11932 ir_refs_add(test_zval_inputs, ir_END());
11933 }
11934 }
11935 }
11936 switch (type) {
11937 case BP_JIT_IS:
11938 if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11939 if (if_packed) {
11940 ir_IF_FALSE(if_packed);
11941 if_packed = IR_UNUSED;
11942 }
11943 if (!op2_loaded) {
11944 // JIT: hval = Z_LVAL_P(dim);
11945 h = jit_Z_LVAL(jit, op2_addr);
11946 op2_loaded = 1;
11947 }
11948 if (packed_loaded) {
11949 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11950 } else {
11951 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11952 }
11953 if (not_found_exit_addr) {
11954 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11955 } else {
11956 if_found = ir_IF(ref);
11957 ir_IF_FALSE(if_found);
11958 ir_END_list(*end_inputs);
11959 ir_IF_TRUE(if_found);
11960 }
11961 ir_refs_add(test_zval_values, ref);
11962 ir_refs_add(test_zval_inputs, ir_END());
11963 } else if (!not_found_exit_addr && !packed_loaded) {
11964 ir_END_list(*end_inputs);
11965 }
11966 break;
11967 case BP_VAR_R:
11968 case BP_VAR_IS:
11969 case BP_VAR_UNSET:
11970 if (packed_loaded) {
11971 ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
11972
11973 if (result_type_guard) {
11974 /* perform IS_UNDEF check only after result type guard (during deoptimization) */
11975 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11976 ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
11977 } else if (type == BP_VAR_IS && not_found_exit_addr) {
11978 ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
11979 } else {
11980 ir_ref if_def = ir_IF(type_ref);
11981 ir_IF_FALSE(if_def);
11982 ir_END_list(idx_not_found_inputs);
11983 ir_IF_TRUE(if_def);
11984 }
11985 ir_refs_add(found_inputs, ir_END());
11986 ir_refs_add(found_vals, ref);
11987 }
11988 if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11989 if (if_packed) {
11990 ir_IF_FALSE(if_packed);
11991 if_packed = IR_UNUSED;
11992 }
11993 if (!op2_loaded) {
11994 // JIT: hval = Z_LVAL_P(dim);
11995 h = jit_Z_LVAL(jit, op2_addr);
11996 op2_loaded = 1;
11997 }
11998 if (packed_loaded) {
11999 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12000 } else {
12001 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12002 }
12003 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12004 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12005 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12006 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12007 } else if (type == BP_VAR_IS && result_type_guard) {
12008 if_found = ir_IF(ref);
12009 ir_IF_FALSE(if_found);
12010 ir_END_list(*not_found_inputs);
12011 ir_IF_TRUE(if_found);
12012 } else {
12013 if_found = ir_IF(ref);
12014 ir_IF_FALSE(if_found);
12015 ir_END_list(idx_not_found_inputs);
12016 ir_IF_TRUE(if_found);
12017 }
12018 ir_refs_add(found_inputs, ir_END());
12019 ir_refs_add(found_vals, ref);
12020 } else if (!packed_loaded) {
12021 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12022 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12023 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12024 jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
12025 } else if (type == BP_VAR_IS && result_type_guard) {
12026 ir_END_list(*not_found_inputs);
12027 } else {
12028 ir_END_list(idx_not_found_inputs);
12029 }
12030 }
12031
12032 if (idx_not_found_inputs) {
12033 ir_MERGE_list(idx_not_found_inputs);
12034 switch (type) {
12035 case BP_VAR_R:
12036 ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
12037 // JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
12038 // JIT: retval = &EG(uninitialized_zval);
12039 jit_SET_EX_OPLINE(jit, opline);
12040 if (Z_MODE(op2_addr) == IS_REG) {
12041 if (!op2_loaded) {
12042 // JIT: hval = Z_LVAL_P(dim);
12043 h = jit_Z_LVAL(jit, op2_addr);
12044 }
12045 if (GCC_GLOBAL_REGS) {
12046 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h);
12047 } else {
12048 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h, jit_FP(jit));
12049 }
12050 } else {
12051 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
12052 }
12053 ir_END_list(*end_inputs);
12054 break;
12055 case BP_VAR_IS:
12056 case BP_VAR_UNSET:
12057 if (!not_found_exit_addr) {
12058 // JIT: retval = &EG(uninitialized_zval);
12059 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12060 ir_END_list(*end_inputs);
12061 }
12062 break;
12063 default:
12064 ZEND_UNREACHABLE();
12065 }
12066 }
12067 break;
12068 case BP_VAR_RW:
12069 if (packed_loaded) {
12070 if (not_found_exit_addr) {
12071 ir_refs_add(found_inputs, ir_END());
12072 ir_refs_add(found_vals, ref);
12073 } else {
12074 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12075 ir_IF_TRUE(if_def);
12076 ir_refs_add(found_inputs, ir_END());
12077 ir_refs_add(found_vals, ref);
12078 ir_IF_FALSE_cold(if_def);
12079 ir_END_list(idx_not_found_inputs);
12080 }
12081 }
12082 if (!packed_loaded ||
12083 !not_found_exit_addr ||
12084 (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
12085 if (if_packed) {
12086 ir_IF_FALSE(if_packed);
12087 if_packed = IR_UNUSED;
12088 ir_END_list(idx_not_found_inputs);
12089 } else if (!packed_loaded) {
12090 ir_END_list(idx_not_found_inputs);
12091 }
12092
12093 ir_MERGE_list(idx_not_found_inputs);
12094 if (!op2_loaded) {
12095 // JIT: hval = Z_LVAL_P(dim);
12096 h = jit_Z_LVAL(jit, op2_addr);
12097 }
12098 if (packed_loaded) {
12099 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
12100 ht_ref, h);
12101 } else {
12102 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
12103 }
12104 if (not_found_exit_addr) {
12105 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12106 } else {
12107 if_found = ir_IF(ref);
12108 ir_IF_FALSE(if_found);
12109 ir_END_list(*end_inputs);
12110 ir_IF_TRUE(if_found);
12111 }
12112 ir_refs_add(found_inputs, ir_END());
12113 ir_refs_add(found_vals, ref);
12114 }
12115 break;
12116 case BP_VAR_W:
12117 if (packed_loaded) {
12118 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12119 ir_IF_TRUE_cold(if_def);
12120 ir_refs_add(found_inputs, ir_END());
12121 ir_refs_add(found_vals, ref);
12122 ir_IF_FALSE(if_def);
12123 ir_END_list(idx_not_found_inputs);
12124 }
12125 if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
12126 if (if_packed) {
12127 ir_IF_FALSE(if_packed);
12128 if_packed = IR_UNUSED;
12129 ir_END_list(idx_not_found_inputs);
12130 } else if (!packed_loaded) {
12131 ir_END_list(idx_not_found_inputs);
12132 }
12133 ir_MERGE_list(idx_not_found_inputs);
12134 if (!op2_loaded) {
12135 // JIT: hval = Z_LVAL_P(dim);
12136 h = jit_Z_LVAL(jit, op2_addr);
12137 }
12138 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
12139 ir_refs_add(found_inputs, ir_END());
12140 ir_refs_add(found_vals, ref);
12141 }
12142 break;
12143 default:
12144 ZEND_UNREACHABLE();
12145 }
12146 }
12147
12148 if (op2_info & MAY_BE_STRING) {
12149 ir_ref key;
12150
12151 if (if_type) {
12152 ir_IF_FALSE(if_type);
12153 if_type = IS_UNUSED;
12154 }
12155
12156 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12157 // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
12158 if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
12159 ir_IF_TRUE(if_type);
12160 }
12161
12162 // JIT: offset_key = Z_STR_P(dim);
12163 key = jit_Z_PTR(jit, op2_addr);
12164
12165 // JIT: retval = zend_hash_find(ht, offset_key);
12166 switch (type) {
12167 case BP_JIT_IS:
12168 if (opline->op2_type != IS_CONST) {
12169 ir_ref if_num, end1, ref2;
12170
12171 if_num = ir_IF(
12172 ir_ULE(
12173 ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12174 ir_CONST_CHAR('9')));
12175 ir_IF_TRUE_cold(if_num);
12176 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12177 end1 = ir_END();
12178 ir_IF_FALSE(if_num);
12179 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12180 ir_MERGE_WITH(end1);
12181 ref = ir_PHI_2(IR_ADDR, ref2, ref);
12182 } else {
12183 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12184 }
12185 if (not_found_exit_addr) {
12186 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12187 } else {
12188 if_found = ir_IF(ref);
12189 ir_IF_FALSE(if_found);
12190 ir_END_list(*end_inputs);
12191 ir_IF_TRUE(if_found);
12192 }
12193 ir_refs_add(test_zval_values, ref);
12194 ir_refs_add(test_zval_inputs, ir_END());
12195 break;
12196 case BP_VAR_R:
12197 case BP_VAR_IS:
12198 case BP_VAR_UNSET:
12199 if (opline->op2_type != IS_CONST) {
12200 ir_ref if_num, end1, ref2;
12201
12202 if_num = ir_IF(
12203 ir_ULE(
12204 ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12205 ir_CONST_CHAR('9')));
12206 ir_IF_TRUE_cold(if_num);
12207 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12208 end1 = ir_END();
12209 ir_IF_FALSE(if_num);
12210 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12211 ir_MERGE_WITH(end1);
12212 ref = ir_PHI_2(IR_ADDR, ref2, ref);
12213 } else {
12214 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12215 }
12216 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12217 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12218 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12219 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12220 } else if (type == BP_VAR_IS && result_type_guard) {
12221 if_found = ir_IF(ref);
12222 ir_IF_FALSE(if_found);
12223 ir_END_list(*not_found_inputs);
12224 ir_IF_TRUE(if_found);
12225 } else {
12226 if_found = ir_IF(ref);
12227 switch (type) {
12228 case BP_VAR_R:
12229 ir_IF_FALSE_cold(if_found);
12230 // JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
12231 jit_SET_EX_OPLINE(jit, opline);
12232 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
12233 ir_END_list(*end_inputs);
12234 break;
12235 case BP_VAR_IS:
12236 case BP_VAR_UNSET:
12237 ir_IF_FALSE(if_found);
12238 // JIT: retval = &EG(uninitialized_zval);
12239 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12240 ir_END_list(*end_inputs);
12241 break;
12242 default:
12243 ZEND_UNREACHABLE();
12244 }
12245 ir_IF_TRUE(if_found);
12246 }
12247 ir_refs_add(found_inputs, ir_END());
12248 ir_refs_add(found_vals, ref);
12249 break;
12250 case BP_VAR_RW:
12251 if (opline->op2_type != IS_CONST) {
12252 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
12253 } else {
12254 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
12255 }
12256 if (not_found_exit_addr) {
12257 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12258 } else {
12259 if_found = ir_IF(ref);
12260 ir_IF_FALSE(if_found);
12261 ir_END_list(*end_inputs);
12262 ir_IF_TRUE(if_found);
12263 }
12264 ir_refs_add(found_inputs, ir_END());
12265 ir_refs_add(found_vals, ref);
12266 break;
12267 case BP_VAR_W:
12268 if (opline->op2_type != IS_CONST) {
12269 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12270 } else {
12271 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12272 }
12273 ir_refs_add(found_inputs, ir_END());
12274 ir_refs_add(found_vals, ref);
12275 break;
12276 default:
12277 ZEND_UNREACHABLE();
12278 }
12279 }
12280
12281 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12282 if (if_type) {
12283 ir_IF_FALSE_cold(if_type);
12284 if_type = IS_UNDEF;
12285 }
12286 if (type != BP_VAR_RW) {
12287 jit_SET_EX_OPLINE(jit, opline);
12288 }
12289 ref = jit_ZVAL_ADDR(jit, op2_addr);
12290 switch (type) {
12291 case BP_VAR_R:
12292 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12293 ht_ref,
12294 ref,
12295 jit_ZVAL_ADDR(jit, res_addr));
12296 ir_END_list(*end_inputs);
12297 break;
12298 case BP_JIT_IS:
12299 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12300 if (not_found_exit_addr) {
12301 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12302 ir_refs_add(found_inputs, ir_END());
12303 } else if (found_exit_addr) {
12304 ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12305 ir_END_list(*end_inputs);
12306 } else {
12307 if_found = ir_IF(ref);
12308 ir_IF_TRUE(if_found);
12309 ir_refs_add(found_inputs, ir_END());
12310 ir_IF_FALSE(if_found);
12311 ir_END_list(*end_inputs);
12312 }
12313 break;
12314 case BP_VAR_IS:
12315 case BP_VAR_UNSET:
12316 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12317 ht_ref,
12318 ref,
12319 jit_ZVAL_ADDR(jit, res_addr));
12320 ir_END_list(*end_inputs);
12321 break;
12322 case BP_VAR_RW:
12323 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12324 if_found = ir_IF(ref);
12325 ir_IF_TRUE(if_found);
12326 ir_refs_add(found_inputs, ir_END());
12327 ir_refs_add(found_vals, ref);
12328 ir_IF_FALSE(if_found);
12329 ir_END_list(*end_inputs);
12330 break;
12331 case BP_VAR_W:
12332 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12333 if_found = ir_IF(ref);
12334 ir_IF_TRUE(if_found);
12335 ir_refs_add(found_inputs, ir_END());
12336 ir_refs_add(found_vals, ref);
12337 ir_IF_FALSE(if_found);
12338 ir_END_list(*end_inputs);
12339 break;
12340 default:
12341 ZEND_UNREACHABLE();
12342 }
12343 }
12344
12345 if (type == BP_JIT_IS
12346 && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12347 /* dead code */
12348 ir_END_list(*end_inputs);
12349 } else if (type == BP_JIT_IS
12350 && (op1_info & MAY_BE_ARRAY)
12351 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12352 && test_zval_inputs->count) {
12353
12354 ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12355 ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12356
12357 if (op1_info & MAY_BE_ARRAY_OF_REF) {
12358 ref = jit_ZVAL_DEREF_ref(jit, ref);
12359 }
12360 cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12361 if (not_found_exit_addr) {
12362 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12363 ir_refs_add(found_inputs, ir_END());
12364 } else if (found_exit_addr) {
12365 ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12366 ir_END_list(*end_inputs);
12367 } else {
12368 ir_ref if_set = ir_IF(cond);
12369 ir_IF_FALSE(if_set);
12370 ir_END_list(*end_inputs);
12371 ir_IF_TRUE(if_set);
12372 ir_refs_add(found_inputs, ir_END());
12373 }
12374 }
12375
12376 return 1;
12377 }
12378
12379 static int zend_jit_fetch_dim_read(zend_jit_ctx *jit,
12380 const zend_op *opline,
12381 zend_ssa *ssa,
12382 const zend_ssa_op *ssa_op,
12383 uint32_t op1_info,
12384 zend_jit_addr op1_addr,
12385 bool op1_avoid_refcounting,
12386 uint32_t op2_info,
12387 zend_jit_addr op2_addr,
12388 zend_ssa_range *op2_range,
12389 uint32_t res_info,
12390 zend_jit_addr res_addr,
12391 uint8_t dim_type)
12392 {
12393 zend_jit_addr orig_op1_addr;
12394 const void *exit_addr = NULL;
12395 const void *not_found_exit_addr = NULL;
12396 bool result_type_guard = 0;
12397 bool result_avoid_refcounting = 0;
12398 uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12399 int may_throw = 0;
12400 ir_ref if_type = IR_UNUSED;
12401 ir_ref end_inputs = IR_UNUSED;
12402 ir_ref not_found_inputs = IR_UNUSED;
12403
12404 orig_op1_addr = OP1_ADDR();
12405
12406 if (opline->opcode != ZEND_FETCH_DIM_IS
12407 && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12408 && !has_concrete_type(op1_info)) {
12409 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12410 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12411 if (!exit_addr) {
12412 return 0;
12413 }
12414 }
12415
12416 if ((res_info & MAY_BE_GUARD)
12417 && JIT_G(current_frame)
12418 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12419
12420 if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12421 result_type_guard = 1;
12422 res_info &= ~MAY_BE_GUARD;
12423 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12424 }
12425
12426 if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12427 && (opline->opcode == ZEND_FETCH_LIST_R
12428 || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12429 || op1_avoid_refcounting)
12430 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12431 && (ssa_op+1)->op1_use == ssa_op->result_def
12432 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12433 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12434 result_avoid_refcounting = 1;
12435 ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12436 }
12437
12438 if (opline->opcode == ZEND_FETCH_DIM_IS
12439 && !(res_info & MAY_BE_NULL)) {
12440 uint32_t flags = 0;
12441 uint32_t old_op1_info = 0;
12442 uint32_t old_info;
12443 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12444 int32_t exit_point;
12445
12446 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
12447 && !op1_avoid_refcounting) {
12448 flags |= ZEND_JIT_EXIT_FREE_OP1;
12449 }
12450 if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12451 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12452 flags |= ZEND_JIT_EXIT_FREE_OP2;
12453 }
12454
12455 if (op1_avoid_refcounting) {
12456 old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12457 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12458 }
12459
12460 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12461 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12462 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_TYPE_ONLY);
12463 exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12464 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12465 not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12466 if (!not_found_exit_addr) {
12467 return 0;
12468 }
12469
12470 if (op1_avoid_refcounting) {
12471 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12472 }
12473 }
12474 }
12475
12476 if (op1_info & MAY_BE_REF) {
12477 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12478 ref = jit_ZVAL_DEREF_ref(jit, ref);
12479 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12480 }
12481
12482 if (op1_info & MAY_BE_ARRAY) {
12483 ir_ref ht_ref, ref;
12484 zend_jit_addr val_addr;
12485 ir_refs *found_inputs, *found_vals;
12486
12487 ir_refs_init(found_inputs, 10);
12488 ir_refs_init(found_vals, 10);
12489
12490 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12491 if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12492 jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12493 } else {
12494 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12495 ir_IF_TRUE(if_type);
12496 }
12497 }
12498
12499 ht_ref = jit_Z_PTR(jit, op1_addr);
12500
12501 if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12502 (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12503 may_throw = 1;
12504 }
12505
12506 if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12507 (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12508 op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12509 result_type_guard, ht_ref, found_inputs, found_vals,
12510 &end_inputs, ¬_found_inputs)) {
12511 return 0;
12512 }
12513
12514 if (found_inputs->count) {
12515 ir_MERGE_N(found_inputs->count, found_inputs->refs);
12516 ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12517 val_addr = ZEND_ADDR_REF_ZVAL(ref);
12518
12519 if (result_type_guard) {
12520 uint8_t type = concrete_type(res_info);
12521 uint32_t flags = 0;
12522
12523 if (opline->opcode != ZEND_FETCH_LIST_R
12524 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12525 && !op1_avoid_refcounting) {
12526 flags |= ZEND_JIT_EXIT_FREE_OP1;
12527 }
12528 if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12529 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12530 flags |= ZEND_JIT_EXIT_FREE_OP2;
12531 }
12532
12533 val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12534 (op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12535 if (!val_addr) {
12536 return 0;
12537 }
12538
12539 if (not_found_inputs) {
12540 ir_END_list(not_found_inputs);
12541 ir_MERGE_list(not_found_inputs);
12542 }
12543
12544 // ZVAL_COPY
12545 jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12546 if (Z_MODE(res_addr) != IS_REG) {
12547 } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12548 return 0;
12549 }
12550 } else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12551 // ZVAL_COPY_DEREF
12552 ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12553 if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12554 return 0;
12555 }
12556 } else {
12557 // ZVAL_COPY
12558 jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, 1);
12559 }
12560
12561 ir_END_list(end_inputs);
12562 } else if (not_found_inputs) {
12563 ir_MERGE_list(not_found_inputs);
12564 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12565 ir_END_list(end_inputs);
12566 } else if (!end_inputs && jit->ctx.control) {
12567 ir_END_list(end_inputs); /* dead code */
12568 }
12569 }
12570
12571 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12572 if (if_type) {
12573 ir_IF_FALSE_cold(if_type);
12574 if_type = IS_UNDEF;
12575 }
12576
12577 if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12578 ir_ref str_ref;
12579
12580 may_throw = 1;
12581 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12582 if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12583 jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12584 } else {
12585 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12586 ir_IF_TRUE(if_type);
12587 }
12588 }
12589 jit_SET_EX_OPLINE(jit, opline);
12590 str_ref = jit_Z_PTR(jit, op1_addr);
12591 if (opline->opcode != ZEND_FETCH_DIM_IS) {
12592 ir_ref ref;
12593
12594 if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12595 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12596 str_ref, jit_Z_LVAL(jit, op2_addr));
12597 } else {
12598 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12599 str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12600 }
12601 jit_set_Z_PTR(jit, res_addr, ref);
12602 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12603 } else {
12604 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12605 str_ref,
12606 jit_ZVAL_ADDR(jit, op2_addr),
12607 jit_ZVAL_ADDR(jit, res_addr));
12608 }
12609 ir_END_list(end_inputs);
12610 }
12611
12612 if (op1_info & MAY_BE_OBJECT) {
12613 ir_ref arg2;
12614
12615 if (if_type) {
12616 ir_IF_FALSE_cold(if_type);
12617 if_type = IS_UNDEF;
12618 }
12619
12620 may_throw = 1;
12621 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12622 if (exit_addr) {
12623 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12624 } else {
12625 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12626 ir_IF_TRUE(if_type);
12627 }
12628 }
12629
12630 jit_SET_EX_OPLINE(jit, opline);
12631 if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12632 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12633 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12634 } else {
12635 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12636 }
12637
12638 if (opline->opcode != ZEND_FETCH_DIM_IS) {
12639 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12640 jit_ZVAL_ADDR(jit, op1_addr),
12641 arg2,
12642 jit_ZVAL_ADDR(jit, res_addr));
12643 } else {
12644 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12645 jit_ZVAL_ADDR(jit, op1_addr),
12646 arg2,
12647 jit_ZVAL_ADDR(jit, res_addr));
12648 }
12649
12650 ir_END_list(end_inputs);
12651 }
12652
12653 if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12654 && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12655
12656 if (if_type) {
12657 ir_IF_FALSE_cold(if_type);
12658 if_type = IS_UNDEF;
12659 }
12660
12661 if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12662 jit_SET_EX_OPLINE(jit, opline);
12663 if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12664 may_throw = 1;
12665 zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL, 0, 1, 0);
12666 }
12667
12668 if (op2_info & MAY_BE_UNDEF) {
12669 may_throw = 1;
12670 zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL, 0, 1, 0);
12671 }
12672 }
12673
12674 if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
12675 ir_ref ref;
12676
12677 may_throw = 1;
12678 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12679 ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
12680 } else {
12681 jit_SET_EX_OPLINE(jit, opline);
12682 ref = jit_ZVAL_ADDR(jit, op1_addr);
12683 }
12684 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
12685 }
12686
12687 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12688 ir_END_list(end_inputs);
12689 }
12690 }
12691
12692 if (end_inputs) {
12693 ir_MERGE_list(end_inputs);
12694
12695 #ifdef ZEND_JIT_USE_RC_INFERENCE
12696 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12697 /* Magic offsetGet() may increase refcount of the key */
12698 op2_info |= MAY_BE_RCN;
12699 }
12700 #endif
12701
12702 if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
12703 if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
12704 may_throw = 1;
12705 }
12706 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12707 }
12708 if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12709 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
12710 if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
12711 may_throw = 1;
12712 }
12713 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
12714 }
12715 }
12716
12717 if (may_throw) {
12718 zend_jit_check_exception(jit);
12719 }
12720 } else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
12721 ir_BEGIN(IR_UNUSED); /* unreachable tail */
12722 }
12723
12724 return 1;
12725 }
12726
12727 static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx *jit,
12728 const zend_op *opline,
12729 uint32_t *op1_info_ptr,
12730 zend_jit_addr op1_addr,
12731 ir_ref *if_type,
12732 ir_ref *ht_ref,
12733 int *may_throw)
12734 {
12735 ir_ref ref = IR_UNUSED;
12736 ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
12737 ir_refs *array_inputs, *array_values;
12738 uint32_t op1_info = *op1_info_ptr;
12739
12740 ir_refs_init(array_inputs, 4);
12741 ir_refs_init(array_values, 4);
12742
12743 ref = jit_ZVAL_ADDR(jit, op1_addr);
12744 if (op1_info & MAY_BE_REF) {
12745 ir_ref if_reference, if_array, end1, ref2;
12746
12747 *may_throw = 1;
12748 if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
12749 ir_IF_FALSE(if_reference);
12750 end1 = ir_END();
12751 ir_IF_TRUE_cold(if_reference);
12752 array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
12753 if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
12754 ir_IF_TRUE(if_array);
12755 array_reference_end = ir_END();
12756 ir_IF_FALSE_cold(if_array);
12757 if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
12758 jit_SET_EX_OPLINE(jit, opline);
12759 }
12760 ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
12761 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
12762
12763 ir_MERGE_WITH(end1);
12764 ref = ir_PHI_2(IR_ADDR, ref2, ref);
12765 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12766 }
12767
12768 if (op1_info & MAY_BE_ARRAY) {
12769 ir_ref op1_ref = ref;
12770
12771 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12772 *if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12773 ir_IF_TRUE(*if_type);
12774 }
12775 if (array_reference_end) {
12776 ir_MERGE_WITH(array_reference_end);
12777 op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
12778 }
12779 // JIT: SEPARATE_ARRAY()
12780 ref = jit_Z_PTR_ref(jit, op1_ref);
12781 if (RC_MAY_BE_N(op1_info)) {
12782 if (RC_MAY_BE_1(op1_info)) {
12783 ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
12784 ir_IF_TRUE(if_refcount_1);
12785 ir_refs_add(array_inputs, ir_END());
12786 ir_refs_add(array_values, ref);
12787 ir_IF_FALSE(if_refcount_1);
12788 }
12789 ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
12790 }
12791 if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
12792 ir_refs_add(array_inputs, ir_END());
12793 ir_refs_add(array_values, ref);
12794 }
12795 }
12796
12797 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
12798 if (*if_type) {
12799 ir_IF_FALSE_cold(*if_type);
12800 *if_type = IR_UNUSED;
12801 }
12802 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12803 *if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
12804 ir_IF_TRUE(*if_type);
12805 }
12806 if ((op1_info & MAY_BE_UNDEF)
12807 && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
12808 ir_ref end1 = IR_UNUSED;
12809
12810 *may_throw = 1;
12811 if (op1_info & MAY_BE_NULL) {
12812 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
12813 ir_IF_TRUE(if_def);
12814 end1 = ir_END();
12815 ir_IF_FALSE(if_def);
12816 }
12817 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
12818 if (end1) {
12819 ir_MERGE_WITH(end1);
12820 }
12821 }
12822 // JIT: ZVAL_ARR(container, zend_new_array(8));
12823 ref = ir_CALL_1(IR_ADDR,
12824 jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
12825 jit_ZVAL_ADDR(jit, op1_addr));
12826 if (array_inputs->count) {
12827 ir_refs_add(array_inputs, ir_END());
12828 ir_refs_add(array_values, ref);
12829 }
12830 op1_info &= ~(MAY_BE_UNDEF | MAY_BE_NULL);
12831 op1_info |= MAY_BE_ARRAY | MAY_BE_RC1;
12832 *op1_info_ptr = op1_info;
12833 }
12834
12835 if (array_inputs->count) {
12836 ir_MERGE_N(array_inputs->count, array_inputs->refs);
12837 ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
12838 }
12839
12840 *ht_ref = ref;
12841 return op1_addr;
12842 }
12843
12844 static int zend_jit_fetch_dim(zend_jit_ctx *jit,
12845 const zend_op *opline,
12846 uint32_t op1_info,
12847 zend_jit_addr op1_addr,
12848 uint32_t op2_info,
12849 zend_jit_addr op2_addr,
12850 zend_ssa_range *op2_range,
12851 zend_jit_addr res_addr,
12852 uint8_t dim_type)
12853 {
12854 int may_throw = 0;
12855 ir_ref end_inputs = IR_UNUSED;
12856 ir_ref ref, if_type = IR_UNUSED, ht_ref;
12857
12858 if (opline->opcode == ZEND_FETCH_DIM_RW) {
12859 jit_SET_EX_OPLINE(jit, opline);
12860 }
12861
12862 op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
12863
12864 if (op1_info & MAY_BE_ARRAY) {
12865 ir_refs *found_inputs, *found_vals;
12866
12867 ir_refs_init(found_inputs, 8);
12868 ir_refs_init(found_vals, 8);
12869
12870 if (opline->op2_type == IS_UNUSED) {
12871 ir_ref if_ok;
12872
12873 may_throw = 1;
12874 // JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
12875 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
12876 ht_ref, jit_EG(uninitialized_zval));
12877
12878 // JIT: if (UNEXPECTED(!var_ptr)) {
12879 if_ok = ir_IF(ref);
12880 ir_IF_FALSE_cold(if_ok);
12881 if (opline->opcode != ZEND_FETCH_DIM_RW) {
12882 jit_SET_EX_OPLINE(jit, opline);
12883 }
12884 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
12885 ir_END_list(end_inputs);
12886
12887 ir_IF_TRUE(if_ok);
12888 jit_set_Z_PTR(jit, res_addr, ref);
12889 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12890
12891 ir_END_list(end_inputs);
12892 } else {
12893 uint32_t type;
12894
12895 switch (opline->opcode) {
12896 case ZEND_FETCH_DIM_W:
12897 case ZEND_FETCH_LIST_W:
12898 type = BP_VAR_W;
12899 break;
12900 case ZEND_FETCH_DIM_RW:
12901 may_throw = 1;
12902 type = BP_VAR_RW;
12903 break;
12904 case ZEND_FETCH_DIM_UNSET:
12905 type = BP_VAR_UNSET;
12906 break;
12907 default:
12908 ZEND_UNREACHABLE();
12909 }
12910
12911 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12912 may_throw = 1;
12913 }
12914 if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
12915 op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
12916 0, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
12917 return 0;
12918 }
12919
12920 if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
12921 if (end_inputs) {
12922 ir_MERGE_list(end_inputs);
12923 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12924 end_inputs = ir_END();
12925 }
12926 } else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12927 /* impossible dead path */
12928 end_inputs = ir_END();
12929 } else {
12930 ZEND_ASSERT(end_inputs == IR_UNUSED);
12931 }
12932
12933 if (found_inputs->count) {
12934 ir_MERGE_N(found_inputs->count, found_inputs->refs);
12935 ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12936 jit_set_Z_PTR(jit, res_addr, ref);
12937 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12938 ir_END_list(end_inputs);
12939 }
12940
12941 }
12942 }
12943
12944 if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
12945 ir_ref arg2;
12946
12947 may_throw = 1;
12948
12949 if (if_type) {
12950 ir_IF_FALSE(if_type);
12951 if_type = IR_UNUSED;
12952 }
12953
12954 if (opline->opcode != ZEND_FETCH_DIM_RW) {
12955 jit_SET_EX_OPLINE(jit, opline);
12956 }
12957
12958 if (opline->op2_type == IS_UNUSED) {
12959 arg2 = IR_NULL;
12960 } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12961 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12962 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
12963 } else {
12964 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12965 }
12966
12967 switch (opline->opcode) {
12968 case ZEND_FETCH_DIM_W:
12969 case ZEND_FETCH_LIST_W:
12970 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
12971 jit_ZVAL_ADDR(jit, op1_addr),
12972 arg2,
12973 jit_ZVAL_ADDR(jit, res_addr));
12974 break;
12975 case ZEND_FETCH_DIM_RW:
12976 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
12977 jit_ZVAL_ADDR(jit, op1_addr),
12978 arg2,
12979 jit_ZVAL_ADDR(jit, res_addr));
12980 break;
12981 // case ZEND_FETCH_DIM_UNSET:
12982 // | EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
12983 // break;
12984 default:
12985 ZEND_UNREACHABLE();
12986 }
12987
12988 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12989 ir_END_list(end_inputs);
12990 }
12991 }
12992
12993 #ifdef ZEND_JIT_USE_RC_INFERENCE
12994 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
12995 /* ASSIGN_DIM may increase refcount of the key */
12996 op2_info |= MAY_BE_RCN;
12997 }
12998 #endif
12999
13000 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
13001 && (op2_info & MAY_HAVE_DTOR)
13002 && (op2_info & MAY_BE_RC1)) {
13003 may_throw = 1;
13004 }
13005
13006 if (end_inputs) {
13007 ir_MERGE_list(end_inputs);
13008 }
13009
13010 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13011
13012 if (may_throw) {
13013 zend_jit_check_exception(jit);
13014 }
13015
13016 return 1;
13017 }
13018
13019 static int zend_jit_isset_isempty_dim(zend_jit_ctx *jit,
13020 const zend_op *opline,
13021 uint32_t op1_info,
13022 zend_jit_addr op1_addr,
13023 bool op1_avoid_refcounting,
13024 uint32_t op2_info,
13025 zend_jit_addr op2_addr,
13026 zend_ssa_range *op2_range,
13027 uint8_t dim_type,
13028 int may_throw,
13029 uint8_t smart_branch_opcode,
13030 uint32_t target_label,
13031 uint32_t target_label2,
13032 const void *exit_addr)
13033 {
13034 zend_jit_addr res_addr;
13035 ir_ref if_type = IR_UNUSED;
13036 ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
13037 ir_refs *true_inputs;
13038
13039 ir_refs_init(true_inputs, 8);
13040
13041 // TODO: support for empty() ???
13042 ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
13043
13044 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13045
13046 if (op1_info & MAY_BE_REF) {
13047 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
13048 ref = jit_ZVAL_DEREF_ref(jit, ref);
13049 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
13050 }
13051
13052 if (op1_info & MAY_BE_ARRAY) {
13053 const void *found_exit_addr = NULL;
13054 const void *not_found_exit_addr = NULL;
13055 ir_ref ht_ref;
13056
13057 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
13058 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
13059 ir_IF_TRUE(if_type);
13060 }
13061
13062 ht_ref = jit_Z_PTR(jit, op1_addr);
13063
13064 if (exit_addr
13065 && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
13066 && !may_throw
13067 && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
13068 && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
13069 if (smart_branch_opcode == ZEND_JMPNZ) {
13070 found_exit_addr = exit_addr;
13071 } else {
13072 not_found_exit_addr = exit_addr;
13073 }
13074 }
13075 if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
13076 op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
13077 0, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
13078 return 0;
13079 }
13080
13081 if (found_exit_addr) {
13082 ir_MERGE_list(false_inputs);
13083 return 1;
13084 } else if (not_found_exit_addr) {
13085 ir_MERGE_N(true_inputs->count, true_inputs->refs);
13086 return 1;
13087 }
13088 }
13089
13090 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
13091 if (if_type) {
13092 ir_IF_FALSE(if_type);
13093 if_type = IR_UNUSED;
13094 }
13095
13096 if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
13097 ir_ref ref, arg1, arg2, if_true;
13098
13099 jit_SET_EX_OPLINE(jit, opline);
13100 arg1 = jit_ZVAL_ADDR(jit, op1_addr);
13101 if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13102 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13103 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
13104 } else {
13105 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13106 }
13107 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
13108 if_true = ir_IF(ref);
13109 ir_IF_TRUE(if_true);
13110 ir_refs_add(true_inputs, ir_END());
13111 ir_IF_FALSE(if_true);
13112 ir_END_list(false_inputs);
13113 } else {
13114 if (op2_info & MAY_BE_UNDEF) {
13115 ir_ref end1 = IR_UNUSED;
13116
13117 if (op2_info & MAY_BE_ANY) {
13118 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
13119 ir_IF_TRUE(if_def);
13120 end1 = ir_END();
13121 ir_IF_FALSE(if_def);
13122 }
13123 jit_SET_EX_OPLINE(jit, opline);
13124 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
13125 if (end1) {
13126 ir_MERGE_WITH(end1);
13127 }
13128 }
13129 ir_END_list(false_inputs);
13130 }
13131 }
13132
13133 #ifdef ZEND_JIT_USE_RC_INFERENCE
13134 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
13135 /* Magic offsetExists() may increase refcount of the key */
13136 op2_info |= MAY_BE_RCN;
13137 }
13138 #endif
13139
13140 if (true_inputs->count) {
13141 ir_MERGE_N(true_inputs->count, true_inputs->refs);
13142
13143 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13144 if (!op1_avoid_refcounting) {
13145 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13146 }
13147 if (may_throw) {
13148 zend_jit_check_exception_undef_result(jit, opline);
13149 }
13150 if (!(opline->extended_value & ZEND_ISEMPTY)) {
13151 if (exit_addr) {
13152 if (smart_branch_opcode == ZEND_JMPNZ) {
13153 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13154 } else {
13155 ir_END_list(end_inputs);
13156 }
13157 } else if (smart_branch_opcode) {
13158 if (smart_branch_opcode == ZEND_JMPZ) {
13159 _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13160 } else if (smart_branch_opcode == ZEND_JMPNZ) {
13161 _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13162 } else {
13163 ZEND_UNREACHABLE();
13164 }
13165 } else {
13166 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
13167 ir_END_list(end_inputs);
13168 }
13169 } else {
13170 ZEND_UNREACHABLE(); // TODO: support for empty()
13171 }
13172 }
13173
13174 ir_MERGE_list(false_inputs);
13175 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13176 if (!op1_avoid_refcounting) {
13177 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13178 }
13179 if (may_throw) {
13180 zend_jit_check_exception_undef_result(jit, opline);
13181 }
13182 if (!(opline->extended_value & ZEND_ISEMPTY)) {
13183 if (exit_addr) {
13184 if (smart_branch_opcode == ZEND_JMPZ) {
13185 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13186 } else {
13187 ir_END_list(end_inputs);
13188 }
13189 } else if (smart_branch_opcode) {
13190 if (smart_branch_opcode == ZEND_JMPZ) {
13191 _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13192 } else if (smart_branch_opcode == ZEND_JMPNZ) {
13193 _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13194 } else {
13195 ZEND_UNREACHABLE();
13196 }
13197 } else {
13198 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
13199 ir_END_list(end_inputs);
13200 }
13201 } else {
13202 ZEND_UNREACHABLE(); // TODO: support for empty()
13203 }
13204
13205 if (!exit_addr && smart_branch_opcode) {
13206 jit->b = -1;
13207 } else {
13208 ir_MERGE_list(end_inputs);
13209 }
13210
13211 return 1;
13212 }
13213
13214 static int zend_jit_assign_dim(zend_jit_ctx *jit,
13215 const zend_op *opline,
13216 uint32_t op1_info,
13217 zend_jit_addr op1_addr,
13218 bool op1_indirect,
13219 uint32_t op2_info,
13220 zend_jit_addr op2_addr,
13221 zend_ssa_range *op2_range,
13222 uint32_t val_info,
13223 zend_jit_addr op3_addr,
13224 zend_jit_addr op3_def_addr,
13225 zend_jit_addr res_addr,
13226 uint8_t dim_type,
13227 int may_throw)
13228 {
13229 ir_ref if_type = IR_UNUSED;
13230 ir_ref end_inputs = IR_UNUSED, ht_ref;
13231
13232 if (op3_addr != op3_def_addr && op3_def_addr) {
13233 if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
13234 return 0;
13235 }
13236 if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
13237 op3_addr = op3_def_addr;
13238 }
13239 }
13240
13241 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
13242 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13243 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13244
13245 if (!exit_addr) {
13246 return 0;
13247 }
13248
13249 jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
13250
13251 val_info &= ~MAY_BE_UNDEF;
13252 }
13253
13254 op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13255
13256 if (op1_info & MAY_BE_ARRAY) {
13257 if (opline->op2_type == IS_UNUSED) {
13258 uint32_t var_info = MAY_BE_NULL;
13259 ir_ref if_ok, ref;
13260 zend_jit_addr var_addr;
13261
13262 // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13263 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13264 ht_ref, jit_EG(uninitialized_zval));
13265
13266 // JIT: if (UNEXPECTED(!var_ptr)) {
13267 if_ok = ir_IF(ref);
13268 ir_IF_FALSE_cold(if_ok);
13269
13270 // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13271 jit_SET_EX_OPLINE(jit, opline);
13272 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13273
13274 ir_END_list(end_inputs);
13275
13276 ir_IF_TRUE(if_ok);
13277 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13278 if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13279 return 0;
13280 }
13281 } else {
13282 uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13283 zend_jit_addr var_addr;
13284 ir_ref ref;
13285 ir_refs *found_inputs, *found_values;
13286
13287 ir_refs_init(found_inputs, 8);
13288 ir_refs_init(found_values, 8);
13289
13290 if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13291 op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13292 0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13293 return 0;
13294 }
13295
13296 if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13297 var_info |= MAY_BE_REF;
13298 }
13299 if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13300 var_info |= MAY_BE_RC1;
13301 }
13302
13303 if (found_inputs->count) {
13304 ir_MERGE_N(found_inputs->count, found_inputs->refs);
13305 ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13306 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13307
13308 // JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13309 if (opline->op1_type == IS_VAR
13310 && Z_MODE(op3_addr) != IS_REG
13311 && opline->result_type == IS_UNUSED
13312 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13313 if (!zend_jit_assign_to_variable_call(jit, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13314 return 0;
13315 }
13316 } else {
13317 if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0, 0)) {
13318 return 0;
13319 }
13320 }
13321 }
13322 }
13323
13324 ir_END_list(end_inputs);
13325 }
13326
13327 if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13328 ir_ref arg2, arg4;
13329
13330 if (if_type) {
13331 ir_IF_FALSE_cold(if_type);
13332 if_type = IR_UNUSED;
13333 }
13334
13335 jit_SET_EX_OPLINE(jit, opline);
13336
13337 if (opline->op2_type == IS_UNUSED) {
13338 arg2 = IR_NULL;
13339 } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13340 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13341 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13342 } else {
13343 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13344 }
13345
13346 if (opline->result_type == IS_UNUSED) {
13347 arg4 = IR_NULL;
13348 } else {
13349 arg4 = jit_ZVAL_ADDR(jit, res_addr);
13350 }
13351 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13352 jit_ZVAL_ADDR(jit, op1_addr),
13353 arg2,
13354 jit_ZVAL_ADDR(jit, op3_addr),
13355 arg4);
13356
13357 #ifdef ZEND_JIT_USE_RC_INFERENCE
13358 if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13359 /* ASSIGN_DIM may increase refcount of the value */
13360 val_info |= MAY_BE_RCN;
13361 }
13362 #endif
13363
13364 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13365
13366 ir_END_list(end_inputs);
13367 }
13368
13369 #ifdef ZEND_JIT_USE_RC_INFERENCE
13370 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
13371 /* ASSIGN_DIM may increase refcount of the key */
13372 op2_info |= MAY_BE_RCN;
13373 }
13374 #endif
13375
13376 ir_MERGE_list(end_inputs);
13377 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13378
13379 if (!op1_indirect) {
13380 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13381 }
13382
13383 if (may_throw) {
13384 zend_jit_check_exception(jit);
13385 }
13386
13387 return 1;
13388 }
13389
13390 static int zend_jit_assign_dim_op(zend_jit_ctx *jit,
13391 const zend_op *opline,
13392 uint32_t op1_info,
13393 uint32_t op1_def_info,
13394 zend_jit_addr op1_addr,
13395 bool op1_indirect,
13396 uint32_t op2_info,
13397 zend_jit_addr op2_addr,
13398 zend_ssa_range *op2_range,
13399 uint32_t op1_data_info,
13400 zend_jit_addr op3_addr,
13401 zend_ssa_range *op1_data_range,
13402 uint8_t dim_type,
13403 int may_throw)
13404 {
13405 zend_jit_addr var_addr = IS_UNUSED;
13406 const void *not_found_exit_addr = NULL;
13407 uint32_t var_info = MAY_BE_NULL;
13408 ir_ref if_type = IS_UNUSED;
13409 ir_ref end_inputs = IR_UNUSED, ht_ref;
13410 bool emit_fast_path = 1;
13411
13412 ZEND_ASSERT(opline->result_type == IS_UNUSED);
13413
13414 if (may_throw) {
13415 jit_SET_EX_OPLINE(jit, opline);
13416 }
13417
13418 op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13419
13420 if (op1_info & MAY_BE_ARRAY) {
13421 uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13422
13423 if (opline->op2_type == IS_UNUSED) {
13424 var_info = MAY_BE_NULL;
13425 ir_ref if_ok, ref;
13426
13427 // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13428 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13429 ht_ref, jit_EG(uninitialized_zval));
13430
13431 // JIT: if (UNEXPECTED(!var_ptr)) {
13432 if_ok = ir_IF(ref);
13433 ir_IF_FALSE_cold(if_ok);
13434
13435 // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13436 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13437
13438 ir_END_list(end_inputs);
13439
13440 ir_IF_TRUE(if_ok);
13441 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13442 } else {
13443 ir_ref ref;
13444 ir_refs *found_inputs, *found_values;
13445
13446 ir_refs_init(found_inputs, 8);
13447 ir_refs_init(found_values, 8);
13448
13449 var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13450 if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13451 var_info |= MAY_BE_REF;
13452 }
13453 if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13454 var_info |= MAY_BE_RC1;
13455 }
13456
13457 if (dim_type != IS_UNKNOWN
13458 && dim_type != IS_UNDEF
13459 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13460 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13461 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13462 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13463 not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13464 if (!not_found_exit_addr) {
13465 return 0;
13466 }
13467 }
13468
13469 if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13470 op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13471 0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13472 return 0;
13473 }
13474
13475 if (found_inputs->count) {
13476 ir_MERGE_N(found_inputs->count, found_inputs->refs);
13477 ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13478 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13479
13480 if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13481 jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13482 var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13483 }
13484 if (var_info & MAY_BE_REF) {
13485 binary_op_type binary_op = get_binary_op(opline->extended_value);
13486 ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13487
13488 ref = jit_ZVAL_ADDR(jit, var_addr);
13489 if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13490 ir_IF_FALSE(if_ref);
13491 noref_path = ir_END();
13492 ir_IF_TRUE(if_ref);
13493
13494 reference = jit_Z_PTR_ref(jit, ref);
13495 ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13496 if_typed = jit_if_TYPED_REF(jit, reference);
13497 ir_IF_FALSE(if_typed);
13498 ref_path = ir_END();
13499 ir_IF_TRUE_cold(if_typed);
13500
13501 arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13502 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13503 reference, arg2, ir_CONST_FC_FUNC(binary_op));
13504
13505 ir_END_list(end_inputs);
13506
13507 ir_MERGE_2(noref_path, ref_path);
13508 ref = ir_PHI_2(IR_ADDR, ref, ref2);
13509 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13510 }
13511 } else {
13512 emit_fast_path = 0;
13513 }
13514 }
13515
13516 if (emit_fast_path) {
13517 uint8_t val_op_type = (opline+1)->op1_type;
13518
13519 if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13520 /* prevent FREE_OP in the helpers */
13521 val_op_type = IS_CV;
13522 }
13523
13524 switch (opline->extended_value) {
13525 case ZEND_ADD:
13526 case ZEND_SUB:
13527 case ZEND_MUL:
13528 case ZEND_DIV:
13529 if (!zend_jit_math_helper(jit, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, op3_addr, op1_data_info, 0, var_addr, var_def_info, var_info,
13530 1 /* may overflow */, may_throw)) {
13531 return 0;
13532 }
13533 break;
13534 case ZEND_BW_OR:
13535 case ZEND_BW_AND:
13536 case ZEND_BW_XOR:
13537 case ZEND_SL:
13538 case ZEND_SR:
13539 case ZEND_MOD:
13540 if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13541 IS_CV, opline->op1, var_addr, var_info, NULL,
13542 val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13543 op1_data_range,
13544 0, var_addr, var_def_info, var_info, may_throw)) {
13545 return 0;
13546 }
13547 break;
13548 case ZEND_CONCAT:
13549 if (!zend_jit_concat_helper(jit, opline, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, op3_addr, op1_data_info, var_addr,
13550 may_throw)) {
13551 return 0;
13552 }
13553 break;
13554 default:
13555 ZEND_UNREACHABLE();
13556 }
13557
13558 ir_END_list(end_inputs);
13559 }
13560 }
13561
13562 if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13563 binary_op_type binary_op;
13564 ir_ref arg2;
13565
13566 if (if_type) {
13567 ir_IF_FALSE_cold(if_type);
13568 if_type = IS_UNUSED;
13569 }
13570
13571 if (opline->op2_type == IS_UNUSED) {
13572 arg2 = IR_NULL;
13573 } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13574 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13575 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13576 } else {
13577 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13578 }
13579 binary_op = get_binary_op(opline->extended_value);
13580 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13581 jit_ZVAL_ADDR(jit, op1_addr),
13582 arg2,
13583 jit_ZVAL_ADDR(jit, op3_addr),
13584 ir_CONST_FC_FUNC(binary_op));
13585 ir_END_list(end_inputs);
13586 }
13587
13588 if (end_inputs) {
13589 ir_MERGE_list(end_inputs);
13590 }
13591
13592 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13593 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13594 if (!op1_indirect) {
13595 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
13596 }
13597 if (may_throw) {
13598 zend_jit_check_exception(jit);
13599 }
13600
13601 return 1;
13602 }
13603
13604 static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13605 {
13606 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13607
13608 // JIT: ZVAL_COPY(res, value);
13609 if (opline->op1_type == IS_CONST) {
13610 zval *zv = RT_CONSTANT(opline, opline->op1);
13611
13612 jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
13613 } else {
13614 zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13615
13616 jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13617 }
13618
13619 // JIT: Z_FE_POS_P(res) = 0;
13620 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13621
13622 return 1;
13623 }
13624
13625 static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13626 {
13627 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13628 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13629 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13630 ir_ref ref;
13631
13632 if (!exit_addr) {
13633 return 0;
13634 }
13635
13636 ref = ir_AND_U32(
13637 ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
13638 ir_CONST_U32(HASH_FLAG_PACKED));
13639 if (op_info & MAY_BE_ARRAY_PACKED) {
13640 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13641 } else {
13642 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
13643 }
13644
13645 return 1;
13646 }
13647
13648 static int zend_jit_fe_fetch(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, uint8_t exit_opcode, const void *exit_addr)
13649 {
13650 zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13651 ir_ref ref, ht_ref, hash_pos_ref, packed_pos_ref, hash_p_ref = IR_UNUSED, packed_p_ref = IR_UNUSED, if_packed = IR_UNUSED;
13652 ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
13653 ir_ref exit_inputs = IR_UNUSED;
13654
13655 if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
13656 /* empty array */
13657 if (exit_addr) {
13658 if (exit_opcode == ZEND_JMP) {
13659 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13660 }
13661 } else {
13662 zend_basic_block *bb;
13663
13664 ZEND_ASSERT(jit->b >= 0);
13665 bb = &jit->ssa->cfg.blocks[jit->b];
13666 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
13667 jit->b = -1;
13668 }
13669 return 1;
13670 }
13671
13672 // JIT: array = EX_VAR(opline->op1.var);
13673 // JIT: fe_ht = Z_ARRVAL_P(array);
13674 ht_ref = jit_Z_PTR(jit, op1_addr);
13675
13676 if (op1_info & MAY_BE_PACKED_GUARD) {
13677 if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
13678 return 0;
13679 }
13680 }
13681
13682 // JIT: pos = Z_FE_POS_P(array);
13683 hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
13684
13685 if (MAY_BE_HASH(op1_info)) {
13686 ir_ref loop_ref, pos2_ref, p2_ref;
13687
13688 if (MAY_BE_PACKED(op1_info)) {
13689 ref = ir_AND_U32(
13690 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
13691 ir_CONST_U32(HASH_FLAG_PACKED));
13692 if_packed = ir_IF(ref);
13693 ir_IF_FALSE(if_packed);
13694 }
13695
13696 // JIT: p = fe_ht->arData + pos;
13697 if (sizeof(void*) == 8) {
13698 ref = ir_ZEXT_A(hash_pos_ref);
13699 } else {
13700 ref = ir_BITCAST_A(hash_pos_ref);
13701 }
13702 hash_p_ref = ir_ADD_A(
13703 ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
13704 ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
13705
13706 loop_ref = ir_LOOP_BEGIN(ir_END());
13707 hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
13708 hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
13709
13710 // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13711 ref = ir_ULT(hash_pos_ref,
13712 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13713
13714 // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13715 // JIT: ZEND_VM_CONTINUE();
13716
13717 if (exit_addr) {
13718 if (exit_opcode == ZEND_JMP) {
13719 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13720 } else {
13721 ir_ref if_fit = ir_IF(ref);
13722 ir_IF_FALSE(if_fit);
13723 ir_END_list(exit_inputs);
13724 ir_IF_TRUE(if_fit);
13725 }
13726 } else {
13727 ir_ref if_fit = ir_IF(ref);
13728 ir_IF_FALSE(if_fit);
13729 ir_END_list(exit_inputs);
13730 ir_IF_TRUE(if_fit);
13731 }
13732
13733 // JIT: pos++;
13734 pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
13735
13736 // JIT: value_type = Z_TYPE_INFO_P(value);
13737 // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13738 if (!exit_addr || exit_opcode == ZEND_JMP) {
13739 if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
13740 ir_IF_FALSE(if_def_hash);
13741 } else {
13742 ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
13743 }
13744
13745 // JIT: p++;
13746 p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
13747
13748 ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13749 ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
13750 ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
13751
13752 if (MAY_BE_PACKED(op1_info)) {
13753 ir_IF_TRUE(if_packed);
13754 }
13755 }
13756 if (MAY_BE_PACKED(op1_info)) {
13757 ir_ref loop_ref, pos2_ref, p2_ref;
13758
13759 // JIT: p = fe_ht->arPacked + pos;
13760 if (sizeof(void*) == 8) {
13761 ref = ir_ZEXT_A(packed_pos_ref);
13762 } else {
13763 ref = ir_BITCAST_A(packed_pos_ref);
13764 }
13765 packed_p_ref = ir_ADD_A(
13766 ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
13767 ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
13768
13769 loop_ref = ir_LOOP_BEGIN(ir_END());
13770 packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
13771 packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
13772
13773 // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13774 ref = ir_ULT(packed_pos_ref,
13775 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13776
13777 // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13778 // JIT: ZEND_VM_CONTINUE();
13779 if (exit_addr) {
13780 if (exit_opcode == ZEND_JMP) {
13781 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13782 } else {
13783 ir_ref if_fit = ir_IF(ref);
13784 ir_IF_FALSE(if_fit);
13785 ir_END_list(exit_inputs);
13786 ir_IF_TRUE(if_fit);
13787 }
13788 } else {
13789 ir_ref if_fit = ir_IF(ref);
13790 ir_IF_FALSE(if_fit);
13791 ir_END_list(exit_inputs);
13792 ir_IF_TRUE(if_fit);
13793 }
13794
13795 // JIT: pos++;
13796 pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
13797
13798 // JIT: value_type = Z_TYPE_INFO_P(value);
13799 // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13800 if (!exit_addr || exit_opcode == ZEND_JMP) {
13801 if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
13802 ir_IF_FALSE(if_def_packed);
13803 } else {
13804 ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
13805 }
13806
13807 // JIT: p++;
13808 p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
13809
13810 ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13811 ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
13812 ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
13813 }
13814
13815 if (!exit_addr || exit_opcode == ZEND_JMP) {
13816 zend_jit_addr val_addr;
13817 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
13818 uint32_t val_info;
13819 ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
13820
13821 if (RETURN_VALUE_USED(opline)) {
13822 zend_jit_addr res_addr = RES_ADDR();
13823
13824 if (MAY_BE_HASH(op1_info)) {
13825 ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
13826
13827 ZEND_ASSERT(if_def_hash);
13828 ir_IF_TRUE(if_def_hash);
13829
13830 // JIT: Z_FE_POS_P(array) = pos + 1;
13831 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13832 ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
13833
13834 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13835 key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
13836 }
13837 if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
13838 && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
13839 // JIT: if (!p->key) {
13840 if_key = ir_IF(key_ref);
13841 ir_IF_TRUE(if_key);
13842 }
13843 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13844 ir_ref if_interned, interned_path;
13845
13846 // JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
13847 jit_set_Z_PTR(jit, res_addr, key_ref);
13848 ref = ir_AND_U32(
13849 ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
13850 ir_CONST_U32(IS_STR_INTERNED));
13851 if_interned = ir_IF(ref);
13852 ir_IF_TRUE(if_interned);
13853
13854 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
13855
13856 interned_path = ir_END();
13857 ir_IF_FALSE(if_interned);
13858
13859 jit_GC_ADDREF(jit, key_ref);
13860 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
13861
13862 ir_MERGE_WITH(interned_path);
13863
13864 if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13865 key_path = ir_END();
13866 }
13867 }
13868 if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13869 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13870 ir_IF_FALSE(if_key);
13871 }
13872 // JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
13873 ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
13874 jit_set_Z_LVAL(jit, res_addr, ref);
13875 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13876
13877 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13878 ir_MERGE_WITH(key_path);
13879 }
13880 }
13881 if (MAY_BE_PACKED(op1_info)) {
13882 hash_path = ir_END();
13883 } else {
13884 p_ref = hash_p_ref;
13885 }
13886 }
13887 if (MAY_BE_PACKED(op1_info)) {
13888 ZEND_ASSERT(if_def_packed);
13889 ir_IF_TRUE(if_def_packed);
13890
13891 // JIT: Z_FE_POS_P(array) = pos + 1;
13892 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13893 ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
13894
13895 // JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
13896 if (sizeof(zend_long) == 8) {
13897 packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
13898 } else {
13899 packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
13900 }
13901 jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
13902 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13903
13904 if (MAY_BE_HASH(op1_info)) {
13905 ir_MERGE_WITH(hash_path);
13906 p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
13907 } else {
13908 p_ref = packed_p_ref;
13909 }
13910 }
13911 } else {
13912 ir_ref pos_ref = IR_UNUSED;
13913
13914 if (if_def_hash && if_def_packed) {
13915 ir_IF_TRUE(if_def_hash);
13916 ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
13917 pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
13918 p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
13919 } else if (if_def_hash) {
13920 ir_IF_TRUE(if_def_hash);
13921 pos_ref = hash_pos_ref;
13922 p_ref = hash_p_ref;
13923 } else if (if_def_packed) {
13924 ir_IF_TRUE(if_def_packed);
13925 pos_ref = packed_pos_ref;
13926 p_ref = packed_p_ref;
13927 } else {
13928 ZEND_UNREACHABLE();
13929 }
13930
13931 // JIT: Z_FE_POS_P(array) = pos + 1;
13932 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13933 ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
13934 }
13935
13936 val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
13937 if (val_info & MAY_BE_ARRAY) {
13938 val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13939 }
13940 if (op1_info & MAY_BE_ARRAY_OF_REF) {
13941 val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
13942 MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
13943 } else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13944 val_info |= MAY_BE_RC1 | MAY_BE_RCN;
13945 }
13946
13947 val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
13948 if (opline->op2_type == IS_CV) {
13949 // JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
13950 if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, 1)) {
13951 return 0;
13952 }
13953 } else {
13954 // JIT: ZVAL_COPY(res, value);
13955 jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, 1);
13956 }
13957
13958 if (!exit_addr) {
13959 zend_basic_block *bb;
13960
13961 ZEND_ASSERT(jit->b >= 0);
13962 bb = &jit->ssa->cfg.blocks[jit->b];
13963 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
13964 ZEND_ASSERT(exit_inputs);
13965 if (!jit->ctx.ir_base[exit_inputs].op2) {
13966 ref = exit_inputs;
13967 } else {
13968 ir_MERGE_list(exit_inputs);
13969 ref = ir_END();
13970 }
13971 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
13972 jit->b = -1;
13973 }
13974 } else {
13975 ZEND_ASSERT(exit_inputs);
13976 ir_MERGE_list(exit_inputs);
13977 }
13978
13979 return 1;
13980 }
13981
13982 static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
13983 {
13984 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13985 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13986 ir_ref ref = jit_Z_PTR(jit, this_addr);
13987
13988 jit_set_Z_PTR(jit, var_addr, ref);
13989 jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
13990 jit_GC_ADDREF(jit, ref);
13991
13992 return 1;
13993 }
13994
13995 static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
13996 {
13997 if (!op_array->scope ||
13998 (op_array->fn_flags & ZEND_ACC_STATIC) ||
13999 ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) {
14000 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14001 if (!JIT_G(current_frame) ||
14002 !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
14003
14004 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14005 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14006 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14007
14008 if (!exit_addr) {
14009 return 0;
14010 }
14011
14012 jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
14013
14014 if (JIT_G(current_frame)) {
14015 TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
14016 }
14017 }
14018 } else {
14019 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14020 ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
14021
14022 ir_IF_FALSE_cold(if_object);
14023 jit_SET_EX_OPLINE(jit, opline);
14024 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
14025
14026 ir_IF_TRUE(if_object);
14027 }
14028 }
14029
14030 if (!check_only) {
14031 if (!zend_jit_load_this(jit, opline->result.var)) {
14032 return 0;
14033 }
14034 }
14035
14036 return 1;
14037 }
14038
14039 static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
14040 {
14041 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14042 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14043
14044 if (!exit_addr) {
14045 return 0;
14046 }
14047
14048 ir_GUARD(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce))), ir_CONST_ADDR(ce)),
14049 ir_CONST_ADDR(exit_addr));
14050
14051 return 1;
14052 }
14053
14054 static int zend_jit_fetch_obj(zend_jit_ctx *jit,
14055 const zend_op *opline,
14056 const zend_op_array *op_array,
14057 zend_ssa *ssa,
14058 const zend_ssa_op *ssa_op,
14059 uint32_t op1_info,
14060 zend_jit_addr op1_addr,
14061 bool op1_indirect,
14062 zend_class_entry *ce,
14063 bool ce_is_instanceof,
14064 bool on_this,
14065 bool delayed_fetch_this,
14066 bool op1_avoid_refcounting,
14067 zend_class_entry *trace_ce,
14068 zend_jit_addr res_addr,
14069 uint8_t prop_type,
14070 int may_throw)
14071 {
14072 zval *member;
14073 zend_property_info *prop_info;
14074 bool may_be_dynamic = 1;
14075 zend_jit_addr prop_addr;
14076 uint32_t res_info = RES_INFO();
14077 ir_ref prop_type_ref = IR_UNUSED;
14078 ir_ref obj_ref = IR_UNUSED;
14079 ir_ref prop_ref = IR_UNUSED;
14080 ir_ref end_inputs = IR_UNUSED;
14081 ir_ref slow_inputs = IR_UNUSED;
14082 ir_ref end_values = IR_UNUSED;
14083
14084 ZEND_ASSERT(opline->op2_type == IS_CONST);
14085 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14086
14087 member = RT_CONSTANT(opline, opline->op2);
14088 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14089 prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
14090
14091 if (on_this) {
14092 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14093 obj_ref = jit_Z_PTR(jit, this_addr);
14094 } else {
14095 if (opline->op1_type == IS_VAR
14096 && opline->opcode == ZEND_FETCH_OBJ_W
14097 && (op1_info & MAY_BE_INDIRECT)
14098 && Z_REG(op1_addr) == ZREG_FP) {
14099 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14100 }
14101 if (op1_info & MAY_BE_REF) {
14102 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14103 }
14104 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14105 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14106 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14107 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14108
14109 if (!exit_addr) {
14110 return 0;
14111 }
14112 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14113 } else {
14114 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14115
14116 ir_IF_FALSE_cold(if_obj);
14117 if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14118 ir_ref op1_ref = IR_UNUSED;
14119
14120 jit_SET_EX_OPLINE(jit, opline);
14121 if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
14122 zend_jit_addr orig_op1_addr = OP1_ADDR();
14123 ir_ref fast_path = IR_UNUSED;
14124
14125 if (op1_info & MAY_BE_ANY) {
14126 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
14127 ir_IF_TRUE(if_def);
14128 fast_path = ir_END();
14129 ir_IF_FALSE_cold(if_def);
14130 }
14131 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
14132 ir_CONST_U32(opline->op1.var));
14133 if (fast_path) {
14134 ir_MERGE_WITH(fast_path);
14135 }
14136 op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
14137 } else {
14138 op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
14139 }
14140 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14141 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
14142 op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14143 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14144 } else {
14145 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
14146 op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14147 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14148 }
14149 } else {
14150 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14151 }
14152 ir_END_list(end_inputs);
14153
14154 ir_IF_TRUE(if_obj);
14155 }
14156 }
14157 obj_ref = jit_Z_PTR(jit, op1_addr);
14158 }
14159
14160 ZEND_ASSERT(obj_ref);
14161 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14162 prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
14163 if (prop_info) {
14164 ce = trace_ce;
14165 ce_is_instanceof = 0;
14166 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14167 if (on_this && JIT_G(current_frame)
14168 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14169 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14170 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14171 if (on_this && JIT_G(current_frame)) {
14172 JIT_G(current_frame)->ce = ce;
14173 TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14174 }
14175 } else {
14176 return 0;
14177 }
14178 if (ssa->var_info && ssa_op->op1_use >= 0) {
14179 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14180 ssa->var_info[ssa_op->op1_use].ce = ce;
14181 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14182 }
14183 }
14184 }
14185 }
14186
14187 if (!prop_info) {
14188 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14189 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14190 ir_ref if_same = ir_IF(ir_EQ(ref,
14191 ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14192
14193 ir_IF_FALSE_cold(if_same);
14194 ir_END_list(slow_inputs);
14195
14196 ir_IF_TRUE(if_same);
14197 ir_ref offset_ref = ir_LOAD_A(
14198 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14199
14200 may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array);
14201 if (may_be_dynamic) {
14202 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14203 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14204 ir_IF_TRUE_cold(if_dynamic);
14205 ir_END_list(slow_inputs);
14206 } else {
14207 ir_IF_TRUE_cold(if_dynamic);
14208 jit_SET_EX_OPLINE(jit, opline);
14209
14210 if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14211 if (Z_MODE(res_addr) == IS_REG) {
14212 ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
14213 obj_ref, offset_ref);
14214 ir_END_PHI_list(end_values, val_addr);
14215 } else {
14216 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
14217 obj_ref, offset_ref);
14218 ir_END_list(end_inputs);
14219 }
14220 } else {
14221 if (Z_MODE(res_addr) == IS_REG) {
14222 ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
14223 obj_ref, offset_ref);
14224 ir_END_PHI_list(end_values, val_addr);
14225 } else {
14226 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
14227 obj_ref, offset_ref);
14228 ir_END_list(end_inputs);
14229 }
14230 }
14231 }
14232 ir_IF_FALSE(if_dynamic);
14233 }
14234 prop_ref = ir_ADD_A(obj_ref, offset_ref);
14235 prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
14236 ir_ref if_def = ir_IF(prop_type_ref);
14237 ir_IF_FALSE_cold(if_def);
14238 ir_END_list(slow_inputs);
14239 ir_IF_TRUE(if_def);
14240 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14241 if (opline->opcode == ZEND_FETCH_OBJ_W
14242 && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
14243 uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14244
14245 ir_ref allowed_inputs = IR_UNUSED;
14246 ir_ref forbidden_inputs = IR_UNUSED;
14247
14248 ir_ref prop_info_ref = ir_LOAD_A(
14249 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14250 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14251
14252 ir_IF_TRUE_cold(if_has_prop_info);
14253
14254 ir_ref prop_flags = ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags)));
14255 ir_ref if_readonly_or_avis = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK)));
14256
14257 ir_IF_FALSE(if_readonly_or_avis);
14258 ir_END_list(allowed_inputs);
14259
14260 ir_IF_TRUE_cold(if_readonly_or_avis);
14261
14262 ir_ref if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14263 ir_IF_TRUE(if_readonly);
14264 ir_END_list(forbidden_inputs);
14265
14266 ir_IF_FALSE(if_readonly);
14267 ir_ref has_avis_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), prop_info_ref);
14268 ir_ref if_avis_access = ir_IF(has_avis_access);
14269 ir_IF_TRUE(if_avis_access);
14270 ir_END_list(allowed_inputs);
14271
14272 ir_IF_FALSE(if_avis_access);
14273 ir_END_list(forbidden_inputs);
14274
14275 ir_MERGE_list(forbidden_inputs);
14276
14277 ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14278 ir_IF_TRUE(if_prop_obj);
14279 ref = jit_Z_PTR(jit, prop_addr);
14280 jit_GC_ADDREF(jit, ref);
14281 jit_set_Z_PTR(jit, res_addr, ref);
14282 jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14283 ir_END_list(end_inputs);
14284
14285 ir_IF_FALSE_cold(if_prop_obj);
14286
14287 jit_SET_EX_OPLINE(jit, opline);
14288 if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14289 ir_IF_TRUE(if_readonly);
14290 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), prop_info_ref);
14291 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14292 ir_END_list(end_inputs);
14293
14294 ir_IF_FALSE(if_readonly);
14295 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14296 prop_info_ref, ir_CONST_ADDR("indirectly modify"));
14297 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14298 ir_END_list(end_inputs);
14299
14300 ir_MERGE_list(allowed_inputs);
14301
14302 if (flags == ZEND_FETCH_DIM_WRITE) {
14303 jit_SET_EX_OPLINE(jit, opline);
14304 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14305 prop_ref, prop_info_ref);
14306 ir_END_list(end_inputs);
14307 ir_IF_FALSE(if_has_prop_info);
14308 } else if (flags == ZEND_FETCH_REF) {
14309 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14310 prop_ref,
14311 prop_info_ref,
14312 jit_ZVAL_ADDR(jit, res_addr));
14313 ir_END_list(end_inputs);
14314 ir_IF_FALSE(if_has_prop_info);
14315 } else {
14316 ZEND_ASSERT(flags == 0);
14317 ir_MERGE_WITH_EMPTY_FALSE(if_has_prop_info);
14318 }
14319 }
14320 } else {
14321 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14322 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14323 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14324 if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14325 /* perform IS_UNDEF check only after result type guard (during deoptimization) */
14326 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14327 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14328
14329 if (!exit_addr) {
14330 return 0;
14331 }
14332 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14333 ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14334 }
14335 } else {
14336 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14337 ir_ref if_def = ir_IF(prop_type_ref);
14338 ir_IF_FALSE_cold(if_def);
14339 ir_END_list(slow_inputs);
14340 ir_IF_TRUE(if_def);
14341 }
14342 if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14343 ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14344 ir_IF_TRUE(if_prop_obj);
14345 ir_ref ref = jit_Z_PTR(jit, prop_addr);
14346 jit_GC_ADDREF(jit, ref);
14347 jit_set_Z_PTR(jit, res_addr, ref);
14348 jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14349 ir_END_list(end_inputs);
14350
14351 ir_IF_FALSE_cold(if_prop_obj);
14352 jit_SET_EX_OPLINE(jit, opline);
14353 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), ir_CONST_ADDR(prop_info));
14354 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14355 ir_END_list(end_inputs);
14356
14357 goto result_fetched;
14358 } else if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)) {
14359 /* Readonly properties which are also asymmetric are never mutable indirectly, which is
14360 * handled by the previous branch. */
14361 ir_ref has_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), ir_CONST_ADDR(prop_info));
14362
14363 ir_ref if_access = ir_IF(has_access);
14364 ir_IF_FALSE_cold(if_access);
14365
14366 ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14367 ir_IF_TRUE(if_prop_obj);
14368 ir_ref ref = jit_Z_PTR(jit, prop_addr);
14369 jit_GC_ADDREF(jit, ref);
14370 jit_set_Z_PTR(jit, res_addr, ref);
14371 jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14372 ir_END_list(end_inputs);
14373
14374 ir_IF_FALSE_cold(if_prop_obj);
14375 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14376 ir_CONST_ADDR(prop_info), ir_CONST_ADDR("indirectly modify"));
14377 ir_END_list(end_inputs);
14378
14379 ir_IF_TRUE(if_access);
14380 }
14381
14382 if (opline->opcode == ZEND_FETCH_OBJ_W
14383 && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
14384 && ZEND_TYPE_IS_SET(prop_info->type)) {
14385 uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14386
14387 if (flags == ZEND_FETCH_DIM_WRITE) {
14388 if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14389 if (!prop_type_ref) {
14390 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14391 }
14392 ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14393 ir_IF_TRUE_cold(if_null_or_flase);
14394 jit_SET_EX_OPLINE(jit, opline);
14395 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14396 prop_ref, ir_CONST_ADDR(prop_info));
14397 ir_END_list(end_inputs);
14398 ir_IF_FALSE(if_null_or_flase);
14399 }
14400 } else if (flags == ZEND_FETCH_REF) {
14401 ir_ref ref;
14402
14403 if (!prop_type_ref) {
14404 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14405 }
14406
14407 ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14408 ir_IF_FALSE(if_reference);
14409 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14410 ref = ir_CONST_ADDR(prop_info);
14411 } else {
14412 int prop_info_offset =
14413 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14414
14415 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14416 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14417 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14418 }
14419 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14420 prop_ref,
14421 ref,
14422 jit_ZVAL_ADDR(jit, res_addr));
14423 ir_END_list(end_inputs);
14424 ir_IF_TRUE(if_reference);
14425 } else {
14426 ZEND_UNREACHABLE();
14427 }
14428 }
14429 }
14430
14431 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14432 ZEND_ASSERT(prop_ref);
14433 jit_set_Z_PTR(jit, res_addr, prop_ref);
14434 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14435 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14436 ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14437 }
14438 ir_END_list(end_inputs);
14439 } else {
14440 if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
14441 || Z_MODE(res_addr) == IS_REG) {
14442 ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14443 } else {
14444 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14445
14446 if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14447 return 0;
14448 }
14449 ir_END_list(end_inputs);
14450 }
14451 }
14452
14453 result_fetched:
14454 if (op1_avoid_refcounting) {
14455 SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14456 }
14457
14458 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14459 ir_MERGE_list(slow_inputs);
14460 jit_SET_EX_OPLINE(jit, opline);
14461
14462 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14463 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14464 ir_END_list(end_inputs);
14465 } else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14466 if (Z_MODE(res_addr) == IS_REG) {
14467 ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14468 ir_END_PHI_list(end_values, val_ref);
14469 } else {
14470 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14471 ir_END_list(end_inputs);
14472 }
14473 } else {
14474 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14475 ir_END_list(end_inputs);
14476 }
14477 }
14478
14479 if (end_values) {
14480 ir_ref val_ref = ir_PHI_list(end_values);
14481 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14482 bool result_avoid_refcounting = 0;
14483
14484 ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14485 || opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14486 || opline->opcode == ZEND_FETCH_OBJ_IS);
14487 ZEND_ASSERT(end_inputs == IR_UNUSED);
14488 if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14489 uint8_t type = concrete_type(res_info);
14490 uint32_t flags = 0;
14491
14492 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14493 && !delayed_fetch_this
14494 && !op1_avoid_refcounting) {
14495 flags = ZEND_JIT_EXIT_FREE_OP1;
14496 }
14497
14498 if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14499 && !(flags & ZEND_JIT_EXIT_FREE_OP1)
14500 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
14501 && (ssa_op+1)->op1_use == ssa_op->result_def
14502 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14503 result_avoid_refcounting = 1;
14504 ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14505 }
14506
14507 val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14508 1, flags, op1_avoid_refcounting);
14509 if (!val_addr) {
14510 return 0;
14511 }
14512
14513 res_info &= ~MAY_BE_GUARD;
14514 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14515 }
14516
14517 // ZVAL_COPY
14518 jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14519
14520 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14521 return 0;
14522 }
14523 } else {
14524 ir_MERGE_list(end_inputs);
14525 }
14526
14527 if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14528 if (opline->op1_type == IS_VAR
14529 && opline->opcode == ZEND_FETCH_OBJ_W
14530 && (op1_info & MAY_BE_RC1)) {
14531 zend_jit_addr orig_op1_addr = OP1_ADDR();
14532 ir_ref if_refcounted, ptr, refcount, if_non_zero;
14533 ir_ref merge_inputs = IR_UNUSED;
14534
14535 if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14536 ir_IF_FALSE( if_refcounted);
14537 ir_END_list(merge_inputs);
14538 ir_IF_TRUE( if_refcounted);
14539 ptr = jit_Z_PTR(jit, orig_op1_addr);
14540 refcount = jit_GC_DELREF(jit, ptr);
14541 if_non_zero = ir_IF(refcount);
14542 ir_IF_TRUE( if_non_zero);
14543 ir_END_list(merge_inputs);
14544 ir_IF_FALSE( if_non_zero);
14545 jit_SET_EX_OPLINE(jit, opline);
14546 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14547 ir_END_list(merge_inputs);
14548 ir_MERGE_list(merge_inputs);
14549 } else if (!op1_avoid_refcounting) {
14550 if (on_this) {
14551 op1_info &= ~MAY_BE_RC1;
14552 }
14553 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14554 }
14555 }
14556
14557 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14558 && prop_info
14559 && (opline->opcode != ZEND_FETCH_OBJ_W ||
14560 !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14561 !ZEND_TYPE_IS_SET(prop_info->type))
14562 && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14563 may_throw = 0;
14564 }
14565
14566 if (may_throw) {
14567 zend_jit_check_exception(jit);
14568 }
14569
14570 return 1;
14571 }
14572
14573 static int zend_jit_assign_obj(zend_jit_ctx *jit,
14574 const zend_op *opline,
14575 const zend_op_array *op_array,
14576 zend_ssa *ssa,
14577 const zend_ssa_op *ssa_op,
14578 uint32_t op1_info,
14579 zend_jit_addr op1_addr,
14580 uint32_t val_info,
14581 zend_jit_addr val_addr,
14582 zend_jit_addr val_def_addr,
14583 zend_jit_addr res_addr,
14584 bool op1_indirect,
14585 zend_class_entry *ce,
14586 bool ce_is_instanceof,
14587 bool on_this,
14588 bool delayed_fetch_this,
14589 zend_class_entry *trace_ce,
14590 uint8_t prop_type,
14591 int may_throw)
14592 {
14593 zval *member;
14594 zend_string *name;
14595 zend_property_info *prop_info;
14596 zend_jit_addr prop_addr;
14597 ir_ref obj_ref = IR_UNUSED;
14598 ir_ref prop_ref = IR_UNUSED;
14599 ir_ref delayed_end_input = IR_UNUSED;
14600 ir_ref end_inputs = IR_UNUSED;
14601 ir_ref slow_inputs = IR_UNUSED;
14602 uint32_t res_info = RES_INFO();
14603
14604 if (val_addr != val_def_addr && val_def_addr) {
14605 if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14606 return 0;
14607 }
14608 if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14609 val_addr = val_def_addr;
14610 }
14611 }
14612
14613 ZEND_ASSERT(opline->op2_type == IS_CONST);
14614 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14615
14616 member = RT_CONSTANT(opline, opline->op2);
14617 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14618 name = Z_STR_P(member);
14619 prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14620
14621 if (on_this) {
14622 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14623 obj_ref = jit_Z_PTR(jit, this_addr);
14624 } else {
14625 if (opline->op1_type == IS_VAR
14626 && (op1_info & MAY_BE_INDIRECT)
14627 && Z_REG(op1_addr) == ZREG_FP) {
14628 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14629 }
14630 if (op1_info & MAY_BE_REF) {
14631 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14632 }
14633 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14634 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14635 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14636 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14637
14638 if (!exit_addr) {
14639 return 0;
14640 }
14641 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14642 } else {
14643 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14644 ir_IF_FALSE_cold(if_obj);
14645
14646 jit_SET_EX_OPLINE(jit, opline);
14647 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14648 jit_ZVAL_ADDR(jit, op1_addr),
14649 ir_CONST_ADDR(ZSTR_VAL(name)));
14650
14651 if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
14652 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14653 }
14654
14655 ir_END_list(end_inputs);
14656
14657 ir_IF_TRUE(if_obj);
14658 }
14659 }
14660 obj_ref = jit_Z_PTR(jit, op1_addr);
14661 }
14662
14663 ZEND_ASSERT(obj_ref);
14664 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14665 prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14666 if (prop_info) {
14667 ce = trace_ce;
14668 ce_is_instanceof = 0;
14669 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14670 if (on_this && JIT_G(current_frame)
14671 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14672 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14673 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14674 if (on_this && JIT_G(current_frame)) {
14675 JIT_G(current_frame)->ce = ce;
14676 TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14677 }
14678 } else {
14679 return 0;
14680 }
14681 if (ssa->var_info && ssa_op->op1_use >= 0) {
14682 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14683 ssa->var_info[ssa_op->op1_use].ce = ce;
14684 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14685 }
14686 if (ssa->var_info && ssa_op->op1_def >= 0) {
14687 ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14688 ssa->var_info[ssa_op->op1_def].ce = ce;
14689 ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14690 }
14691 }
14692 }
14693 }
14694
14695 if (!prop_info) {
14696 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14697 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14698 ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14699
14700 ir_IF_FALSE_cold(if_same);
14701 ir_END_list(slow_inputs);
14702
14703 ir_IF_TRUE(if_same);
14704 ir_ref offset_ref = ir_LOAD_A(
14705 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14706
14707 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14708 ir_IF_TRUE_cold(if_dynamic);
14709 ir_END_list(slow_inputs);
14710
14711 ir_IF_FALSE(if_dynamic);
14712 prop_ref = ir_ADD_A(obj_ref, offset_ref);
14713 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14714 ir_IF_FALSE_cold(if_def);
14715 ir_END_list(slow_inputs);
14716
14717 ir_IF_TRUE(if_def);
14718 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14719
14720 if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14721 ir_ref arg3, arg4;
14722 ir_ref prop_info_ref = ir_LOAD_A(
14723 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14724 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14725 ir_IF_TRUE_cold(if_has_prop_info);
14726
14727 if (Z_MODE(val_addr) == IS_REG) {
14728 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14729 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14730 return 0;
14731 }
14732 arg3 = jit_ZVAL_ADDR(jit, real_addr);
14733 } else {
14734 arg3 = jit_ZVAL_ADDR(jit, val_addr);
14735 }
14736
14737 if (!RETURN_VALUE_USED(opline)) {
14738 arg4 = IR_NULL;
14739 } else if (Z_MODE(res_addr) == IS_REG) {
14740 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14741 arg4 = jit_ZVAL_ADDR(jit, real_addr);
14742 } else {
14743 arg4 = jit_ZVAL_ADDR(jit, res_addr);
14744 }
14745 // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14746 jit_SET_EX_OPLINE(jit, opline);
14747 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14748 prop_ref,
14749 prop_info_ref,
14750 arg3,
14751 arg4);
14752
14753 if ((opline+1)->op1_type == IS_CONST) {
14754 // TODO: ???
14755 // if (Z_TYPE_P(value) == orig_type) {
14756 // CACHE_PTR_EX(cache_slot + 2, NULL);
14757 }
14758
14759 if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14760 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14761 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14762 return 0;
14763 }
14764 }
14765
14766 ir_END_list(end_inputs);
14767 ir_IF_FALSE(if_has_prop_info);
14768 }
14769 } else {
14770 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14771 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14772 /* With the exception of __clone(), readonly assignment always happens on IS_UNDEF, doding
14773 * the fast path. Thus, the fast path is not useful. */
14774 if (prop_info->flags & ZEND_ACC_READONLY) {
14775 ZEND_ASSERT(slow_inputs == IR_UNUSED);
14776 goto slow_path;
14777 }
14778 // Undefined property with potential magic __get()/__set() or lazy object
14779 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14780 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14781 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14782
14783 if (!exit_addr) {
14784 return 0;
14785 }
14786 ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14787 } else {
14788 ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14789 ir_IF_FALSE_cold(if_def);
14790 ir_END_list(slow_inputs);
14791 ir_IF_TRUE(if_def);
14792 }
14793 if (ZEND_TYPE_IS_SET(prop_info->type)) {
14794 ir_ref ref, arg3, arg4;
14795
14796 // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14797 jit_SET_EX_OPLINE(jit, opline);
14798 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14799 ref = ir_CONST_ADDR(prop_info);
14800 } else {
14801 int prop_info_offset =
14802 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14803
14804 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14805 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14806 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14807 }
14808 if (Z_MODE(val_addr) == IS_REG) {
14809 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14810 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14811 return 0;
14812 }
14813 arg3 = jit_ZVAL_ADDR(jit, real_addr);
14814 } else {
14815 arg3 = jit_ZVAL_ADDR(jit, val_addr);
14816 }
14817 if (!RETURN_VALUE_USED(opline)) {
14818 arg4 = IR_NULL;
14819 } else if (Z_MODE(res_addr) == IS_REG) {
14820 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14821 arg4 = jit_ZVAL_ADDR(jit, real_addr);
14822 } else {
14823 arg4 = jit_ZVAL_ADDR(jit, res_addr);
14824 }
14825 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14826 prop_ref,
14827 ref,
14828 arg3,
14829 arg4);
14830
14831 if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14832 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14833 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14834 return 0;
14835 }
14836 }
14837 ir_END_list(end_inputs);
14838 }
14839 }
14840
14841 if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14842 if (Z_MODE(val_addr) != IS_REG
14843 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
14844 && opline->result_type == IS_UNUSED) {
14845 if (!zend_jit_assign_to_variable_call(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
14846 return 0;
14847 }
14848 } else {
14849 if (!zend_jit_assign_to_variable(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0, 0)) {
14850 return 0;
14851 }
14852 }
14853 if (end_inputs || slow_inputs) {
14854 if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14855 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14856 /* skip FREE_OP_DATA() */
14857 delayed_end_input = ir_END();
14858 } else {
14859 ir_END_list(end_inputs);
14860 }
14861 }
14862 }
14863
14864 if (slow_inputs) {
14865 ir_ref arg3, arg5;
14866
14867 ir_MERGE_list(slow_inputs);
14868
14869 slow_path:
14870 jit_SET_EX_OPLINE(jit, opline);
14871
14872 if (Z_MODE(val_addr) == IS_REG) {
14873 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14874 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14875 return 0;
14876 }
14877 arg3 = jit_ZVAL_ADDR(jit, real_addr);
14878 } else {
14879 arg3 = jit_ZVAL_ADDR(jit, val_addr);
14880 }
14881 if (!RETURN_VALUE_USED(opline)) {
14882 arg5 = IR_NULL;
14883 } else if (Z_MODE(res_addr) == IS_REG) {
14884 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14885 arg5 = jit_ZVAL_ADDR(jit, real_addr);
14886 } else {
14887 arg5 = jit_ZVAL_ADDR(jit, res_addr);
14888 }
14889
14890 // JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14891 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14892 ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
14893 obj_ref,
14894 ir_CONST_ADDR(name),
14895 arg3,
14896 ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
14897 arg5);
14898
14899 if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14900 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14901 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14902 return 0;
14903 }
14904 }
14905 ir_END_list(end_inputs);
14906 }
14907
14908 if (end_inputs) {
14909 ir_MERGE_list(end_inputs);
14910
14911 if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14912 val_info |= MAY_BE_RC1|MAY_BE_RCN;
14913 }
14914 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
14915
14916 if (delayed_end_input) {
14917 ir_MERGE_WITH(delayed_end_input);
14918 }
14919 }
14920
14921 if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14922 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14923 }
14924
14925 if (may_throw) {
14926 zend_jit_check_exception(jit);
14927 }
14928
14929 return 1;
14930 }
14931
14932 static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
14933 const zend_op *opline,
14934 const zend_op_array *op_array,
14935 zend_ssa *ssa,
14936 const zend_ssa_op *ssa_op,
14937 uint32_t op1_info,
14938 zend_jit_addr op1_addr,
14939 uint32_t val_info,
14940 zend_jit_addr val_addr,
14941 zend_ssa_range *val_range,
14942 bool op1_indirect,
14943 zend_class_entry *ce,
14944 bool ce_is_instanceof,
14945 bool on_this,
14946 bool delayed_fetch_this,
14947 zend_class_entry *trace_ce,
14948 uint8_t prop_type)
14949 {
14950 zval *member;
14951 zend_string *name;
14952 zend_property_info *prop_info;
14953 zend_jit_addr prop_addr;
14954 bool use_prop_guard = 0;
14955 bool may_throw = 0;
14956 binary_op_type binary_op = get_binary_op(opline->extended_value);
14957 ir_ref obj_ref = IR_UNUSED;
14958 ir_ref prop_ref = IR_UNUSED;
14959 ir_ref end_inputs = IR_UNUSED;
14960 ir_ref slow_inputs = IR_UNUSED;
14961
14962 ZEND_ASSERT(opline->op2_type == IS_CONST);
14963 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14964 ZEND_ASSERT(opline->result_type == IS_UNUSED);
14965
14966 member = RT_CONSTANT(opline, opline->op2);
14967 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14968 name = Z_STR_P(member);
14969 prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14970
14971 if (on_this) {
14972 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14973 obj_ref = jit_Z_PTR(jit, this_addr);
14974 } else {
14975 if (opline->op1_type == IS_VAR
14976 && (op1_info & MAY_BE_INDIRECT)
14977 && Z_REG(op1_addr) == ZREG_FP) {
14978 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14979 }
14980 if (op1_info & MAY_BE_REF) {
14981 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14982 }
14983 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14984 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14985 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14986 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14987
14988 if (!exit_addr) {
14989 return 0;
14990 }
14991 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14992 } else {
14993 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14994 ir_IF_FALSE_cold(if_obj);
14995
14996 jit_SET_EX_OPLINE(jit, opline);
14997 ir_CALL_2(IR_VOID,
14998 (op1_info & MAY_BE_UNDEF) ?
14999 ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
15000 ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
15001 jit_ZVAL_ADDR(jit, op1_addr),
15002 ir_CONST_ADDR(ZSTR_VAL(name)));
15003
15004 may_throw = 1;
15005
15006 ir_END_list(end_inputs);
15007 ir_IF_TRUE(if_obj);
15008 }
15009 }
15010 obj_ref = jit_Z_PTR(jit, op1_addr);
15011 }
15012
15013 ZEND_ASSERT(obj_ref);
15014 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15015 prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15016 if (prop_info) {
15017 ce = trace_ce;
15018 ce_is_instanceof = 0;
15019 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15020 if (on_this && JIT_G(current_frame)
15021 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15022 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15023 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15024 if (on_this && JIT_G(current_frame)) {
15025 JIT_G(current_frame)->ce = ce;
15026 TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15027 }
15028 } else {
15029 return 0;
15030 }
15031 if (ssa->var_info && ssa_op->op1_use >= 0) {
15032 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15033 ssa->var_info[ssa_op->op1_use].ce = ce;
15034 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15035 }
15036 if (ssa->var_info && ssa_op->op1_def >= 0) {
15037 ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15038 ssa->var_info[ssa_op->op1_def].ce = ce;
15039 ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15040 }
15041 }
15042 }
15043 }
15044
15045 use_prop_guard = (prop_type != IS_UNKNOWN
15046 && prop_type != IS_UNDEF
15047 && prop_type != IS_REFERENCE
15048 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15049
15050 if (!prop_info) {
15051 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15052 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15053 ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15054
15055 ir_IF_FALSE_cold(if_same);
15056 ir_END_list(slow_inputs);
15057
15058 ir_IF_TRUE(if_same);
15059 if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15060 ir_ref prop_info_ref = ir_LOAD_A(
15061 ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15062 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15063 ir_IF_TRUE_cold(if_has_prop_info);
15064 ir_END_list(slow_inputs);
15065
15066 ir_IF_FALSE(if_has_prop_info);
15067 }
15068 ir_ref offset_ref = ir_LOAD_A(
15069 ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15070
15071 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15072 ir_IF_TRUE_cold(if_dynamic);
15073 ir_END_list(slow_inputs);
15074
15075 ir_IF_FALSE(if_dynamic);
15076
15077 prop_ref = ir_ADD_A(obj_ref, offset_ref);
15078 if (!use_prop_guard) {
15079 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15080 ir_IF_FALSE_cold(if_def);
15081 ir_END_list(slow_inputs);
15082
15083 ir_IF_TRUE(if_def);
15084 }
15085 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15086 } else {
15087 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15088 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15089
15090 if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15091 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15092 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15093 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15094
15095 if (!exit_addr) {
15096 return 0;
15097 }
15098 ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15099 } else {
15100 ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15101 ir_IF_FALSE_cold(if_def);
15102 ir_END_list(slow_inputs);
15103 ir_IF_TRUE(if_def);
15104 }
15105 }
15106 if (ZEND_TYPE_IS_SET(prop_info->type)) {
15107 ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15108
15109 may_throw = 1;
15110
15111 jit_SET_EX_OPLINE(jit, opline);
15112
15113 if (Z_MODE(val_addr) == IS_REG) {
15114 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15115 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15116 return 0;
15117 }
15118 arg2 = jit_ZVAL_ADDR(jit, real_addr);
15119 } else {
15120 arg2 = jit_ZVAL_ADDR(jit, val_addr);
15121 }
15122
15123 if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15124 ir_IF_FALSE(if_ref);
15125 noref_path = ir_END();
15126 ir_IF_TRUE(if_ref);
15127
15128 reference = jit_Z_PTR(jit, prop_addr);
15129 ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15130 if_typed = jit_if_TYPED_REF(jit, reference);
15131 ir_IF_FALSE(if_typed);
15132 ref_path = ir_END();
15133 ir_IF_TRUE_cold(if_typed);
15134
15135 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15136 reference,
15137 arg2,
15138 ir_CONST_FC_FUNC(binary_op));
15139
15140 ir_END_list(end_inputs);
15141
15142 ir_MERGE_2(noref_path, ref_path);
15143 prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15144 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15145
15146 // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15147 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15148 ref = ir_CONST_ADDR(prop_info);
15149 } else {
15150 int prop_info_offset =
15151 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15152
15153 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15154 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15155 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15156 }
15157
15158 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
15159 prop_ref,
15160 ref,
15161 arg2,
15162 ir_CONST_FC_FUNC(binary_op));
15163
15164 ir_END_list(end_inputs);
15165 }
15166 }
15167
15168 if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15169 zend_jit_addr var_addr = prop_addr;
15170 uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15171 uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15172
15173 if (use_prop_guard) {
15174 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15175 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15176 if (!exit_addr) {
15177 return 0;
15178 }
15179
15180 jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15181 var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15182 }
15183
15184 if (var_info & MAY_BE_REF) {
15185 ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15186
15187 may_throw = 1;
15188
15189 if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15190 ir_IF_FALSE(if_ref);
15191 noref_path = ir_END();
15192 ir_IF_TRUE(if_ref);
15193
15194 reference = jit_Z_PTR(jit, var_addr);
15195 ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15196 if_typed = jit_if_TYPED_REF(jit, reference);
15197 ir_IF_FALSE(if_typed);
15198 ref_path = ir_END();
15199 ir_IF_TRUE_cold(if_typed);
15200
15201 jit_SET_EX_OPLINE(jit, opline);
15202
15203 if (Z_MODE(val_addr) == IS_REG) {
15204 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15205 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15206 return 0;
15207 }
15208 arg2 = jit_ZVAL_ADDR(jit, real_addr);
15209 } else {
15210 arg2 = jit_ZVAL_ADDR(jit, val_addr);
15211 }
15212 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15213 reference,
15214 arg2,
15215 ir_CONST_FC_FUNC(binary_op));
15216
15217 ir_END_list(end_inputs);
15218
15219 ir_MERGE_2(noref_path, ref_path);
15220 prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15221 var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15222
15223 var_info &= ~MAY_BE_REF;
15224 }
15225
15226 uint8_t val_op_type = (opline+1)->op1_type;
15227 if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
15228 /* prevent FREE_OP in the helpers */
15229 val_op_type = IS_CV;
15230 }
15231
15232 switch (opline->extended_value) {
15233 case ZEND_ADD:
15234 case ZEND_SUB:
15235 case ZEND_MUL:
15236 if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15237 (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15238 if (opline->extended_value != ZEND_ADD ||
15239 (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
15240 (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
15241 may_throw = 1;
15242 }
15243 }
15244 if (!zend_jit_math_helper(jit, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, val_addr, val_info, 0, var_addr, var_def_info, var_info,
15245 1 /* may overflow */, 0)) {
15246 return 0;
15247 }
15248 break;
15249 case ZEND_BW_OR:
15250 case ZEND_BW_AND:
15251 case ZEND_BW_XOR:
15252 if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15253 (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15254 if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
15255 (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
15256 may_throw = 1;
15257 }
15258 }
15259 goto long_math;
15260 case ZEND_SL:
15261 case ZEND_SR:
15262 if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15263 (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15264 may_throw = 1;
15265 }
15266 if (val_op_type != IS_CONST ||
15267 Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15268 Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
15269 may_throw = 1;
15270 }
15271 goto long_math;
15272 case ZEND_MOD:
15273 if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15274 (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15275 may_throw = 1;
15276 }
15277 if (val_op_type != IS_CONST ||
15278 Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15279 Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
15280 may_throw = 1;
15281 }
15282 long_math:
15283 if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
15284 IS_CV, opline->op1, var_addr, var_info, NULL,
15285 val_op_type, (opline+1)->op1, val_addr, val_info,
15286 val_range,
15287 0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
15288 return 0;
15289 }
15290 break;
15291 case ZEND_CONCAT:
15292 may_throw = 1;
15293 if (!zend_jit_concat_helper(jit, opline, IS_CV, opline->op1, var_addr, var_info, val_op_type, (opline+1)->op1, val_addr, val_info, var_addr,
15294 0)) {
15295 return 0;
15296 }
15297 break;
15298 default:
15299 ZEND_UNREACHABLE();
15300 }
15301 if (end_inputs || slow_inputs) {
15302 ir_END_list(end_inputs);
15303 }
15304 }
15305
15306 if (slow_inputs) {
15307 ir_ref arg3;
15308
15309 ir_MERGE_list(slow_inputs);
15310
15311 may_throw = 1;
15312
15313 if (Z_MODE(val_addr) == IS_REG) {
15314 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15315 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15316 return 0;
15317 }
15318 arg3 = jit_ZVAL_ADDR(jit, real_addr);
15319 } else {
15320 arg3 = jit_ZVAL_ADDR(jit, val_addr);
15321 }
15322 jit_SET_EX_OPLINE(jit, opline);
15323 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15324 ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15325 obj_ref,
15326 ir_CONST_ADDR(name),
15327 arg3,
15328 ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15329 ir_CONST_FC_FUNC(binary_op));
15330
15331 ir_END_list(end_inputs);
15332 }
15333
15334 if (end_inputs) {
15335 ir_MERGE_list(end_inputs);
15336 }
15337
15338 if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15339 val_info |= MAY_BE_RC1|MAY_BE_RCN;
15340 }
15341
15342 // JIT: FREE_OP_DATA();
15343 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15344
15345 if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15346 if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15347 may_throw = 1;
15348 }
15349 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15350 }
15351
15352 if (may_throw) {
15353 zend_jit_check_exception(jit);
15354 }
15355
15356 return 1;
15357 }
15358
15359 static int zend_jit_incdec_obj(zend_jit_ctx *jit,
15360 const zend_op *opline,
15361 const zend_op_array *op_array,
15362 zend_ssa *ssa,
15363 const zend_ssa_op *ssa_op,
15364 uint32_t op1_info,
15365 zend_jit_addr op1_addr,
15366 bool op1_indirect,
15367 zend_class_entry *ce,
15368 bool ce_is_instanceof,
15369 bool on_this,
15370 bool delayed_fetch_this,
15371 zend_class_entry *trace_ce,
15372 uint8_t prop_type)
15373 {
15374 zval *member;
15375 zend_string *name;
15376 zend_property_info *prop_info;
15377 zend_jit_addr res_addr = 0;
15378 zend_jit_addr prop_addr;
15379 bool use_prop_guard = 0;
15380 bool may_throw = 0;
15381 uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15382 ir_ref obj_ref = IR_UNUSED;
15383 ir_ref prop_ref = IR_UNUSED;
15384 ir_ref end_inputs = IR_UNUSED;
15385 ir_ref slow_inputs = IR_UNUSED;
15386
15387 ZEND_ASSERT(opline->op2_type == IS_CONST);
15388 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15389
15390 if (opline->result_type != IS_UNUSED) {
15391 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15392 }
15393
15394 member = RT_CONSTANT(opline, opline->op2);
15395 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15396 name = Z_STR_P(member);
15397 prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15398
15399 if (on_this) {
15400 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15401 obj_ref = jit_Z_PTR(jit, this_addr);
15402 } else {
15403 if (opline->op1_type == IS_VAR
15404 && (op1_info & MAY_BE_INDIRECT)
15405 && Z_REG(op1_addr) == ZREG_FP) {
15406 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15407 }
15408 if (op1_info & MAY_BE_REF) {
15409 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15410 }
15411 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15412 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15413 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15414 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15415
15416 if (!exit_addr) {
15417 return 0;
15418 }
15419 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15420 } else {
15421 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15422 ir_IF_FALSE_cold(if_obj);
15423
15424 jit_SET_EX_OPLINE(jit, opline);
15425 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15426 jit_ZVAL_ADDR(jit, op1_addr),
15427 ir_CONST_ADDR(ZSTR_VAL(name)));
15428
15429 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15430 ir_IF_TRUE(if_obj);
15431 }
15432 }
15433 obj_ref = jit_Z_PTR(jit, op1_addr);
15434 }
15435
15436 ZEND_ASSERT(obj_ref);
15437 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15438 prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15439 if (prop_info) {
15440 ce = trace_ce;
15441 ce_is_instanceof = 0;
15442 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15443 if (on_this && JIT_G(current_frame)
15444 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15445 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15446 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15447 if (on_this && JIT_G(current_frame)) {
15448 JIT_G(current_frame)->ce = ce;
15449 TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15450 }
15451 } else {
15452 return 0;
15453 }
15454 if (ssa->var_info && ssa_op->op1_use >= 0) {
15455 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15456 ssa->var_info[ssa_op->op1_use].ce = ce;
15457 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15458 }
15459 if (ssa->var_info && ssa_op->op1_def >= 0) {
15460 ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15461 ssa->var_info[ssa_op->op1_def].ce = ce;
15462 ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15463 }
15464 }
15465 }
15466 }
15467
15468 use_prop_guard = (prop_type != IS_UNKNOWN
15469 && prop_type != IS_UNDEF
15470 && prop_type != IS_REFERENCE
15471 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15472
15473 if (!prop_info) {
15474 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15475 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15476 ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15477
15478 ir_IF_FALSE_cold(if_same);
15479 ir_END_list(slow_inputs);
15480
15481 ir_IF_TRUE(if_same);
15482 if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15483 ir_ref prop_info_ref = ir_LOAD_A(
15484 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15485 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15486 ir_IF_TRUE_cold(if_has_prop_info);
15487 ir_END_list(slow_inputs);
15488
15489 ir_IF_FALSE(if_has_prop_info);
15490 }
15491 ir_ref offset_ref = ir_LOAD_A(
15492 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15493
15494 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15495 ir_IF_TRUE_cold(if_dynamic);
15496 ir_END_list(slow_inputs);
15497
15498 ir_IF_FALSE(if_dynamic);
15499
15500 prop_ref = ir_ADD_A(obj_ref, offset_ref);
15501 if (!use_prop_guard) {
15502 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15503 ir_IF_FALSE_cold(if_def);
15504 ir_END_list(slow_inputs);
15505
15506 ir_IF_TRUE(if_def);
15507 }
15508 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15509 } else {
15510 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15511 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15512
15513 if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15514 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15515 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15516 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15517
15518 if (!exit_addr) {
15519 return 0;
15520 }
15521 ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15522 } else {
15523 ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15524 ir_IF_FALSE_cold(if_def);
15525 ir_END_list(slow_inputs);
15526 ir_IF_TRUE(if_def);
15527 }
15528 }
15529
15530 if (ZEND_TYPE_IS_SET(prop_info->type)) {
15531 const void *func;
15532 ir_ref ref;
15533
15534 may_throw = 1;
15535 jit_SET_EX_OPLINE(jit, opline);
15536
15537 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15538 ref = ir_CONST_ADDR(prop_info);
15539 } else {
15540 int prop_info_offset =
15541 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15542
15543 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15544 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15545 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15546 }
15547
15548 if (opline->result_type == IS_UNUSED) {
15549 switch (opline->opcode) {
15550 case ZEND_PRE_INC_OBJ:
15551 case ZEND_POST_INC_OBJ:
15552 func = zend_jit_inc_typed_prop;
15553 break;
15554 case ZEND_PRE_DEC_OBJ:
15555 case ZEND_POST_DEC_OBJ:
15556 func = zend_jit_dec_typed_prop;
15557 break;
15558 default:
15559 ZEND_UNREACHABLE();
15560 }
15561
15562 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
15563 } else {
15564 switch (opline->opcode) {
15565 case ZEND_PRE_INC_OBJ:
15566 func = zend_jit_pre_inc_typed_prop;
15567 break;
15568 case ZEND_PRE_DEC_OBJ:
15569 func = zend_jit_pre_dec_typed_prop;
15570 break;
15571 case ZEND_POST_INC_OBJ:
15572 func = zend_jit_post_inc_typed_prop;
15573 break;
15574 case ZEND_POST_DEC_OBJ:
15575 func = zend_jit_post_dec_typed_prop;
15576 break;
15577 default:
15578 ZEND_UNREACHABLE();
15579 }
15580 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func),
15581 prop_ref,
15582 ref,
15583 jit_ZVAL_ADDR(jit, res_addr));
15584 }
15585 ir_END_list(end_inputs);
15586 }
15587 }
15588
15589 if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15590 uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15591 zend_jit_addr var_addr = prop_addr;
15592 ir_ref if_long = IR_UNUSED;
15593 ir_ref if_overflow = IR_UNUSED;
15594
15595 if (use_prop_guard) {
15596 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15597 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15598 if (!exit_addr) {
15599 return 0;
15600 }
15601
15602 jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15603 var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15604 }
15605
15606 if (var_info & MAY_BE_REF) {
15607 const void *func;
15608 ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
15609
15610 if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15611 ir_IF_FALSE(if_ref);
15612 noref_path = ir_END();
15613 ir_IF_TRUE(if_ref);
15614
15615 reference = jit_Z_PTR(jit, var_addr);
15616 ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15617 if_typed = jit_if_TYPED_REF(jit, reference);
15618 ir_IF_FALSE(if_typed);
15619 ref_path = ir_END();
15620 ir_IF_TRUE_cold(if_typed);
15621
15622 switch (opline->opcode) {
15623 case ZEND_PRE_INC_OBJ:
15624 func = zend_jit_pre_inc_typed_ref;
15625 break;
15626 case ZEND_PRE_DEC_OBJ:
15627 func = zend_jit_pre_dec_typed_ref;
15628 break;
15629 case ZEND_POST_INC_OBJ:
15630 func = zend_jit_post_inc_typed_ref;
15631 break;
15632 case ZEND_POST_DEC_OBJ:
15633 func = zend_jit_post_dec_typed_ref;
15634 break;
15635 default:
15636 ZEND_UNREACHABLE();
15637 }
15638
15639 may_throw = 1;
15640 jit_SET_EX_OPLINE(jit, opline);
15641 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func),
15642 reference,
15643 (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15644
15645 ir_END_list(end_inputs);
15646
15647 ir_MERGE_2(noref_path, ref_path);
15648 prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15649 var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15650
15651 var_info &= ~MAY_BE_REF;
15652 }
15653
15654 if (var_info & MAY_BE_LONG) {
15655 ir_ref addr, ref;
15656
15657 if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15658 if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
15659 ir_IF_TRUE(if_long);
15660 }
15661
15662 addr = jit_ZVAL_ADDR(jit, var_addr);
15663 ref = ir_LOAD_L(addr);
15664 if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15665 if (opline->result_type != IS_UNUSED) {
15666 jit_set_Z_LVAL(jit, res_addr, ref);
15667 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15668 }
15669 }
15670 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15671 ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
15672 } else {
15673 ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
15674 }
15675
15676 ir_STORE(addr, ref);
15677 if_overflow = ir_IF(ir_OVERFLOW(ref));
15678 ir_IF_FALSE(if_overflow);
15679
15680 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
15681 if (opline->result_type != IS_UNUSED) {
15682 jit_set_Z_LVAL(jit, res_addr, ref);
15683 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15684 }
15685 }
15686 ir_END_list(end_inputs);
15687 }
15688
15689 if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15690 if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15691 may_throw = 1;
15692 }
15693 if (if_long) {
15694 ir_IF_FALSE_cold(if_long);
15695 }
15696 if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15697 jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, 1);
15698 }
15699 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15700 if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15701 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
15702 jit_ZVAL_ADDR(jit, var_addr),
15703 jit_ZVAL_ADDR(jit, res_addr));
15704 } else {
15705 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function),
15706 jit_ZVAL_ADDR(jit, var_addr));
15707 }
15708 } else {
15709 if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15710 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
15711 jit_ZVAL_ADDR(jit, var_addr),
15712 jit_ZVAL_ADDR(jit, res_addr));
15713 } else {
15714 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function),
15715 jit_ZVAL_ADDR(jit, var_addr));
15716 }
15717 }
15718
15719 ir_END_list(end_inputs);
15720 }
15721 if (var_info & MAY_BE_LONG) {
15722 ir_IF_TRUE_cold(if_overflow);
15723 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15724 #if SIZEOF_ZEND_LONG == 4
15725 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
15726 jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
15727 #else
15728 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
15729 #endif
15730 jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15731 if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15732 #if SIZEOF_ZEND_LONG == 4
15733 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
15734 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
15735 #else
15736 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
15737 #endif
15738 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15739 }
15740 } else {
15741 #if SIZEOF_ZEND_LONG == 4
15742 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
15743 jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
15744 #else
15745 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
15746 #endif
15747 jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15748 if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15749 #if SIZEOF_ZEND_LONG == 4
15750 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
15751 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
15752 #else
15753 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
15754 #endif
15755 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15756 }
15757 }
15758 if (opline->result_type != IS_UNUSED
15759 && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
15760 && prop_info
15761 && !ZEND_TYPE_IS_SET(prop_info->type)
15762 && (res_info & MAY_BE_GUARD)
15763 && (res_info & MAY_BE_LONG)) {
15764 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
15765 uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
15766 int32_t exit_point;
15767 const void *exit_addr;
15768
15769 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
15770 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15771 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15772 if (!exit_addr) {
15773 return 0;
15774 }
15775 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
15776 ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
15777 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15778 } else {
15779 ir_END_list(end_inputs);
15780 }
15781 }
15782 }
15783
15784 if (slow_inputs) {
15785 const void *func;
15786
15787 ir_MERGE_list(slow_inputs);
15788
15789 // JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
15790 switch (opline->opcode) {
15791 case ZEND_PRE_INC_OBJ:
15792 func = zend_jit_pre_inc_obj_helper;
15793 break;
15794 case ZEND_PRE_DEC_OBJ:
15795 func = zend_jit_pre_dec_obj_helper;
15796 break;
15797 case ZEND_POST_INC_OBJ:
15798 func = zend_jit_post_inc_obj_helper;
15799 break;
15800 case ZEND_POST_DEC_OBJ:
15801 func = zend_jit_post_dec_obj_helper;
15802 break;
15803 default:
15804 ZEND_UNREACHABLE();
15805 }
15806
15807 may_throw = 1;
15808 jit_SET_EX_OPLINE(jit, opline);
15809 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15810 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func),
15811 obj_ref,
15812 ir_CONST_ADDR(name),
15813 ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15814 (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15815
15816 ir_END_list(end_inputs);
15817 }
15818
15819 if (end_inputs) {
15820 ir_MERGE_list(end_inputs);
15821 }
15822
15823 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
15824 if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15825 may_throw = 1;
15826 }
15827 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15828 }
15829
15830 if (may_throw) {
15831 zend_jit_check_exception(jit);
15832 }
15833
15834 return 1;
15835 }
15836
15837 static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
15838 {
15839 zend_jit_addr res_addr = RES_ADDR();
15840 uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
15841 uint32_t flags;
15842 ir_ref ref, ref2, if_cached, fast_path, cold_path, prop_info_ref, if_typed, if_def;
15843 int fetch_type;
15844 zend_property_info *known_prop_info = NULL;
15845 zend_class_entry *ce;
15846
15847 ce = zend_get_known_class(op_array, opline, opline->op2_type, opline->op2);
15848 if (ce) {
15849 zval *zv = RT_CONSTANT(opline, opline->op1);
15850 zend_string *prop_name;
15851
15852 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
15853 prop_name = Z_STR_P(zv);
15854 zv = zend_hash_find(&ce->properties_info, prop_name);
15855 if (zv) {
15856 zend_property_info *prop_info = Z_PTR_P(zv);
15857
15858 if (prop_info->flags & ZEND_ACC_STATIC) {
15859 if (prop_info->ce == op_array->scope
15860 || (prop_info->flags & ZEND_ACC_PUBLIC)
15861 || ((prop_info->flags & ZEND_ACC_PROTECTED)
15862 && op_array->scope
15863 && instanceof_function_slow(op_array->scope, prop_info->ce))) {
15864 known_prop_info = prop_info;
15865 }
15866 }
15867 }
15868 }
15869
15870 switch (opline->opcode) {
15871 case ZEND_FETCH_STATIC_PROP_R:
15872 case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
15873 fetch_type = BP_VAR_R;
15874 break;
15875 case ZEND_FETCH_STATIC_PROP_IS:
15876 fetch_type = BP_VAR_IS;
15877 break;
15878 case ZEND_FETCH_STATIC_PROP_W:
15879 fetch_type = BP_VAR_W;
15880 break;
15881 case ZEND_FETCH_STATIC_PROP_RW:
15882 fetch_type = BP_VAR_RW;
15883 break;
15884 case ZEND_FETCH_STATIC_PROP_UNSET:
15885 fetch_type = BP_VAR_UNSET;
15886 break;
15887 EMPTY_SWITCH_DEFAULT_CASE();
15888 }
15889
15890 // JIT: result = CACHED_PTR(cache_slot + sizeof(void *));
15891 ref = ir_LOAD_A(
15892 ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*)));
15893
15894 // JIT: if (result)
15895 if_cached = ir_IF(ref);
15896 ir_IF_TRUE(if_cached);
15897
15898 if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW) {
15899 if (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type)) {
15900 ir_ref merge = IR_UNUSED;
15901
15902 // JIT: if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
15903 if_typed = IR_UNUSED;
15904 if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
15905 ir_IF_FALSE_cold(if_def);
15906 if (!known_prop_info) {
15907 // JIT: if (ZEND_TYPE_IS_SET(property_info->type))
15908 prop_info_ref = ir_LOAD_L(
15909 ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
15910 if_typed = ir_IF(ir_AND_U32(
15911 ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
15912 ir_CONST_U32(_ZEND_TYPE_MASK)));
15913 ir_IF_FALSE(if_typed);
15914 ir_END_list(merge);
15915 ir_IF_TRUE(if_typed);
15916 }
15917 // JIT: zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
15918 // ZSTR_VAL(property_info->ce->name),
15919 // zend_get_unmangled_property_name(property_info->name));
15920 jit_SET_EX_OPLINE(jit, opline);
15921 ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_uninit_static_prop));
15922 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
15923
15924 ir_IF_TRUE(if_def);
15925 if (!known_prop_info) {
15926 ir_END_list(merge);
15927 ir_MERGE_list(merge);
15928 }
15929 }
15930 } else if (fetch_type == BP_VAR_W) {
15931 flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
15932 if (flags && (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type))) {
15933 ir_ref merge = IR_UNUSED;
15934
15935 if (!known_prop_info) {
15936 // JIT: if (ZEND_TYPE_IS_SET(property_info->type))
15937 prop_info_ref = ir_LOAD_L(
15938 ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
15939 if_typed = ir_IF(ir_AND_U32(
15940 ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
15941 ir_CONST_U32(_ZEND_TYPE_MASK)));
15942 ir_IF_FALSE(if_typed);
15943 ir_END_list(merge);
15944 ir_IF_TRUE(if_typed);
15945 } else {
15946 prop_info_ref = ir_CONST_ADDR(known_prop_info);
15947 }
15948
15949 // JIT: zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
15950 ir_ref if_ok = ir_IF(ir_CALL_5(IR_BOOL, ir_CONST_FUNC(zend_handle_fetch_obj_flags),
15951 IR_NULL, ref, IR_NULL, prop_info_ref, ir_CONST_U32(flags)));
15952 ir_IF_FALSE_cold(if_ok);
15953 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
15954 ir_IF_TRUE(if_ok);
15955 if (!known_prop_info) {
15956 ir_END_list(merge);
15957 ir_MERGE_list(merge);
15958 }
15959 }
15960 }
15961
15962 fast_path = ir_END();
15963
15964 ir_IF_FALSE_cold(if_cached);
15965 jit_SET_EX_OPLINE(jit, opline);
15966 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_fetch_static_property), jit_FP(jit), ir_CONST_I32(fetch_type));
15967 zend_jit_check_exception_undef_result(jit, opline);
15968 cold_path = ir_END();
15969
15970 ir_MERGE_2(fast_path, cold_path);
15971 ref = ir_PHI_2(IR_ADDR, ref, ref2);
15972
15973 if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_IS) {
15974 // JIT: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), result);
15975 if (!zend_jit_zval_copy_deref(jit, res_addr, ZEND_ADDR_REF_ZVAL(ref),
15976 jit_Z_TYPE_INFO_ref(jit, ref))) {
15977 return 0;
15978 }
15979 } else {
15980 // JIT: ZVAL_INDIRECT(EX_VAR(opline->result.var), result);
15981 jit_set_Z_PTR(jit, res_addr, ref);
15982 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
15983 }
15984
15985 return 1;
15986 }
15987
15988 static int zend_jit_switch(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info)
15989 {
15990 HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
15991 const zend_op *next_opline = NULL;
15992 ir_refs *slow_inputs;
15993
15994 ir_refs_init(slow_inputs, 8);
15995
15996 if (trace) {
15997 ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
15998 ZEND_ASSERT(trace->opline != NULL);
15999 next_opline = trace->opline;
16000 }
16001
16002 if (opline->op1_type == IS_CONST) {
16003 zval *zv = RT_CONSTANT(opline, opline->op1);
16004 zval *jump_zv = NULL;
16005 int b;
16006
16007 if (opline->opcode == ZEND_SWITCH_LONG) {
16008 if (Z_TYPE_P(zv) == IS_LONG) {
16009 jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16010 }
16011 } else if (opline->opcode == ZEND_SWITCH_STRING) {
16012 if (Z_TYPE_P(zv) == IS_STRING) {
16013 jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16014 }
16015 } else if (opline->opcode == ZEND_MATCH) {
16016 if (Z_TYPE_P(zv) == IS_LONG) {
16017 jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16018 } else if (Z_TYPE_P(zv) == IS_STRING) {
16019 jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16020 }
16021 } else {
16022 ZEND_UNREACHABLE();
16023 }
16024 if (next_opline) {
16025 const zend_op *target;
16026
16027 if (jump_zv != NULL) {
16028 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
16029 } else {
16030 target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16031 }
16032 ZEND_ASSERT(target == next_opline);
16033 } else {
16034 if (jump_zv != NULL) {
16035 b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
16036 } else {
16037 b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
16038 }
16039 _zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
16040 jit->b = -1;
16041 }
16042 } else {
16043 zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
16044 uint32_t op1_info = OP1_INFO();
16045 zend_jit_addr op1_addr = OP1_ADDR();
16046 const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16047 const zend_op *target;
16048 int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
16049 int b;
16050 int32_t exit_point;
16051 const void *exit_addr;
16052 const void *default_label = NULL;
16053 zval *zv;
16054
16055 if (next_opline) {
16056 if (next_opline != default_opline) {
16057 exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
16058 default_label = zend_jit_trace_get_exit_addr(exit_point);
16059 if (!default_label) {
16060 return 0;
16061 }
16062 }
16063 }
16064
16065 if (opline->opcode == ZEND_SWITCH_LONG) {
16066 if (op1_info & MAY_BE_LONG) {
16067 const void *fallback_label = NULL;
16068
16069 if (next_opline) {
16070 if (next_opline != opline + 1) {
16071 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16072 fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16073 if (!fallback_label) {
16074 return 0;
16075 }
16076 }
16077 }
16078 if (op1_info & MAY_BE_REF) {
16079 ir_ref ref, if_long, fast_path, ref2;
16080
16081 ref = jit_ZVAL_ADDR(jit, op1_addr);
16082 if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16083 ir_IF_TRUE(if_long);
16084 fast_path = ir_END();
16085 ir_IF_FALSE_cold(if_long);
16086
16087 // JIT: ZVAL_DEREF(op)
16088 if (fallback_label) {
16089 jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16090 } else {
16091 ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
16092 ir_IF_FALSE_cold(if_ref);
16093 ir_refs_add(slow_inputs, ir_END());
16094 ir_IF_TRUE(if_ref);
16095 }
16096
16097 ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16098 op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16099
16100 if (fallback_label) {
16101 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16102 } else {
16103 if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16104 ir_IF_FALSE_cold(if_long);
16105 ir_refs_add(slow_inputs, ir_END());
16106 ir_IF_TRUE(if_long);
16107 }
16108
16109 ir_MERGE_2(fast_path, ir_END());
16110 ref = ir_PHI_2(IR_ADDR, ref, ref2);
16111 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16112 } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16113 if (fallback_label) {
16114 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16115 } else {
16116 ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16117 ir_IF_FALSE_cold(if_long);
16118 ir_refs_add(slow_inputs, ir_END());
16119 ir_IF_TRUE(if_long);
16120 }
16121 }
16122 ir_ref ref = jit_Z_LVAL(jit, op1_addr);
16123
16124 if (!HT_IS_PACKED(jumptable)) {
16125 ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16126 ir_CONST_ADDR(jumptable), ref);
16127 ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16128 /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16129 if (sizeof(Bucket) == 32) {
16130 ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16131 } else {
16132 ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16133 }
16134 }
16135 ref = ir_SWITCH(ref);
16136
16137 if (next_opline) {
16138 ir_ref continue_list = IR_UNUSED;
16139
16140 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16141 ir_ref idx;
16142 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16143
16144 if (HT_IS_PACKED(jumptable)) {
16145 idx = ir_CONST_LONG(zv - jumptable->arPacked);
16146 } else {
16147 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16148 }
16149 ir_CASE_VAL(ref, idx);
16150 if (target == next_opline) {
16151 ir_END_list(continue_list);
16152 } else {
16153 exit_point = zend_jit_trace_get_exit_point(target, 0);
16154 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16155 if (!exit_addr) {
16156 return 0;
16157 }
16158 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16159 }
16160 } ZEND_HASH_FOREACH_END();
16161
16162 ir_CASE_DEFAULT(ref);
16163 if (next_opline == default_opline) {
16164 ir_END_list(continue_list);
16165 } else {
16166 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16167 }
16168 if (continue_list) {
16169 ir_MERGE_list(continue_list);
16170 } else {
16171 ZEND_ASSERT(slow_inputs->count);
16172 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16173 }
16174 } else {
16175 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16176 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16177 b = ssa->cfg.map[target - op_array->opcodes];
16178 _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16179 } ZEND_HASH_FOREACH_END();
16180
16181 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16182 if (slow_inputs->count) {
16183 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16184 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16185 }
16186 jit->b = -1;
16187 }
16188 } else if (!next_opline) {
16189 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16190 jit->b = -1;
16191 }
16192 } else if (opline->opcode == ZEND_SWITCH_STRING) {
16193 if (op1_info & MAY_BE_STRING) {
16194 const void *fallback_label = NULL;
16195
16196 if (next_opline) {
16197 if (next_opline != opline + 1) {
16198 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16199 fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16200 if (!fallback_label) {
16201 return 0;
16202 }
16203 }
16204 }
16205 if (op1_info & MAY_BE_REF) {
16206 ir_ref ref, if_string, fast_path, ref2;
16207
16208 ref = jit_ZVAL_ADDR(jit, op1_addr);
16209 if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16210 ir_IF_TRUE(if_string);
16211 fast_path = ir_END();
16212 ir_IF_FALSE_cold(if_string);
16213
16214 // JIT: ZVAL_DEREF(op)
16215 if (fallback_label) {
16216 jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16217 } else {
16218 ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16219 ir_IF_FALSE_cold(if_ref);
16220 ir_refs_add(slow_inputs, ir_END());
16221 ir_IF_TRUE(if_ref);
16222 }
16223
16224 ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16225 op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16226
16227 if (fallback_label) {
16228 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16229 } else {
16230 if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16231 ir_IF_FALSE_cold(if_string);
16232 ir_refs_add(slow_inputs, ir_END());
16233 ir_IF_TRUE(if_string);
16234 }
16235
16236 ir_MERGE_2(fast_path, ir_END());
16237 ref = ir_PHI_2(IR_ADDR, ref, ref2);
16238 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16239 } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
16240 if (fallback_label) {
16241 jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
16242 } else {
16243 ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16244 ir_IF_FALSE_cold(if_string);
16245 ir_refs_add(slow_inputs, ir_END());
16246 ir_IF_TRUE(if_string);
16247 }
16248 }
16249
16250 ir_ref ref = jit_Z_PTR(jit, op1_addr);
16251 ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16252 ir_CONST_ADDR(jumptable), ref);
16253 ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16254 /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16255 if (sizeof(Bucket) == 32) {
16256 ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16257 } else {
16258 ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16259 }
16260 ref = ir_SWITCH(ref);
16261
16262 if (next_opline) {
16263 ir_ref continue_list = IR_UNUSED;
16264
16265 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16266 ir_ref idx;
16267 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16268
16269 if (HT_IS_PACKED(jumptable)) {
16270 idx = ir_CONST_LONG(zv - jumptable->arPacked);
16271 } else {
16272 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16273 }
16274 ir_CASE_VAL(ref, idx);
16275 if (target == next_opline) {
16276 ir_END_list(continue_list);
16277 } else {
16278 exit_point = zend_jit_trace_get_exit_point(target, 0);
16279 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16280 if (!exit_addr) {
16281 return 0;
16282 }
16283 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16284 }
16285 } ZEND_HASH_FOREACH_END();
16286
16287 ir_CASE_DEFAULT(ref);
16288 if (next_opline == default_opline) {
16289 ir_END_list(continue_list);
16290 } else {
16291 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16292 }
16293 if (continue_list) {
16294 ir_MERGE_list(continue_list);
16295 } else {
16296 ZEND_ASSERT(slow_inputs->count);
16297 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16298 }
16299 } else {
16300 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16301 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16302 b = ssa->cfg.map[target - op_array->opcodes];
16303 _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16304 } ZEND_HASH_FOREACH_END();
16305 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16306 if (slow_inputs->count) {
16307 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16308 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16309 }
16310 jit->b = -1;
16311 }
16312 } else if (!next_opline) {
16313 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16314 jit->b = -1;
16315 }
16316 } else if (opline->opcode == ZEND_MATCH) {
16317 ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
16318 ir_ref continue_list = IR_UNUSED;
16319
16320 if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
16321 ir_ref long_path = IR_UNUSED;
16322
16323 if (op1_info & MAY_BE_REF) {
16324 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
16325 }
16326 if (op1_info & MAY_BE_LONG) {
16327 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16328 if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
16329 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16330 ir_IF_TRUE(if_type);
16331 } else if (default_label) {
16332 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
16333 } else if (next_opline) {
16334 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16335 ir_IF_FALSE(if_type);
16336 ir_END_list(continue_list);
16337 ir_IF_TRUE(if_type);
16338 } else {
16339 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16340 ir_IF_FALSE(if_type);
16341 ir_END_list(default_input_list);
16342 ir_IF_TRUE(if_type);
16343 }
16344 }
16345 ref = jit_Z_LVAL(jit, op1_addr);
16346 ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16347 ir_CONST_ADDR(jumptable), ref);
16348 if (op1_info & MAY_BE_STRING) {
16349 long_path = ir_END();
16350 }
16351 }
16352 if (op1_info & MAY_BE_STRING) {
16353 if (if_type) {
16354 ir_IF_FALSE(if_type);
16355 if_type = IS_UNUSED;
16356 }
16357 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
16358 if (op1_info & MAY_BE_UNDEF) {
16359 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16360 ir_IF_TRUE(if_type);
16361 } else if (default_label) {
16362 jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
16363 } else if (next_opline) {
16364 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16365 ir_IF_FALSE(if_type);
16366 ir_END_list(continue_list);
16367 ir_IF_TRUE(if_type);
16368 } else {
16369 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16370 ir_IF_FALSE(if_type);
16371 ir_END_list(default_input_list);
16372 ir_IF_TRUE(if_type);
16373 }
16374 }
16375 ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
16376 ref2 = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16377 ir_CONST_ADDR(jumptable), ref2);
16378 if (op1_info & MAY_BE_LONG) {
16379 ir_MERGE_WITH(long_path);
16380 ref = ir_PHI_2(IR_LONG, ref2, ref);
16381 } else {
16382 ref = ref2;
16383 }
16384 }
16385
16386 ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16387 /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16388 if (HT_IS_PACKED(jumptable)) {
16389 ZEND_ASSERT(sizeof(zval) == 16);
16390 ref = ir_SHR_L(ref, ir_CONST_LONG(4));
16391 } else {
16392 if (sizeof(Bucket) == 32) {
16393 ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16394 } else {
16395 ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16396 }
16397 }
16398 ref = ir_SWITCH(ref);
16399
16400 if (next_opline) {
16401 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16402 ir_ref idx;
16403 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16404
16405 if (HT_IS_PACKED(jumptable)) {
16406 idx = ir_CONST_LONG(zv - jumptable->arPacked);
16407 } else {
16408 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16409 }
16410 ir_CASE_VAL(ref, idx);
16411 if (target == next_opline) {
16412 ir_END_list(continue_list);
16413 } else {
16414 exit_point = zend_jit_trace_get_exit_point(target, 0);
16415 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16416 if (!exit_addr) {
16417 return 0;
16418 }
16419 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16420 }
16421 } ZEND_HASH_FOREACH_END();
16422
16423 ir_CASE_DEFAULT(ref);
16424 if (next_opline == default_opline) {
16425 ir_END_list(continue_list);
16426 } else {
16427 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16428 }
16429 } else {
16430 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16431 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16432 b = ssa->cfg.map[target - op_array->opcodes];
16433 _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16434 } ZEND_HASH_FOREACH_END();
16435 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16436 }
16437 } else if (!(op1_info & MAY_BE_UNDEF)) {
16438 if (next_opline) {
16439 if (next_opline == default_opline) {
16440 ir_END_list(continue_list);
16441 } else {
16442 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16443 }
16444 } else {
16445 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16446 }
16447 }
16448
16449 if (op1_info & MAY_BE_UNDEF) {
16450 if (if_type) {
16451 ir_IF_FALSE(if_type);
16452 if_type = IS_UNUSED;
16453 }
16454 if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16455 if (default_label) {
16456 jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16457 } else if (next_opline) {
16458 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16459 ir_IF_TRUE(if_def);
16460 ir_END_list(continue_list);
16461 ir_IF_FALSE_cold(if_def);
16462 } else {
16463 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16464 ir_IF_TRUE(if_def);
16465 ir_END_list(default_input_list);
16466 ir_IF_FALSE_cold(if_def);
16467 }
16468 }
16469
16470 jit_SET_EX_OPLINE(jit, opline);
16471 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16472 ir_CONST_U32(opline->op1.var));
16473 zend_jit_check_exception_undef_result(jit, opline);
16474 if (default_label) {
16475 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16476 } else if (next_opline) {
16477 ir_END_list(continue_list);
16478 } else {
16479 ir_END_list(default_input_list);
16480 }
16481 }
16482 if (next_opline) {
16483 ZEND_ASSERT(continue_list);
16484 ir_MERGE_list(continue_list);
16485 } else {
16486 if (default_input_list) {
16487 if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16488 ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16489 jit->ctx.ir_base[ref].op3 = default_input_list;
16490 } else {
16491 ir_MERGE_list(default_input_list);
16492 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16493 }
16494 }
16495 jit->b = -1;
16496 }
16497 } else {
16498 ZEND_UNREACHABLE();
16499 }
16500 }
16501 return 1;
16502 }
16503
16504 static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16505 {
16506 int i, count;
16507 zend_basic_block *bb;
16508
16509 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : (IR_START_BR_TARGET|IR_ENTRY_BR_TARGET));
16510
16511 jit->ctx.spill_base = ZREG_FP;
16512
16513 jit->op_array = jit->current_op_array = op_array;
16514 jit->ssa = ssa;
16515 jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16516 jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16517
16518 count = 0;
16519 for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
16520 jit->bb_predecessors[i] = count;
16521 count += bb->predecessors_count;
16522 }
16523 jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
16524
16525 if (!GCC_GLOBAL_REGS) {
16526 ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16527 jit_STORE_FP(jit, ref);
16528 jit->ctx.flags |= IR_FASTCALL_FUNC;
16529 }
16530
16531 return 1;
16532 }
16533
16534 static void *zend_jit_finish(zend_jit_ctx *jit)
16535 {
16536 void *entry;
16537 size_t size;
16538 zend_string *str = NULL;
16539
16540 if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP|
16541 ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_SCCP|
16542 ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS|ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
16543 if (jit->name) {
16544 str = zend_string_copy(jit->name);
16545 } else {
16546 str = zend_jit_func_name(jit->op_array);
16547 }
16548 }
16549
16550 if (jit->op_array) {
16551 /* Only for function JIT */
16552 _zend_jit_fix_merges(jit);
16553 #if defined(IR_TARGET_AARCH64)
16554 } else if (jit->trace) {
16555 jit->ctx.deoptimization_exits = jit->trace->exit_count;
16556 jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
16557 #endif
16558 } else {
16559 #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
16560 jit->ctx.flags |= IR_GEN_CACHE_DEMOTE;
16561 #endif
16562 }
16563
16564 entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
16565 if (entry) {
16566 if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16567 #ifdef HAVE_CAPSTONE
16568 if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16569 if (str) {
16570 ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
16571 }
16572 ir_disasm(str ? ZSTR_VAL(str) : "unknown",
16573 entry, size,
16574 (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0,
16575 &jit->ctx, stderr);
16576 }
16577 #endif
16578 #ifndef _WIN32
16579 if (str) {
16580 if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
16581 uintptr_t sp_offset = 0;
16582
16583 // ir_mem_unprotect(entry, size);
16584 if (!(jit->ctx.flags & IR_FUNCTION)
16585 && zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16586 #if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
16587 sp_offset = zend_jit_hybrid_vm_sp_adj;
16588 #else
16589 sp_offset = sizeof(void*);
16590 #endif
16591 } else {
16592 sp_offset = sizeof(void*);
16593 }
16594 ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
16595 // ir_mem_protect(entry, size);
16596 }
16597
16598 if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16599 ir_perf_map_register(ZSTR_VAL(str), entry, size);
16600 if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
16601 ir_perf_jitdump_register(ZSTR_VAL(str), entry, size);
16602 }
16603 }
16604 }
16605 #endif
16606 }
16607
16608 if (jit->op_array) {
16609 /* Only for function JIT */
16610 const zend_op_array *op_array = jit->op_array;
16611 zend_op *opline = (zend_op*)op_array->opcodes;
16612
16613 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
16614 while (opline->opcode == ZEND_RECV) {
16615 opline++;
16616 }
16617 }
16618 opline->handler = entry;
16619
16620 if (jit->ctx.entries_count) {
16621 /* For all entries */
16622 int i = jit->ctx.entries_count;
16623 do {
16624 ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
16625 op_array->opcodes[insn->op2].handler = (char*)entry + insn->op3;
16626 } while (i != 0);
16627 }
16628 } else {
16629 /* Only for tracing JIT */
16630 zend_jit_trace_info *t = jit->trace;
16631 zend_jit_trace_stack *stack;
16632 uint32_t i;
16633
16634 if (t) {
16635 for (i = 0; i < t->stack_map_size; i++) {
16636 stack = t->stack_map + i;
16637 if (stack->flags & ZREG_SPILL_SLOT) {
16638 stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
16639 stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
16640 }
16641 }
16642 }
16643
16644 zend_jit_trace_add_code(entry, size);
16645 }
16646 }
16647
16648 if (str) {
16649 zend_string_release(str);
16650 }
16651
16652 return entry;
16653 }
16654
16655 static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
16656 {
16657 const void *entry;
16658 size_t size;
16659 ir_code_buffer code_buffer;
16660
16661 code_buffer.start = dasm_buf;
16662 code_buffer.end = dasm_end;
16663 code_buffer.pos = *dasm_ptr;
16664
16665 entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
16666 &code_buffer, &size);
16667
16668 *dasm_ptr = code_buffer.pos;
16669
16670 if (entry) {
16671 #ifdef HAVE_CAPSTONE
16672 if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16673 uint32_t i;
16674 char name[32];
16675
16676 for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
16677 snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
16678 ir_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
16679 }
16680 }
16681 #endif
16682 }
16683
16684 return entry;
16685 }
16686
16687 static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
16688 {
16689 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16690 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16691 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16692
16693 if (!exit_addr) {
16694 return 0;
16695 }
16696 ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
16697
16698 return 1;
16699 }
16700
16701 static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
16702 {
16703 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16704 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16705 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16706
16707 if (!exit_addr) {
16708 return 0;
16709 }
16710 ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
16711
16712 return 1;
16713 }
16714
16715 static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
16716 {
16717 uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16718 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16719
16720 if (!exit_addr) {
16721 return 0;
16722 }
16723 ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16724
16725 return 1;
16726 }
16727
16728 static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
16729 {
16730 uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
16731 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16732
16733 if (!exit_addr) {
16734 return 0;
16735 }
16736
16737 ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
16738 zend_jit_set_last_valid_opline(jit, opline);
16739
16740 return 1;
16741 }
16742
16743 static bool zend_jit_guard_reference(zend_jit_ctx *jit,
16744 const zend_op *opline,
16745 zend_jit_addr *var_addr_ptr,
16746 zend_jit_addr *ref_addr_ptr,
16747 bool add_ref_guard)
16748 {
16749 zend_jit_addr var_addr = *var_addr_ptr;
16750 const void *exit_addr = NULL;
16751 ir_ref ref;
16752
16753 if (add_ref_guard) {
16754 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16755
16756 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16757 if (!exit_addr) {
16758 return 0;
16759 }
16760
16761 ref = jit_Z_TYPE(jit, var_addr);
16762 ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16763 }
16764
16765 ref = jit_Z_PTR(jit, var_addr);
16766 *ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
16767 ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16768 var_addr = ZEND_ADDR_REF_ZVAL(ref);
16769 *var_addr_ptr = var_addr;
16770
16771 return 1;
16772 }
16773
16774 static bool zend_jit_fetch_reference(zend_jit_ctx *jit,
16775 const zend_op *opline,
16776 uint8_t var_type,
16777 uint32_t *var_info_ptr,
16778 zend_jit_addr *var_addr_ptr,
16779 bool add_ref_guard,
16780 bool add_type_guard)
16781 {
16782 zend_jit_addr var_addr = *var_addr_ptr;
16783 uint32_t var_info = *var_info_ptr;
16784 const void *exit_addr = NULL;
16785 ir_ref ref;
16786
16787 if (add_ref_guard || add_type_guard) {
16788 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16789
16790 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16791 if (!exit_addr) {
16792 return 0;
16793 }
16794 }
16795
16796 if (add_ref_guard) {
16797 ref = jit_Z_TYPE(jit, var_addr);
16798 ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16799 }
16800 if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
16801 /* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
16802 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
16803 jit_ZVAL_ADDR(jit, var_addr));
16804 *var_addr_ptr = var_addr;
16805 } else {
16806 ref = jit_Z_PTR(jit, var_addr);
16807 ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
16808 var_addr = ZEND_ADDR_REF_ZVAL(ref);
16809 *var_addr_ptr = var_addr;
16810 }
16811
16812 if (var_type != IS_UNKNOWN) {
16813 var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16814 }
16815 if (add_type_guard
16816 && var_type != IS_UNKNOWN
16817 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16818 ref = jit_Z_TYPE(jit, var_addr);
16819 ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
16820
16821 ZEND_ASSERT(var_info & (1 << var_type));
16822 if (var_type < IS_STRING) {
16823 var_info = (1 << var_type);
16824 } else if (var_type != IS_ARRAY) {
16825 var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16826 } else {
16827 var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
16828 }
16829
16830 *var_info_ptr = var_info;
16831 } else {
16832 var_info &= ~MAY_BE_REF;
16833 *var_info_ptr = var_info;
16834 }
16835 *var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
16836
16837 return 1;
16838 }
16839
16840 static bool zend_jit_fetch_indirect_var(zend_jit_ctx *jit, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_indirect_guard)
16841 {
16842 zend_jit_addr var_addr = *var_addr_ptr;
16843 uint32_t var_info = *var_info_ptr;
16844 int32_t exit_point;
16845 const void *exit_addr;
16846 ir_ref ref = IR_UNUSED;
16847
16848 if (add_indirect_guard) {
16849 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16850 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16851
16852 if (!exit_addr) {
16853 return 0;
16854 }
16855 jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
16856 ref = jit_Z_PTR(jit, var_addr);
16857 } else {
16858 /* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
16859 * is eliminated by store forwarding (S2L) */
16860 ref = jit_Z_PTR(jit, var_addr);
16861 }
16862 *var_info_ptr &= ~MAY_BE_INDIRECT;
16863 var_addr = ZEND_ADDR_REF_ZVAL(ref);
16864 *var_addr_ptr = var_addr;
16865
16866 if (var_type != IS_UNKNOWN) {
16867 var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16868 }
16869 if (!(var_type & IS_TRACE_REFERENCE)
16870 && var_type != IS_UNKNOWN
16871 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16872 exit_point = zend_jit_trace_get_exit_point(opline, 0);
16873 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16874
16875 if (!exit_addr) {
16876 return 0;
16877 }
16878
16879 jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
16880
16881 //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
16882 ZEND_ASSERT(var_info & (1 << var_type));
16883 if (var_type < IS_STRING) {
16884 var_info = (1 << var_type);
16885 } else if (var_type != IS_ARRAY) {
16886 var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16887 } else {
16888 var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
16889 }
16890
16891 *var_info_ptr = var_info;
16892 }
16893
16894 return 1;
16895 }
16896
16897 static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_array, const zend_op *opline, int may_throw, zend_jit_trace_rec *trace)
16898 {
16899 zend_jit_op_array_trace_extension *jit_extension =
16900 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
16901 size_t offset = jit_extension->offset;
16902 const void *handler =
16903 (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
16904 ir_ref ref;
16905
16906 zend_jit_set_ip(jit, opline);
16907 if (GCC_GLOBAL_REGS) {
16908 ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
16909 } else {
16910 ref = jit_FP(jit);
16911 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
16912 }
16913 if (may_throw
16914 && opline->opcode != ZEND_RETURN
16915 && opline->opcode != ZEND_RETURN_BY_REF) {
16916 zend_jit_check_exception(jit);
16917 }
16918
16919 while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
16920 trace++;
16921 }
16922
16923 if (!GCC_GLOBAL_REGS
16924 && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
16925 if (opline->opcode == ZEND_RETURN ||
16926 opline->opcode == ZEND_RETURN_BY_REF ||
16927 opline->opcode == ZEND_DO_UCALL ||
16928 opline->opcode == ZEND_DO_FCALL_BY_NAME ||
16929 opline->opcode == ZEND_DO_FCALL ||
16930 opline->opcode == ZEND_GENERATOR_CREATE) {
16931
16932 ir_ref addr = jit_EG(current_execute_data);
16933
16934 jit_STORE_FP(jit, ir_LOAD_A(addr));
16935 }
16936 }
16937
16938 if (zend_jit_trace_may_exit(op_array, opline)) {
16939 if (opline->opcode == ZEND_RETURN ||
16940 opline->opcode == ZEND_RETURN_BY_REF ||
16941 opline->opcode == ZEND_GENERATOR_CREATE) {
16942
16943 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16944 if (trace->op != ZEND_JIT_TRACE_END ||
16945 (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16946 trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16947 /* this check may be handled by the following OPLINE guard or jmp [IP] */
16948 ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
16949 jit_STUB_ADDR(jit, jit_stub_trace_halt));
16950 }
16951 } else if (GCC_GLOBAL_REGS) {
16952 ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16953 } else {
16954 ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16955 }
16956 } else if (opline->opcode == ZEND_GENERATOR_RETURN ||
16957 opline->opcode == ZEND_YIELD ||
16958 opline->opcode == ZEND_YIELD_FROM) {
16959 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
16960 ir_BEGIN(IR_UNUSED); /* unreachable block */
16961 }
16962 if (trace->op != ZEND_JIT_TRACE_END ||
16963 (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16964 trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16965
16966 const zend_op *next_opline = trace->opline;
16967 const zend_op *exit_opline = NULL;
16968 uint32_t exit_point;
16969 const void *exit_addr;
16970 uint32_t old_info = 0;
16971 uint32_t old_res_info = 0;
16972 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16973
16974 if (zend_is_smart_branch(opline)) {
16975 bool exit_if_true = 0;
16976 exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
16977 } else {
16978 switch (opline->opcode) {
16979 case ZEND_JMPZ:
16980 case ZEND_JMPNZ:
16981 case ZEND_JMPZ_EX:
16982 case ZEND_JMPNZ_EX:
16983 case ZEND_JMP_SET:
16984 case ZEND_COALESCE:
16985 case ZEND_JMP_NULL:
16986 case ZEND_FE_RESET_R:
16987 case ZEND_FE_RESET_RW:
16988 exit_opline = (trace->opline == opline + 1) ?
16989 OP_JMP_ADDR(opline, opline->op2) :
16990 opline + 1;
16991 break;
16992 case ZEND_FE_FETCH_R:
16993 case ZEND_FE_FETCH_RW:
16994 exit_opline = (trace->opline == opline + 1) ?
16995 ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
16996 opline + 1;
16997 break;
16998
16999 }
17000 }
17001
17002 switch (opline->opcode) {
17003 case ZEND_FE_FETCH_R:
17004 case ZEND_FE_FETCH_RW:
17005 if (opline->op2_type != IS_UNUSED) {
17006 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
17007 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
17008 }
17009 break;
17010 case ZEND_BIND_INIT_STATIC_OR_JMP:
17011 if (opline->op1_type == IS_CV) {
17012 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
17013 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
17014 }
17015 break;
17016 }
17017 if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17018 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
17019 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
17020 }
17021 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
17022 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17023
17024 if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17025 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
17026 }
17027 switch (opline->opcode) {
17028 case ZEND_FE_FETCH_R:
17029 case ZEND_FE_FETCH_RW:
17030 if (opline->op2_type != IS_UNUSED) {
17031 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
17032 }
17033 break;
17034 case ZEND_BIND_INIT_STATIC_OR_JMP:
17035 if (opline->op1_type == IS_CV) {
17036 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
17037 }
17038 break;
17039 }
17040
17041 if (!exit_addr) {
17042 return 0;
17043 }
17044 ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
17045 }
17046 }
17047
17048 zend_jit_set_last_valid_opline(jit, trace->opline);
17049
17050 return 1;
17051 }
17052
17053 static int zend_jit_deoptimizer_start(zend_jit_ctx *jit,
17054 zend_string *name,
17055 uint32_t trace_num,
17056 uint32_t exit_num)
17057 {
17058 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
17059
17060 jit->ctx.spill_base = ZREG_FP;
17061
17062 jit->op_array = NULL;
17063 jit->ssa = NULL;
17064 jit->name = zend_string_copy(name);
17065
17066 jit->ctx.flags |= IR_SKIP_PROLOGUE;
17067
17068 return 1;
17069 }
17070
17071 static int zend_jit_trace_start(zend_jit_ctx *jit,
17072 const zend_op_array *op_array,
17073 zend_ssa *ssa,
17074 zend_string *name,
17075 uint32_t trace_num,
17076 zend_jit_trace_info *parent,
17077 uint32_t exit_num)
17078 {
17079 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
17080
17081 jit->ctx.spill_base = ZREG_FP;
17082
17083 jit->op_array = NULL;
17084 jit->current_op_array = op_array;
17085 jit->ssa = ssa;
17086 jit->name = zend_string_copy(name);
17087
17088 if (!GCC_GLOBAL_REGS) {
17089 if (!parent) {
17090 ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
17091 jit_STORE_FP(jit, ref);
17092 jit->ctx.flags |= IR_FASTCALL_FUNC;
17093 }
17094 }
17095
17096 if (parent) {
17097 jit->ctx.flags |= IR_SKIP_PROLOGUE;
17098 }
17099
17100 if (parent) {
17101 int i;
17102 int parent_vars_count = parent->exit_info[exit_num].stack_size;
17103 zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
17104 parent->stack_map +
17105 parent->exit_info[exit_num].stack_offset;
17106
17107 /* prevent clobbering of registers used for deoptimization */
17108 for (i = 0; i < parent_vars_count; i++) {
17109 if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
17110 && STACK_REG(parent_stack, i) != ZREG_NONE) {
17111 int32_t reg = STACK_REG(parent_stack, i);
17112 ir_type type;
17113
17114 if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
17115 type = IR_ADDR;
17116 } else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
17117 type = IR_LONG;
17118 } else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
17119 type = IR_DOUBLE;
17120 } else {
17121 ZEND_UNREACHABLE();
17122 }
17123 if (ssa && ssa->vars[i].no_val) {
17124 /* pass */
17125 } else {
17126 ir_ref ref = ir_RLOAD(type, reg);
17127
17128 if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
17129 /* op3 is used as a flag that the value is already stored in memory.
17130 * In case the IR framework decides to spill the result of IR_LOAD,
17131 * it doesn't have to store the value once again.
17132 *
17133 * See: insn->op3 check in ir_emit_rload()
17134 */
17135 ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
17136 }
17137 }
17138 }
17139 }
17140 }
17141
17142 if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
17143 ZEND_ASSERT(parent->exit_info[exit_num].poly_func_reg >= 0 && parent->exit_info[exit_num].poly_this_reg >= 0);
17144 ir_RLOAD_A(parent->exit_info[exit_num].poly_func_reg);
17145 ir_RLOAD_A(parent->exit_info[exit_num].poly_this_reg);
17146 }
17147
17148 ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
17149
17150 return 1;
17151 }
17152
17153 static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
17154 {
17155 return ir_LOOP_BEGIN(ir_END());
17156 }
17157
17158 static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
17159 {
17160 int dst_var = phi->ssa_var;
17161 int src_var = phi->sources[0];
17162 ir_ref ref;
17163
17164 ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
17165 ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
17166
17167 ref = ir_PHI_2(
17168 (jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
17169 zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
17170
17171 src_var = phi->sources[1];
17172 ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
17173 jit->ra[src_var].flags |= ZREG_FORWARD;
17174
17175 zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
17176 }
17177
17178 static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
17179 {
17180 if (timeout_exit_addr) {
17181 zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17182 }
17183 ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
17184 ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
17185 return 1;
17186 }
17187
17188 static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
17189 {
17190 if (GCC_GLOBAL_REGS) {
17191 if (!original_handler) {
17192 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
17193 } else {
17194 ir_TAILCALL(IR_VOID, zend_jit_orig_opline_handler(jit));
17195 }
17196 } else {
17197 if (original_handler) {
17198 ir_ref ref;
17199 ir_ref addr = zend_jit_orig_opline_handler(jit);
17200
17201 #if defined(IR_TARGET_X86)
17202 addr = ir_CAST_FC_FUNC(addr);
17203 #endif
17204 ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
17205 if (opline &&
17206 (opline->opcode == ZEND_RETURN
17207 || opline->opcode == ZEND_RETURN_BY_REF
17208 || opline->opcode == ZEND_GENERATOR_RETURN
17209 || opline->opcode == ZEND_GENERATOR_CREATE
17210 || opline->opcode == ZEND_YIELD
17211 || opline->opcode == ZEND_YIELD_FROM)) {
17212 ir_RETURN(ref);
17213 return 1;
17214 }
17215 }
17216 ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
17217 }
17218 return 1;
17219 }
17220
17221 static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr)
17222 {
17223 return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
17224 }
17225
17226 static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
17227 {
17228 const void *link_addr;
17229
17230 /* Skip prologue. */
17231 ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
17232 link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
17233
17234 if (timeout_exit_addr) {
17235 zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17236 }
17237 ir_IJMP(ir_CONST_ADDR(link_addr));
17238
17239 return 1;
17240 }
17241
17242 static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, zend_jit_trace_rec *trace)
17243 {
17244 uint32_t op1_info, op2_info;
17245
17246 switch (opline->opcode) {
17247 case ZEND_SEND_VAR:
17248 case ZEND_SEND_VAL:
17249 case ZEND_SEND_VAL_EX:
17250 return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
17251 case ZEND_QM_ASSIGN:
17252 case ZEND_IS_SMALLER:
17253 case ZEND_IS_SMALLER_OR_EQUAL:
17254 case ZEND_IS_EQUAL:
17255 case ZEND_IS_NOT_EQUAL:
17256 case ZEND_IS_IDENTICAL:
17257 case ZEND_IS_NOT_IDENTICAL:
17258 case ZEND_CASE:
17259 return 1;
17260 case ZEND_RETURN:
17261 return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
17262 case ZEND_ASSIGN:
17263 return (opline->op1_type == IS_CV);
17264 case ZEND_ASSIGN_OP:
17265 if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
17266 return 0;
17267 }
17268 op1_info = OP1_INFO();
17269 op2_info = OP2_INFO();
17270 return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
17271 case ZEND_ADD:
17272 case ZEND_SUB:
17273 case ZEND_MUL:
17274 op1_info = OP1_INFO();
17275 op2_info = OP2_INFO();
17276 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
17277 return 0;
17278 }
17279 if (trace && trace->op1_type != IS_UNKNOWN) {
17280 op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17281 }
17282 if (trace && trace->op2_type != IS_UNKNOWN) {
17283 op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17284 }
17285 return !(op1_info & MAY_BE_UNDEF)
17286 && !(op2_info & MAY_BE_UNDEF)
17287 && (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
17288 && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
17289 case ZEND_BW_OR:
17290 case ZEND_BW_AND:
17291 case ZEND_BW_XOR:
17292 case ZEND_SL:
17293 case ZEND_SR:
17294 case ZEND_MOD:
17295 op1_info = OP1_INFO();
17296 op2_info = OP2_INFO();
17297 if (trace && trace->op1_type != IS_UNKNOWN) {
17298 op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17299 }
17300 if (trace && trace->op2_type != IS_UNKNOWN) {
17301 op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17302 }
17303 return (op1_info & MAY_BE_LONG)
17304 && (op2_info & MAY_BE_LONG);
17305 case ZEND_PRE_INC:
17306 case ZEND_PRE_DEC:
17307 case ZEND_POST_INC:
17308 case ZEND_POST_DEC:
17309 op1_info = OP1_INFO();
17310 return opline->op1_type == IS_CV
17311 && (op1_info & MAY_BE_LONG)
17312 && !(op1_info & MAY_BE_REF);
17313 case ZEND_STRLEN:
17314 op1_info = OP1_INFO();
17315 return (opline->op1_type & (IS_CV|IS_CONST))
17316 && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
17317 case ZEND_COUNT:
17318 op1_info = OP1_INFO();
17319 return (opline->op1_type & (IS_CV|IS_CONST))
17320 && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
17321 case ZEND_JMPZ:
17322 case ZEND_JMPNZ:
17323 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17324 if (!ssa->cfg.map) {
17325 return 0;
17326 }
17327 if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
17328 ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
17329 return 0;
17330 }
17331 }
17332 ZEND_FALLTHROUGH;
17333 case ZEND_BOOL:
17334 case ZEND_BOOL_NOT:
17335 case ZEND_JMPZ_EX:
17336 case ZEND_JMPNZ_EX:
17337 return 1;
17338 case ZEND_FETCH_CONSTANT:
17339 return 1;
17340 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
17341 if ((opline->extended_value & ZEND_ISEMPTY)) {
17342 return 0;
17343 }
17344 ZEND_FALLTHROUGH;
17345 case ZEND_FETCH_DIM_R:
17346 case ZEND_FETCH_DIM_IS:
17347 case ZEND_FETCH_LIST_R:
17348 op1_info = OP1_INFO();
17349 op2_info = OP2_INFO();
17350 if (trace
17351 && trace->op1_type != IS_UNKNOWN
17352 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17353 op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17354 }
17355 return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17356 (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17357 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17358 case ZEND_ASSIGN_DIM_OP:
17359 if (opline->result_type != IS_UNUSED) {
17360 return 0;
17361 }
17362 if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17363 return 0;
17364 }
17365 ZEND_FALLTHROUGH;
17366 case ZEND_ASSIGN_DIM:
17367 case ZEND_FETCH_DIM_W:
17368 case ZEND_FETCH_DIM_RW:
17369 case ZEND_FETCH_LIST_W:
17370 op1_info = OP1_INFO();
17371 op2_info = OP2_INFO();
17372 if (trace) {
17373 if (opline->op1_type == IS_CV) {
17374 if ((opline->opcode == ZEND_ASSIGN_DIM
17375 || opline->opcode == ZEND_ASSIGN_DIM_OP)
17376 && (opline+1)->op1_type == IS_CV
17377 && (opline+1)->op1.var == opline->op1.var) {
17378 /* skip $a[x] = $a; */
17379 return 0;
17380 }
17381 } else if (opline->op1_type == IS_VAR) {
17382 if (trace->op1_type == IS_UNKNOWN
17383 || !(trace->op1_type & IS_TRACE_INDIRECT)
17384 || opline->result_type != IS_UNUSED) {
17385 return 0;
17386 }
17387 }
17388 if (trace->op1_type != IS_UNKNOWN
17389 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17390 op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17391 }
17392 } else {
17393 if (opline->op1_type != IS_CV) {
17394 return 0;
17395 }
17396 }
17397 return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17398 (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17399 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17400 case ZEND_ASSIGN_OBJ_OP:
17401 if (opline->result_type != IS_UNUSED) {
17402 return 0;
17403 }
17404 if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17405 return 0;
17406 }
17407 ZEND_FALLTHROUGH;
17408 case ZEND_FETCH_OBJ_R:
17409 case ZEND_ASSIGN_OBJ:
17410 if (opline->op2_type != IS_CONST
17411 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
17412 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
17413 return 0;
17414 }
17415 op1_info = OP1_INFO();
17416 return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
17417 }
17418 return 0;
17419 }
17420
17421 static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
17422 {
17423 if (ssa->vars[var].no_val) {
17424 /* we don't need the value */
17425 return 0;
17426 }
17427
17428 if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
17429 /* Disable global register allocation,
17430 * register allocation for SSA variables connected through Phi functions
17431 */
17432 if (ssa->vars[var].definition_phi) {
17433 return 0;
17434 }
17435 if (ssa->vars[var].phi_use_chain) {
17436 zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
17437 do {
17438 if (!ssa->vars[phi->ssa_var].no_val) {
17439 return 0;
17440 }
17441 phi = zend_ssa_next_use_phi(ssa, var, phi);
17442 } while (phi);
17443 }
17444 }
17445
17446 if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
17447 ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
17448 /* bad type */
17449 return 0;
17450 }
17451
17452 return 1;
17453 }
17454
17455 static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17456 {
17457 if (!zend_jit_var_supports_reg(ssa, var)) {
17458 return 0;
17459 }
17460
17461 if (ssa->vars[var].definition >= 0) {
17462 uint32_t def = ssa->vars[var].definition;
17463 if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17464 return 0;
17465 }
17466 }
17467
17468 if (ssa->vars[var].use_chain >= 0) {
17469 int use = ssa->vars[var].use_chain;
17470
17471 do {
17472 if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17473 !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17474 return 0;
17475 }
17476 use = zend_ssa_next_use(ssa->ops, var, use);
17477 } while (use >= 0);
17478 }
17479
17480 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17481 int def_block, use_block, b, use, j;
17482 zend_basic_block *bb;
17483 zend_ssa_phi *p;
17484 bool ret = 1;
17485 zend_worklist worklist;
17486 ALLOCA_FLAG(use_heap)
17487
17488 /* Check if live range is split by ENTRY block */
17489 if (ssa->vars[var].definition >= 0) {
17490 def_block =ssa->cfg.map[ssa->vars[var].definition];
17491 } else {
17492 ZEND_ASSERT(ssa->vars[var].definition_phi);
17493 def_block = ssa->vars[var].definition_phi->block;
17494 }
17495
17496 ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
17497
17498 if (ssa->vars[var].use_chain >= 0) {
17499 use = ssa->vars[var].use_chain;
17500 do {
17501 use_block = ssa->cfg.map[use];
17502 if (use_block != def_block) {
17503 zend_worklist_push(&worklist, use_block);
17504 }
17505 use = zend_ssa_next_use(ssa->ops, var, use);
17506 } while (use >= 0);
17507 }
17508
17509 p = ssa->vars[var].phi_use_chain;
17510 while (p) {
17511 use_block = p->block;
17512 if (use_block != def_block) {
17513 bb = &ssa->cfg.blocks[use_block];
17514 for (j = 0; j < bb->predecessors_count; j++) {
17515 if (p->sources[j] == var) {
17516 use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
17517 if (use_block != def_block) {
17518 zend_worklist_push(&worklist, use_block);
17519 }
17520 }
17521 }
17522 }
17523 p = zend_ssa_next_use_phi(ssa, var, p);
17524 }
17525
17526 while (zend_worklist_len(&worklist) != 0) {
17527 b = zend_worklist_pop(&worklist);
17528 bb = &ssa->cfg.blocks[b];
17529 if (bb->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
17530 ret = 0;
17531 break;
17532 }
17533 for (j = 0; j < bb->predecessors_count; j++) {
17534 b = ssa->cfg.predecessors[bb->predecessor_offset + j];
17535 if (b != def_block) {
17536 zend_worklist_push(&worklist, b);
17537 }
17538 }
17539 }
17540
17541 ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
17542
17543 return ret;
17544 }
17545
17546 return 1;
17547 }
17548
17549 static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
17550 // JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
17551 ir_ref observer_handler;
17552 zend_function *fbc = ZEND_FLF_FUNC(opline);
17553 // Not need for runtime cache or generator checks here, we just need if_unobserved
17554 ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17555
17556 // Call zend_frameless_observed_call for the main logic.
17557 ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
17558
17559 ir_ref skip = ir_END();
17560 ir_IF_TRUE(if_unobserved);
17561 return skip;
17562 }
17563
17564 static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
17565 {
17566 jit_SET_EX_OPLINE(jit, opline);
17567
17568 void *function = ZEND_FLF_HANDLER(opline);
17569 zend_jit_addr res_addr = RES_ADDR();
17570 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17571 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17572
17573 ir_ref skip_observer = IR_UNUSED;
17574 if (ZEND_OBSERVER_ENABLED) {
17575 skip_observer = jit_frameless_observer(jit, opline);
17576 }
17577
17578 ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17579
17580 if (skip_observer != IR_UNUSED) {
17581 ir_MERGE_WITH(skip_observer);
17582 }
17583
17584 zend_jit_check_exception(jit);
17585 }
17586
17587 static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
17588 {
17589 jit_SET_EX_OPLINE(jit, opline);
17590
17591 /* Avoid dropping RC check in case op escapes. */
17592 if (op1_info & MAY_BE_RC1) {
17593 op1_info |= MAY_BE_RCN;
17594 }
17595
17596 void *function = ZEND_FLF_HANDLER(opline);
17597 zend_jit_addr res_addr = RES_ADDR();
17598 zend_jit_addr op1_addr = OP1_ADDR();
17599 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17600 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17601 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17602 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17603 op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17604 op1_info &= ~MAY_BE_UNDEF;
17605 op1_info |= MAY_BE_NULL;
17606 op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17607 }
17608 if (op1_info & MAY_BE_REF) {
17609 op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17610 }
17611
17612 ir_ref skip_observer = IR_UNUSED;
17613 if (ZEND_OBSERVER_ENABLED) {
17614 skip_observer = jit_frameless_observer(jit, opline);
17615 }
17616
17617 ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17618
17619 if (skip_observer != IR_UNUSED) {
17620 ir_MERGE_WITH(skip_observer);
17621 }
17622
17623 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17624 zend_jit_check_exception(jit);
17625 }
17626
17627 static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
17628 {
17629 jit_SET_EX_OPLINE(jit, opline);
17630
17631 /* Avoid dropping RC check in case op escapes. */
17632 if (op1_info & MAY_BE_RC1) {
17633 op1_info |= MAY_BE_RCN;
17634 }
17635 if (op2_info & MAY_BE_RC1) {
17636 op2_info |= MAY_BE_RCN;
17637 }
17638
17639 void *function = ZEND_FLF_HANDLER(opline);
17640 zend_jit_addr res_addr = RES_ADDR();
17641 zend_jit_addr op1_addr = OP1_ADDR();
17642 zend_jit_addr op2_addr = OP2_ADDR();
17643 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17644 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17645 ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17646 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17647 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17648 op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17649 op1_info &= ~MAY_BE_UNDEF;
17650 op1_info |= MAY_BE_NULL;
17651 op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17652 }
17653 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17654 op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17655 op2_info &= ~MAY_BE_UNDEF;
17656 op2_info |= MAY_BE_NULL;
17657 op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17658 }
17659 if (op1_info & MAY_BE_REF) {
17660 op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17661 }
17662 if (op2_info & MAY_BE_REF) {
17663 op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17664 }
17665
17666 ir_ref skip_observer = IR_UNUSED;
17667 if (ZEND_OBSERVER_ENABLED) {
17668 skip_observer = jit_frameless_observer(jit, opline);
17669 }
17670
17671 ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17672
17673 if (skip_observer != IR_UNUSED) {
17674 ir_MERGE_WITH(skip_observer);
17675 }
17676
17677 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17678 /* Set OP1 to UNDEF in case FREE_OP2() throws. */
17679 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17680 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17681 }
17682 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17683 zend_jit_check_exception(jit);
17684 }
17685
17686 static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, uint32_t op1_data_info)
17687 {
17688 jit_SET_EX_OPLINE(jit, opline);
17689
17690 /* Avoid dropping RC check in case op escapes. */
17691 if (op1_info & MAY_BE_RC1) {
17692 op1_info |= MAY_BE_RCN;
17693 }
17694 if (op2_info & MAY_BE_RC1) {
17695 op2_info |= MAY_BE_RCN;
17696 }
17697 if (op1_data_info & MAY_BE_RC1) {
17698 op1_data_info |= MAY_BE_RCN;
17699 }
17700
17701 void *function = ZEND_FLF_HANDLER(opline);
17702 uint8_t op_data_type = (opline + 1)->op1_type;
17703 zend_jit_addr res_addr = RES_ADDR();
17704 zend_jit_addr op1_addr = OP1_ADDR();
17705 zend_jit_addr op2_addr = OP2_ADDR();
17706 zend_jit_addr op3_addr = OP1_DATA_ADDR();
17707 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17708 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17709 ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17710 ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
17711 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17712 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17713 op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17714 op1_info &= ~MAY_BE_UNDEF;
17715 op1_info |= MAY_BE_NULL;
17716 op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17717 }
17718 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17719 op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17720 op2_info &= ~MAY_BE_UNDEF;
17721 op2_info |= MAY_BE_NULL;
17722 op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17723 }
17724 if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
17725 op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17726 op1_data_info &= ~MAY_BE_UNDEF;
17727 op1_data_info |= MAY_BE_NULL;
17728 op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
17729 }
17730 if (op1_info & MAY_BE_REF) {
17731 op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17732 }
17733 if (op2_info & MAY_BE_REF) {
17734 op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17735 }
17736 if (op1_data_info & MAY_BE_REF) {
17737 op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
17738 }
17739
17740 ir_ref skip_observer = IR_UNUSED;
17741 if (ZEND_OBSERVER_ENABLED) {
17742 skip_observer = jit_frameless_observer(jit, opline);
17743 }
17744
17745 ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17746
17747 if (skip_observer != IR_UNUSED) {
17748 ir_MERGE_WITH(skip_observer);
17749 }
17750
17751 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17752 /* Set OP1 to UNDEF in case FREE_OP2() throws. */
17753 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
17754 && ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
17755 || (op_data_type & (IS_VAR|IS_TMP_VAR)))) {
17756 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17757 }
17758 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17759 /* If OP1 is a TMP|VAR, we don't need to set OP2 to UNDEF on free because
17760 * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
17761 if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR))
17762 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17763 && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0) {
17764 jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
17765 }
17766 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
17767 zend_jit_check_exception(jit);
17768 }
17769
17770 /*
17771 * Local variables:
17772 * tab-width: 4
17773 * c-basic-offset: 4
17774 * indent-tabs-mode: t
17775 * End:
17776 */
17777