php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_jit_ir.c
Go to the documentation of this file.
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# define IR_SHADOW_ARGS 32
43# else
44# define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<12) | (1<<13) | (1<<14) | (1<<15)) /* all preserved registers */
45# endif
46#elif defined(IR_TARGET_AARCH64)
47# define IR_REG_SP 31 /* IR_REG_RSP */
48# define IR_REG_FP 29 /* IR_REG_X29 */
49# define ZREG_FP 27 /* IR_REG_X27 */
50# define ZREG_IP 28 /* IR_REG_X28 */
51# define ZREG_FIRST_FPR 32
52# define IR_REGSET_PRESERVED ((1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23) | \
53 (1<<24) | (1<<25) | (1<<26) | (1<<27) | (1<<28)) /* all preserved registers */
54#else
55# error "Unknown IR target"
56#endif
57
58#define ZREG_RX ZREG_IP
59
60#define OPTIMIZE_FOR_SIZE 0
61
62/* IR builder defines */
63#undef _ir_CTX
64#define _ir_CTX (&jit->ctx)
65
66#undef ir_CONST_ADDR
67#define ir_CONST_ADDR(_addr) jit_CONST_ADDR(jit, (uintptr_t)(_addr))
68#define ir_CONST_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), 0)
69#define ir_CONST_FC_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), IR_FASTCALL_FUNC)
70#define ir_CAST_FC_FUNC(_addr) ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
71 ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_I32))
72
73#define ir_CONST_FUNC_PROTO(_addr, _proto) \
74 jit_CONST_FUNC_PROTO(jit, (uintptr_t)(_addr), (_proto))
75
76#undef ir_ADD_OFFSET
77#define ir_ADD_OFFSET(_addr, _offset) \
78 jit_ADD_OFFSET(jit, _addr, _offset)
79
80#ifdef ZEND_ENABLE_ZVAL_LONG64
81# define IR_LONG IR_I64
82# define ir_CONST_LONG ir_CONST_I64
83# define ir_UNARY_OP_L ir_UNARY_OP_I64
84# define ir_BINARY_OP_L ir_BINARY_OP_I64
85# define ir_ADD_L ir_ADD_I64
86# define ir_SUB_L ir_SUB_I64
87# define ir_MUL_L ir_MUL_I64
88# define ir_DIV_L ir_DIV_I64
89# define ir_MOD_L ir_MOD_I64
90# define ir_NEG_L ir_NEG_I64
91# define ir_ABS_L ir_ABS_I64
92# define ir_SEXT_L ir_SEXT_I64
93# define ir_ZEXT_L ir_ZEXT_I64
94# define ir_TRUNC_L ir_TRUNC_I64
95# define ir_BITCAST_L ir_BITCAST_I64
96# define ir_FP2L ir_FP2I64
97# define ir_ADD_OV_L ir_ADD_OV_I64
98# define ir_SUB_OV_L ir_SUB_OV_I64
99# define ir_MUL_OV_L ir_MUL_OV_I64
100# define ir_NOT_L ir_NOT_I64
101# define ir_OR_L ir_OR_I64
102# define ir_AND_L ir_AND_I64
103# define ir_XOR_L ir_XOR_I64
104# define ir_SHL_L ir_SHL_I64
105# define ir_SHR_L ir_SHR_I64
106# define ir_SAR_L ir_SAR_I64
107# define ir_ROL_L ir_ROL_I64
108# define ir_ROR_L ir_ROR_I64
109# define ir_MIN_L ir_MIN_I64
110# define ir_MAX_L ir_MAX_I64
111# define ir_LOAD_L ir_LOAD_I64
112#else
113# define IR_LONG IR_I32
114# define ir_CONST_LONG ir_CONST_I32
115# define ir_UNARY_OP_L ir_UNARY_OP_I32
116# define ir_BINARY_OP_L ir_BINARY_OP_I32
117# define ir_ADD_L ir_ADD_I32
118# define ir_SUB_L ir_SUB_I32
119# define ir_MUL_L ir_MUL_I32
120# define ir_DIV_L ir_DIV_I32
121# define ir_MOD_L ir_MOD_I32
122# define ir_NEG_L ir_NEG_I32
123# define ir_ABS_L ir_ABS_I32
124# define ir_SEXT_L ir_SEXT_I32
125# define ir_ZEXT_L ir_ZEXT_I32
126# define ir_TRUNC_L ir_TRUNC_I32
127# define ir_BITCAST_L ir_BITCAST_I32
128# define ir_FP2L ir_FP2I32
129# define ir_ADD_OV_L ir_ADD_OV_I32
130# define ir_SUB_OV_L ir_SUB_OV_I32
131# define ir_MUL_OV_L ir_MUL_OV_I32
132# define ir_NOT_L ir_NOT_I32
133# define ir_OR_L ir_OR_I32
134# define ir_AND_L ir_AND_I32
135# define ir_XOR_L ir_XOR_I32
136# define ir_SHL_L ir_SHL_I32
137# define ir_SHR_L ir_SHR_I32
138# define ir_SAR_L ir_SAR_I32
139# define ir_ROL_L ir_ROL_I32
140# define ir_ROR_L ir_ROR_I32
141# define ir_MIN_L ir_MIN_I32
142# define ir_MAX_L ir_MAX_I32
143# define ir_LOAD_L ir_LOAD_I32
144#endif
145
146/* A helper structure to collect IT rers for the following use in (MERGE/PHI)_N */
147typedef struct _ir_refs {
148 uint32_t count;
149 uint32_t limit;
152
153#define ir_refs_size(_n) (offsetof(ir_refs, refs) + sizeof(ir_ref) * (_n))
154#define ir_refs_init(_name, _n) _name = alloca(ir_refs_size(_n)); \
155 do {_name->count = 0; _name->limit = (_n);} while (0)
156
157static void ir_refs_add(ir_refs *refs, ir_ref ref)
158{
159 ir_ref *ptr;
160
161 ZEND_ASSERT(refs->count < refs->limit);
162 ptr = refs->refs;
163 ptr[refs->count++] = ref;
164}
165
166static size_t zend_jit_trace_prologue_size = (size_t)-1;
167#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
168static uint32_t allowed_opt_flags = 0;
169static uint32_t default_mflags = 0;
170#endif
171static bool delayed_call_chain = 0; // TODO: remove this var (use jit->delayed_call_level) ???
172
173#ifdef ZTS
174# ifdef _WIN32
175extern uint32_t _tls_index;
176extern char *_tls_start;
177extern char *_tls_end;
178# endif
179
180static size_t tsrm_ls_cache_tcb_offset = 0;
181static size_t tsrm_tls_index = 0;
182static size_t tsrm_tls_offset = 0;
183
184# define EG_TLS_OFFSET(field) \
185 (executor_globals_offset + offsetof(zend_executor_globals, field))
186
187# define CG_TLS_OFFSET(field) \
188 (compiler_globals_offset + offsetof(zend_compiler_globals, field))
189
190# define jit_EG(_field) \
191 ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
192
193# define jit_CG(_field) \
194 ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
195
196#else
197
198# define jit_EG(_field) \
199 ir_CONST_ADDR(&EG(_field))
200
201# define jit_CG(_field) \
202 ir_CONST_ADDR(&CG(_field))
203
204#endif
205
206#define jit_CALL(_call, _field) \
207 ir_ADD_OFFSET(_call, offsetof(zend_execute_data, _field))
208
209#define jit_EX(_field) \
210 jit_CALL(jit_FP(jit), _field)
211
212#define jit_RX(_field) \
213 jit_CALL(jit_IP(jit), _field)
214
215#define JIT_STUBS(_) \
216 _(exception_handler, IR_SKIP_PROLOGUE) \
217 _(exception_handler_undef, IR_SKIP_PROLOGUE) \
218 _(exception_handler_free_op2, IR_SKIP_PROLOGUE) \
219 _(exception_handler_free_op1_op2, IR_SKIP_PROLOGUE) \
220 _(interrupt_handler, IR_SKIP_PROLOGUE) \
221 _(leave_function_handler, IR_SKIP_PROLOGUE) \
222 _(negative_shift, IR_SKIP_PROLOGUE) \
223 _(mod_by_zero, IR_SKIP_PROLOGUE) \
224 _(invalid_this, IR_SKIP_PROLOGUE) \
225 _(undefined_function, IR_SKIP_PROLOGUE) \
226 _(throw_cannot_pass_by_ref, IR_SKIP_PROLOGUE) \
227 _(icall_throw, IR_SKIP_PROLOGUE) \
228 _(leave_throw, IR_SKIP_PROLOGUE) \
229 _(hybrid_runtime_jit, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
230 _(hybrid_profile_jit, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
231 _(hybrid_func_hot_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
232 _(hybrid_loop_hot_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
233 _(hybrid_func_trace_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
234 _(hybrid_ret_trace_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
235 _(hybrid_loop_trace_counter, IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
236 _(trace_halt, IR_SKIP_PROLOGUE) \
237 _(trace_escape, IR_SKIP_PROLOGUE) \
238 _(trace_exit, IR_SKIP_PROLOGUE) \
239 _(undefined_offset, IR_FUNCTION | IR_FASTCALL_FUNC) \
240 _(undefined_key, IR_FUNCTION | IR_FASTCALL_FUNC) \
241 _(cannot_add_element, IR_FUNCTION | IR_FASTCALL_FUNC) \
242 _(assign_const, IR_FUNCTION | IR_FASTCALL_FUNC) \
243 _(assign_tmp, IR_FUNCTION | IR_FASTCALL_FUNC) \
244 _(assign_var, IR_FUNCTION | IR_FASTCALL_FUNC) \
245 _(assign_cv_noref, IR_FUNCTION | IR_FASTCALL_FUNC) \
246 _(assign_cv, IR_FUNCTION | IR_FASTCALL_FUNC) \
247 _(new_array, IR_FUNCTION | IR_FASTCALL_FUNC) \
248
249#define JIT_STUB_ID(name, flags) \
250 jit_stub_ ## name,
251
252#define JIT_STUB_FORWARD(name, flags) \
253 static int zend_jit_ ## name ## _stub(zend_jit_ctx *jit);
254
255#define JIT_STUB(name, flags) \
256 {JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, flags},
257
262
267
268typedef struct _zend_jit_ctx {
275 int b; /* current basic block number or -1 */
276#ifdef ZTS
277 ir_ref tls;
278#endif
280 ir_ref poly_func_ref; /* restored from parent trace snapshot */
281 ir_ref poly_this_ref; /* restored from parent trace snapshot */
288 ir_ref *bb_start_ref; /* PHP BB -> IR ref mapping */
289 ir_ref *bb_predecessors; /* PHP BB -> index in bb_edges -> IR refs of predessors */
299
300typedef int8_t zend_reg;
301
303#if defined(IR_TARGET_X64)
304 uint64_t gpr[16]; /* general purpose integer register */
305 double fpr[16]; /* floating point registers */
306#elif defined(IR_TARGET_X86)
307 uint32_t gpr[8]; /* general purpose integer register */
308 double fpr[8]; /* floating point registers */
309#elif defined (IR_TARGET_AARCH64)
310 uint64_t gpr[32]; /* general purpose integer register */
311 double fpr[32]; /* floating point registers */
312#else
313# error "Unknown IR target"
314#endif
316
317/* Keep 32 exit points in a single code block */
318#define ZEND_JIT_EXIT_POINTS_SPACING 4 // push byte + short jmp = bytes
319#define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
320
321static uint32_t zend_jit_exit_point_by_addr(const void *addr);
322int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
323
324static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
325 const zend_op *opline,
326 zend_jit_addr var_use_addr,
327 zend_jit_addr var_addr,
328 uint32_t var_info,
329 uint32_t var_def_info,
330 uint8_t val_type,
331 zend_jit_addr val_addr,
332 uint32_t val_info,
333 zend_jit_addr res_addr,
334 zend_jit_addr ref_addr,
335 bool check_exception);
336
337typedef struct _zend_jit_stub {
338 const char *name;
339 int (*stub)(zend_jit_ctx *jit);
340 uint32_t flags;
342
344
345static const zend_jit_stub zend_jit_stubs[] = {
347};
348
349#if defined(_WIN32) || defined(IR_TARGET_AARCH64)
350/* We keep addresses in SHM to share them between sepaeate processes (on Windows) or to support veneers (on AArch64) */
351static void** zend_jit_stub_handlers = NULL;
352#else
353static void* zend_jit_stub_handlers[sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])];
354#endif
355
356#if defined(IR_TARGET_AARCH64)
357
358# ifdef __FreeBSD__
359/* https://github.com/freebsd/freebsd-src/blob/c52ca7dd09066648b1cc40f758289404d68ab886/libexec/rtld-elf/aarch64/reloc.c#L180-L184 */
360typedef struct TLSDescriptor {
361 void* thunk;
362 int index;
363 size_t offset;
364} TLSDescriptor;
365# endif
366
367#define IR_HAS_VENEERS (1U<<31) /* IR_RESERVED_FLAG_1 */
368
369static const void *zend_jit_get_veneer(ir_ctx *ctx, const void *addr)
370{
371 int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
372
373 for (i = 0; i < count; i++) {
374 if (zend_jit_stub_handlers[i] == addr) {
375 return zend_jit_stub_handlers[count + i];
376 }
377 }
378
379 if (((zend_jit_ctx*)ctx)->trace
380 && (void*)addr >= dasm_buf && (void*)addr < dasm_end) {
381 uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
382
383 if (exit_point != (uint32_t)-1) {
384 zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
385
386 ZEND_ASSERT(exit_point < t->exit_count);
387 return (const void*)((char*)ctx->deoptimization_exits_base + (exit_point * 4));
388 }
389 }
390
391 return NULL;
392}
393
394static bool zend_jit_set_veneer(ir_ctx *ctx, const void *addr, const void *veneer)
395{
396 int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
397 uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
398
399 if (exit_point != (uint32_t)-1) {
400 return 1;
401 }
402 for (i = 0; i < count; i++) {
403 if (zend_jit_stub_handlers[i] == addr) {
404 const void **ptr = (const void**)&zend_jit_stub_handlers[count + i];
405 *ptr = veneer;
406 ctx->flags2 |= IR_HAS_VENEERS;
407#ifdef HAVE_CAPSTONE
408 int64_t offset;
410 const char *name = ir_disasm_find_symbol((uint64_t)(uintptr_t)addr, &offset);
411
412 if (name && !offset) {
413 if (strstr(name, "@veneer") == NULL) {
414 char *new_name;
415
416 zend_spprintf(&new_name, 0, "%s@veneer", name);
417 ir_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
418 efree(new_name);
419 } else {
420 ir_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
421 }
422 }
423 }
424#endif
425 return 1;
426 }
427 }
428
429 return 0;
430}
431
432static void zend_jit_commit_veneers(void)
433{
434 int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
435
436 for (i = 0; i < count; i++) {
437 if (zend_jit_stub_handlers[count + i]) {
438 zend_jit_stub_handlers[i] = zend_jit_stub_handlers[count + i];
439 zend_jit_stub_handlers[count + i] = NULL;
440 }
441 }
442}
443#endif
444
445static bool zend_jit_prefer_const_addr_load(zend_jit_ctx *jit, uintptr_t addr)
446{
447#if defined(IR_TARGET_X86)
448 return 0; /* always use immediate value */
449#elif defined(IR_TARGET_X64)
450 return addr > 0xffffffff; /* prefer loading long constant from memery */
451#elif defined(IR_TARGET_AARCH64)
452 return addr > 0xffff;
453#else
454# error "Unknown IR target"
455#endif
456}
457
458static const char* zend_reg_name(int8_t reg)
459{
460 return ir_reg_name(reg, ir_reg_is_int(reg) ? IR_LONG : IR_DOUBLE);
461}
462
463/* IR helpers */
464
465#ifdef ZTS
466static ir_ref jit_TLS(zend_jit_ctx *jit)
467{
468 ZEND_ASSERT(jit->ctx.control);
469 if (jit->tls) {
470 /* Emit "TLS" once for basic block */
471 ir_insn *insn;
472 ir_ref ref = jit->ctx.control;
473
474 while (1) {
475 if (ref == jit->tls) {
476 return jit->tls;
477 }
478 insn = &jit->ctx.ir_base[ref];
479 if (insn->op >= IR_START || insn->op == IR_CALL) {
480 break;
481 }
482 ref = insn->op1;
483 }
484 }
485 jit->tls = ir_TLS(
486 tsrm_ls_cache_tcb_offset ? tsrm_ls_cache_tcb_offset : tsrm_tls_index,
487 tsrm_ls_cache_tcb_offset ? IR_NULL : tsrm_tls_offset);
488 return jit->tls;
489}
490#endif
491
492static ir_ref jit_CONST_ADDR(zend_jit_ctx *jit, uintptr_t addr)
493{
494 ir_ref ref;
495 zval *zv;
496
497 if (addr == 0) {
498 return IR_NULL;
499 }
501 if (Z_TYPE_P(zv) == IS_LONG) {
502 ref = Z_LVAL_P(zv);
503 ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_ADDR, IR_ADDR));
504 } else {
505 ref = ir_unique_const_addr(&jit->ctx, addr);
506 ZVAL_LONG(zv, ref);
507 }
508 return ref;
509}
510
511static ir_ref jit_CONST_FUNC_PROTO(zend_jit_ctx *jit, uintptr_t addr, ir_ref proto)
512{
513 ir_ref ref;
514 ir_insn *insn;
515 zval *zv;
516
517 ZEND_ASSERT(addr != 0);
519 if (Z_TYPE_P(zv) == IS_LONG) {
520 ref = Z_LVAL_P(zv);
521 ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_FUNC_ADDR, IR_ADDR) && jit->ctx.ir_base[ref].proto == proto);
522 } else {
523 ref = ir_unique_const_addr(&jit->ctx, addr);
524 insn = &jit->ctx.ir_base[ref];
525 insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
526 insn->proto = proto;
527 ZVAL_LONG(zv, ref);
528 }
529 return ref;
530}
531
532static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags)
533{
534#if defined(IR_TARGET_X86)
535 /* TODO: dummy prototype (only flags matter) ??? */
536 ir_ref proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
537#else
538 ir_ref proto = 0;
539#endif
540
541 return jit_CONST_FUNC_PROTO(jit, addr, proto);
542}
543
544static ir_ref jit_ADD_OFFSET(zend_jit_ctx *jit, ir_ref addr, uintptr_t offset)
545{
546 if (offset) {
548 }
549 return addr;
550}
551
552static ir_ref jit_EG_exception(zend_jit_ctx *jit)
553{
554#ifdef ZTS
555 return jit_EG(exception);
556#else
557 ir_ref ref = jit->eg_exception_addr;
558
559 if (UNEXPECTED(!ref)) {
560 ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)&EG(exception));
561 jit->eg_exception_addr = ref;
562 }
563 return ref;
564#endif
565}
566
567static ir_ref jit_STUB_ADDR(zend_jit_ctx *jit, jit_stub_id id)
568{
569 ir_ref ref = jit->stub_addr[id];
570
571 if (UNEXPECTED(!ref)) {
572 ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
573 jit->stub_addr[id] = ref;
574 }
575 return ref;
576}
577
578static ir_ref jit_STUB_FUNC_ADDR(zend_jit_ctx *jit, jit_stub_id id, uint16_t flags)
579{
580 ir_ref ref = jit->stub_addr[id];
581 ir_insn *insn;
582
583 if (UNEXPECTED(!ref)) {
584 ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
585 insn = &jit->ctx.ir_base[ref];
586 insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
587#if defined(IR_TARGET_X86)
588 /* TODO: dummy prototype (only flags matter) ??? */
589 insn->proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
590#else
591 insn->proto = 0;
592#endif
593 jit->stub_addr[id] = ref;
594 }
595 return ref;
596}
597
598static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
599{
600 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
601 const void *ptr = (const void*)jit->ctx.ir_base[addr].val.addr;
602 const zend_op_array *op_array = &JIT_G(current_frame)->func->op_array;
603 uint32_t stack_size = op_array->last_var + op_array->T;
604
605 if (ptr == zend_jit_stub_handlers[jit_stub_exception_handler]
606 || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_undef]
607 || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op1_op2]
608 || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op2]
609 || ptr == zend_jit_stub_handlers[jit_stub_interrupt_handler]
610 || ptr == zend_jit_stub_handlers[jit_stub_leave_function_handler]
611 || ptr == zend_jit_stub_handlers[jit_stub_negative_shift]
612 || ptr == zend_jit_stub_handlers[jit_stub_mod_by_zero]
613 || ptr == zend_jit_stub_handlers[jit_stub_invalid_this]
614 || ptr == zend_jit_stub_handlers[jit_stub_undefined_function]
615 || ptr == zend_jit_stub_handlers[jit_stub_throw_cannot_pass_by_ref]
616 || ptr == zend_jit_stub_handlers[jit_stub_icall_throw]
617 || ptr == zend_jit_stub_handlers[jit_stub_leave_throw]
618 || ptr == zend_jit_stub_handlers[jit_stub_trace_halt]
619 || ptr == zend_jit_stub_handlers[jit_stub_trace_escape]) {
620 /* This is a GUARD that trigger exit through a stub code (without deoptimization) */
621 return;
622 }
623
624 /* Check if we need snapshot entries for polymorphic method call */
625 zend_jit_trace_info *t = jit->trace;
626 uint32_t exit_point = 0, n = 0;
627
628 if (addr < 0) {
629 /* addr is not always the address of the *last* exit point,
630 * so we can not optimize this to 'exit_point = t->exit_count-1' */
631 exit_point = zend_jit_exit_point_by_addr(ptr);
632 ZEND_ASSERT(exit_point != -1);
633 if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
634 n = 2;
635 }
636 }
637
638 if (stack_size || n) {
639 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
640 uint32_t snapshot_size, i;
641
642 snapshot_size = stack_size;
643 while (snapshot_size > 0) {
644 ir_ref ref = STACK_REF(stack, snapshot_size - 1);
645
646 if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, snapshot_size - 1) & (/*ZREG_LOAD|*/ZREG_STORE))) {
647 snapshot_size--;
648 } else {
649 break;
650 }
651 }
652 if (snapshot_size || n) {
653 ir_ref snapshot;
654
655 snapshot = ir_SNAPSHOT(snapshot_size + n);
656 for (i = 0; i < snapshot_size; i++) {
657 ir_ref ref = STACK_REF(stack, i);
658
659 if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, i) & (/*ZREG_LOAD|*/ZREG_STORE))) {
660 ref = IR_UNUSED;
661 }
662 ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
663 }
664 if (n) {
665 ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func.ref);
666 ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this.ref);
667 }
668 }
669 }
670 }
671}
672
673static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
674{
675 int32_t i;
676
677 for (i = 0; i < t->consts_count; i++) {
678 if (t->constants[i].i == val) {
679 return i;
680 }
681 }
682 ZEND_ASSERT(i < 0x7fffffff);
683 t->consts_count = i + 1;
684 t->constants = erealloc(t->constants, (i + 1) * sizeof(zend_jit_exit_const));
685 t->constants[i].i = val;
686 return i;
687}
688
689uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
690{
691 uint32_t stack_size, stack_offset;
692 uint32_t new_exit_point = t->exit_count;
693
694 if (new_exit_point >= ZEND_JIT_TRACE_MAX_EXITS) {
695 ctx->status = -ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
696 return exit_point;
697 }
698
699 t->exit_count++;
700 memcpy(&t->exit_info[new_exit_point], &t->exit_info[exit_point], sizeof(zend_jit_trace_exit_info));
701 stack_size = t->exit_info[new_exit_point].stack_size;
702 if (stack_size != 0) {
703 stack_offset = t->stack_map_size;
704 t->stack_map_size += stack_size;
705 // TODO: reduce number of reallocations ???
707 memcpy(t->stack_map + stack_offset, t->stack_map + t->exit_info[new_exit_point].stack_offset, stack_size * sizeof(zend_jit_trace_stack));
708 t->exit_info[new_exit_point].stack_offset = stack_offset;
709 }
710 t->exit_info[new_exit_point].flags &= ~ZEND_JIT_EXIT_FIXED;
711
712 return new_exit_point;
713}
714
715static void zend_jit_resolve_ref_snapshot(zend_jit_ref_snapshot *dest, ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, int op)
716{
717 int8_t *reg_ops = ctx->regs[snapshot_ref];
718 ZEND_ASSERT(reg_ops[op] != ZREG_NONE);
719
720 int8_t reg = reg_ops[op];
721 int32_t offset;
722
723 if (IR_REG_SPILLED(reg)) {
724 reg = ((ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP) | IR_REG_SPILL_LOAD;
725 offset = ir_get_spill_slot_offset(ctx, ir_insn_op(snapshot, op));
726 } else {
727 offset = 0;
728 }
729
730 dest->reg = reg;
731 dest->offset = offset;
732}
733
734static bool zend_jit_ref_snapshot_equals(const zend_jit_ref_snapshot *a, const zend_jit_ref_snapshot *b)
735{
736 return a->reg == b->reg
737 && (!IR_REG_SPILLED(a->reg) || (a->offset == b->offset));
738}
739
740void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
741{
742 zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
743 uint32_t exit_point, exit_flags;
744 ir_ref n = snapshot->inputs_count;
745 ir_ref i;
746
747 exit_point = zend_jit_exit_point_by_addr(addr);
748 ZEND_ASSERT(exit_point < t->exit_count);
749 exit_flags = t->exit_info[exit_point].flags;
750
751 if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
753 zend_jit_resolve_ref_snapshot(&func, ctx, snapshot_ref, snapshot, n - 1);
754 zend_jit_resolve_ref_snapshot(&this, ctx, snapshot_ref, snapshot, n);
755
756 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
757 && (!zend_jit_ref_snapshot_equals(&t->exit_info[exit_point].poly_func, &func)
758 || !zend_jit_ref_snapshot_equals(&t->exit_info[exit_point].poly_this, &this))) {
759 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
760 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
761 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
762 }
763 t->exit_info[exit_point].poly_func = func;
764 t->exit_info[exit_point].poly_this = this;
765 n -= 2;
766 }
767
768 for (i = 2; i <= n; i++) {
769 ir_ref ref = ir_insn_op(snapshot, i);
770
771 if (ref) {
772 int8_t *reg_ops = ctx->regs[snapshot_ref];
773 int8_t reg = reg_ops[i];
774 ir_ref var = i - 2;
775
776 ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
777 if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
778 ZEND_ASSERT(reg != ZREG_NONE);
779 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
780 && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
781 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
782 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
783 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
784 }
785 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
786 } else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
787 ZEND_ASSERT(t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_LONG ||
788 t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_DOUBLE);
789
790 if (ref > 0) {
791 if (reg != ZREG_NONE) {
792 if (reg & IR_REG_SPILL_LOAD) {
794 /* spill slot on a CPU stack */
795 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
796 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].ref != ref
797 || t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
798 || !(t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ZREG_SPILL_SLOT))) {
799 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
800 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
801 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
802 }
803 t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
804 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
805 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
806 } else if (reg & IR_REG_SPILL_SPECIAL) {
807 /* spill slot on a VM stack */
808 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
809 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
810 || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
811 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
812 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
813 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
814 }
815 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
816 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
817 } else {
818 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
819 && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
820 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
821 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
822 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
823 }
824 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
825 }
826 } else {
827 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
828 && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
829 || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
830 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
831 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
832 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
833 }
834 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
835 }
836 } else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
837 int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
838 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
839 t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
840 }
841 }
842 }
843 }
844 t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
845 return addr;
846}
847
848static void jit_SIDE_EXIT(zend_jit_ctx *jit, ir_ref addr)
849{
850 jit_SNAPSHOT(jit, addr);
851 ir_IJMP(addr);
852}
853
854/* PHP JIT helpers */
855
856static ir_ref jit_EMALLOC(zend_jit_ctx *jit, size_t size, const zend_op_array *op_array, const zend_op *opline)
857{
858#if ZEND_DEBUG
859 return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_emalloc),
861 op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
862 ir_CONST_U32(opline ? opline->lineno : 0),
863 IR_NULL,
864 ir_CONST_U32(0));
865#elif defined(HAVE_BUILTIN_CONSTANT_P)
866 if (size > 24 && size <= 32) {
867 return ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_emalloc_32));
868 } else {
870 }
871#else
873#endif
874}
875
876static ir_ref jit_EFREE(zend_jit_ctx *jit, ir_ref ptr, size_t size, const zend_op_array *op_array, const zend_op *opline)
877{
878#if ZEND_DEBUG
879 return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_efree),
880 ptr,
881 op_array && op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
882 ir_CONST_U32(opline ? opline->lineno : 0),
883 IR_NULL,
884 ir_CONST_U32(0));
885#elif defined(HAVE_BUILTIN_CONSTANT_P)
886 if (size > 24 && size <= 32) {
887 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree_32), ptr);
888 } else {
889 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
890 }
891#else
892 return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
893#endif
894}
895
896static ir_ref jit_FP(zend_jit_ctx *jit)
897{
898 ZEND_ASSERT(jit->ctx.control);
899 if (jit->fp == IR_UNUSED) {
900 /* Emit "RLOAD FP" once for basic block */
901 jit->fp = ir_RLOAD_A(ZREG_FP);
902 } else {
903 ir_insn *insn;
904 ir_ref ref = jit->ctx.control;
905
906 while (1) {
907 if (ref == jit->fp) {
908 break;
909 }
910 insn = &jit->ctx.ir_base[ref];
911 if (insn->op >= IR_START || insn->op == IR_CALL) {
912 jit->fp = ir_RLOAD_A(ZREG_FP);
913 break;
914 }
915 ref = insn->op1;
916 }
917 }
918 return jit->fp;
919}
920
921static void jit_STORE_FP(zend_jit_ctx *jit, ir_ref ref)
922{
923 ir_RSTORE(ZREG_FP, ref);
924 jit->fp = IR_UNUSED;
925}
926
927static ir_ref jit_IP(zend_jit_ctx *jit)
928{
929 return ir_RLOAD_A(ZREG_IP);
930}
931
932static void jit_STORE_IP(zend_jit_ctx *jit, ir_ref ref)
933{
934 ir_RSTORE(ZREG_IP, ref);
935}
936
937static ir_ref jit_IP32(zend_jit_ctx *jit)
938{
939 return ir_RLOAD_U32(ZREG_IP);
940}
941
942static void jit_LOAD_IP(zend_jit_ctx *jit, ir_ref ref)
943{
944 if (GCC_GLOBAL_REGS) {
945 jit_STORE_IP(jit, ref);
946 } else {
947 ir_STORE(jit_EX(opline), ref);
948 }
949}
950
951static void jit_LOAD_IP_ADDR(zend_jit_ctx *jit, const zend_op *target)
952{
953 jit_LOAD_IP(jit, ir_CONST_ADDR(target));
954}
955
956static void zend_jit_track_last_valid_opline(zend_jit_ctx *jit)
957{
958 jit->use_last_valid_opline = 0;
960}
961
962static void zend_jit_use_last_valid_opline(zend_jit_ctx *jit)
963{
964 if (jit->track_last_valid_opline) {
965 jit->use_last_valid_opline = 1;
967 }
968}
969
970static bool zend_jit_trace_uses_initial_ip(zend_jit_ctx *jit)
971{
972 return jit->use_last_valid_opline;
973}
974
975static void zend_jit_set_last_valid_opline(zend_jit_ctx *jit, const zend_op *opline)
976{
977 if (!jit->reuse_ip) {
979 jit->last_valid_opline = opline;
980 }
981}
982
983static void zend_jit_reset_last_valid_opline(zend_jit_ctx *jit)
984{
986 jit->last_valid_opline = NULL;
987}
988
989static void zend_jit_start_reuse_ip(zend_jit_ctx *jit)
990{
991 zend_jit_reset_last_valid_opline(jit);
992 jit->reuse_ip = 1;
993}
994
995static int zend_jit_reuse_ip(zend_jit_ctx *jit)
996{
997 if (!jit->reuse_ip) {
998 zend_jit_start_reuse_ip(jit);
999 // RX = EX(call);
1000 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
1001 }
1002 return 1;
1003}
1004
1005static void zend_jit_stop_reuse_ip(zend_jit_ctx *jit)
1006{
1007 jit->reuse_ip = 0;
1008}
1009
1010static int zend_jit_save_call_chain(zend_jit_ctx *jit, uint32_t call_level)
1011{
1012 ir_ref rx, call;
1013
1014 if (call_level == 1) {
1015 // JIT: call = NULL;
1016 call = IR_NULL;
1017 } else {
1018 // JIT: call = EX(call);
1020 }
1021
1022 rx = jit_IP(jit);
1023
1024 // JIT: call->prev_execute_data = call;
1026
1027 // JIT: EX(call) = call;
1028 ir_STORE(jit_EX(call), rx);
1029
1030 jit->delayed_call_level = 0;
1031 delayed_call_chain = 0;
1032
1033 return 1;
1034}
1035
1036static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target)
1037{
1038 ir_ref ref;
1040
1041 if (jit->delayed_call_level) {
1042 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
1043 return 0;
1044 }
1045 }
1046
1047 if (jit->last_valid_opline) {
1048 zend_jit_use_last_valid_opline(jit);
1049 if (jit->last_valid_opline != target) {
1050 if (GCC_GLOBAL_REGS) {
1051 ref = jit_IP(jit);
1052 } else {
1053 addr = jit_EX(opline);
1054 ref = ir_LOAD_A(addr);
1055 }
1056 if (target > jit->last_valid_opline) {
1057 ref = ir_ADD_OFFSET(ref, (uintptr_t)target - (uintptr_t)jit->last_valid_opline);
1058 } else {
1059 ref = ir_SUB_A(ref, ir_CONST_ADDR((uintptr_t)jit->last_valid_opline - (uintptr_t)target));
1060 }
1061 if (GCC_GLOBAL_REGS) {
1062 jit_STORE_IP(jit, ref);
1063 } else {
1064 ir_STORE(addr, ref);
1065 }
1066 }
1067 } else {
1068 if (GCC_GLOBAL_REGS) {
1069 jit_STORE_IP(jit, ir_CONST_ADDR(target));
1070 } else {
1071 ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1072 }
1073 }
1074 jit->reuse_ip = 0;
1075 zend_jit_set_last_valid_opline(jit, target);
1076 return 1;
1077}
1078
1079static int zend_jit_set_ip_ex(zend_jit_ctx *jit, const zend_op *target, bool set_ip_reg)
1080{
1081 if (!GCC_GLOBAL_REGS && set_ip_reg && !jit->last_valid_opline) {
1082 /* Optimization to avoid duplicate constant load */
1083 ir_STORE(jit_EX(opline), ir_HARD_COPY_A(ir_CONST_ADDR(target)));
1084 return 1;
1085 }
1086 return zend_jit_set_ip(jit, target);
1087}
1088
1089static void jit_SET_EX_OPLINE(zend_jit_ctx *jit, const zend_op *target)
1090{
1091 if (jit->last_valid_opline == target) {
1092 zend_jit_use_last_valid_opline(jit);
1093 if (GCC_GLOBAL_REGS) {
1094 // EX(opline) = opline
1095 ir_STORE(jit_EX(opline), jit_IP(jit));
1096 }
1097 } else {
1098 ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1099 if (!GCC_GLOBAL_REGS) {
1100 zend_jit_reset_last_valid_opline(jit);
1101 }
1102 }
1103}
1104
1105static ir_ref jit_ZVAL_ADDR(zend_jit_ctx *jit, zend_jit_addr addr)
1106{
1107 if (Z_MODE(addr) == IS_MEM_ZVAL) {
1108 ir_ref reg;
1109
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 {
1116 }
1117 return ir_ADD_OFFSET(reg, Z_OFFSET(addr));
1118 } else if (Z_MODE(addr) == IS_REF_ZVAL) {
1119 return Z_IR_REF(addr);
1120 } else {
1122 return ir_CONST_ADDR(Z_ZV(addr));
1123 }
1124}
1125
1126static ir_ref jit_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref)
1127{
1128 return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type)));
1129}
1130
1131static ir_ref jit_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr)
1132{
1133 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1134 return ir_CONST_U8(Z_TYPE_P(Z_ZV(addr)));
1135 } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1136 ir_ref reg;
1137
1139 if (Z_REG(addr) == ZREG_FP) {
1140 reg = jit_FP(jit);
1141 } else if (Z_REG(addr) == ZREG_RX) {
1142 reg = jit_IP(jit);
1143 } else {
1145 }
1146 return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type)));
1147 } else {
1148 return jit_Z_TYPE_ref(jit, jit_ZVAL_ADDR(jit, addr));
1149 }
1150}
1151
1152static ir_ref jit_Z_TYPE_FLAGS_ref(zend_jit_ctx *jit, ir_ref ref)
1153{
1154 return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type_flags)));
1155}
1156
1157static ir_ref jit_Z_TYPE_FLAGS(zend_jit_ctx *jit, zend_jit_addr addr)
1158{
1159 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1161 } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1162 ir_ref reg;
1163
1165 if (Z_REG(addr) == ZREG_FP) {
1166 reg = jit_FP(jit);
1167 } else if (Z_REG(addr) == ZREG_RX) {
1168 reg = jit_IP(jit);
1169 } else {
1171 }
1172 return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type_flags)));
1173 } else {
1174 return jit_Z_TYPE_FLAGS_ref(jit, jit_ZVAL_ADDR(jit, addr));
1175 }
1176}
1177
1178static ir_ref jit_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref)
1179{
1180 return ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)));
1181}
1182
1183static ir_ref jit_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr)
1184{
1185 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1187 } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1188 ir_ref reg;
1189
1191 if (Z_REG(addr) == ZREG_FP) {
1192 reg = jit_FP(jit);
1193 } else if (Z_REG(addr) == ZREG_RX) {
1194 reg = jit_IP(jit);
1195 } else {
1197 }
1198 return ir_LOAD_U32(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)));
1199 } else {
1200 return jit_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr));
1201 }
1202}
1203
1204static void jit_set_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type_info)
1205{
1206 ir_STORE(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)), type_info);
1207}
1208
1209static void jit_set_Z_TYPE_INFO_ex(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref type_info)
1210{
1211 if (Z_MODE(addr) == IS_MEM_ZVAL) {
1212 ir_ref reg;
1213
1215 if (Z_REG(addr) == ZREG_FP) {
1216 reg = jit_FP(jit);
1217 } else if (Z_REG(addr) == ZREG_RX) {
1218 reg = jit_IP(jit);
1219 } else {
1221 }
1222 ir_STORE(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)), type_info);
1223 } else {
1224 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr), type_info);
1225 }
1226}
1227
1228static void jit_set_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr, uint32_t type_info)
1229{
1230 if (type_info < IS_STRING
1231 && Z_MODE(addr) == IS_MEM_ZVAL
1232 && Z_REG(addr) == ZREG_FP
1233 && JIT_G(current_frame)
1234 && STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(addr))) == type_info) {
1235 /* type is already set */
1236 return;
1237 }
1238 jit_set_Z_TYPE_INFO_ex(jit, addr, ir_CONST_U32(type_info));
1239}
1240
1241static ir_ref jit_if_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type)
1242{
1243 return ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), type));
1244}
1245
1246static ir_ref jit_if_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1247{
1249 return ir_IF(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)));
1250}
1251
1252static ir_ref jit_if_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1253{
1254 ir_ref ref = jit_Z_TYPE(jit, addr);
1255
1256 if (type != IS_UNDEF) {
1257 ref = ir_NE(ref, ir_CONST_U8(type));
1258 }
1259 return ir_IF(ref);
1260}
1261
1262static void jit_guard_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1263{
1264 ir_ref ref = jit_Z_TYPE(jit, addr);
1265
1266 if (type != IS_UNDEF) {
1267 ir_GUARD(ir_EQ(ref, ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
1268 } else {
1269 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1270 }
1271}
1272
1273static void jit_guard_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1274{
1275 ir_ref ref = jit_Z_TYPE(jit, addr);
1276
1277 if (type != IS_UNDEF) {
1278 ref = ir_NE(ref, ir_CONST_U8(type));
1279 }
1280 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
1281}
1282
1283static ir_ref jit_if_REFCOUNTED(zend_jit_ctx *jit, zend_jit_addr addr)
1284{
1285 return ir_IF(jit_Z_TYPE_FLAGS(jit, addr));
1286}
1287
1288static ir_ref jit_if_COLLECTABLE_ref(zend_jit_ctx *jit, ir_ref addr_ref)
1289{
1290 return ir_IF(ir_AND_U8(jit_Z_TYPE_FLAGS_ref(jit, addr_ref), ir_CONST_U8(IS_TYPE_COLLECTABLE)));
1291}
1292
1293static ir_ref jit_Z_LVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1294{
1295 return ir_LOAD_L(ref);
1296}
1297
1298static ir_ref jit_Z_DVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1299{
1300 return ir_LOAD_D(ref);
1301}
1302
1303static bool zend_jit_spilling_may_cause_conflict(zend_jit_ctx *jit, int var, ir_ref val)
1304{
1305 if (jit->ctx.ir_base[val].op == IR_RLOAD) {
1306 /* Deoptimization */
1307 return 0;
1308 }
1309// if (jit->ctx.ir_base[val].op == IR_LOAD
1310// && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1311// && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1312// && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1313// && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1314// && 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)) {
1315// /* LOAD from the same location (the LOAD is pinned) */
1316// // TODO: should be anti-dependent with the following stores ???
1317// return 0;
1318// }
1319 if (jit->ssa->vars[var].var < jit->current_op_array->last_var) {
1320 /* IS_CV */
1321 if (jit->ctx.ir_base[val].op == IR_LOAD
1322 && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1323 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1324 && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1325 && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1326 && 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)
1327 && 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) {
1328 /* binding between different CVs may cause spill conflict */
1329 return 1;
1330 } else if (jit->ssa->vars[var].definition >= 0
1331 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1332 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1333 && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].no_val
1334 && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi
1335 && (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)) {
1336 /* Avoid moving spill store out of loop */
1337 return 1;
1338 } else if (jit->ssa->vars[var].definition >= 0
1339 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1340 && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1341 && jit->ssa->ops[jit->ssa->vars[var].definition].op2_use >= 0
1342 && jit->ra[jit->ssa->ops[jit->ssa->vars[var].definition].op2_use].ref == val) {
1343 /* Avoid spill conflict between of ASSIGN.op1_def and ASSIGN.op1_use */
1344 return 1;
1345 }
1346 return 0;
1347 }
1348 return 1;
1349}
1350
1351static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
1352{
1353 int var;
1354
1356 var = Z_SSA_VAR(addr);
1357 if (var == jit->delay_var) {
1358 ir_refs_add(jit->delay_refs, val);
1359 return;
1360 }
1361 ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
1362
1363 /* Negative "var" has special meaning for IR */
1364 if (val > 0) {
1365 if (jit->ctx.binding) {
1366 ir_ref old = ir_binding_find(&jit->ctx, val);
1367 if (old && old != -EX_NUM_TO_VAR(jit->ssa->vars[var].var)) {
1368 val = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[val].type), val, 1);
1369 }
1370 }
1371 if (!zend_jit_spilling_may_cause_conflict(jit, var, val)) {
1372 val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
1373 }
1374 }
1375 jit->ra[var].ref = val;
1376
1377 if (jit->ra[var].flags & ZREG_FORWARD) {
1378 zend_ssa_phi *phi = jit->ssa->vars[var].phi_use_chain;
1379 zend_basic_block *bb;
1380 int n, j, *p;
1381 ir_ref *q;
1382
1383 jit->ra[var].flags &= ~ZREG_FORWARD;
1384 while (phi != NULL) {
1385 zend_ssa_phi *dst_phi = phi;
1386 int src_var = var;
1387
1388 if (dst_phi->pi >= 0) {
1389 jit->ra[src_var].ref = val;
1390 src_var = dst_phi->ssa_var;
1391 if (!(jit->ra[src_var].flags & ZREG_FORWARD)) {
1392 phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1393 continue;
1394 }
1395 dst_phi = jit->ssa->vars[src_var].phi_use_chain;
1396 ZEND_ASSERT(dst_phi != NULL && "reg forwarding");
1397 ZEND_ASSERT(!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding");
1398 jit->ra[src_var].flags &= ~ZREG_FORWARD;
1399 }
1400
1401 if (jit->ra[dst_phi->ssa_var].ref > 0) {
1402 ir_insn *phi_insn = &jit->ctx.ir_base[jit->ra[dst_phi->ssa_var].ref];
1403 if (phi_insn->op == IR_PHI) {
1404// ZEND_ASSERT(ir_operands_count(ctx, phi_insn) == n + 1);
1405 bb = &jit->ssa->cfg.blocks[dst_phi->block];
1406 n = bb->predecessors_count;
1407 for (j = 0, p = &dst_phi->sources[0], q = phi_insn->ops + 2; j < n; j++, p++, q++) {
1408 if (*p == src_var) {
1409 *q = val;
1410 }
1411 }
1412 }
1413 }
1414
1415 phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1416 }
1417 }
1418}
1419
1420static ir_ref zend_jit_use_reg(zend_jit_ctx *jit, zend_jit_addr addr)
1421{
1422 int var = Z_SSA_VAR(addr);
1423
1425 ZEND_ASSERT(jit->ra && jit->ra[var].ref);
1426 if (jit->ra[var].ref == IR_NULL) {
1427 zend_jit_addr mem_addr;
1428 ir_ref ref;
1429
1430 ZEND_ASSERT(jit->ra[var].flags & ZREG_LOAD);
1431 mem_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(jit->ssa->vars[var].var));
1432 if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_LONG) {
1433 ref = jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1434 } else if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1435 ref = jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1436 } else {
1438 }
1439 zend_jit_def_reg(jit, addr, ref);
1440 return ref;
1441 }
1442 return jit->ra[Z_SSA_VAR(addr)].ref;
1443}
1444
1445static void zend_jit_gen_pi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1446{
1447 int src_var = phi->sources[0];
1448 int dst_var = phi->ssa_var;
1449
1450 ZEND_ASSERT(phi->pi >= 0);
1451 ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1452 ZEND_ASSERT(jit->ra[src_var].ref);
1453
1454 if (jit->ra[src_var].ref == IR_NULL) {
1455 /* Not defined yet */
1456 if (jit->ssa->vars[dst_var].use_chain < 0
1457 && jit->ssa->vars[dst_var].phi_use_chain) {
1458 zend_ssa_phi *phi = jit->ssa->vars[dst_var].phi_use_chain;
1459 if (!zend_ssa_next_use_phi(jit->ssa, dst_var, phi)) {
1460 /* This is a Pi forwarded to Phi */
1461 jit->ra[src_var].flags |= ZREG_FORWARD;
1462 return;
1463 }
1464 }
1465 ZEND_ASSERT(0 && "Not defined Pi source");
1466 }
1467 /* Reuse register */
1468 zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var),
1469 zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)));
1470}
1471
1472static void zend_jit_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1473{
1474 int dst_var = phi->ssa_var;
1475 zend_basic_block *bb = &jit->ssa->cfg.blocks[phi->block];
1476 int n = bb->predecessors_count;
1477 int i;
1478 ir_type type = (jit->ssa->var_info[phi->ssa_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE;
1479 ir_ref merge = jit->bb_start_ref[phi->block];
1480 ir_ref ref;
1481 ir_ref old_insns_count = jit->ctx.insns_count;
1482 ir_ref same_src_ref = IR_UNUSED;
1483 bool phi_inputs_are_the_same = 1;
1484
1485 ZEND_ASSERT(phi->pi < 0);
1486 ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1487 ZEND_ASSERT(merge);
1488 ZEND_ASSERT(jit->ctx.ir_base[merge].op == IR_MERGE || jit->ctx.ir_base[merge].op == IR_LOOP_BEGIN);
1489 ZEND_ASSERT(n == jit->ctx.ir_base[merge].inputs_count);
1490
1491 ref = ir_emit_N(&jit->ctx, IR_OPT(IR_PHI, type), n + 1);
1492 ir_set_op(&jit->ctx, ref, 1, merge);
1493
1494 for (i = 0; i < n; i++) {
1495 int src_var = phi->sources[i];
1496
1497 ZEND_ASSERT(jit->ra[src_var].ref);
1498 if (jit->ra[src_var].ref == IR_NULL) {
1499 jit->ra[src_var].flags |= ZREG_FORWARD;
1500 phi_inputs_are_the_same = 0;
1501 } else {
1502 ir_ref src_ref = zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var));
1503 if (i == 0) {
1504 same_src_ref = src_ref;
1505 } else if (same_src_ref != src_ref) {
1506 phi_inputs_are_the_same = 0;
1507 }
1508 ir_set_op(&jit->ctx, ref, i + 2, src_ref);
1509 }
1510 }
1511 if (phi_inputs_are_the_same) {
1512 ref = same_src_ref;
1513 jit->ctx.insns_count = old_insns_count;
1514 }
1515
1516 zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
1517}
1518
1519static ir_ref jit_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1520{
1521 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1522 return ir_CONST_LONG(Z_LVAL_P(Z_ZV(addr)));
1523 } else if (Z_MODE(addr) == IS_REG) {
1524 return zend_jit_use_reg(jit, addr);
1525 } else {
1526 return jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1527 }
1528}
1529
1530static void jit_set_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1531{
1532 if (Z_MODE(addr) == IS_REG) {
1533 zend_jit_def_reg(jit, addr, lval);
1534 } else {
1535 ir_STORE(jit_ZVAL_ADDR(jit, addr), lval);
1536 }
1537}
1538
1539#if SIZEOF_ZEND_LONG == 4
1540static ir_ref jit_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr)
1541{
1542 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1543 return ir_CONST_U32((Z_ZV(addr))->value.ww.w2);
1544 } else {
1545 return ir_LOAD_L(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)));
1546 }
1547}
1548
1549static void jit_set_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1550{
1551 ir_STORE(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)), lval);
1552}
1553#endif
1554
1555static ir_ref jit_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1556{
1557 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1559 } else if (Z_MODE(addr) == IS_REG) {
1560 return zend_jit_use_reg(jit, addr);
1561 } else {
1562 return jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1563 }
1564}
1565
1566static void jit_set_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref dval)
1567{
1568 if (Z_MODE(addr) == IS_REG) {
1569 zend_jit_def_reg(jit, addr, dval);
1570 } else {
1571 ir_STORE(jit_ZVAL_ADDR(jit, addr), dval);
1572 }
1573}
1574
1575static ir_ref jit_Z_PTR_ref(zend_jit_ctx *jit, ir_ref ref)
1576{
1577 return ir_LOAD_A(ref);
1578}
1579
1580static ir_ref jit_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr)
1581{
1582 if (Z_MODE(addr) == IS_CONST_ZVAL) {
1583 return ir_CONST_ADDR(Z_PTR_P(Z_ZV(addr)));
1584 } else {
1585 return jit_Z_PTR_ref(jit, jit_ZVAL_ADDR(jit, addr));
1586 }
1587}
1588
1589static void jit_set_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref ptr)
1590{
1591 ir_STORE(jit_ZVAL_ADDR(jit, addr), ptr);
1592}
1593
1594static ir_ref jit_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref)
1595{
1596 return ir_LOAD_U32(ref);
1597}
1598
1599static void jit_set_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref, uint32_t refcount)
1600{
1601 ir_STORE(ref, ir_CONST_U32(refcount));
1602}
1603
1604static void jit_GC_ADDREF(zend_jit_ctx *jit, ir_ref ref)
1605{
1607}
1608
1609static void jit_GC_ADDREF2(zend_jit_ctx *jit, ir_ref ref)
1610{
1611 ir_ref counter = ir_LOAD_U32(ref);
1612 ir_STORE(ref, ir_ADD_U32(counter, ir_CONST_U32(2)));
1613}
1614
1615static ir_ref jit_GC_DELREF(zend_jit_ctx *jit, ir_ref ref)
1616{
1617 ir_ref counter = ir_LOAD_U32(ref);
1618 counter = ir_SUB_U32(counter, ir_CONST_U32(1));
1619 ir_STORE(ref, counter);
1620 return counter;
1621}
1622
1623static ir_ref jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx *jit, ir_ref ref)
1624{
1625 return ir_IF(
1626 ir_AND_U32(
1627 ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_refcounted, gc.u.type_info))),
1629}
1630
1631static 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)
1632{
1633 ir_ref ref = IR_UNUSED;
1634
1635 if (Z_TYPE_P(zv) > IS_TRUE) {
1636 if (Z_TYPE_P(zv) == IS_DOUBLE) {
1637 jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE(Z_DVAL_P(zv)));
1638 } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
1639 jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE((double)Z_LVAL_P(zv)));
1640 } else if (Z_TYPE_P(zv) == IS_LONG) {
1641 jit_set_Z_LVAL(jit, dst, ir_CONST_LONG(Z_LVAL_P(zv)));
1642 } else {
1643 ref = ir_CONST_ADDR(Z_PTR_P(zv));
1644 jit_set_Z_PTR(jit, dst, ref);
1645 if (addref && Z_REFCOUNTED_P(zv)) {
1646 jit_GC_ADDREF(jit, ref);
1647 }
1648 }
1649 }
1650 if (Z_MODE(dst) != IS_REG) {
1651 if (dst_def_info == MAY_BE_DOUBLE) {
1652 if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1653 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
1654 }
1655 } 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) {
1656 jit_set_Z_TYPE_INFO(jit, dst, Z_TYPE_INFO_P(zv));
1657 }
1658 }
1659}
1660
1661static ir_ref jit_if_TYPED_REF(zend_jit_ctx *jit, ir_ref ref)
1662{
1663 return ir_IF(ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr))));
1664}
1665
1666static 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)
1667{
1668 ir_ref ref = IR_UNUSED;
1669
1670 if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1671 if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1672 jit_set_Z_LVAL(jit, dst, jit_Z_LVAL(jit, src));
1673 } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1674 jit_set_Z_DVAL(jit, dst, jit_Z_DVAL(jit, src));
1675 } else {
1676#if SIZEOF_ZEND_LONG == 4
1677 if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1678 jit_set_Z_W2(jit, dst, jit_Z_W2(jit, src));
1679 }
1680#endif
1681 ref = jit_Z_PTR(jit, src);
1682 jit_set_Z_PTR(jit, dst, ref);
1683 }
1684 }
1685 if (has_concrete_type(src_info & MAY_BE_ANY)
1687 && !(src_info & MAY_BE_GUARD)) {
1688 if (Z_MODE(dst) != IS_REG
1689 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1690 uint8_t type = concrete_type(src_info);
1691 jit_set_Z_TYPE_INFO(jit, dst, type);
1692 }
1693 } else {
1694 ir_ref type = jit_Z_TYPE_INFO(jit, src);
1695 jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1696 if (addref) {
1698 ir_ref if_refcounted = IR_UNUSED;
1699
1700 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1701 if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1702 ir_IF_TRUE(if_refcounted);
1703 }
1704
1705 jit_GC_ADDREF(jit, ref);
1706
1707 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1708 ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1709 }
1710 }
1711 }
1712 }
1713}
1714
1715static 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)
1716{
1717 ir_ref ref = IR_UNUSED;
1718
1719 if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1720 if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1721 ref = jit_Z_LVAL(jit, src);
1722 jit_set_Z_LVAL(jit, dst, ref);
1723 jit_set_Z_LVAL(jit, dst2, ref);
1724 } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1725 ref = jit_Z_DVAL(jit, src);
1726 jit_set_Z_DVAL(jit, dst, ref);
1727 jit_set_Z_DVAL(jit, dst2, ref);
1728 } else {
1729#if SIZEOF_ZEND_LONG == 4
1730 if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1731 ref = jit_Z_W2(jit, src);
1732 jit_set_Z_W2(jit, dst, ref);
1733 jit_set_Z_W2(jit, dst2, ref);
1734 }
1735#endif
1736 ref = jit_Z_PTR(jit, src);
1737 jit_set_Z_PTR(jit, dst, ref);
1738 jit_set_Z_PTR(jit, dst2, ref);
1739 }
1740 }
1741 if (has_concrete_type(src_info & MAY_BE_ANY)
1743 && !(src_info & MAY_BE_GUARD)) {
1744 uint8_t type = concrete_type(src_info);
1745 ir_ref type_ref = ir_CONST_U32(type);
1746
1747 if (Z_MODE(dst) != IS_REG
1748 && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1749 jit_set_Z_TYPE_INFO_ex(jit, dst, type_ref);
1750 }
1751 if (Z_MODE(dst2) != IS_REG) {
1752 jit_set_Z_TYPE_INFO_ex(jit, dst2, type_ref);
1753 }
1754 } else {
1755 ir_ref type = jit_Z_TYPE_INFO(jit, src);
1756 jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1757 jit_set_Z_TYPE_INFO_ex(jit, dst2, type);
1758 if (addref) {
1760 ir_ref if_refcounted = IR_UNUSED;
1761
1762 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1763 if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1764 ir_IF_TRUE(if_refcounted);
1765 }
1766
1767 if (addref == 2) {
1768 jit_GC_ADDREF2(jit, ref);
1769 } else {
1770 jit_GC_ADDREF(jit, ref);
1771 }
1772
1773 if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1774 ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1775 }
1776 }
1777 }
1778 }
1779}
1780
1781static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const zend_op *opline)
1782{
1783 if (!((op_info) & MAY_BE_GUARD)
1784 && has_concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1785 uint8_t type = concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1786 if (type == IS_STRING && !ZEND_DEBUG) {
1788 return;
1789 } else if (type == IS_ARRAY) {
1792 jit_SET_EX_OPLINE(jit, opline);
1793 }
1795 } else {
1796 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_array_free), ref);
1797 }
1798 return;
1799 } else if (type == IS_OBJECT) {
1800 if (opline) {
1801 jit_SET_EX_OPLINE(jit, opline);
1802 }
1804 return;
1805 }
1806 }
1807 if (opline) {
1808 jit_SET_EX_OPLINE(jit, opline);
1809 }
1811}
1812
1813static void jit_ZVAL_PTR_DTOR(zend_jit_ctx *jit,
1815 uint32_t op_info,
1816 bool gc,
1817 const zend_op *opline)
1818{
1819 ir_ref ref, ref2;
1820 ir_ref if_refcounted = IR_UNUSED;
1821 ir_ref if_not_zero = IR_UNUSED;
1822 ir_ref end_inputs = IR_UNUSED;
1823
1826 if_refcounted = jit_if_REFCOUNTED(jit, addr);
1827 ir_IF_FALSE(if_refcounted);
1828 ir_END_list(end_inputs);
1829 ir_IF_TRUE(if_refcounted);
1830 }
1831 ref = jit_Z_PTR(jit, addr);
1832 ref2 = jit_GC_DELREF(jit, ref);
1833
1834 if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1835 if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1836 if_not_zero = ir_IF(ref2);
1837 ir_IF_FALSE(if_not_zero);
1838 }
1839 // zval_dtor_func(r);
1840 jit_ZVAL_DTOR(jit, ref, op_info, opline);
1841 if (if_not_zero) {
1842 ir_END_list(end_inputs);
1843 ir_IF_TRUE(if_not_zero);
1844 }
1845 }
1846 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))) {
1847 ir_ref if_may_not_leak;
1848
1849 if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1850 ir_ref if_ref, if_collectable;
1851
1852 if_ref = jit_if_Z_TYPE(jit, addr, IS_REFERENCE);
1853 ir_IF_TRUE(if_ref);
1854
1856
1857 if_collectable = jit_if_COLLECTABLE_ref(jit, ref2);
1858 ir_IF_FALSE(if_collectable);
1859 ir_END_list(end_inputs);
1860 ir_IF_TRUE(if_collectable);
1861
1862 ref2 = jit_Z_PTR_ref(jit, ref2);
1863
1865 ref = ir_PHI_2(IR_ADDR, ref2, ref);
1866 }
1867
1868 if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1869 ir_IF_TRUE(if_may_not_leak);
1870 ir_END_list(end_inputs);
1871 ir_IF_FALSE(if_may_not_leak);
1872
1873 if (opline) {
1874 jit_SET_EX_OPLINE(jit, opline);
1875 }
1877 }
1878
1879 if (end_inputs) {
1880 ir_END_list(end_inputs);
1881 ir_MERGE_list(end_inputs);
1882 }
1883 }
1884}
1885
1886static void jit_FREE_OP(zend_jit_ctx *jit,
1887 uint8_t op_type,
1888 znode_op op,
1889 uint32_t op_info,
1890 const zend_op *opline)
1891{
1892 if (op_type & (IS_VAR|IS_TMP_VAR)) {
1893 jit_ZVAL_PTR_DTOR(jit,
1894 ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var),
1895 op_info, 0, opline);
1896 }
1897}
1898
1899static void jit_OBJ_RELEASE(zend_jit_ctx *jit, ir_ref ref)
1900{
1901 ir_ref end_inputs = IR_UNUSED;
1902 ir_ref if_not_zero, if_may_not_leak;
1903
1904 // JIT: if (GC_DELREF(obj) == 0) {
1905 if_not_zero = ir_IF(jit_GC_DELREF(jit, ref));
1906 ir_IF_FALSE(if_not_zero);
1907
1908 // JIT: zend_objects_store_del(obj)
1910 ir_END_list(end_inputs);
1911
1912 ir_IF_TRUE(if_not_zero);
1913 if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1914
1915 ir_IF_TRUE(if_may_not_leak);
1916 ir_END_list(end_inputs);
1917
1918 ir_IF_FALSE(if_may_not_leak);
1920 ir_END_list(end_inputs);
1921
1922 ir_MERGE_list(end_inputs);
1923}
1924
1925static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
1926{
1927 ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
1928
1929 if (exit_addr) {
1930 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1931 } else if (!opline || jit->last_valid_opline == opline) {
1932 ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1933 } else {
1934 ir_ref if_timeout = ir_IF(ref);
1935
1936 ir_IF_TRUE_cold(if_timeout);
1937 jit_LOAD_IP_ADDR(jit, opline);
1938 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1939 ir_IF_FALSE(if_timeout);
1940 }
1941}
1942
1943/* stubs */
1944
1945static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
1946{
1947 const void *handler;
1948
1949 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1950 handler = zend_get_opcode_handler_func(EG(exception_op));
1951
1953 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
1954 } else {
1955 handler = EG(exception_op)->handler;
1956
1957 if (GCC_GLOBAL_REGS) {
1959 } else {
1960 ir_ref ref, if_negative;
1961
1962 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), jit_FP(jit));
1963 if_negative = ir_IF(ir_LT(ref, ir_CONST_U32(0)));
1964 ir_IF_TRUE(if_negative);
1965 ir_MERGE_WITH_EMPTY_FALSE(if_negative);
1966 ref = ir_PHI_2(IR_I32, ref, ir_CONST_I32(1));
1967 ir_RETURN(ref);
1968 }
1969 }
1970 return 1;
1971}
1972
1973static int zend_jit_exception_handler_undef_stub(zend_jit_ctx *jit)
1974{
1975 ir_ref ref, result_type, if_result_used;
1976
1977 ref = jit_EG(opline_before_exception);
1978 result_type = ir_LOAD_U8(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result_type)));
1979
1980 if_result_used = ir_IF(ir_AND_U8(result_type, ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1981 ir_IF_TRUE(if_result_used);
1982
1984 if (sizeof(void*) == 8) {
1985 ref = ir_ZEXT_A(ref);
1986 }
1987 ir_STORE(ir_ADD_OFFSET(ir_ADD_A(jit_FP(jit), ref), offsetof(zval, u1.type_info)), ir_CONST_U32(IS_UNDEF));
1988 ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
1989
1990 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
1991
1992 return 1;
1993}
1994
1995static int zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx *jit)
1996{
1997 ir_ref ref, if_dtor;
1998 zend_jit_addr var_addr;
1999
2000 ref = ir_LOAD_A(jit_EG(opline_before_exception));
2001 if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op1_type))),
2003 ir_IF_TRUE(if_dtor);
2004 ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op1.var)));
2005 if (sizeof(void*) == 8) {
2006 ref = ir_ZEXT_A(ref);
2007 }
2008 ref = ir_ADD_A(jit_FP(jit), ref);
2009 var_addr = ZEND_ADDR_REF_ZVAL(ref);
2010 jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
2012
2013 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
2014
2015 return 1;
2016}
2017
2018static int zend_jit_exception_handler_free_op2_stub(zend_jit_ctx *jit)
2019{
2020 ir_ref ref, if_dtor;
2021 zend_jit_addr var_addr;
2022
2023 ref = ir_LOAD_A(jit_EG(opline_before_exception));
2024 if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op2_type))),
2026 ir_IF_TRUE(if_dtor);
2027 ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.var)));
2028 if (sizeof(void*) == 8) {
2029 ref = ir_ZEXT_A(ref);
2030 }
2031 ref = ir_ADD_A(jit_FP(jit), ref);
2032 var_addr = ZEND_ADDR_REF_ZVAL(ref);
2033 jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, NULL);
2035
2036 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2037
2038 return 1;
2039}
2040
2041static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit)
2042{
2043 ir_ref if_timeout, if_exception;
2044
2045 if (GCC_GLOBAL_REGS) {
2046 // EX(opline) = opline
2047 ir_STORE(jit_EX(opline), jit_IP(jit));
2048 }
2049
2050 ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0));
2051 if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0)));
2052 ir_IF_FALSE(if_timeout);
2054 ir_MERGE_WITH_EMPTY_TRUE(if_timeout);
2055
2058 if_exception = ir_IF(ir_LOAD_A(jit_EG(exception)));
2059 ir_IF_TRUE(if_exception);
2060 ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper));
2061 ir_MERGE_WITH_EMPTY_FALSE(if_exception);
2062
2063 jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
2064 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2065 }
2066
2067 if (GCC_GLOBAL_REGS) {
2068 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2069 } else {
2071 }
2072 return 1;
2073}
2074
2075static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit)
2076{
2077 ir_ref call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
2079
2080 ir_IF_FALSE(if_top);
2081
2082 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2084 jit_STORE_IP(jit,
2085 ir_LOAD_A(jit_EX(opline)));
2086 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2087 } else if (GCC_GLOBAL_REGS) {
2089 } else {
2091 }
2092
2093 ir_IF_TRUE(if_top);
2094
2095 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2097 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2098 } else if (GCC_GLOBAL_REGS) {
2100 } else {
2102 }
2103
2104 return 1;
2105}
2106
2107static int zend_jit_negative_shift_stub(zend_jit_ctx *jit)
2108{
2111 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2113 ir_CONST_ADDR("Bit shift by negative number"));
2114 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2115 return 1;
2116}
2117
2118static int zend_jit_mod_by_zero_stub(zend_jit_ctx *jit)
2119{
2122 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2124 ir_CONST_ADDR("Modulo by zero"));
2125 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2126 return 1;
2127}
2128
2129static int zend_jit_invalid_this_stub(zend_jit_ctx *jit)
2130{
2133 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2134 IR_NULL,
2135 ir_CONST_ADDR("Using $this when not in object context"));
2136 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2137 return 1;
2138}
2139
2140static int zend_jit_undefined_function_stub(zend_jit_ctx *jit)
2141{
2142 // JIT: load EX(opline)
2143 ir_ref ref = ir_LOAD_A(jit_FP(jit));
2145
2146 if (sizeof(void*) == 8) {
2148 } else {
2149 arg3 = ir_LOAD_A(arg3);
2150 }
2152
2155 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2156 IR_NULL,
2157 ir_CONST_ADDR("Call to undefined function %s()"),
2158 arg3);
2159
2160 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2161
2162 return 1;
2163}
2164
2165static int zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx *jit)
2166{
2167 ir_ref opline, ref, rx, if_eq, if_tmp;
2168
2169 // JIT: opline = EX(opline)
2170 opline = ir_LOAD_A(jit_FP(jit));
2171
2172 // JIT: ZVAL_UNDEF(ZEND_CALL_VAR(RX, opline->result.var))
2173 ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2174 if (sizeof(void*) == 8) {
2175 ref = ir_ZEXT_A(ref);
2176 }
2177 rx = jit_IP(jit);
2178 jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(rx, ref), ir_CONST_U32(IS_UNDEF));
2179
2180 // last EX(call) frame may be delayed
2181 // JIT: if (EX(call) == RX)
2182 ref = ir_LOAD_A(jit_EX(call));
2183 if_eq = ir_IF(ir_EQ(rx, ref));
2184 ir_IF_FALSE(if_eq);
2185
2186 // JIT: RX->prev_execute_data == EX(call)
2188
2189 // JIT: EX(call) = RX
2190 ir_STORE(jit_EX(call), rx);
2192
2193 // JIT: IP = opline
2194 jit_STORE_IP(jit, opline);
2195
2196 // JIT: zend_cannot_pass_by_reference(opline->op2.num)
2198 ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.num))));
2199
2200 // JIT: if (IP->op1_type == IS_TMP_VAR)
2201 ref = ir_LOAD_U8(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1_type)));
2202 if_tmp = ir_IF(ir_EQ(ref, ir_CONST_U8(IS_TMP_VAR)));
2203 ir_IF_TRUE(if_tmp);
2204
2205 // JIT: zval_ptr_dtor(EX_VAR(IP->op1.var))
2206 ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1.var)));
2207 if (sizeof(void*) == 8) {
2208 ref = ir_ZEXT_A(ref);
2209 }
2210 ref = ir_ADD_A(jit_FP(jit), ref);
2211 jit_ZVAL_PTR_DTOR(jit,
2212 ZEND_ADDR_REF_ZVAL(ref),
2215
2216 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2217
2218 return 1;
2219}
2220
2221static int zend_jit_icall_throw_stub(zend_jit_ctx *jit)
2222{
2223 ir_ref ip, if_set;
2224
2225 // JIT: zend_rethrow_exception(zend_execute_data *execute_data)
2226 // JIT: if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
2227 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2228 ip = jit_IP(jit);
2229 if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2231 ir_IF_FALSE(if_set);
2232
2233 // JIT: EG(opline_before_exception) = opline;
2234 ir_STORE(jit_EG(opline_before_exception), ip);
2236
2237 // JIT: opline = EG(exception_op);
2238 jit_STORE_IP(jit, jit_EG(exception_op));
2239
2240 if (GCC_GLOBAL_REGS) {
2241 ir_STORE(jit_EX(opline), jit_IP(jit));
2242 }
2243
2244 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2245
2246 return 1;
2247}
2248
2249static int zend_jit_leave_throw_stub(zend_jit_ctx *jit)
2250{
2251 ir_ref ip, if_set;
2252
2253 // JIT: if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
2254 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2255 ip = jit_IP(jit);
2256 if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2258 ir_IF_FALSE(if_set);
2259
2260 // JIT: EG(opline_before_exception) = opline;
2261 ir_STORE(jit_EG(opline_before_exception), ip);
2263
2264 // JIT: opline = EG(exception_op);
2265 jit_LOAD_IP(jit, jit_EG(exception_op));
2266
2267 if (GCC_GLOBAL_REGS) {
2268 ir_STORE(jit_EX(opline), jit_IP(jit));
2269
2270 // JIT: HANDLE_EXCEPTION()
2271 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2272 } else {
2273 ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
2274 }
2275
2276 return 1;
2277}
2278
2279static int zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx *jit)
2280{
2281 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2282 return 0;
2283 }
2284
2285 ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_runtime_jit));
2286 ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2287 return 1;
2288}
2289
2290static int zend_jit_hybrid_profile_jit_stub(zend_jit_ctx *jit)
2291{
2292 ir_ref addr, func, run_time_cache, jit_extension;
2293
2294 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2295 return 0;
2296 }
2297
2300
2302 run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
2304
2306 addr = ir_ADD_OFFSET(run_time_cache, zend_jit_profile_counter_rid * sizeof(void*));
2307 } else {
2308 addr = run_time_cache;
2309 }
2311
2312 addr = ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_extension, orig_handler));
2314
2315 return 1;
2316}
2317
2318static int _zend_jit_hybrid_hot_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2319{
2320 ir_ref func, jit_extension, addr, ref, if_overflow;
2321
2325 ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2326 ir_STORE(addr, ref);
2327 if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2328
2329 ir_IF_TRUE_cold(if_overflow);
2332 jit_FP(jit),
2333 jit_IP(jit));
2334 ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2335
2336 ir_IF_FALSE(if_overflow);
2337 ref = ir_SUB_A(jit_IP(jit),
2339 ref = ir_DIV_A(ref, ir_CONST_ADDR(sizeof(zend_op) / sizeof(void*)));
2340
2341 addr = ir_ADD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, orig_handlers)),
2342 ref);
2344
2345 return 1;
2346}
2347
2348static int zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx *jit)
2349{
2350 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2351 return 0;
2352 }
2353
2354 return _zend_jit_hybrid_hot_counter_stub(jit,
2355 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2356}
2357
2358static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit)
2359{
2360 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2361 return 0;
2362 }
2363
2364 return _zend_jit_hybrid_hot_counter_stub(jit,
2365 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2366}
2367
2368static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset)
2369{
2370 ir_ref addr;
2371
2372 if (GCC_GLOBAL_REGS) {
2373 addr = ir_ADD_A(offset, jit_IP(jit));
2374 } else {
2375 addr = ir_ADD_A(offset, ir_LOAD_A(jit_EX(opline)));
2376 }
2377
2378 return ir_LOAD_A(addr);
2379}
2380
2381static ir_ref zend_jit_orig_opline_handler(zend_jit_ctx *jit)
2382{
2383 ir_ref func, jit_extension, offset;
2384
2388 return _zend_jit_orig_opline_handler(jit, offset);
2389}
2390
2391static int _zend_jit_hybrid_trace_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2392{
2393 ir_ref func, jit_extension, offset, addr, ref, if_overflow, ret, if_halt;
2394
2399 ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2400 ir_STORE(addr, ref);
2401 if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2402
2403 ir_IF_TRUE_cold(if_overflow);
2406 jit_FP(jit),
2407 jit_IP(jit));
2408 if_halt = ir_IF(ir_LT(ret, ir_CONST_I32(0)));
2409 ir_IF_FALSE(if_halt);
2410
2411 ref = jit_EG(current_execute_data);
2412 jit_STORE_FP(jit, ir_LOAD_A(ref));
2413 ref = ir_LOAD_A(jit_EX(opline));
2414 jit_STORE_IP(jit, ref);
2415 ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2416
2417 ir_IF_FALSE(if_overflow);
2418 ir_IJMP(_zend_jit_orig_opline_handler(jit, offset));
2419
2420 ir_IF_TRUE(if_halt);
2422
2423 return 1;
2424}
2425
2426static int zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx *jit)
2427{
2428 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2429 return 0;
2430 }
2431
2432 return _zend_jit_hybrid_trace_counter_stub(jit,
2433 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2434}
2435
2436static int zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx *jit)
2437{
2438 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2439 return 0;
2440 }
2441
2442 return _zend_jit_hybrid_trace_counter_stub(jit,
2443 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2444}
2445
2446static int zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx *jit)
2447{
2448 if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2449 return 0;
2450 }
2451
2452 return _zend_jit_hybrid_trace_counter_stub(jit,
2453 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2454}
2455
2456static int zend_jit_trace_halt_stub(zend_jit_ctx *jit)
2457{
2458 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2460 } else if (GCC_GLOBAL_REGS) {
2461 jit_STORE_IP(jit, IR_NULL);
2463 } else {
2464 ir_RETURN(ir_CONST_I32(-1)); // ZEND_VM_RETURN
2465 }
2466 return 1;
2467}
2468
2469static int zend_jit_trace_escape_stub(zend_jit_ctx *jit)
2470{
2471 if (GCC_GLOBAL_REGS) {
2472 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2473 } else {
2474 ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2475 }
2476
2477 return 1;
2478}
2479
2480static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
2481{
2482 ir_ref ref, ret, if_zero, addr;
2483
2484 if (GCC_GLOBAL_REGS) {
2485 // EX(opline) = opline
2486 ir_STORE(jit_EX(opline), jit_IP(jit));
2487 }
2488
2490
2491 if_zero = ir_IF(ir_EQ(ret, ir_CONST_I32(0)));
2492
2493 ir_IF_TRUE(if_zero);
2494
2495 if (GCC_GLOBAL_REGS) {
2496 ref = jit_EG(current_execute_data);
2497 jit_STORE_FP(jit, ir_LOAD_A(ref));
2498 ref = ir_LOAD_A(jit_EX(opline));
2499 jit_STORE_IP(jit, ref);
2500 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2501 } else {
2502 ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2503 }
2504
2505 ir_IF_FALSE(if_zero);
2506
2507 ir_GUARD(ir_GE(ret, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2508
2509 ref = jit_EG(current_execute_data);
2510 jit_STORE_FP(jit, ir_LOAD_A(ref));
2511
2512 if (GCC_GLOBAL_REGS) {
2513 ref = ir_LOAD_A(jit_EX(opline));
2514 jit_STORE_IP(jit, ref);
2515 }
2516
2517 // check for interrupt (try to avoid this ???)
2518 zend_jit_check_timeout(jit, NULL, NULL);
2519
2520 addr = zend_jit_orig_opline_handler(jit);
2521 if (GCC_GLOBAL_REGS) {
2523 } else {
2524#if defined(IR_TARGET_X86)
2526#endif
2527 ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
2528 ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2529 ir_RETURN(ir_CONST_I32(1)); // ZEND_VM_ENTER
2530 }
2531
2532 return 1;
2533}
2534
2535static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit)
2536{
2537 if (GCC_GLOBAL_REGS) {
2539 } else {
2541 }
2542
2543 return 1;
2544}
2545
2546static int zend_jit_undefined_key_stub(zend_jit_ctx *jit)
2547{
2548 if (GCC_GLOBAL_REGS) {
2550 } else {
2552 }
2553
2554 return 1;
2555}
2556
2557static int zend_jit_cannot_add_element_stub(zend_jit_ctx *jit)
2558{
2559 ir_ref opline = ir_LOAD_A(jit_EX(opline));
2560 ir_ref ref, if_result_used;
2561
2562 if_result_used = ir_IF(ir_AND_U8(
2563 ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, result_type))),
2565 ir_IF_TRUE(if_result_used);
2566
2567 ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2568 if (sizeof(void*) == 8) {
2569 ref = ir_ZEXT_A(ref);
2570 }
2571 jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_UNDEF));
2572 ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2573
2576 ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2577 IR_NULL,
2578 ir_CONST_ADDR("Cannot add element to the array as the next element is already occupied"));
2580
2581 return 1;
2582}
2583
2584static int zend_jit_assign_const_stub(zend_jit_ctx *jit)
2585{
2586 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2587 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2588
2589 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2591 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2592
2593 if (!zend_jit_assign_to_variable(
2594 jit, NULL,
2595 var_addr, var_addr, -1, -1,
2596 IS_CONST, val_addr, val_info,
2597 0, 0, 0)) {
2598 return 0;
2599 }
2601 return 1;
2602}
2603
2604static int zend_jit_assign_tmp_stub(zend_jit_ctx *jit)
2605{
2606 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2607 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2608
2609 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2611 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2612
2613 if (!zend_jit_assign_to_variable(
2614 jit, NULL,
2615 var_addr, var_addr, -1, -1,
2616 IS_TMP_VAR, val_addr, val_info,
2617 0, 0, 0)) {
2618 return 0;
2619 }
2621 return 1;
2622}
2623
2624static int zend_jit_assign_var_stub(zend_jit_ctx *jit)
2625{
2626 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2627 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2628
2629 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2631 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2632
2633 if (!zend_jit_assign_to_variable(
2634 jit, NULL,
2635 var_addr, var_addr, -1, -1,
2636 IS_VAR, val_addr, val_info,
2637 0, 0, 0)) {
2638 return 0;
2639 }
2641 return 1;
2642}
2643
2644static int zend_jit_assign_cv_noref_stub(zend_jit_ctx *jit)
2645{
2646 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2647 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2648
2649 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2651 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2652
2653 if (!zend_jit_assign_to_variable(
2654 jit, NULL,
2655 var_addr, var_addr, -1, -1,
2656 IS_CV, val_addr, val_info,
2657 0, 0, 0)) {
2658 return 0;
2659 }
2661 return 1;
2662}
2663
2664static int zend_jit_new_array_stub(zend_jit_ctx *jit)
2665{
2666 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2667 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2669
2670 jit_set_Z_PTR(jit, var_addr, ref);
2671 jit_set_Z_TYPE_INFO(jit, var_addr, IS_ARRAY_EX);
2672 ir_RETURN(ref);
2673 return 1;
2674}
2675
2676static int zend_jit_assign_cv_stub(zend_jit_ctx *jit)
2677{
2678 ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2679 ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2680
2681 zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2683 uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2684
2685 if (!zend_jit_assign_to_variable(
2686 jit, NULL,
2687 var_addr, var_addr, -1, -1,
2688 IS_CV, val_addr, val_info,
2689 0, 0, 0)) {
2690 return 0;
2691 }
2693 return 1;
2694}
2695
2696static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2697{
2698#if defined (__CET__) && (__CET__ & 1) != 0
2700#endif
2702
2703 ir_init(&jit->ctx, flags, 256, 1024);
2704 jit->ctx.ret_type = -1;
2705
2706#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2707 jit->ctx.mflags |= default_mflags;
2708 if (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX) {
2709 jit->ctx.mflags |= IR_X86_AVX;
2710 }
2711#elif defined(IR_TARGET_AARCH64)
2712 jit->ctx.get_veneer = zend_jit_get_veneer;
2713 jit->ctx.set_veneer = zend_jit_set_veneer;
2714#endif
2715
2716 jit->ctx.fixed_regset = (1<<ZREG_FP) | (1<<ZREG_IP);
2717 if (!(flags & IR_FUNCTION)) {
2719 if (zend_jit_vm_kind == ZEND_VM_KIND_CALL) {
2720 jit->ctx.flags |= IR_FUNCTION;
2721 /* Stack must be 16 byte aligned */
2722 /* TODO: select stack size ??? */
2723#if defined(IR_TARGET_AARCH64)
2725 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 16; /* 10 saved registers and 6 spill slots (8 bytes) */
2726#elif defined(_WIN64)
2727 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 8 saved registers and 3 spill slots (8 bytes) */
2728#elif defined(IR_TARGET_X86_64)
2729 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 9; /* 6 saved registers and 3 spill slots (8 bytes) */
2730#else /* IR_TARGET_x86 */
2731 jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */
2732#endif
2733 if (GCC_GLOBAL_REGS) {
2734 jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<<ZREG_FP) | (1<<ZREG_IP));
2735 } else {
2737//#ifdef _WIN64
2738// jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
2739//#endif
2740 }
2741#ifdef _WIN64
2743#else
2744 jit->ctx.fixed_call_stack_size = 16;
2745#endif
2746 } else {
2747#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2748 jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
2749 if (jit->ctx.fixed_stack_red_zone > 16) {
2751 jit->ctx.fixed_call_stack_size = 16;
2752 }
2754#else
2755 jit->ctx.fixed_stack_red_zone = 0;
2756 jit->ctx.fixed_stack_frame_size = 32; /* 4 spill slots (8 bytes) or 8 spill slots (4 bytes) */
2757 jit->ctx.fixed_call_stack_size = 16;
2758#endif
2759#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2760 jit->ctx.fixed_regset |= (1<<IR_REG_FP); /* prevent %rbp (%r5) usage */
2761#endif
2762 }
2763 }
2764
2765 jit->ctx.snapshot_create = (ir_snapshot_create_t)jit_SNAPSHOT;
2766
2767 jit->op_array = NULL;
2768 jit->current_op_array = NULL;
2769 jit->ssa = NULL;
2770 jit->name = NULL;
2771 jit->last_valid_opline = NULL;
2772 jit->use_last_valid_opline = 0;
2773 jit->track_last_valid_opline = 0;
2774 jit->reuse_ip = 0;
2775 jit->delayed_call_level = 0;
2776 delayed_call_chain = 0;
2777 jit->b = -1;
2778#ifdef ZTS
2779 jit->tls = IR_UNUSED;
2780#endif
2781 jit->fp = IR_UNUSED;
2782 jit->poly_func_ref = IR_UNUSED;
2783 jit->poly_this_ref = IR_UNUSED;
2785 jit->return_inputs = IR_UNUSED;
2786 jit->bb_start_ref = NULL;
2787 jit->bb_predecessors = NULL;
2788 jit->bb_edges = NULL;
2789 jit->trace = NULL;
2790 jit->ra = NULL;
2791 jit->delay_var = -1;
2792 jit->delay_refs = NULL;
2793 jit->eg_exception_addr = 0;
2794 zend_hash_init(&jit->addr_hash, 64, NULL, NULL, 0);
2795 memset(jit->stub_addr, 0, sizeof(jit->stub_addr));
2796
2797 ir_START();
2798}
2799
2800static int zend_jit_free_ctx(zend_jit_ctx *jit)
2801{
2802 if (jit->name) {
2803 zend_string_release(jit->name);
2804 }
2806 ir_free(&jit->ctx);
2807 return 1;
2808}
2809
2810static void *zend_jit_ir_compile(ir_ctx *ctx, size_t *size, const char *name)
2811{
2812 void *entry;
2813 ir_code_buffer code_buffer;
2814
2816 if (name) fprintf(stderr, "%s: ; after folding\n", name);
2817 ir_save(ctx, 0, stderr);
2818 }
2819
2820#if ZEND_DEBUG
2821 ir_check(ctx);
2822#endif
2823
2825
2826#if ZEND_DEBUG
2827 ir_check(ctx);
2828#endif
2829
2830#if 1
2831 ir_sccp(ctx);
2832#endif
2833
2835 if (name) fprintf(stderr, "%s: ; after SCCP\n", name);
2836 ir_save(ctx, 0, stderr);
2837 }
2838
2839 ir_build_cfg(ctx);
2841 ir_find_loops(ctx);
2842
2844 if (name) fprintf(stderr, "%s: ; after CFG\n", name);
2845 ir_save(ctx, IR_SAVE_CFG, stderr);
2846 }
2847
2848 ir_gcm(ctx);
2849
2851 if (name) fprintf(stderr, "%s: ; after GCM\n", name);
2852 ir_save(ctx, IR_SAVE_CFG|IR_SAVE_CFG_MAP, stderr);
2853 }
2854
2855 ir_schedule(ctx);
2856
2858 if (name) fprintf(stderr, "%s: ; after schedule\n", name);
2859 ir_save(ctx, IR_SAVE_CFG, stderr);
2860 }
2861
2862 ir_match(ctx);
2863#if !defined(IR_TARGET_AARCH64)
2864 ctx->flags &= ~IR_USE_FRAME_POINTER; /* don't use FRAME_POINTER even with ALLOCA, TODO: cleanup this ??? */
2865#endif
2868 ir_coalesce(ctx);
2869 ir_reg_alloc(ctx);
2870
2872 if (name) fprintf(stderr, "%s: ; after register allocation\n", name);
2874 ir_dump_live_ranges(ctx, stderr);
2875 }
2876
2877 ir_schedule_blocks(ctx);
2878
2881 if (name) fprintf(stderr, "%s: ; codegen\n", name);
2882 ir_dump_codegen(ctx, stderr);
2883 } else {
2884 if (name) fprintf(stderr, "%s: ; final\n", name);
2886 }
2887 }
2888
2889#if ZEND_DEBUG
2890 ir_check(ctx);
2891#endif
2892
2893 code_buffer.start = dasm_buf;
2894 code_buffer.end = dasm_end;
2895 code_buffer.pos = *dasm_ptr;
2896 ctx->code_buffer = &code_buffer;
2897
2898 entry = ir_emit_code(ctx, size);
2899
2900 *dasm_ptr = code_buffer.pos;
2901
2902#if defined(IR_TARGET_AARCH64)
2903 if (ctx->flags2 & IR_HAS_VENEERS) {
2904 zend_jit_commit_veneers();
2905 }
2906#endif
2907
2908 return entry;
2909}
2910
2911static void zend_jit_setup_stubs(void)
2912{
2913 zend_jit_ctx jit;
2914 void *entry;
2915 size_t size;
2916 uint32_t i;
2917
2918 for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
2919 zend_jit_init_ctx(&jit, zend_jit_stubs[i].flags);
2920
2921 if (!zend_jit_stubs[i].stub(&jit)) {
2922 zend_jit_free_ctx(&jit);
2923 zend_jit_stub_handlers[i] = NULL;
2924 continue;
2925 }
2926
2927 entry = zend_jit_ir_compile(&jit.ctx, &size, zend_jit_stubs[i].name);
2928 if (!entry) {
2929 zend_jit_free_ctx(&jit);
2930 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile stub");
2931 }
2932
2933 zend_jit_stub_handlers[i] = entry;
2934
2936#ifdef HAVE_CAPSTONE
2938 ir_disasm_add_symbol(zend_jit_stubs[i].name, (uintptr_t)entry, size);
2939 }
2941 ir_disasm(zend_jit_stubs[i].name,
2942 entry, size, (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0, &jit.ctx, stderr);
2943 }
2944#endif
2945#ifndef _WIN32
2947// ir_mem_unprotect(entry, size);
2948 ir_gdb_register(zend_jit_stubs[i].name, entry, size, 0, 0);
2949// ir_mem_protect(entry, size);
2950 }
2951
2953 ir_perf_map_register(zend_jit_stubs[i].name, entry, size);
2955 ir_perf_jitdump_register(zend_jit_stubs[i].name, entry, size);
2956 }
2957 }
2958#endif
2959 }
2960 zend_jit_free_ctx(&jit);
2961 }
2962}
2963
2964#define REGISTER_HELPER(n) \
2965 ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)n, sizeof(void*));
2966#define REGISTER_DATA(n) \
2967 ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)&n, sizeof(n));
2968
2969static void zend_jit_setup_disasm(void)
2970{
2971#ifdef HAVE_CAPSTONE
2973
2975 zend_op opline;
2976
2977 memset(&opline, 0, sizeof(opline));
2978
2979 opline.opcode = ZEND_DO_UCALL;
2980 opline.result_type = IS_UNUSED;
2982 ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2983
2984 opline.opcode = ZEND_DO_UCALL;
2985 opline.result_type = IS_VAR;
2987 ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2988
2990 opline.result_type = IS_UNUSED;
2992 ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2993
2995 opline.result_type = IS_VAR;
2997 ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
2998
2999 opline.opcode = ZEND_DO_FCALL;
3000 opline.result_type = IS_UNUSED;
3002 ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3003
3004 opline.opcode = ZEND_DO_FCALL;
3005 opline.result_type = IS_VAR;
3007 ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3008
3009 opline.opcode = ZEND_RETURN;
3010 opline.op1_type = IS_CONST;
3012 ir_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3013
3014 opline.opcode = ZEND_RETURN;
3015 opline.op1_type = IS_TMP_VAR;
3017 ir_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3018
3019 opline.opcode = ZEND_RETURN;
3020 opline.op1_type = IS_VAR;
3022 ir_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3023
3024 opline.opcode = ZEND_RETURN;
3025 opline.op1_type = IS_CV;
3027 ir_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3028
3029 ir_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
3030 }
3031
3033
3034 REGISTER_HELPER(zend_runtime_jit);
3038
3039 REGISTER_HELPER(zend_jit_array_free);
3040 REGISTER_HELPER(zend_jit_undefined_op_helper);
3041 REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
3042 REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
3043 REGISTER_HELPER(zend_jit_post_inc_typed_ref);
3044 REGISTER_HELPER(zend_jit_post_dec_typed_ref);
3045 REGISTER_HELPER(zend_jit_pre_inc);
3046 REGISTER_HELPER(zend_jit_pre_dec);
3047 REGISTER_HELPER(zend_jit_add_arrays_helper);
3048 REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
3049 REGISTER_HELPER(zend_jit_fast_concat_helper);
3050 REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
3051 REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
3052 REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
3053 REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
3054 REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
3055 REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
3056 REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
3057 REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
3058 REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
3059 REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
3060 REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
3063 REGISTER_HELPER(zend_jit_int_extend_stack_helper);
3064 REGISTER_HELPER(zend_jit_extend_stack_helper);
3065 REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
3066 REGISTER_HELPER(zend_jit_find_func_helper);
3067 REGISTER_HELPER(zend_jit_find_ns_func_helper);
3068 REGISTER_HELPER(zend_jit_jmp_frameless_helper);
3069 REGISTER_HELPER(zend_jit_unref_helper);
3070 REGISTER_HELPER(zend_jit_invalid_method_call);
3071 REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
3072 REGISTER_HELPER(zend_jit_find_method_helper);
3073 REGISTER_HELPER(zend_jit_find_method_tmp_helper);
3074 REGISTER_HELPER(zend_jit_push_static_metod_call_frame);
3075 REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
3076 REGISTER_HELPER(zend_jit_free_trampoline_helper);
3077 REGISTER_HELPER(zend_jit_verify_return_slow);
3084 REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3086 REGISTER_HELPER(zend_jit_free_call_frame);
3087 REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3088 REGISTER_HELPER(zend_jit_verify_arg_slow);
3090 REGISTER_HELPER(zend_jit_only_vars_by_reference);
3094 REGISTER_HELPER(zend_jit_fetch_global_helper);
3095 REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3096 REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3097 REGISTER_HELPER(zend_jit_hash_lookup_rw);
3098 REGISTER_HELPER(zend_jit_symtable_find);
3099 REGISTER_HELPER(zend_jit_symtable_lookup_w);
3100 REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3101 REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3102 REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3103 REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3104 REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3105 REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3106 REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3107 REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3108 REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3109 REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3110 REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3111 REGISTER_HELPER(zend_jit_invalid_array_access);
3112 REGISTER_HELPER(zend_jit_zval_array_dup);
3113 REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3114 REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3115 REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3116 REGISTER_HELPER(zend_jit_isset_dim_helper);
3117 REGISTER_HELPER(zend_jit_assign_dim_helper);
3118 REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3119 REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3120 REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3121 REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3122 REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3123 REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3124 REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3125 REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3126 REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3127 REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3128 REGISTER_HELPER(zend_jit_check_array_promotion);
3129 REGISTER_HELPER(zend_jit_create_typed_ref);
3130 REGISTER_HELPER(zend_jit_invalid_property_write);
3131 REGISTER_HELPER(zend_jit_invalid_property_read);
3132 REGISTER_HELPER(zend_jit_extract_helper);
3133 REGISTER_HELPER(zend_jit_invalid_property_assign);
3134 REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3135 REGISTER_HELPER(zend_jit_assign_obj_helper);
3136 REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3137 REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3138 REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3139 REGISTER_HELPER(zend_jit_invalid_property_incdec);
3140 REGISTER_HELPER(zend_jit_inc_typed_prop);
3141 REGISTER_HELPER(zend_jit_dec_typed_prop);
3142 REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3143 REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3144 REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3145 REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3146 REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3147 REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3148 REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3149 REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3150 REGISTER_HELPER(zend_jit_rope_end);
3152
3153#ifndef ZTS
3154 REGISTER_DATA(EG(current_execute_data));
3156 REGISTER_DATA(EG(opline_before_exception));
3157 REGISTER_DATA(EG(vm_interrupt));
3158 REGISTER_DATA(EG(timed_out));
3159 REGISTER_DATA(EG(uninitialized_zval));
3160 REGISTER_DATA(EG(zend_constants));
3161 REGISTER_DATA(EG(jit_trace_num));
3162 REGISTER_DATA(EG(vm_stack_top));
3163 REGISTER_DATA(EG(vm_stack_end));
3164 REGISTER_DATA(EG(exception_op));
3165 REGISTER_DATA(EG(symbol_table));
3166
3167 REGISTER_DATA(CG(map_ptr_base));
3168#endif
3169#endif
3170}
3171
3172static void zend_jit_calc_trace_prologue_size(void)
3173{
3174 zend_jit_ctx jit_ctx;
3175 zend_jit_ctx *jit = &jit_ctx;
3176 void *entry;
3177 size_t size;
3178
3179 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
3180
3181 if (!GCC_GLOBAL_REGS) {
3182 ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3183 jit_STORE_FP(jit, ref);
3184 jit->ctx.flags |= IR_FASTCALL_FUNC;
3185 }
3186
3188
3189 entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3190 zend_jit_free_ctx(jit);
3191
3192 if (!entry) {
3193 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3194 }
3195
3196 zend_jit_trace_prologue_size = size;
3197}
3198
3199#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3200static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3201
3203typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3206
3211
3212static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3213{
3215 arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3216 arg->cnt++;
3217 if (arg->cnt == 3) {
3218 return 5; // _URC_END_OF_STACK
3219 }
3220 return 0; // _URC_NO_REASON;
3221}
3222
3223static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3224{
3226
3227 memset(&arg, 0, sizeof(arg));
3228 _Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3229 if (arg.cnt == 3) {
3230 zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3231 }
3232}
3233
3234extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3235
3236static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3237{
3238 void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3239
3240 orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3241 zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3242 execute_ex(NULL); // set sp_adj[SP_ADJ_VM]
3243 zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3244}
3245#endif
3246
3247#ifdef _WIN64
3248/*
3249 * We use a single unwind entry for the whole JIT buffer.
3250 * This works, because all the JIT-ed PHP functions have the same "fixed stack frame".
3251 */
3252static PRUNTIME_FUNCTION zend_jit_uw_func = NULL;
3253
3254#ifdef ZEND_JIT_RT_UNWINDER
3255static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
3256{
3257 return zend_jit_uw_func;
3258}
3259#endif
3260
3261static void zend_jit_setup_unwinder(void)
3262{
3263 /* Hardcoded SEH unwind data for JIT-ed PHP functions with "fixed stack frame" */
3264 static const unsigned char uw_data[] = {
3265 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3266 0x10, // UBYTE Size of prolog
3267 0x09, // UBYTE Count of unwind codes
3268 0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3269 // USHORT * n Unwind codes array
3270 0x10, 0x82, // c: subq $0x48, %rsp
3271 0x0c, 0xf0, // a: pushq %r15
3272 0x0a, 0xe0, // 8: pushq %r14
3273 0x08, 0xd0, // 6: pushq %r13
3274 0x06, 0xc0, // 4: pushq %r12
3275 0x04, 0x70, // 3: pushq %rdi
3276 0x03, 0x60, // 2: pushq %rsi
3277 0x02, 0x50, // 1: pushq %rbp
3278 0x01, 0x30, // 0: pushq %rbx
3279 0x00, 0x00,
3280 };
3281 static const unsigned char uw_data_exitcall[] = {
3282 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3283 0x10, // UBYTE Size of prolog
3284 0x0a, // UBYTE Count of unwind codes
3285 0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3286 // USHORT * n Unwind codes array
3287 0x10, 0x01, 0x2f, 0x00, // c: subq 376, %rsp ; 0x48 + 32+16*8+16*8+8+8
3288 0x0c, 0xf0, // a: pushq %r15
3289 0x0a, 0xe0, // 8: pushq %r14
3290 0x08, 0xd0, // 6: pushq %r13
3291 0x06, 0xc0, // 4: pushq %r12
3292 0x04, 0x70, // 3: pushq %rdi
3293 0x03, 0x60, // 2: pushq %rsi
3294 0x02, 0x50, // 1: pushq %rbp
3295 0x01, 0x30, // 0: pushq %rbx
3296 };
3297
3298 zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
3299 *dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) * 4 +
3300 sizeof(uw_data) + sizeof(uw_data_exitcall) + sizeof(uw_data), 16);
3301
3302 zend_jit_uw_func[0].BeginAddress = 0;
3303 zend_jit_uw_func[1].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_trace_exit] - (uintptr_t)dasm_buf;
3304 zend_jit_uw_func[2].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_undefined_offset] - (uintptr_t)dasm_buf;
3305
3306 zend_jit_uw_func[0].EndAddress = zend_jit_uw_func[1].BeginAddress;
3307 zend_jit_uw_func[1].EndAddress = zend_jit_uw_func[2].BeginAddress;
3308 zend_jit_uw_func[2].EndAddress = (uintptr_t)dasm_end - (uintptr_t)dasm_buf;
3309
3310 zend_jit_uw_func[0].UnwindData = (uintptr_t)zend_jit_uw_func - (uintptr_t)dasm_buf + sizeof(RUNTIME_FUNCTION) * 4;
3311 zend_jit_uw_func[1].UnwindData = zend_jit_uw_func[0].UnwindData + sizeof(uw_data);
3312 zend_jit_uw_func[2].UnwindData = zend_jit_uw_func[1].UnwindData + sizeof(uw_data_exitcall);
3313
3314 memcpy((char*)dasm_buf + zend_jit_uw_func[0].UnwindData, uw_data, sizeof(uw_data));
3315 memcpy((char*)dasm_buf + zend_jit_uw_func[1].UnwindData, uw_data_exitcall, sizeof(uw_data_exitcall));
3316 memcpy((char*)dasm_buf + zend_jit_uw_func[2].UnwindData, uw_data, sizeof(uw_data));
3317
3318#ifdef ZEND_JIT_RT_UNWINDER
3319 RtlInstallFunctionTableCallback(
3320 (uintptr_t)dasm_buf | 3,
3321 (uintptr_t) dasm_buf,
3322 (uintptr_t)dasm_end - (uintptr_t)dasm_buf,
3323 zend_jit_unwind_callback,
3324 NULL,
3325 NULL);
3326#else
3327 RtlAddFunctionTable(zend_jit_uw_func, 3, (uintptr_t)dasm_buf);
3328#endif
3329}
3330#endif
3331
3332
3333static void zend_jit_setup(bool reattached)
3334{
3335#if defined(IR_TARGET_X86)
3336 if (!zend_cpu_supports_sse2()) {
3337 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3338 }
3339#endif
3340#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3341 allowed_opt_flags = 0;
3342 if (zend_cpu_supports_avx()) {
3343 allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3344 }
3345# if defined(PHP_HAVE_BUILTIN_CPU_SUPPORTS) && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
3346 if (zend_cpu_supports_cldemote()) {
3347 default_mflags |= IR_X86_CLDEMOTE;
3348 }
3349# endif
3350#endif
3351#ifdef ZTS
3352#if defined(IR_TARGET_AARCH64)
3353 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3354
3355# ifdef __FreeBSD__
3356 if (tsrm_ls_cache_tcb_offset == 0) {
3357 TLSDescriptor **where;
3358
3359 __asm__(
3360 "adrp %0, :tlsdesc:_tsrm_ls_cache\n"
3361 "add %0, %0, :tlsdesc_lo12:_tsrm_ls_cache\n"
3362 : "=r" (where));
3363 /* See https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst
3364 * section "Relocations for thread-local storage".
3365 * The first entry holds a pointer to the variable's TLS descriptor resolver function and the second entry holds
3366 * a platform-specific offset or pointer. */
3367 TLSDescriptor *tlsdesc = where[1];
3368
3369 tsrm_tls_offset = tlsdesc->offset;
3370 /* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/22ca6db50f4e6bd75a141f57cf953d8de6531a06/lib/libc/gen/tls.c#L88) */
3371 tsrm_tls_index = (tlsdesc->index + 1) * 8;
3372 }
3373# elif defined(__MUSL__)
3374 if (tsrm_ls_cache_tcb_offset == 0) {
3375 size_t **where;
3376
3377 __asm__(
3378 "adrp %0, :tlsdesc:_tsrm_ls_cache\n"
3379 "add %0, %0, :tlsdesc_lo12:_tsrm_ls_cache\n"
3380 : "=r" (where));
3381 /* See https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst */
3382 size_t *tlsdesc = where[1];
3383
3384 tsrm_tls_offset = tlsdesc[1];
3385 tsrm_tls_index = tlsdesc[0] * 8;
3386 }
3387# else
3388 ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0);
3389# endif
3390# elif defined(_WIN64)
3391 tsrm_tls_index = _tls_index * sizeof(void*);
3392
3393 /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3394 /* Probably, it might be better solution */
3395 do {
3396 void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
3397 void *val = _tsrm_ls_cache;
3398 size_t offset = 0;
3399 size_t size = (char*)&_tls_end - (char*)&_tls_start;
3400
3401 while (offset < size) {
3402 if (*tls_mem == val) {
3403 tsrm_tls_offset = offset;
3404 break;
3405 }
3406 tls_mem++;
3407 offset += sizeof(void*);
3408 }
3409 if (offset >= size) {
3410 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3411 }
3412 } while(0);
3413# elif defined(ZEND_WIN32)
3414 tsrm_tls_index = _tls_index * sizeof(void*);
3415
3416 /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
3417 /* Probably, it might be better solution */
3418 do {
3419 void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
3420 void *val = _tsrm_ls_cache;
3421 size_t offset = 0;
3422 size_t size = (char*)&_tls_end - (char*)&_tls_start;
3423
3424 while (offset < size) {
3425 if (*tls_mem == val) {
3426 tsrm_tls_offset = offset;
3427 break;
3428 }
3429 tls_mem++;
3430 offset += sizeof(void*);
3431 }
3432 if (offset >= size) {
3433 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
3434 }
3435 } while(0);
3436# elif defined(__APPLE__) && defined(__x86_64__)
3437 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3438 if (tsrm_ls_cache_tcb_offset == 0) {
3439 size_t *ti;
3440 __asm__(
3441 "leaq __tsrm_ls_cache(%%rip),%0"
3442 : "=r" (ti));
3443 tsrm_tls_offset = ti[2];
3444 tsrm_tls_index = ti[1] * 8;
3445 }
3446# elif defined(__GNUC__) && defined(__x86_64__)
3447 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3448 if (tsrm_ls_cache_tcb_offset == 0) {
3449#if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && \
3450 !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3451 size_t ret;
3452
3453 asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
3454 : "=r" (ret));
3455 tsrm_ls_cache_tcb_offset = ret;
3456#elif defined(__MUSL__)
3457 size_t *ti;
3458
3459 __asm__(
3460 "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3461 : "=a" (ti));
3462 tsrm_tls_offset = ti[1];
3463 tsrm_tls_index = ti[0] * 8;
3464#elif defined(__FreeBSD__)
3465 size_t *ti;
3466
3467 __asm__(
3468 "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3469 : "=a" (ti));
3470 tsrm_tls_offset = ti[1];
3471 /* Index is offset by 1 on FreeBSD (https://github.com/freebsd/freebsd-src/blob/bf56e8b9c8639ac4447d223b83cdc128107cc3cd/libexec/rtld-elf/rtld.c#L5260) */
3472 tsrm_tls_index = (ti[0] + 1) * 8;
3473#else
3474 size_t *ti;
3475
3476 __asm__(
3477 "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
3478 : "=a" (ti));
3479 tsrm_tls_offset = ti[1];
3480 tsrm_tls_index = ti[0] * 16;
3481#endif
3482 }
3483# elif defined(__GNUC__) && defined(__i386__)
3484 tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
3485 if (tsrm_ls_cache_tcb_offset == 0) {
3486#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
3487 size_t ret;
3488
3489 asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
3490 : "=a" (ret));
3491 tsrm_ls_cache_tcb_offset = ret;
3492#else
3493 size_t *ti, _ebx, _ecx, _edx;
3494
3495 __asm__(
3496 "call 1f\n"
3497 ".subsection 1\n"
3498 "1:\tmovl (%%esp), %%ebx\n\t"
3499 "ret\n"
3500 ".previous\n\t"
3501 "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
3502 "leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
3503 "call ___tls_get_addr@plt\n\t"
3504 "leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
3505 : "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
3506 tsrm_tls_offset = ti[1];
3507 tsrm_tls_index = ti[0] * 8;
3508#endif
3509 }
3510# endif
3511#endif
3512
3513#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3514 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3515 zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3516 }
3517#endif
3518
3520 zend_jit_setup_disasm();
3521 }
3522
3523#ifndef _WIN32
3526 }
3527
3528#endif
3535 }
3536
3537 zend_jit_calc_trace_prologue_size();
3538 if (!reattached) {
3539 zend_jit_setup_stubs();
3540 }
3541 JIT_G(debug) = debug;
3542
3543#ifdef _WIN64
3544 zend_jit_setup_unwinder();
3545#endif
3546}
3547
3548static void zend_jit_shutdown_ir(void)
3549{
3550#ifndef _WIN32
3553 }
3556 }
3557#endif
3558#ifdef HAVE_CAPSTONE
3561 }
3562#endif
3563}
3564
3565/* PHP control flow reconstruction helpers */
3566static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3567{
3568 ir_ref ref = ir_IF(condition);
3569 /* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3570 *
3571 * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3572 * to start target block
3573 */
3574 ir_set_op(&jit->ctx, ref, 3, true_block);
3575 return ref;
3576}
3577
3578static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3579{
3581 ZEND_ASSERT(if_ref);
3582 ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3583 ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3584 if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3585 ir_IF_TRUE(if_ref);
3586 } else {
3587 ir_IF_FALSE(if_ref);
3588 }
3589}
3590
3591static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref);
3592
3593static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3594{
3595 int i, *p;
3596 zend_basic_block *bb;
3597 ir_ref *r, header;
3598
3600 bb = &jit->ssa->cfg.blocks[b];
3601 p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3602 r = &jit->bb_edges[jit->bb_predecessors[b]];
3603 for (i = 0; i < bb->predecessors_count; i++, p++, r++) {
3604 if (*p == pred) {
3605 ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3606 header = jit->bb_start_ref[b];
3607 if (header) {
3608 /* this is back edge */
3609 ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3610 if (jit->ctx.ir_base[ref].op == IR_END) {
3611 jit->ctx.ir_base[ref].op = IR_LOOP_END;
3612 } else if (jit->ctx.ir_base[ref].op == IR_IF) {
3613 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3614 ref = ir_LOOP_END();
3615 } else if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
3616 zend_jit_case_start(jit, pred, b, ref);
3617 ref = ir_LOOP_END();
3618 } else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3619 ir_BEGIN(ref);
3620 ref = ir_LOOP_END();
3621 } else {
3623 }
3624 ir_MERGE_SET_OP(header, i + 1, ref);
3625 }
3626 *r = ref;
3627 return;
3628 }
3629 }
3631}
3632
3633static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3634 uint32_t true_label,
3635 uint32_t false_label,
3636 ir_ref true_inputs,
3637 ir_ref false_inputs)
3638{
3639 ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3640
3642 if (true_inputs) {
3643 ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3644 if (!jit->ctx.ir_base[true_inputs].op2) {
3645 true_path = true_inputs;
3646 } else {
3647 ir_MERGE_list(true_inputs);
3648 true_path = ir_END();
3649 }
3650 }
3651 if (false_inputs) {
3652 ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3653 if (!jit->ctx.ir_base[false_inputs].op2) {
3654 false_path = false_inputs;
3655 } else {
3656 ir_MERGE_list(false_inputs);
3657 false_path = ir_END();
3658 }
3659 }
3660
3661 if (true_label == false_label && true_path && false_path) {
3662 ir_MERGE_2(true_path, false_path);
3663 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3664 } else if (!true_path && !false_path) {
3665 /* dead code */
3666 true_path = ir_END();
3667 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3668 } else {
3669 if (true_path) {
3670 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3671 }
3672 if (false_path) {
3673 _zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3674 }
3675 }
3676
3677 jit->b = -1;
3678}
3679
3680static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3681{
3682 int i, count;
3683 ir_ref j, k, n, *p, *q, *r;
3684 ir_ref ref;
3685 ir_insn *insn, *phi;
3686
3688 count = jit->ssa->cfg.blocks_count;
3689 for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3690 ref = *p;
3691 if (ref) {
3692 insn = &jit->ctx.ir_base[ref];
3693 if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3694 n = insn->inputs_count;
3695 /* Remove IS_UNUSED inputs */
3696 for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3697 if (*q) {
3698 if (q != r) {
3699 *r = *q;
3700 phi = insn + 1 + (n >> 2);
3701 while (phi->op == IR_PI) {
3702 phi++;
3703 }
3704 while (phi->op == IR_PHI) {
3705 ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3706 phi += 1 + ((n + 1) >> 2);
3707 }
3708 }
3709 k++;
3710 r++;
3711 }
3712 }
3713 if (k != n) {
3714 ir_ref n2, k2;
3715
3716 if (k <= 1) {
3717 insn->op = IR_BEGIN;
3718 insn->inputs_count = 0;
3719 } else {
3720 insn->inputs_count = k;
3721 }
3722 n2 = 1 + (n >> 2);
3723 k2 = 1 + (k >> 2);
3724 while (k2 != n2) {
3725 (insn+k2)->optx = IR_NOP;
3726 k2++;
3727 }
3728 phi = insn + 1 + (n >> 2);
3729 while (phi->op == IR_PI) {
3730 phi++;
3731 }
3732 while (phi->op == IR_PHI) {
3733 if (k <= 1) {
3734 phi->op = IR_COPY;
3735 phi->op1 = phi->op2;
3736 phi->op2 = 1;
3737 phi->inputs_count = 0;
3738 } else {
3739 phi->inputs_count = k + 1;
3740 }
3741 n2 = 1 + ((n + 1) >> 2);
3742 k2 = 1 + ((k + 1) >> 2);
3743 while (k2 != n2) {
3744 (phi+k2)->optx = IR_NOP;
3745 k2++;
3746 }
3747 phi += 1 + ((n + 1) >> 2);
3748 }
3749 }
3750 }
3751 }
3752 }
3753}
3754
3755static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3756{
3757 zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3758 const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3759
3760 if (opline->opcode == ZEND_SWITCH_LONG
3761 || opline->opcode == ZEND_SWITCH_STRING
3762 || opline->opcode == ZEND_MATCH) {
3763 HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3764 const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3765 int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3766 zval *zv;
3767 ir_ref list = IR_UNUSED, idx;
3768 bool first = 1;
3769
3770 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3771 const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3772 int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3773
3774 if (b == case_b) {
3775 if (!first) {
3776 ir_END_list(list);
3777 }
3778 if (HT_IS_PACKED(jumptable)) {
3779 idx = ir_CONST_LONG(zv - jumptable->arPacked);
3780 } else {
3781 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3782 }
3783 ir_CASE_VAL(switch_ref, idx);
3784 first = 0;
3785 }
3787 if (default_b == case_b) {
3788 if (!first) {
3789 ir_END_list(list);
3790 }
3791 if (jit->ctx.ir_base[switch_ref].op3) {
3792 /* op3 may contain a list of additional "default" path inputs for MATCH */
3793 ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3794 jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3795 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3796 ir_ref end = ref;
3797 while (jit->ctx.ir_base[end].op2) {
3798 ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3799 end = jit->ctx.ir_base[end].op2;
3800 }
3801 jit->ctx.ir_base[end].op2 = list;
3802 list = ref;
3803 }
3804 ir_CASE_DEFAULT(switch_ref);
3805 }
3806 if (list) {
3807 ir_END_list(list);
3808 ir_MERGE_list(list);
3809 }
3810 } else {
3812 }
3813}
3814
3815static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3816{
3817 zend_basic_block *bb;
3818 int i, n, *p, pred;
3819 ir_ref ref, bb_start;
3820
3822 ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3823 bb = &jit->ssa->cfg.blocks[b];
3824 ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3825 n = bb->predecessors_count;
3826
3827 if (n == 0) {
3828 /* pass */
3829 ZEND_ASSERT(jit->ctx.control);
3830#if ZEND_DEBUG
3831 ref = jit->ctx.control;
3832 ir_insn *insn = &jit->ctx.ir_base[ref];
3833 while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3834 ref = insn->op1;
3835 insn = &jit->ctx.ir_base[ref];
3836 }
3837 ZEND_ASSERT(insn->op == IR_START);
3838 ZEND_ASSERT(ref == 1);
3839#endif
3840 bb_start = 1;
3842 /* prvent END/BEGIN merging */
3843 jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3844 bb_start = jit->ctx.control;
3845 }
3846 } else if (n == 1) {
3847 ZEND_ASSERT(!jit->ctx.control);
3848 pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3849 ref = jit->bb_edges[jit->bb_predecessors[b]];
3850 if (ref == IR_UNUSED) {
3851 if (!jit->ctx.control) {
3852 ir_BEGIN(IR_UNUSED); /* unreachable block */
3853 }
3854 } else {
3855 ir_op op = jit->ctx.ir_base[ref].op;
3856
3857 if (op == IR_IF) {
3858 if (!jit->ctx.control) {
3859 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3860 } else {
3861 ir_ref entry_path = ir_END();
3862 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3863 ir_MERGE_WITH(entry_path);
3864 }
3865 } else if (op == IR_SWITCH) {
3866 zend_jit_case_start(jit, pred, b, ref);
3867 } else {
3868 if (!jit->ctx.control) {
3869 ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3870 if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3872 /* prvent END/BEGIN merging */
3873 jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3874 } else {
3875 ir_BEGIN(ref);
3876 }
3877 } else {
3878 ir_MERGE_WITH(ref);
3879 }
3880 }
3881 }
3882 bb_start = jit->ctx.control;
3883 } else {
3884 int forward_edges_count = 0;
3885 int back_edges_count = 0;
3886 ir_ref *pred_refs;
3887 ir_ref entry_path = IR_UNUSED;
3888 ALLOCA_FLAG(use_heap);
3889
3890 ZEND_ASSERT(!jit->ctx.control);
3891 if (jit->ctx.control) {
3892 entry_path = ir_END();
3893 }
3894 pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3895 for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3896 pred = *p;
3897 if (jit->bb_start_ref[pred]) {
3898 /* forward edge */
3899 forward_edges_count++;
3900 ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3901 if (ref == IR_UNUSED) {
3902 /* dead edge */
3903 pred_refs[i] = IR_UNUSED;
3904 } else {
3905 ir_op op = jit->ctx.ir_base[ref].op;
3906
3907 if (op == IR_IF) {
3908 jit_IF_TRUE_FALSE_ex(jit, ref, b);
3909 pred_refs[i] = ir_END();
3910 } else if (op == IR_SWITCH) {
3911 zend_jit_case_start(jit, pred, b, ref);
3912 pred_refs[i] = ir_END();
3913 } else {
3914 ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3915 pred_refs[i] = ref;
3916 }
3917 }
3918 } else {
3919 /* backward edge */
3920 back_edges_count++;
3921 pred_refs[i] = IR_UNUSED;
3922 }
3923 }
3924
3925 if (bb->flags & ZEND_BB_LOOP_HEADER) {
3926 ZEND_ASSERT(back_edges_count != 0);
3927 ZEND_ASSERT(forward_edges_count != 0);
3928 ir_MERGE_N(n, pred_refs);
3929 jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3930 bb_start = jit->ctx.control;
3931 if (entry_path) {
3932 ir_MERGE_WITH(entry_path);
3933 }
3934 } else {
3935// ZEND_ASSERT(back_edges_count != 0);
3936 /* edges from exceptional blocks may be counted as back edges */
3937 ir_MERGE_N(n, pred_refs);
3938 bb_start = jit->ctx.control;
3939 if (entry_path) {
3940 ir_MERGE_WITH(entry_path);
3941 }
3942 }
3943 free_alloca(pred_refs, use_heap);
3944 }
3945 jit->b = b;
3946 jit->bb_start_ref[b] = bb_start;
3947
3948 if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3949 jit->ctx.fold_cse_limit = bb_start;
3950 }
3951
3952 return 1;
3953}
3954
3955static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3956{
3957 int succ;
3958 zend_basic_block *bb;
3959
3961 if (jit->b != b) {
3962 return 1;
3963 }
3964
3965 bb = &jit->ssa->cfg.blocks[b];
3966 ZEND_ASSERT(bb->successors_count != 0);
3967 if (bb->successors_count == 1) {
3968 succ = bb->successors[0];
3969 } else {
3970 const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3971
3972 /* Use only the following successor of SWITCH and FE_RESET_R */
3974 || opline->opcode == ZEND_SWITCH_STRING
3975 || opline->opcode == ZEND_MATCH
3976 || opline->opcode == ZEND_FE_RESET_R);
3977 succ = b + 1;
3978 }
3979 _zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3980 jit->b = -1;
3981 return 1;
3982}
3983
3984static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3985{
3986 ir_ref ref;
3987
3988#if 1
3989 if (GCC_GLOBAL_REGS) {
3990 ref = jit_IP32(jit);
3991 } else {
3992 ref = ir_LOAD_U32(jit_EX(opline));
3993 }
3994 ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3995#else
3996 if (GCC_GLOBAL_REGS) {
3997 ref = jit_IP(jit);
3998 } else {
3999 ref = ir_LOAD_A(jit_EX(opline));
4000 }
4001 ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
4002#endif
4003 return ref;
4004}
4005
4006static int zend_jit_jmp_frameless(
4007 zend_jit_ctx *jit,
4008 const zend_op *opline,
4009 const void *exit_addr,
4010 zend_jmp_fl_result guard
4011) {
4012 ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
4013 zend_basic_block *bb;
4014
4015 // JIT: CACHED_PTR(opline->extended_value)
4016 cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
4017 cache_result = ir_LOAD_L(cache_slot_ref);
4018
4019 // JIT: if (UNEXPECTED(!result))
4020 if_ref = ir_IF(cache_result);
4021 ir_IF_FALSE_cold(if_ref);
4022 zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
4023 function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
4024 ir_CONST_ADDR(func_name_zv),
4025 cache_slot_ref);
4027
4028 phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
4029
4030 if (exit_addr) {
4031 ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
4032 } else {
4033 ZEND_ASSERT(jit->b >= 0);
4034 bb = &jit->ssa->cfg.blocks[jit->b];
4035 // JIT: if (result == ZEND_JMP_FL_HIT)
4036 ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
4037 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
4038 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
4039 jit->b = -1;
4040 }
4041
4042 return 1;
4043}
4044
4045static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
4046{
4047 ir_ref ref;
4048 zend_basic_block *bb;
4049
4050 ZEND_ASSERT(jit->b >= 0);
4051 bb = &jit->ssa->cfg.blocks[jit->b];
4052
4053 ZEND_ASSERT(bb->successors_count == 2);
4054 if (bb->successors[0] == bb->successors[1]) {
4055 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
4056 jit->b = -1;
4057 zend_jit_set_last_valid_opline(jit, next_opline);
4058 return 1;
4059 }
4060
4061 ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
4062
4063 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
4064 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
4065
4066 jit->b = -1;
4067 zend_jit_set_last_valid_opline(jit, next_opline);
4068
4069 return 1;
4070}
4071
4072static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *next_opline, uint32_t var)
4073{
4074 ir_ref ref;
4075
4076 ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, IR_EQ, next_opline)), ir_CONST_U32(IS_FALSE));
4077
4078 // EX_VAR(var) = ...
4079 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
4080
4081 zend_jit_reset_last_valid_opline(jit);
4082 return zend_jit_set_ip(jit, next_opline - 1);
4083}
4084
4085/* PHP JIT handlers */
4086static void zend_jit_check_exception(zend_jit_ctx *jit)
4087{
4088 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
4089 jit_STUB_ADDR(jit, jit_stub_exception_handler));
4090}
4091
4092static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
4093{
4094 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
4095 jit_STUB_ADDR(jit,
4096 (opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
4097}
4098
4099static void zend_jit_type_check_undef(zend_jit_ctx *jit,
4100 ir_ref type,
4101 uint32_t var,
4102 const zend_op *opline,
4103 bool check_exception,
4104 bool in_cold_path,
4105 bool undef_result)
4106{
4107 ir_ref if_def = ir_IF(type);
4108
4109 if (!in_cold_path) {
4110 ir_IF_FALSE_cold(if_def);
4111 } else {
4112 ir_IF_FALSE(if_def);
4113 }
4114 if (opline) {
4115 jit_SET_EX_OPLINE(jit, opline);
4116 }
4117 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
4118 if (check_exception) {
4119 if (undef_result) {
4120 zend_jit_check_exception_undef_result(jit, opline);
4121 } else {
4122 zend_jit_check_exception(jit);
4123 }
4124 }
4126}
4127
4128static ir_ref zend_jit_zval_check_undef(zend_jit_ctx *jit,
4129 ir_ref ref,
4130 uint32_t var,
4131 const zend_op *opline,
4132 bool check_exception)
4133{
4134 ir_ref if_def, ref2;
4135
4136 if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
4137 ir_IF_FALSE_cold(if_def);
4138
4139 if (opline) {
4140 jit_SET_EX_OPLINE(jit, opline);
4141 }
4142
4143 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
4144
4145 if (check_exception) {
4146 zend_jit_check_exception(jit);
4147 }
4148
4149 ref2 = jit_EG(uninitialized_zval);
4150
4152
4153 return ir_PHI_2(IR_ADDR, ref2, ref);
4154}
4155
4156static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
4157{
4158 zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4159 int pred;
4160 ir_ref ref;
4161
4163
4164 pred = jit->bb_predecessors[b];
4165 ref = jit->bb_edges[pred];
4166
4167 ZEND_ASSERT(ref);
4168 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
4169
4170 /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4171 ir_ENTRY(ref, bb->start);
4172 if (!GCC_GLOBAL_REGS) {
4173 /* 2 is hardcoded reference to IR_PARAM */
4174 ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4175 ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4176 jit_STORE_FP(jit, 2);
4177 }
4178
4179 ir_MERGE_WITH(ref);
4180 jit->bb_edges[pred] = ir_END();
4181}
4182
4183static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4184{
4185 zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4186 ir_ref ref = ir_END();
4187
4188 /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4189 ir_ENTRY(ref, bb->start);
4190 if (!GCC_GLOBAL_REGS) {
4191 /* 2 is hardcoded reference to IR_PARAM */
4192 ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4193 ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4194 jit_STORE_FP(jit, 2);
4195 }
4196
4197 ir_MERGE_WITH(ref);
4198}
4199
4200static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4201{
4202 ir_ENTRY(src, label);
4203 if (!GCC_GLOBAL_REGS) {
4204 /* 2 is hardcoded reference to IR_PARAM */
4205 ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4206 ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4207 jit_STORE_FP(jit, 2);
4208 }
4209 return ir_END();
4210}
4211
4212static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4213{
4214 ir_ref ref;
4215 const void *handler;
4216
4217 zend_jit_set_ip(jit, opline);
4218 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4220 } else {
4221 handler = opline->handler;
4222 }
4223 if (GCC_GLOBAL_REGS) {
4225 } else {
4226 ref = jit_FP(jit);
4228 }
4229 if (may_throw) {
4230 zend_jit_check_exception(jit);
4231 }
4232 /* Skip the following OP_DATA */
4233 switch (opline->opcode) {
4234 case ZEND_ASSIGN_DIM:
4235 case ZEND_ASSIGN_OBJ:
4237 case ZEND_ASSIGN_DIM_OP:
4238 case ZEND_ASSIGN_OBJ_OP:
4243 zend_jit_set_last_valid_opline(jit, opline + 2);
4244 break;
4245 default:
4246 zend_jit_set_last_valid_opline(jit, opline + 1);
4247 break;
4248 }
4249 return 1;
4250}
4251
4252static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4253{
4254 const void *handler;
4255 ir_ref ref;
4256 zend_basic_block *bb;
4257
4258 zend_jit_set_ip(jit, opline);
4259 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
4260 if (opline->opcode == ZEND_DO_UCALL ||
4261 opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4262 opline->opcode == ZEND_DO_FCALL ||
4263 opline->opcode == ZEND_RETURN) {
4264
4265 /* Use inlined HYBRID VM handler */
4266 handler = opline->handler;
4268 } else {
4271 ref = ir_LOAD_A(jit_IP(jit));
4272 ir_TAILCALL(IR_VOID, ref);
4273 }
4274 } else {
4275 handler = opline->handler;
4276 if (GCC_GLOBAL_REGS) {
4278 } else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4279 && (opline->opcode == ZEND_CATCH
4280 || opline->opcode == ZEND_FAST_CALL
4281 || opline->opcode == ZEND_FAST_RET
4282 || opline->opcode == ZEND_MATCH_ERROR
4283 || opline->opcode == ZEND_THROW
4284 || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4285 ref = jit_FP(jit);
4286 ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4288 } else {
4289 ref = jit_FP(jit);
4290 ir_TAILCALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
4291 }
4292 }
4293 if (jit->b >= 0) {
4294 bb = &jit->ssa->cfg.blocks[jit->b];
4295 if (bb->successors_count > 0
4296 && (opline->opcode == ZEND_DO_FCALL
4297 || opline->opcode == ZEND_DO_UCALL
4298 || opline->opcode == ZEND_DO_FCALL_BY_NAME
4299 || opline->opcode == ZEND_INCLUDE_OR_EVAL
4300 || opline->opcode == ZEND_GENERATOR_CREATE
4301 || opline->opcode == ZEND_YIELD
4302 || opline->opcode == ZEND_YIELD_FROM
4303 || opline->opcode == ZEND_FAST_CALL)) {
4304 /* Add a fake control edge from UNREACHABLE to the following ENTRY */
4305 int succ;
4306
4307 if (bb->successors_count == 1) {
4308 succ = bb->successors[0];
4310 } else {
4311 /* Use only the following successor of FAST_CALL */
4312 ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4313 succ = jit->b + 1;
4314 /* we need an entry */
4315 jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4316 }
4317 ref = jit->ctx.insns_count - 1;
4318 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4319 ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4320 _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4321 }
4322 jit->b = -1;
4323 zend_jit_reset_last_valid_opline(jit);
4324 }
4325 return 1;
4326}
4327
4328static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4329{
4330 return zend_jit_tail_handler(jit, opline);
4331}
4332
4333static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4334{
4335 ZEND_ASSERT(Z_MODE(src) == IS_REG);
4337
4338 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4339 jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4340 if (set_type &&
4341 (Z_REG(dst) != ZREG_FP ||
4342 !JIT_G(current_frame) ||
4343 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4344 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4345 }
4346 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4347 jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4348 if (set_type &&
4349 (Z_REG(dst) != ZREG_FP ||
4350 !JIT_G(current_frame) ||
4351 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4352 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4353 }
4354 } else {
4356 }
4357 return 1;
4358}
4359
4360static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4361{
4362 ZEND_ASSERT(Z_MODE(src) == IS_REG);
4364
4365 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4366 jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4367 if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4368 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4369 } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4370 /* invalidate memory type */
4371 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4372 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4373 }
4374 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4375 jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4376 if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4377 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4378 } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4379 /* invalidate memory type */
4380 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4381 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4382 }
4383 } else {
4385 }
4386 return 1;
4387}
4388
4389static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4390{
4392 ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4393
4394 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4395 zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4396 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4397 zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4398 } else {
4400 }
4401 return 1;
4402}
4403
4404static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4405{
4406 zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4407 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4408
4409 return zend_jit_spill_store(jit, src, dst, info, set_type);
4410}
4411
4412static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4413{
4414 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4415
4416 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4417 jit_set_Z_LVAL(jit, dst, src);
4418 if (set_type &&
4419 (Z_REG(dst) != ZREG_FP ||
4420 !JIT_G(current_frame) ||
4421 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4422 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4423 }
4424 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4425 jit_set_Z_DVAL(jit, dst, src);
4426 if (set_type &&
4427 (Z_REG(dst) != ZREG_FP ||
4428 !JIT_G(current_frame) ||
4429 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4430 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4431 }
4432 } else {
4434 }
4435 return 1;
4436}
4437
4438static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4439{
4440 ir_ref ref = jit->ctx.control;
4441 ir_insn *insn;
4442
4443 while (1) {
4444 insn = &jit->ctx.ir_base[ref];
4445 if (insn->op == IR_RLOAD && insn->op2 == reg) {
4446 ZEND_ASSERT(insn->type == type);
4447 return ref;
4448 } else if (insn->op == IR_START) {
4449 break;
4450 }
4451 ref = insn->op1;
4452 }
4453 return ir_RLOAD(type, reg);
4454}
4455
4456/* Same as zend_jit_deopt_rload(), but 'reg' may be spilled on C stack */
4457static ir_ref zend_jit_deopt_rload_spilled(zend_jit_ctx *jit, ir_type type, int8_t reg, int32_t offset)
4458{
4459 ZEND_ASSERT(reg >= 0);
4460
4461 if (IR_REG_SPILLED(reg)) {
4462 return ir_LOAD(type, ir_ADD_OFFSET(zend_jit_deopt_rload(jit, type, IR_REG_NUM(reg)), offset));
4463 } else {
4464 return zend_jit_deopt_rload(jit, type, reg);
4465 }
4466}
4467
4468static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4469{
4470 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4471 ir_ref src = ir_CONST_LONG(val);
4472
4473 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4474 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4475 }
4476 jit_set_Z_LVAL(jit, dst, src);
4477 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4478 return 1;
4479}
4480
4481static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4482{
4483 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4484 ir_ref src = ir_CONST_DOUBLE(val);
4485
4486 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4487 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4488 }
4489 jit_set_Z_DVAL(jit, dst, src);
4490 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4491 return 1;
4492}
4493
4494static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4495{
4496 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4497
4499 jit_set_Z_TYPE_INFO(jit, dst, type);
4500 return 1;
4501}
4502
4503static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4504{
4505 zend_jit_addr src;
4506 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4507 ir_type type;
4508
4509 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4510 type = IR_LONG;
4511 src = zend_jit_deopt_rload(jit, type, reg);
4512 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4513 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4514 } else if (!in_mem) {
4515 jit_set_Z_LVAL(jit, dst, src);
4516 if (set_type &&
4517 (Z_REG(dst) != ZREG_FP ||
4518 !JIT_G(current_frame) ||
4519 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4520 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4521 }
4522 }
4523 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4524 type = IR_DOUBLE;
4525 src = zend_jit_deopt_rload(jit, type, reg);
4526 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4527 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4528 } else if (!in_mem) {
4529 jit_set_Z_DVAL(jit, dst, src);
4530 if (set_type &&
4531 (Z_REG(dst) != ZREG_FP ||
4532 !JIT_G(current_frame) ||
4533 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4534 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4535 }
4536 }
4537 } else {
4539 }
4540 return 1;
4541}
4542
4543static int zend_jit_store_spill_slot(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, int32_t offset, bool set_type)
4544{
4545 zend_jit_addr src;
4546 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4547
4548 if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4550 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4551 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4552 } else {
4553 jit_set_Z_LVAL(jit, dst, src);
4554 if (set_type &&
4555 (Z_REG(dst) != ZREG_FP ||
4556 !JIT_G(current_frame) ||
4557 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4558 jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4559 }
4560 }
4561 } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4563 if (jit->ra && jit->ra[var].ref == IR_NULL) {
4564 zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4565 } else {
4566 jit_set_Z_DVAL(jit, dst, src);
4567 if (set_type &&
4568 (Z_REG(dst) != ZREG_FP ||
4569 !JIT_G(current_frame) ||
4570 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4571 jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4572 }
4573 }
4574 } else {
4576 }
4577 return 1;
4578}
4579
4580static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4581{
4582 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4583
4584 jit_set_Z_TYPE_INFO(jit, dst, type);
4585 return 1;
4586}
4587
4588static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4589{
4590 ir_ref if_refcounted, end1;
4591
4592 if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4593 ir_IF_FALSE(if_refcounted);
4594 end1 = ir_END();
4595 ir_IF_TRUE(if_refcounted);
4596 jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4597 ir_MERGE_WITH(end1);
4598 return 1;
4599}
4600
4601static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4602{
4603 if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4604 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4605 return zend_jit_spill_store(jit, src, dst, info, 1);
4606 }
4607 return 1;
4608}
4609
4610static 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)
4611{
4612 if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4613 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4614 bool set_type = 1;
4615
4616 if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4617 (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4618 if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4619 if (JIT_G(current_frame)) {
4620 uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4621
4622 if (mem_type != IS_UNKNOWN
4623 && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4624 set_type = 0;
4625 }
4626 } else {
4627 set_type = 0;
4628 }
4629 }
4630 }
4631 return zend_jit_spill_store(jit, src, dst, info, set_type);
4632 }
4633 return 1;
4634}
4635
4636static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4637{
4638 zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4639 zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4640
4641 return zend_jit_load_reg(jit, src, dst, info);
4642}
4643
4644static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4645{
4646 if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4647 /* Invalidate operand type to prevent incorrect destuction by exception_handler_free_op1_op2() */
4648 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4649 jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4650 }
4651 return 1;
4652}
4653
4654static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4655{
4656 if (!zend_jit_same_addr(src, dst)) {
4657 if (Z_MODE(src) == IS_REG) {
4658 if (Z_MODE(dst) == IS_REG) {
4659 zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4660 if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4661 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4662
4663 if (!zend_jit_spill_store(jit, dst, var_addr, info,
4664 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4665 JIT_G(current_frame) == NULL ||
4666 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4667 (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4668 )) {
4669 return 0;
4670 }
4671 }
4672 } else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4673 if (!Z_LOAD(src) && !Z_STORE(src)) {
4674 if (!zend_jit_spill_store(jit, src, dst, info,
4675 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4676 JIT_G(current_frame) == NULL ||
4677 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4678 (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4679 )) {
4680 return 0;
4681 }
4682 }
4683 } else {
4685 }
4686 } else if (Z_MODE(src) == IS_MEM_ZVAL) {
4687 if (Z_MODE(dst) == IS_REG) {
4688 if (!zend_jit_load_reg(jit, src, dst, info)) {
4689 return 0;
4690 }
4691 } else {
4693 }
4694 } else {
4696 }
4697 } else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4698 dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4699 if (!zend_jit_spill_store(jit, src, dst, info,
4700 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4701 JIT_G(current_frame) == NULL ||
4702 STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4703 (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4704 )) {
4705 return 0;
4706 }
4707 }
4708 return 1;
4709}
4710
4715
4716static 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) {
4717 ir_ref run_time_cache;
4718 struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4719 if (func) {
4720 ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4721 } else {
4722 // JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4723 ZEND_ASSERT(rx != IR_UNUSED);
4724 ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4725 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4727 ir_IF_TRUE(if_trampoline_or_generator);
4728 ir_END_list(data.ir_end_inputs);
4729 ir_IF_FALSE(if_trampoline_or_generator);
4730 }
4731 if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4732 // JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4733 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)));
4734#ifndef ZTS
4735 } else if (func && rx == IS_UNUSED) { // happens for internal functions only
4737 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4738#endif
4739 } else {
4740 // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4741 if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4742 run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4743 } else {
4744 // JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4745 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4746 ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4747 ir_IF_TRUE(if_odd);
4748
4749 ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4750
4751 ir_ref if_odd_end = ir_END();
4752 ir_IF_FALSE(if_odd);
4753
4754 // JIT: if (func->common.runtime_cache != NULL) {
4755 ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4756 ir_IF_TRUE(if_rt_cache);
4757 ir_END_list(data.ir_end_inputs);
4758 ir_IF_FALSE(if_rt_cache);
4759
4760 ir_MERGE_WITH(if_odd_end);
4761 run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4762 }
4763 }
4764 // JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4765 if (func) {
4766 *observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4767 } else {
4768 // JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4770 ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4771 ir_IF_TRUE(if_internal_func);
4772
4773 ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4774
4775 ir_ref if_internal_func_end = ir_END();
4776 ir_IF_FALSE(if_internal_func);
4777
4778 ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4779
4780 ir_MERGE_WITH(if_internal_func_end);
4781 *observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
4782 }
4783
4784 // JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4785 data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4786 ir_IF_FALSE(data.if_unobserved);
4787 return data;
4788}
4789
4790/* For frameless the true branch of if_unobserved is used and this function not called. */
4791static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4792 ir_END_list(data->ir_end_inputs);
4793 ir_IF_TRUE(data->if_unobserved);
4794 ir_END_list(data->ir_end_inputs);
4795 ir_MERGE_list(data->ir_end_inputs);
4796}
4797
4798static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4800}
4801
4802static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4803 // JIT: if (execute_data == EG(current_observed_frame)) {
4804 ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4805 ir_IF_TRUE(has_end_observer);
4807 rx, res_ref);
4808 ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4809}
4810
4811static 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)
4812{
4813 ir_ref if_long = IR_UNUSED;
4814 ir_ref op1_lval_ref = IR_UNUSED;
4815 ir_ref ref;
4816 ir_op op;
4817
4818 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4819 if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4820 ir_IF_TRUE(if_long);
4821 }
4822 if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4823 op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4824 jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4825 if (Z_MODE(res_addr) != IS_REG) {
4826 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4827 }
4828 }
4829 if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4830 && Z_MODE(op1_addr) == IS_REG
4831 && !Z_LOAD(op1_addr)
4832 && !Z_STORE(op1_addr)) {
4833 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4834 }
4835 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4836 op = may_overflow ? IR_ADD_OV : IR_ADD;
4837 } else {
4838 op = may_overflow ? IR_SUB_OV : IR_SUB;
4839 }
4840 if (!op1_lval_ref) {
4841 op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4842 }
4843 ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4844 if (op1_def_info & MAY_BE_LONG) {
4845 jit_set_Z_LVAL(jit, op1_def_addr, ref);
4846 }
4847 if (may_overflow &&
4848 (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4849 ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4850 int32_t exit_point;
4851 const void *exit_addr;
4852 zend_jit_trace_stack *stack;
4853 uint32_t old_op1_info, old_res_info = 0;
4854
4855 stack = JIT_G(current_frame)->stack;
4856 old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4857 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4858 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4859 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4860 } else {
4861 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4862 }
4863 if (opline->result_type != IS_UNUSED) {
4864 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4865 if (opline->opcode == ZEND_PRE_INC) {
4866 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4867 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4868 } else if (opline->opcode == ZEND_PRE_DEC) {
4869 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4870 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4871 } else if (opline->opcode == ZEND_POST_INC) {
4872 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4874 } else if (opline->opcode == ZEND_POST_DEC) {
4875 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4877 }
4878 }
4879
4880 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4881 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4882 ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4883
4884 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4885 opline->result_type != IS_UNUSED) {
4886 jit_set_Z_LVAL(jit, res_addr, ref);
4887 if (Z_MODE(res_addr) != IS_REG) {
4888 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4889 }
4890 }
4891
4892 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4893 if (opline->result_type != IS_UNUSED) {
4894 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4895 }
4896 } else if (may_overflow) {
4897 ir_ref if_overflow;
4898 ir_ref merge_inputs = IR_UNUSED;
4899
4900 if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4901 || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4902 int32_t exit_point;
4903 const void *exit_addr;
4904 zend_jit_trace_stack *stack;
4905 uint32_t old_res_info = 0;
4906
4907 stack = JIT_G(current_frame)->stack;
4908 if (opline->result_type != IS_UNUSED) {
4909 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4910 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4911 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4912 }
4913 }
4914 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4915 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4916 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4917 opline->result_type != IS_UNUSED) {
4918 if_overflow = ir_IF(ir_OVERFLOW(ref));
4919 ir_IF_FALSE_cold(if_overflow);
4920 jit_set_Z_LVAL(jit, res_addr, ref);
4921 if (Z_MODE(res_addr) != IS_REG) {
4922 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4923 }
4924 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
4925 ir_IF_TRUE(if_overflow);
4926 } else {
4927 ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4928 }
4929 if (opline->result_type != IS_UNUSED) {
4930 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4931 }
4932 } else {
4933 if_overflow = ir_IF(ir_OVERFLOW(ref));
4934 ir_IF_FALSE(if_overflow);
4935 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4936 opline->result_type != IS_UNUSED) {
4937 jit_set_Z_LVAL(jit, res_addr, ref);
4938 if (Z_MODE(res_addr) != IS_REG) {
4939 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4940 }
4941 }
4942 ir_END_list(merge_inputs);
4943
4944 /* overflow => cold path */
4945 ir_IF_TRUE_cold(if_overflow);
4946 }
4947
4948 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4949 if (Z_MODE(op1_def_addr) == IS_REG) {
4950 jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4951 } else {
4952#if SIZEOF_ZEND_LONG == 4
4953 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0));
4954 jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0x41e00000));
4955#else
4956 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4957#endif
4958 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4959 }
4960 } else {
4961 if (Z_MODE(op1_def_addr) == IS_REG) {
4962 jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4963 } else {
4964#if SIZEOF_ZEND_LONG == 4
4965 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x00200000));
4966 jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0xc1e00000));
4967#else
4968 jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4969#endif
4970 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4971 }
4972 }
4973 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4974 opline->result_type != IS_UNUSED) {
4975 if (opline->opcode == ZEND_PRE_INC) {
4976 if (Z_MODE(res_addr) == IS_REG) {
4977 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4978 } else {
4979#if SIZEOF_ZEND_LONG == 4
4980 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
4981 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
4982#else
4983 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4984#endif
4985 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4986 }
4987 } else {
4988 if (Z_MODE(res_addr) == IS_REG) {
4989 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4990 } else {
4991#if SIZEOF_ZEND_LONG == 4
4992 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
4993 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
4994#else
4995 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
4996#endif
4997 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4998 }
4999 }
5000 }
5001
5002 if (merge_inputs) {
5003 ir_END_list(merge_inputs);
5004 ir_MERGE_list(merge_inputs);
5005 }
5006 } else {
5007 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
5008 opline->result_type != IS_UNUSED) {
5009 jit_set_Z_LVAL(jit, res_addr, ref);
5010 if (Z_MODE(res_addr) != IS_REG) {
5011 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5012 }
5013 }
5014 }
5015 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5016 ir_ref merge_inputs = ir_END();
5017
5018 /* !is_long => cold path */
5019 ir_IF_FALSE_cold(if_long);
5020 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5021 jit_SET_EX_OPLINE(jit, opline);
5022 if (op1_info & MAY_BE_UNDEF) {
5023 ir_ref if_def;
5024
5025 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5026 ir_IF_FALSE_cold(if_def);
5027
5028 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5029 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5030
5031 jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
5033
5034 op1_info |= MAY_BE_NULL;
5035 }
5036
5037 ref = jit_ZVAL_ADDR(jit, op1_addr);
5038
5039 if (op1_info & MAY_BE_REF) {
5040 ir_ref if_ref, if_typed, func, ref2, arg2;
5041
5042 if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
5043 ir_IF_TRUE(if_ref);
5044 ref2 = jit_Z_PTR_ref(jit, ref);
5045
5046 if_typed = jit_if_TYPED_REF(jit, ref2);
5047 ir_IF_TRUE(if_typed);
5048
5049 if (RETURN_VALUE_USED(opline)) {
5050 ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
5051 arg2 = jit_ZVAL_ADDR(jit, res_addr);
5052 } else {
5053 arg2 = IR_NULL;
5054 }
5055 if (opline->opcode == ZEND_PRE_INC) {
5056 func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
5057 } else if (opline->opcode == ZEND_PRE_DEC) {
5058 func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
5059 } else if (opline->opcode == ZEND_POST_INC) {
5060 func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
5061 } else if (opline->opcode == ZEND_POST_DEC) {
5062 func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
5063 } else {
5065 }
5066
5067 ir_CALL_2(IR_VOID, func, ref2, arg2);
5068 zend_jit_check_exception(jit);
5069 ir_END_list(merge_inputs);
5070
5071 ir_IF_FALSE(if_typed);
5072 ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
5074 ref = ir_PHI_2(IR_ADDR, ref2, ref);
5075 }
5076
5077 if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
5078 jit_ZVAL_COPY(jit,
5079 res_addr,
5080 res_use_info,
5081 ZEND_ADDR_REF_ZVAL(ref), op1_info, 1);
5082 }
5083 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
5084 if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
5085 ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
5086 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
5087 } else {
5089 }
5090 } else {
5091 if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
5092 ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
5093 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec), ref, arg2);
5094 } else {
5096 }
5097 }
5098 if (may_throw) {
5099 zend_jit_check_exception(jit);
5100 }
5101 } else {
5102 ref = jit_Z_DVAL(jit, op1_addr);
5103 if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
5104 jit_set_Z_DVAL(jit, res_addr, ref);
5105 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5106 }
5107 if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
5108 op = IR_ADD;
5109 } else {
5110 op = IR_SUB;
5111 }
5112 ref = ir_BINARY_OP_D(op, ref, ir_CONST_DOUBLE(1.0));
5113 jit_set_Z_DVAL(jit, op1_def_addr, ref);
5114 if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
5115 opline->result_type != IS_UNUSED) {
5116 jit_set_Z_DVAL(jit, res_addr, ref);
5117 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5118 }
5119 }
5120 ir_END_list(merge_inputs);
5121 ir_MERGE_list(merge_inputs);
5122 }
5123 if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
5124 return 0;
5125 }
5126 if (opline->result_type != IS_UNUSED) {
5127 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5128 return 0;
5129 }
5130 }
5131 return 1;
5132}
5133
5134static int zend_jit_math_long_long(zend_jit_ctx *jit,
5135 const zend_op *opline,
5136 uint8_t opcode,
5137 zend_jit_addr op1_addr,
5138 zend_jit_addr op2_addr,
5139 zend_jit_addr res_addr,
5140 uint32_t res_info,
5141 uint32_t res_use_info,
5142 int may_overflow)
5143{
5144 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5145 ir_op op;
5146 ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
5147
5148 if (opcode == ZEND_ADD) {
5149 op = may_overflow ? IR_ADD_OV : IR_ADD;
5150 } else if (opcode == ZEND_SUB) {
5151 op = may_overflow ? IR_SUB_OV : IR_SUB;
5152 } else if (opcode == ZEND_MUL) {
5153 op = may_overflow ? IR_MUL_OV : IR_MUL;
5154 } else {
5156 }
5157 op1 = jit_Z_LVAL(jit, op1_addr);
5158 op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5159 ref = ir_BINARY_OP_L(op, op1, op2);
5160
5161 if (may_overflow) {
5162 if (res_info & MAY_BE_GUARD) {
5163 if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
5164 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5165 uint32_t old_res_info;
5166 int32_t exit_point;
5167 const void *exit_addr;
5168
5169 if (opline->opcode == ZEND_ADD
5170 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5171 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5172 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5173 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5174 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5175 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5176 } else if (opline->opcode == ZEND_SUB
5177 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5178 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5179 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5180 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5181 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5182 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5183 } else {
5184 exit_point = zend_jit_trace_get_exit_point(opline, 0);
5185 }
5186
5187 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5188 if (!exit_addr) {
5189 return 0;
5190 }
5191 ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5192 may_overflow = 0;
5193 } else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
5194 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
5195 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5196
5197 if (!exit_addr) {
5198 return 0;
5199 }
5200 ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5201 } else {
5203 }
5204 } else {
5205 if_overflow = ir_IF(ir_OVERFLOW(ref));
5206 ir_IF_FALSE(if_overflow);
5207 }
5208 }
5209
5210 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5211 jit_set_Z_LVAL(jit, res_addr, ref);
5212
5213 if (Z_MODE(res_addr) != IS_REG) {
5214 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5215 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5216 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5217 }
5218 }
5219 }
5220 }
5221
5222 if (may_overflow) {
5223 ir_ref fast_path = IR_UNUSED;
5224
5225 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5226 fast_path = ir_END();
5227 ir_IF_TRUE_cold(if_overflow);
5228 }
5229 if (opcode == ZEND_ADD) {
5230 if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5231 if (Z_MODE(res_addr) == IS_REG) {
5232 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5233 } else {
5234#if SIZEOF_ZEND_LONG == 4
5235 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
5236 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
5237#else
5238 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5239#endif
5240 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5241 }
5242 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5243 ir_MERGE_WITH(fast_path);
5244 }
5245 return 1;
5246 }
5247 op = IR_ADD;
5248 } else if (opcode == ZEND_SUB) {
5249 if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5250 if (Z_MODE(res_addr) == IS_REG) {
5251 jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5252 } else {
5253#if SIZEOF_ZEND_LONG == 4
5254 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
5255 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
5256#else
5257 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
5258#endif
5259 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5260 }
5261 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5262 ir_MERGE_WITH(fast_path);
5263 }
5264 return 1;
5265 }
5266 op = IR_SUB;
5267 } else if (opcode == ZEND_MUL) {
5268 op = IR_MUL;
5269 } else {
5271 }
5272#if 1
5273 /* reload */
5274 op1 = jit_Z_LVAL(jit, op1_addr);
5275 op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5276#endif
5277#if 1
5278 /* disable CSE */
5279 ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5280 jit->ctx.fold_cse_limit = 0x7fffffff;
5281#endif
5282 op1 = ir_INT2D(op1);
5283 op2 = ir_INT2D(op2);
5284#if 1
5285 jit->ctx.fold_cse_limit = old_cse_limit;
5286#endif
5287 ref = ir_BINARY_OP_D(op, op1, op2);
5288 jit_set_Z_DVAL(jit, res_addr, ref);
5289 if (Z_MODE(res_addr) != IS_REG) {
5290 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5291 }
5292 if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5293 ir_MERGE_WITH(fast_path);
5294 }
5295 }
5296
5297 return 1;
5298}
5299
5300static int zend_jit_math_long_double(zend_jit_ctx *jit,
5301 uint8_t opcode,
5302 zend_jit_addr op1_addr,
5303 zend_jit_addr op2_addr,
5304 zend_jit_addr res_addr,
5305 uint32_t res_use_info)
5306{
5307 ir_op op;
5308 ir_ref op1, op2, ref;
5309
5310 if (opcode == ZEND_ADD) {
5311 op = IR_ADD;
5312 } else if (opcode == ZEND_SUB) {
5313 op = IR_SUB;
5314 } else if (opcode == ZEND_MUL) {
5315 op = IR_MUL;
5316 } else if (opcode == ZEND_DIV) {
5317 op = IR_DIV;
5318 } else {
5320 }
5321 op1 = jit_Z_LVAL(jit, op1_addr);
5322 op2 = jit_Z_DVAL(jit, op2_addr);
5323 ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5324 jit_set_Z_DVAL(jit, res_addr, ref);
5325
5326 if (Z_MODE(res_addr) != IS_REG) {
5327 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5328 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5329 }
5330 }
5331 return 1;
5332}
5333
5334static int zend_jit_math_double_long(zend_jit_ctx *jit,
5335 uint8_t opcode,
5336 zend_jit_addr op1_addr,
5337 zend_jit_addr op2_addr,
5338 zend_jit_addr res_addr,
5339 uint32_t res_use_info)
5340{
5341 ir_op op;
5342 ir_ref op1, op2, ref;
5343
5344 if (opcode == ZEND_ADD) {
5345 op = IR_ADD;
5346 } else if (opcode == ZEND_SUB) {
5347 op = IR_SUB;
5348 } else if (opcode == ZEND_MUL) {
5349 op = IR_MUL;
5350 } else if (opcode == ZEND_DIV) {
5351 op = IR_DIV;
5352 } else {
5354 }
5355 op1 = jit_Z_DVAL(jit, op1_addr);
5356 op2 = jit_Z_LVAL(jit, op2_addr);
5357 ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5358 jit_set_Z_DVAL(jit, res_addr, ref);
5359
5360 if (Z_MODE(res_addr) != IS_REG) {
5361 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5362 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5363 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5364 }
5365 }
5366 }
5367 return 1;
5368}
5369
5370static int zend_jit_math_double_double(zend_jit_ctx *jit,
5371 uint8_t opcode,
5372 zend_jit_addr op1_addr,
5373 zend_jit_addr op2_addr,
5374 zend_jit_addr res_addr,
5375 uint32_t res_use_info)
5376{
5377 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5378 ir_op op;
5379 ir_ref op1, op2, ref;
5380
5381 if (opcode == ZEND_ADD) {
5382 op = IR_ADD;
5383 } else if (opcode == ZEND_SUB) {
5384 op = IR_SUB;
5385 } else if (opcode == ZEND_MUL) {
5386 op = IR_MUL;
5387 } else if (opcode == ZEND_DIV) {
5388 op = IR_DIV;
5389 } else {
5391 }
5392 op1 = jit_Z_DVAL(jit, op1_addr);
5393 op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5394 ref = ir_BINARY_OP_D(op, op1, op2);
5395 jit_set_Z_DVAL(jit, res_addr, ref);
5396
5397 if (Z_MODE(res_addr) != IS_REG) {
5398 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5399 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5400 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5401 }
5402 }
5403 }
5404 return 1;
5405}
5406
5407static int zend_jit_math_helper(zend_jit_ctx *jit,
5408 const zend_op *opline,
5409 uint8_t opcode,
5410 uint8_t op1_type,
5411 znode_op op1,
5412 zend_jit_addr op1_addr,
5413 uint32_t op1_info,
5414 uint8_t op2_type,
5415 znode_op op2,
5416 zend_jit_addr op2_addr,
5417 uint32_t op2_info,
5418 uint32_t res_var,
5419 zend_jit_addr res_addr,
5420 uint32_t res_info,
5421 uint32_t res_use_info,
5422 int may_overflow,
5423 int may_throw)
5424{
5425 ir_ref if_op1_long = IR_UNUSED;
5426 ir_ref if_op1_double = IR_UNUSED;
5427 ir_ref if_op2_double = IR_UNUSED;
5428 ir_ref if_op1_long_op2_long = IR_UNUSED;
5429 ir_ref if_op1_long_op2_double = IR_UNUSED;
5430 ir_ref if_op1_double_op2_double = IR_UNUSED;
5431 ir_ref if_op1_double_op2_long = IR_UNUSED;
5432 ir_ref slow_inputs = IR_UNUSED;
5433 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5434 ir_refs *end_inputs;
5435 ir_refs *res_inputs;
5436
5437 ir_refs_init(end_inputs, 6);
5438 ir_refs_init(res_inputs, 6);
5439
5440 if (Z_MODE(op1_addr) == IS_REG) {
5441 if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5442 /* Force load */
5443 zend_jit_use_reg(jit, op1_addr);
5444 }
5445 } else if (Z_MODE(op2_addr) == IS_REG) {
5446 if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5447 /* Force load */
5448 zend_jit_use_reg(jit, op2_addr);
5449 }
5450 }
5451
5452 if (Z_MODE(res_addr) == IS_REG) {
5453 jit->delay_var = Z_SSA_VAR(res_addr);
5454 jit->delay_refs = res_inputs;
5455 }
5456
5457 if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5458 if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5459 if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5460 ir_IF_TRUE(if_op1_long);
5461 }
5462 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5463 if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5464 ir_IF_TRUE(if_op1_long_op2_long);
5465 }
5466 if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5467 return 0;
5468 }
5469 ir_refs_add(end_inputs, ir_END());
5470 if (if_op1_long) {
5471 ir_IF_FALSE_cold(if_op1_long);
5472 ir_END_list(slow_inputs);
5473 }
5474 if (if_op1_long_op2_long) {
5475 ir_IF_FALSE_cold(if_op1_long_op2_long);
5476 ir_END_list(slow_inputs);
5477 }
5478 } else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
5479 if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5480 if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5481 ir_IF_TRUE(if_op1_long);
5482 }
5483 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5484 if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5485 ir_IF_FALSE_cold(if_op1_long_op2_long);
5486 if (op2_info & MAY_BE_DOUBLE) {
5487 if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5488 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5489 ir_IF_FALSE_cold(if_op1_long_op2_double);
5490 ir_END_list(slow_inputs);
5491 ir_IF_TRUE(if_op1_long_op2_double);
5492 }
5493 if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5494 return 0;
5495 }
5496 ir_refs_add(end_inputs, ir_END());
5497 } else {
5498 ir_END_list(slow_inputs);
5499 }
5500 ir_IF_TRUE(if_op1_long_op2_long);
5501 }
5502 if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5503 return 0;
5504 }
5505 ir_refs_add(end_inputs, ir_END());
5506
5507 if (if_op1_long) {
5508 ir_IF_FALSE_cold(if_op1_long);
5509 }
5510
5511 if (op1_info & MAY_BE_DOUBLE) {
5512 if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5513 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5514 ir_IF_FALSE_cold(if_op1_double);
5515 ir_END_list(slow_inputs);
5516 ir_IF_TRUE(if_op1_double);
5517 }
5518 if (op2_info & MAY_BE_DOUBLE) {
5519 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5520 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5521 ir_IF_TRUE(if_op1_double_op2_double);
5522 }
5523 if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5524 return 0;
5525 }
5526 ir_refs_add(end_inputs, ir_END());
5527 if (if_op1_double_op2_double) {
5528 ir_IF_FALSE_cold(if_op1_double_op2_double);
5529 }
5530 }
5531 if (!same_ops) {
5532 if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5533 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5534 ir_IF_FALSE_cold(if_op1_double_op2_long);
5535 ir_END_list(slow_inputs);
5536 ir_IF_TRUE(if_op1_double_op2_long);
5537 }
5538 if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5539 return 0;
5540 }
5541 ir_refs_add(end_inputs, ir_END());
5542 } else if (if_op1_double_op2_double) {
5543 ir_END_list(slow_inputs);
5544 }
5545 } else if (if_op1_long) {
5546 ir_END_list(slow_inputs);
5547 }
5548 } else if ((op1_info & MAY_BE_DOUBLE) &&
5549 !(op1_info & MAY_BE_LONG) &&
5550 (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5551 (res_info & MAY_BE_DOUBLE)) {
5552 if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5553 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5554 ir_IF_FALSE_cold(if_op1_double);
5555 ir_END_list(slow_inputs);
5556 ir_IF_TRUE(if_op1_double);
5557 }
5558 if (op2_info & MAY_BE_DOUBLE) {
5559 if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5560 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5561 ir_IF_TRUE(if_op1_double_op2_double);
5562 }
5563 if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5564 return 0;
5565 }
5566 ir_refs_add(end_inputs, ir_END());
5567 if (if_op1_double_op2_double) {
5568 ir_IF_FALSE_cold(if_op1_double_op2_double);
5569 }
5570 }
5571 if (!same_ops && (op2_info & MAY_BE_LONG)) {
5572 if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5573 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5574 ir_IF_FALSE_cold(if_op1_double_op2_long);
5575 ir_END_list(slow_inputs);
5576 ir_IF_TRUE(if_op1_double_op2_long);
5577 }
5578 if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5579 return 0;
5580 }
5581 ir_refs_add(end_inputs, ir_END());
5582 } else if (if_op1_double_op2_double) {
5583 ir_END_list(slow_inputs);
5584 }
5585 } else if ((op2_info & MAY_BE_DOUBLE) &&
5586 !(op2_info & MAY_BE_LONG) &&
5587 (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5588 (res_info & MAY_BE_DOUBLE)) {
5589 if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5590 if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5591 ir_IF_FALSE_cold(if_op2_double);
5592 ir_END_list(slow_inputs);
5593 ir_IF_TRUE(if_op2_double);
5594 }
5595 if (op1_info & MAY_BE_DOUBLE) {
5596 if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5597 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5598 ir_IF_TRUE(if_op1_double_op2_double);
5599 }
5600 if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5601 return 0;
5602 }
5603 ir_refs_add(end_inputs, ir_END());
5604 if (if_op1_double_op2_double) {
5605 ir_IF_FALSE_cold(if_op1_double_op2_double);
5606 }
5607 }
5608 if (!same_ops && (op1_info & MAY_BE_LONG)) {
5609 if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5610 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5611 ir_IF_FALSE_cold(if_op1_long_op2_double);
5612 ir_END_list(slow_inputs);
5613 ir_IF_TRUE(if_op1_long_op2_double);
5614 }
5615 if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5616 return 0;
5617 }
5618 ir_refs_add(end_inputs, ir_END());
5619 } else if (if_op1_double_op2_double) {
5620 ir_END_list(slow_inputs);
5621 }
5622 }
5623
5624 if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5625 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5627
5628 if (slow_inputs) {
5629 ir_MERGE_list(slow_inputs);
5630 }
5631
5632 if (Z_MODE(op1_addr) == IS_REG) {
5633 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5634 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5635 return 0;
5636 }
5637 op1_addr = real_addr;
5638 }
5639 if (Z_MODE(op2_addr) == IS_REG) {
5640 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5641 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5642 return 0;
5643 }
5644 op2_addr = real_addr;
5645 }
5646 if (Z_MODE(res_addr) == IS_REG) {
5647 arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5648 } else {
5649 arg1 = jit_ZVAL_ADDR(jit, res_addr);
5650 }
5651 arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5652 arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5653 jit_SET_EX_OPLINE(jit, opline);
5654 if (opcode == ZEND_ADD) {
5656 } else if (opcode == ZEND_SUB) {
5658 } else if (opcode == ZEND_MUL) {
5660 } else if (opcode == ZEND_DIV) {
5662 } else {
5664 }
5666
5667 jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5668 jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5669
5670 if (may_throw) {
5671 if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5672 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5673 jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5674 } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5675 zend_jit_check_exception_undef_result(jit, opline);
5676 } else {
5677 zend_jit_check_exception(jit);
5678 }
5679 }
5680 if (Z_MODE(res_addr) == IS_REG) {
5681 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5682 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5683 return 0;
5684 }
5685 }
5686 ir_refs_add(end_inputs, ir_END());
5687 }
5688
5689 if (end_inputs->count) {
5690 ir_MERGE_N(end_inputs->count, end_inputs->refs);
5691 }
5692
5693 if (Z_MODE(res_addr) == IS_REG) {
5694 ZEND_ASSERT(jit->delay_refs == res_inputs);
5695 ZEND_ASSERT(end_inputs->count == res_inputs->count);
5696 jit->delay_var = -1;
5697 jit->delay_refs = NULL;
5698 if (res_inputs->count == 1) {
5699 zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5700 } else {
5701 ir_ref phi = ir_PHI_N((res_info & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE, res_inputs->count, res_inputs->refs);
5702 zend_jit_def_reg(jit, res_addr, phi);
5703 }
5704 }
5705
5706 return 1;
5707}
5708
5709static 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)
5710{
5711 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5712
5713 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)) {
5714 return 0;
5715 }
5716 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5717 return 0;
5718 }
5719 return 1;
5720}
5721
5722static 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)
5723{
5724 ir_ref ref;
5725 ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5726 ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5727
5728 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5729 jit_set_Z_PTR(jit, res_addr, ref);
5730 jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5731 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5732 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5733 return 1;
5734}
5735
5736static int zend_jit_long_math_helper(zend_jit_ctx *jit,
5737 const zend_op *opline,
5738 uint8_t opcode,
5739 uint8_t op1_type,
5740 znode_op op1,
5741 zend_jit_addr op1_addr,
5742 uint32_t op1_info,
5743 zend_ssa_range *op1_range,
5744 uint8_t op2_type,
5745 znode_op op2,
5746 zend_jit_addr op2_addr,
5747 uint32_t op2_info,
5748 zend_ssa_range *op2_range,
5749 uint32_t res_var,
5750 zend_jit_addr res_addr,
5751 uint32_t res_info,
5752 uint32_t res_use_info,
5753 int may_throw)
5754{
5755 ir_ref ref = IR_UNUSED;
5756 ir_ref if_long1 = IR_UNUSED;
5757 ir_ref if_long2 = IR_UNUSED;
5758 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5759 ir_refs *res_inputs;
5760
5761 ir_refs_init(res_inputs, 2);
5762
5763 if (Z_MODE(op1_addr) == IS_REG
5764 && Z_LOAD(op1_addr)
5765 && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5766 /* Force load */
5767 zend_jit_use_reg(jit, op1_addr);
5768 }
5769 if (Z_MODE(op2_addr) == IS_REG
5770 && Z_LOAD(op2_addr)
5771 && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5772 /* Force load */
5773 zend_jit_use_reg(jit, op2_addr);
5774 }
5775
5776 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5777 if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5778 ir_IF_TRUE(if_long1);
5779 }
5780 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5781 if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5782 ir_IF_TRUE(if_long2);
5783 }
5784
5785 if (opcode == ZEND_SL) {
5786 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5787 zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5788
5789 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5790 if (EXPECTED(op2_lval > 0)) {
5791 ref = ir_CONST_LONG(0);
5792 } else {
5793 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5794 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5795 jit_SET_EX_OPLINE(jit, opline);
5796 ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5797 if (Z_MODE(res_addr) == IS_REG) {
5798 ref = ir_CONST_LONG(0); // dead code
5799 }
5800 }
5801 } else {
5802 ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5803 }
5804 } else {
5805 ref = jit_Z_LVAL(jit, op2_addr);
5806 if (!op2_range ||
5807 op2_range->min < 0 ||
5808 op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5809
5810 ir_ref if_wrong, cold_path, ref2, if_ok;
5811 ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5812
5813 if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5814 ir_IF_TRUE_cold(if_wrong);
5815 if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5816 ir_IF_FALSE(if_ok);
5817 jit_SET_EX_OPLINE(jit, opline);
5818 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5819 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5820 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5821 ir_IF_TRUE(if_ok);
5822 ref2 = ir_CONST_LONG(0);
5823 cold_path = ir_END();
5824 ir_IF_FALSE(if_wrong);
5825 ref = ir_SHL_L(op1_ref, ref);
5826 ir_MERGE_WITH(cold_path);
5827 ref = ir_PHI_2(IR_LONG, ref, ref2);
5828 } else {
5829 ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5830 }
5831 }
5832 } else if (opcode == ZEND_SR) {
5833 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5834 zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5835
5836 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5837 if (EXPECTED(op2_lval > 0)) {
5838 ref = ir_SAR_L(
5839 jit_Z_LVAL(jit, op1_addr),
5840 ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5841 } else {
5842 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5843 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5844 jit_SET_EX_OPLINE(jit, opline);
5845 ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5846 if (Z_MODE(res_addr) == IS_REG) {
5847 ref = ir_CONST_LONG(0); // dead code
5848 }
5849 }
5850 } else {
5851 ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5852 }
5853 } else {
5854 ref = jit_Z_LVAL(jit, op2_addr);
5855 if (!op2_range ||
5856 op2_range->min < 0 ||
5857 op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5858
5859 ir_ref if_wrong, cold_path, ref2, if_ok;
5860
5861 if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5862 ir_IF_TRUE_cold(if_wrong);
5863 if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5864 ir_IF_FALSE(if_ok);
5865 jit_SET_EX_OPLINE(jit, opline);
5866 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5867 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5868 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5869 ir_IF_TRUE(if_ok);
5870 ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5871 cold_path = ir_END();
5872 ir_IF_FALSE(if_wrong);
5873 ir_MERGE_WITH(cold_path);
5874 ref = ir_PHI_2(IR_LONG, ref, ref2);
5875 }
5876 ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5877 }
5878 } else if (opcode == ZEND_MOD) {
5879 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5880 zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5881
5882 if (op2_lval == 0) {
5883 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5884 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5885 jit_SET_EX_OPLINE(jit, opline);
5886 ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5887 if (Z_MODE(res_addr) == IS_REG) {
5888 ref = ir_CONST_LONG(0); // dead code
5889 }
5890 } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5891 ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5892 } else {
5893 ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5894 }
5895 } else {
5896 ir_ref zero_path = 0;
5897 ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5898
5899 ref = jit_Z_LVAL(jit, op2_addr);
5900 if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5901 ir_ref if_ok = ir_IF(ref);
5902 ir_IF_FALSE(if_ok);
5903 jit_SET_EX_OPLINE(jit, opline);
5904 zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5905 zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5906 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5907 ir_IF_TRUE(if_ok);
5908 }
5909
5910 /* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5911 if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5912 ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5913 ir_IF_TRUE_cold(if_minus_one);
5914 zero_path = ir_END();
5915 ir_IF_FALSE(if_minus_one);
5916 }
5917 ref = ir_MOD_L(op1_ref, ref);
5918
5919 if (zero_path) {
5920 ir_MERGE_WITH(zero_path);
5921 ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5922 }
5923 }
5924 } else {
5925 ir_op op;
5926 ir_ref op1, op2;
5927
5928 if (opcode == ZEND_BW_OR) {
5929 op = IR_OR;
5930 } else if (opcode == ZEND_BW_AND) {
5931 op = IR_AND;
5932 } else if (opcode == ZEND_BW_XOR) {
5933 op = IR_XOR;
5934 } else {
5936 }
5937 op1 = jit_Z_LVAL(jit, op1_addr);
5938 op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5939 ref = ir_BINARY_OP_L(op, op1, op2);
5940 }
5941
5942 if (ref) {
5943 if (Z_MODE(res_addr) == IS_REG
5944 && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5945 || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5946 jit->delay_var = Z_SSA_VAR(res_addr);
5947 jit->delay_refs = res_inputs;
5948 }
5949 jit_set_Z_LVAL(jit, res_addr, ref);
5950 if (Z_MODE(res_addr) != IS_REG) {
5951 if (!zend_jit_same_addr(op1_addr, res_addr)) {
5952 if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5953 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5954 }
5955 }
5956 }
5957 }
5958
5959 if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5960 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5961 ir_ref fast_path = ir_END();
5963
5964 if (if_long2 && if_long1) {
5965 ir_ref ref;
5966 ir_IF_FALSE_cold(if_long2);
5967 ref = ir_END();
5968 ir_IF_FALSE_cold(if_long1);
5969 ir_MERGE_2(ref, ir_END());
5970 } else if (if_long1) {
5971 ir_IF_FALSE_cold(if_long1);
5972 } else if (if_long2) {
5973 ir_IF_FALSE_cold(if_long2);
5974 }
5975
5976 if (op1_info & MAY_BE_UNDEF) {
5977 ir_ref if_def, ref, ref2;
5978
5979 ref = jit_ZVAL_ADDR(jit, op1_addr);
5980 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5981 ir_IF_FALSE_cold(if_def);
5982
5983 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5984 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5985
5986 ref2 = jit_EG(uninitialized_zval);
5988 ref = ir_PHI_2(IR_ADDR, ref2, ref);
5989 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5990 }
5991
5992 if (op2_info & MAY_BE_UNDEF) {
5993 ir_ref if_def, ref, ref2;
5994
5995 ref = jit_ZVAL_ADDR(jit, op2_addr);
5996 if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5997 ir_IF_FALSE_cold(if_def);
5998
5999 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
6000 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
6001
6002 ref2 = jit_EG(uninitialized_zval);
6004 ref = ir_PHI_2(IR_ADDR, ref2, ref);
6005 op2_addr = ZEND_ADDR_REF_ZVAL(ref);
6006 }
6007
6008 if (Z_MODE(op1_addr) == IS_REG) {
6009 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
6010 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
6011 return 0;
6012 }
6013 op1_addr = real_addr;
6014 }
6015 if (Z_MODE(op2_addr) == IS_REG) {
6016 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
6017 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6018 return 0;
6019 }
6020 op2_addr = real_addr;
6021 }
6022 if (Z_MODE(res_addr) == IS_REG) {
6023 arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
6024 } else {
6025 arg1 = jit_ZVAL_ADDR(jit, res_addr);
6026 }
6027 arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6028 arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6029 jit_SET_EX_OPLINE(jit, opline);
6030 if (opcode == ZEND_BW_OR) {
6032 } else if (opcode == ZEND_BW_AND) {
6034 } else if (opcode == ZEND_BW_XOR) {
6036 } else if (opcode == ZEND_SL) {
6038 } else if (opcode == ZEND_SR) {
6040 } else if (opcode == ZEND_MOD) {
6042 } else {
6044 }
6046
6047 if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
6048 /* compound assignment may decrement "op2" refcount */
6049 op2_info |= MAY_BE_RC1;
6050 }
6051
6052 jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6053 jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6054
6055 if (may_throw) {
6056 if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6057 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6058 jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6059 } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6060 zend_jit_check_exception_undef_result(jit, opline);
6061 } else {
6062 zend_jit_check_exception(jit);
6063 }
6064 }
6065
6066 if (Z_MODE(res_addr) == IS_REG) {
6067 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
6068 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
6069 return 0;
6070 }
6071 }
6072
6073 ir_MERGE_2(fast_path, ir_END());
6074
6075 if (Z_MODE(res_addr) == IS_REG) {
6076 ZEND_ASSERT(jit->delay_refs == res_inputs);
6077 ZEND_ASSERT(res_inputs->count == 2);
6078 jit->delay_var = -1;
6079 jit->delay_refs = NULL;
6080 if (res_inputs->count == 1) {
6081 zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
6082 } else {
6083 ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
6084 zend_jit_def_reg(jit, res_addr, phi);
6085 }
6086 }
6087 }
6088
6089 return 1;
6090}
6091
6092static 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)
6093{
6094 ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
6095
6096 if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
6097 opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6098 opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6099 opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
6100 return 0;
6101 }
6102 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6103 return 0;
6104 }
6105 return 1;
6106}
6107
6108static int zend_jit_concat_helper(zend_jit_ctx *jit,
6109 const zend_op *opline,
6110 uint8_t op1_type,
6111 znode_op op1,
6112 zend_jit_addr op1_addr,
6113 uint32_t op1_info,
6114 uint8_t op2_type,
6115 znode_op op2,
6116 zend_jit_addr op2_addr,
6117 uint32_t op2_info,
6118 zend_jit_addr res_addr,
6119 int may_throw)
6120{
6121 ir_ref if_op1_string = IR_UNUSED;
6122 ir_ref if_op2_string = IR_UNUSED;
6123 ir_ref fast_path = IR_UNUSED;
6124
6125 if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6126 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
6127 if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
6128 ir_IF_TRUE(if_op1_string);
6129 }
6130 if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
6131 if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
6132 ir_IF_TRUE(if_op2_string);
6133 }
6134 if (zend_jit_same_addr(op1_addr, res_addr)) {
6135 ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6136 ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6137
6138 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
6139 /* concatenation with itself may reduce refcount */
6140 op2_info |= MAY_BE_RC1;
6141 } else {
6142 ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6143 ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6144 ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6145
6146 if (op1_type == IS_CV || op1_type == IS_CONST) {
6147 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
6148 } else {
6149 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
6150 }
6151 }
6152 /* concatenation with empty string may increase refcount */
6153 op2_info |= MAY_BE_RCN;
6154 jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
6155 if (if_op1_string || if_op2_string) {
6156 fast_path = ir_END();
6157 }
6158 }
6159 if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
6160 (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
6161 if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6162 if (if_op1_string && if_op2_string) {
6163 ir_IF_FALSE(if_op1_string);
6164 ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
6165 } else if (if_op1_string) {
6166 ir_IF_FALSE_cold(if_op1_string);
6167 } else if (if_op2_string) {
6168 ir_IF_FALSE_cold(if_op2_string);
6169 }
6170 }
6171 ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6172 ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6173 ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6174
6175 jit_SET_EX_OPLINE(jit, opline);
6177 /* concatenation with empty string may increase refcount */
6178 op1_info |= MAY_BE_RCN;
6179 op2_info |= MAY_BE_RCN;
6180 jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6181 jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6182 if (may_throw) {
6183 if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6184 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6185 jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6186 } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6187 zend_jit_check_exception_undef_result(jit, opline);
6188 } else {
6189 zend_jit_check_exception(jit);
6190 }
6191 }
6192 if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6193 ir_MERGE_WITH(fast_path);
6194 }
6195 }
6196 return 1;
6197}
6198
6199static 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)
6200{
6201 zend_jit_addr op1_addr, op2_addr;
6202
6203 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6204 ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
6205
6206 op1_addr = OP1_ADDR();
6207 op2_addr = OP2_ADDR();
6208
6209 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);
6210}
6211
6212static int zend_jit_assign_op(zend_jit_ctx *jit,
6213 const zend_op *opline,
6214 uint32_t op1_info,
6215 zend_jit_addr op1_addr,
6216 zend_ssa_range *op1_range,
6217 uint32_t op1_def_info,
6218 zend_jit_addr op1_def_addr,
6219 uint32_t op1_mem_info,
6220 uint32_t op2_info,
6221 zend_jit_addr op2_addr,
6222 zend_ssa_range *op2_range,
6223 int may_overflow,
6224 int may_throw)
6225{
6226 int result = 1;
6227 ir_ref slow_path = IR_UNUSED;
6228
6229 ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6230 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6231
6232 if (op1_info & MAY_BE_REF) {
6233 ir_ref ref, ref2, arg2, op1_noref_path;
6234 ir_ref if_op1_ref = IR_UNUSED;
6235 ir_ref if_op1_typed = IR_UNUSED;
6236 binary_op_type binary_op = get_binary_op(opline->extended_value);
6237
6238 ref = jit_ZVAL_ADDR(jit, op1_addr);
6239 if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6240 ir_IF_FALSE(if_op1_ref);
6241 op1_noref_path = ir_END();
6242 ir_IF_TRUE(if_op1_ref);
6243 ref2 = jit_Z_PTR_ref(jit, ref);
6244
6245 if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6246 ir_IF_TRUE_cold(if_op1_typed);
6247
6248 if (Z_MODE(op2_addr) == IS_REG) {
6249 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6250 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6251 return 0;
6252 }
6253 arg2 = jit_ZVAL_ADDR(jit, real_addr);
6254 } else {
6255 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6256 }
6257 jit_SET_EX_OPLINE(jit, opline);
6258 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6260 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6261 ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6262 } else {
6263 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6264 ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6265 }
6266 zend_jit_check_exception(jit);
6267 slow_path = ir_END();
6268
6269 ir_IF_FALSE(if_op1_typed);
6270 ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6271
6272 ir_MERGE_WITH(op1_noref_path);
6273 ref = ir_PHI_2(IR_ADDR, ref2, ref);
6274 ZEND_ASSERT(op1_addr == op1_def_addr);
6275 op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6276 }
6277
6278 switch (opline->extended_value) {
6279 case ZEND_ADD:
6280 case ZEND_SUB:
6281 case ZEND_MUL:
6282 case ZEND_DIV:
6283 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);
6284 break;
6285 case ZEND_BW_OR:
6286 case ZEND_BW_AND:
6287 case ZEND_BW_XOR:
6288 case ZEND_SL:
6289 case ZEND_SR:
6290 case ZEND_MOD:
6291 result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6292 opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6293 opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6294 opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6295 break;
6296 case ZEND_CONCAT:
6297 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);
6298 break;
6299 default:
6301 }
6302
6303 if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
6304 return 0;
6305 }
6306
6307 if (op1_info & MAY_BE_REF) {
6308 ir_MERGE_WITH(slow_path);
6309 }
6310
6311 return result;
6312}
6313
6314static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6315{
6316 ir_ref if_ref, ref2;
6317
6318 if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6319 ir_IF_TRUE(if_ref);
6320 ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6322 return ir_PHI_2(IR_ADDR, ref2, ref);
6323}
6324
6325static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6326{
6327 ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6328 ref = jit_ZVAL_DEREF_ref(jit, ref);
6329 return ZEND_ADDR_REF_ZVAL(ref);
6330}
6331
6332static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6333{
6334 ir_ref if_ref, ref2;
6335
6336 if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6337 ir_IF_TRUE(if_ref);
6338 ref2 = jit_Z_PTR_ref(jit, ref);
6340 return ir_PHI_2(IR_ADDR, ref2, ref);
6341}
6342
6343static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6344{
6345 ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6346 ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6347 return ZEND_ADDR_REF_ZVAL(ref);
6348}
6349
6350static int zend_jit_simple_assign(zend_jit_ctx *jit,
6351 const zend_op *opline,
6352 zend_jit_addr var_addr,
6353 uint32_t var_info,
6354 uint32_t var_def_info,
6355 uint8_t val_type,
6356 zend_jit_addr val_addr,
6357 uint32_t val_info,
6358 zend_jit_addr res_addr,
6359 bool check_exception)
6360{
6361 ir_ref end_inputs = IR_UNUSED;
6362
6363 if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6364 zval *zv = Z_ZV(val_addr);
6365
6366 if (!res_addr) {
6367 jit_ZVAL_COPY_CONST(jit,
6368 var_addr,
6369 var_info, var_def_info,
6370 zv, 1);
6371 } else {
6372 jit_ZVAL_COPY_CONST(jit,
6373 var_addr,
6374 var_info, var_def_info,
6375 zv, 1);
6376 jit_ZVAL_COPY_CONST(jit,
6377 res_addr,
6378 -1, var_def_info,
6379 zv, 1);
6380 }
6381 } else {
6382 if (val_info & MAY_BE_UNDEF) {
6383 ir_ref if_def, ret;
6384
6385 if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6386 ir_IF_FALSE_cold(if_def);
6387
6388 jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6389 if (res_addr) {
6390 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6391 }
6392 jit_SET_EX_OPLINE(jit, opline);
6393
6394 ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6395 // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6396 ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6397
6398 if (check_exception) {
6399 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6400 }
6401
6402 ir_END_list(end_inputs);
6403 ir_IF_TRUE(if_def);
6404 }
6405 if (val_info & MAY_BE_REF) {
6406 if (val_type == IS_CV) {
6407 ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6408 ref = jit_ZVAL_DEREF_ref(jit, ref);
6409 val_addr = ZEND_ADDR_REF_ZVAL(ref);
6410 } else {
6411 ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6412
6413 ref = jit_ZVAL_ADDR(jit, val_addr);
6414 type = jit_Z_TYPE_ref(jit, ref);
6416
6417 ir_IF_TRUE_cold(if_ref);
6418 ref = jit_Z_PTR_ref(jit, ref);
6420 if (!res_addr) {
6421 jit_ZVAL_COPY(jit,
6422 var_addr,
6423 var_info,
6424 ZEND_ADDR_REF_ZVAL(ref2), val_info, 1);
6425 } else {
6426 jit_ZVAL_COPY_2(jit,
6427 res_addr,
6428 var_addr,
6429 var_info,
6430 ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6431 }
6432
6433 refcount = jit_GC_DELREF(jit, ref);
6434 if_not_zero = ir_IF(refcount);
6435 ir_IF_FALSE(if_not_zero);
6436 // TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6437 // This is related to GH-10168 (keep this before GH-10168 is completely closed)
6438 // jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6439 jit_ZVAL_DTOR(jit, ref, val_info, opline);
6440 ir_END_list(end_inputs);
6441 ir_IF_TRUE(if_not_zero);
6442 ir_END_list(end_inputs);
6443
6444 ir_IF_FALSE(if_ref);
6445 }
6446 }
6447
6448 if (!res_addr) {
6449 jit_ZVAL_COPY(jit,
6450 var_addr,
6451 var_info,
6452 val_addr, val_info, val_type == IS_CV);
6453 } else {
6454 jit_ZVAL_COPY_2(jit,
6455 res_addr,
6456 var_addr,
6457 var_info,
6458 val_addr, val_info, val_type == IS_CV ? 2 : 1);
6459 }
6460 }
6461
6462 if (end_inputs) {
6463 ir_END_list(end_inputs);
6464 ir_MERGE_list(end_inputs);
6465 }
6466
6467 return 1;
6468}
6469
6470static int zend_jit_assign_to_variable_call(zend_jit_ctx *jit,
6471 const zend_op *opline,
6472 zend_jit_addr __var_use_addr,
6473 zend_jit_addr var_addr,
6474 uint32_t __var_info,
6475 uint32_t __var_def_info,
6476 uint8_t val_type,
6477 zend_jit_addr val_addr,
6478 uint32_t val_info,
6479 zend_jit_addr __res_addr,
6480 bool __check_exception)
6481{
6483 ir_ref undef_path = IR_UNUSED;
6484
6485 if (val_info & MAY_BE_UNDEF) {
6486 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6487 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6488 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6489
6490 if (!exit_addr) {
6491 return 0;
6492 }
6493
6494 jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6495 } else {
6496 ir_ref if_def;
6497
6498 ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6499 if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6500 ir_IF_FALSE_cold(if_def);
6501 jit_SET_EX_OPLINE(jit, opline);
6502 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6503
6504 ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6505 jit_ZVAL_ADDR(jit, var_addr),
6506 jit_EG(uninitialized_zval));
6507
6508 undef_path = ir_END();
6509 ir_IF_TRUE(if_def);
6510 }
6511 }
6512
6514 func = jit_stub_assign_tmp;
6515 } else if (val_type == IS_CONST) {
6516 func = jit_stub_assign_const;
6517 } else if (val_type == IS_TMP_VAR) {
6518 func = jit_stub_assign_tmp;
6519 } else if (val_type == IS_VAR) {
6520 if (!(val_info & MAY_BE_REF)) {
6521 func = jit_stub_assign_tmp;
6522 } else {
6523 func = jit_stub_assign_var;
6524 }
6525 } else if (val_type == IS_CV) {
6526 if (!(val_info & MAY_BE_REF)) {
6527 func = jit_stub_assign_cv_noref;
6528 } else {
6529 func = jit_stub_assign_cv;
6530 }
6531 } else {
6533 }
6534
6535 if (opline) {
6536 jit_SET_EX_OPLINE(jit, opline);
6537 }
6538
6539 ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6540 jit_ZVAL_ADDR(jit, var_addr),
6541 jit_ZVAL_ADDR(jit, val_addr));
6542
6543 if (undef_path) {
6544 ir_MERGE_WITH(undef_path);
6545 }
6546
6547 return 1;
6548}
6549
6550static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
6551 const zend_op *opline,
6552 zend_jit_addr var_use_addr,
6553 zend_jit_addr var_addr,
6554 uint32_t var_info,
6555 uint32_t var_def_info,
6556 uint8_t val_type,
6557 zend_jit_addr val_addr,
6558 uint32_t val_info,
6559 zend_jit_addr res_addr,
6560 zend_jit_addr ref_addr,
6561 bool check_exception)
6562{
6563 ir_ref if_refcounted = IR_UNUSED;
6564 ir_ref simple_inputs = IR_UNUSED;
6565 bool done = 0;
6566 zend_jit_addr real_res_addr = 0;
6567 ir_refs *end_inputs;
6568 ir_refs *res_inputs;
6569
6570 ir_refs_init(end_inputs, 6);
6571 ir_refs_init(res_inputs, 6);
6572
6573 if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6574 /* Force load */
6575 zend_jit_use_reg(jit, val_addr);
6576 }
6577
6578 if (Z_MODE(var_addr) == IS_REG) {
6579 jit->delay_var = Z_SSA_VAR(var_addr);
6580 jit->delay_refs = res_inputs;
6581 if (Z_MODE(res_addr) == IS_REG) {
6582 real_res_addr = res_addr;
6583 res_addr = 0;
6584 }
6585 } else if (Z_MODE(res_addr) == IS_REG) {
6586 jit->delay_var = Z_SSA_VAR(res_addr);
6587 jit->delay_refs = res_inputs;
6588 }
6589
6590 if ((var_info & MAY_BE_REF) || ref_addr) {
6591 ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6592 uintptr_t func;
6593
6594 if (!ref_addr) {
6595 ref = jit_ZVAL_ADDR(jit, var_use_addr);
6596 if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6597 ir_IF_TRUE(if_ref);
6598 ref2 = jit_Z_PTR_ref(jit, ref);
6599 } else {
6600 ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6601 }
6602 if_typed = jit_if_TYPED_REF(jit, ref2);
6603 ir_IF_TRUE_cold(if_typed);
6604 jit_SET_EX_OPLINE(jit, opline);
6605 if (Z_MODE(val_addr) == IS_REG) {
6606 zend_jit_addr real_addr;
6607
6608 if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6609 real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6610 } else {
6611 ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6612 real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6613 }
6614 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6615 return 0;
6616 }
6617 arg2 = jit_ZVAL_ADDR(jit, real_addr);
6618 } else {
6619 arg2 = jit_ZVAL_ADDR(jit, val_addr);
6620 }
6621 if (!res_addr) {
6622 if (val_type == IS_CONST) {
6623 func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6624 } else if (val_type == IS_TMP_VAR) {
6625 func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6626 } else if (val_type == IS_VAR) {
6627 func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6628 } else if (val_type == IS_CV) {
6629 func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6630 } else {
6632 }
6633 ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6634 } else {
6635 if (val_type == IS_CONST) {
6636 func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6637 } else if (val_type == IS_TMP_VAR) {
6638 func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6639 } else if (val_type == IS_VAR) {
6640 func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6641 } else if (val_type == IS_CV) {
6642 func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6643 } else {
6645 }
6646 ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6647 }
6648 if (check_exception) {
6649 zend_jit_check_exception(jit);
6650 }
6651 ir_refs_add(end_inputs, ir_END());
6652
6653 if (!ref_addr) {
6654 ir_IF_FALSE(if_ref);
6655 non_ref_path = ir_END();
6656 ir_IF_FALSE(if_typed);
6657 ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6658 ir_MERGE_WITH(non_ref_path);
6659 ref = ir_PHI_2(IR_ADDR, ref2, ref);
6660 var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6661 } else {
6662 ir_IF_FALSE(if_typed);
6663 }
6664 }
6665
6667 ir_ref ref, counter, if_not_zero;
6668
6670 if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6671 ir_IF_FALSE(if_refcounted);
6672 ir_END_list(simple_inputs);
6673 ir_IF_TRUE_cold(if_refcounted);
6674 } else if (RC_MAY_BE_1(var_info)) {
6675 done = 1;
6676 }
6677 ref = jit_Z_PTR(jit, var_use_addr);
6678 if (RC_MAY_BE_1(var_info)) {
6679 if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0)) {
6680 return 0;
6681 }
6682 counter = jit_GC_DELREF(jit, ref);
6683
6684 if_not_zero = ir_IF(counter);
6685 ir_IF_FALSE(if_not_zero);
6686 jit_ZVAL_DTOR(jit, ref, var_info, opline);
6687 if (check_exception) {
6688 zend_jit_check_exception(jit);
6689 }
6690 ir_refs_add(end_inputs, ir_END());
6691 ir_IF_TRUE(if_not_zero);
6692 if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6693 ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6694 ir_IF_FALSE(if_may_leak);
6695 if (opline) {
6696 jit_SET_EX_OPLINE(jit, opline);
6697 }
6699
6700 if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6701 ZEND_ASSERT(jit->delay_refs == res_inputs);
6702 ZEND_ASSERT(res_inputs->count > 0);
6703 ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6704 }
6705 if (check_exception && (val_info & MAY_BE_UNDEF)) {
6706 zend_jit_check_exception(jit);
6707 }
6708 ir_refs_add(end_inputs, ir_END());
6709 ir_IF_TRUE(if_may_leak);
6710 }
6711 if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6712 ZEND_ASSERT(jit->delay_refs == res_inputs);
6713 ZEND_ASSERT(res_inputs->count > 0);
6714 ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6715 }
6716 if (check_exception && (val_info & MAY_BE_UNDEF)) {
6717 zend_jit_check_exception(jit);
6718 }
6719 ir_refs_add(end_inputs, ir_END());
6720 } else /* if (RC_MAY_BE_N(var_info)) */ {
6721 jit_GC_DELREF(jit, ref);
6722 if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6723 ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6724 ir_IF_FALSE(if_may_leak);
6725 if (opline) {
6726 jit_SET_EX_OPLINE(jit, opline);
6727 }
6729 ir_END_list(simple_inputs);
6730 ir_IF_TRUE(if_may_leak);
6731 }
6732 ir_END_list(simple_inputs);
6733 }
6734 }
6735
6736 if (simple_inputs) {
6737 ir_MERGE_list(simple_inputs);
6738 }
6739
6740 if (!done) {
6741 if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6742 return 0;
6743 }
6744 if (end_inputs->count) {
6745 ir_refs_add(end_inputs, ir_END());
6746 }
6747 }
6748
6749 if (end_inputs->count) {
6750 ir_MERGE_N(end_inputs->count, end_inputs->refs);
6751 }
6752
6753 if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6754 ir_ref phi;
6755
6756 ZEND_ASSERT(jit->delay_refs == res_inputs);
6757 ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6758 jit->delay_var = -1;
6759 jit->delay_refs = NULL;
6760 if (res_inputs->count == 1) {
6761 phi = res_inputs->refs[0];
6762 } else {
6763 phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6764 res_inputs->count, res_inputs->refs);
6765 }
6766 if (Z_MODE(var_addr) == IS_REG) {
6767 if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6768 phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6769 }
6770 zend_jit_def_reg(jit, var_addr, phi);
6771 if (real_res_addr) {
6772 if (var_def_info & MAY_BE_LONG) {
6773 jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6774 } else {
6775 jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6776 }
6777 }
6778 } else {
6779 zend_jit_def_reg(jit, res_addr, phi);
6780 }
6781 }
6782
6783 return 1;
6784}
6785
6786static 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)
6787{
6788 if (op1_addr != op1_def_addr) {
6789 if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6790 return 0;
6791 }
6792 if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6793 op1_addr = op1_def_addr;
6794 }
6795 }
6796
6797 if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 1)) {
6798 return 0;
6799 }
6800 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6801 return 0;
6802 }
6803 return 1;
6804}
6805
6806static int zend_jit_assign(zend_jit_ctx *jit,
6807 const zend_op *opline,
6808 uint32_t op1_info,
6809 zend_jit_addr op1_use_addr,
6810 uint32_t op1_def_info,
6811 zend_jit_addr op1_addr,
6812 uint32_t op2_info,
6813 zend_jit_addr op2_addr,
6814 zend_jit_addr op2_def_addr,
6815 uint32_t res_info,
6816 zend_jit_addr res_addr,
6817 zend_jit_addr ref_addr,
6818 int may_throw)
6819{
6820 ZEND_ASSERT(opline->op1_type == IS_CV);
6821
6822 if (op2_addr != op2_def_addr) {
6823 if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6824 return 0;
6825 }
6826 if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6827 op2_addr = op2_def_addr;
6828 }
6829 }
6830
6831 if (Z_MODE(op1_addr) != IS_REG
6832 && Z_MODE(op1_use_addr) == IS_REG
6833 && !Z_LOAD(op1_use_addr)
6834 && !Z_STORE(op1_use_addr)) {
6835 /* Force type update */
6836 op1_info |= MAY_BE_UNDEF;
6837 }
6838 if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6839 opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6840 return 0;
6841 }
6842 if (Z_MODE(op1_addr) == IS_REG) {
6843 if (Z_STORE(op1_addr)) {
6844 if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6845 return 0;
6846 }
6848 && Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6849 && Z_REG(op1_use_addr) == ZREG_FP
6850 && EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6851 /* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6852 if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6853 jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6854 if (JIT_G(current_frame)) {
6855 SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6856 }
6857 } else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6858 jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6859 if (JIT_G(current_frame)) {
6860 SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6861 }
6862 } else {
6864 }
6865 }
6866 }
6867 if (opline->result_type != IS_UNUSED) {
6868 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6869 return 0;
6870 }
6871 }
6872
6873 return 1;
6874}
6875
6876static ir_op zend_jit_cmp_op(const zend_op *opline)
6877{
6878 ir_op op;
6879
6880 switch (opline->opcode) {
6881 case ZEND_IS_EQUAL:
6882 case ZEND_IS_IDENTICAL:
6883 case ZEND_CASE:
6884 case ZEND_CASE_STRICT:
6885 op = IR_EQ;
6886 break;
6887 case ZEND_IS_NOT_EQUAL:
6889 op = IR_NE;
6890 break;
6891 case ZEND_IS_SMALLER:
6892 op = IR_LT;
6893 break;
6895 op = IR_LE;
6896 break;
6897 default:
6899 }
6900 return op;
6901}
6902
6903static ir_ref zend_jit_cmp_long_long(zend_jit_ctx *jit,
6904 const zend_op *opline,
6905 zend_ssa_range *op1_range,
6906 zend_jit_addr op1_addr,
6907 zend_ssa_range *op2_range,
6908 zend_jit_addr op2_addr,
6909 zend_jit_addr res_addr,
6910 uint8_t smart_branch_opcode,
6911 uint32_t target_label,
6912 uint32_t target_label2,
6913 const void *exit_addr,
6914 bool skip_comparison)
6915{
6916 ir_ref ref;
6917 bool result;
6918
6919 if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6920 if (!smart_branch_opcode ||
6921 smart_branch_opcode == ZEND_JMPZ_EX ||
6922 smart_branch_opcode == ZEND_JMPNZ_EX) {
6923 jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6924 }
6925 if (smart_branch_opcode && !exit_addr) {
6926 if (smart_branch_opcode == ZEND_JMPZ ||
6927 smart_branch_opcode == ZEND_JMPZ_EX) {
6928 return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6929 } else if (smart_branch_opcode == ZEND_JMPNZ ||
6930 smart_branch_opcode == ZEND_JMPNZ_EX) {
6931 return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6932 } else {
6934 }
6935 }
6936 if (opline->opcode != ZEND_IS_IDENTICAL
6937 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6938 && opline->opcode != ZEND_CASE_STRICT) {
6939 return ir_END();
6940 } else {
6941 return IR_NULL; /* success */
6942 }
6943 }
6944
6945 ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6946
6947 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6948 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6950 }
6951 if (exit_addr) {
6952 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6953 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6954 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6955 } else {
6956 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6957 }
6958 } else {
6959 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6960 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6961 } else {
6962 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6963 }
6964 }
6965 } else if (smart_branch_opcode) {
6966 return jit_IF_ex(jit, ref,
6967 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6968 }
6969
6970 if (opline->opcode != ZEND_IS_IDENTICAL
6971 && opline->opcode != ZEND_IS_NOT_IDENTICAL
6972 && opline->opcode != ZEND_CASE_STRICT) {
6973 return ir_END();
6974 } else {
6975 return IR_NULL; /* success */
6976 }
6977}
6978
6979static 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)
6980{
6981 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));
6982
6983 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6984 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6986 }
6987 if (exit_addr) {
6988 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6989 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6990 } else {
6991 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6992 }
6993 } else if (smart_branch_opcode) {
6994 return jit_IF_ex(jit, ref,
6995 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6996 }
6997 return ir_END();
6998}
6999
7000static 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)
7001{
7002 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)));
7003
7004 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7005 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7007 }
7008 if (exit_addr) {
7009 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7010 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7011 } else {
7012 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7013 }
7014 } else if (smart_branch_opcode) {
7015 return jit_IF_ex(jit, ref,
7016 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7017 }
7018 return ir_END();
7019}
7020
7021static 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)
7022{
7023 ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
7024
7025 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7026 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7028 }
7029 if (exit_addr) {
7030 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7031 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
7032 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7033 } else {
7034 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7035 }
7036 } else {
7037 if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
7038 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7039 } else {
7040 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7041 }
7042 }
7043 } else if (smart_branch_opcode) {
7044 return jit_IF_ex(jit, ref,
7045 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7046 }
7047 if (opline->opcode != ZEND_IS_IDENTICAL
7048 && opline->opcode != ZEND_IS_NOT_IDENTICAL
7049 && opline->opcode != ZEND_CASE_STRICT) {
7050 return ir_END();
7051 } else {
7052 return IR_NULL; /* success */
7053 }
7054}
7055
7056static 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)
7057{
7058 ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
7059
7060 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7061 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7063 }
7064 if (exit_addr) {
7065 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7066 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7067 } else {
7068 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7069 }
7070 } else if (smart_branch_opcode) {
7071 return jit_IF_ex(jit, ref,
7072 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7073 }
7074
7075 return ir_END();
7076}
7077
7078static int zend_jit_cmp(zend_jit_ctx *jit,
7079 const zend_op *opline,
7080 uint32_t op1_info,
7081 zend_ssa_range *op1_range,
7082 zend_jit_addr op1_addr,
7083 uint32_t op2_info,
7084 zend_ssa_range *op2_range,
7085 zend_jit_addr op2_addr,
7086 zend_jit_addr res_addr,
7087 int may_throw,
7088 uint8_t smart_branch_opcode,
7089 uint32_t target_label,
7090 uint32_t target_label2,
7091 const void *exit_addr,
7092 bool skip_comparison)
7093{
7094 ir_ref ref = IR_UNUSED;
7095 ir_ref if_op1_long = IR_UNUSED;
7096 ir_ref if_op1_double = IR_UNUSED;
7097 ir_ref if_op2_double = IR_UNUSED;
7098 ir_ref if_op1_long_op2_long = IR_UNUSED;
7099 ir_ref if_op1_long_op2_double = IR_UNUSED;
7100 ir_ref if_op1_double_op2_double = IR_UNUSED;
7101 ir_ref if_op1_double_op2_long = IR_UNUSED;
7102 ir_ref slow_inputs = IR_UNUSED;
7103 bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
7104 bool has_slow =
7105 (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7106 (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7107 ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7109 ir_refs *end_inputs;
7110
7111 ir_refs_init(end_inputs, 8);
7112
7113 if (Z_MODE(op1_addr) == IS_REG) {
7114 if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
7115 /* Force load */
7116 zend_jit_use_reg(jit, op1_addr);
7117 }
7118 } else if (Z_MODE(op2_addr) == IS_REG) {
7119 if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
7120 /* Force load */
7121 zend_jit_use_reg(jit, op2_addr);
7122 }
7123 }
7124
7125 if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
7126 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
7127 if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7128 ir_IF_TRUE(if_op1_long);
7129 }
7130 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
7131 if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7132 ir_IF_FALSE_cold(if_op1_long_op2_long);
7133 if (op2_info & MAY_BE_DOUBLE) {
7134 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7135 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7136 ir_IF_FALSE_cold(if_op1_long_op2_double);
7137 ir_END_list(slow_inputs);
7138 ir_IF_TRUE(if_op1_long_op2_double);
7139 }
7140 ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7141 if (!ref) {
7142 return 0;
7143 }
7144 ir_refs_add(end_inputs, ref);
7145 } else {
7146 ir_END_list(slow_inputs);
7147 }
7148 ir_IF_TRUE(if_op1_long_op2_long);
7149 }
7150 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);
7151 if (!ref) {
7152 return 0;
7153 }
7154 ir_refs_add(end_inputs, ref);
7155
7156 if (if_op1_long) {
7157 ir_IF_FALSE_cold(if_op1_long);
7158 }
7159 if (op1_info & MAY_BE_DOUBLE) {
7160 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7161 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7162 ir_IF_FALSE_cold(if_op1_double);
7163 ir_END_list(slow_inputs);
7164 ir_IF_TRUE(if_op1_double);
7165 }
7166 if (op2_info & MAY_BE_DOUBLE) {
7167 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7168 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7169 ir_IF_TRUE(if_op1_double_op2_double);
7170 }
7171 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7172 if (!ref) {
7173 return 0;
7174 }
7175 ir_refs_add(end_inputs, ref);
7176 if (if_op1_double_op2_double) {
7177 ir_IF_FALSE_cold(if_op1_double_op2_double);
7178 }
7179 }
7180 if (!same_ops) {
7181 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7182 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7183 ir_IF_FALSE_cold(if_op1_double_op2_long);
7184 ir_END_list(slow_inputs);
7185 ir_IF_TRUE(if_op1_double_op2_long);
7186 }
7187 ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7188 if (!ref) {
7189 return 0;
7190 }
7191 ir_refs_add(end_inputs, ref);
7192 } else if (if_op1_double_op2_double) {
7193 ir_END_list(slow_inputs);
7194 }
7195 } else if (if_op1_long) {
7196 ir_END_list(slow_inputs);
7197 }
7198 } else if ((op1_info & MAY_BE_DOUBLE) &&
7199 !(op1_info & MAY_BE_LONG) &&
7200 (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7201 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7202 if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7203 ir_IF_FALSE_cold(if_op1_double);
7204 ir_END_list(slow_inputs);
7205 ir_IF_TRUE(if_op1_double);
7206 }
7207 if (op2_info & MAY_BE_DOUBLE) {
7208 if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7209 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7210 ir_IF_TRUE(if_op1_double_op2_double);
7211 }
7212 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7213 if (!ref) {
7214 return 0;
7215 }
7216 ir_refs_add(end_inputs, ref);
7217 if (if_op1_double_op2_double) {
7218 ir_IF_FALSE_cold(if_op1_double_op2_double);
7219 }
7220 }
7221 if (!same_ops && (op2_info & MAY_BE_LONG)) {
7222 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7223 if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7224 ir_IF_FALSE_cold(if_op1_double_op2_long);
7225 ir_END_list(slow_inputs);
7226 ir_IF_TRUE(if_op1_double_op2_long);
7227 }
7228 ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7229 if (!ref) {
7230 return 0;
7231 }
7232 ir_refs_add(end_inputs, ref);
7233 } else if (if_op1_double_op2_double) {
7234 ir_END_list(slow_inputs);
7235 }
7236 } else if ((op2_info & MAY_BE_DOUBLE) &&
7237 !(op2_info & MAY_BE_LONG) &&
7238 (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7239 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7240 if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7241 ir_IF_FALSE_cold(if_op2_double);
7242 ir_END_list(slow_inputs);
7243 ir_IF_TRUE(if_op2_double);
7244 }
7245 if (op1_info & MAY_BE_DOUBLE) {
7246 if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7247 if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7248 ir_IF_TRUE(if_op1_double_op2_double);
7249 }
7250 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7251 if (!ref) {
7252 return 0;
7253 }
7254 ir_refs_add(end_inputs, ref);
7255 if (if_op1_double_op2_double) {
7256 ir_IF_FALSE_cold(if_op1_double_op2_double);
7257 }
7258 }
7259 if (!same_ops && (op1_info & MAY_BE_LONG)) {
7260 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7261 if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7262 ir_IF_FALSE_cold(if_op1_long_op2_double);
7263 ir_END_list(slow_inputs);
7264 ir_IF_TRUE(if_op1_long_op2_double);
7265 }
7266 ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7267 if (!ref) {
7268 return 0;
7269 }
7270 ir_refs_add(end_inputs, ref);
7271 } else if (if_op1_double_op2_double) {
7272 ir_END_list(slow_inputs);
7273 }
7274 }
7275
7276 if (has_slow ||
7277 (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7278 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7279 ir_ref op1, op2, ref;
7280
7281 if (slow_inputs) {
7282 ir_MERGE_list(slow_inputs);
7283 }
7284 jit_SET_EX_OPLINE(jit, opline);
7285
7286 if (Z_MODE(op1_addr) == IS_REG) {
7287 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7288 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7289 return 0;
7290 }
7291 op1_addr = real_addr;
7292 }
7293 if (Z_MODE(op2_addr) == IS_REG) {
7294 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7295 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7296 return 0;
7297 }
7298 op2_addr = real_addr;
7299 }
7300
7301 op1 = jit_ZVAL_ADDR(jit, op1_addr);
7302 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7303 op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, 0);
7304 }
7305 op2 = jit_ZVAL_ADDR(jit, op2_addr);
7306 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7307 op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, 0);
7308 }
7309 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7310 if (opline->opcode != ZEND_CASE) {
7311 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7312 }
7313 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7314 if (may_throw) {
7315 zend_jit_check_exception_undef_result(jit, opline);
7316 }
7317
7318 ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7319 if (!ref) {
7320 return 0;
7321 }
7322 ir_refs_add(end_inputs, ref);
7323 }
7324
7325 if (end_inputs->count) {
7326 uint32_t n = end_inputs->count;
7327
7328 if (smart_branch_opcode && !exit_addr) {
7329 zend_basic_block *bb;
7330 ir_ref ref;
7331 uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7332 target_label2 : target_label;
7333 uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7334 target_label : target_label2;
7335
7336 ZEND_ASSERT(jit->b >= 0);
7337 bb = &jit->ssa->cfg.blocks[jit->b];
7338 ZEND_ASSERT(bb->successors_count == 2);
7339
7340 if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7341 ir_ref merge_inputs = IR_UNUSED;
7342
7343 while (n) {
7344 n--;
7345 ir_IF_TRUE(end_inputs->refs[n]);
7346 ir_END_list(merge_inputs);
7347 ir_IF_FALSE(end_inputs->refs[n]);
7348 ir_END_list(merge_inputs);
7349 }
7350 ir_MERGE_list(merge_inputs);
7351 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7352 } else if (n == 1) {
7353 ref = end_inputs->refs[0];
7354 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7355 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7356 } else {
7357 ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7358
7359 while (n) {
7360 n--;
7361 jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label);
7362 ir_END_list(true_inputs);
7363 jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label2);
7364 ir_END_list(false_inputs);
7365 }
7366 ir_MERGE_list(true_inputs);
7367 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7368 ir_MERGE_list(false_inputs);
7369 _zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7370 }
7371 jit->b = -1;
7372 } else {
7373 ir_MERGE_N(n, end_inputs->refs);
7374 }
7375 } else if (smart_branch_opcode && !exit_addr) {
7376 /* dead code */
7377 _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7378 jit->b = -1;
7379 }
7380
7381 return 1;
7382}
7383
7384static int zend_jit_identical(zend_jit_ctx *jit,
7385 const zend_op *opline,
7386 uint32_t op1_info,
7387 zend_ssa_range *op1_range,
7388 zend_jit_addr op1_addr,
7389 uint32_t op2_info,
7390 zend_ssa_range *op2_range,
7391 zend_jit_addr op2_addr,
7392 zend_jit_addr res_addr,
7393 int may_throw,
7394 uint8_t smart_branch_opcode,
7395 uint32_t target_label,
7396 uint32_t target_label2,
7397 const void *exit_addr,
7398 bool skip_comparison)
7399{
7400 bool always_false = 0, always_true = 0;
7401 ir_ref ref = IR_UNUSED;
7402
7403 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7404 ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7405 op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, 0);
7406 op1_info |= MAY_BE_NULL;
7407 op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7408 }
7409 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7410 ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7411 op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, 0);
7412 op2_info |= MAY_BE_NULL;
7413 op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7414 }
7415
7416 if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7417 always_false = 1;
7418 } else if (has_concrete_type(op1_info)
7419 && has_concrete_type(op2_info)
7420 && concrete_type(op1_info) == concrete_type(op2_info)
7421 && concrete_type(op1_info) <= IS_TRUE) {
7422 always_true = 1;
7423 } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7424 if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7425 always_true = 1;
7426 } else {
7427 always_false = 1;
7428 }
7429 }
7430
7431 if (always_true) {
7432 if (opline->opcode != ZEND_CASE_STRICT) {
7433 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7434 }
7435 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7436 if (!smart_branch_opcode
7437 || smart_branch_opcode == ZEND_JMPZ_EX
7438 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7439 jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7440 }
7441 if (may_throw) {
7442 zend_jit_check_exception(jit);
7443 }
7444 if (exit_addr) {
7445 if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7446 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7447 }
7448 } else if (smart_branch_opcode) {
7449 uint32_t label;
7450
7451 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7452 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7453 target_label : target_label2;
7454 } else {
7455 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7456 target_label2 : target_label;
7457 }
7458 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7459 jit->b = -1;
7460 }
7461 return 1;
7462 } else if (always_false) {
7463 if (opline->opcode != ZEND_CASE_STRICT) {
7464 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7465 }
7466 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7467 if (!smart_branch_opcode
7468 || smart_branch_opcode == ZEND_JMPZ_EX
7469 || smart_branch_opcode == ZEND_JMPNZ_EX) {
7470 jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7471 }
7472 if (may_throw) {
7473 zend_jit_check_exception(jit);
7474 }
7475 if (exit_addr) {
7476 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7477 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7478 }
7479 } else if (smart_branch_opcode) {
7480 uint32_t label;
7481
7482 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7483 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7484 target_label2 : target_label;
7485 } else {
7486 label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7487 target_label : target_label2;
7488 }
7489 _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7490 jit->b = -1;
7491 }
7492 return 1;
7493 }
7494
7495 if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7496 ref = jit_ZVAL_ADDR(jit, op1_addr);
7497 ref = jit_ZVAL_DEREF_ref(jit, ref);
7498 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7499 }
7500 if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7501 ref = jit_ZVAL_ADDR(jit, op2_addr);
7502 ref = jit_ZVAL_DEREF_ref(jit, ref);
7503 op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7504 }
7505
7506 if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7507 (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7508 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);
7509 if (!ref) {
7510 return 0;
7511 }
7512 } else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7513 (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7514 ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7515 if (!ref) {
7516 return 0;
7517 }
7518 } else {
7519 if (opline->op1_type != IS_CONST) {
7520 if (Z_MODE(op1_addr) == IS_REG) {
7521 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7522 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7523 return 0;
7524 }
7525 op1_addr = real_addr;
7526 }
7527 }
7528 if (opline->op2_type != IS_CONST) {
7529 if (Z_MODE(op2_addr) == IS_REG) {
7530 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7531 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7532 return 0;
7533 }
7534 }
7535 }
7536
7537 if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7538 zval *val = Z_ZV(op1_addr);
7539
7540 ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7541 } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7542 zval *val = Z_ZV(op2_addr);
7543
7544 ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7545 } else {
7546 if (Z_MODE(op1_addr) == IS_REG) {
7547 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7548 if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7549 return 0;
7550 }
7551 op1_addr = real_addr;
7552 }
7553 if (Z_MODE(op2_addr) == IS_REG) {
7554 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7555 if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7556 return 0;
7557 }
7558 op2_addr = real_addr;
7559 }
7560 if (may_throw) {
7561 jit_SET_EX_OPLINE(jit, opline);
7562 }
7563
7565 jit_ZVAL_ADDR(jit, op1_addr),
7566 jit_ZVAL_ADDR(jit, op2_addr));
7567 }
7568
7569 if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7570 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7571 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7573 } else {
7574 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7576 }
7577 }
7578 if (opline->opcode != ZEND_CASE_STRICT) {
7579 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7580 }
7581 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7582 if (may_throw) {
7583 zend_jit_check_exception_undef_result(jit, opline);
7584 }
7585 if (exit_addr) {
7586 if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7587 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7588 } else {
7589 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7590 }
7591 } else if (smart_branch_opcode) {
7592 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7593 /* swap labels */
7594 uint32_t tmp = target_label;
7595 target_label = target_label2;
7596 target_label2 = tmp;
7597 }
7598 ref = jit_IF_ex(jit, ref,
7599 (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7600 }
7601 }
7602
7603 if (smart_branch_opcode && !exit_addr) {
7604 zend_basic_block *bb;
7605
7606 ZEND_ASSERT(jit->b >= 0);
7607 bb = &jit->ssa->cfg.blocks[jit->b];
7608 ZEND_ASSERT(bb->successors_count == 2);
7609
7610 if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7611 ir_IF_TRUE(ref);
7613 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7614 } else {
7615 ZEND_ASSERT(bb->successors_count == 2);
7616 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7617 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7618 }
7619 jit->b = -1;
7620 }
7621
7622 return 1;
7623}
7624
7625static 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)
7626{
7627 uint32_t true_label = -1;
7628 uint32_t false_label = -1;
7629 bool set_bool = 0;
7630 bool set_bool_not = 0;
7631 bool always_true = 0, always_false = 0;
7632 ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7634
7635 if (branch_opcode == ZEND_BOOL) {
7636 set_bool = 1;
7637 } else if (branch_opcode == ZEND_BOOL_NOT) {
7638 set_bool = 1;
7639 set_bool_not = 1;
7640 } else if (branch_opcode == ZEND_JMPZ) {
7641 true_label = target_label2;
7642 false_label = target_label;
7643 } else if (branch_opcode == ZEND_JMPNZ) {
7644 true_label = target_label;
7645 false_label = target_label2;
7646 } else if (branch_opcode == ZEND_JMPZ_EX) {
7647 set_bool = 1;
7648 true_label = target_label2;
7649 false_label = target_label;
7650 } else if (branch_opcode == ZEND_JMPNZ_EX) {
7651 set_bool = 1;
7652 true_label = target_label;
7653 false_label = target_label2;
7654 } else {
7656 }
7657
7658 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7659 ref = jit_ZVAL_ADDR(jit, op1_addr);
7660 ref = jit_ZVAL_DEREF_ref(jit, ref);
7661 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7662 }
7663
7664 if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
7665 if (zend_is_true(Z_ZV(op1_addr))) {
7666 always_true = 1;
7667 } else {
7668 always_false = 1;
7669 }
7670 } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7671 if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7672 always_true = 1;
7673 } else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7674 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7675 ref = jit_ZVAL_ADDR(jit, op1_addr);
7676 zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, 0);
7677 }
7678 always_false = 1;
7679 }
7680 }
7681
7682 if (always_true) {
7683 if (set_bool) {
7684 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7685 }
7686 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7687 if (may_throw) {
7688 zend_jit_check_exception(jit);
7689 }
7690 if (true_label != (uint32_t)-1) {
7691 ZEND_ASSERT(exit_addr == NULL);
7692 _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7693 jit->b = -1;
7694 }
7695 return 1;
7696 } else if (always_false) {
7697 if (set_bool) {
7698 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7699 }
7700 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7701 if (may_throw) {
7702 zend_jit_check_exception(jit);
7703 }
7704 if (false_label != (uint32_t)-1) {
7705 ZEND_ASSERT(exit_addr == NULL);
7706 _zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7707 jit->b = -1;
7708 }
7709 return 1;
7710 }
7711
7713 type = jit_Z_TYPE(jit, op1_addr);
7714 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7715 ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7716
7717 ir_IF_TRUE_cold(if_type);
7718
7719 if (op1_info & MAY_BE_UNDEF) {
7720 zend_jit_type_check_undef(jit,
7721 type,
7722 opline->op1.var,
7723 opline, 1, 0, 1);
7724 }
7725 if (set_bool) {
7726 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7727 }
7728 if (exit_addr) {
7729 if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
7730 ir_END_list(end_inputs);
7731 } else {
7732 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7733 }
7734 } else if (false_label != (uint32_t)-1) {
7735 ir_END_list(false_inputs);
7736 } else {
7737 ir_END_list(end_inputs);
7738 }
7739 ir_IF_FALSE(if_type);
7740 }
7741
7742 if (op1_info & MAY_BE_TRUE) {
7743 ir_ref if_type = IR_UNUSED;
7744
7745 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7746 if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7747
7748 ir_IF_TRUE(if_type);
7749 }
7750 if (set_bool) {
7751 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7752 }
7753 if (exit_addr) {
7754 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7755 ir_END_list(end_inputs);
7756 } else {
7757 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7758 }
7759 } else if (true_label != (uint32_t)-1) {
7760 ir_END_list(true_inputs);
7761 } else {
7762 ir_END_list(end_inputs);
7763 }
7764 if (if_type) {
7765 ir_IF_FALSE(if_type);
7766 }
7767 }
7768 }
7769
7770 if (op1_info & MAY_BE_LONG) {
7771 ir_ref if_long = IR_UNUSED;
7772 ir_ref ref;
7773
7775 if (!type) {
7776 type = jit_Z_TYPE(jit, op1_addr);
7777 }
7778 if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7779 ir_IF_TRUE(if_long);
7780 }
7781 ref = jit_Z_LVAL(jit, op1_addr);
7782 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7783 ref = ir_NE(ref, ir_CONST_LONG(0));
7784 if (set_bool_not) {
7785 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7787 } else {
7788 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7790 }
7791 ir_END_list(end_inputs);
7792 } else if (exit_addr) {
7793 if (set_bool) {
7794 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7796 }
7797 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7798 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7799 } else {
7800 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7801 }
7802 ir_END_list(end_inputs);
7803 } else {
7804 ir_ref if_val = ir_IF(ref);
7805 ir_IF_TRUE(if_val);
7806 if (set_bool) {
7807 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7808 }
7809 ir_END_list(true_inputs);
7810 ir_IF_FALSE(if_val);
7811 if (set_bool) {
7812 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7813 }
7814 ir_END_list(false_inputs);
7815 }
7816 if (if_long) {
7817 ir_IF_FALSE(if_long);
7818 }
7819 }
7820
7821 if (op1_info & MAY_BE_DOUBLE) {
7822 ir_ref if_double = IR_UNUSED;
7823 ir_ref ref;
7824
7826 if (!type) {
7827 type = jit_Z_TYPE(jit, op1_addr);
7828 }
7829 if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7830 ir_IF_TRUE(if_double);
7831 }
7832 ref = ir_NE(jit_Z_DVAL(jit, op1_addr), ir_CONST_DOUBLE(0.0));
7833 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7834 if (set_bool_not) {
7835 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7837 } else {
7838 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7840 }
7841 ir_END_list(end_inputs);
7842 } else if (exit_addr) {
7843 if (set_bool) {
7844 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7846 }
7847 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7848 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7849 } else {
7850 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7851 }
7852 ir_END_list(end_inputs);
7853 } else {
7854 ir_ref if_val = ir_IF(ref);
7855 ir_IF_TRUE(if_val);
7856 if (set_bool) {
7857 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7858 }
7859 ir_END_list(true_inputs);
7860 ir_IF_FALSE(if_val);
7861 if (set_bool) {
7862 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7863 }
7864 ir_END_list(false_inputs);
7865 }
7866 if (if_double) {
7867 ir_IF_FALSE(if_double);
7868 }
7869 }
7870
7872 jit_SET_EX_OPLINE(jit, opline);
7873 ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7874 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7875 if (may_throw) {
7876 zend_jit_check_exception_undef_result(jit, opline);
7877 }
7878 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7879 if (set_bool_not) {
7880 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7882 } else {
7883 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7885 }
7886 if (end_inputs) {
7887 ir_END_list(end_inputs);
7888 }
7889 } else if (exit_addr) {
7890 if (set_bool) {
7891 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7893 }
7894 if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7895 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7896 } else {
7897 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7898 }
7899 if (end_inputs) {
7900 ir_END_list(end_inputs);
7901 }
7902 } else {
7903 ir_ref if_val = ir_IF(ref);
7904 ir_IF_TRUE(if_val);
7905 if (set_bool) {
7906 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7907 }
7908 ir_END_list(true_inputs);
7909 ir_IF_FALSE(if_val);
7910 if (set_bool) {
7911 jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7912 }
7913 ir_END_list(false_inputs);
7914 }
7915 }
7916
7917 if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7918 if (end_inputs) {
7919 ir_MERGE_list(end_inputs);
7920 }
7921 } else {
7922 _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7923 }
7924
7925 return 1;
7926}
7927
7928static 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)
7929{
7930 uint32_t defined_label = (uint32_t)-1;
7931 uint32_t undefined_label = (uint32_t)-1;
7932 zval *zv = RT_CONSTANT(opline, opline->op1);
7933 zend_jit_addr res_addr = 0;
7934 ir_ref ref, ref2, if_set, if_zero, if_set2;
7935 ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7936
7937 if (smart_branch_opcode && !exit_addr) {
7938 if (smart_branch_opcode == ZEND_JMPZ) {
7939 defined_label = target_label2;
7940 undefined_label = target_label;
7941 } else if (smart_branch_opcode == ZEND_JMPNZ) {
7942 defined_label = target_label;
7943 undefined_label = target_label2;
7944 } else {
7946 }
7947 } else {
7948 res_addr = RES_ADDR();
7949 }
7950
7951 // if (CACHED_PTR(opline->extended_value)) {
7952 ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7953
7954 if_set = ir_IF(ref);
7955
7956 ir_IF_FALSE_cold(if_set);
7957 if_zero = ir_END();
7958
7959 ir_IF_TRUE(if_set);
7960 if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7961 ir_IF_FALSE(if_set2);
7962
7963 if (exit_addr) {
7964 if (smart_branch_opcode == ZEND_JMPNZ) {
7965 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7966 } else {
7967 ir_END_list(end_inputs);
7968 }
7969 } else if (smart_branch_opcode) {
7970 ir_END_list(true_inputs);
7971 } else {
7972 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7973 ir_END_list(end_inputs);
7974 }
7975
7976 ir_IF_TRUE_cold(if_set2);
7977
7978 ref2 = jit_EG(zend_constants);
7979 ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7980 if (sizeof(void*) == 8) {
7981 ref = ir_TRUNC_U32(ref);
7982 }
7983 ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7984 ref2 = ir_IF(ref2);
7985 ir_IF_TRUE(ref2);
7986
7987 if (exit_addr) {
7988 if (smart_branch_opcode == ZEND_JMPZ) {
7989 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7990 } else {
7991 ir_END_list(end_inputs);
7992 }
7993 } else if (smart_branch_opcode) {
7994 ir_END_list(false_inputs);
7995 } else {
7996 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7997 ir_END_list(end_inputs);
7998 }
7999
8000 ir_IF_FALSE(ref2);
8001 ir_MERGE_2(if_zero, ir_END());
8002
8003 jit_SET_EX_OPLINE(jit, opline);
8005 if (exit_addr) {
8006 if (smart_branch_opcode == ZEND_JMPZ) {
8007 ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
8008 } else {
8009 ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
8010 }
8011 ir_END_list(end_inputs);
8012 } else if (smart_branch_opcode) {
8013 ref2 = ir_IF(ref2);
8014 ir_IF_TRUE(ref2);
8015 ir_END_list(true_inputs);
8016 ir_IF_FALSE(ref2);
8017 ir_END_list(false_inputs);
8018 } else {
8019 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8021 ir_END_list(end_inputs);
8022 }
8023
8024 if (!smart_branch_opcode || exit_addr) {
8025 if (end_inputs) {
8026 ir_MERGE_list(end_inputs);
8027 }
8028 } else {
8029 _zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
8030 }
8031
8032 return 1;
8033}
8034
8035static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
8036{
8037 zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
8038 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
8039
8040 ir_IF_FALSE_cold(if_def);
8041
8043 if (!zend_jit_save_call_chain(jit, -1)) {
8044 return 0;
8045 }
8046 }
8047
8048 if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
8049 && (opline-1)->opcode != ZEND_FETCH_LIST_R
8050 && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
8051 && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
8052 zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
8053
8054 zend_jit_zval_try_addref(jit, val_addr);
8055 }
8056
8057 jit_LOAD_IP_ADDR(jit, opline - 1);
8058 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
8059
8060 ir_IF_TRUE(if_def);
8061
8062 return 1;
8063}
8064
8065static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
8066{
8067 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
8068 zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
8069
8070 // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8071 jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, 1);
8072 return 1;
8073}
8074
8075static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx *jit,
8076 const zend_op *opline,
8077 zend_jit_addr val_addr,
8078 uint8_t type,
8079 bool deref,
8080 uint32_t flags,
8081 bool op1_avoid_refcounting)
8082{
8083 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
8084 int32_t exit_point;
8085 const void *res_exit_addr = NULL;
8086 ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
8087 ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
8088 uint32_t old_op1_info = 0;
8089 uint32_t old_info;
8090 ir_ref old_ref;
8091
8092
8093 if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
8094 old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
8095 if (op1_avoid_refcounting
8096 || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
8097 && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
8098 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
8099 }
8100 }
8101 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
8102 old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
8103 CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
8104 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
8105
8106 if (deref) {
8107 ir_ref if_type;
8108
8109 if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
8110 if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
8111 } else {
8112 if_type = jit_if_Z_TYPE(jit, val_addr, type);
8113 }
8114 ir_IF_TRUE(if_type);
8115 end1 = ir_END();
8116 ref1 = ref;
8117 ir_IF_FALSE_cold(if_type);
8118
8120 exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
8121 res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8122 if (!res_exit_addr) {
8123 return 0;
8124 }
8125
8126 jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
8127 ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
8128 val_addr = ZEND_ADDR_REF_ZVAL(ref);
8129 }
8130
8132 exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
8133 res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8134 if (!res_exit_addr) {
8135 return 0;
8136 }
8137
8138 if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
8139 ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
8140 } else {
8141 jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
8142 }
8143
8144 if (deref) {
8145 ir_MERGE_WITH(end1);
8146 ref = ir_PHI_2(IR_ADDR, ref, ref1);
8147 }
8148
8149 val_addr = ZEND_ADDR_REF_ZVAL(ref);
8150
8151 SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
8152 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
8153 if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
8154 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
8155 }
8156
8157 return val_addr;
8158}
8159
8160static int zend_jit_fetch_constant(zend_jit_ctx *jit,
8161 const zend_op *opline,
8162 const zend_op_array *op_array,
8163 zend_ssa *ssa,
8164 const zend_ssa_op *ssa_op,
8165 zend_jit_addr res_addr)
8166{
8167 zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
8168 uint32_t res_info = RES_INFO();
8169 ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
8170
8171 // JIT: c = CACHED_PTR(opline->extended_value);
8172 ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
8173
8174 // JIT: if (c != NULL)
8175 if_set = ir_IF(ref);
8176
8177 if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
8178 // JIT: if (!IS_SPECIAL_CACHE_VAL(c))
8179 ir_IF_FALSE_cold(if_set);
8180 not_set_path = ir_END();
8181 ir_IF_TRUE(if_set);
8182 if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
8183 ir_IF_TRUE_cold(if_special);
8184 special_path = ir_END();
8185 ir_IF_FALSE(if_special);
8186 fast_path = ir_END();
8187 ir_MERGE_2(not_set_path, special_path);
8188 } else {
8189 ir_IF_TRUE(if_set);
8190 fast_path = ir_END();
8191 ir_IF_FALSE_cold(if_set);
8192 }
8193
8194 // JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
8195 jit_SET_EX_OPLINE(jit, opline);
8198 ir_CONST_U32(opline->op1.num));
8199 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8200
8201 ir_MERGE_WITH(fast_path);
8202 ref = ir_PHI_2(IR_ADDR, ref2, ref);
8203
8204 if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
8205 uint8_t type = concrete_type(res_info);
8206 zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
8207
8208 const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, 0, 0, 0);
8209 if (!const_addr) {
8210 return 0;
8211 }
8212
8213 res_info &= ~MAY_BE_GUARD;
8214 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
8215
8216 // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8217 jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, 1);
8218 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
8219 return 0;
8220 }
8221 } else {
8222 ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
8223
8224 // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8225 jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, 1);
8226 }
8227
8228
8229 return 1;
8230}
8231
8232static 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)
8233{
8234 uint32_t mask;
8235 zend_jit_addr op1_addr = OP1_ADDR();
8236 zend_jit_addr res_addr = 0;
8237 uint32_t true_label = -1, false_label = -1;
8238 ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8239
8240 // TODO: support for is_resource() ???
8242
8243 if (smart_branch_opcode && !exit_addr) {
8244 if (smart_branch_opcode == ZEND_JMPZ) {
8245 true_label = target_label2;
8246 false_label = target_label;
8247 } else if (smart_branch_opcode == ZEND_JMPNZ) {
8248 true_label = target_label;
8249 false_label = target_label2;
8250 } else {
8252 }
8253 } else {
8254 res_addr = RES_ADDR();
8255 }
8256
8257 if (op1_info & MAY_BE_UNDEF) {
8258 ir_ref if_def = IR_UNUSED;
8259
8260 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8261 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8262 ir_IF_FALSE_cold(if_def);
8263 }
8264
8265 jit_SET_EX_OPLINE(jit, opline);
8266 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8267 zend_jit_check_exception_undef_result(jit, opline);
8268 if (opline->extended_value & MAY_BE_NULL) {
8269 if (exit_addr) {
8270 if (smart_branch_opcode == ZEND_JMPNZ) {
8271 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8272 } else {
8273 ir_END_list(end_inputs);
8274 }
8275 } else if (smart_branch_opcode) {
8276 ir_END_list(true_inputs);
8277 } else {
8278 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8279 ir_END_list(end_inputs);
8280 }
8281 } else {
8282 if (exit_addr) {
8283 if (smart_branch_opcode == ZEND_JMPZ) {
8284 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8285 } else {
8286 ir_END_list(end_inputs);
8287 }
8288 } else if (smart_branch_opcode) {
8289 ir_END_list(false_inputs);
8290 } else {
8291 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8292 if (if_def) {
8293 ir_END_list(end_inputs);
8294 }
8295 }
8296 }
8297
8298 if (if_def) {
8299 ir_IF_TRUE(if_def);
8300 op1_info |= MAY_BE_NULL;
8301 }
8302 }
8303
8304 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8305 mask = opline->extended_value;
8306 if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8307 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8308 if (exit_addr) {
8309 if (smart_branch_opcode == ZEND_JMPNZ) {
8310 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8311 } else if (end_inputs) {
8312 ir_END_list(end_inputs);
8313 }
8314 } else if (smart_branch_opcode) {
8315 ir_END_list(true_inputs);
8316 } else {
8317 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8318 ir_END_list(end_inputs);
8319 }
8320 } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8321 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8322 if (exit_addr) {
8323 if (smart_branch_opcode == ZEND_JMPZ) {
8324 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8325 } else if (end_inputs) {
8326 ir_END_list(end_inputs);
8327 }
8328 } else if (smart_branch_opcode) {
8329 ir_END_list(false_inputs);
8330 } else {
8331 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8332 ir_END_list(end_inputs);
8333 }
8334 } else {
8335 ir_ref ref;
8336 bool invert = 0;
8337 uint8_t type;
8338
8339 switch (mask) {
8340 case MAY_BE_NULL: type = IS_NULL; break;
8341 case MAY_BE_FALSE: type = IS_FALSE; break;
8342 case MAY_BE_TRUE: type = IS_TRUE; break;
8343 case MAY_BE_LONG: type = IS_LONG; break;
8344 case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8345 case MAY_BE_STRING: type = IS_STRING; break;
8346 case MAY_BE_ARRAY: type = IS_ARRAY; break;
8347 case MAY_BE_OBJECT: type = IS_OBJECT; break;
8348 case MAY_BE_ANY - MAY_BE_NULL: type = IS_NULL; invert = 1; break;
8349 case MAY_BE_ANY - MAY_BE_FALSE: type = IS_FALSE; invert = 1; break;
8350 case MAY_BE_ANY - MAY_BE_TRUE: type = IS_TRUE; invert = 1; break;
8351 case MAY_BE_ANY - MAY_BE_LONG: type = IS_LONG; invert = 1; break;
8352 case MAY_BE_ANY - MAY_BE_DOUBLE: type = IS_DOUBLE; invert = 1; break;
8353 case MAY_BE_ANY - MAY_BE_STRING: type = IS_STRING; invert = 1; break;
8354 case MAY_BE_ANY - MAY_BE_ARRAY: type = IS_ARRAY; invert = 1; break;
8355 case MAY_BE_ANY - MAY_BE_OBJECT: type = IS_OBJECT; invert = 1; break;
8356 case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break;
8357 default:
8358 type = 0;
8359 }
8360
8361 if (op1_info & MAY_BE_REF) {
8362 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8363 ref = jit_ZVAL_DEREF_ref(jit, ref);
8364 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8365 }
8366 if (type == 0) {
8367 ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8368 if (!smart_branch_opcode) {
8369 ref = ir_NE(ref, ir_CONST_U32(0));
8370 }
8371 } else if (invert) {
8372 ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8373 } else {
8374 ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8375 }
8376
8377 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8378
8379 if (exit_addr) {
8380 if (smart_branch_opcode == ZEND_JMPZ) {
8381 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8382 } else {
8383 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8384 }
8385 if (end_inputs) {
8386 ir_END_list(end_inputs);
8387 }
8388 } else if (smart_branch_opcode) {
8389 ir_ref if_val = ir_IF(ref);
8390 ir_IF_TRUE(if_val);
8391 ir_END_list(true_inputs);
8392 ir_IF_FALSE(if_val);
8393 ir_END_list(false_inputs);
8394 } else {
8395 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8397 ir_END_list(end_inputs);
8398 }
8399 }
8400 }
8401
8402 if (!smart_branch_opcode || exit_addr) {
8403 if (end_inputs) {
8404 ir_MERGE_list(end_inputs);
8405 } else if (exit_addr && !jit->ctx.control) {
8406 ir_BEGIN(IR_UNUSED); /* unreachable block */
8407 }
8408 } else {
8409 _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8410 }
8411
8412 return 1;
8413}
8414
8415static 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)
8416{
8417 zend_jit_addr res_addr = RES_ADDR();
8418 uint32_t true_label = -1, false_label = -1;
8419 ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8420
8421 // TODO: support for empty() ???
8423
8424 if (smart_branch_opcode && !exit_addr) {
8425 if (smart_branch_opcode == ZEND_JMPZ) {
8426 true_label = target_label2;
8427 false_label = target_label;
8428 } else if (smart_branch_opcode == ZEND_JMPNZ) {
8429 true_label = target_label;
8430 false_label = target_label2;
8431 } else {
8433 }
8434 } else {
8435 res_addr = RES_ADDR();
8436 }
8437
8438 if (op1_info & MAY_BE_REF) {
8439 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8440 ref = jit_ZVAL_DEREF_ref(jit, ref);
8441 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8442 }
8443
8444 if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8445 if (exit_addr) {
8446 ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8447 } else if (smart_branch_opcode) {
8448 ir_END_list(true_inputs);
8449 } else {
8450 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8451 ir_END_list(end_inputs);
8452 }
8453 } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8454 if (exit_addr) {
8455 ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8456 } else if (smart_branch_opcode) {
8457 ir_END_list(false_inputs);
8458 } else {
8459 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8460 ir_END_list(end_inputs);
8461 }
8462 } else {
8463 ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8464 if (exit_addr) {
8465 if (smart_branch_opcode == ZEND_JMPNZ) {
8466 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8467 } else {
8468 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8469 }
8470 } else if (smart_branch_opcode) {
8471 ir_ref if_val = ir_IF(ref);
8472 ir_IF_TRUE(if_val);
8473 ir_END_list(true_inputs);
8474 ir_IF_FALSE(if_val);
8475 ir_END_list(false_inputs);
8476 } else {
8477 jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8479 ir_END_list(end_inputs);
8480 }
8481 }
8482
8483 if (!smart_branch_opcode || exit_addr) {
8484 if (end_inputs) {
8485 ir_MERGE_list(end_inputs);
8486 }
8487 } else {
8488 _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8489 }
8490
8491 return 1;
8492}
8493
8494/* copy of hidden zend_closure */
8495typedef struct _zend_closure {
8498 zval this_ptr;
8502
8503static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8504{
8505 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8506 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8507
8508 if (!exit_addr) {
8509 return 0;
8510 }
8511
8512 // JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8513 ir_GUARD(
8514 ir_UGE(
8515 ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8516 ir_CONST_ADDR(used_stack)),
8517 ir_CONST_ADDR(exit_addr));
8518
8519 return 1;
8520}
8521
8522static int zend_jit_free_trampoline(zend_jit_ctx *jit, ir_ref func)
8523{
8524 // JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8525 ir_ref if_trampoline = ir_IF(ir_AND_U32(
8528
8529 ir_IF_TRUE(if_trampoline);
8530 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8531 ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8532
8533 return 1;
8534}
8535
8536static 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)
8537{
8538 uint32_t used_stack;
8539 ir_ref used_stack_ref = IR_UNUSED;
8540 bool stack_check = 1;
8541 ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8542
8543 ZEND_ASSERT(func_ref != IR_NULL);
8544 if (func) {
8545 used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8546 if ((int)used_stack <= checked_stack) {
8547 stack_check = 0;
8548 }
8549 used_stack_ref = ir_CONST_ADDR(used_stack);
8550 } else {
8551 ir_ref num_args_ref;
8552 ir_ref if_internal_func = IR_UNUSED;
8553 const size_t func_type_offset = is_closure ? offsetof(zend_closure, func.type) : offsetof(zend_function, type);
8554
8555 used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8556 used_stack_ref = ir_CONST_ADDR(used_stack);
8557 used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8558
8559 // JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8560 ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, func_type_offset));
8561 if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8562 ir_IF_FALSE(if_internal_func);
8563
8564 // JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8565 num_args_ref = ir_CONST_U32(opline->extended_value);
8566 if (!is_closure) {
8567 ref = ir_SUB_U32(
8568 ir_SUB_U32(
8569 ir_MIN_U32(
8570 num_args_ref,
8573 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8574 } else {
8575 ref = ir_SUB_U32(
8576 ir_SUB_U32(
8577 ir_MIN_U32(
8578 num_args_ref,
8579 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8580 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8581 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8582 }
8583 ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8584 if (sizeof(void*) == 8) {
8585 ref = ir_SEXT_A(ref);
8586 }
8587 ref = ir_SUB_A(used_stack_ref, ref);
8588
8589 ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8590 used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8591 }
8592
8593 zend_jit_start_reuse_ip(jit);
8594
8595 // JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8596 jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8597
8598 if (stack_check) {
8599 // JIT: Check Stack Overflow
8600 ref = ir_UGE(
8601 ir_SUB_A(
8602 ir_LOAD_A(jit_EG(vm_stack_end)),
8603 jit_IP(jit)),
8604 used_stack_ref);
8605
8606 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8607 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8608 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8609
8610 if (!exit_addr) {
8611 return 0;
8612 }
8613
8614 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8615 } else {
8616 if_enough_stack = ir_IF(ref);
8617 ir_IF_FALSE_cold(if_enough_stack);
8618
8619#ifdef _WIN32
8620 if (0) {
8621#else
8622 if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8623#endif
8624 jit_SET_EX_OPLINE(jit, opline);
8625 ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8626 } else {
8627 if (!is_closure) {
8628 ref = func_ref;
8629 } else {
8630 ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8631 }
8632 jit_SET_EX_OPLINE(jit, opline);
8633 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8634 used_stack_ref, ref);
8635 }
8636 jit_STORE_IP(jit, ref);
8637
8638 cold_path = ir_END();
8639 ir_IF_TRUE(if_enough_stack);
8640 }
8641 }
8642
8643 ref = jit_EG(vm_stack_top);
8644 rx = jit_IP(jit);
8645#if !OPTIMIZE_FOR_SIZE
8646 /* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8647 * This vesions is longer but faster
8648 * mov EG(vm_stack_top), %CALL
8649 * lea size(%call), %tmp
8650 * mov %tmp, EG(vm_stack_top)
8651 */
8652 top = rx;
8653#else
8654 /* JIT: EG(vm_stack_top) += used_stack;
8655 * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8656 * mov EG(vm_stack_top), %CALL
8657 * add $size, EG(vm_stack_top)
8658 */
8659 top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8660#endif
8661 ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8662
8663 // JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8664 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8665 // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8667 }
8668#ifdef _WIN32
8669 if (0) {
8670#else
8671 if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8672#endif
8673 if (cold_path) {
8674 ir_MERGE_WITH(cold_path);
8675 rx = jit_IP(jit);
8676 }
8677
8678 // JIT: call->func = func;
8679 ir_STORE(jit_CALL(rx, func), func_ref);
8680 } else {
8681 if (!is_closure) {
8682 // JIT: call->func = func;
8683 ir_STORE(jit_CALL(rx, func), func_ref);
8684 } else {
8685 // JIT: call->func = &closure->func;
8687 }
8688 if (cold_path) {
8689 ir_MERGE_WITH(cold_path);
8690 rx = jit_IP(jit);
8691 }
8692 }
8693 if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8694 // JIT: Z_PTR(call->This) = obj;
8695 ZEND_ASSERT(this_ref != IR_NULL);
8696 ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8697 if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8698 // JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8699 ref = jit_CALL(rx, This.u1.type_info);
8700 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8702 } else {
8704 }
8705 } else {
8706 if (opline->op1_type == IS_CV) {
8707 // JIT: GC_ADDREF(obj);
8708 jit_GC_ADDREF(jit, this_ref);
8709 }
8710
8711 // JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8712 ref = jit_CALL(rx, This.u1.type_info);
8713 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8715 } else {
8716 ir_STORE(ref,
8719 }
8720 }
8721 } else if (!is_closure) {
8722 // JIT: Z_CE(call->This) = called_scope;
8723 ir_STORE(jit_CALL(rx, This), IR_NULL);
8724 } else {
8725 ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8726 ir_ref if_cond_user = IR_UNUSED;
8727
8728 if (opline->op2_type == IS_CV) {
8729 // JIT: GC_ADDREF(closure);
8730 jit_GC_ADDREF(jit, func_ref);
8731 }
8732
8733 // JIT: RX(object_or_called_scope) = closure->called_scope;
8734 object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8735
8736 // JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8737 // (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8739 ir_AND_U32(
8740 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8743 // JIT: if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
8744 if_cond = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.u1.v.type))));
8745 ir_IF_TRUE(if_cond);
8746
8747 // JIT: call_info |= ZEND_CALL_HAS_THIS;
8749
8750 // JIT: object_or_called_scope = Z_OBJ(closure->this_ptr);
8751 object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr.value.ptr)));
8752
8754 call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8755 object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8756
8757 // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8758 ref = jit_CALL(rx, This.u1.type_info);
8760
8761 // JIT: Z_PTR(call->This) = object_or_called_scope;
8762 ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8763
8764 if (!func) {
8765 // JIT: if (closure->func.common.type & ZEND_USER_FUNCTION)
8768 ir_IF_TRUE(if_cond_user);
8769 }
8770
8771 if (!func || func->common.type == ZEND_USER_FUNCTION) {
8772 // JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8773 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8775 }
8776
8777 if (!func) {
8778 ir_MERGE_WITH_EMPTY_FALSE(if_cond_user);
8779 }
8780 }
8781
8782 // JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8783 ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8784
8785 return 1;
8786}
8787
8788static int zend_jit_func_guard(zend_jit_ctx *jit, ir_ref func_ref, const zend_function *func, const void *exit_addr)
8789{
8790 if (func->type == ZEND_USER_FUNCTION &&
8791 (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8792 (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8793 !func->common.function_name)) {
8794 const zend_op *opcodes = func->op_array.opcodes;
8795
8796 // JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8797 ir_GUARD(
8798 ir_EQ(
8799 ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8800 ir_CONST_ADDR(opcodes)),
8801 ir_CONST_ADDR(exit_addr));
8802#ifdef ZEND_WIN32
8803 } else if (func->type == ZEND_INTERNAL_FUNCTION) {
8804 // ASLR may cause different addresses in different workers. Check for the internal function handler.
8805 // JIT: if (call->func.internal_function.handler != handler) goto exit_addr;
8806 ir_GUARD(
8807 ir_EQ(
8809 ir_CONST_FC_FUNC(func->internal_function.handler)),
8810 ir_CONST_ADDR(exit_addr));
8811#endif
8812 } else {
8813 // JIT: if (call->func != func) goto exit_addr;
8814 ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8815 }
8816
8817 return 1;
8818}
8819
8820static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8821{
8822 int32_t exit_point;
8823 const void *exit_addr;
8824 ir_ref call;
8825
8826 if (func->type == ZEND_USER_FUNCTION
8827 && !zend_accel_in_shm(func->op_array.opcodes)) {
8828 /* op_array and op_array->opcodes are not persistent. We can't link. */
8829 return 0;
8830 }
8831
8832 exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8833 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8834 if (!exit_addr) {
8835 return 0;
8836 }
8837
8838 // call = EX(call);
8840 while (level > 0) {
8841 // call = call->prev_execute_data
8843 level--;
8844 }
8845
8846 return zend_jit_func_guard(jit, ir_LOAD_A(jit_CALL(call, func)), func, exit_addr);
8847}
8848
8849static 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)
8850{
8851 zend_func_info *info = ZEND_FUNC_INFO(op_array);
8854 ir_ref func_ref = IR_UNUSED;
8855
8856 if (jit->delayed_call_level) {
8857 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8858 return 0;
8859 }
8860 }
8861
8862 if (info) {
8863 call_info = info->callee_info;
8864 while (call_info && call_info->caller_init_opline != opline) {
8865 call_info = call_info->next_callee;
8866 }
8867 if (call_info && call_info->callee_func && !call_info->is_prototype) {
8868 func = call_info->callee_func;
8869 }
8870 }
8871
8872 if (!func
8873 && trace
8874 && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8875#ifdef _WIN32
8876 /* ASLR */
8877 if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8878 func = (zend_function*)trace->func;
8879 }
8880#else
8881 func = (zend_function*)trace->func;
8882#endif
8883 }
8884
8885#ifdef _WIN32
8886 if (0) {
8887#else
8888 if (opline->opcode == ZEND_INIT_FCALL
8889 && func
8890 && func->type == ZEND_INTERNAL_FUNCTION) {
8891#endif
8892 /* load constant address later */
8893 func_ref = ir_CONST_ADDR(func);
8894 } else if (func && op_array == &func->op_array) {
8895 /* recursive call */
8896 if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8897 || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8898 func_ref = ir_LOAD_A(jit_EX(func));
8899 } else {
8900 func_ref = ir_CONST_ADDR(func);
8901 }
8902 } else {
8903 ir_ref if_func, cache_slot_ref, ref;
8904
8905 // JIT: if (CACHED_PTR(opline->result.num))
8906 cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8907 func_ref = ir_LOAD_A(cache_slot_ref);
8908 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8909 && func
8910 && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8911 && opline->opcode != ZEND_INIT_FCALL) {
8912 /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8913 if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8914 } else {
8915 if_func = ir_IF(func_ref);
8916 }
8917 ir_IF_FALSE_cold(if_func);
8918 if (opline->opcode == ZEND_INIT_FCALL
8919 && func
8920 && func->type == ZEND_USER_FUNCTION
8921 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8922 ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8923 ir_STORE(cache_slot_ref, ref);
8924 ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8925 } else {
8926 zval *zv = RT_CONSTANT(opline, opline->op2);
8927
8928 if (opline->opcode == ZEND_INIT_FCALL) {
8929 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8931 cache_slot_ref);
8932 } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8933 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8934 ir_CONST_ADDR(Z_STR_P(zv + 1)),
8935 cache_slot_ref);
8936 } else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8937 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8939 cache_slot_ref);
8940 } else {
8942 }
8943 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8944 int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8945 func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8946 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8947
8948 if (!exit_addr) {
8949 return 0;
8950 }
8951 if (!func || opline->opcode == ZEND_INIT_FCALL) {
8952 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8953 } else if (!zend_jit_func_guard(jit, ref, func, exit_addr)) {
8954 return 0;
8955 }
8956 } else {
8957jit_SET_EX_OPLINE(jit, opline);
8958 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8959 }
8960 }
8961 ir_MERGE_WITH_EMPTY_TRUE(if_func);
8962 func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8963 }
8964
8965 if (!zend_jit_push_call_frame(jit, opline, op_array, func, 0, 0, checked_stack, func_ref, IR_UNUSED)) {
8966 return 0;
8967 }
8968
8969 if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8970 if (!zend_jit_save_call_chain(jit, call_level)) {
8971 return 0;
8972 }
8973 } else {
8974 ZEND_ASSERT(call_level > 0);
8975 jit->delayed_call_level = call_level;
8976 delayed_call_chain = 1;
8977 }
8978
8979 if (trace
8980 && trace->op == ZEND_JIT_TRACE_END
8981 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
8982 if (!zend_jit_set_ip(jit, opline + 1)) {
8983 return 0;
8984 }
8985 }
8986
8987 return 1;
8988}
8989
8990static int zend_jit_init_method_call(zend_jit_ctx *jit,
8991 const zend_op *opline,
8992 uint32_t b,
8993 const zend_op_array *op_array,
8994 zend_ssa *ssa,
8995 const zend_ssa_op *ssa_op,
8996 int call_level,
8997 uint32_t op1_info,
8998 zend_jit_addr op1_addr,
8999 zend_class_entry *ce,
9000 bool ce_is_instanceof,
9001 bool on_this,
9002 bool delayed_fetch_this,
9003 zend_class_entry *trace_ce,
9004 zend_jit_trace_rec *trace,
9005 int checked_stack,
9006 ir_ref func_ref,
9007 ir_ref this_ref,
9008 bool polymorphic_side_trace)
9009{
9010 zend_func_info *info = ZEND_FUNC_INFO(op_array);
9013 zval *function_name;
9014 ir_ref if_static = IR_UNUSED, cold_path;
9015
9016 ZEND_ASSERT(opline->op2_type == IS_CONST);
9017 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
9018
9019 function_name = RT_CONSTANT(opline, opline->op2);
9020
9021 if (info) {
9022 call_info = info->callee_info;
9023 while (call_info && call_info->caller_init_opline != opline) {
9024 call_info = call_info->next_callee;
9025 }
9026 if (call_info && call_info->callee_func && !call_info->is_prototype) {
9027 func = call_info->callee_func;
9028 }
9029 }
9030
9031 if (polymorphic_side_trace) {
9032 /* function is passed from parent snapshot */
9033 ZEND_ASSERT(func_ref != IR_UNUSED && this_ref != IR_UNUSED);
9034 } else {
9035 ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
9036
9037 if (on_this) {
9038 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
9039 this_ref = jit_Z_PTR(jit, this_addr);
9040 } else {
9041 if (op1_info & MAY_BE_REF) {
9042 if (opline->op1_type == IS_CV) {
9043 // JIT: ZVAL_DEREF(op1)
9044 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
9045 ref = jit_ZVAL_DEREF_ref(jit, ref);
9046 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9047 } else {
9048 ir_ref if_ref;
9049
9050 /* Hack: Convert reference to regular value to simplify JIT code */
9051 ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
9052
9053 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9054 ir_IF_TRUE(if_ref);
9055 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
9056
9058 }
9059 }
9060 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
9061 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9062 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9063 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9064
9065 if (!exit_addr) {
9066 return 0;
9067 }
9068 ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
9069 ir_CONST_ADDR(exit_addr));
9070 } else {
9071 ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
9072
9073 ir_IF_FALSE_cold(if_object);
9074
9075 jit_SET_EX_OPLINE(jit, opline);
9076 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9077 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
9078 jit_ZVAL_ADDR(jit, op1_addr));
9079 } else {
9080 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
9081 jit_ZVAL_ADDR(jit, op1_addr));
9082 }
9083 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
9084 ir_IF_TRUE(if_object);
9085 }
9086 }
9087
9088 this_ref = jit_Z_PTR(jit, op1_addr);
9089 }
9090
9091 if (jit->delayed_call_level) {
9092 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9093 return 0;
9094 }
9095 }
9096
9097 if (func) {
9098 // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9099 ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9100
9101 if_found = ir_IF(ref);
9102 ir_IF_TRUE(if_found);
9103 fast_path = ir_END();
9104 } else {
9105 // JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
9106 run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
9107 ref = ir_EQ(
9108 ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
9109 ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
9110 if_found = ir_IF(ref);
9111 ir_IF_TRUE(if_found);
9112
9113 // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9114 ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
9115 fast_path = ir_END();
9116
9117 }
9118
9119 ir_IF_FALSE_cold(if_found);
9120 jit_SET_EX_OPLINE(jit, opline);
9121
9122 if (!jit->ctx.fixed_call_stack_size) {
9123 // JIT: alloca(sizeof(void*));
9124 this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
9125 } else {
9126#ifdef _WIN64
9127 this_ref2 = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9128#else
9129 this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
9130#endif
9131 }
9132 ir_STORE(this_ref2, this_ref);
9133
9134 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9135 ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
9136 this_ref,
9137 ir_CONST_ADDR(function_name),
9138 this_ref2);
9139 } else {
9140 ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
9141 this_ref,
9142 ir_CONST_ADDR(function_name),
9143 this_ref2);
9144 }
9145
9146
9147 if (!jit->ctx.fixed_call_stack_size) {
9148 this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9149 // JIT: revert alloca
9150 ir_AFREE(ir_CONST_ADDR(0x10));
9151 } else {
9152#ifdef _WIN64
9153 this_ref2 = ir_LOAD_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9154#else
9155 this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9156#endif
9157 }
9158
9159 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9160
9161 ir_MERGE_WITH(fast_path);
9162 func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
9163 this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
9164 }
9165
9166 if ((!func || zend_jit_may_be_modified(func, op_array))
9167 && trace
9168 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9169 && trace->func) {
9170 int32_t exit_point;
9171 const void *exit_addr;
9172
9173 exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
9174 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9175 if (!exit_addr) {
9176 return 0;
9177 }
9178
9179 jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
9180 jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
9181
9182 func = (zend_function*)trace->func;
9183
9184 if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9185 return 0;
9186 }
9187 }
9188
9189 if (!func) {
9190 // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9191 if_static = ir_IF(ir_AND_U32(
9192 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9194 ir_IF_TRUE_cold(if_static);
9195 }
9196
9197 if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9198 ir_ref ret;
9199
9200 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9201 ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_metod_call_frame_tmp),
9202 this_ref,
9203 func_ref,
9204 ir_CONST_U32(opline->extended_value));
9205 } else {
9206 ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_metod_call_frame),
9207 this_ref,
9208 func_ref,
9209 ir_CONST_U32(opline->extended_value));
9210 }
9211
9212 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
9213 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9214 }
9215 jit_STORE_IP(jit, ret);
9216 }
9217
9218 if (!func) {
9219 cold_path = ir_END();
9220 ir_IF_FALSE(if_static);
9221 }
9222
9223 if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9224 if (!zend_jit_push_call_frame(jit, opline, NULL, func, 0, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
9225 return 0;
9226 }
9227 }
9228
9229 if (!func) {
9230 ir_MERGE_WITH(cold_path);
9231 }
9232 zend_jit_start_reuse_ip(jit);
9233
9234 if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9235 if (!zend_jit_save_call_chain(jit, call_level)) {
9236 return 0;
9237 }
9238 } else {
9239 ZEND_ASSERT(call_level > 0);
9240 delayed_call_chain = 1;
9241 jit->delayed_call_level = call_level;
9242 }
9243
9244 if (trace
9245 && trace->op == ZEND_JIT_TRACE_END
9246 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
9247 if (!zend_jit_set_ip(jit, opline + 1)) {
9248 return 0;
9249 }
9250 }
9251
9252 return 1;
9253}
9254
9255static int zend_jit_init_closure_call(zend_jit_ctx *jit,
9256 const zend_op *opline,
9257 uint32_t b,
9258 const zend_op_array *op_array,
9259 zend_ssa *ssa,
9260 const zend_ssa_op *ssa_op,
9261 int call_level,
9262 zend_jit_trace_rec *trace,
9263 int checked_stack)
9264{
9266 zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9267 ir_ref ref;
9268
9269 ref = jit_Z_PTR(jit, op2_addr);
9270
9271 if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9272 && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9273 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9274 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9275
9276 if (!exit_addr) {
9277 return 0;
9278 }
9279
9280 ir_GUARD(
9281 ir_EQ(
9284 ir_CONST_ADDR(exit_addr));
9285
9286 if (ssa->var_info && ssa_op->op2_use >= 0) {
9287 ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9288 ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9289 ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9290 }
9291 }
9292
9293 if (trace
9294 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9295 && trace->func
9296 && trace->func->type == ZEND_USER_FUNCTION) {
9297 const zend_op *opcodes;
9298 int32_t exit_point;
9299 const void *exit_addr;
9300
9301 func = (zend_function*)trace->func;
9302 opcodes = func->op_array.opcodes;
9303 exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9304 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9305 if (!exit_addr) {
9306 return 0;
9307 }
9308
9309 ir_GUARD(
9310 ir_EQ(
9311 ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9312 ir_CONST_ADDR(opcodes)),
9313 ir_CONST_ADDR(exit_addr));
9314 }
9315
9316 if (jit->delayed_call_level) {
9317 if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9318 return 0;
9319 }
9320 }
9321
9322 if (!zend_jit_push_call_frame(jit, opline, NULL, func, 1, 0, checked_stack, ref, IR_UNUSED)) {
9323 return 0;
9324 }
9325
9326 if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9327 if (!zend_jit_save_call_chain(jit, call_level)) {
9328 return 0;
9329 }
9330 } else {
9331 ZEND_ASSERT(call_level > 0);
9332 delayed_call_chain = 1;
9333 jit->delayed_call_level = call_level;
9334 }
9335
9336 if (trace
9337 && trace->op == ZEND_JIT_TRACE_END
9338 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
9339 if (!zend_jit_set_ip(jit, opline + 1)) {
9340 return 0;
9341 }
9342 }
9343
9344 return 1;
9345}
9346
9347static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9348{
9349 uint32_t arg_num = opline->op2.num;
9350 zend_jit_addr arg_addr;
9351
9353
9354 if (!zend_jit_reuse_ip(jit)) {
9355 return 0;
9356 }
9357
9358 if (opline->opcode == ZEND_SEND_VAL_EX) {
9359 uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9360
9362
9363 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9364 && JIT_G(current_frame)
9365 && JIT_G(current_frame)->call
9366 && JIT_G(current_frame)->call->func) {
9367 if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9368 /* Don't generate code that always throws exception */
9369 return 0;
9370 }
9371 } else {
9372 ir_ref cond = ir_AND_U32(
9374 ir_CONST_U32(mask));
9375
9376 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9377 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9378 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9379 if (!exit_addr) {
9380 return 0;
9381 }
9382 ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9383 } else {
9384 ir_ref if_pass_by_ref;
9385
9386 if_pass_by_ref = ir_IF(cond);
9387
9388 ir_IF_TRUE_cold(if_pass_by_ref);
9389 if (Z_MODE(op1_addr) == IS_REG) {
9390 /* set type to avoid zval_ptr_dtor() on uninitialized value */
9391 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9392 jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9393 }
9394 jit_SET_EX_OPLINE(jit, opline);
9395 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9396
9397 ir_IF_FALSE(if_pass_by_ref);
9398 }
9399 }
9400 }
9401
9402 arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9403
9404 if (opline->op1_type == IS_CONST) {
9405 zval *zv = RT_CONSTANT(opline, opline->op1);
9406
9407 jit_ZVAL_COPY_CONST(jit,
9408 arg_addr,
9410 zv, 1);
9411 } else {
9412 jit_ZVAL_COPY(jit,
9413 arg_addr,
9414 MAY_BE_ANY,
9415 op1_addr, op1_info, 0);
9416 }
9417
9418 return 1;
9419}
9420
9421static 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)
9422{
9423 zend_jit_addr op1_addr, arg_addr, ref_addr;
9424 ir_ref ref_path = IR_UNUSED;
9425
9426 op1_addr = OP1_ADDR();
9427 arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9428
9429 if (!zend_jit_reuse_ip(jit)) {
9430 return 0;
9431 }
9432
9433 if (opline->op1_type == IS_VAR) {
9434 if (op1_info & MAY_BE_INDIRECT) {
9435 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9436 }
9437 } else if (opline->op1_type == IS_CV) {
9438 if (op1_info & MAY_BE_UNDEF) {
9439 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9440 // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9441 ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9442 ir_IF_FALSE(if_def);
9443 // JIT: ZVAL_NULL(op1)
9444 jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9446 }
9447 op1_info &= ~MAY_BE_UNDEF;
9448 op1_info |= MAY_BE_NULL;
9449 }
9450 } else {
9452 }
9453
9454 if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9455 ir_ref ref, ref2;
9456
9457 if (op1_info & MAY_BE_REF) {
9458 ir_ref if_ref;
9459
9460 // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9461 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9462 ir_IF_TRUE(if_ref);
9463 // JIT: ref = Z_PTR_P(op1)
9464 ref = jit_Z_PTR(jit, op1_addr);
9465 // JIT: GC_ADDREF(ref)
9466 jit_GC_ADDREF(jit, ref);
9467 // JIT: ZVAL_REFERENCE(arg, ref)
9468 jit_set_Z_PTR(jit, arg_addr, ref);
9469 jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9470 ref_path = ir_END();
9471 ir_IF_FALSE(if_ref);
9472 }
9473
9474 // JIT: ZVAL_NEW_REF(arg, varptr);
9475 // JIT: ref = emalloc(sizeof(zend_reference));
9476 ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9477 // JIT: GC_REFCOUNT(ref) = 2
9478 jit_set_GC_REFCOUNT(jit, ref, 2);
9479 // JIT: GC_TYPE(ref) = GC_REFERENCE
9483 ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9484
9485 // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9486 jit_ZVAL_COPY(jit,
9487 ref_addr,
9488 MAY_BE_ANY,
9489 op1_addr, op1_info, 0);
9490
9491 // JIT: ZVAL_REFERENCE(arg, ref)
9492 jit_set_Z_PTR(jit, op1_addr, ref);
9493 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9494
9495 // JIT: ZVAL_REFERENCE(arg, ref)
9496 jit_set_Z_PTR(jit, arg_addr, ref);
9497 jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9498 }
9499
9500 if (ref_path) {
9501 ir_MERGE_WITH(ref_path);
9502 }
9503
9504 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9505
9506 return 1;
9507}
9508
9509static 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)
9510{
9511 uint32_t arg_num = opline->op2.num;
9512 zend_jit_addr arg_addr;
9513 ir_ref end_inputs = IR_UNUSED;
9514
9515 ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9516 opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9518
9519 arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9520
9521 if (!zend_jit_reuse_ip(jit)) {
9522 return 0;
9523 }
9524
9525 if (opline->opcode == ZEND_SEND_VAR_EX) {
9526 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9527 && JIT_G(current_frame)
9528 && JIT_G(current_frame)->call
9529 && JIT_G(current_frame)->call->func) {
9530 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9531 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9532 return 0;
9533 }
9534 return 1;
9535 }
9536 } else {
9537 uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9538
9539 // JIT: if (RX->func->quick_arg_flags & mask)
9540 ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9542 ir_CONST_U32(mask)));
9543 ir_IF_TRUE_cold(if_send_by_ref);
9544
9545 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9546 return 0;
9547 }
9548
9549 ir_END_list(end_inputs);
9550 ir_IF_FALSE(if_send_by_ref);
9551 }
9552 } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9553 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9554 && JIT_G(current_frame)
9555 && JIT_G(current_frame)->call
9556 && JIT_G(current_frame)->call->func) {
9557 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9558
9559 // JIT: ZVAL_COPY_VALUE(arg, op1)
9560 jit_ZVAL_COPY(jit,
9561 arg_addr,
9562 MAY_BE_ANY,
9563 op1_addr, op1_info, 0);
9564
9565 if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9566 if (!(op1_info & MAY_BE_REF)) {
9567 /* Don't generate code that always throws exception */
9568 return 0;
9569 } else {
9570 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9571 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9572 if (!exit_addr) {
9573 return 0;
9574 }
9575
9576 // JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9577 ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9578 ir_CONST_ADDR(exit_addr));
9579 }
9580 }
9581 return 1;
9582 }
9583 } else {
9584 uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9585 ir_ref func, if_send_by_ref, if_prefer_ref;
9586
9587 // JIT: if (RX->func->quick_arg_flags & mask)
9589 if_send_by_ref = ir_IF(ir_AND_U32(
9591 ir_CONST_U32(mask)));
9592 ir_IF_TRUE_cold(if_send_by_ref);
9593
9594 mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9595
9596 // JIT: ZVAL_COPY_VALUE(arg, op1)
9597 jit_ZVAL_COPY(jit,
9598 arg_addr,
9599 MAY_BE_ANY,
9600 op1_addr, op1_info, 0);
9601
9602 if (op1_info & MAY_BE_REF) {
9603 ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9604 ir_IF_TRUE(if_ref);
9605 ir_END_list(end_inputs);
9606 ir_IF_FALSE(if_ref);
9607 }
9608
9609 // JIT: if (RX->func->quick_arg_flags & mask)
9610 if_prefer_ref = ir_IF(ir_AND_U32(
9612 ir_CONST_U32(mask)));
9613 ir_IF_TRUE(if_prefer_ref);
9614 ir_END_list(end_inputs);
9615 ir_IF_FALSE(if_prefer_ref);
9616
9617 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9618 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9619 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9620 if (!exit_addr) {
9621 return 0;
9622 }
9623 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9624 } else {
9625 jit_SET_EX_OPLINE(jit, opline);
9626 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9627 jit_ZVAL_ADDR(jit, arg_addr));
9628 zend_jit_check_exception(jit);
9629 ir_END_list(end_inputs);
9630 }
9631
9632 ir_IF_FALSE(if_send_by_ref);
9633 }
9634 } else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9635 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9636 && JIT_G(current_frame)
9637 && JIT_G(current_frame)->call
9638 && JIT_G(current_frame)->call->func) {
9639 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9640 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9641 return 0;
9642 }
9643 return 1;
9644 }
9645 } else {
9646 // JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9647 ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9648 ir_LOAD_U32(jit_RX(This.u1.type_info)),
9650 ir_IF_TRUE_cold(if_send_by_ref);
9651
9652 if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9653 return 0;
9654 }
9655
9656 ir_END_list(end_inputs);
9657 ir_IF_FALSE(if_send_by_ref);
9658 }
9659 }
9660
9661 if (op1_info & MAY_BE_UNDEF) {
9662 ir_ref ref, if_def = IR_UNUSED;
9663
9664 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9665 if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9666 ir_IF_FALSE_cold(if_def);
9667 }
9668
9669 // JIT: zend_jit_undefined_op_helper(opline->op1.var)
9670 jit_SET_EX_OPLINE(jit, opline);
9671 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9672 ir_CONST_U32(opline->op1.var));
9673
9674 // JIT: ZVAL_NULL(arg)
9675 jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9676
9677 // JIT: check_exception
9678 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9679
9680 if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9681 ir_END_list(end_inputs);
9682 ir_IF_TRUE(if_def);
9683 } else {
9684 if (end_inputs) {
9685 ir_END_list(end_inputs);
9686 ir_MERGE_list(end_inputs);
9687 }
9688 return 1;
9689 }
9690 }
9691
9692 if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9693 // JIT: ZVAL_COPY_VALUE(arg, op1)
9694 jit_ZVAL_COPY(jit,
9695 arg_addr,
9696 MAY_BE_ANY,
9697 op1_addr, op1_info, 0);
9698 if (op1_info & MAY_BE_REF) {
9699 // JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9700 ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9701 ir_IF_TRUE(if_ref);
9702 ir_END_list(end_inputs);
9703 ir_IF_FALSE(if_ref);
9704 }
9705 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9706 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9707 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9708 if (!exit_addr) {
9709 return 0;
9710 }
9711 ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9712 } else {
9713 jit_SET_EX_OPLINE(jit, opline);
9714 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9715 jit_ZVAL_ADDR(jit, arg_addr));
9716 zend_jit_check_exception(jit);
9717 }
9718 } else {
9719 if (op1_info & MAY_BE_REF) {
9720 if (opline->op1_type == IS_CV) {
9721 ir_ref ref;
9722
9723 // JIT: ZVAL_DEREF(op1)
9724 ref = jit_ZVAL_ADDR(jit, op1_addr);
9725 ref = jit_ZVAL_DEREF_ref(jit, ref);
9726 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9727
9728 // JIT: ZVAL_COPY(arg, op1)
9729 jit_ZVAL_COPY(jit,
9730 arg_addr,
9731 MAY_BE_ANY,
9732 op1_addr, op1_info, 1);
9733 } else {
9734 ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9735 zend_jit_addr ref_addr;
9736
9737 // JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9738 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9739 ir_IF_TRUE_cold(if_ref);
9740
9741 // JIT: ref = Z_COUNTED_P(op1);
9742 ref = jit_Z_PTR(jit, op1_addr);
9744 ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9745
9746 // JIT: ZVAL_COPY_VALUE(arg, op1);
9747 jit_ZVAL_COPY(jit,
9748 arg_addr,
9749 MAY_BE_ANY,
9750 ref_addr, op1_info, 0);
9751
9752 // JIT: if (GC_DELREF(ref) != 0)
9753 refcount = jit_GC_DELREF(jit, ref);
9754 if_not_zero = ir_IF(refcount);
9755 ir_IF_TRUE(if_not_zero);
9756
9757 // JIT: if (Z_REFCOUNTED_P(arg)
9758 if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9759 ir_IF_TRUE(if_refcounted);
9760 // JIT: Z_ADDREF_P(arg)
9761 jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9762 ir_END_list(end_inputs);
9763 ir_IF_FALSE(if_refcounted);
9764 ir_END_list(end_inputs);
9765
9766 ir_IF_FALSE(if_not_zero);
9767
9768 // JIT: efree(ref)
9769 jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9770 ir_END_list(end_inputs);
9771
9772 ir_IF_FALSE(if_ref);
9773
9774 // JIT: ZVAL_COPY_VALUE(arg, op1);
9775 jit_ZVAL_COPY(jit,
9776 arg_addr,
9777 MAY_BE_ANY,
9778 op1_addr, op1_info, 0);
9779 }
9780 } else {
9781 if (op1_addr != op1_def_addr) {
9782 if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9783 return 0;
9784 }
9785 if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9786 op1_addr = op1_def_addr;
9787 }
9788 }
9789
9790 // JIT: ZVAL_COPY_VALUE(arg, op1)
9791 jit_ZVAL_COPY(jit,
9792 arg_addr,
9793 MAY_BE_ANY,
9794 op1_addr, op1_info, opline->op1_type == IS_CV);
9795 }
9796 }
9797
9798 if (end_inputs) {
9799 ir_END_list(end_inputs);
9800 ir_MERGE_list(end_inputs);
9801 }
9802
9803 return 1;
9804}
9805
9806static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
9807{
9808 uint32_t arg_num = opline->op2.num;
9809 ir_ref ref;
9810
9811 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9812 && JIT_G(current_frame)
9813 && JIT_G(current_frame)->call
9814 && JIT_G(current_frame)->call->func) {
9815 if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9816 if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
9818 // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9819 if (jit->reuse_ip) {
9820 ref = jit_IP(jit);
9821 } else {
9822 ref = ir_LOAD_A(jit_EX(call));
9823 }
9824 ref = jit_CALL(ref, This.u1.type_info);
9826 }
9827 } else {
9828 if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
9830 // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9831 if (jit->reuse_ip) {
9832 ref = jit_IP(jit);
9833 } else {
9834 ref = ir_LOAD_A(jit_EX(call));
9835 }
9836 ref = jit_CALL(ref, This.u1.type_info);
9838 }
9839 }
9840 } else {
9841 // JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
9842 uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9843 ir_ref rx, if_ref, cold_path;
9844
9845 if (!zend_jit_reuse_ip(jit)) {
9846 return 0;
9847 }
9848
9849 rx = jit_IP(jit);
9850
9851 ref = ir_AND_U32(
9853 ir_CONST_U32(mask));
9854 if_ref = ir_IF(ref);
9855 ir_IF_TRUE_cold(if_ref);
9856
9857 // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9858 ref = jit_CALL(rx, This.u1.type_info);
9860
9861 cold_path = ir_END();
9862 ir_IF_FALSE(if_ref);
9863
9864 // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9865 ref = jit_CALL(rx, This.u1.type_info);
9867
9868 ir_MERGE_WITH(cold_path);
9869 }
9870
9871 return 1;
9872}
9873
9874static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
9875{
9876 ir_ref call, if_may_have_undef, ret;
9877
9878 if (jit->reuse_ip) {
9879 call = jit_IP(jit);
9880 } else {
9882 }
9883
9884 if_may_have_undef = ir_IF(ir_AND_U8(
9885 ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
9887
9888 ir_IF_TRUE_cold(if_may_have_undef);
9889 jit_SET_EX_OPLINE(jit, opline);
9891 ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9892 ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
9893
9894 return 1;
9895}
9896
9897static 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)
9898{
9899 zend_func_info *info = ZEND_FUNC_INFO(op_array);
9901 const zend_function *func = NULL;
9902 uint32_t i;
9903 uint32_t call_num_args = 0;
9904 bool unknown_num_args = 0;
9905 const void *exit_addr = NULL;
9906 const zend_op *prev_opline;
9907 ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
9908
9909 prev_opline = opline - 1;
9910 while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
9911 prev_opline--;
9912 }
9913 if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
9914 prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
9915 unknown_num_args = 1;
9916 }
9917
9918 if (info) {
9919 call_info = info->callee_info;
9920 while (call_info && call_info->caller_call_opline != opline) {
9921 call_info = call_info->next_callee;
9922 }
9923 if (call_info && call_info->callee_func && !call_info->is_prototype) {
9924 func = call_info->callee_func;
9925 }
9926 if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
9927 && (!JIT_G(current_frame)
9928 || !JIT_G(current_frame)->call
9929 || !JIT_G(current_frame)->call->func)) {
9930 call_info = NULL; func = NULL; /* megamorphic call from trait */
9931 }
9932 }
9933 if (!func) {
9934 /* resolve function at run time */
9935 } else if (func->type == ZEND_USER_FUNCTION) {
9936 ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
9937 call_num_args = call_info->num_args;
9938 } else if (func->type == ZEND_INTERNAL_FUNCTION) {
9939 ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
9940 call_num_args = call_info->num_args;
9941 } else {
9943 }
9944
9945 if (trace && !func) {
9946 if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
9947 ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION);
9948#ifndef ZEND_WIN32
9949 // TODO: ASLR may cause different addresses in different workers ???
9950 func = trace->func;
9951 if (JIT_G(current_frame) &&
9952 JIT_G(current_frame)->call &&
9953 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9954 call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9955 } else {
9956 unknown_num_args = 1;
9957 }
9958#endif
9959 } else if (trace->op == ZEND_JIT_TRACE_ENTER) {
9960 ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
9961 if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
9962 func = trace->func;
9963 if (JIT_G(current_frame) &&
9964 JIT_G(current_frame)->call &&
9965 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
9966 call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
9967 } else {
9968 unknown_num_args = 1;
9969 }
9970 }
9971 }
9972 }
9973
9974 bool may_have_extra_named_params =
9976 (!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
9977
9978 if (!jit->reuse_ip) {
9979 zend_jit_start_reuse_ip(jit);
9980 // JIT: call = EX(call);
9981 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
9982 }
9983 rx = jit_IP(jit);
9984 zend_jit_stop_reuse_ip(jit);
9985
9986 jit_SET_EX_OPLINE(jit, opline);
9987
9988 if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
9989 if (!func) {
9990 if (trace) {
9991 uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9992
9993 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9994 if (!exit_addr) {
9995 return 0;
9996 }
9997
9998 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10000 ir_AND_U32(
10001 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10003 ir_CONST_ADDR(exit_addr));
10004 }
10005 }
10006 }
10007
10008 if (!jit->delayed_call_level) {
10009 // JIT: EX(call) = call->prev_execute_data;
10011 (call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
10012 }
10013 delayed_call_chain = 0;
10014 jit->delayed_call_level = 0;
10015
10016 // JIT: call->prev_execute_data = execute_data;
10017 ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
10018
10019 if (!func) {
10020 if (!func_ref) {
10021 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10022 }
10023 }
10024
10025 if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10026 if (!func) {
10027 if (!trace) {
10028 ir_ref if_deprecated, ret;
10029
10030 if_deprecated = ir_IF(ir_AND_U32(
10031 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10033 ir_IF_TRUE_cold(if_deprecated);
10034
10035 if (GCC_GLOBAL_REGS) {
10037 } else {
10039 }
10040 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10041 ir_MERGE_WITH_EMPTY_FALSE(if_deprecated);
10042 }
10043 } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10044 ir_ref ret;
10045
10046 if (GCC_GLOBAL_REGS) {
10048 } else {
10050 }
10051 ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10052 }
10053 }
10054
10055 if (!func
10056 && opline->opcode != ZEND_DO_UCALL
10057 && opline->opcode != ZEND_DO_ICALL) {
10058 ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
10059 if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
10060 ir_IF_TRUE(if_user);
10061 }
10062
10063 if ((!func || func->type == ZEND_USER_FUNCTION)
10064 && opline->opcode != ZEND_DO_ICALL) {
10065 bool recursive_call_through_jmp = 0;
10066 uint32_t num_args = 0;
10067
10068 // JIT: EX(call) = NULL;
10070
10071 // JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
10073 RETURN_VALUE_USED(opline) ?
10074 jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
10075 IR_NULL);
10076
10077 // JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
10078 if (!func || func->op_array.cache_size) {
10079 ir_ref run_time_cache;
10080
10081 if (func && op_array == &func->op_array) {
10082 /* recursive call */
10083 run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
10084 } else if (func
10085 && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
10086 && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
10087 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
10088 (uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
10089 } else if ((func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) ||
10090 (JIT_G(current_frame) &&
10091 JIT_G(current_frame)->call &&
10092 TRACE_FRAME_IS_CLOSURE_CALL(JIT_G(current_frame)->call))) {
10093 /* Closures always use direct pointers */
10094 ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10095
10096 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10097 } else {
10098 ir_ref if_odd, run_time_cache2;
10099 ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10100
10101 run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10102 if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
10103 ir_IF_TRUE(if_odd);
10104
10105 run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
10106
10108 run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
10109 }
10110
10111 ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
10112 }
10113
10114 // JIT: EG(current_execute_data) = execute_data = call;
10115 ir_STORE(jit_EG(current_execute_data), rx);
10116 jit_STORE_FP(jit, rx);
10117
10118 // JIT: opline = op_array->opcodes;
10119 if (func && !unknown_num_args) {
10120
10121 for (i = call_num_args; i < func->op_array.last_var; i++) {
10122 uint32_t n = EX_NUM_TO_VAR(i);
10123 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
10124
10125 jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
10126 }
10127
10128 if (call_num_args <= func->op_array.num_args) {
10129 if (!trace || (trace->op == ZEND_JIT_TRACE_END
10130 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10131 if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
10132 if (trace) {
10133 num_args = 0;
10134 } else if (call_info) {
10135 num_args = skip_valid_arguments(op_array, ssa, call_info);
10136 } else {
10137 num_args = call_num_args;
10138 }
10139 } else {
10140 num_args = call_num_args;
10141 }
10142 if (zend_accel_in_shm(func->op_array.opcodes)) {
10143 jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
10144 } else {
10145 if (!func_ref) {
10146 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10147 }
10148 ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10149 if (num_args) {
10150 ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
10151 }
10152 jit_LOAD_IP(jit, ip);
10153 }
10154
10155 if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
10156 /* recursive call */
10157 recursive_call_through_jmp = 1;
10158 }
10159 }
10160 } else {
10161 ir_ref helper;
10162 if (!trace || (trace->op == ZEND_JIT_TRACE_END
10163 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10164 ir_ref ip;
10165
10166 if (zend_accel_in_shm(func->op_array.opcodes)) {
10167 ip = ir_CONST_ADDR(func->op_array.opcodes);
10168 } else {
10169 if (!func_ref) {
10170 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10171 }
10172 ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10173 }
10174 jit_LOAD_IP(jit, ip);
10176 } else {
10178 }
10179 if (GCC_GLOBAL_REGS) {
10180 ir_CALL(IR_VOID, helper);
10181 } else {
10182 ir_CALL_1(IR_VOID, helper, jit_FP(jit));
10183 }
10184 }
10185 } else {
10186 ir_ref ip;
10187 ir_ref merge_inputs = IR_UNUSED;
10188
10189 // JIT: opline = op_array->opcodes
10190 if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10191 ip = ir_CONST_ADDR(func->op_array.opcodes);
10192 } else {
10193 if (!func_ref) {
10194 func_ref = ir_LOAD_A(jit_CALL(rx, func));
10195 }
10196 ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10197 }
10198 jit_LOAD_IP(jit, ip);
10199
10200 // JIT: num_args = EX_NUM_ARGS();
10201 ir_ref num_args, first_extra_arg;
10202
10203 num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
10204 if (func) {
10205 first_extra_arg = ir_CONST_U32(func->op_array.num_args);
10206 } else {
10207 // JIT: first_extra_arg = op_array->num_args;
10208 ZEND_ASSERT(func_ref);
10209 first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
10210 }
10211
10212 // JIT: if (UNEXPECTED(num_args > first_extra_arg))
10213 ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
10214 ir_IF_TRUE_cold(if_extra_args);
10215 if (GCC_GLOBAL_REGS) {
10217 } else {
10219 }
10220 ir_END_list(merge_inputs);
10221 ir_IF_FALSE(if_extra_args);
10222 if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10223 if (!func) {
10224 // JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10225 ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
10226 ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10228 ir_IF_TRUE(if_has_type_hints);
10229 ir_END_list(merge_inputs);
10230 ir_IF_FALSE(if_has_type_hints);
10231 }
10232 // JIT: opline += num_args;
10233
10235
10236 if (sizeof(void*) == 8) {
10237 ref = ir_ZEXT_A(ref);
10238 }
10239
10240 if (GCC_GLOBAL_REGS) {
10241 jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10242 } else {
10243 ir_ref addr = jit_EX(opline);
10244
10246 }
10247 }
10248
10249 ir_END_list(merge_inputs);
10250 ir_MERGE_list(merge_inputs);
10251
10252 // JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10253 ir_ref last_var;
10254
10255 if (func) {
10256 last_var = ir_CONST_U32(func->op_array.last_var);
10257 } else {
10258 ZEND_ASSERT(func_ref);
10259 last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10260 }
10261
10262 ir_ref idx = ir_SUB_U32(last_var, num_args);
10263 ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10264 ir_IF_TRUE(if_need);
10265
10266 // JIT: zval *var = EX_VAR_NUM(num_args);
10267 if (sizeof(void*) == 8) {
10269 }
10270 ir_ref var_ref = ir_ADD_OFFSET(
10271 ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10272 (ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10273
10274 ir_ref loop = ir_LOOP_BEGIN(ir_END());
10275 var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10276 idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10277 ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10278 ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10279 ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10280 ir_PHI_SET_OP(idx, 2, idx2);
10281 ir_ref if_not_zero = ir_IF(idx2);
10282 ir_IF_TRUE(if_not_zero);
10283 ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10284 ir_IF_FALSE(if_not_zero);
10286 }
10287
10288 if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10289 ir_ref observer_handler;
10290 ir_ref rx = jit_FP(jit);
10291 struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10292 if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10293 ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10294 jit_SET_EX_OPLINE(jit, trace[1].opline);
10295 } else if (GCC_GLOBAL_REGS) {
10296 // EX(opline) = opline
10297 ir_STORE(jit_EX(opline), jit_IP(jit));
10298 }
10299 jit_observer_fcall_begin(jit, rx, observer_handler);
10300
10301 if (trace) {
10302 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10303
10304 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10305 if (!exit_addr) {
10306 return 0;
10307 }
10308 } else {
10309 exit_addr = NULL;
10310 }
10311
10312 zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr);
10313
10314 jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10315 }
10316
10317 if (trace) {
10318 if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10319 user_path = ir_END();
10320 }
10321 } else {
10322 zend_basic_block *bb;
10323
10324 do {
10325 if (recursive_call_through_jmp) {
10326 ir_ref begin, end;
10327 ir_insn *insn;
10328
10329 /* attempt to convert direct recursive call into loop */
10330 begin = jit->bb_start_ref[num_args];
10332 insn = &jit->ctx.ir_base[begin];
10333 if (insn->op == IR_BEGIN) {
10334 end = ir_LOOP_END();
10335 insn = &jit->ctx.ir_base[begin];
10336 insn->op = IR_LOOP_BEGIN;
10337 insn->inputs_count = 2;
10338 insn->op2 = end;
10339 break;
10340 } else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10341 && insn->inputs_count == 2) {
10342 end = ir_LOOP_END();
10343 insn = &jit->ctx.ir_base[begin];
10344 insn->op = IR_LOOP_BEGIN;
10345 insn->inputs_count = 3;
10346 insn->op3 = end;
10347 break;
10348 } else if (insn->op == IR_LOOP_BEGIN && insn->inputs_count == 3) {
10349 ZEND_ASSERT(jit->ctx.ir_base[insn->op3].op == IR_LOOP_END);
10350 jit->ctx.ir_base[insn->op3].op = IR_END;
10351 ir_MERGE_2(insn->op3, ir_END());
10352 end = ir_LOOP_END();
10353 insn = &jit->ctx.ir_base[begin];
10354 insn->op3 = end;
10355 break;
10356 }
10357 }
10358 /* fallback to indirect JMP or RETURN */
10359 if (GCC_GLOBAL_REGS) {
10360 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
10361 } else {
10363 }
10364 } while (0);
10365
10366 bb = &jit->ssa->cfg.blocks[jit->b];
10367 if (bb->successors_count > 0) {
10368 int succ;
10369 ir_ref ref;
10370
10371 ZEND_ASSERT(bb->successors_count == 1);
10372 succ = bb->successors[0];
10373 /* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10374 ref = jit->ctx.insns_count - 1;
10375 ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10376 || jit->ctx.ir_base[ref].op == IR_RETURN
10377 || jit->ctx.ir_base[ref].op == IR_LOOP_END);
10379 ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10380 if (func || (opline->opcode == ZEND_DO_UCALL)) {
10381 _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10382 jit->b = -1;
10383 } else {
10384 user_path = ref;
10385 }
10386 }
10387 }
10388 }
10389
10390 if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10391 && (opline->opcode != ZEND_DO_UCALL)) {
10392 if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10393 ir_IF_FALSE(if_user);
10394 }
10395
10396 // JIT: EG(current_execute_data) = execute_data;
10397 ir_STORE(jit_EG(current_execute_data), rx);
10398
10399 bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10400 if (may_have_observer) {
10401 ir_ref observer_handler;
10402 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)));
10403 jit_observer_fcall_begin(jit, rx, observer_handler);
10404 jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10405 }
10406
10407 // JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10408 ir_ref res_addr = IR_UNUSED, func_ptr;
10409
10410 if (RETURN_VALUE_USED(opline)) {
10411 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10412 } else {
10413 /* CPU stack allocated temporary zval */
10414 ir_ref ptr;
10415
10416 if (!jit->ctx.fixed_call_stack_size) {
10417 // JIT: alloca(sizeof(void*));
10418 ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10419 } else {
10420#ifdef _WIN64
10421 ptr = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
10422#else
10423 ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10424#endif
10425 }
10426 res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10427 }
10428
10429 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10430
10431 zend_jit_reset_last_valid_opline(jit);
10432
10433 // JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10434 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10437 } else {
10438 if (func) {
10439 func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10440 } else {
10442#if defined(IR_TARGET_X86)
10443 func_ptr = ir_CAST_FC_FUNC(func_ptr);
10444#endif
10445 }
10446 ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10447 }
10448
10449 if (may_have_observer) {
10450 jit_observer_fcall_end(jit, rx, res_ref);
10451 }
10452
10453 /* When zend_interrupt_function is set, it gets called while
10454 * the frame is still on top. This is less efficient than
10455 * doing it later once it's popped off. There is code further
10456 * down that handles when there isn't an interrupt function.
10457 */
10459 // JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
10460 ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
10461 ir_IF_TRUE_cold(if_interrupt);
10463 ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
10464 }
10465
10466 // JIT: EG(current_execute_data) = execute_data;
10467 ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10468
10469 // JIT: zend_vm_stack_free_args(call);
10470 if (func && !unknown_num_args) {
10471 for (i = 0; i < call_num_args; i++ ) {
10472 if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10473 uint32_t offset = EX_NUM_TO_VAR(i);
10475
10476 jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, opline);
10477 }
10478 }
10479 } else {
10480 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10481 }
10482
10483 if (may_have_extra_named_params) {
10484 // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10485 ir_ref if_has_named = ir_IF(ir_AND_U8(
10486 ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10488 ir_IF_TRUE_cold(if_has_named);
10489
10491 ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10492
10493 ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10494 }
10495
10496 if (opline->opcode == ZEND_DO_FCALL) {
10497 // TODO: optimize ???
10498 // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10499 ir_ref if_release_this = ir_IF(ir_AND_U8(
10500 ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10502 ir_IF_TRUE_cold(if_release_this);
10503
10504 // JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10505 jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10506
10507 ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10508 }
10509
10510
10511 ir_ref allocated_path = IR_UNUSED;
10512
10513 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10514 !JIT_G(current_frame) ||
10515 !JIT_G(current_frame)->call ||
10516 !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10517 prev_opline->opcode == ZEND_SEND_UNPACK ||
10518 prev_opline->opcode == ZEND_SEND_ARRAY ||
10519 prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10520
10521 // JIT: zend_vm_stack_free_call_frame(call);
10522 // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10523 ir_ref if_allocated = ir_IF(ir_AND_U8(
10524 ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10526 ir_IF_TRUE_cold(if_allocated);
10527
10528 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10529
10530 allocated_path = ir_END();
10531 ir_IF_FALSE(if_allocated);
10532 }
10533
10534 ir_STORE(jit_EG(vm_stack_top), rx);
10535
10536 if (allocated_path) {
10537 ir_MERGE_WITH(allocated_path);
10538 }
10539
10540 if (!RETURN_VALUE_USED(opline)) {
10541 zend_class_entry *ce;
10542 bool ce_is_instanceof;
10543 uint32_t func_info = call_info ?
10544 zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10546
10547 /* If an exception is thrown, the return_value may stay at the
10548 * original value of null. */
10549 func_info |= MAY_BE_NULL;
10550
10552 ir_ref sp;
10553 if (!jit->ctx.fixed_call_stack_size) {
10554 sp = ir_RLOAD_A(IR_REG_SP);
10555 } else {
10556#ifdef _WIN64
10557 sp = jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS);
10558#else
10559 sp = ir_RLOAD_A(IR_REG_SP);
10560#endif
10561 }
10562 res_addr = ZEND_ADDR_REF_ZVAL(sp);
10563 jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
10564 }
10565 if (!jit->ctx.fixed_call_stack_size) {
10566 // JIT: revert alloca
10567 ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10568 }
10569 }
10570
10571 // JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10572 ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10573 jit_STUB_ADDR(jit, jit_stub_icall_throw));
10574
10575 /* If there isn't a zend_interrupt_function, the timeout is
10576 * handled here because it's more efficient.
10577 */
10579 // TODO: Can we avoid checking for interrupts after each call ???
10580 if (trace && jit->last_valid_opline != opline) {
10581 int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10582
10583 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10584 if (!exit_addr) {
10585 return 0;
10586 }
10587 } else {
10588 exit_addr = NULL;
10589 }
10590
10591 zend_jit_check_timeout(jit, opline + 1, exit_addr);
10592 }
10593
10594 if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10595 jit_LOAD_IP_ADDR(jit, opline + 1);
10596 } else if (trace
10597 && trace->op == ZEND_JIT_TRACE_END
10598 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
10599 jit_LOAD_IP_ADDR(jit, opline + 1);
10600 }
10601 }
10602
10603 if (user_path) {
10604 ir_MERGE_WITH(user_path);
10605 }
10606
10607 return 1;
10608}
10609
10610static 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)
10611{
10612 ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10613
10614 ir_IF_FALSE(if_skip_constructor);
10615
10616 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10617 if (!zend_jit_tail_handler(jit, opline)) {
10618 return 0;
10619 }
10620 } else {
10621 if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10622 return 0;
10623 }
10624 }
10625
10626 /* override predecessors of the next block */
10627 ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10628 if (!jit->ctx.control) {
10629 ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10630 ir_IF_TRUE(if_skip_constructor);
10631 ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10632 jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10633 } else {
10634 ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10635 /* merge current control path with the true branch of constructor skip condition */
10636 ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10637 jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10638
10639 jit->b = -1;
10640 }
10641
10642 return 1;
10643}
10644
10645static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
10646{
10647 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10648 uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10649 ir_ref ref, fast_path = IR_UNUSED;
10650
10651 ref = jit_ZVAL_ADDR(jit, res_addr);
10652 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10653 && JIT_G(current_frame)
10654 && JIT_G(current_frame)->prev) {
10655 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10656 uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10657
10658 if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10659 return 1;
10660 }
10661 }
10662
10663 if (ZEND_ARG_SEND_MODE(arg_info)) {
10664 if (opline->opcode == ZEND_RECV_INIT) {
10665 ref = jit_ZVAL_DEREF_ref(jit, ref);
10666 } else {
10667 ref = jit_Z_PTR_ref(jit, ref);
10669 }
10670 }
10671
10672 if (type_mask != 0) {
10673 if (is_power_of_two(type_mask)) {
10674 uint32_t type_code = concrete_type(type_mask);
10675 ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10676 ir_IF_TRUE(if_ok);
10677 fast_path = ir_END();
10678 ir_IF_FALSE_cold(if_ok);
10679 } else {
10680 ir_ref if_ok = ir_IF(ir_AND_U32(
10681 ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10682 ir_CONST_U32(type_mask)));
10683 ir_IF_TRUE(if_ok);
10684 fast_path = ir_END();
10685 ir_IF_FALSE_cold(if_ok);
10686 }
10687 }
10688
10689 jit_SET_EX_OPLINE(jit, opline);
10690 ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10691 ref, ir_CONST_ADDR(arg_info));
10692
10693 if (check_exception) {
10694 ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10695 }
10696
10697 if (fast_path) {
10698 ir_MERGE_WITH(fast_path);
10699 }
10700
10701 return 1;
10702}
10703
10704static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
10705{
10706 uint32_t arg_num = opline->op1.num;
10707 zend_arg_info *arg_info = NULL;
10708
10709 if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10711 arg_info = &op_array->arg_info[arg_num-1];
10712 } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10713 arg_info = &op_array->arg_info[op_array->num_args];
10714 }
10715 if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10716 arg_info = NULL;
10717 }
10718 }
10719
10720 if (arg_info || (opline+1)->opcode != ZEND_RECV) {
10721 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10722 if (!JIT_G(current_frame) ||
10723 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
10724 arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10725 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10726 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10727
10728 if (!exit_addr) {
10729 return 0;
10730 }
10731 ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
10732 ir_CONST_ADDR(exit_addr));
10733 }
10734 } else {
10735 ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10736 ir_IF_FALSE_cold(if_ok);
10737
10738 jit_SET_EX_OPLINE(jit, opline);
10740 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10741 ir_IF_TRUE(if_ok);
10742 }
10743 }
10744
10745 if (arg_info) {
10746 if (!zend_jit_verify_arg_type(jit, opline, arg_info, 1)) {
10747 return 0;
10748 }
10749 }
10750
10751 return 1;
10752}
10753
10754static 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)
10755{
10756 uint32_t arg_num = opline->op1.num;
10757 zval *zv = RT_CONSTANT(opline, opline->op2);
10758 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10759 ir_ref ref, if_fail, skip_path = IR_UNUSED;
10760
10761 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10762 && JIT_G(current_frame)
10763 && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
10764 if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10765 jit_ZVAL_COPY_CONST(jit,
10766 res_addr,
10767 -1, -1,
10768 zv, 1);
10769 }
10770 } else {
10771 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10772 (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
10773 ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10774 ir_IF_TRUE(if_skip);
10775 skip_path = ir_END();
10776 ir_IF_FALSE(if_skip);
10777 }
10778 jit_ZVAL_COPY_CONST(jit,
10779 res_addr,
10780 -1, -1,
10781 zv, 1);
10782 }
10783
10784 if (Z_CONSTANT_P(zv)) {
10785 jit_SET_EX_OPLINE(jit, opline);
10787 jit_ZVAL_ADDR(jit, res_addr),
10789
10790 if_fail = ir_IF(ref);
10791 ir_IF_TRUE_cold(if_fail);
10792 jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, opline);
10793 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10794 ir_IF_FALSE(if_fail);
10795 }
10796
10797 if (skip_path) {
10798 ir_MERGE_WITH(skip_path);
10799 }
10800
10801 if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10802 do {
10803 zend_arg_info *arg_info;
10804
10806 arg_info = &op_array->arg_info[arg_num-1];
10807 } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
10808 arg_info = &op_array->arg_info[op_array->num_args];
10809 } else {
10810 break;
10811 }
10812 if (!ZEND_TYPE_IS_SET(arg_info->type)) {
10813 break;
10814 }
10815 if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw)) {
10816 return 0;
10817 }
10818 } while (0);
10819 }
10820
10821 return 1;
10822}
10823
10824static bool zend_jit_verify_return_type(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
10825{
10826 zend_arg_info *arg_info = &op_array->arg_info[-1];
10827 ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
10828 zend_jit_addr op1_addr = OP1_ADDR();
10829 bool needs_slow_check = 1;
10830 uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10831 ir_ref fast_path = IR_UNUSED;
10832
10833 if (type_mask != 0) {
10834 if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
10835 /* pass */
10836 } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
10837 needs_slow_check = 0;
10838 } else if (is_power_of_two(type_mask)) {
10839 uint32_t type_code = concrete_type(type_mask);
10840 ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
10841
10842 ir_IF_TRUE(if_ok);
10843 fast_path = ir_END();
10844 ir_IF_FALSE_cold(if_ok);
10845 } else {
10846 ir_ref if_ok = ir_IF(ir_AND_U32(
10847 ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
10848 ir_CONST_U32(type_mask)));
10849
10850 ir_IF_TRUE(if_ok);
10851 fast_path = ir_END();
10852 ir_IF_FALSE_cold(if_ok);
10853 }
10854 }
10855 if (needs_slow_check) {
10856 ir_ref ref;
10857
10858 jit_SET_EX_OPLINE(jit, opline);
10859 ref = jit_ZVAL_ADDR(jit, op1_addr);
10860 if (op1_info & MAY_BE_UNDEF) {
10861 ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1);
10862 }
10863
10864 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
10865 ref,
10867 ir_CONST_ADDR(arg_info),
10868 ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num));
10869
10870 zend_jit_check_exception(jit);
10871
10872 if (fast_path) {
10873 ir_MERGE_WITH(fast_path);
10874 }
10875 }
10876
10877 return 1;
10878}
10879
10880static int zend_jit_leave_frame(zend_jit_ctx *jit)
10881{
10882 // JIT: EG(current_execute_data) = EX(prev_execute_data);
10883 ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10884 return 1;
10885}
10886
10887static int zend_jit_free_cvs(zend_jit_ctx *jit)
10888{
10889 // JIT: EG(current_execute_data) = EX(prev_execute_data);
10890 ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
10891
10892 // JIT: zend_free_compiled_variables(execute_data);
10894 return 1;
10895}
10896
10897static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
10898{
10900 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
10901
10902 jit_ZVAL_PTR_DTOR(jit, var_addr, info, 1, NULL);
10903 }
10904 return 1;
10905}
10906
10907static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
10908{
10910 jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, opline);
10911 }
10912 return 1;
10913}
10914
10915static int zend_jit_leave_func(zend_jit_ctx *jit,
10916 const zend_op_array *op_array,
10917 const zend_op *opline,
10918 uint32_t op1_info,
10919 bool left_frame,
10920 zend_jit_trace_rec *trace,
10921 zend_jit_trace_info *trace_info,
10922 int indirect_var_access,
10923 int may_throw)
10924{
10925 bool may_be_top_frame =
10926 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10927 !JIT_G(current_frame) ||
10928 !TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
10929 bool may_need_call_helper =
10930 indirect_var_access || /* may have symbol table */
10931 !op_array->function_name || /* may have symbol table */
10932 may_be_top_frame ||
10933 (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
10934 JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10935 !JIT_G(current_frame) ||
10936 TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
10937 (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
10938 bool may_need_release_this =
10939 !(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
10940 op_array->scope &&
10941 !(op_array->fn_flags & ZEND_ACC_STATIC) &&
10942 (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10943 !JIT_G(current_frame) ||
10944 !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
10945 ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
10946
10947 if (may_need_call_helper) {
10948 if (!left_frame) {
10949 left_frame = 1;
10950 if (!zend_jit_leave_frame(jit)) {
10951 return 0;
10952 }
10953 }
10954 /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
10955 call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
10956 ref = ir_AND_U32(call_info,
10958 if (trace && trace->op != ZEND_JIT_TRACE_END) {
10959 ir_ref if_slow = ir_IF(ref);
10960
10961 ir_IF_TRUE_cold(if_slow);
10962 if (!GCC_GLOBAL_REGS) {
10963 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit));
10964 } else {
10966 }
10967
10968 if (may_be_top_frame) {
10969 // TODO: try to avoid this check ???
10970 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
10971#if 0
10972 /* this check should be handled by the following OPLINE guard */
10973 | cmp IP, zend_jit_halt_op
10974 | je ->trace_halt
10975#endif
10976 } else if (GCC_GLOBAL_REGS) {
10977 ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10978 } else {
10979 ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
10980 }
10981 }
10982
10983 if (!GCC_GLOBAL_REGS) {
10984 // execute_data = EG(current_execute_data)
10985 jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
10986 }
10987 cold_path = ir_END();
10988 ir_IF_FALSE(if_slow);
10989 } else {
10990 ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
10991 }
10992 }
10993
10995 if (!left_frame) {
10996 left_frame = 1;
10997 if (!zend_jit_leave_frame(jit)) {
10998 return 0;
10999 }
11000 }
11001 // JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
11002 jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
11003 } else if (may_need_release_this) {
11004 ir_ref if_release, fast_path = IR_UNUSED;
11005
11006 if (!left_frame) {
11007 left_frame = 1;
11008 if (!zend_jit_leave_frame(jit)) {
11009 return 0;
11010 }
11011 }
11012 if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
11013 // JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
11014 if (!call_info) {
11015 call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11016 }
11018 ir_IF_FALSE(if_release);
11019 fast_path = ir_END();
11020 ir_IF_TRUE(if_release);
11021 }
11022 // JIT: OBJ_RELEASE(execute_data->This))
11023 jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
11024 if (fast_path) {
11025 ir_MERGE_WITH(fast_path);
11026 }
11027 // TODO: avoid EG(excption) check for $this->foo() calls
11028 may_throw = 1;
11029 }
11030
11031 // JIT: EG(vm_stack_top) = (zval*)execute_data
11032 ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
11033
11034 // JITL execute_data = EX(prev_execute_data)
11035 jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
11036
11037 if (!left_frame) {
11038 // JIT: EG(current_execute_data) = execute_data
11039 ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
11040 }
11041
11042 if (trace) {
11043 if (trace->op != ZEND_JIT_TRACE_END
11044 && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11045 zend_jit_reset_last_valid_opline(jit);
11046 } else {
11047 if (GCC_GLOBAL_REGS) {
11048 /* We add extra RLOAD and RSTORE to make fusion for persistent register
11049 * mov (%FP), %IP
11050 * add $0x1c, %IP
11051 * The naive (commented) code leads to extra register allocation and move.
11052 * mov (%FP), %tmp
11053 * add $0x1c, %tmp
11054 * mov %tmp, %FP
11055 */
11056#if 0
11057 jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
11058#else
11059 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11060 jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11061#endif
11062 } else {
11063 ir_ref ref = jit_EX(opline);
11064
11065 ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
11066 }
11067 }
11068
11069 if (cold_path) {
11070 ir_MERGE_WITH(cold_path);
11071 }
11072
11073 if (trace->op == ZEND_JIT_TRACE_BACK
11074 && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11075 const zend_op *next_opline = trace->opline;
11076
11077 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11078 && (op1_info & MAY_BE_RC1)
11080 /* exception might be thrown during destruction of unused return value */
11081 // JIT: if (EG(exception))
11082 ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11083 }
11084 do {
11085 trace++;
11086 } while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
11087 ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11088 next_opline = trace->opline;
11089 ZEND_ASSERT(next_opline != NULL);
11090
11091 if (trace->op == ZEND_JIT_TRACE_END
11092 && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
11093 trace_info->flags |= ZEND_JIT_TRACE_LOOP;
11094
11095 ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
11096
11097 ir_IF_TRUE(if_eq);
11099 ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
11101 ir_IF_FALSE(if_eq);
11102
11103#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
11104 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11105#else
11106 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
11107#endif
11108 } else {
11109 ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
11110 }
11111
11112 zend_jit_set_last_valid_opline(jit, trace->opline);
11113
11114 return 1;
11115 } else if (may_throw ||
11116 (((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11117 && (op1_info & MAY_BE_RC1)
11119 && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
11120 // JIT: if (EG(exception))
11121 ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11122 }
11123
11124 return 1;
11125 } else {
11126 // JIT: if (EG(exception))
11127 ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11128 // JIT: opline = EX(opline) + 1
11129 if (GCC_GLOBAL_REGS) {
11130 jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11131 jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11132 } else {
11133 ir_ref ref = jit_EX(opline);
11134
11135 ir_STORE(ref, ir_ADD_OFFSET(ir_LOAD_A(ref), sizeof(zend_op)));
11136 }
11137 }
11138
11139 if (GCC_GLOBAL_REGS) {
11140 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11141 } else {
11142 ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
11143 }
11144
11145 jit->b = -1;
11146
11147 return 1;
11148}
11149
11150static void zend_jit_common_return(zend_jit_ctx *jit)
11151{
11154}
11155
11156static 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)
11157{
11158 zend_jit_addr ret_addr;
11159 int8_t return_value_used = -1;
11160 ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
11161
11162 ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
11163 ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
11164
11165 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11166 jit->return_inputs = IR_UNUSED;
11167 if (JIT_G(current_frame)) {
11168 if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
11169 return_value_used = 1;
11170 } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
11171 return_value_used = 0;
11172 } else {
11173 return_value_used = -1;
11174 }
11175 }
11176 }
11177
11179 if (Z_MODE(op1_addr) == IS_REG) {
11180 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
11181
11182 if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
11183 return 0;
11184 }
11185 op1_addr = dst;
11186 }
11187 jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
11188 }
11189
11190 // JIT: if (!EX(return_value))
11192 ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
11193 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11195 if (return_value_used == -1) {
11196 if_return_value_used = ir_IF(return_value);
11197 ir_IF_FALSE_cold(if_return_value_used);
11198 }
11199 if (return_value_used != 1) {
11201 ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11202 ir_IF_FALSE(if_refcounted);
11204 ir_IF_TRUE(if_refcounted);
11205 }
11206 ref = jit_Z_PTR(jit, op1_addr);
11207 refcount = jit_GC_DELREF(jit, ref);
11208
11209 if (RC_MAY_BE_1(op1_info)) {
11210 if (RC_MAY_BE_N(op1_info)) {
11211 ir_ref if_non_zero = ir_IF(refcount);
11212 ir_IF_TRUE(if_non_zero);
11214 ir_IF_FALSE(if_non_zero);
11215 }
11216 jit_ZVAL_DTOR(jit, ref, op1_info, opline);
11217 }
11218 if (return_value_used == -1) {
11220 }
11221 }
11222 } else if (return_value_used == -1) {
11223 if_return_value_used = ir_IF(return_value);
11224 ir_IF_FALSE_cold(if_return_value_used);
11226 }
11227
11228 if (if_return_value_used) {
11229 ir_IF_TRUE(if_return_value_used);
11230 }
11231
11232 if (return_value_used == 0) {
11233 if (jit->return_inputs) {
11237 jit->return_inputs = IR_UNUSED;
11238 }
11239 return 1;
11240 }
11241
11242 if (opline->op1_type == IS_CONST) {
11243 zval *zv = RT_CONSTANT(opline, opline->op1);
11244
11245 jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
11246 } else if (opline->op1_type == IS_TMP_VAR) {
11247 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11248 } else if (opline->op1_type == IS_CV) {
11249 if (op1_info & MAY_BE_REF) {
11250 ref = jit_ZVAL_ADDR(jit, op1_addr);
11251 ref = jit_ZVAL_DEREF_ref(jit, ref);
11252 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11253 }
11254
11256 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11257 (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11258 !op_array->function_name) {
11259 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 1);
11260 } else if (return_value_used != 1) {
11261 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11262 // JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11263 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11264 } else {
11265 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11266 }
11267 } else {
11268 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11269 }
11270 } else {
11271 if (op1_info & MAY_BE_REF) {
11272 ir_ref if_ref, ref2, if_non_zero;
11273 zend_jit_addr ref_addr;
11274
11275 if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11276 ir_IF_TRUE_cold(if_ref);
11277
11278 // JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11279 ref = jit_Z_PTR(jit, op1_addr);
11280
11281 // JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11283 ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11284 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, 0);
11285 ref2 = jit_GC_DELREF(jit, ref);
11286 if_non_zero = ir_IF(ref2);
11287 ir_IF_TRUE(if_non_zero);
11288
11289 // JIT: if (IS_REFCOUNTED())
11290 ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11291 ir_IF_FALSE(if_refcounted);
11293 ir_IF_TRUE(if_refcounted);
11294
11295 // JIT: ADDREF
11296 ref2 = jit_Z_PTR(jit, ret_addr);
11297 jit_GC_ADDREF(jit, ref2);
11299
11300 ir_IF_FALSE(if_non_zero);
11301
11302 jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11304
11305 ir_IF_FALSE(if_ref);
11306 }
11307 jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, 0);
11308 }
11309
11310 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11311 if (jit->return_inputs) {
11314 jit->return_inputs = IR_UNUSED;
11315 }
11316 } else {
11318 jit->b = -1;
11319 }
11320
11321 return 1;
11322}
11323
11324static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11325{
11326 zend_jit_addr op1_addr = OP1_ADDR();
11327 zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11328 ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11329 ir_ref if_fit, if_reference, if_same_key, fast_path;
11330 ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11331
11332 // JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11333 cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11334 idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11335
11336 // JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11337 num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11338 ir_CONST_U32(sizeof(Bucket)));
11339 if (sizeof(void*) == 8) {
11340 num_used_ref = ir_ZEXT_A(num_used_ref);
11341 }
11342 if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11343 ir_IF_FALSE_cold(if_fit);
11344 ir_END_list(slow_inputs);
11345 ir_IF_TRUE(if_fit);
11346
11347 // JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11348 bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11349 if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11350 ir_IF_FALSE_cold(if_reference);
11351 ir_END_list(slow_inputs);
11352 ir_IF_TRUE(if_reference);
11353
11354 // JIT: (EXPECTED(p->key == varname))
11355 if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11356 ir_IF_FALSE_cold(if_same_key);
11357 ir_END_list(slow_inputs);
11358 ir_IF_TRUE(if_same_key);
11359
11360 // JIT: GC_ADDREF(Z_PTR(p->val))
11361 ref = jit_Z_PTR_ref(jit, bucket_ref);
11362 jit_GC_ADDREF(jit, ref);
11363
11364 fast_path = ir_END();
11365 ir_MERGE_list(slow_inputs);
11366
11367 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11368 ir_CONST_ADDR(varname),
11369 cache_slot_ref);
11370
11371 ir_MERGE_WITH(fast_path);
11372 ref = ir_PHI_2(IR_ADDR, ref2, ref);
11373
11375 ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11376
11377 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11378 // JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11379 if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11380 ir_IF_TRUE_cold(if_refcounted);
11381 }
11382
11383 // JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11384 ref2 = jit_Z_PTR(jit, op1_addr);
11385
11386 // JIT: ZVAL_REF(variable_ptr, ref)
11387 jit_set_Z_PTR(jit, op1_addr, ref);
11388 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11389
11390 // JIT: if (GC_DELREF(garbage) == 0)
11391 refcount = jit_GC_DELREF(jit, ref2);
11392 if_non_zero = ir_IF(refcount);
11393 if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11394 ir_IF_TRUE(if_non_zero);
11395 ir_END_list(end_inputs);
11396 }
11397 ir_IF_FALSE(if_non_zero);
11398
11399 jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11400 if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11401 ir_END_list(end_inputs);
11402 ir_IF_TRUE(if_non_zero);
11403
11404 // JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11405 if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11406 ir_IF_TRUE(if_may_not_leak);
11407 ir_END_list(end_inputs);
11408 ir_IF_FALSE(if_may_not_leak);
11409 if (opline) {
11410 jit_SET_EX_OPLINE(jit, opline);
11411 }
11413 }
11414 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11415 ir_END_list(end_inputs);
11416 ir_IF_FALSE(if_refcounted);
11417 }
11418 }
11419
11420 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11421 // JIT: ZVAL_REF(variable_ptr, ref)
11422 jit_set_Z_PTR(jit, op1_addr, ref);
11423 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11424 }
11425
11426 if (end_inputs) {
11427 ir_END_list(end_inputs);
11428 ir_MERGE_list(end_inputs);
11429 }
11430
11431 return 1;
11432}
11433
11434static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11435{
11436 zend_jit_addr op1_addr = OP1_ADDR();
11437
11439 if (may_throw) {
11440 jit_SET_EX_OPLINE(jit, opline);
11441 }
11442 if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11443 ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11444
11445 if (op1_info & MAY_BE_ARRAY) {
11446 if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11447 ir_IF_TRUE(if_array);
11448 ir_END_list(end_inputs);
11449 ir_IF_FALSE(if_array);
11450 }
11451 ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11452 if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11453 ir_IF_TRUE(if_exists);
11454 ir_END_list(end_inputs);
11455 ir_IF_FALSE(if_exists);
11456
11458
11459 ir_END_list(end_inputs);
11460 ir_MERGE_list(end_inputs);
11461 }
11462
11463 jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11464
11465 if (may_throw) {
11466 zend_jit_check_exception(jit);
11467 }
11468 }
11469
11470 return 1;
11471}
11472
11473static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11474{
11475 if (opline->op1_type == IS_CONST) {
11476 zval *zv;
11477 size_t len;
11478
11479 zv = RT_CONSTANT(opline, opline->op1);
11481 len = Z_STRLEN_P(zv);
11482
11483 if (len > 0) {
11484 const char *str = Z_STRVAL_P(zv);
11485
11486 jit_SET_EX_OPLINE(jit, opline);
11489
11490 zend_jit_check_exception(jit);
11491 }
11492 } else {
11493 zend_jit_addr op1_addr = OP1_ADDR();
11494 ir_ref ref;
11495
11497
11498 jit_SET_EX_OPLINE(jit, opline);
11499
11500 ref = jit_Z_PTR(jit, op1_addr);
11504
11505 if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11506 jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, 0, opline);
11507 }
11508
11509 zend_jit_check_exception(jit);
11510 }
11511 return 1;
11512}
11513
11514static 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)
11515{
11516 if (opline->op1_type == IS_CONST) {
11517 zval *zv;
11518 size_t len;
11519
11520 zv = RT_CONSTANT(opline, opline->op1);
11522 len = Z_STRLEN_P(zv);
11523
11524 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11525 if (Z_MODE(res_addr) != IS_REG) {
11526 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11527 } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11528 return 0;
11529 }
11530 } else {
11531 ir_ref ref;
11532
11534
11535 ref = jit_Z_PTR(jit, op1_addr);
11537 jit_set_Z_LVAL(jit, res_addr, ref);
11538
11539 if (Z_MODE(res_addr) == IS_REG) {
11540 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11541 return 0;
11542 }
11543 } else {
11544 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11545 }
11546 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11547 }
11548 return 1;
11549}
11550
11551static 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)
11552{
11553 if (opline->op1_type == IS_CONST) {
11554 zval *zv;
11556
11557 zv = RT_CONSTANT(opline, opline->op1);
11559 count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11560
11561 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11562 if (Z_MODE(res_addr) != IS_REG) {
11563 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11564 } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11565 return 0;
11566 }
11567 } else {
11568 ir_ref ref;
11569
11571 // Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11572
11573 ref = jit_Z_PTR(jit, op1_addr);
11574 if (sizeof(void*) == 8) {
11575 ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11576 ref = ir_ZEXT_L(ref);
11577 } else {
11578 ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11579 }
11580 jit_set_Z_LVAL(jit, res_addr, ref);
11581
11582 if (Z_MODE(res_addr) == IS_REG) {
11583 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11584 return 0;
11585 }
11586 } else {
11587 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11588 }
11589 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11590 }
11591
11592 if (may_throw) {
11593 zend_jit_check_exception(jit);
11594 }
11595 return 1;
11596}
11597
11598static 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)
11599{
11600 HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11601 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11602 ir_ref ref;
11603
11604 ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11606
11607 // JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11608 if (opline->op1_type != IS_CONST) {
11611 jit_Z_PTR(jit, op1_addr));
11612 } else {
11613 zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11614
11617 }
11618
11619 if (exit_addr) {
11620 if (smart_branch_opcode == ZEND_JMPZ) {
11621 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11622 } else {
11623 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11624 }
11625 } else if (smart_branch_opcode) {
11626 zend_basic_block *bb;
11627
11628 ZEND_ASSERT(jit->b >= 0);
11629 bb = &jit->ssa->cfg.blocks[jit->b];
11630 ZEND_ASSERT(bb->successors_count == 2);
11631 ref = jit_IF_ex(jit, ref,
11632 (smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11633 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11634 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11635 jit->b = -1;
11636 } else {
11637 jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11639 }
11640
11641 return 1;
11642}
11643
11644static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11645{
11646 uint32_t offset;
11647
11648 offset = (opline->opcode == ZEND_ROPE_INIT) ?
11649 opline->result.var :
11650 opline->op1.var + opline->extended_value * sizeof(zend_string*);
11651
11652 if (opline->op2_type == IS_CONST) {
11653 zval *zv = RT_CONSTANT(opline, opline->op2);
11654 zend_string *str;
11655
11656 ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11657 str = Z_STR_P(zv);
11658
11659 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11660 } else {
11661 zend_jit_addr op2_addr = OP2_ADDR();
11662 ir_ref ref;
11663
11664 ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11665
11666 ref = jit_Z_PTR(jit, op2_addr);
11667 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11668 if (opline->op2_type == IS_CV) {
11669 ir_ref if_refcounted, long_path;
11670
11671 if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11672 ir_IF_TRUE(if_refcounted);
11673 jit_GC_ADDREF(jit, ref);
11674 long_path = ir_END();
11675
11676 ir_IF_FALSE(if_refcounted);
11677 ir_MERGE_WITH(long_path);
11678 }
11679 }
11680
11681 if (opline->opcode == ZEND_ROPE_END) {
11682 zend_jit_addr res_addr = RES_ADDR();
11683 ir_ref ref;
11684
11685 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11686 ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11687 ir_CONST_U32(opline->extended_value));
11688
11689 jit_set_Z_PTR(jit, res_addr, ref);
11690 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11691 }
11692
11693 return 1;
11694}
11695
11696static int zend_jit_zval_copy_deref_reg(zend_jit_ctx *jit, zend_jit_addr res_addr, uint32_t res_info, zend_jit_addr val_addr, ir_ref type, ir_ref *values)
11697{
11698 ir_ref if_type, val;
11699
11700 if (res_info == MAY_BE_LONG) {
11701 if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_LONG)));
11702 ir_IF_TRUE(if_type);
11703 val = jit_ZVAL_ADDR(jit, val_addr);
11704 ir_END_PHI_list(*values, val);
11705 ir_IF_FALSE(if_type);
11706 val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
11707 ir_END_PHI_list(*values, val);
11708 } else if (res_info == MAY_BE_DOUBLE) {
11709 if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_DOUBLE)));
11710 ir_IF_TRUE(if_type);
11711 val = jit_ZVAL_ADDR(jit, val_addr);
11712 ir_END_PHI_list(*values, val);
11713 ir_IF_FALSE(if_type);
11714 val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
11715 ir_END_PHI_list(*values, val);
11716 } else {
11718 }
11719 return 1;
11720}
11721
11722static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
11723{
11724 ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
11725 ir_refs *merge_inputs, *types, *ptrs;
11726#if SIZEOF_ZEND_LONG == 4
11727 ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
11728 ir_refs *values; /* we need this only for zval.w2 copy */
11729#endif
11730
11731 ir_refs_init(merge_inputs, 4);
11732 ir_refs_init(types, 4);
11733 ir_refs_init(ptrs, 4);
11734#if SIZEOF_ZEND_LONG == 4
11735 ir_refs_init(values, 4);
11736#endif
11737
11738 // JIT: ptr = Z_PTR_P(val);
11739 ptr = jit_Z_PTR(jit, val_addr);
11740
11741 // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11743 ir_IF_FALSE_cold(if_refcounted);
11744 ir_refs_add(merge_inputs, ir_END());
11745 ir_refs_add(types, type);
11746 ir_refs_add(ptrs, ptr);
11747#if SIZEOF_ZEND_LONG == 4
11748 ir_refs_add(values, val);
11749#endif
11750
11751 ir_IF_TRUE(if_refcounted);
11752
11753 // JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
11754 if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
11755// if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
11756 ir_IF_TRUE(if_reference);
11757
11758 // JIT: val = Z_REFVAL_P(val);
11760 type2 = jit_Z_TYPE_INFO_ref(jit, val2);
11761 ptr2 = jit_Z_PTR_ref(jit, val2);
11762
11763 // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11765 ir_IF_FALSE_cold(if_refcounted2);
11766 ir_refs_add(merge_inputs, ir_END());
11767 ir_refs_add(types, type2);
11768 ir_refs_add(ptrs, ptr2);
11769#if SIZEOF_ZEND_LONG == 4
11770 ir_refs_add(values, val2);
11771#endif
11772
11773 ir_IF_TRUE(if_refcounted2);
11774 ir_MERGE_WITH_EMPTY_FALSE(if_reference);
11775 type = ir_PHI_2(IR_U32, type2, type);
11776 ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
11777#if SIZEOF_ZEND_LONG == 4
11778 val = ir_PHI_2(IR_ADDR, val2, val);
11779#endif
11780
11781 // JIT: Z_ADDREF_P(val);
11782 jit_GC_ADDREF(jit, ptr);
11783 ir_refs_add(merge_inputs, ir_END());
11784 ir_refs_add(types, type);
11785 ir_refs_add(ptrs, ptr);
11786#if SIZEOF_ZEND_LONG == 4
11787 ir_refs_add(values, val);
11788#endif
11789
11790 ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
11791 type = ir_PHI_N(IR_U32, types->count, types->refs);
11792 ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
11793#if SIZEOF_ZEND_LONG == 4
11794 val = ir_PHI_N(IR_ADDR, values->count, values->refs);
11795 val_addr = ZEND_ADDR_REF_ZVAL(val);
11796#endif
11797
11798 // JIT: Z_PTR_P(res) = ptr;
11799 jit_set_Z_PTR(jit, res_addr, ptr);
11800#if SIZEOF_ZEND_LONG == 4
11801 jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
11802#endif
11803 jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
11804
11805 return 1;
11806}
11807
11808static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx *jit,
11809 const zend_op *opline,
11810 uint32_t type,
11811 uint32_t op1_info,
11812 uint32_t op2_info,
11813 zend_jit_addr op2_addr,
11814 zend_ssa_range *op2_range,
11815 uint8_t dim_type,
11816 const void *found_exit_addr,
11817 const void *not_found_exit_addr,
11818 const void *exit_addr,
11819 bool result_type_guard,
11820 ir_ref ht_ref,
11821 ir_refs *found_inputs,
11822 ir_refs *found_vals,
11823 ir_ref *end_inputs,
11824 ir_ref *not_found_inputs)
11825{
11826 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11827 ir_ref ref = IR_UNUSED, cond, if_found;
11828 ir_ref if_type = IS_UNUSED;
11829 ir_refs *test_zval_inputs, *test_zval_values;
11830
11831 ir_refs_init(test_zval_inputs, 4);
11832 ir_refs_init(test_zval_values, 4);
11833
11834 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11835 && type == BP_VAR_R
11836 && !exit_addr) {
11837 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11838 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11839 if (!exit_addr) {
11840 return 0;
11841 }
11842 }
11843
11844 if (op2_info & MAY_BE_LONG) {
11845 bool op2_loaded = 0;
11846 bool packed_loaded = 0;
11847 bool bad_packed_key = 0;
11848 ir_ref if_packed = IS_UNDEF;
11849 ir_ref h = IR_UNUSED;
11850 ir_ref idx_not_found_inputs = IR_UNUSED;
11851
11852 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
11853 // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
11854 if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
11855 ir_IF_TRUE(if_type);
11856 }
11857 if (op1_info & MAY_BE_PACKED_GUARD) {
11858 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
11859 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11860
11861 if (!exit_addr) {
11862 return 0;
11863 }
11864 cond = ir_AND_U32(
11865 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11867 if (op1_info & MAY_BE_ARRAY_PACKED) {
11868 ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11869 } else {
11870 ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
11871 }
11872 }
11873 if (type == BP_VAR_W) {
11874 // JIT: hval = Z_LVAL_P(dim);
11875 h = jit_Z_LVAL(jit, op2_addr);
11876 op2_loaded = 1;
11877 }
11878 if (op1_info & MAY_BE_ARRAY_PACKED) {
11879 zend_long val = -1;
11880
11881 if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
11882 val = Z_LVAL_P(Z_ZV(op2_addr));
11883 if (val >= 0 && val < HT_MAX_SIZE) {
11884 packed_loaded = 1;
11885 } else {
11886 bad_packed_key = 1;
11887 }
11888 h = ir_CONST_LONG(val);
11889 } else {
11890 if (!op2_loaded) {
11891 // JIT: hval = Z_LVAL_P(dim);
11892 h = jit_Z_LVAL(jit, op2_addr);
11893 op2_loaded = 1;
11894 }
11895 packed_loaded = 1;
11896 }
11897
11898 if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
11899 /* don't generate "fast" code for packed array */
11900 packed_loaded = 0;
11901 }
11902
11903 if (packed_loaded) {
11904 // JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
11905 if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11906 if_packed = ir_IF(
11907 ir_AND_U32(
11908 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
11910 ir_IF_TRUE(if_packed);
11911 }
11912 // JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
11913 ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
11914#if SIZEOF_ZEND_LONG == 8
11915 if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
11916 || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
11917 /* comapre only the lower 32-bits to allow load fusion on x86_64 */
11918 cond = ir_ULT(ir_TRUNC_U32(h), ref);
11919 } else {
11920 cond = ir_ULT(h, ir_ZEXT_L(ref));
11921 }
11922#else
11923 cond = ir_ULT(h, ref);
11924#endif
11925 if (type == BP_JIT_IS) {
11926 if (not_found_exit_addr) {
11927 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11928 } else {
11929 ir_ref if_fit = ir_IF(cond);
11930 ir_IF_FALSE(if_fit);
11931 ir_END_list(*end_inputs);
11932 ir_IF_TRUE(if_fit);
11933 }
11934 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
11935 ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
11936 } else if (type == BP_VAR_IS && not_found_exit_addr) {
11937 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11938 } else if (type == BP_VAR_RW && not_found_exit_addr) {
11939 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
11940 } else if (type == BP_VAR_IS && result_type_guard) {
11941 ir_ref if_fit = ir_IF(cond);
11942 ir_IF_FALSE(if_fit);
11943 ir_END_list(*not_found_inputs);
11944 ir_IF_TRUE(if_fit);
11945 } else {
11946 ir_ref if_fit = ir_IF(cond);
11947 ir_IF_FALSE(if_fit);
11948 ir_END_list(idx_not_found_inputs);
11949 ir_IF_TRUE(if_fit);
11950 }
11951 // JIT: _ret = &_ht->arPacked[h];
11952 ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
11953 ref = ir_BITCAST_A(ref);
11954 ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
11955 if (type == BP_JIT_IS) {
11956 ir_refs_add(test_zval_values, ref);
11957 ir_refs_add(test_zval_inputs, ir_END());
11958 }
11959 }
11960 }
11961 switch (type) {
11962 case BP_JIT_IS:
11963 if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
11964 if (if_packed) {
11965 ir_IF_FALSE(if_packed);
11966 if_packed = IR_UNUSED;
11967 }
11968 if (!op2_loaded) {
11969 // JIT: hval = Z_LVAL_P(dim);
11970 h = jit_Z_LVAL(jit, op2_addr);
11971 op2_loaded = 1;
11972 }
11973 if (packed_loaded) {
11974 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
11975 } else {
11976 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
11977 }
11978 if (not_found_exit_addr) {
11979 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
11980 } else {
11981 if_found = ir_IF(ref);
11982 ir_IF_FALSE(if_found);
11983 ir_END_list(*end_inputs);
11984 ir_IF_TRUE(if_found);
11985 }
11986 ir_refs_add(test_zval_values, ref);
11987 ir_refs_add(test_zval_inputs, ir_END());
11988 } else if (!not_found_exit_addr && !packed_loaded) {
11989 ir_END_list(*end_inputs);
11990 }
11991 break;
11992 case BP_VAR_R:
11993 case BP_VAR_IS:
11994 case BP_VAR_UNSET:
11995 if (packed_loaded) {
11996 ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
11997
11998 if (result_type_guard) {
11999 /* perform IS_UNDEF check only after result type guard (during deoptimization) */
12000 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12001 ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
12002 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12003 ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
12004 } else {
12005 ir_ref if_def = ir_IF(type_ref);
12006 ir_IF_FALSE(if_def);
12007 ir_END_list(idx_not_found_inputs);
12008 ir_IF_TRUE(if_def);
12009 }
12010 ir_refs_add(found_inputs, ir_END());
12011 ir_refs_add(found_vals, ref);
12012 }
12013 if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12014 if (if_packed) {
12015 ir_IF_FALSE(if_packed);
12016 if_packed = IR_UNUSED;
12017 }
12018 if (!op2_loaded) {
12019 // JIT: hval = Z_LVAL_P(dim);
12020 h = jit_Z_LVAL(jit, op2_addr);
12021 op2_loaded = 1;
12022 }
12023 if (packed_loaded) {
12024 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12025 } else {
12026 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12027 }
12028 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12029 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12030 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12031 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12032 } else if (type == BP_VAR_IS && result_type_guard) {
12033 if_found = ir_IF(ref);
12034 ir_IF_FALSE(if_found);
12035 ir_END_list(*not_found_inputs);
12036 ir_IF_TRUE(if_found);
12037 } else {
12038 if_found = ir_IF(ref);
12039 ir_IF_FALSE(if_found);
12040 ir_END_list(idx_not_found_inputs);
12041 ir_IF_TRUE(if_found);
12042 }
12043 ir_refs_add(found_inputs, ir_END());
12044 ir_refs_add(found_vals, ref);
12045 } else if (!packed_loaded) {
12046 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12047 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12048 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12049 jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
12050 } else if (type == BP_VAR_IS && result_type_guard) {
12051 ir_END_list(*not_found_inputs);
12052 } else {
12053 ir_END_list(idx_not_found_inputs);
12054 }
12055 }
12056
12057 if (idx_not_found_inputs) {
12058 ir_MERGE_list(idx_not_found_inputs);
12059 switch (type) {
12060 case BP_VAR_R:
12062 // JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
12063 // JIT: retval = &EG(uninitialized_zval);
12064 jit_SET_EX_OPLINE(jit, opline);
12065 if (Z_MODE(op2_addr) == IS_REG) {
12066 if (!op2_loaded) {
12067 // JIT: hval = Z_LVAL_P(dim);
12068 h = jit_Z_LVAL(jit, op2_addr);
12069 }
12070 if (GCC_GLOBAL_REGS) {
12072 } else {
12074 }
12075 } else {
12076 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
12077 }
12078 ir_END_list(*end_inputs);
12079 break;
12080 case BP_VAR_IS:
12081 case BP_VAR_UNSET:
12082 if (!not_found_exit_addr) {
12083 // JIT: retval = &EG(uninitialized_zval);
12084 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12085 ir_END_list(*end_inputs);
12086 }
12087 break;
12088 default:
12090 }
12091 }
12092 break;
12093 case BP_VAR_RW:
12094 if (packed_loaded) {
12095 if (not_found_exit_addr) {
12096 ir_refs_add(found_inputs, ir_END());
12097 ir_refs_add(found_vals, ref);
12098 } else {
12099 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12100 ir_IF_TRUE(if_def);
12101 ir_refs_add(found_inputs, ir_END());
12102 ir_refs_add(found_vals, ref);
12103 ir_IF_FALSE_cold(if_def);
12104 ir_END_list(idx_not_found_inputs);
12105 }
12106 }
12107 if (!packed_loaded ||
12108 !not_found_exit_addr ||
12109 (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
12110 if (if_packed) {
12111 ir_IF_FALSE(if_packed);
12112 if_packed = IR_UNUSED;
12113 ir_END_list(idx_not_found_inputs);
12114 } else if (!packed_loaded) {
12115 ir_END_list(idx_not_found_inputs);
12116 }
12117
12118 ir_MERGE_list(idx_not_found_inputs);
12119 if (!op2_loaded) {
12120 // JIT: hval = Z_LVAL_P(dim);
12121 h = jit_Z_LVAL(jit, op2_addr);
12122 }
12123 if (packed_loaded) {
12124 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
12125 ht_ref, h);
12126 } else {
12127 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
12128 }
12129 if (not_found_exit_addr) {
12130 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12131 } else {
12132 if_found = ir_IF(ref);
12133 ir_IF_FALSE(if_found);
12134 ir_END_list(*end_inputs);
12135 ir_IF_TRUE(if_found);
12136 }
12137 ir_refs_add(found_inputs, ir_END());
12138 ir_refs_add(found_vals, ref);
12139 }
12140 break;
12141 case BP_VAR_W:
12142 if (packed_loaded) {
12143 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12144 ir_IF_TRUE_cold(if_def);
12145 ir_refs_add(found_inputs, ir_END());
12146 ir_refs_add(found_vals, ref);
12147 ir_IF_FALSE(if_def);
12148 ir_END_list(idx_not_found_inputs);
12149 }
12150 if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
12151 if (if_packed) {
12152 ir_IF_FALSE(if_packed);
12153 if_packed = IR_UNUSED;
12154 ir_END_list(idx_not_found_inputs);
12155 } else if (!packed_loaded) {
12156 ir_END_list(idx_not_found_inputs);
12157 }
12158 ir_MERGE_list(idx_not_found_inputs);
12159 if (!op2_loaded) {
12160 // JIT: hval = Z_LVAL_P(dim);
12161 h = jit_Z_LVAL(jit, op2_addr);
12162 }
12163 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
12164 ir_refs_add(found_inputs, ir_END());
12165 ir_refs_add(found_vals, ref);
12166 }
12167 break;
12168 default:
12170 }
12171 }
12172
12173 if (op2_info & MAY_BE_STRING) {
12174 ir_ref key;
12175
12176 if (if_type) {
12177 ir_IF_FALSE(if_type);
12178 if_type = IS_UNUSED;
12179 }
12180
12181 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12182 // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
12183 if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
12184 ir_IF_TRUE(if_type);
12185 }
12186
12187 // JIT: offset_key = Z_STR_P(dim);
12188 key = jit_Z_PTR(jit, op2_addr);
12189
12190 // JIT: retval = zend_hash_find(ht, offset_key);
12191 switch (type) {
12192 case BP_JIT_IS:
12193 if (opline->op2_type != IS_CONST) {
12194 ir_ref if_num, end1, ref2;
12195
12196 if_num = ir_IF(
12197 ir_ULE(
12199 ir_CONST_CHAR('9')));
12200 ir_IF_TRUE_cold(if_num);
12201 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12202 end1 = ir_END();
12203 ir_IF_FALSE(if_num);
12204 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12205 ir_MERGE_WITH(end1);
12206 ref = ir_PHI_2(IR_ADDR, ref2, ref);
12207 } else {
12208 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12209 }
12210 if (not_found_exit_addr) {
12211 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12212 } else {
12213 if_found = ir_IF(ref);
12214 ir_IF_FALSE(if_found);
12215 ir_END_list(*end_inputs);
12216 ir_IF_TRUE(if_found);
12217 }
12218 ir_refs_add(test_zval_values, ref);
12219 ir_refs_add(test_zval_inputs, ir_END());
12220 break;
12221 case BP_VAR_R:
12222 case BP_VAR_IS:
12223 case BP_VAR_UNSET:
12224 if (opline->op2_type != IS_CONST) {
12225 ir_ref if_num, end1, ref2;
12226
12227 if_num = ir_IF(
12228 ir_ULE(
12230 ir_CONST_CHAR('9')));
12231 ir_IF_TRUE_cold(if_num);
12232 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12233 end1 = ir_END();
12234 ir_IF_FALSE(if_num);
12235 ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12236 ir_MERGE_WITH(end1);
12237 ref = ir_PHI_2(IR_ADDR, ref2, ref);
12238 } else {
12239 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12240 }
12241 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12242 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12243 } else if (type == BP_VAR_IS && not_found_exit_addr) {
12244 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12245 } else if (type == BP_VAR_IS && result_type_guard) {
12246 if_found = ir_IF(ref);
12247 ir_IF_FALSE(if_found);
12248 ir_END_list(*not_found_inputs);
12249 ir_IF_TRUE(if_found);
12250 } else {
12251 if_found = ir_IF(ref);
12252 switch (type) {
12253 case BP_VAR_R:
12254 ir_IF_FALSE_cold(if_found);
12255 // JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
12256 jit_SET_EX_OPLINE(jit, opline);
12257 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
12258 ir_END_list(*end_inputs);
12259 break;
12260 case BP_VAR_IS:
12261 case BP_VAR_UNSET:
12262 ir_IF_FALSE(if_found);
12263 // JIT: retval = &EG(uninitialized_zval);
12264 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12265 ir_END_list(*end_inputs);
12266 break;
12267 default:
12269 }
12270 ir_IF_TRUE(if_found);
12271 }
12272 ir_refs_add(found_inputs, ir_END());
12273 ir_refs_add(found_vals, ref);
12274 break;
12275 case BP_VAR_RW:
12276 if (opline->op2_type != IS_CONST) {
12277 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
12278 } else {
12279 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
12280 }
12281 if (not_found_exit_addr) {
12282 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12283 } else {
12284 if_found = ir_IF(ref);
12285 ir_IF_FALSE(if_found);
12286 ir_END_list(*end_inputs);
12287 ir_IF_TRUE(if_found);
12288 }
12289 ir_refs_add(found_inputs, ir_END());
12290 ir_refs_add(found_vals, ref);
12291 break;
12292 case BP_VAR_W:
12293 if (opline->op2_type != IS_CONST) {
12294 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12295 } else {
12296 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12297 }
12298 ir_refs_add(found_inputs, ir_END());
12299 ir_refs_add(found_vals, ref);
12300 break;
12301 default:
12303 }
12304 }
12305
12306 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12307 if (if_type) {
12308 ir_IF_FALSE_cold(if_type);
12309 if_type = IS_UNDEF;
12310 }
12311 if (type != BP_VAR_RW) {
12312 jit_SET_EX_OPLINE(jit, opline);
12313 }
12314 ref = jit_ZVAL_ADDR(jit, op2_addr);
12315 switch (type) {
12316 case BP_VAR_R:
12317 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12318 ht_ref,
12319 ref,
12320 jit_ZVAL_ADDR(jit, res_addr));
12321 ir_END_list(*end_inputs);
12322 break;
12323 case BP_JIT_IS:
12324 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12325 if (not_found_exit_addr) {
12326 ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12327 ir_refs_add(found_inputs, ir_END());
12328 } else if (found_exit_addr) {
12329 ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12330 ir_END_list(*end_inputs);
12331 } else {
12332 if_found = ir_IF(ref);
12333 ir_IF_TRUE(if_found);
12334 ir_refs_add(found_inputs, ir_END());
12335 ir_IF_FALSE(if_found);
12336 ir_END_list(*end_inputs);
12337 }
12338 break;
12339 case BP_VAR_IS:
12340 case BP_VAR_UNSET:
12341 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12342 ht_ref,
12343 ref,
12344 jit_ZVAL_ADDR(jit, res_addr));
12345 ir_END_list(*end_inputs);
12346 break;
12347 case BP_VAR_RW:
12348 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12349 if_found = ir_IF(ref);
12350 ir_IF_TRUE(if_found);
12351 ir_refs_add(found_inputs, ir_END());
12352 ir_refs_add(found_vals, ref);
12353 ir_IF_FALSE(if_found);
12354 ir_END_list(*end_inputs);
12355 break;
12356 case BP_VAR_W:
12357 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12358 if_found = ir_IF(ref);
12359 ir_IF_TRUE(if_found);
12360 ir_refs_add(found_inputs, ir_END());
12361 ir_refs_add(found_vals, ref);
12362 ir_IF_FALSE(if_found);
12363 ir_END_list(*end_inputs);
12364 break;
12365 default:
12367 }
12368 }
12369
12370 if (type == BP_JIT_IS
12371 && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12372 /* dead code */
12373 ir_END_list(*end_inputs);
12374 } else if (type == BP_JIT_IS
12375 && (op1_info & MAY_BE_ARRAY)
12376 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12377 && test_zval_inputs->count) {
12378
12379 ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12380 ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12381
12382 if (op1_info & MAY_BE_ARRAY_OF_REF) {
12383 ref = jit_ZVAL_DEREF_ref(jit, ref);
12384 }
12385 cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12386 if (not_found_exit_addr) {
12387 ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12388 ir_refs_add(found_inputs, ir_END());
12389 } else if (found_exit_addr) {
12390 ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12391 ir_END_list(*end_inputs);
12392 } else {
12393 ir_ref if_set = ir_IF(cond);
12394 ir_IF_FALSE(if_set);
12395 ir_END_list(*end_inputs);
12396 ir_IF_TRUE(if_set);
12397 ir_refs_add(found_inputs, ir_END());
12398 }
12399 }
12400
12401 return 1;
12402}
12403
12404static int zend_jit_fetch_dim_read(zend_jit_ctx *jit,
12405 const zend_op *opline,
12406 zend_ssa *ssa,
12407 const zend_ssa_op *ssa_op,
12408 uint32_t op1_info,
12409 zend_jit_addr op1_addr,
12410 bool op1_avoid_refcounting,
12411 uint32_t op2_info,
12412 zend_jit_addr op2_addr,
12413 zend_ssa_range *op2_range,
12414 uint32_t res_info,
12415 zend_jit_addr res_addr,
12416 uint8_t dim_type)
12417{
12418 zend_jit_addr orig_op1_addr;
12419 const void *exit_addr = NULL;
12420 const void *not_found_exit_addr = NULL;
12421 bool result_type_guard = 0;
12422 bool result_avoid_refcounting = 0;
12423 uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12424 int may_throw = 0;
12425 ir_ref if_type = IR_UNUSED;
12426 ir_ref end_inputs = IR_UNUSED;
12427 ir_ref not_found_inputs = IR_UNUSED;
12428
12429 orig_op1_addr = OP1_ADDR();
12430
12431 if (opline->opcode != ZEND_FETCH_DIM_IS
12432 && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12433 && !has_concrete_type(op1_info)) {
12434 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12435 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12436 if (!exit_addr) {
12437 return 0;
12438 }
12439 }
12440
12441 if ((res_info & MAY_BE_GUARD)
12442 && JIT_G(current_frame)
12443 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12444
12445 if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12446 result_type_guard = 1;
12447 res_info &= ~MAY_BE_GUARD;
12448 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12449 }
12450
12451 if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12452 && (opline->opcode == ZEND_FETCH_LIST_R
12453 || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12454 || op1_avoid_refcounting)
12456 && (ssa_op+1)->op1_use == ssa_op->result_def
12458 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12459 result_avoid_refcounting = 1;
12460 ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12461 }
12462
12463 if (opline->opcode == ZEND_FETCH_DIM_IS
12464 && !(res_info & MAY_BE_NULL)) {
12465 uint32_t flags = 0;
12466 uint32_t old_op1_info = 0;
12467 uint32_t old_info;
12468 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12469 int32_t exit_point;
12470
12471 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
12472 && !op1_avoid_refcounting) {
12474 }
12475 if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12478 }
12479
12480 if (op1_avoid_refcounting) {
12481 old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12482 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12483 }
12484
12485 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12486 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12488 exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12489 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12490 not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12491 if (!not_found_exit_addr) {
12492 return 0;
12493 }
12494
12495 if (op1_avoid_refcounting) {
12496 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12497 }
12498 }
12499 }
12500
12501 if (op1_info & MAY_BE_REF) {
12502 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12503 ref = jit_ZVAL_DEREF_ref(jit, ref);
12504 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12505 }
12506
12507 if (op1_info & MAY_BE_ARRAY) {
12508 ir_ref ht_ref, ref;
12509 zend_jit_addr val_addr;
12510 ir_refs *found_inputs, *found_vals;
12511
12512 ir_refs_init(found_inputs, 10);
12513 ir_refs_init(found_vals, 10);
12514
12515 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12516 if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12517 jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12518 } else {
12519 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12520 ir_IF_TRUE(if_type);
12521 }
12522 }
12523
12524 ht_ref = jit_Z_PTR(jit, op1_addr);
12525
12526 if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12527 (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12528 may_throw = 1;
12529 }
12530
12531 if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12532 (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12533 op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12534 result_type_guard, ht_ref, found_inputs, found_vals,
12535 &end_inputs, &not_found_inputs)) {
12536 return 0;
12537 }
12538
12539 if (found_inputs->count) {
12540 ir_MERGE_N(found_inputs->count, found_inputs->refs);
12541 ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12542 val_addr = ZEND_ADDR_REF_ZVAL(ref);
12543
12544 if (result_type_guard) {
12545 uint8_t type = concrete_type(res_info);
12546 uint32_t flags = 0;
12547
12548 if (opline->opcode != ZEND_FETCH_LIST_R
12549 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12550 && !op1_avoid_refcounting) {
12552 }
12553 if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12556 }
12557
12558 val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12559 (op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12560 if (!val_addr) {
12561 return 0;
12562 }
12563
12564 if (not_found_inputs) {
12565 ir_END_list(not_found_inputs);
12566 ir_MERGE_list(not_found_inputs);
12567 }
12568
12569 // ZVAL_COPY
12570 jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12571 if (Z_MODE(res_addr) != IS_REG) {
12572 } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12573 return 0;
12574 }
12575 } else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12576 // ZVAL_COPY_DEREF
12577 ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12578 if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12579 return 0;
12580 }
12581 } else {
12582 // ZVAL_COPY
12583 jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, 1);
12584 }
12585
12586 ir_END_list(end_inputs);
12587 } else if (not_found_inputs) {
12588 ir_MERGE_list(not_found_inputs);
12589 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12590 ir_END_list(end_inputs);
12591 } else if (!end_inputs && jit->ctx.control) {
12592 ir_END_list(end_inputs); /* dead code */
12593 }
12594 }
12595
12596 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12597 if (if_type) {
12598 ir_IF_FALSE_cold(if_type);
12599 if_type = IS_UNDEF;
12600 }
12601
12602 if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12603 ir_ref str_ref;
12604
12605 may_throw = 1;
12606 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12607 if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12608 jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12609 } else {
12610 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12611 ir_IF_TRUE(if_type);
12612 }
12613 }
12614 jit_SET_EX_OPLINE(jit, opline);
12615 str_ref = jit_Z_PTR(jit, op1_addr);
12616 if (opline->opcode != ZEND_FETCH_DIM_IS) {
12617 ir_ref ref;
12618
12619 if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12620 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12621 str_ref, jit_Z_LVAL(jit, op2_addr));
12622 } else {
12623 ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12624 str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12625 }
12626 jit_set_Z_PTR(jit, res_addr, ref);
12627 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12628 } else {
12629 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12630 str_ref,
12631 jit_ZVAL_ADDR(jit, op2_addr),
12632 jit_ZVAL_ADDR(jit, res_addr));
12633 }
12634 ir_END_list(end_inputs);
12635 }
12636
12637 if (op1_info & MAY_BE_OBJECT) {
12638 ir_ref arg2;
12639
12640 if (if_type) {
12641 ir_IF_FALSE_cold(if_type);
12642 if_type = IS_UNDEF;
12643 }
12644
12645 may_throw = 1;
12646 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12647 if (exit_addr) {
12648 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12649 } else {
12650 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12651 ir_IF_TRUE(if_type);
12652 }
12653 }
12654
12655 jit_SET_EX_OPLINE(jit, opline);
12656 if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12657 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12658 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12659 } else {
12660 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12661 }
12662
12663 if (opline->opcode != ZEND_FETCH_DIM_IS) {
12664 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12665 jit_ZVAL_ADDR(jit, op1_addr),
12666 arg2,
12667 jit_ZVAL_ADDR(jit, res_addr));
12668 } else {
12669 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12670 jit_ZVAL_ADDR(jit, op1_addr),
12671 arg2,
12672 jit_ZVAL_ADDR(jit, res_addr));
12673 }
12674
12675 ir_END_list(end_inputs);
12676 }
12677
12678 if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12679 && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12680
12681 if (if_type) {
12682 ir_IF_FALSE_cold(if_type);
12683 if_type = IS_UNDEF;
12684 }
12685
12686 if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12687 jit_SET_EX_OPLINE(jit, opline);
12688 if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12689 may_throw = 1;
12690 zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL, 0, 1, 0);
12691 }
12692
12693 if (op2_info & MAY_BE_UNDEF) {
12694 may_throw = 1;
12695 zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL, 0, 1, 0);
12696 }
12697 }
12698
12699 if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
12700 ir_ref ref;
12701
12702 may_throw = 1;
12703 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12704 ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
12705 } else {
12706 jit_SET_EX_OPLINE(jit, opline);
12707 ref = jit_ZVAL_ADDR(jit, op1_addr);
12708 }
12709 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
12710 }
12711
12712 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12713 ir_END_list(end_inputs);
12714 }
12715 }
12716
12717 if (end_inputs) {
12718 ir_MERGE_list(end_inputs);
12719
12720#ifdef ZEND_JIT_USE_RC_INFERENCE
12721 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12722 /* Magic offsetGet() may increase refcount of the key */
12723 op2_info |= MAY_BE_RCN;
12724 }
12725#endif
12726
12727 if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
12728 if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
12729 may_throw = 1;
12730 }
12731 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
12732 }
12733 if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12734 if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
12735 if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
12736 may_throw = 1;
12737 }
12738 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
12739 }
12740 }
12741
12742 if (may_throw) {
12743 zend_jit_check_exception(jit);
12744 }
12745 } else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
12746 ir_BEGIN(IR_UNUSED); /* unreachable tail */
12747 }
12748
12749 return 1;
12750}
12751
12752static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx *jit,
12753 const zend_op *opline,
12754 uint32_t op1_info,
12755 zend_jit_addr op1_addr,
12756 ir_ref *if_type,
12757 ir_ref *ht_ref,
12758 int *may_throw)
12759{
12760 ir_ref ref = IR_UNUSED;
12761 ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
12762 ir_refs *array_inputs, *array_values;
12763
12764 ir_refs_init(array_inputs, 4);
12766
12767 ref = jit_ZVAL_ADDR(jit, op1_addr);
12768 if (op1_info & MAY_BE_REF) {
12769 ir_ref if_reference, if_array, end1, ref2;
12770
12771 *may_throw = 1;
12772 if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
12773 ir_IF_FALSE(if_reference);
12774 end1 = ir_END();
12775 ir_IF_TRUE_cold(if_reference);
12776 array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
12777 if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
12778 ir_IF_TRUE(if_array);
12779 array_reference_end = ir_END();
12780 ir_IF_FALSE_cold(if_array);
12781 if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
12782 jit_SET_EX_OPLINE(jit, opline);
12783 }
12784 ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
12785 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
12786
12787 ir_MERGE_WITH(end1);
12788 ref = ir_PHI_2(IR_ADDR, ref2, ref);
12789 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12790 }
12791
12792 if (op1_info & MAY_BE_ARRAY) {
12793 ir_ref op1_ref = ref;
12794
12795 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12796 *if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12797 ir_IF_TRUE(*if_type);
12798 }
12799 if (array_reference_end) {
12800 ir_MERGE_WITH(array_reference_end);
12801 op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
12802 }
12803 // JIT: SEPARATE_ARRAY()
12804 ref = jit_Z_PTR_ref(jit, op1_ref);
12805 if (RC_MAY_BE_N(op1_info)) {
12806 if (RC_MAY_BE_1(op1_info)) {
12807 ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
12808 ir_IF_TRUE(if_refcount_1);
12809 ir_refs_add(array_inputs, ir_END());
12810 ir_refs_add(array_values, ref);
12811 ir_IF_FALSE(if_refcount_1);
12812 }
12813 ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
12814 }
12815 if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
12816 ir_refs_add(array_inputs, ir_END());
12817 ir_refs_add(array_values, ref);
12818 }
12819 }
12820
12821 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
12822 if (*if_type) {
12823 ir_IF_FALSE_cold(*if_type);
12824 *if_type = IR_UNUSED;
12825 }
12826 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12827 *if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
12828 ir_IF_TRUE(*if_type);
12829 }
12830 if ((op1_info & MAY_BE_UNDEF)
12831 && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
12832 ir_ref end1 = IR_UNUSED;
12833
12834 *may_throw = 1;
12835 if (op1_info & MAY_BE_NULL) {
12836 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
12837 ir_IF_TRUE(if_def);
12838 end1 = ir_END();
12839 ir_IF_FALSE(if_def);
12840 }
12841 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
12842 if (end1) {
12843 ir_MERGE_WITH(end1);
12844 }
12845 }
12846 // JIT: ZVAL_ARR(container, zend_new_array(8));
12847 ref = ir_CALL_1(IR_ADDR,
12848 jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
12849 jit_ZVAL_ADDR(jit, op1_addr));
12850 if (array_inputs->count) {
12851 ir_refs_add(array_inputs, ir_END());
12852 ir_refs_add(array_values, ref);
12853 }
12854 }
12855
12856 if (array_inputs->count) {
12857 ir_MERGE_N(array_inputs->count, array_inputs->refs);
12858 ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
12859 }
12860
12861 *ht_ref = ref;
12862 return op1_addr;
12863}
12864
12865static int zend_jit_fetch_dim(zend_jit_ctx *jit,
12866 const zend_op *opline,
12867 uint32_t op1_info,
12868 zend_jit_addr op1_addr,
12869 uint32_t op2_info,
12870 zend_jit_addr op2_addr,
12871 zend_ssa_range *op2_range,
12872 zend_jit_addr res_addr,
12873 uint8_t dim_type)
12874{
12875 int may_throw = 0;
12876 ir_ref end_inputs = IR_UNUSED;
12877 ir_ref ref, if_type = IR_UNUSED, ht_ref;
12878
12879 if (opline->opcode == ZEND_FETCH_DIM_RW) {
12880 jit_SET_EX_OPLINE(jit, opline);
12881 }
12882
12883 op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
12884
12885 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
12886 ir_refs *found_inputs, *found_vals;
12887
12888 ir_refs_init(found_inputs, 8);
12889 ir_refs_init(found_vals, 8);
12890
12891 if (opline->op2_type == IS_UNUSED) {
12892 ir_ref if_ok;
12893
12894 may_throw = 1;
12895 // JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
12897 ht_ref, jit_EG(uninitialized_zval));
12898
12899 // JIT: if (UNEXPECTED(!var_ptr)) {
12900 if_ok = ir_IF(ref);
12901 ir_IF_FALSE_cold(if_ok);
12902 if (opline->opcode != ZEND_FETCH_DIM_RW) {
12903 jit_SET_EX_OPLINE(jit, opline);
12904 }
12905 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
12906 ir_END_list(end_inputs);
12907
12908 ir_IF_TRUE(if_ok);
12909 jit_set_Z_PTR(jit, res_addr, ref);
12910 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12911
12912 ir_END_list(end_inputs);
12913 } else {
12914 uint32_t type;
12915
12916 switch (opline->opcode) {
12917 case ZEND_FETCH_DIM_W:
12918 case ZEND_FETCH_LIST_W:
12919 type = BP_VAR_W;
12920 break;
12921 case ZEND_FETCH_DIM_RW:
12922 may_throw = 1;
12923 type = BP_VAR_RW;
12924 break;
12927 break;
12928 default:
12930 }
12931
12932 if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12933 may_throw = 1;
12934 }
12935 if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
12936 op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
12937 0, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
12938 return 0;
12939 }
12940
12941 if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
12942 if (end_inputs) {
12943 ir_MERGE_list(end_inputs);
12944 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12945 end_inputs = ir_END();
12946 }
12947 } else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12948 /* impossible dead path */
12949 end_inputs = ir_END();
12950 } else {
12951 ZEND_ASSERT(end_inputs == IR_UNUSED);
12952 }
12953
12954 if (found_inputs->count) {
12955 ir_MERGE_N(found_inputs->count, found_inputs->refs);
12956 ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12957 jit_set_Z_PTR(jit, res_addr, ref);
12958 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
12959 ir_END_list(end_inputs);
12960 }
12961
12962 }
12963 }
12964
12965 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12966 ir_ref arg2;
12967
12968 may_throw = 1;
12969
12970 if (if_type) {
12971 ir_IF_FALSE(if_type);
12972 if_type = IR_UNUSED;
12973 }
12974
12975 if (opline->opcode != ZEND_FETCH_DIM_RW) {
12976 jit_SET_EX_OPLINE(jit, opline);
12977 }
12978
12979 if (opline->op2_type == IS_UNUSED) {
12980 arg2 = IR_NULL;
12981 } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12982 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12983 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
12984 } else {
12985 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12986 }
12987
12988 switch (opline->opcode) {
12989 case ZEND_FETCH_DIM_W:
12990 case ZEND_FETCH_LIST_W:
12991 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
12992 jit_ZVAL_ADDR(jit, op1_addr),
12993 arg2,
12994 jit_ZVAL_ADDR(jit, res_addr));
12995 break;
12996 case ZEND_FETCH_DIM_RW:
12997 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
12998 jit_ZVAL_ADDR(jit, op1_addr),
12999 arg2,
13000 jit_ZVAL_ADDR(jit, res_addr));
13001 break;
13002// case ZEND_FETCH_DIM_UNSET:
13003// | EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
13004// break;
13005 default:
13007 }
13008
13009 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13010 ir_END_list(end_inputs);
13011 }
13012 }
13013
13014#ifdef ZEND_JIT_USE_RC_INFERENCE
13016 /* ASSIGN_DIM may increase refcount of the key */
13017 op2_info |= MAY_BE_RCN;
13018 }
13019#endif
13020
13021 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
13022 && (op2_info & MAY_HAVE_DTOR)
13023 && (op2_info & MAY_BE_RC1)) {
13024 may_throw = 1;
13025 }
13026
13027 if (end_inputs) {
13028 ir_MERGE_list(end_inputs);
13029 }
13030
13031 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13032
13033 if (may_throw) {
13034 zend_jit_check_exception(jit);
13035 }
13036
13037 return 1;
13038}
13039
13040static int zend_jit_isset_isempty_dim(zend_jit_ctx *jit,
13041 const zend_op *opline,
13042 uint32_t op1_info,
13043 zend_jit_addr op1_addr,
13044 bool op1_avoid_refcounting,
13045 uint32_t op2_info,
13046 zend_jit_addr op2_addr,
13047 zend_ssa_range *op2_range,
13048 uint8_t dim_type,
13049 int may_throw,
13050 uint8_t smart_branch_opcode,
13051 uint32_t target_label,
13052 uint32_t target_label2,
13053 const void *exit_addr)
13054{
13055 zend_jit_addr res_addr;
13056 ir_ref if_type = IR_UNUSED;
13057 ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
13058 ir_refs *true_inputs;
13059
13060 ir_refs_init(true_inputs, 8);
13061
13062 // TODO: support for empty() ???
13064
13065 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13066
13067 if (op1_info & MAY_BE_REF) {
13068 ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
13069 ref = jit_ZVAL_DEREF_ref(jit, ref);
13070 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
13071 }
13072
13073 if (op1_info & MAY_BE_ARRAY) {
13074 const void *found_exit_addr = NULL;
13075 const void *not_found_exit_addr = NULL;
13076 ir_ref ht_ref;
13077
13078 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
13079 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
13080 ir_IF_TRUE(if_type);
13081 }
13082
13083 ht_ref = jit_Z_PTR(jit, op1_addr);
13084
13085 if (exit_addr
13086 && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
13087 && !may_throw
13088 && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
13089 && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
13090 if (smart_branch_opcode == ZEND_JMPNZ) {
13091 found_exit_addr = exit_addr;
13092 } else {
13093 not_found_exit_addr = exit_addr;
13094 }
13095 }
13096 if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
13097 op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
13098 0, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
13099 return 0;
13100 }
13101
13102 if (found_exit_addr) {
13103 ir_MERGE_list(false_inputs);
13104 return 1;
13105 } else if (not_found_exit_addr) {
13106 ir_MERGE_N(true_inputs->count, true_inputs->refs);
13107 return 1;
13108 }
13109 }
13110
13111 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
13112 if (if_type) {
13113 ir_IF_FALSE(if_type);
13114 if_type = IR_UNUSED;
13115 }
13116
13117 if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
13118 ir_ref ref, arg1, arg2, if_true;
13119
13120 jit_SET_EX_OPLINE(jit, opline);
13121 arg1 = jit_ZVAL_ADDR(jit, op1_addr);
13122 if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13123 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13124 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
13125 } else {
13126 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13127 }
13128 ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
13129 if_true = ir_IF(ref);
13130 ir_IF_TRUE(if_true);
13131 ir_refs_add(true_inputs, ir_END());
13132 ir_IF_FALSE(if_true);
13133 ir_END_list(false_inputs);
13134 } else {
13135 if (op2_info & MAY_BE_UNDEF) {
13136 ir_ref end1 = IR_UNUSED;
13137
13138 if (op2_info & MAY_BE_ANY) {
13139 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
13140 ir_IF_TRUE(if_def);
13141 end1 = ir_END();
13142 ir_IF_FALSE(if_def);
13143 }
13144 jit_SET_EX_OPLINE(jit, opline);
13145 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
13146 if (end1) {
13147 ir_MERGE_WITH(end1);
13148 }
13149 }
13150 ir_END_list(false_inputs);
13151 }
13152 }
13153
13154#ifdef ZEND_JIT_USE_RC_INFERENCE
13155 if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
13156 /* Magic offsetExists() may increase refcount of the key */
13157 op2_info |= MAY_BE_RCN;
13158 }
13159#endif
13160
13161 if (true_inputs->count) {
13162 ir_MERGE_N(true_inputs->count, true_inputs->refs);
13163
13164 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13165 if (!op1_avoid_refcounting) {
13166 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13167 }
13168 if (may_throw) {
13169 zend_jit_check_exception_undef_result(jit, opline);
13170 }
13171 if (!(opline->extended_value & ZEND_ISEMPTY)) {
13172 if (exit_addr) {
13173 if (smart_branch_opcode == ZEND_JMPNZ) {
13174 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13175 } else {
13176 ir_END_list(end_inputs);
13177 }
13178 } else if (smart_branch_opcode) {
13179 if (smart_branch_opcode == ZEND_JMPZ) {
13180 _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13181 } else if (smart_branch_opcode == ZEND_JMPNZ) {
13182 _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13183 } else {
13185 }
13186 } else {
13187 jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
13188 ir_END_list(end_inputs);
13189 }
13190 } else {
13191 ZEND_UNREACHABLE(); // TODO: support for empty()
13192 }
13193 }
13194
13195 ir_MERGE_list(false_inputs);
13196 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13197 if (!op1_avoid_refcounting) {
13198 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13199 }
13200 if (may_throw) {
13201 zend_jit_check_exception_undef_result(jit, opline);
13202 }
13203 if (!(opline->extended_value & ZEND_ISEMPTY)) {
13204 if (exit_addr) {
13205 if (smart_branch_opcode == ZEND_JMPZ) {
13206 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13207 } else {
13208 ir_END_list(end_inputs);
13209 }
13210 } else if (smart_branch_opcode) {
13211 if (smart_branch_opcode == ZEND_JMPZ) {
13212 _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13213 } else if (smart_branch_opcode == ZEND_JMPNZ) {
13214 _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13215 } else {
13217 }
13218 } else {
13219 jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
13220 ir_END_list(end_inputs);
13221 }
13222 } else {
13223 ZEND_UNREACHABLE(); // TODO: support for empty()
13224 }
13225
13226 if (!exit_addr && smart_branch_opcode) {
13227 jit->b = -1;
13228 } else {
13229 ir_MERGE_list(end_inputs);
13230 }
13231
13232 return 1;
13233}
13234
13235static int zend_jit_assign_dim(zend_jit_ctx *jit,
13236 const zend_op *opline,
13237 uint32_t op1_info,
13238 zend_jit_addr op1_addr,
13239 uint32_t op2_info,
13240 zend_jit_addr op2_addr,
13241 zend_ssa_range *op2_range,
13242 uint32_t val_info,
13243 zend_jit_addr op3_addr,
13244 zend_jit_addr op3_def_addr,
13245 zend_jit_addr res_addr,
13246 uint8_t dim_type,
13247 int may_throw)
13248{
13249 ir_ref if_type = IR_UNUSED;
13250 ir_ref end_inputs = IR_UNUSED, ht_ref;
13251
13252 if (op3_addr != op3_def_addr && op3_def_addr) {
13253 if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
13254 return 0;
13255 }
13256 if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
13257 op3_addr = op3_def_addr;
13258 }
13259 }
13260
13261 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
13262 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13263 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13264
13265 if (!exit_addr) {
13266 return 0;
13267 }
13268
13269 jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
13270
13271 val_info &= ~MAY_BE_UNDEF;
13272 }
13273
13274 op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13275
13276 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13277 if (opline->op2_type == IS_UNUSED) {
13278 uint32_t var_info = MAY_BE_NULL;
13279 ir_ref if_ok, ref;
13280 zend_jit_addr var_addr;
13281
13282 // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13284 ht_ref, jit_EG(uninitialized_zval));
13285
13286 // JIT: if (UNEXPECTED(!var_ptr)) {
13287 if_ok = ir_IF(ref);
13288 ir_IF_FALSE_cold(if_ok);
13289
13290 // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13291 jit_SET_EX_OPLINE(jit, opline);
13292 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13293
13294 ir_END_list(end_inputs);
13295
13296 ir_IF_TRUE(if_ok);
13297 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13298 if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
13299 return 0;
13300 }
13301 } else {
13302 uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13303 zend_jit_addr var_addr;
13304 ir_ref ref;
13305 ir_refs *found_inputs, *found_values;
13306
13307 ir_refs_init(found_inputs, 8);
13308 ir_refs_init(found_values, 8);
13309
13310 if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13311 op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13312 0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13313 return 0;
13314 }
13315
13316 if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13317 var_info |= MAY_BE_REF;
13318 }
13320 var_info |= MAY_BE_RC1;
13321 }
13322
13323 if (found_inputs->count) {
13324 ir_MERGE_N(found_inputs->count, found_inputs->refs);
13325 ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13326 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13327
13328 // JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13329 if (opline->op1_type == IS_VAR
13330 && Z_MODE(op3_addr) != IS_REG
13331 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13332 ZEND_ASSERT(opline->result_type == IS_UNUSED);
13333 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)) {
13334 return 0;
13335 }
13336 } else {
13337 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)) {
13338 return 0;
13339 }
13340 }
13341 }
13342 }
13343
13344 ir_END_list(end_inputs);
13345 }
13346
13347 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13348 ir_ref arg2, arg4;
13349
13350 if (if_type) {
13351 ir_IF_FALSE_cold(if_type);
13352 if_type = IR_UNUSED;
13353 }
13354
13355 jit_SET_EX_OPLINE(jit, opline);
13356
13357 if (opline->op2_type == IS_UNUSED) {
13358 arg2 = IR_NULL;
13359 } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13360 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13361 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13362 } else {
13363 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13364 }
13365
13366 if (opline->result_type == IS_UNUSED) {
13367 arg4 = IR_NULL;
13368 } else {
13369 arg4 = jit_ZVAL_ADDR(jit, res_addr);
13370 }
13371 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13372 jit_ZVAL_ADDR(jit, op1_addr),
13373 arg2,
13374 jit_ZVAL_ADDR(jit, op3_addr),
13375 arg4);
13376
13377#ifdef ZEND_JIT_USE_RC_INFERENCE
13378 if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13379 /* ASSIGN_DIM may increase refcount of the value */
13380 val_info |= MAY_BE_RCN;
13381 }
13382#endif
13383
13384 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13385
13386 ir_END_list(end_inputs);
13387 }
13388
13389#ifdef ZEND_JIT_USE_RC_INFERENCE
13391 /* ASSIGN_DIM may increase refcount of the key */
13392 op2_info |= MAY_BE_RCN;
13393 }
13394#endif
13395
13396 ir_MERGE_list(end_inputs);
13397 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13398
13399 if (may_throw) {
13400 zend_jit_check_exception(jit);
13401 }
13402
13403 return 1;
13404}
13405
13406static int zend_jit_assign_dim_op(zend_jit_ctx *jit,
13407 const zend_op *opline,
13408 uint32_t op1_info,
13409 uint32_t op1_def_info,
13410 zend_jit_addr op1_addr,
13411 uint32_t op2_info,
13412 zend_jit_addr op2_addr,
13413 zend_ssa_range *op2_range,
13414 uint32_t op1_data_info,
13415 zend_jit_addr op3_addr,
13416 zend_ssa_range *op1_data_range,
13417 uint8_t dim_type,
13418 int may_throw)
13419{
13420 zend_jit_addr var_addr = IS_UNUSED;
13421 const void *not_found_exit_addr = NULL;
13422 uint32_t var_info = MAY_BE_NULL;
13423 ir_ref if_type = IS_UNUSED;
13424 ir_ref end_inputs = IR_UNUSED, ht_ref;
13425 bool emit_fast_path = 1;
13426
13427 ZEND_ASSERT(opline->result_type == IS_UNUSED);
13428
13429 if (may_throw) {
13430 jit_SET_EX_OPLINE(jit, opline);
13431 }
13432
13433 op1_addr = zend_jit_prepare_array_update(jit, opline, op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13434
13435 if (Z_MODE(op3_addr) == IS_REG
13436 && Z_LOAD(op3_addr)
13437 && jit->ra[Z_SSA_VAR(op3_addr)].ref == IR_NULL) {
13438 /* Force load */
13439 zend_jit_use_reg(jit, op3_addr);
13440 }
13441
13442
13443 if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13444 uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13445
13446 if (opline->op2_type == IS_UNUSED) {
13447 var_info = MAY_BE_NULL;
13448 ir_ref if_ok, ref;
13449
13450 // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13452 ht_ref, jit_EG(uninitialized_zval));
13453
13454 // JIT: if (UNEXPECTED(!var_ptr)) {
13455 if_ok = ir_IF(ref);
13456 ir_IF_FALSE_cold(if_ok);
13457
13458 // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13459 ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13460
13461 ir_END_list(end_inputs);
13462
13463 ir_IF_TRUE(if_ok);
13464 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13465 } else {
13466 ir_ref ref;
13467 ir_refs *found_inputs, *found_values;
13468
13469 ir_refs_init(found_inputs, 8);
13470 ir_refs_init(found_values, 8);
13471
13472 var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13473 if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13474 var_info |= MAY_BE_REF;
13475 }
13477 var_info |= MAY_BE_RC1;
13478 }
13479
13480 if (dim_type != IS_UNKNOWN
13481 && dim_type != IS_UNDEF
13482 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13483 && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13484 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13485 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13486 not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13487 if (!not_found_exit_addr) {
13488 return 0;
13489 }
13490 }
13491
13492 if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13493 op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13494 0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13495 return 0;
13496 }
13497
13498 if (found_inputs->count) {
13499 ir_MERGE_N(found_inputs->count, found_inputs->refs);
13500 ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13501 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13502
13503 if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13504 jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13505 var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13506 }
13507 if (var_info & MAY_BE_REF) {
13508 binary_op_type binary_op = get_binary_op(opline->extended_value);
13509 ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13510
13511 ref = jit_ZVAL_ADDR(jit, var_addr);
13512 if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13513 ir_IF_FALSE(if_ref);
13514 noref_path = ir_END();
13515 ir_IF_TRUE(if_ref);
13516
13517 reference = jit_Z_PTR_ref(jit, ref);
13518 ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13519 if_typed = jit_if_TYPED_REF(jit, reference);
13520 ir_IF_FALSE(if_typed);
13521 ref_path = ir_END();
13522 ir_IF_TRUE_cold(if_typed);
13523
13524 if (Z_MODE(op3_addr) == IS_REG) {
13525 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
13526 if (!zend_jit_spill_store_inv(jit, op3_addr, real_addr, op1_data_info)) {
13527 return 0;
13528 }
13529 op3_addr = real_addr;
13530 }
13531 arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13532 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13533 reference, arg2, ir_CONST_FC_FUNC(binary_op));
13534
13535 ir_END_list(end_inputs);
13536
13537 ir_MERGE_2(noref_path, ref_path);
13538 ref = ir_PHI_2(IR_ADDR, ref, ref2);
13539 var_addr = ZEND_ADDR_REF_ZVAL(ref);
13540 }
13541 } else {
13542 emit_fast_path = 0;
13543 }
13544 }
13545
13546 if (emit_fast_path) {
13547 uint8_t val_op_type = (opline+1)->op1_type;
13548
13549 if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13550 /* prevent FREE_OP in the helpers */
13551 val_op_type = IS_CV;
13552 }
13553
13554 switch (opline->extended_value) {
13555 case ZEND_ADD:
13556 case ZEND_SUB:
13557 case ZEND_MUL:
13558 case ZEND_DIV:
13559 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,
13560 1 /* may overflow */, may_throw)) {
13561 return 0;
13562 }
13563 break;
13564 case ZEND_BW_OR:
13565 case ZEND_BW_AND:
13566 case ZEND_BW_XOR:
13567 case ZEND_SL:
13568 case ZEND_SR:
13569 case ZEND_MOD:
13570 if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13571 IS_CV, opline->op1, var_addr, var_info, NULL,
13572 val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13573 op1_data_range,
13574 0, var_addr, var_def_info, var_info, may_throw)) {
13575 return 0;
13576 }
13577 break;
13578 case ZEND_CONCAT:
13579 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,
13580 may_throw)) {
13581 return 0;
13582 }
13583 break;
13584 default:
13586 }
13587
13588 ir_END_list(end_inputs);
13589 }
13590 }
13591
13592 if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13593 binary_op_type binary_op;
13594 ir_ref arg2;
13595
13596 if (if_type) {
13597 ir_IF_FALSE_cold(if_type);
13598 if_type = IS_UNUSED;
13599 }
13600
13601 if (opline->op2_type == IS_UNUSED) {
13602 arg2 = IR_NULL;
13603 } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13604 ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13605 arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13606 } else {
13607 arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13608 }
13609 binary_op = get_binary_op(opline->extended_value);
13610 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13611 jit_ZVAL_ADDR(jit, op1_addr),
13612 arg2,
13613 jit_ZVAL_ADDR(jit, op3_addr),
13614 ir_CONST_FC_FUNC(binary_op));
13615 ir_END_list(end_inputs);
13616 }
13617
13618 if (end_inputs) {
13619 ir_MERGE_list(end_inputs);
13620 }
13621
13622 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13623 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13624 if (may_throw) {
13625 zend_jit_check_exception(jit);
13626 }
13627
13628 return 1;
13629}
13630
13631static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13632{
13633 zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13634
13635 // JIT: ZVAL_COPY(res, value);
13636 if (opline->op1_type == IS_CONST) {
13637 zval *zv = RT_CONSTANT(opline, opline->op1);
13638
13639 jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, 1);
13640 } else {
13641 zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13642
13643 jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13644 }
13645
13646 // JIT: Z_FE_POS_P(res) = 0;
13647 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13648
13649 return 1;
13650}
13651
13652static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13653{
13654 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13655 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13656 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13657 ir_ref ref;
13658
13659 if (!exit_addr) {
13660 return 0;
13661 }
13662
13663 ref = ir_AND_U32(
13664 ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
13666 if (op_info & MAY_BE_ARRAY_PACKED) {
13667 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13668 } else {
13669 ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
13670 }
13671
13672 return 1;
13673}
13674
13675static 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)
13676{
13677 zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13678 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;
13679 ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
13680 ir_ref exit_inputs = IR_UNUSED;
13681
13682 if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
13683 /* empty array */
13684 if (exit_addr) {
13685 if (exit_opcode == ZEND_JMP) {
13686 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13687 }
13688 } else {
13689 zend_basic_block *bb;
13690
13691 ZEND_ASSERT(jit->b >= 0);
13692 bb = &jit->ssa->cfg.blocks[jit->b];
13693 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
13694 jit->b = -1;
13695 }
13696 return 1;
13697 }
13698
13699 // JIT: array = EX_VAR(opline->op1.var);
13700 // JIT: fe_ht = Z_ARRVAL_P(array);
13701 ht_ref = jit_Z_PTR(jit, op1_addr);
13702
13703 if (op1_info & MAY_BE_PACKED_GUARD) {
13704 if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
13705 return 0;
13706 }
13707 }
13708
13709 // JIT: pos = Z_FE_POS_P(array);
13710 hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
13711
13712 if (MAY_BE_HASH(op1_info)) {
13713 ir_ref loop_ref, pos2_ref, p2_ref;
13714
13715 if (MAY_BE_PACKED(op1_info)) {
13716 ref = ir_AND_U32(
13717 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
13719 if_packed = ir_IF(ref);
13720 ir_IF_FALSE(if_packed);
13721 }
13722
13723 // JIT: p = fe_ht->arData + pos;
13724 if (sizeof(void*) == 8) {
13725 ref = ir_ZEXT_A(hash_pos_ref);
13726 } else {
13727 ref = ir_BITCAST_A(hash_pos_ref);
13728 }
13729 hash_p_ref = ir_ADD_A(
13730 ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
13731 ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
13732
13733 loop_ref = ir_LOOP_BEGIN(ir_END());
13734 hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
13735 hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
13736
13737 // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13738 ref = ir_ULT(hash_pos_ref,
13739 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13740
13741 // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13742 // JIT: ZEND_VM_CONTINUE();
13743
13744 if (exit_addr) {
13745 if (exit_opcode == ZEND_JMP) {
13746 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13747 } else {
13748 ir_ref if_fit = ir_IF(ref);
13749 ir_IF_FALSE(if_fit);
13750 ir_END_list(exit_inputs);
13751 ir_IF_TRUE(if_fit);
13752 }
13753 } else {
13754 ir_ref if_fit = ir_IF(ref);
13755 ir_IF_FALSE(if_fit);
13756 ir_END_list(exit_inputs);
13757 ir_IF_TRUE(if_fit);
13758 }
13759
13760 // JIT: pos++;
13761 pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
13762
13763 // JIT: value_type = Z_TYPE_INFO_P(value);
13764 // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13765 if (!exit_addr || exit_opcode == ZEND_JMP) {
13766 if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
13767 ir_IF_FALSE(if_def_hash);
13768 } else {
13769 ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
13770 }
13771
13772 // JIT: p++;
13773 p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
13774
13775 ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13776 ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
13777 ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
13778
13779 if (MAY_BE_PACKED(op1_info)) {
13780 ir_IF_TRUE(if_packed);
13781 }
13782 }
13783 if (MAY_BE_PACKED(op1_info)) {
13784 ir_ref loop_ref, pos2_ref, p2_ref;
13785
13786 // JIT: p = fe_ht->arPacked + pos;
13787 if (sizeof(void*) == 8) {
13788 ref = ir_ZEXT_A(packed_pos_ref);
13789 } else {
13790 ref = ir_BITCAST_A(packed_pos_ref);
13791 }
13792 packed_p_ref = ir_ADD_A(
13793 ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
13794 ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
13795
13796 loop_ref = ir_LOOP_BEGIN(ir_END());
13797 packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
13798 packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
13799
13800 // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13801 ref = ir_ULT(packed_pos_ref,
13802 ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13803
13804 // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13805 // JIT: ZEND_VM_CONTINUE();
13806 if (exit_addr) {
13807 if (exit_opcode == ZEND_JMP) {
13808 ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13809 } else {
13810 ir_ref if_fit = ir_IF(ref);
13811 ir_IF_FALSE(if_fit);
13812 ir_END_list(exit_inputs);
13813 ir_IF_TRUE(if_fit);
13814 }
13815 } else {
13816 ir_ref if_fit = ir_IF(ref);
13817 ir_IF_FALSE(if_fit);
13818 ir_END_list(exit_inputs);
13819 ir_IF_TRUE(if_fit);
13820 }
13821
13822 // JIT: pos++;
13823 pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
13824
13825 // JIT: value_type = Z_TYPE_INFO_P(value);
13826 // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13827 if (!exit_addr || exit_opcode == ZEND_JMP) {
13828 if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
13829 ir_IF_FALSE(if_def_packed);
13830 } else {
13831 ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
13832 }
13833
13834 // JIT: p++;
13835 p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
13836
13837 ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13838 ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
13839 ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
13840 }
13841
13842 if (!exit_addr || exit_opcode == ZEND_JMP) {
13843 zend_jit_addr val_addr;
13844 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
13845 uint32_t val_info;
13846 ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
13847
13848 if (RETURN_VALUE_USED(opline)) {
13849 zend_jit_addr res_addr = RES_ADDR();
13850
13851 if (MAY_BE_HASH(op1_info)) {
13852 ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
13853
13854 ZEND_ASSERT(if_def_hash);
13855 ir_IF_TRUE(if_def_hash);
13856
13857 // JIT: Z_FE_POS_P(array) = pos + 1;
13858 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13859 ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
13860
13861 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13862 key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
13863 }
13864 if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
13865 && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
13866 // JIT: if (!p->key) {
13867 if_key = ir_IF(key_ref);
13868 ir_IF_TRUE(if_key);
13869 }
13870 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13871 ir_ref if_interned, interned_path;
13872
13873 // JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
13874 jit_set_Z_PTR(jit, res_addr, key_ref);
13875 ref = ir_AND_U32(
13876 ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
13878 if_interned = ir_IF(ref);
13879 ir_IF_TRUE(if_interned);
13880
13881 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
13882
13883 interned_path = ir_END();
13884 ir_IF_FALSE(if_interned);
13885
13886 jit_GC_ADDREF(jit, key_ref);
13887 jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
13888
13889 ir_MERGE_WITH(interned_path);
13890
13891 if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13892 key_path = ir_END();
13893 }
13894 }
13895 if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
13896 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13897 ir_IF_FALSE(if_key);
13898 }
13899 // JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
13900 ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
13901 jit_set_Z_LVAL(jit, res_addr, ref);
13902 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13903
13904 if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
13905 ir_MERGE_WITH(key_path);
13906 }
13907 }
13908 if (MAY_BE_PACKED(op1_info)) {
13909 hash_path = ir_END();
13910 } else {
13911 p_ref = hash_p_ref;
13912 }
13913 }
13914 if (MAY_BE_PACKED(op1_info)) {
13915 ZEND_ASSERT(if_def_packed);
13916 ir_IF_TRUE(if_def_packed);
13917
13918 // JIT: Z_FE_POS_P(array) = pos + 1;
13919 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13920 ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
13921
13922 // JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
13923 if (sizeof(zend_long) == 8) {
13924 packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
13925 } else {
13926 packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
13927 }
13928 jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
13929 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
13930
13931 if (MAY_BE_HASH(op1_info)) {
13932 ir_MERGE_WITH(hash_path);
13933 p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
13934 } else {
13935 p_ref = packed_p_ref;
13936 }
13937 }
13938 } else {
13939 ir_ref pos_ref = IR_UNUSED;
13940
13941 if (if_def_hash && if_def_packed) {
13942 ir_IF_TRUE(if_def_hash);
13943 ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
13944 pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
13945 p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
13946 } else if (if_def_hash) {
13947 ir_IF_TRUE(if_def_hash);
13948 pos_ref = hash_pos_ref;
13949 p_ref = hash_p_ref;
13950 } else if (if_def_packed) {
13951 ir_IF_TRUE(if_def_packed);
13952 pos_ref = packed_pos_ref;
13953 p_ref = packed_p_ref;
13954 } else {
13956 }
13957
13958 // JIT: Z_FE_POS_P(array) = pos + 1;
13959 ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
13960 ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
13961 }
13962
13963 val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
13964 if (val_info & MAY_BE_ARRAY) {
13966 }
13967 if (op1_info & MAY_BE_ARRAY_OF_REF) {
13968 val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
13970 } else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13971 val_info |= MAY_BE_RC1 | MAY_BE_RCN;
13972 }
13973
13974 val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
13975 if (opline->op2_type == IS_CV) {
13976 // JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
13977 if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, 1)) {
13978 return 0;
13979 }
13980 } else {
13981 // JIT: ZVAL_COPY(res, value);
13982 jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, 1);
13983 }
13984
13985 if (!exit_addr) {
13986 zend_basic_block *bb;
13987
13988 ZEND_ASSERT(jit->b >= 0);
13989 bb = &jit->ssa->cfg.blocks[jit->b];
13990 _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
13991 ZEND_ASSERT(exit_inputs);
13992 if (!jit->ctx.ir_base[exit_inputs].op2) {
13993 ref = exit_inputs;
13994 } else {
13995 ir_MERGE_list(exit_inputs);
13996 ref = ir_END();
13997 }
13998 _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
13999 jit->b = -1;
14000 }
14001 } else {
14002 ZEND_ASSERT(exit_inputs);
14003 ir_MERGE_list(exit_inputs);
14004 }
14005
14006 return 1;
14007}
14008
14009static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
14010{
14011 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14012 zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
14013 ir_ref ref = jit_Z_PTR(jit, this_addr);
14014
14015 jit_set_Z_PTR(jit, var_addr, ref);
14016 jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
14017 jit_GC_ADDREF(jit, ref);
14018
14019 return 1;
14020}
14021
14022static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
14023{
14024 if (!op_array->scope ||
14025 (op_array->fn_flags & ZEND_ACC_STATIC) ||
14027 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14028 if (!JIT_G(current_frame) ||
14029 !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
14030
14031 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14032 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14033 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14034
14035 if (!exit_addr) {
14036 return 0;
14037 }
14038
14039 jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
14040
14041 if (JIT_G(current_frame)) {
14042 TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
14043 }
14044 }
14045 } else {
14046 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14047 ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
14048
14049 ir_IF_FALSE_cold(if_object);
14050 jit_SET_EX_OPLINE(jit, opline);
14051 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
14052
14053 ir_IF_TRUE(if_object);
14054 }
14055 }
14056
14057 if (!check_only) {
14058 if (!zend_jit_load_this(jit, opline->result.var)) {
14059 return 0;
14060 }
14061 }
14062
14063 return 1;
14064}
14065
14066static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
14067{
14068 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14069 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14070
14071 if (!exit_addr) {
14072 return 0;
14073 }
14074
14076 ir_CONST_ADDR(exit_addr));
14077
14078 return 1;
14079}
14080
14081static int zend_jit_fetch_obj(zend_jit_ctx *jit,
14082 const zend_op *opline,
14083 const zend_op_array *op_array,
14084 zend_ssa *ssa,
14085 const zend_ssa_op *ssa_op,
14086 uint32_t op1_info,
14087 zend_jit_addr op1_addr,
14088 bool op1_indirect,
14089 zend_class_entry *ce,
14090 bool ce_is_instanceof,
14091 bool on_this,
14092 bool delayed_fetch_this,
14093 bool op1_avoid_refcounting,
14094 zend_class_entry *trace_ce,
14095 zend_jit_addr res_addr,
14096 uint8_t prop_type,
14097 int may_throw)
14098{
14099 zval *member;
14101 bool may_be_dynamic = 1;
14102 zend_jit_addr prop_addr;
14103 uint32_t res_info = RES_INFO();
14104 ir_ref prop_type_ref = IR_UNUSED;
14105 ir_ref obj_ref = IR_UNUSED;
14106 ir_ref prop_ref = IR_UNUSED;
14107 ir_ref end_inputs = IR_UNUSED;
14108 ir_ref slow_inputs = IR_UNUSED;
14109 ir_ref end_values = IR_UNUSED;
14110
14111 ZEND_ASSERT(opline->op2_type == IS_CONST);
14112 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14113
14114 member = RT_CONSTANT(opline, opline->op2);
14115 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14116 prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
14117
14118 if (on_this) {
14119 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14120 obj_ref = jit_Z_PTR(jit, this_addr);
14121 } else {
14122 if (opline->op1_type == IS_VAR
14123 && opline->opcode == ZEND_FETCH_OBJ_W
14124 && (op1_info & MAY_BE_INDIRECT)
14125 && Z_REG(op1_addr) == ZREG_FP) {
14126 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14127 }
14128 if (op1_info & MAY_BE_REF) {
14129 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14130 }
14131 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14132 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14133 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14134 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14135
14136 if (!exit_addr) {
14137 return 0;
14138 }
14139 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14140 } else {
14141 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14142
14143 ir_IF_FALSE_cold(if_obj);
14144 if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14145 ir_ref op1_ref = IR_UNUSED;
14146
14147 jit_SET_EX_OPLINE(jit, opline);
14148 if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
14149 zend_jit_addr orig_op1_addr = OP1_ADDR();
14150 ir_ref fast_path = IR_UNUSED;
14151
14152 if (op1_info & MAY_BE_ANY) {
14153 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
14154 ir_IF_TRUE(if_def);
14155 fast_path = ir_END();
14156 ir_IF_FALSE_cold(if_def);
14157 }
14158 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
14159 ir_CONST_U32(opline->op1.var));
14160 if (fast_path) {
14161 ir_MERGE_WITH(fast_path);
14162 }
14163 op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
14164 } else {
14165 op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
14166 }
14167 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14168 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
14169 op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14170 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14171 } else {
14172 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
14173 op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14174 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14175 }
14176 } else {
14177 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14178 }
14179 ir_END_list(end_inputs);
14180
14181 ir_IF_TRUE(if_obj);
14182 }
14183 }
14184 obj_ref = jit_Z_PTR(jit, op1_addr);
14185 }
14186
14187 ZEND_ASSERT(obj_ref);
14188 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14189 prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
14190 if (prop_info) {
14191 ce = trace_ce;
14192 ce_is_instanceof = 0;
14193 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14194 if (on_this && JIT_G(current_frame)
14195 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14196 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14197 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14198 if (on_this && JIT_G(current_frame)) {
14199 JIT_G(current_frame)->ce = ce;
14201 }
14202 } else {
14203 return 0;
14204 }
14205 if (ssa->var_info && ssa_op->op1_use >= 0) {
14206 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14207 ssa->var_info[ssa_op->op1_use].ce = ce;
14208 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14209 }
14210 }
14211 }
14212 }
14213
14214 if (!prop_info) {
14215 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14216 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14217 ir_ref if_same = ir_IF(ir_EQ(ref,
14218 ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14219
14220 ir_IF_FALSE_cold(if_same);
14221 ir_END_list(slow_inputs);
14222
14223 ir_IF_TRUE(if_same);
14224 ir_ref offset_ref = ir_LOAD_A(
14225 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14226
14227 may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array);
14228 if (may_be_dynamic) {
14229 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14230 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14231 ir_IF_TRUE_cold(if_dynamic);
14232 ir_END_list(slow_inputs);
14233 } else {
14234 ir_IF_TRUE_cold(if_dynamic);
14235 jit_SET_EX_OPLINE(jit, opline);
14236
14237 if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14238 if (Z_MODE(res_addr) == IS_REG) {
14239 ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
14240 obj_ref, offset_ref);
14241 ir_END_PHI_list(end_values, val_addr);
14242 } else {
14243 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
14244 obj_ref, offset_ref);
14245 ir_END_list(end_inputs);
14246 }
14247 } else {
14248 if (Z_MODE(res_addr) == IS_REG) {
14249 ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
14250 obj_ref, offset_ref);
14251 ir_END_PHI_list(end_values, val_addr);
14252 } else {
14253 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
14254 obj_ref, offset_ref);
14255 ir_END_list(end_inputs);
14256 }
14257 }
14258 }
14259 ir_IF_FALSE(if_dynamic);
14260 }
14261 prop_ref = ir_ADD_A(obj_ref, offset_ref);
14262 prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
14263 ir_ref if_def = ir_IF(prop_type_ref);
14264 ir_IF_FALSE_cold(if_def);
14265 ir_END_list(slow_inputs);
14266 ir_IF_TRUE(if_def);
14267 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14268 if (opline->opcode == ZEND_FETCH_OBJ_W
14269 && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
14270 uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14271
14272 ir_ref allowed_inputs = IR_UNUSED;
14273 ir_ref forbidden_inputs = IR_UNUSED;
14274
14275 ir_ref prop_info_ref = ir_LOAD_A(
14276 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14277 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14278
14279 ir_IF_TRUE_cold(if_has_prop_info);
14280
14281 ir_ref prop_flags = ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags)));
14282 ir_ref if_readonly_or_avis = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK)));
14283
14284 ir_IF_FALSE(if_readonly_or_avis);
14285 ir_END_list(allowed_inputs);
14286
14287 ir_IF_TRUE_cold(if_readonly_or_avis);
14288
14289 ir_ref if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14290 ir_IF_TRUE(if_readonly);
14291 ir_END_list(forbidden_inputs);
14292
14293 ir_IF_FALSE(if_readonly);
14294 ir_ref has_avis_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), prop_info_ref);
14295 ir_ref if_avis_access = ir_IF(has_avis_access);
14296 ir_IF_TRUE(if_avis_access);
14297 ir_END_list(allowed_inputs);
14298
14299 ir_IF_FALSE(if_avis_access);
14300 ir_END_list(forbidden_inputs);
14301
14302 ir_MERGE_list(forbidden_inputs);
14303
14304 ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14305 ir_IF_TRUE(if_prop_obj);
14306 ref = jit_Z_PTR(jit, prop_addr);
14307 jit_GC_ADDREF(jit, ref);
14308 jit_set_Z_PTR(jit, res_addr, ref);
14309 jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14310 ir_END_list(end_inputs);
14311
14312 ir_IF_FALSE_cold(if_prop_obj);
14313
14314 jit_SET_EX_OPLINE(jit, opline);
14315 if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14316 ir_IF_TRUE(if_readonly);
14318 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14319 ir_END_list(end_inputs);
14320
14321 ir_IF_FALSE(if_readonly);
14323 prop_info_ref, ir_CONST_ADDR("indirectly modify"));
14324 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14325 ir_END_list(end_inputs);
14326
14327 ir_MERGE_list(allowed_inputs);
14328
14329 if (flags == ZEND_FETCH_DIM_WRITE) {
14330 jit_SET_EX_OPLINE(jit, opline);
14331 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14332 prop_ref, prop_info_ref);
14333 ir_END_list(end_inputs);
14334 ir_IF_FALSE(if_has_prop_info);
14335 } else if (flags == ZEND_FETCH_REF) {
14336 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14337 prop_ref,
14338 prop_info_ref,
14339 jit_ZVAL_ADDR(jit, res_addr));
14340 ir_END_list(end_inputs);
14341 ir_IF_FALSE(if_has_prop_info);
14342 } else {
14343 ZEND_ASSERT(flags == 0);
14344 ir_MERGE_WITH_EMPTY_FALSE(if_has_prop_info);
14345 }
14346 }
14347 } else {
14348 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14349 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14350 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14351 if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14352 /* perform IS_UNDEF check only after result type guard (during deoptimization) */
14353 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14354 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14355
14356 if (!exit_addr) {
14357 return 0;
14358 }
14359 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14360 ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14361 }
14362 } else {
14363 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14364 ir_ref if_def = ir_IF(prop_type_ref);
14365 ir_IF_FALSE_cold(if_def);
14366 ir_END_list(slow_inputs);
14367 ir_IF_TRUE(if_def);
14368 }
14369 if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14370 ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14371 ir_IF_TRUE(if_prop_obj);
14372 ir_ref ref = jit_Z_PTR(jit, prop_addr);
14373 jit_GC_ADDREF(jit, ref);
14374 jit_set_Z_PTR(jit, res_addr, ref);
14375 jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14376 ir_END_list(end_inputs);
14377
14378 ir_IF_FALSE_cold(if_prop_obj);
14379 jit_SET_EX_OPLINE(jit, opline);
14381 jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14382 ir_END_list(end_inputs);
14383
14384 goto result_fetched;
14385 } else if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)) {
14386 /* Readonly properties which are also asymmetric are never mutable indirectly, which is
14387 * handled by the previous branch. */
14389
14390 ir_ref if_access = ir_IF(has_access);
14391 ir_IF_FALSE_cold(if_access);
14392
14393 ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14394 ir_IF_TRUE(if_prop_obj);
14395 ir_ref ref = jit_Z_PTR(jit, prop_addr);
14396 jit_GC_ADDREF(jit, ref);
14397 jit_set_Z_PTR(jit, res_addr, ref);
14398 jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14399 ir_END_list(end_inputs);
14400
14401 ir_IF_FALSE_cold(if_prop_obj);
14403 ir_CONST_ADDR(prop_info), ir_CONST_ADDR("indirectly modify"));
14404 ir_END_list(end_inputs);
14405
14406 ir_IF_TRUE(if_access);
14407 }
14408
14409 if (opline->opcode == ZEND_FETCH_OBJ_W
14411 && ZEND_TYPE_IS_SET(prop_info->type)) {
14412 uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14413
14414 if (flags == ZEND_FETCH_DIM_WRITE) {
14415 if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14416 if (!prop_type_ref) {
14417 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14418 }
14419 ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14420 ir_IF_TRUE_cold(if_null_or_flase);
14421 jit_SET_EX_OPLINE(jit, opline);
14422 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14423 prop_ref, ir_CONST_ADDR(prop_info));
14424 ir_END_list(end_inputs);
14425 ir_IF_FALSE(if_null_or_flase);
14426 }
14427 } else if (flags == ZEND_FETCH_REF) {
14428 ir_ref ref;
14429
14430 if (!prop_type_ref) {
14431 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14432 }
14433
14434 ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14435 ir_IF_FALSE(if_reference);
14436 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14437 ref = ir_CONST_ADDR(prop_info);
14438 } else {
14439 int prop_info_offset =
14440 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14441
14442 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14443 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14444 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14445 }
14446 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14447 prop_ref,
14448 ref,
14449 jit_ZVAL_ADDR(jit, res_addr));
14450 ir_END_list(end_inputs);
14451 ir_IF_TRUE(if_reference);
14452 } else {
14454 }
14455 }
14456 }
14457
14458 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14459 ZEND_ASSERT(prop_ref);
14460 jit_set_Z_PTR(jit, res_addr, prop_ref);
14461 jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14462 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14463 ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14464 }
14465 ir_END_list(end_inputs);
14466 } else {
14467 if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
14468 ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14469 } else if ((res_info & MAY_BE_GUARD) && Z_MODE(res_addr) == IS_REG) {
14470 ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14471 } else if (Z_MODE(res_addr) == IS_REG) {
14472 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14473
14474 if (!zend_jit_zval_copy_deref_reg(jit, res_addr, res_info & ~MAY_BE_GUARD, prop_addr, prop_type_ref, &end_values)) {
14475 return 0;
14476 }
14477 } else {
14478 prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14479
14480 if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14481 return 0;
14482 }
14483 ir_END_list(end_inputs);
14484 }
14485 }
14486
14487result_fetched:
14488 if (op1_avoid_refcounting) {
14489 SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14490 }
14491
14492 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14493 ir_MERGE_list(slow_inputs);
14494 jit_SET_EX_OPLINE(jit, opline);
14495
14496 op1_info |= MAY_BE_RC1 | MAY_BE_RCN; /* object may be captured/released in magic handler */
14497 if (opline->opcode == ZEND_FETCH_OBJ_W) {
14498 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14499 ir_END_list(end_inputs);
14500 } else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14501 if (Z_MODE(res_addr) == IS_REG) {
14502 ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14503 ir_END_PHI_list(end_values, val_ref);
14504 } else {
14505 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14506 ir_END_list(end_inputs);
14507 }
14508 } else {
14509 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14510 ir_END_list(end_inputs);
14511 }
14512 }
14513
14514 if (end_values) {
14515 ir_ref val_ref = ir_PHI_list(end_values);
14516 zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14517 bool result_avoid_refcounting = 0;
14518
14520 || opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14521 || opline->opcode == ZEND_FETCH_OBJ_IS);
14522 ZEND_ASSERT(end_inputs == IR_UNUSED);
14523 if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14524 uint8_t type = concrete_type(res_info);
14526
14527 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14528 && !delayed_fetch_this
14529 && !op1_avoid_refcounting) {
14531 }
14532
14533 if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14536 && (ssa_op+1)->op1_use == ssa_op->result_def
14537 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14538 result_avoid_refcounting = 1;
14539 ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14540 }
14541
14542 val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14543 1, flags, op1_avoid_refcounting);
14544 if (!val_addr) {
14545 return 0;
14546 }
14547
14548 res_info &= ~MAY_BE_GUARD;
14549 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14550 }
14551
14552 // ZVAL_COPY
14553 jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14554
14555 if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14556 return 0;
14557 }
14558 } else {
14559 ir_MERGE_list(end_inputs);
14560 }
14561
14562 if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14563 if (opline->op1_type == IS_VAR
14564 && opline->opcode == ZEND_FETCH_OBJ_W
14565 && (op1_info & MAY_BE_RC1)) {
14566 zend_jit_addr orig_op1_addr = OP1_ADDR();
14567 ir_ref if_refcounted, ptr, refcount, if_non_zero;
14568 ir_ref merge_inputs = IR_UNUSED;
14569
14570 if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14571 ir_IF_FALSE( if_refcounted);
14572 ir_END_list(merge_inputs);
14573 ir_IF_TRUE( if_refcounted);
14574 ptr = jit_Z_PTR(jit, orig_op1_addr);
14575 refcount = jit_GC_DELREF(jit, ptr);
14576 if_non_zero = ir_IF(refcount);
14577 ir_IF_TRUE( if_non_zero);
14578 ir_END_list(merge_inputs);
14579 ir_IF_FALSE( if_non_zero);
14580 jit_SET_EX_OPLINE(jit, opline);
14581 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14582 ir_END_list(merge_inputs);
14583 ir_MERGE_list(merge_inputs);
14584 } else if (!op1_avoid_refcounting) {
14585 if (on_this) {
14586 op1_info &= ~MAY_BE_RC1;
14587 }
14588 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14589 }
14590 }
14591
14592 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14593 && prop_info
14594 && (opline->opcode != ZEND_FETCH_OBJ_W ||
14595 !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14597 && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14598 may_throw = 0;
14599 }
14600
14601 if (may_throw) {
14602 if (Z_MODE(res_addr) == IS_REG) {
14603 zend_jit_check_exception_undef_result(jit, opline);
14604 } else {
14605 zend_jit_check_exception(jit);
14606 }
14607 }
14608
14609 return 1;
14610}
14611
14612static int zend_jit_assign_obj(zend_jit_ctx *jit,
14613 const zend_op *opline,
14614 const zend_op_array *op_array,
14615 zend_ssa *ssa,
14616 const zend_ssa_op *ssa_op,
14617 uint32_t op1_info,
14618 zend_jit_addr op1_addr,
14619 uint32_t val_info,
14620 zend_jit_addr val_addr,
14621 zend_jit_addr val_def_addr,
14622 zend_jit_addr res_addr,
14623 bool op1_indirect,
14624 zend_class_entry *ce,
14625 bool ce_is_instanceof,
14626 bool on_this,
14627 bool delayed_fetch_this,
14628 zend_class_entry *trace_ce,
14629 uint8_t prop_type,
14630 int may_throw)
14631{
14632 zval *member;
14635 zend_jit_addr prop_addr;
14636 ir_ref obj_ref = IR_UNUSED;
14637 ir_ref prop_ref = IR_UNUSED;
14638 ir_ref delayed_end_input = IR_UNUSED;
14639 ir_ref end_inputs = IR_UNUSED;
14640 ir_ref slow_inputs = IR_UNUSED;
14641 uint32_t res_info = RES_INFO();
14642
14643 if (val_addr != val_def_addr && val_def_addr) {
14644 if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14645 return 0;
14646 }
14647 if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14648 val_addr = val_def_addr;
14649 }
14650 }
14651
14652 ZEND_ASSERT(opline->op2_type == IS_CONST);
14653 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14654
14655 member = RT_CONSTANT(opline, opline->op2);
14656 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14657 name = Z_STR_P(member);
14658 prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14659
14660 if (on_this) {
14661 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14662 obj_ref = jit_Z_PTR(jit, this_addr);
14663 } else {
14664 if (opline->op1_type == IS_VAR
14665 && (op1_info & MAY_BE_INDIRECT)
14666 && Z_REG(op1_addr) == ZREG_FP) {
14667 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14668 }
14669 if (op1_info & MAY_BE_REF) {
14670 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14671 }
14672 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14673 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14674 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14675 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14676
14677 if (!exit_addr) {
14678 return 0;
14679 }
14680 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14681 } else {
14682 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14683 ir_IF_FALSE_cold(if_obj);
14684
14685 jit_SET_EX_OPLINE(jit, opline);
14686 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14687 jit_ZVAL_ADDR(jit, op1_addr),
14689
14690 if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
14691 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14692 }
14693
14694 ir_END_list(end_inputs);
14695
14696 ir_IF_TRUE(if_obj);
14697 }
14698 }
14699 obj_ref = jit_Z_PTR(jit, op1_addr);
14700 }
14701
14702 ZEND_ASSERT(obj_ref);
14703 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14704 prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14705 if (prop_info) {
14706 ce = trace_ce;
14707 ce_is_instanceof = 0;
14708 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14709 if (on_this && JIT_G(current_frame)
14710 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14711 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14712 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14713 if (on_this && JIT_G(current_frame)) {
14714 JIT_G(current_frame)->ce = ce;
14716 }
14717 } else {
14718 return 0;
14719 }
14720 if (ssa->var_info && ssa_op->op1_use >= 0) {
14721 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14722 ssa->var_info[ssa_op->op1_use].ce = ce;
14723 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14724 }
14725 if (ssa->var_info && ssa_op->op1_def >= 0) {
14726 ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14727 ssa->var_info[ssa_op->op1_def].ce = ce;
14728 ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14729 }
14730 }
14731 }
14732 }
14733
14734 if (!prop_info) {
14735 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14736 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14737 ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14738
14739 ir_IF_FALSE_cold(if_same);
14740 ir_END_list(slow_inputs);
14741
14742 ir_IF_TRUE(if_same);
14743 ir_ref offset_ref = ir_LOAD_A(
14744 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14745
14746 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14747 ir_IF_TRUE_cold(if_dynamic);
14748 ir_END_list(slow_inputs);
14749
14750 ir_IF_FALSE(if_dynamic);
14751 prop_ref = ir_ADD_A(obj_ref, offset_ref);
14752 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14753 ir_IF_FALSE_cold(if_def);
14754 ir_END_list(slow_inputs);
14755
14756 ir_IF_TRUE(if_def);
14757 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14758
14759 if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14760 ir_ref arg3, arg4;
14761 ir_ref prop_info_ref = ir_LOAD_A(
14762 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14763 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14764 ir_IF_TRUE_cold(if_has_prop_info);
14765
14766 if (Z_MODE(val_addr) == IS_REG) {
14767 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14768 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14769 return 0;
14770 }
14771 arg3 = jit_ZVAL_ADDR(jit, real_addr);
14772 } else {
14773 arg3 = jit_ZVAL_ADDR(jit, val_addr);
14774 }
14775
14776 if (!RETURN_VALUE_USED(opline)) {
14777 arg4 = IR_NULL;
14778 } else if (Z_MODE(res_addr) == IS_REG) {
14779 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14780 arg4 = jit_ZVAL_ADDR(jit, real_addr);
14781 } else {
14782 arg4 = jit_ZVAL_ADDR(jit, res_addr);
14783 }
14784 // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14785 jit_SET_EX_OPLINE(jit, opline);
14786 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14787 prop_ref,
14788 prop_info_ref,
14789 arg3,
14790 arg4);
14791
14792 if ((opline+1)->op1_type == IS_CONST) {
14793 // TODO: ???
14794 // if (Z_TYPE_P(value) == orig_type) {
14795 // CACHE_PTR_EX(cache_slot + 2, NULL);
14796 }
14797
14798 ir_END_list(end_inputs);
14799 ir_IF_FALSE(if_has_prop_info);
14800 }
14801 } else {
14802 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14803 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14804 /* With the exception of __clone(), readonly assignment always happens on IS_UNDEF, doding
14805 * the fast path. Thus, the fast path is not useful. */
14806 if (prop_info->flags & ZEND_ACC_READONLY) {
14807 ZEND_ASSERT(slow_inputs == IR_UNUSED);
14808 goto slow_path;
14809 }
14810 // Undefined property with potential magic __get()/__set() or lazy object
14811 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14812 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14813 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14814
14815 if (!exit_addr) {
14816 return 0;
14817 }
14818 ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
14819 } else {
14820 ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
14821 ir_IF_FALSE_cold(if_def);
14822 ir_END_list(slow_inputs);
14823 ir_IF_TRUE(if_def);
14824 }
14825 if (ZEND_TYPE_IS_SET(prop_info->type)) {
14826 ir_ref ref, arg3, arg4;
14827
14828 // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14829 jit_SET_EX_OPLINE(jit, opline);
14830 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14831 ref = ir_CONST_ADDR(prop_info);
14832 } else {
14833 int prop_info_offset =
14834 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14835
14836 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14837 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14838 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14839 }
14840 if (Z_MODE(val_addr) == IS_REG) {
14841 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14842 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14843 return 0;
14844 }
14845 arg3 = jit_ZVAL_ADDR(jit, real_addr);
14846 } else {
14847 arg3 = jit_ZVAL_ADDR(jit, val_addr);
14848 }
14849 if (!RETURN_VALUE_USED(opline)) {
14850 arg4 = IR_NULL;
14851 } else if (Z_MODE(res_addr) == IS_REG) {
14852 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14853 arg4 = jit_ZVAL_ADDR(jit, real_addr);
14854 } else {
14855 arg4 = jit_ZVAL_ADDR(jit, res_addr);
14856 }
14857 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
14858 prop_ref,
14859 ref,
14860 arg3,
14861 arg4);
14862
14863 ir_END_list(end_inputs);
14864 }
14865 }
14866
14867 if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14868 if (Z_MODE(val_addr) != IS_REG
14869 && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
14870 && opline->result_type == IS_UNUSED) {
14871 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)) {
14872 return 0;
14873 }
14874 } else {
14875 zend_jit_addr real_res_addr;
14876
14877 if (res_addr && Z_MODE(res_addr) == IS_REG) {
14878 real_res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14879 } else {
14880 real_res_addr = res_addr;
14881 }
14882 if (!zend_jit_assign_to_variable(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, real_res_addr, 0, 0)) {
14883 return 0;
14884 }
14885 }
14886 if (end_inputs || slow_inputs) {
14887 if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14889 /* skip FREE_OP_DATA() */
14890 delayed_end_input = ir_END();
14891 } else {
14892 ir_END_list(end_inputs);
14893 }
14894 }
14895 }
14896
14897 if (slow_inputs) {
14898 ir_ref arg3, arg5;
14899
14900 ir_MERGE_list(slow_inputs);
14901
14902slow_path:
14903 jit_SET_EX_OPLINE(jit, opline);
14904
14905 if (Z_MODE(val_addr) == IS_REG) {
14906 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14907 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14908 return 0;
14909 }
14910 arg3 = jit_ZVAL_ADDR(jit, real_addr);
14911 } else {
14912 arg3 = jit_ZVAL_ADDR(jit, val_addr);
14913 }
14914 if (!RETURN_VALUE_USED(opline)) {
14915 arg5 = IR_NULL;
14916 } else if (Z_MODE(res_addr) == IS_REG) {
14917 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14918 arg5 = jit_ZVAL_ADDR(jit, real_addr);
14919 } else {
14920 arg5 = jit_ZVAL_ADDR(jit, res_addr);
14921 }
14922
14923 // JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14924 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14925 ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
14926 obj_ref,
14928 arg3,
14929 ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
14930 arg5);
14931
14932 ir_END_list(end_inputs);
14933 }
14934
14935 if (end_inputs) {
14936 ir_MERGE_list(end_inputs);
14937
14939 val_info |= MAY_BE_RC1|MAY_BE_RCN;
14940 }
14941 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
14942
14943 if (delayed_end_input) {
14944 ir_MERGE_WITH(delayed_end_input);
14945 }
14946 }
14947
14948 if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14949 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14950 }
14951
14952 if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14953 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14954 if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14955 return 0;
14956 }
14957 }
14958
14959 if (may_throw) {
14960 zend_jit_check_exception(jit);
14961 }
14962
14963 return 1;
14964}
14965
14966static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
14967 const zend_op *opline,
14968 const zend_op_array *op_array,
14969 zend_ssa *ssa,
14970 const zend_ssa_op *ssa_op,
14971 uint32_t op1_info,
14972 zend_jit_addr op1_addr,
14973 uint32_t val_info,
14974 zend_jit_addr val_addr,
14975 zend_ssa_range *val_range,
14976 bool op1_indirect,
14977 zend_class_entry *ce,
14978 bool ce_is_instanceof,
14979 bool on_this,
14980 bool delayed_fetch_this,
14981 zend_class_entry *trace_ce,
14982 uint8_t prop_type)
14983{
14984 zval *member;
14987 zend_jit_addr prop_addr;
14988 bool use_prop_guard = 0;
14989 bool may_throw = 0;
14990 binary_op_type binary_op = get_binary_op(opline->extended_value);
14991 ir_ref obj_ref = IR_UNUSED;
14992 ir_ref prop_ref = IR_UNUSED;
14993 ir_ref end_inputs = IR_UNUSED;
14994 ir_ref slow_inputs = IR_UNUSED;
14995
14996 ZEND_ASSERT(opline->op2_type == IS_CONST);
14997 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14998 ZEND_ASSERT(opline->result_type == IS_UNUSED);
14999
15000 member = RT_CONSTANT(opline, opline->op2);
15001 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15002 name = Z_STR_P(member);
15003 prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15004
15005 if (on_this) {
15006 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15007 obj_ref = jit_Z_PTR(jit, this_addr);
15008 } else {
15009 if (opline->op1_type == IS_VAR
15010 && (op1_info & MAY_BE_INDIRECT)
15011 && Z_REG(op1_addr) == ZREG_FP) {
15012 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15013 }
15014 if (op1_info & MAY_BE_REF) {
15015 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15016 }
15017 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15018 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15019 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15020 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15021
15022 if (!exit_addr) {
15023 return 0;
15024 }
15025 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15026 } else {
15027 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15028 ir_IF_FALSE_cold(if_obj);
15029
15030 jit_SET_EX_OPLINE(jit, opline);
15032 (op1_info & MAY_BE_UNDEF) ?
15033 ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
15034 ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
15035 jit_ZVAL_ADDR(jit, op1_addr),
15037
15038 may_throw = 1;
15039
15040 ir_END_list(end_inputs);
15041 ir_IF_TRUE(if_obj);
15042 }
15043 }
15044 obj_ref = jit_Z_PTR(jit, op1_addr);
15045 }
15046
15047 ZEND_ASSERT(obj_ref);
15048 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15049 prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15050 if (prop_info) {
15051 ce = trace_ce;
15052 ce_is_instanceof = 0;
15053 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15054 if (on_this && JIT_G(current_frame)
15055 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15056 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15057 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15058 if (on_this && JIT_G(current_frame)) {
15059 JIT_G(current_frame)->ce = ce;
15061 }
15062 } else {
15063 return 0;
15064 }
15065 if (ssa->var_info && ssa_op->op1_use >= 0) {
15066 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15067 ssa->var_info[ssa_op->op1_use].ce = ce;
15068 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15069 }
15070 if (ssa->var_info && ssa_op->op1_def >= 0) {
15071 ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15072 ssa->var_info[ssa_op->op1_def].ce = ce;
15073 ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15074 }
15075 }
15076 }
15077 }
15078
15079 use_prop_guard = (prop_type != IS_UNKNOWN
15080 && prop_type != IS_UNDEF
15081 && prop_type != IS_REFERENCE
15082 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15083
15084 if (Z_MODE(val_addr) == IS_REG
15085 && Z_LOAD(val_addr)
15086 && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
15087 /* Force load */
15088 zend_jit_use_reg(jit, val_addr);
15089 }
15090
15091 if (!prop_info) {
15092 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15093 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15094 ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15095
15096 ir_IF_FALSE_cold(if_same);
15097 ir_END_list(slow_inputs);
15098
15099 ir_IF_TRUE(if_same);
15100 if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15101 ir_ref prop_info_ref = ir_LOAD_A(
15102 ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15103 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15104 ir_IF_TRUE_cold(if_has_prop_info);
15105 ir_END_list(slow_inputs);
15106
15107 ir_IF_FALSE(if_has_prop_info);
15108 }
15109 ir_ref offset_ref = ir_LOAD_A(
15110 ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15111
15112 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15113 ir_IF_TRUE_cold(if_dynamic);
15114 ir_END_list(slow_inputs);
15115
15116 ir_IF_FALSE(if_dynamic);
15117
15118 prop_ref = ir_ADD_A(obj_ref, offset_ref);
15119 if (!use_prop_guard) {
15120 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15121 ir_IF_FALSE_cold(if_def);
15122 ir_END_list(slow_inputs);
15123
15124 ir_IF_TRUE(if_def);
15125 }
15126 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15127 } else {
15128 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15129 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15130
15131 if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15132 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15133 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15134 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15135
15136 if (!exit_addr) {
15137 return 0;
15138 }
15139 ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15140 } else {
15141 ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15142 ir_IF_FALSE_cold(if_def);
15143 ir_END_list(slow_inputs);
15144 ir_IF_TRUE(if_def);
15145 }
15146 }
15147 if (ZEND_TYPE_IS_SET(prop_info->type)) {
15148 ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15149
15150 may_throw = 1;
15151
15152 jit_SET_EX_OPLINE(jit, opline);
15153
15154 if (Z_MODE(val_addr) == IS_REG) {
15155 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15156 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15157 return 0;
15158 }
15159 arg2 = jit_ZVAL_ADDR(jit, real_addr);
15160 } else {
15161 arg2 = jit_ZVAL_ADDR(jit, val_addr);
15162 }
15163
15164 if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15165 ir_IF_FALSE(if_ref);
15166 noref_path = ir_END();
15167 ir_IF_TRUE(if_ref);
15168
15169 reference = jit_Z_PTR(jit, prop_addr);
15170 ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15171 if_typed = jit_if_TYPED_REF(jit, reference);
15172 ir_IF_FALSE(if_typed);
15173 ref_path = ir_END();
15174 ir_IF_TRUE_cold(if_typed);
15175
15176 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15177 reference,
15178 arg2,
15179 ir_CONST_FC_FUNC(binary_op));
15180
15181 ir_END_list(end_inputs);
15182
15183 ir_MERGE_2(noref_path, ref_path);
15184 prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15185 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15186
15187 // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15188 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15189 ref = ir_CONST_ADDR(prop_info);
15190 } else {
15191 int prop_info_offset =
15192 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15193
15194 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15195 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15196 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15197 }
15198
15199 ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
15200 prop_ref,
15201 ref,
15202 arg2,
15203 ir_CONST_FC_FUNC(binary_op));
15204
15205 ir_END_list(end_inputs);
15206 }
15207 }
15208
15209 if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15210 zend_jit_addr var_addr = prop_addr;
15211 uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15212 uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15213
15214 if (use_prop_guard) {
15215 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15216 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15217 if (!exit_addr) {
15218 return 0;
15219 }
15220
15221 jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15222 var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15223 }
15224
15225 if (var_info & MAY_BE_REF) {
15226 ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15227
15228 may_throw = 1;
15229
15230 if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15231 ir_IF_FALSE(if_ref);
15232 noref_path = ir_END();
15233 ir_IF_TRUE(if_ref);
15234
15235 reference = jit_Z_PTR(jit, var_addr);
15236 ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15237 if_typed = jit_if_TYPED_REF(jit, reference);
15238 ir_IF_FALSE(if_typed);
15239 ref_path = ir_END();
15240 ir_IF_TRUE_cold(if_typed);
15241
15242 jit_SET_EX_OPLINE(jit, opline);
15243
15244 if (Z_MODE(val_addr) == IS_REG) {
15245 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15246 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15247 return 0;
15248 }
15249 arg2 = jit_ZVAL_ADDR(jit, real_addr);
15250 } else {
15251 arg2 = jit_ZVAL_ADDR(jit, val_addr);
15252 }
15253 ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15254 reference,
15255 arg2,
15256 ir_CONST_FC_FUNC(binary_op));
15257
15258 ir_END_list(end_inputs);
15259
15260 ir_MERGE_2(noref_path, ref_path);
15261 prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15262 var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15263
15264 var_info &= ~MAY_BE_REF;
15265 }
15266
15267 uint8_t val_op_type = (opline+1)->op1_type;
15268 if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
15269 /* prevent FREE_OP in the helpers */
15270 val_op_type = IS_CV;
15271 }
15272
15273 switch (opline->extended_value) {
15274 case ZEND_ADD:
15275 case ZEND_SUB:
15276 case ZEND_MUL:
15279 if (opline->extended_value != ZEND_ADD ||
15280 (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
15281 (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
15282 may_throw = 1;
15283 }
15284 }
15285 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,
15286 1 /* may overflow */, 0)) {
15287 return 0;
15288 }
15289 break;
15290 case ZEND_BW_OR:
15291 case ZEND_BW_AND:
15292 case ZEND_BW_XOR:
15295 if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
15296 (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
15297 may_throw = 1;
15298 }
15299 }
15300 goto long_math;
15301 case ZEND_SL:
15302 case ZEND_SR:
15305 may_throw = 1;
15306 }
15307 if (val_op_type != IS_CONST ||
15308 Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15309 Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
15310 may_throw = 1;
15311 }
15312 goto long_math;
15313 case ZEND_MOD:
15316 may_throw = 1;
15317 }
15318 if (val_op_type != IS_CONST ||
15319 Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15320 Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
15321 may_throw = 1;
15322 }
15323long_math:
15324 if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
15325 IS_CV, opline->op1, var_addr, var_info, NULL,
15326 val_op_type, (opline+1)->op1, val_addr, val_info,
15327 val_range,
15328 0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
15329 return 0;
15330 }
15331 break;
15332 case ZEND_CONCAT:
15333 may_throw = 1;
15334 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,
15335 0)) {
15336 return 0;
15337 }
15338 break;
15339 default:
15341 }
15342 if (end_inputs || slow_inputs) {
15343 ir_END_list(end_inputs);
15344 }
15345 }
15346
15347 if (slow_inputs) {
15348 ir_ref arg3;
15349
15350 ir_MERGE_list(slow_inputs);
15351
15352 may_throw = 1;
15353
15354 if (Z_MODE(val_addr) == IS_REG) {
15355 zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15356 if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15357 return 0;
15358 }
15359 arg3 = jit_ZVAL_ADDR(jit, real_addr);
15360 } else {
15361 arg3 = jit_ZVAL_ADDR(jit, val_addr);
15362 }
15363 jit_SET_EX_OPLINE(jit, opline);
15364 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15365 ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15366 obj_ref,
15368 arg3,
15369 ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15370 ir_CONST_FC_FUNC(binary_op));
15371
15372 ir_END_list(end_inputs);
15373 }
15374
15375 if (end_inputs) {
15376 ir_MERGE_list(end_inputs);
15377 }
15378
15380 val_info |= MAY_BE_RC1|MAY_BE_RCN;
15381 }
15382
15383 // JIT: FREE_OP_DATA();
15384 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15385
15386 if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15387 if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15388 may_throw = 1;
15389 }
15390 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15391 }
15392
15393 if (may_throw) {
15394 zend_jit_check_exception(jit);
15395 }
15396
15397 return 1;
15398}
15399
15400static int zend_jit_incdec_obj(zend_jit_ctx *jit,
15401 const zend_op *opline,
15402 const zend_op_array *op_array,
15403 zend_ssa *ssa,
15404 const zend_ssa_op *ssa_op,
15405 uint32_t op1_info,
15406 zend_jit_addr op1_addr,
15407 bool op1_indirect,
15408 zend_class_entry *ce,
15409 bool ce_is_instanceof,
15410 bool on_this,
15411 bool delayed_fetch_this,
15412 zend_class_entry *trace_ce,
15413 uint8_t prop_type)
15414{
15415 zval *member;
15418 zend_jit_addr res_addr = 0;
15419 zend_jit_addr prop_addr;
15420 bool use_prop_guard = 0;
15421 bool may_throw = 0;
15422 uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15423 ir_ref obj_ref = IR_UNUSED;
15424 ir_ref prop_ref = IR_UNUSED;
15425 ir_ref end_inputs = IR_UNUSED;
15426 ir_ref slow_inputs = IR_UNUSED;
15427
15428 ZEND_ASSERT(opline->op2_type == IS_CONST);
15429 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15430
15431 if (opline->result_type != IS_UNUSED) {
15432 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15433 }
15434
15435 member = RT_CONSTANT(opline, opline->op2);
15436 ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15437 name = Z_STR_P(member);
15438 prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15439
15440 if (on_this) {
15441 zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15442 obj_ref = jit_Z_PTR(jit, this_addr);
15443 } else {
15444 if (opline->op1_type == IS_VAR
15445 && (op1_info & MAY_BE_INDIRECT)
15446 && Z_REG(op1_addr) == ZREG_FP) {
15447 op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15448 }
15449 if (op1_info & MAY_BE_REF) {
15450 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15451 }
15452 if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15453 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15454 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15455 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15456
15457 if (!exit_addr) {
15458 return 0;
15459 }
15460 jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15461 } else {
15462 ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15463 ir_IF_FALSE_cold(if_obj);
15464
15465 jit_SET_EX_OPLINE(jit, opline);
15466 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15467 jit_ZVAL_ADDR(jit, op1_addr),
15469
15470 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15471 ir_IF_TRUE(if_obj);
15472 }
15473 }
15474 obj_ref = jit_Z_PTR(jit, op1_addr);
15475 }
15476
15477 ZEND_ASSERT(obj_ref);
15478 if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15479 prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15480 if (prop_info) {
15481 ce = trace_ce;
15482 ce_is_instanceof = 0;
15483 if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15484 if (on_this && JIT_G(current_frame)
15485 && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15486 ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15487 } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15488 if (on_this && JIT_G(current_frame)) {
15489 JIT_G(current_frame)->ce = ce;
15491 }
15492 } else {
15493 return 0;
15494 }
15495 if (ssa->var_info && ssa_op->op1_use >= 0) {
15496 ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15497 ssa->var_info[ssa_op->op1_use].ce = ce;
15498 ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15499 }
15500 if (ssa->var_info && ssa_op->op1_def >= 0) {
15501 ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15502 ssa->var_info[ssa_op->op1_def].ce = ce;
15503 ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15504 }
15505 }
15506 }
15507 }
15508
15509 use_prop_guard = (prop_type != IS_UNKNOWN
15510 && prop_type != IS_UNDEF
15511 && prop_type != IS_REFERENCE
15512 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15513
15514 if (!prop_info) {
15515 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15516 ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15517 ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15518
15519 ir_IF_FALSE_cold(if_same);
15520 ir_END_list(slow_inputs);
15521
15522 ir_IF_TRUE(if_same);
15523 if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15524 ir_ref prop_info_ref = ir_LOAD_A(
15525 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15526 ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15527 ir_IF_TRUE_cold(if_has_prop_info);
15528 ir_END_list(slow_inputs);
15529
15530 ir_IF_FALSE(if_has_prop_info);
15531 }
15532 ir_ref offset_ref = ir_LOAD_A(
15533 ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15534
15535 ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15536 ir_IF_TRUE_cold(if_dynamic);
15537 ir_END_list(slow_inputs);
15538
15539 ir_IF_FALSE(if_dynamic);
15540
15541 prop_ref = ir_ADD_A(obj_ref, offset_ref);
15542 if (!use_prop_guard) {
15543 ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15544 ir_IF_FALSE_cold(if_def);
15545 ir_END_list(slow_inputs);
15546
15547 ir_IF_TRUE(if_def);
15548 }
15549 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15550 } else {
15551 prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15552 prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15553
15554 if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15555 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15556 int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15557 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15558
15559 if (!exit_addr) {
15560 return 0;
15561 }
15562 ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15563 } else {
15564 ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15565 ir_IF_FALSE_cold(if_def);
15566 ir_END_list(slow_inputs);
15567 ir_IF_TRUE(if_def);
15568 }
15569 }
15570
15571 if (ZEND_TYPE_IS_SET(prop_info->type)) {
15572 const void *func;
15573 ir_ref ref;
15574
15575 may_throw = 1;
15576 jit_SET_EX_OPLINE(jit, opline);
15577
15578 if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15579 ref = ir_CONST_ADDR(prop_info);
15580 } else {
15581 int prop_info_offset =
15582 (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15583
15584 ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15585 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15586 ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15587 }
15588
15589 if (opline->result_type == IS_UNUSED) {
15590 switch (opline->opcode) {
15591 case ZEND_PRE_INC_OBJ:
15592 case ZEND_POST_INC_OBJ:
15593 func = zend_jit_inc_typed_prop;
15594 break;
15595 case ZEND_PRE_DEC_OBJ:
15596 case ZEND_POST_DEC_OBJ:
15597 func = zend_jit_dec_typed_prop;
15598 break;
15599 default:
15601 }
15602
15603 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
15604 } else {
15605 switch (opline->opcode) {
15606 case ZEND_PRE_INC_OBJ:
15607 func = zend_jit_pre_inc_typed_prop;
15608 break;
15609 case ZEND_PRE_DEC_OBJ:
15610 func = zend_jit_pre_dec_typed_prop;
15611 break;
15612 case ZEND_POST_INC_OBJ:
15613 func = zend_jit_post_inc_typed_prop;
15614 break;
15615 case ZEND_POST_DEC_OBJ:
15616 func = zend_jit_post_dec_typed_prop;
15617 break;
15618 default:
15620 }
15622 prop_ref,
15623 ref,
15624 jit_ZVAL_ADDR(jit, res_addr));
15625 }
15626 ir_END_list(end_inputs);
15627 }
15628 }
15629
15630 if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15631 uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15632 zend_jit_addr var_addr = prop_addr;
15633 ir_ref if_long = IR_UNUSED;
15634 ir_ref if_overflow = IR_UNUSED;
15635
15636 if (use_prop_guard) {
15637 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15638 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15639 if (!exit_addr) {
15640 return 0;
15641 }
15642
15643 jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15644 var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15645 }
15646
15647 if (var_info & MAY_BE_REF) {
15648 const void *func;
15649 ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
15650
15651 if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15652 ir_IF_FALSE(if_ref);
15653 noref_path = ir_END();
15654 ir_IF_TRUE(if_ref);
15655
15656 reference = jit_Z_PTR(jit, var_addr);
15657 ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15658 if_typed = jit_if_TYPED_REF(jit, reference);
15659 ir_IF_FALSE(if_typed);
15660 ref_path = ir_END();
15661 ir_IF_TRUE_cold(if_typed);
15662
15663 switch (opline->opcode) {
15664 case ZEND_PRE_INC_OBJ:
15665 func = zend_jit_pre_inc_typed_ref;
15666 break;
15667 case ZEND_PRE_DEC_OBJ:
15668 func = zend_jit_pre_dec_typed_ref;
15669 break;
15670 case ZEND_POST_INC_OBJ:
15671 func = zend_jit_post_inc_typed_ref;
15672 break;
15673 case ZEND_POST_DEC_OBJ:
15674 func = zend_jit_post_dec_typed_ref;
15675 break;
15676 default:
15678 }
15679
15680 may_throw = 1;
15681 jit_SET_EX_OPLINE(jit, opline);
15683 reference,
15684 (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15685
15686 ir_END_list(end_inputs);
15687
15688 ir_MERGE_2(noref_path, ref_path);
15689 prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15690 var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15691
15692 var_info &= ~MAY_BE_REF;
15693 }
15694
15695 if (var_info & MAY_BE_LONG) {
15696 ir_ref addr, ref;
15697
15698 if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15699 if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
15700 ir_IF_TRUE(if_long);
15701 }
15702
15703 addr = jit_ZVAL_ADDR(jit, var_addr);
15704 ref = ir_LOAD_L(addr);
15705 if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15706 if (opline->result_type != IS_UNUSED) {
15707 jit_set_Z_LVAL(jit, res_addr, ref);
15708 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15709 }
15710 }
15711 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15712 ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
15713 } else {
15714 ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
15715 }
15716
15717 ir_STORE(addr, ref);
15718 if_overflow = ir_IF(ir_OVERFLOW(ref));
15719 ir_IF_FALSE(if_overflow);
15720
15721 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
15722 if (opline->result_type != IS_UNUSED) {
15723 jit_set_Z_LVAL(jit, res_addr, ref);
15724 jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15725 }
15726 }
15727 ir_END_list(end_inputs);
15728 }
15729
15730 if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15731 if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15732 may_throw = 1;
15733 }
15734 if (if_long) {
15735 ir_IF_FALSE_cold(if_long);
15736 }
15737 if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15738 jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, 1);
15739 }
15740 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15741 if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15742 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
15743 jit_ZVAL_ADDR(jit, var_addr),
15744 jit_ZVAL_ADDR(jit, res_addr));
15745 } else {
15747 jit_ZVAL_ADDR(jit, var_addr));
15748 }
15749 } else {
15750 if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15751 ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
15752 jit_ZVAL_ADDR(jit, var_addr),
15753 jit_ZVAL_ADDR(jit, res_addr));
15754 } else {
15756 jit_ZVAL_ADDR(jit, var_addr));
15757 }
15758 }
15759
15760 ir_END_list(end_inputs);
15761 }
15762 if (var_info & MAY_BE_LONG) {
15763 ir_IF_TRUE_cold(if_overflow);
15764 if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15765#if SIZEOF_ZEND_LONG == 4
15766 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
15767 jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
15768#else
15769 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
15770#endif
15771 jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15772 if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15773#if SIZEOF_ZEND_LONG == 4
15774 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
15775 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
15776#else
15777 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
15778#endif
15779 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15780 }
15781 } else {
15782#if SIZEOF_ZEND_LONG == 4
15783 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
15784 jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
15785#else
15786 jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
15787#endif
15788 jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
15789 if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15790#if SIZEOF_ZEND_LONG == 4
15791 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
15792 jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
15793#else
15794 jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
15795#endif
15796 jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
15797 }
15798 }
15799 if (opline->result_type != IS_UNUSED
15800 && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
15801 && prop_info
15802 && !ZEND_TYPE_IS_SET(prop_info->type)
15803 && (res_info & MAY_BE_GUARD)
15804 && (res_info & MAY_BE_LONG)) {
15805 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
15806 uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
15807 int32_t exit_point;
15808 const void *exit_addr;
15809
15810 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
15811 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15812 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15813 if (!exit_addr) {
15814 return 0;
15815 }
15816 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
15817 ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
15818 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
15819 } else {
15820 ir_END_list(end_inputs);
15821 }
15822 }
15823 }
15824
15825 if (slow_inputs) {
15826 const void *func;
15827
15828 ir_MERGE_list(slow_inputs);
15829
15830 // JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
15831 switch (opline->opcode) {
15832 case ZEND_PRE_INC_OBJ:
15833 func = zend_jit_pre_inc_obj_helper;
15834 break;
15835 case ZEND_PRE_DEC_OBJ:
15836 func = zend_jit_pre_dec_obj_helper;
15837 break;
15838 case ZEND_POST_INC_OBJ:
15839 func = zend_jit_post_inc_obj_helper;
15840 break;
15841 case ZEND_POST_DEC_OBJ:
15842 func = zend_jit_post_dec_obj_helper;
15843 break;
15844 default:
15846 }
15847
15848 may_throw = 1;
15849 jit_SET_EX_OPLINE(jit, opline);
15850 ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15852 obj_ref,
15854 ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15855 (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15856
15857 ir_END_list(end_inputs);
15858 }
15859
15860 if (end_inputs) {
15861 ir_MERGE_list(end_inputs);
15862 }
15863
15864 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
15865 if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15866 may_throw = 1;
15867 }
15868 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15869 }
15870
15871 if (may_throw) {
15872 zend_jit_check_exception(jit);
15873 }
15874
15875 return 1;
15876}
15877
15878static 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)
15879{
15880 HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
15881 const zend_op *next_opline = NULL;
15882 ir_refs *slow_inputs;
15883
15884 ir_refs_init(slow_inputs, 8);
15885
15886 if (trace) {
15887 ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
15888 ZEND_ASSERT(trace->opline != NULL);
15889 next_opline = trace->opline;
15890 }
15891
15892 if (opline->op1_type == IS_CONST) {
15893 zval *zv = RT_CONSTANT(opline, opline->op1);
15894 zval *jump_zv = NULL;
15895 int b;
15896
15897 if (opline->opcode == ZEND_SWITCH_LONG) {
15898 if (Z_TYPE_P(zv) == IS_LONG) {
15899 jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
15900 }
15901 } else if (opline->opcode == ZEND_SWITCH_STRING) {
15902 if (Z_TYPE_P(zv) == IS_STRING) {
15903 jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
15904 }
15905 } else if (opline->opcode == ZEND_MATCH) {
15906 if (Z_TYPE_P(zv) == IS_LONG) {
15907 jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
15908 } else if (Z_TYPE_P(zv) == IS_STRING) {
15909 jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
15910 }
15911 } else {
15913 }
15914 if (next_opline) {
15915 const zend_op *target;
15916
15917 if (jump_zv != NULL) {
15918 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
15919 } else {
15920 target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
15921 }
15922 ZEND_ASSERT(target == next_opline);
15923 } else {
15924 if (jump_zv != NULL) {
15925 b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
15926 } else {
15927 b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
15928 }
15929 _zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
15930 jit->b = -1;
15931 }
15932 } else {
15933 zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
15934 uint32_t op1_info = OP1_INFO();
15935 zend_jit_addr op1_addr = OP1_ADDR();
15936 const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
15937 const zend_op *target;
15938 int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
15939 int b;
15940 int32_t exit_point;
15941 const void *exit_addr;
15942 const void *default_label = NULL;
15943 zval *zv;
15944
15945 if (next_opline) {
15946 if (next_opline != default_opline) {
15947 exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
15948 default_label = zend_jit_trace_get_exit_addr(exit_point);
15949 if (!default_label) {
15950 return 0;
15951 }
15952 }
15953 }
15954
15955 if (opline->opcode == ZEND_SWITCH_LONG) {
15956 if (op1_info & MAY_BE_LONG) {
15957 const void *fallback_label = NULL;
15958
15959 if (next_opline) {
15960 if (next_opline != opline + 1) {
15961 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
15962 fallback_label = zend_jit_trace_get_exit_addr(exit_point);
15963 if (!fallback_label) {
15964 return 0;
15965 }
15966 }
15967 }
15968 if (op1_info & MAY_BE_REF) {
15969 ir_ref ref, if_long, fast_path, ref2;
15970
15971 ref = jit_ZVAL_ADDR(jit, op1_addr);
15972 if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15973 ir_IF_TRUE(if_long);
15974 fast_path = ir_END();
15975 ir_IF_FALSE_cold(if_long);
15976
15977 // JIT: ZVAL_DEREF(op)
15978 if (fallback_label) {
15979 jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
15980 } else {
15981 ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
15982 ir_IF_FALSE_cold(if_ref);
15983 ir_refs_add(slow_inputs, ir_END());
15984 ir_IF_TRUE(if_ref);
15985 }
15986
15987 ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
15988 op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
15989
15990 if (fallback_label) {
15991 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
15992 } else {
15993 if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
15994 ir_IF_FALSE_cold(if_long);
15995 ir_refs_add(slow_inputs, ir_END());
15996 ir_IF_TRUE(if_long);
15997 }
15998
15999 ir_MERGE_2(fast_path, ir_END());
16000 ref = ir_PHI_2(IR_ADDR, ref, ref2);
16001 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16002 } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16003 if (fallback_label) {
16004 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16005 } else {
16006 ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16007 ir_IF_FALSE_cold(if_long);
16008 ir_refs_add(slow_inputs, ir_END());
16009 ir_IF_TRUE(if_long);
16010 }
16011 }
16012 ir_ref ref = jit_Z_LVAL(jit, op1_addr);
16013
16014 if (!HT_IS_PACKED(jumptable)) {
16016 ir_CONST_ADDR(jumptable), ref);
16017 ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16018 /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16019 if (sizeof(Bucket) == 32) {
16020 ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16021 } else {
16022 ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16023 }
16024 }
16025 ref = ir_SWITCH(ref);
16026
16027 if (next_opline) {
16028 ir_ref continue_list = IR_UNUSED;
16029
16030 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16031 ir_ref idx;
16032 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16033
16034 if (HT_IS_PACKED(jumptable)) {
16035 idx = ir_CONST_LONG(zv - jumptable->arPacked);
16036 } else {
16037 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16038 }
16039 ir_CASE_VAL(ref, idx);
16040 if (target == next_opline) {
16041 ir_END_list(continue_list);
16042 } else {
16043 exit_point = zend_jit_trace_get_exit_point(target, 0);
16044 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16045 if (!exit_addr) {
16046 return 0;
16047 }
16048 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16049 }
16051
16052 ir_CASE_DEFAULT(ref);
16053 if (next_opline == default_opline) {
16054 ir_END_list(continue_list);
16055 } else {
16056 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16057 }
16058 if (continue_list) {
16059 ir_MERGE_list(continue_list);
16060 } else {
16061 ZEND_ASSERT(slow_inputs->count);
16062 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16063 }
16064 } else {
16065 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16066 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16067 b = ssa->cfg.map[target - op_array->opcodes];
16068 _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16070
16071 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16072 if (slow_inputs->count) {
16073 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16074 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16075 }
16076 jit->b = -1;
16077 }
16078 } else if (!next_opline) {
16079 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16080 jit->b = -1;
16081 }
16082 } else if (opline->opcode == ZEND_SWITCH_STRING) {
16083 if (op1_info & MAY_BE_STRING) {
16084 const void *fallback_label = NULL;
16085
16086 if (next_opline) {
16087 if (next_opline != opline + 1) {
16088 exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16089 fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16090 if (!fallback_label) {
16091 return 0;
16092 }
16093 }
16094 }
16095 if (op1_info & MAY_BE_REF) {
16096 ir_ref ref, if_string, fast_path, ref2;
16097
16098 ref = jit_ZVAL_ADDR(jit, op1_addr);
16099 if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16100 ir_IF_TRUE(if_string);
16101 fast_path = ir_END();
16102 ir_IF_FALSE_cold(if_string);
16103
16104 // JIT: ZVAL_DEREF(op)
16105 if (fallback_label) {
16106 jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16107 } else {
16108 ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16109 ir_IF_FALSE_cold(if_ref);
16110 ir_refs_add(slow_inputs, ir_END());
16111 ir_IF_TRUE(if_ref);
16112 }
16113
16114 ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16115 op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16116
16117 if (fallback_label) {
16118 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16119 } else {
16120 if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16121 ir_IF_FALSE_cold(if_string);
16122 ir_refs_add(slow_inputs, ir_END());
16123 ir_IF_TRUE(if_string);
16124 }
16125
16126 ir_MERGE_2(fast_path, ir_END());
16127 ref = ir_PHI_2(IR_ADDR, ref, ref2);
16128 op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16129 } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
16130 if (fallback_label) {
16131 jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
16132 } else {
16133 ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16134 ir_IF_FALSE_cold(if_string);
16135 ir_refs_add(slow_inputs, ir_END());
16136 ir_IF_TRUE(if_string);
16137 }
16138 }
16139
16140 ir_ref ref = jit_Z_PTR(jit, op1_addr);
16142 ir_CONST_ADDR(jumptable), ref);
16143 ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16144 /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16145 if (sizeof(Bucket) == 32) {
16146 ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16147 } else {
16148 ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16149 }
16150 ref = ir_SWITCH(ref);
16151
16152 if (next_opline) {
16153 ir_ref continue_list = IR_UNUSED;
16154
16155 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16156 ir_ref idx;
16157 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16158
16159 if (HT_IS_PACKED(jumptable)) {
16160 idx = ir_CONST_LONG(zv - jumptable->arPacked);
16161 } else {
16162 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16163 }
16164 ir_CASE_VAL(ref, idx);
16165 if (target == next_opline) {
16166 ir_END_list(continue_list);
16167 } else {
16168 exit_point = zend_jit_trace_get_exit_point(target, 0);
16169 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16170 if (!exit_addr) {
16171 return 0;
16172 }
16173 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16174 }
16176
16177 ir_CASE_DEFAULT(ref);
16178 if (next_opline == default_opline) {
16179 ir_END_list(continue_list);
16180 } else {
16181 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16182 }
16183 if (continue_list) {
16184 ir_MERGE_list(continue_list);
16185 } else {
16186 ZEND_ASSERT(slow_inputs->count);
16187 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16188 }
16189 } else {
16190 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16191 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16192 b = ssa->cfg.map[target - op_array->opcodes];
16193 _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16195 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16196 if (slow_inputs->count) {
16197 ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16198 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16199 }
16200 jit->b = -1;
16201 }
16202 } else if (!next_opline) {
16203 _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16204 jit->b = -1;
16205 }
16206 } else if (opline->opcode == ZEND_MATCH) {
16207 ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
16208 ir_ref continue_list = IR_UNUSED;
16209
16210 if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
16211 ir_ref long_path = IR_UNUSED;
16212
16213 if (op1_info & MAY_BE_REF) {
16214 op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
16215 }
16216 if (op1_info & MAY_BE_LONG) {
16217 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16218 if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
16219 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16220 ir_IF_TRUE(if_type);
16221 } else if (default_label) {
16222 jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
16223 } else if (next_opline) {
16224 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16225 ir_IF_FALSE(if_type);
16226 ir_END_list(continue_list);
16227 ir_IF_TRUE(if_type);
16228 } else {
16229 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16230 ir_IF_FALSE(if_type);
16231 ir_END_list(default_input_list);
16232 ir_IF_TRUE(if_type);
16233 }
16234 }
16235 ref = jit_Z_LVAL(jit, op1_addr);
16237 ir_CONST_ADDR(jumptable), ref);
16238 if (op1_info & MAY_BE_STRING) {
16239 long_path = ir_END();
16240 }
16241 }
16242 if (op1_info & MAY_BE_STRING) {
16243 if (if_type) {
16244 ir_IF_FALSE(if_type);
16245 if_type = IS_UNUSED;
16246 }
16247 if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
16248 if (op1_info & MAY_BE_UNDEF) {
16249 if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16250 ir_IF_TRUE(if_type);
16251 } else if (default_label) {
16252 jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
16253 } else if (next_opline) {
16254 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16255 ir_IF_FALSE(if_type);
16256 ir_END_list(continue_list);
16257 ir_IF_TRUE(if_type);
16258 } else {
16259 ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16260 ir_IF_FALSE(if_type);
16261 ir_END_list(default_input_list);
16262 ir_IF_TRUE(if_type);
16263 }
16264 }
16265 ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
16267 ir_CONST_ADDR(jumptable), ref2);
16268 if (op1_info & MAY_BE_LONG) {
16269 ir_MERGE_WITH(long_path);
16270 ref = ir_PHI_2(IR_LONG, ref2, ref);
16271 } else {
16272 ref = ref2;
16273 }
16274 }
16275
16276 ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16277 /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16278 if (HT_IS_PACKED(jumptable)) {
16279 ZEND_ASSERT(sizeof(zval) == 16);
16280 ref = ir_SHR_L(ref, ir_CONST_LONG(4));
16281 } else {
16282 if (sizeof(Bucket) == 32) {
16283 ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16284 } else {
16285 ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16286 }
16287 }
16288 ref = ir_SWITCH(ref);
16289
16290 if (next_opline) {
16291 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16292 ir_ref idx;
16293 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16294
16295 if (HT_IS_PACKED(jumptable)) {
16296 idx = ir_CONST_LONG(zv - jumptable->arPacked);
16297 } else {
16298 idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16299 }
16300 ir_CASE_VAL(ref, idx);
16301 if (target == next_opline) {
16302 ir_END_list(continue_list);
16303 } else {
16304 exit_point = zend_jit_trace_get_exit_point(target, 0);
16305 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16306 if (!exit_addr) {
16307 return 0;
16308 }
16309 jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16310 }
16312
16313 ir_CASE_DEFAULT(ref);
16314 if (next_opline == default_opline) {
16315 ir_END_list(continue_list);
16316 } else {
16317 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16318 }
16319 } else {
16320 ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16321 target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16322 b = ssa->cfg.map[target - op_array->opcodes];
16323 _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16325 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16326 }
16327 } else if (!(op1_info & MAY_BE_UNDEF)) {
16328 if (next_opline) {
16329 if (next_opline == default_opline) {
16330 ir_END_list(continue_list);
16331 } else {
16332 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16333 }
16334 } else {
16335 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16336 }
16337 }
16338
16339 if (op1_info & MAY_BE_UNDEF) {
16340 if (if_type) {
16341 ir_IF_FALSE(if_type);
16342 if_type = IS_UNUSED;
16343 }
16344 if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16345 if (default_label) {
16346 jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16347 } else if (next_opline) {
16348 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16349 ir_IF_TRUE(if_def);
16350 ir_END_list(continue_list);
16351 ir_IF_FALSE_cold(if_def);
16352 } else {
16353 ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16354 ir_IF_TRUE(if_def);
16355 ir_END_list(default_input_list);
16356 ir_IF_FALSE_cold(if_def);
16357 }
16358 }
16359
16360 jit_SET_EX_OPLINE(jit, opline);
16361 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16362 ir_CONST_U32(opline->op1.var));
16363 zend_jit_check_exception_undef_result(jit, opline);
16364 if (default_label) {
16365 jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16366 } else if (next_opline) {
16367 ir_END_list(continue_list);
16368 } else {
16369 ir_END_list(default_input_list);
16370 }
16371 }
16372 if (next_opline) {
16373 ZEND_ASSERT(continue_list);
16374 ir_MERGE_list(continue_list);
16375 } else {
16376 if (default_input_list) {
16377 if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16378 ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16379 jit->ctx.ir_base[ref].op3 = default_input_list;
16380 } else {
16381 ir_MERGE_list(default_input_list);
16382 _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16383 }
16384 }
16385 jit->b = -1;
16386 }
16387 } else {
16389 }
16390 }
16391 return 1;
16392}
16393
16394static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16395{
16396 int i, count;
16397 zend_basic_block *bb;
16398
16399 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : (IR_START_BR_TARGET|IR_ENTRY_BR_TARGET));
16400
16401 jit->ctx.spill_base = ZREG_FP;
16402
16403 jit->op_array = jit->current_op_array = op_array;
16404 jit->ssa = ssa;
16405 jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16406 jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16407
16408 count = 0;
16409 for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
16410 jit->bb_predecessors[i] = count;
16412 }
16413 jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
16414
16415 if (!GCC_GLOBAL_REGS) {
16416 ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16417 jit_STORE_FP(jit, ref);
16418 jit->ctx.flags |= IR_FASTCALL_FUNC;
16419 }
16420
16421 return 1;
16422}
16423
16424static void *zend_jit_finish(zend_jit_ctx *jit)
16425{
16426 void *entry;
16427 size_t size;
16428 zend_string *str = NULL;
16429
16433 if (jit->name) {
16434 str = zend_string_copy(jit->name);
16435 } else {
16436 str = zend_jit_func_name(jit->op_array);
16437 }
16438 }
16439
16440 if (jit->op_array) {
16441 /* Only for function JIT */
16442 _zend_jit_fix_merges(jit);
16443#if defined(IR_TARGET_AARCH64)
16444 } else if (jit->trace) {
16445 jit->ctx.deoptimization_exits = jit->trace->exit_count;
16446 jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
16447#endif
16448 } else {
16449#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
16451#endif
16452 }
16453
16454 entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
16455 if (entry) {
16457#ifdef HAVE_CAPSTONE
16459 if (str) {
16460 ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
16461 }
16462 ir_disasm(str ? ZSTR_VAL(str) : "unknown",
16463 entry, size,
16465 &jit->ctx, stderr);
16466 }
16467#endif
16468#ifndef _WIN32
16469 if (str) {
16471 uintptr_t sp_offset = 0;
16472
16473// ir_mem_unprotect(entry, size);
16474 if (!(jit->ctx.flags & IR_FUNCTION)
16475 && zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16476#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
16477 sp_offset = zend_jit_hybrid_vm_sp_adj;
16478#else
16479 sp_offset = sizeof(void*);
16480#endif
16481 } else {
16482 sp_offset = sizeof(void*);
16483 }
16484 ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
16485// ir_mem_protect(entry, size);
16486 }
16487
16489 ir_perf_map_register(ZSTR_VAL(str), entry, size);
16492 }
16493 }
16494 }
16495#endif
16496 }
16497
16498 if (jit->op_array) {
16499 /* Only for function JIT */
16500 const zend_op_array *op_array = jit->op_array;
16501 zend_op *opline = (zend_op*)op_array->opcodes;
16502
16503 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
16504 while (opline->opcode == ZEND_RECV) {
16505 opline++;
16506 }
16507 }
16508 opline->handler = entry;
16509
16510 if (jit->ctx.entries_count) {
16511 /* For all entries */
16512 int i = jit->ctx.entries_count;
16513 do {
16514 ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
16515 op_array->opcodes[insn->op2].handler = (char*)entry + insn->op3;
16516 } while (i != 0);
16517 }
16518 } else {
16519 /* Only for tracing JIT */
16520 zend_jit_trace_info *t = jit->trace;
16521 zend_jit_trace_stack *stack;
16522 uint32_t i;
16523
16524 if (t) {
16525 for (i = 0; i < t->stack_map_size; i++) {
16526 stack = t->stack_map + i;
16527 if (stack->flags & ZREG_SPILL_SLOT) {
16528 stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
16529 stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
16530 }
16531 }
16532 }
16533
16534 zend_jit_trace_add_code(entry, size);
16535 }
16536 }
16537
16538 if (str) {
16539 zend_string_release(str);
16540 }
16541
16542 return entry;
16543}
16544
16545static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
16546{
16547 const void *entry;
16548 size_t size;
16549 ir_code_buffer code_buffer;
16550
16551 code_buffer.start = dasm_buf;
16552 code_buffer.end = dasm_end;
16553 code_buffer.pos = *dasm_ptr;
16554
16555 entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
16556 &code_buffer, &size);
16557
16558 *dasm_ptr = code_buffer.pos;
16559
16560 if (entry) {
16561#ifdef HAVE_CAPSTONE
16563 uint32_t i;
16564 char name[32];
16565
16566 for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
16567 snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
16569 }
16570 }
16571#endif
16572 }
16573
16574 return entry;
16575}
16576
16577static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
16578{
16579 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16580 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16581 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16582
16583 if (!exit_addr) {
16584 return 0;
16585 }
16586 ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
16587
16588 return 1;
16589}
16590
16591static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
16592{
16593 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16594 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16595 zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16596
16597 if (!exit_addr) {
16598 return 0;
16599 }
16600 ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
16601
16602 return 1;
16603}
16604
16605static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
16606{
16607 uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16608 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16609
16610 if (!exit_addr) {
16611 return 0;
16612 }
16613 ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
16614
16615 return 1;
16616}
16617
16618static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
16619{
16620 uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
16621 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16622
16623 if (!exit_addr) {
16624 return 0;
16625 }
16626
16627 ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
16628 zend_jit_set_last_valid_opline(jit, opline);
16629
16630 return 1;
16631}
16632
16633static bool zend_jit_guard_reference(zend_jit_ctx *jit,
16634 const zend_op *opline,
16635 zend_jit_addr *var_addr_ptr,
16636 zend_jit_addr *ref_addr_ptr,
16637 bool add_ref_guard)
16638{
16639 zend_jit_addr var_addr = *var_addr_ptr;
16640 const void *exit_addr = NULL;
16641 ir_ref ref;
16642
16643 if (add_ref_guard) {
16644 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16645
16646 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16647 if (!exit_addr) {
16648 return 0;
16649 }
16650
16651 ref = jit_Z_TYPE(jit, var_addr);
16653 }
16654
16655 ref = jit_Z_PTR(jit, var_addr);
16656 *ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
16658 var_addr = ZEND_ADDR_REF_ZVAL(ref);
16659 *var_addr_ptr = var_addr;
16660
16661 return 1;
16662}
16663
16664static bool zend_jit_fetch_reference(zend_jit_ctx *jit,
16665 const zend_op *opline,
16666 uint8_t var_type,
16667 uint32_t *var_info_ptr,
16668 zend_jit_addr *var_addr_ptr,
16669 bool add_ref_guard,
16670 bool add_type_guard)
16671{
16672 zend_jit_addr var_addr = *var_addr_ptr;
16673 uint32_t var_info = *var_info_ptr;
16674 const void *exit_addr = NULL;
16675 ir_ref ref;
16676
16677 if (add_ref_guard || add_type_guard) {
16678 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16679
16680 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16681 if (!exit_addr) {
16682 return 0;
16683 }
16684 }
16685
16686 if (add_ref_guard) {
16687 ref = jit_Z_TYPE(jit, var_addr);
16689 }
16690 if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
16691 /* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
16692 ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
16693 jit_ZVAL_ADDR(jit, var_addr));
16694 *var_addr_ptr = var_addr;
16695 } else {
16696 ref = jit_Z_PTR(jit, var_addr);
16698 var_addr = ZEND_ADDR_REF_ZVAL(ref);
16699 *var_addr_ptr = var_addr;
16700 }
16701
16702 if (var_type != IS_UNKNOWN) {
16704 }
16705 if (add_type_guard
16706 && var_type != IS_UNKNOWN
16707 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16708 ref = jit_Z_TYPE(jit, var_addr);
16709 ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
16710
16711 ZEND_ASSERT(var_info & (1 << var_type));
16712 if (var_type < IS_STRING) {
16713 var_info = (1 << var_type);
16714 } else if (var_type != IS_ARRAY) {
16715 var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16716 } else {
16718 }
16719
16720 *var_info_ptr = var_info;
16721 } else {
16722 var_info &= ~MAY_BE_REF;
16723 *var_info_ptr = var_info;
16724 }
16725 *var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
16726
16727 return 1;
16728}
16729
16730static 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)
16731{
16732 zend_jit_addr var_addr = *var_addr_ptr;
16733 uint32_t var_info = *var_info_ptr;
16734 int32_t exit_point;
16735 const void *exit_addr;
16736 ir_ref ref = IR_UNUSED;
16737
16738 if (add_indirect_guard) {
16739 int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16740 const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16741
16742 if (!exit_addr) {
16743 return 0;
16744 }
16745 jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
16746 ref = jit_Z_PTR(jit, var_addr);
16747 } else {
16748 /* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
16749 * is eliminated by store forwarding (S2L) */
16750 ref = jit_Z_PTR(jit, var_addr);
16751 }
16752 *var_info_ptr &= ~MAY_BE_INDIRECT;
16753 var_addr = ZEND_ADDR_REF_ZVAL(ref);
16754 *var_addr_ptr = var_addr;
16755
16756 if (var_type != IS_UNKNOWN) {
16757 var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
16758 }
16759 if (!(var_type & IS_TRACE_REFERENCE)
16760 && var_type != IS_UNKNOWN
16761 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
16762 exit_point = zend_jit_trace_get_exit_point(opline, 0);
16763 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16764
16765 if (!exit_addr) {
16766 return 0;
16767 }
16768
16769 jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
16770
16771 //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
16772 ZEND_ASSERT(var_info & (1 << var_type));
16773 if (var_type < IS_STRING) {
16774 var_info = (1 << var_type);
16775 } else if (var_type != IS_ARRAY) {
16776 var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
16777 } else {
16779 }
16780
16781 *var_info_ptr = var_info;
16782 }
16783
16784 return 1;
16785}
16786
16787static 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)
16788{
16789 zend_jit_op_array_trace_extension *jit_extension =
16791 size_t offset = jit_extension->offset;
16792 const void *handler =
16793 (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
16794 ir_ref ref;
16795
16796 zend_jit_set_ip(jit, opline);
16797 if (GCC_GLOBAL_REGS) {
16799 } else {
16800 ref = jit_FP(jit);
16801 ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(handler), ref);
16802 }
16803 if (may_throw
16804 && opline->opcode != ZEND_RETURN
16805 && opline->opcode != ZEND_RETURN_BY_REF) {
16806 zend_jit_check_exception(jit);
16807 }
16808
16809 while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
16810 trace++;
16811 }
16812
16813 if (!GCC_GLOBAL_REGS
16814 && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
16815 if (opline->opcode == ZEND_RETURN ||
16816 opline->opcode == ZEND_RETURN_BY_REF ||
16817 opline->opcode == ZEND_DO_UCALL ||
16818 opline->opcode == ZEND_DO_FCALL_BY_NAME ||
16819 opline->opcode == ZEND_DO_FCALL ||
16820 opline->opcode == ZEND_GENERATOR_CREATE) {
16821
16822 ir_ref addr = jit_EG(current_execute_data);
16823
16824 jit_STORE_FP(jit, ir_LOAD_A(addr));
16825 }
16826 }
16827
16828 if (zend_jit_trace_may_exit(op_array, opline)) {
16829 if (opline->opcode == ZEND_RETURN ||
16830 opline->opcode == ZEND_RETURN_BY_REF ||
16831 opline->opcode == ZEND_GENERATOR_CREATE) {
16832
16833 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
16834 if (trace->op != ZEND_JIT_TRACE_END ||
16835 (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16836 trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16837 /* this check may be handled by the following OPLINE guard or jmp [IP] */
16839 jit_STUB_ADDR(jit, jit_stub_trace_halt));
16840 }
16841 } else if (GCC_GLOBAL_REGS) {
16842 ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16843 } else {
16844 ir_GUARD(ir_GE(ref, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
16845 }
16846 } else if (opline->opcode == ZEND_GENERATOR_RETURN ||
16847 opline->opcode == ZEND_YIELD ||
16848 opline->opcode == ZEND_YIELD_FROM) {
16849 ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
16850 ir_BEGIN(IR_UNUSED); /* unreachable block */
16851 }
16852 if (trace->op != ZEND_JIT_TRACE_END ||
16853 (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16854 trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16855
16856 const zend_op *next_opline = trace->opline;
16857 const zend_op *exit_opline = NULL;
16858 uint32_t exit_point;
16859 const void *exit_addr;
16860 uint32_t old_info = 0;
16861 uint32_t old_res_info = 0;
16862 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16863
16864 if (zend_is_smart_branch(opline)) {
16865 bool exit_if_true = 0;
16866 exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
16867 } else {
16868 switch (opline->opcode) {
16869 case ZEND_JMPZ:
16870 case ZEND_JMPNZ:
16871 case ZEND_JMPZ_EX:
16872 case ZEND_JMPNZ_EX:
16873 case ZEND_JMP_SET:
16874 case ZEND_COALESCE:
16875 case ZEND_JMP_NULL:
16876 case ZEND_FE_RESET_R:
16877 case ZEND_FE_RESET_RW:
16878 exit_opline = (trace->opline == opline + 1) ?
16879 OP_JMP_ADDR(opline, opline->op2) :
16880 opline + 1;
16881 break;
16882 case ZEND_FE_FETCH_R:
16883 case ZEND_FE_FETCH_RW:
16884 exit_opline = (trace->opline == opline + 1) ?
16885 ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
16886 opline + 1;
16887 break;
16888
16889 }
16890 }
16891
16892 switch (opline->opcode) {
16893 case ZEND_FE_FETCH_R:
16894 case ZEND_FE_FETCH_RW:
16895 if (opline->op2_type != IS_UNUSED) {
16896 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
16897 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
16898 }
16899 break;
16901 if (opline->op1_type == IS_CV) {
16902 old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
16903 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
16904 }
16905 break;
16906 }
16907 if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
16908 old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
16909 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
16910 }
16911 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
16912 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16913
16914 if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
16915 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
16916 }
16917 switch (opline->opcode) {
16918 case ZEND_FE_FETCH_R:
16919 case ZEND_FE_FETCH_RW:
16920 if (opline->op2_type != IS_UNUSED) {
16921 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
16922 }
16923 break;
16925 if (opline->op1_type == IS_CV) {
16926 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
16927 }
16928 break;
16929 }
16930
16931 if (!exit_addr) {
16932 return 0;
16933 }
16934 ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
16935 }
16936 }
16937
16938 zend_jit_set_last_valid_opline(jit, trace->opline);
16939
16940 return 1;
16941}
16942
16943static int zend_jit_deoptimizer_start(zend_jit_ctx *jit,
16945 uint32_t trace_num,
16946 uint32_t exit_num)
16947{
16948 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
16949
16950 jit->ctx.spill_base = ZREG_FP;
16951
16952 jit->op_array = NULL;
16953 jit->ssa = NULL;
16954 jit->name = zend_string_copy(name);
16955
16956 jit->ctx.flags |= IR_SKIP_PROLOGUE;
16957
16958 return 1;
16959}
16960
16961static int zend_jit_trace_start(zend_jit_ctx *jit,
16962 const zend_op_array *op_array,
16963 zend_ssa *ssa,
16965 uint32_t trace_num,
16966 zend_jit_trace_info *parent,
16967 uint32_t exit_num)
16968{
16969 zend_jit_init_ctx(jit, (zend_jit_vm_kind == ZEND_VM_KIND_CALL) ? 0 : IR_START_BR_TARGET);
16970
16971 jit->ctx.spill_base = ZREG_FP;
16972
16973 jit->op_array = NULL;
16974 jit->current_op_array = op_array;
16975 jit->ssa = ssa;
16976 jit->name = zend_string_copy(name);
16977
16978 if (!GCC_GLOBAL_REGS) {
16979 if (!parent) {
16980 ir_ref ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16981 jit_STORE_FP(jit, ref);
16982 jit->ctx.flags |= IR_FASTCALL_FUNC;
16983 }
16984 }
16985
16986 if (parent) {
16987 jit->ctx.flags |= IR_SKIP_PROLOGUE;
16988 }
16989
16990 if (parent) {
16991 int i;
16992 int parent_vars_count = parent->exit_info[exit_num].stack_size;
16993 zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
16994 parent->stack_map +
16995 parent->exit_info[exit_num].stack_offset;
16996
16997 /* prevent clobbering of registers used for deoptimization */
16998 for (i = 0; i < parent_vars_count; i++) {
16999 if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
17000 && STACK_REG(parent_stack, i) != ZREG_NONE) {
17001 int32_t reg = STACK_REG(parent_stack, i);
17002 ir_type type;
17003
17004 if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
17005 type = IR_ADDR;
17006 } else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
17007 type = IR_LONG;
17008 } else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
17009 type = IR_DOUBLE;
17010 } else {
17012 }
17013 if (ssa && ssa->vars[i].no_val) {
17014 /* pass */
17015 } else {
17016 ir_ref ref = ir_RLOAD(type, reg);
17017
17018 if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
17019 /* op3 is used as a flag that the value is already stored in memory.
17020 * In case the IR framework decides to spill the result of IR_LOAD,
17021 * it doesn't have to store the value once again.
17022 *
17023 * See: insn->op3 check in ir_emit_rload()
17024 */
17025 ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
17026 }
17027 }
17028 }
17029 }
17030 }
17031
17032 if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
17033 ZEND_ASSERT(parent->exit_info[exit_num].poly_func.reg >= 0 && parent->exit_info[exit_num].poly_this.reg >= 0);
17034 if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_func.reg)) {
17035 ir_RLOAD_A(parent->exit_info[exit_num].poly_func.reg);
17036 }
17037 if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_this.reg)) {
17038 ir_RLOAD_A(parent->exit_info[exit_num].poly_this.reg);
17039 }
17040 }
17041
17042 ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
17043
17044 return 1;
17045}
17046
17047static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
17048{
17049 return ir_LOOP_BEGIN(ir_END());
17050}
17051
17052static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
17053{
17054 int dst_var = phi->ssa_var;
17055 int src_var = phi->sources[0];
17056 ir_ref ref;
17057
17058 ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
17059 ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
17060
17061 ref = ir_PHI_2(
17062 (jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
17063 zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
17064
17065 src_var = phi->sources[1];
17066 ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
17067 jit->ra[src_var].flags |= ZREG_FORWARD;
17068
17069 zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
17070}
17071
17072static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
17073{
17074 if (timeout_exit_addr) {
17075 zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17076 }
17077 ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
17078 ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
17079 return 1;
17080}
17081
17082static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
17083{
17084 if (GCC_GLOBAL_REGS) {
17085 if (!original_handler) {
17086 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
17087 } else {
17088 ir_TAILCALL(IR_VOID, zend_jit_orig_opline_handler(jit));
17089 }
17090 } else {
17091 if (original_handler) {
17092 ir_ref ref;
17093 ir_ref addr = zend_jit_orig_opline_handler(jit);
17094
17095#if defined(IR_TARGET_X86)
17097#endif
17098 ref = ir_CALL_1(IR_I32, addr, jit_FP(jit));
17099 if (opline &&
17100 (opline->opcode == ZEND_RETURN
17101 || opline->opcode == ZEND_RETURN_BY_REF
17102 || opline->opcode == ZEND_GENERATOR_RETURN
17103 || opline->opcode == ZEND_GENERATOR_CREATE
17104 || opline->opcode == ZEND_YIELD
17105 || opline->opcode == ZEND_YIELD_FROM)) {
17106 ir_RETURN(ref);
17107 return 1;
17108 }
17109 }
17110 ir_RETURN(ir_CONST_I32(2)); // ZEND_VM_LEAVE
17111 }
17112 return 1;
17113}
17114
17115static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr)
17116{
17117 return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
17118}
17119
17120static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
17121{
17122 const void *link_addr;
17123
17124 /* Skip prologue. */
17125 ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
17126 link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
17127
17128 if (timeout_exit_addr) {
17129 zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17130 }
17131 ir_IJMP(ir_CONST_ADDR(link_addr));
17132
17133 return 1;
17134}
17135
17136static 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)
17137{
17138 uint32_t op1_info, op2_info;
17139
17140 switch (opline->opcode) {
17141 case ZEND_SEND_VAR:
17142 case ZEND_SEND_VAL:
17143 case ZEND_SEND_VAL_EX:
17144 return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
17145 case ZEND_QM_ASSIGN:
17146 case ZEND_IS_SMALLER:
17148 case ZEND_IS_EQUAL:
17149 case ZEND_IS_NOT_EQUAL:
17150 case ZEND_IS_IDENTICAL:
17152 case ZEND_CASE:
17153 return 1;
17154 case ZEND_RETURN:
17155 return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
17156 case ZEND_ASSIGN:
17157 return (opline->op1_type == IS_CV);
17158 case ZEND_ASSIGN_OP:
17159 if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
17160 return 0;
17161 }
17162 op1_info = OP1_INFO();
17163 op2_info = OP2_INFO();
17164 return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
17165 case ZEND_ADD:
17166 case ZEND_SUB:
17167 case ZEND_MUL:
17168 op1_info = OP1_INFO();
17169 op2_info = OP2_INFO();
17170 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
17171 return 0;
17172 }
17173 if (trace && trace->op1_type != IS_UNKNOWN) {
17174 op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17175 }
17176 if (trace && trace->op2_type != IS_UNKNOWN) {
17177 op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17178 }
17179 return !(op1_info & MAY_BE_UNDEF)
17180 && !(op2_info & MAY_BE_UNDEF)
17181 && (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
17182 && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
17183 case ZEND_BW_OR:
17184 case ZEND_BW_AND:
17185 case ZEND_BW_XOR:
17186 case ZEND_SL:
17187 case ZEND_SR:
17188 case ZEND_MOD:
17189 op1_info = OP1_INFO();
17190 op2_info = OP2_INFO();
17191 if (trace && trace->op1_type != IS_UNKNOWN) {
17192 op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17193 }
17194 if (trace && trace->op2_type != IS_UNKNOWN) {
17195 op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17196 }
17197 return (op1_info & MAY_BE_LONG)
17198 && (op2_info & MAY_BE_LONG);
17199 case ZEND_PRE_INC:
17200 case ZEND_PRE_DEC:
17201 case ZEND_POST_INC:
17202 case ZEND_POST_DEC:
17203 op1_info = OP1_INFO();
17204 return opline->op1_type == IS_CV
17205 && (op1_info & MAY_BE_LONG)
17206 && !(op1_info & MAY_BE_REF);
17207 case ZEND_STRLEN:
17208 op1_info = OP1_INFO();
17209 return (opline->op1_type & (IS_CV|IS_CONST))
17210 && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
17211 case ZEND_COUNT:
17212 op1_info = OP1_INFO();
17213 return (opline->op1_type & (IS_CV|IS_CONST))
17214 && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
17215 case ZEND_JMPZ:
17216 case ZEND_JMPNZ:
17217 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17218 if (!ssa->cfg.map) {
17219 return 0;
17220 }
17221 if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
17222 ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
17223 return 0;
17224 }
17225 }
17227 case ZEND_BOOL:
17228 case ZEND_BOOL_NOT:
17229 case ZEND_JMPZ_EX:
17230 case ZEND_JMPNZ_EX:
17231 return 1;
17233 return 1;
17235 if ((opline->extended_value & ZEND_ISEMPTY)) {
17236 return 0;
17237 }
17239 case ZEND_FETCH_DIM_R:
17240 case ZEND_FETCH_DIM_IS:
17241 case ZEND_FETCH_LIST_R:
17242 op1_info = OP1_INFO();
17243 op2_info = OP2_INFO();
17244 if (trace
17245 && trace->op1_type != IS_UNKNOWN
17246 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17247 op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17248 }
17249 return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17250 (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17251 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17252 case ZEND_ASSIGN_DIM_OP:
17253 if (opline->result_type != IS_UNUSED) {
17254 return 0;
17255 }
17256 if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17257 return 0;
17258 }
17260 case ZEND_ASSIGN_DIM:
17261 case ZEND_FETCH_DIM_W:
17262 case ZEND_FETCH_DIM_RW:
17263 case ZEND_FETCH_LIST_W:
17264 op1_info = OP1_INFO();
17265 op2_info = OP2_INFO();
17266 if (trace) {
17267 if (opline->op1_type == IS_CV) {
17268 if ((opline->opcode == ZEND_ASSIGN_DIM
17269 || opline->opcode == ZEND_ASSIGN_DIM_OP)
17270 && (opline+1)->op1_type == IS_CV
17271 && (opline+1)->op1.var == opline->op1.var) {
17272 /* skip $a[x] = $a; */
17273 return 0;
17274 }
17275 } else if (opline->op1_type == IS_VAR) {
17276 if (trace->op1_type == IS_UNKNOWN
17277 || !(trace->op1_type & IS_TRACE_INDIRECT)
17278 || opline->result_type != IS_UNUSED) {
17279 return 0;
17280 }
17281 }
17282 if (trace->op1_type != IS_UNKNOWN
17283 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17284 op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17285 }
17286 } else {
17287 if (opline->op1_type != IS_CV) {
17288 return 0;
17289 }
17290 }
17291 return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17292 (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17293 ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17294 case ZEND_ASSIGN_OBJ_OP:
17295 if (opline->result_type != IS_UNUSED) {
17296 return 0;
17297 }
17298 if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17299 return 0;
17300 }
17302 case ZEND_FETCH_OBJ_R:
17303 case ZEND_ASSIGN_OBJ:
17304 if (opline->op2_type != IS_CONST
17305 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
17306 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
17307 return 0;
17308 }
17309 op1_info = OP1_INFO();
17310 return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
17311 }
17312 return 0;
17313}
17314
17315static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
17316{
17317 if (ssa->vars[var].no_val) {
17318 /* we don't need the value */
17319 return 0;
17320 }
17321
17322 if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
17323 /* Disable global register allocation,
17324 * register allocation for SSA variables connected through Phi functions
17325 */
17326 if (ssa->vars[var].definition_phi) {
17327 return 0;
17328 }
17329 if (ssa->vars[var].phi_use_chain) {
17330 zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
17331 do {
17332 if (!ssa->vars[phi->ssa_var].no_val) {
17333 return 0;
17334 }
17335 phi = zend_ssa_next_use_phi(ssa, var, phi);
17336 } while (phi);
17337 }
17338 }
17339
17340 if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
17342 /* bad type */
17343 return 0;
17344 }
17345
17346 return 1;
17347}
17348
17349static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17350{
17351 if (!zend_jit_var_supports_reg(ssa, var)) {
17352 return 0;
17353 }
17354
17355 if (ssa->vars[var].definition >= 0) {
17356 uint32_t def = ssa->vars[var].definition;
17357 if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17358 return 0;
17359 }
17360 }
17361
17362 if (ssa->vars[var].use_chain >= 0) {
17363 int use = ssa->vars[var].use_chain;
17364
17365 do {
17366 if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17367 !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17368 return 0;
17369 }
17370 use = zend_ssa_next_use(ssa->ops, var, use);
17371 } while (use >= 0);
17372 }
17373
17374 if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17375 int def_block, use_block, b, use, j;
17376 zend_basic_block *bb;
17377 zend_ssa_phi *p;
17378 bool ret = 1;
17379 zend_worklist worklist;
17380 ALLOCA_FLAG(use_heap)
17381
17382 /* Check if live range is split by ENTRY block */
17383 if (ssa->vars[var].definition >= 0) {
17384 def_block =ssa->cfg.map[ssa->vars[var].definition];
17385 } else {
17386 ZEND_ASSERT(ssa->vars[var].definition_phi);
17387 def_block = ssa->vars[var].definition_phi->block;
17388 }
17389
17390 ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
17391
17392 if (ssa->vars[var].use_chain >= 0) {
17393 use = ssa->vars[var].use_chain;
17394 do {
17395 use_block = ssa->cfg.map[use];
17396 if (use_block != def_block) {
17397 zend_worklist_push(&worklist, use_block);
17398 }
17399 use = zend_ssa_next_use(ssa->ops, var, use);
17400 } while (use >= 0);
17401 }
17402
17403 p = ssa->vars[var].phi_use_chain;
17404 while (p) {
17405 use_block = p->block;
17406 if (use_block != def_block) {
17407 bb = &ssa->cfg.blocks[use_block];
17408 for (j = 0; j < bb->predecessors_count; j++) {
17409 if (p->sources[j] == var) {
17410 use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
17411 if (use_block != def_block) {
17412 zend_worklist_push(&worklist, use_block);
17413 }
17414 }
17415 }
17416 }
17417 p = zend_ssa_next_use_phi(ssa, var, p);
17418 }
17419
17420 while (zend_worklist_len(&worklist) != 0) {
17421 b = zend_worklist_pop(&worklist);
17422 bb = &ssa->cfg.blocks[b];
17424 ret = 0;
17425 break;
17426 }
17427 for (j = 0; j < bb->predecessors_count; j++) {
17428 b = ssa->cfg.predecessors[bb->predecessor_offset + j];
17429 if (b != def_block) {
17430 zend_worklist_push(&worklist, b);
17431 }
17432 }
17433 }
17434
17435 ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
17436
17437 return ret;
17438 }
17439
17440 return 1;
17441}
17442
17443static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
17444 // JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
17445 ir_ref observer_handler;
17446 zend_function *fbc = ZEND_FLF_FUNC(opline);
17447 // Not need for runtime cache or generator checks here, we just need if_unobserved
17448 ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17449
17450 // Call zend_frameless_observed_call for the main logic.
17452
17453 ir_ref skip = ir_END();
17455 return skip;
17456}
17457
17458static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
17459{
17460 jit_SET_EX_OPLINE(jit, opline);
17461
17462 void *function = ZEND_FLF_HANDLER(opline);
17463 zend_jit_addr res_addr = RES_ADDR();
17464 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17465 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17466
17467 ir_ref skip_observer = IR_UNUSED;
17469 skip_observer = jit_frameless_observer(jit, opline);
17470 }
17471
17472 ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17473
17474 if (skip_observer != IR_UNUSED) {
17475 ir_MERGE_WITH(skip_observer);
17476 }
17477
17478 zend_jit_check_exception(jit);
17479}
17480
17481static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
17482{
17483 jit_SET_EX_OPLINE(jit, opline);
17484
17485 /* Avoid dropping RC check in case op escapes. */
17486 if (op1_info & MAY_BE_RC1) {
17487 op1_info |= MAY_BE_RCN;
17488 }
17489
17490 void *function = ZEND_FLF_HANDLER(opline);
17491 zend_jit_addr res_addr = RES_ADDR();
17492 zend_jit_addr op1_addr = OP1_ADDR();
17493 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17494 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17495 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17496 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17497 op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17498 op1_info &= ~MAY_BE_UNDEF;
17499 op1_info |= MAY_BE_NULL;
17500 op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17501 }
17502 if (op1_info & MAY_BE_REF) {
17503 op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17504 }
17505
17506 ir_ref skip_observer = IR_UNUSED;
17508 skip_observer = jit_frameless_observer(jit, opline);
17509 }
17510
17511 ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17512
17513 if (skip_observer != IR_UNUSED) {
17514 ir_MERGE_WITH(skip_observer);
17515 }
17516
17517 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17518 zend_jit_check_exception(jit);
17519}
17520
17521static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
17522{
17523 jit_SET_EX_OPLINE(jit, opline);
17524
17525 /* Avoid dropping RC check in case op escapes. */
17526 if (op1_info & MAY_BE_RC1) {
17527 op1_info |= MAY_BE_RCN;
17528 }
17529 if (op2_info & MAY_BE_RC1) {
17530 op2_info |= MAY_BE_RCN;
17531 }
17532
17533 void *function = ZEND_FLF_HANDLER(opline);
17534 zend_jit_addr res_addr = RES_ADDR();
17535 zend_jit_addr op1_addr = OP1_ADDR();
17536 zend_jit_addr op2_addr = OP2_ADDR();
17537 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17538 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17539 ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17540 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17541 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17542 op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17543 op1_info &= ~MAY_BE_UNDEF;
17544 op1_info |= MAY_BE_NULL;
17545 op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17546 }
17547 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17548 op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17549 op2_info &= ~MAY_BE_UNDEF;
17550 op2_info |= MAY_BE_NULL;
17551 op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17552 }
17553 if (op1_info & MAY_BE_REF) {
17554 op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17555 }
17556 if (op2_info & MAY_BE_REF) {
17557 op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17558 }
17559
17560 ir_ref skip_observer = IR_UNUSED;
17562 skip_observer = jit_frameless_observer(jit, opline);
17563 }
17564
17565 ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17566
17567 if (skip_observer != IR_UNUSED) {
17568 ir_MERGE_WITH(skip_observer);
17569 }
17570
17571 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17572 /* Set OP1 to UNDEF in case FREE_OP2() throws. */
17573 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0
17574 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17575 && (op2_info & MAY_BE_RC1)
17577 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17578 if (JIT_G(current_frame)) {
17579 SET_STACK_TYPE(JIT_G(current_frame)->stack,
17580 EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
17581 }
17582 }
17583 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17584 zend_jit_check_exception(jit);
17585}
17586
17587static 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)
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 if (op2_info & MAY_BE_RC1) {
17596 op2_info |= MAY_BE_RCN;
17597 }
17598 if (op1_data_info & MAY_BE_RC1) {
17599 op1_data_info |= MAY_BE_RCN;
17600 }
17601
17602 void *function = ZEND_FLF_HANDLER(opline);
17603 uint8_t op_data_type = (opline + 1)->op1_type;
17604 zend_jit_addr res_addr = RES_ADDR();
17605 zend_jit_addr op1_addr = OP1_ADDR();
17606 zend_jit_addr op2_addr = OP2_ADDR();
17607 zend_jit_addr op3_addr = OP1_DATA_ADDR();
17608 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17609 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17610 ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17611 ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
17612 jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17613 if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17614 op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17615 op1_info &= ~MAY_BE_UNDEF;
17616 op1_info |= MAY_BE_NULL;
17617 op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17618 }
17619 if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17620 op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17621 op2_info &= ~MAY_BE_UNDEF;
17622 op2_info |= MAY_BE_NULL;
17623 op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17624 }
17625 if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
17626 op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17627 op1_data_info &= ~MAY_BE_UNDEF;
17628 op1_data_info |= MAY_BE_NULL;
17629 op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
17630 }
17631 if (op1_info & MAY_BE_REF) {
17632 op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17633 }
17634 if (op2_info & MAY_BE_REF) {
17635 op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17636 }
17637 if (op1_data_info & MAY_BE_REF) {
17638 op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
17639 }
17640
17641 ir_ref skip_observer = IR_UNUSED;
17643 skip_observer = jit_frameless_observer(jit, opline);
17644 }
17645
17646 ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17647
17648 if (skip_observer != IR_UNUSED) {
17649 ir_MERGE_WITH(skip_observer);
17650 }
17651
17652 jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17653 /* Set OP1 to UNDEF in case FREE_OP2() throws. */
17654 bool op1_undef = false;
17655 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
17656 && (((opline->op2_type & (IS_VAR|IS_TMP_VAR))
17657 && (op2_info & MAY_BE_RC1)
17659 || ((op_data_type & (IS_VAR|IS_TMP_VAR))
17660 && (op1_data_info & MAY_BE_RC1)
17662 op1_undef = true;
17663 jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
17664 if (JIT_G(current_frame)) {
17665 SET_STACK_TYPE(JIT_G(current_frame)->stack,
17666 EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
17667 }
17668 }
17669 jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17670 /* If OP1 is set to UNDEF, we don't need to set OP2 to UNDEF on free because
17671 * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
17672 if (!op1_undef
17673 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17674 && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0
17675 && (op1_data_info & MAY_BE_RC1)
17677 jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
17678 if (JIT_G(current_frame)) {
17679 SET_STACK_TYPE(JIT_G(current_frame)->stack,
17680 EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
17681 }
17682 }
17683 jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
17684 zend_jit_check_exception(jit);
17685}
17686
17687/*
17688 * Local variables:
17689 * tab-width: 4
17690 * c-basic-offset: 4
17691 * indent-tabs-mode: t
17692 * End:
17693 */
size_t len
Definition apprentice.c:174
bool exception
Definition assert.c:30
sizeof(Countable|array $value, int $mode=COUNT_NORMAL)
fprintf($stream, string $format, mixed ... $values)
array_values(array $array)
prev(array|object &$array)
header(string $header, bool $replace=true, int $response_code=0)
count(Countable|array $value, int $mode=COUNT_NORMAL)
strstr(string $haystack, string $needle, bool $before_needle=false)
uint32_t u
Definition cdf.c:78
int begin
Definition eaw_table.h:20
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
void * ptr2
Definition ffi.c:4449
void * ptr
Definition ffi.c:3814
memcpy(ptr1, ptr2, size)
zend_ffi_type * type2
Definition ffi.c:4448
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
zend_long offset
#define NULL
Definition gdcache.h:45
again j
ir_ref ir_binding_find(const ir_ctx *ctx, ir_ref ref)
Definition ir.c:1161
void ir_free(ir_ctx *ctx)
Definition ir.c:412
ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def)
Definition ir.c:1142
ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2)
Definition ir.c:834
void ir_build_def_use_lists(ir_ctx *ctx)
Definition ir.c:1224
ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1)
Definition ir.c:829
ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count)
Definition ir.c:1077
ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t addr)
Definition ir.c:472
void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val)
Definition ir.c:1098
void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit)
Definition ir.c:381
ir_ref ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2)
Definition ir.c:742
ir_ref ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type)
Definition ir.c:721
int ir_disasm_init(void)
Definition ir_disasm.c:850
#define IR_REG_SPILLED(r)
Definition ir.h:790
#define IR_USE_FRAME_POINTER
Definition ir.h:522
#define IR_OPT_CODEGEN
Definition ir.h:534
#define IR_OPT_CFG
Definition ir.h:532
#define IR_START_BR_TARGET
Definition ir.h:525
enum _ir_type ir_type
int ir_match(ir_ctx *ctx)
Definition ir_emit.c:964
#define IR_TRUE
Definition ir.h:398
#define IR_NO_STACK_COMBINE
Definition ir.h:524
bool ir_reg_is_int(int32_t reg)
Definition ir_ra.c:35
int ir_coalesce(ir_ctx *ctx)
Definition ir_ra.c:1856
int ir_assign_virtual_registers(ir_ctx *ctx)
Definition ir_ra.c:82
#define IR_GEN_ENDBR
Definition ir.h:527
#define IR_FUNCTION
Definition ir.h:510
#define IR_GEN_CACHE_DEMOTE
Definition ir.h:538
#define IR_OPT_FOLDING
Definition ir.h:531
int ir_schedule_blocks(ir_ctx *ctx)
Definition ir_cfg.c:1833
#define IR_ENTRY_BR_TARGET
Definition ir.h:526
void ir_disasm_free(void)
Definition ir_disasm.c:858
int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref)
Definition ir_emit.c:1040
#define IR_UNUSED
Definition ir.h:395
int ir_find_loops(ir_ctx *ctx)
Definition ir_cfg.c:911
int ir_disasm(const char *name, const void *start, size_t size, bool asm_addr, ir_ctx *ctx, FILE *f)
Definition ir_disasm.c:326
const void * ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_per_group, const void *exit_addr, ir_code_buffer *code_buffer, size_t *size_ptr)
int ir_gdb_register(const char *name, const void *start, size_t size, uint32_t sp_offset, uint32_t sp_adjustment)
Definition ir_gdb.c:631
#define IR_VARARG_FUNC
Definition ir.h:512
@ IR_VOID
Definition ir.h:151
#define IR_NULL
Definition ir.h:396
#define IR_SAVE_REGS
Definition ir.h:879
void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f)
Definition ir_dump.c:337
int ir_build_dominators_tree(ir_ctx *ctx)
Definition ir_cfg.c:672
int32_t ir_ref
Definition ir.h:390
int ir_build_cfg(ir_ctx *ctx)
Definition ir_cfg.c:80
IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n)
Definition ir.h:727
void ir_disasm_add_symbol(const char *name, uint64_t addr, uint64_t size)
Definition ir_disasm.c:85
#define IR_OPT(op, type)
Definition ir.h:385
#define IR_IS_CONST_REF(ref)
Definition ir.h:392
void * ir_emit_code(ir_ctx *ctx, size_t *size)
int ir_perf_jitdump_register(const char *name, const void *start, size_t size)
Definition ir_perf.c:205
const char * ir_disasm_find_symbol(uint64_t addr, int64_t *offset)
Definition ir_disasm.c:189
#define IR_SAVE_CFG
Definition ir.h:875
IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
Definition ir.h:733
#define IR_FASTCALL_FUNC
Definition ir.h:511
int ir_compute_live_ranges(ir_ctx *ctx)
Definition ir_ra.c:1239
#define IR_SAVE_RULES
Definition ir.h:878
int ir_gcm(ir_ctx *ctx)
Definition ir_gcm.c:564
bool ir_check(const ir_ctx *ctx)
Definition ir_check.c:89
int ir_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr)
Definition ir_patch.c:251
void(* ir_snapshot_create_t)(ir_ctx *ctx, ir_ref addr)
Definition ir.h:559
#define IR_FALSE
Definition ir.h:397
struct _ir_code_buffer ir_code_buffer
#define IR_SKIP_PROLOGUE
Definition ir.h:521
#define IR_REG_SPILL_LOAD
Definition ir.h:787
int ir_perf_jitdump_open(void)
Definition ir_perf.c:101
const char * ir_reg_name(int8_t reg, ir_type type)
#define IR_REG_SPILL_SPECIAL
Definition ir.h:789
void ir_gdb_unregister_all(void)
Definition ir_gdb.c:547
#define IR_REG_NUM(r)
Definition ir.h:792
int ir_sccp(ir_ctx *ctx)
Definition ir_sccp.c:3638
int ir_perf_jitdump_close(void)
Definition ir_perf.c:183
int ir_reg_alloc(ir_ctx *ctx)
Definition ir_ra.c:4111
#define IR_SAVE_CFG_MAP
Definition ir.h:876
struct _ir_ctx ir_ctx
Definition ir.h:550
void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f)
Definition ir_save.c:89
enum _ir_op ir_op
int ir_schedule(ir_ctx *ctx)
Definition ir_gcm.c:788
void ir_dump_codegen(const ir_ctx *ctx, FILE *f)
Definition ir_dump.c:478
void ir_perf_map_register(const char *name, const void *start, size_t size)
Definition ir_perf.c:252
struct _ir_insn ir_insn
#define IR_MERGE_EMPTY_ENTRIES
Definition ir.h:528
#define IR_REGSET_PRESERVED
Definition ir_aarch64.h:157
#define IR_SHADOW_ARGS
Definition ir_aarch64.h:150
#define ir_RLOAD_U32(_reg)
Definition ir_builder.h:551
#define ir_INT2D(_op1)
Definition ir_builder.h:216
#define ir_CONST_DOUBLE(_val)
Definition ir_builder.h:31
#define ir_LOAD_U8(_addr)
Definition ir_builder.h:564
#define ir_ULE(_op1, _op2)
Definition ir_builder.h:76
#define ir_CASE_DEFAULT(_switch)
Definition ir_builder.h:606
#define ir_END_PHI_list(_list, _val)
Definition ir_builder.h:622
#define ir_MIN_U32(_op1, _op2)
Definition ir_builder.h:431
#define ir_END()
Definition ir_builder.h:598
#define ir_IF_TRUE(_if)
Definition ir_builder.h:594
#define ir_AFREE(_size)
Definition ir_builder.h:530
#define ir_SUB_I16(_op1, _op2)
Definition ir_builder.h:101
#define ir_IF(_condition)
Definition ir_builder.h:593
#define ir_LE(_op1, _op2)
Definition ir_builder.h:71
#define ir_PHI_N(type, _n, _inputs)
Definition ir_builder.h:471
#define ir_TAILCALL(type, func)
Definition ir_builder.h:520
#define ir_CONST_U8(_val)
Definition ir_builder.h:21
#define ir_TRUNC_U32(_op1)
Definition ir_builder.h:192
#define ir_LOAD_U32(_addr)
Definition ir_builder.h:566
#define ir_MERGE_WITH(_src2)
Definition ir_builder.h:625
#define ir_MERGE_2(_src1, _src2)
Definition ir_builder.h:599
#define ir_ALLOCA(_size)
Definition ir_builder.h:529
#define ir_SEXT_A(_op1)
Definition ir_builder.h:170
#define ir_LOOP_BEGIN(_src1)
Definition ir_builder.h:602
#define ir_CALL(type, func)
Definition ir_builder.h:511
#define ir_SWITCH(_val)
Definition ir_builder.h:604
#define ir_PHI_2(type, _src1, _src2)
Definition ir_builder.h:470
#define ir_UGE(_op1, _op2)
Definition ir_builder.h:75
#define ir_MERGE_WITH_EMPTY_FALSE(_if)
Definition ir_builder.h:627
#define ir_UGT(_op1, _op2)
Definition ir_builder.h:77
#define ir_MERGE_SET_OP(_ref, _pos, _src)
Definition ir_builder.h:601
#define ir_LOOP_END()
Definition ir_builder.h:603
#define ir_END_list(_list)
Definition ir_builder.h:619
#define ir_SHL_U32(_op1, _op2)
Definition ir_builder.h:326
#define ir_OR_U32(_op1, _op2)
Definition ir_builder.h:288
#define ir_RSTORE(_reg, _val)
Definition ir_builder.h:561
#define ir_GUARD(_condition, _addr)
Definition ir_builder.h:611
#define ir_IF_FALSE_cold(_if)
Definition ir_builder.h:597
#define ir_BEGIN(_src)
Definition ir_builder.h:592
#define ir_ENTRY(_src, _num)
Definition ir_builder.h:591
#define ir_STORE(_addr, _val)
Definition ir_builder.h:576
#define ir_SUB_A(_op1, _op2)
Definition ir_builder.h:98
#define ir_MERGE_WITH_EMPTY_TRUE(_if)
Definition ir_builder.h:626
#define ir_IJMP(_addr)
Definition ir_builder.h:608
#define ir_MUL_A(_op1, _op2)
Definition ir_builder.h:112
#define ir_EQ(_op1, _op2)
Definition ir_builder.h:66
#define ir_AND_A(_op1, _op2)
Definition ir_builder.h:303
#define ir_MERGE_N(_n, _inputs)
Definition ir_builder.h:600
#define ir_AND_U32(_op1, _op2)
Definition ir_builder.h:301
#define ir_CALL_4(type, func, a1, a2, a3, a4)
Definition ir_builder.h:515
#define ir_BINARY_OP_D(_op, _op1, _op2)
Definition ir_builder.h:63
#define ir_EXITCALL(_func)
Definition ir_builder.h:617
#define ir_LOAD(_type, _addr)
Definition ir_builder.h:562
#define ir_ADD_A(_op1, _op2)
Definition ir_builder.h:84
#define ir_TAILCALL_1(type, func, a1)
Definition ir_builder.h:521
#define ir_SHR_A(_op1, _op2)
Definition ir_builder.h:340
#define ir_GT(_op1, _op2)
Definition ir_builder.h:72
#define ir_ULT(_op1, _op2)
Definition ir_builder.h:74
#define ir_TAILCALL_2(type, func, a1, a2)
Definition ir_builder.h:522
#define ir_CALL_1(type, func, a1)
Definition ir_builder.h:512
#define ir_CONST_I16(_val)
Definition ir_builder.h:28
#define ir_SUB_U32(_op1, _op2)
Definition ir_builder.h:96
#define ir_LOAD_D(_addr)
Definition ir_builder.h:574
#define ir_IF_FALSE(_if)
Definition ir_builder.h:596
#define ir_IF_TRUE_cold(_if)
Definition ir_builder.h:595
#define ir_MUL_U32(_op1, _op2)
Definition ir_builder.h:110
#define ir_CALL_2(type, func, a1, a2)
Definition ir_builder.h:513
#define ir_PHI_SET_OP(_ref, _pos, _src)
Definition ir_builder.h:472
#define ir_SNAPSHOT_SET_OP(_s, _pos, _v)
Definition ir_builder.h:615
#define ir_OVERFLOW(_op1)
Definition ir_builder.h:269
#define ir_HARD_COPY_A(_op1)
Definition ir_builder.h:499
#define ir_CONST_U32(_val)
Definition ir_builder.h:23
#define ir_CONST_CHAR(_val)
Definition ir_builder.h:26
#define ir_ADD_U32(_op1, _op2)
Definition ir_builder.h:82
#define ir_UNREACHABLE()
Definition ir_builder.h:609
#define ir_PHI_list(_list)
Definition ir_builder.h:623
#define ir_ZEXT_A(_op1)
Definition ir_builder.h:182
#define ir_GE(_op1, _op2)
Definition ir_builder.h:70
#define ir_TLS(_index, _offset)
Definition ir_builder.h:577
#define ir_PARAM(_type, _name, _num)
Definition ir_builder.h:508
#define ir_LOAD_A(_addr)
Definition ir_builder.h:568
#define ir_GUARD_NOT(_condition, _addr)
Definition ir_builder.h:612
#define ir_AND_U8(_op1, _op2)
Definition ir_builder.h:299
#define ir_CASE_VAL(_switch, _val)
Definition ir_builder.h:605
#define ir_ZEXT_U32(_op1)
Definition ir_builder.h:180
#define ir_MERGE_list(_list)
Definition ir_builder.h:620
#define ir_LOAD_C(_addr)
Definition ir_builder.h:569
#define ir_LT(_op1, _op2)
Definition ir_builder.h:69
#define ir_START()
Definition ir_builder.h:590
#define ir_NE(_op1, _op2)
Definition ir_builder.h:67
#define ir_RETURN(_val)
Definition ir_builder.h:607
#define ir_LOAD_I16(_addr)
Definition ir_builder.h:571
#define ir_CALL_3(type, func, a1, a2, a3)
Definition ir_builder.h:514
#define ir_CONST_I32(_val)
Definition ir_builder.h:29
#define ir_BITCAST_A(_op1)
Definition ir_builder.h:206
#define ir_RLOAD(_type, _reg)
Definition ir_builder.h:547
#define ir_SNAPSHOT(_n)
Definition ir_builder.h:614
#define ir_CALL_5(type, func, a1, a2, a3, a4, a5)
Definition ir_builder.h:516
#define ir_CONST_ADDR(_val)
Definition ir_builder.h:25
#define ir_RLOAD_A(_reg)
Definition ir_builder.h:553
#define ir_DIV_A(_op1, _op2)
Definition ir_builder.h:126
#define ir_CMP_OP(_op, _op1, _op2)
Definition ir_builder.h:34
char * debug
Definition mysqlnd.h:298
char * arena
Definition php_bcmath.h:37
HashTable types
Definition php_ffi.h:36
unsigned const char * end
Definition php_ffi.h:51
#define offsetof(STRUCTURE, FIELD)
#define UINT32_MAX
unsigned char key[REFLECTION_KEY_LEN]
zend_constant * data
original_stack top
p
Definition session.c:1105
void * end
Definition ir.h:569
void * pos
Definition ir.h:570
void * start
Definition ir.h:568
uint32_t mflags
Definition ir.h:582
int32_t fixed_stack_red_zone
Definition ir.h:601
ir_hashtab * binding
Definition ir.h:586
ir_ref control
Definition ir.h:617
uint32_t * entries
Definition ir.h:632
uint32_t entries_count
Definition ir.h:631
int32_t fixed_stack_frame_size
Definition ir.h:602
ir_ref fold_cse_limit
Definition ir.h:584
ir_snapshot_create_t snapshot_create
Definition ir.h:621
ir_code_buffer * code_buffer
Definition ir.h:634
int32_t status
Definition ir.h:583
ir_type ret_type
Definition ir.h:581
ir_regs * regs
Definition ir.h:612
uint64_t fixed_regset
Definition ir.h:600
ir_insn * ir_base
Definition ir.h:574
uint32_t flags
Definition ir.h:579
ir_ref insns_count
Definition ir.h:575
uint32_t flags2
Definition ir.h:580
uint64_t fixed_save_regset
Definition ir.h:604
int32_t fixed_call_stack_size
Definition ir.h:603
int32_t spill_base
Definition ir.h:599
ir_val val
Definition ir.h:477
uint32_t limit
ir_ref refs[] ZEND_ELEMENT_COUNT(count)
uint32_t count
Bucket * arData
Definition zend_types.h:403
zval * arPacked
Definition zend_types.h:404
uint32_t start
Definition zend_cfg.h:45
uint32_t flags
Definition zend_cfg.h:44
uint32_t flags
Definition zend_cfg.h:90
uint32_t * map
Definition zend_cfg.h:89
int blocks_count
Definition zend_cfg.h:85
int * predecessors
Definition zend_cfg.h:88
zend_basic_block * blocks
Definition zend_cfg.h:87
uint32_t ce_flags
Definition zend.h:156
zend_class_entry * called_scope
zend_object std
zend_function func
zif_handler orig_internal_handler
zend_call_info * callee_info
ir_ref trace_loop_ref
ir_ref * bb_predecessors
ir_ref poly_this_ref
const zend_op_array * op_array
zend_jit_trace_info * trace
zend_ssa * ssa
bool track_last_valid_opline
ir_ref eg_exception_addr
bool use_last_valid_opline
ir_ref * bb_start_ref
zend_jit_reg_var * ra
ir_ref poly_func_ref
ir_ref return_inputs
zend_string * name
const zend_op * last_valid_opline
ir_ref stub_addr[jit_last_stub]
const zend_op_array * current_op_array
uint32_t delayed_call_level
ir_refs * delay_refs
HashTable addr_hash
ir_ref * bb_edges
int(* stub)(zend_jit_ctx *jit)
const char * name
zend_jit_ref_snapshot poly_this
zend_jit_ref_snapshot poly_func
zend_jit_exit_const * constants
zend_jit_trace_exit_info * exit_info
zend_jit_trace_stack * stack_map
zend_string * filename
uint32_t required_num_args
zend_class_entry * scope
zend_arg_info * arg_info
uint32_t num_args
zend_op * opcodes
zend_string * function_name
uint32_t fn_flags
znode_op op1
uint8_t result_type
znode_op op2
znode_op result
uint8_t opcode
uint8_t op1_type
uint32_t extended_value
uint32_t lineno
const void * handler
uint8_t op2_type
int result_def
Definition zend_ssa.h:88
int * sources
Definition zend_ssa.h:73
zend_long max
Definition zend_ssa.h:27
zend_long min
Definition zend_ssa.h:26
zend_class_entry * ce
Definition zend_ssa.h:132
zend_ssa_phi * definition_phi
Definition zend_ssa.h:112
zend_ssa_phi * phi_use_chain
Definition zend_ssa.h:113
zend_ssa_var * vars
Definition zend_ssa.h:141
zend_cfg cfg
Definition zend_ssa.h:136
zend_ssa_var_info * var_info
Definition zend_ssa.h:142
zend_ssa_op * ops
Definition zend_ssa.h:140
char val[1]
Definition zend_types.h:377
Definition dce.c:49
$obj a
Definition test.php:84
int64_t i64
Definition ir.h:412
uint32_t var
uint32_t num
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API size_t zend_spprintf(char **message, size_t max_len, const char *format,...)
Definition zend.c:311
ZEND_API void(* zend_interrupt_function)(zend_execute_data *execute_data)
Definition zend.c:89
ZEND_API zend_write_func_t zend_write
Definition zend.c:85
ZEND_NORETURN void zend_accel_error_noreturn(int type, const char *format,...)
#define ACCEL_LOG_FATAL
ZEND_API void ZEND_FASTCALL _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
ZEND_API void *ZEND_FASTCALL _emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
#define ZEND_MM_ALIGNED_SIZE_EX(size, alignment)
Definition zend_alloc.h:37
#define efree(ptr)
Definition zend_alloc.h:155
#define erealloc(ptr, size)
Definition zend_alloc.h:159
struct _zval_struct zval
struct _zend_basic_block zend_basic_block
#define ZEND_BB_REACHABLE
Definition zend_cfg.h:38
#define ZEND_BB_ENTRY
Definition zend_cfg.h:27
#define RETURN_VALUE_USED(opline)
Definition zend_cfg.h:113
#define ZEND_BB_LOOP_HEADER
Definition zend_cfg.h:35
#define ZEND_BB_RECV_ENTRY
Definition zend_cfg.h:33
uint32_t num_args
ZEND_API zend_class_entry * zend_ce_closure
struct _zend_closure zend_closure
execute_data func
ZEND_API bool zend_is_smart_branch(const zend_op *opline)
#define BP_VAR_R
zend_result(ZEND_FASTCALL * binary_op_type)(zval *, zval *, zval *)
#define ZEND_CALL_CLOSURE
struct _zend_op zend_op
#define ZEND_USER_CODE(type)
#define ARG_MUST_BE_SENT_BY_REF(zf, arg_num)
#define IS_UNUSED
#define ZEND_ACC_FAKE_CLOSURE
#define ZEND_CALL_ALLOCATED
#define ZEND_ACC_IMMUTABLE
#define IS_CONST
#define ZEND_ACC_HAS_TYPE_HINTS
#define BP_VAR_W
#define ZEND_SEND_BY_REF
#define IS_SMART_BRANCH_JMPNZ
#define ZEND_INTERNAL_FUNCTION
#define EX_VAR_TO_NUM(n)
#define IS_VAR
#define ZEND_CALL_FRAME_SLOT
#define EX_NUM_TO_VAR(n)
#define ZEND_SEND_PREFER_REF
#define ZEND_ACC_TRAIT_CLONE
#define ZEND_CALL_TOP
#define ZEND_ACC_READONLY
#define IS_SMART_BRANCH_JMPZ
#define ZEND_EVAL_CODE
#define ZEND_ARG_SEND_MODE(arg_info)
#define ZEND_ACC_PPP_SET_MASK
ZEND_API binary_op_type get_binary_op(int opcode)
#define ZEND_CALL_NESTED_FUNCTION
#define ZEND_USER_FUNCTION
#define ZEND_CALL_HAS_SYMBOL_TABLE
#define ZEND_ACC_CALL_VIA_TRAMPOLINE
#define ZEND_ACC_GENERATOR
struct _zend_op_array zend_op_array
#define ZEND_CALL_HAS_THIS
union _znode_op znode_op
#define ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS
struct _zend_property_info zend_property_info
#define ZEND_CALL_HAS_EXTRA_NAMED_PARAMS
#define ZEND_ACC_TRAIT
#define ZEND_FETCH_REF
#define ZEND_FETCH_DIM_WRITE
#define ZEND_EXTRA_VALUE
#define RT_CONSTANT(opline, node)
#define ZEND_ACC_STATIC
#define MAX_ARG_FLAG_NUM
struct _zend_arg_info zend_arg_info
#define OP_JMP_ADDR(opline, node)
#define ZEND_CALL_DYNAMIC
#define ZEND_FETCH_OBJ_FLAGS
#define ZEND_CALL_SEND_ARG_BY_REF
#define ZEND_ACC_VARIADIC
#define ZEND_CALL_FREE_EXTRA_ARGS
#define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num)
#define ZEND_ISEMPTY
#define ZEND_CALL_MAY_HAVE_UNDEF
#define IS_CV
#define IS_TMP_VAR
#define BP_VAR_RW
struct _zend_internal_function zend_internal_function
#define ZEND_ACC_DEPRECATED
#define ZEND_CALL_RELEASE_THIS
void(ZEND_FASTCALL * zif_handler)(INTERNAL_FUNCTION_PARAMETERS)
#define ARG_MAY_BE_SENT_BY_REF(zf, arg_num)
#define ZEND_OFFSET_TO_OPLINE(base, offset)
#define BP_VAR_IS
#define ZEND_ACC_CLOSURE
#define BP_VAR_UNSET
#define ZEND_CALL_FAKE_CLOSURE
#define snprintf
ZEND_API zend_class_entry * zend_ce_arithmetic_error
ZEND_API zend_class_entry * zend_ce_division_by_zero_error
ZEND_API void ZEND_FASTCALL zend_free_extra_named_params(zend_array *extra_named_params)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info)
ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call)
ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *execute_data)
ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *prop_info, const char *operation)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num)
ZEND_API void(* zend_execute_internal)(zend_execute_data *execute_data, zval *return_value)
ZEND_API void execute_ex(zend_execute_data *execute_data)
ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *pp, zend_class_entry *scope)
ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void)
#define CACHE_SPECIAL
ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info)
union _zend_function zend_function
#define ZEND_FLF_HANDLER(opline)
#define ZEND_FLF_FUNC(opline)
ZEND_API int zend_func_info_rid
ZEND_API uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa, zend_class_entry **ce, bool *ce_is_instanceof)
#define ZEND_FUNC_RECURSIVE_DIRECTLY
struct _zend_call_info zend_call_info
#define ZEND_FUNC_INFO(op_array)
struct _zend_func_info zend_func_info
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
Definition zend_gc.c:698
#define CG(v)
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API HashTable *ZEND_FASTCALL _zend_new_array_0(void)
Definition zend_hash.c:282
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
Definition zend_hash.c:1224
ZEND_API zval *ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1234
ZEND_API zval *ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key)
Definition zend_hash.c:1012
ZEND_API zval *ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
Definition zend_hash.c:2679
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
Definition zend_hash.c:1808
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
ZEND_API zval *ZEND_FASTCALL _zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2722
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
Definition zend_hash.c:649
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define HT_IS_PACKED(ht)
Definition zend_hash.h:59
#define HASH_FLAG_PACKED
Definition zend_hash.h:41
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
ZEND_API uint32_t zend_array_element_type(uint32_t t1, uint8_t op_type, int write, int insert)
#define MAY_BE_PACKED_GUARD
#define OP1_INFO()
#define MAY_BE_GUARD
#define OP1_DATA_INFO()
#define RES_INFO()
#define OP2_INFO()
#define MAY_BE_CLASS_GUARD
#define MAY_HAVE_DTOR
#define ZEND_JIT_LEVEL_INLINE
Definition zend_jit.h:34
#define ZEND_JIT_DEBUG_PERF_DUMP
Definition zend_jit.h:60
struct _zend_jit_trace_rec zend_jit_trace_rec
Definition zend_jit.h:99
#define ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE
Definition zend_jit.h:83
#define ZEND_JIT_DEBUG_IR_AFTER_SCCP
Definition zend_jit.h:79
#define ZEND_JIT_CPU_AVX
Definition zend_jit.h:48
#define ZEND_JIT_DEBUG_ASM_ADDR
Definition zend_jit.h:65
#define ZEND_JIT_DEBUG_IR_FINAL
Definition zend_jit.h:78
#define ZREG_NONE
Definition zend_jit.h:187
#define ZREG_FORWARD
Definition zend_jit.h:177
#define ZEND_JIT_DEBUG_PERF
Definition zend_jit.h:59
#define ZREG_SPILL_SLOT
Definition zend_jit.h:179
#define ZEND_JIT_DEBUG_IR_AFTER_REGS
Definition zend_jit.h:84
#define ZEND_JIT_COUNTER_INIT
Definition zend_jit.h:52
#define ZEND_JIT_DEBUG_ASM_STUBS
Definition zend_jit.h:57
#define ZREG_ZVAL_COPY
Definition zend_jit.h:182
#define ZEND_JIT_ON_HOT_TRACE
Definition zend_jit.h:44
#define ZEND_JIT_DEBUG_IR_AFTER_GCM
Definition zend_jit.h:82
#define ZEND_JIT_DEBUG_GDB
Definition zend_jit.h:63
#define ZREG_LOAD
Definition zend_jit.h:171
#define ZEND_JIT_REG_ALLOC_GLOBAL
Definition zend_jit.h:47
#define ZEND_JIT_DEBUG_IR_AFTER_CFG
Definition zend_jit.h:80
#define ZREG_TYPE_ONLY
Definition zend_jit.h:183
#define ZEND_JIT_TRACE_MAX_EXITS
Definition zend_jit.h:90
#define ZREG_STORE
Definition zend_jit.h:172
#define JIT_G(v)
Definition zend_jit.h:151
#define ZEND_JIT_DEBUG_ASM
Definition zend_jit.h:54
#define ZEND_JIT_DEBUG_IR_SRC
Definition zend_jit.h:77
#define ZREG_CONST
Definition zend_jit.h:181
#define ZREG_ZVAL_ADDREF
Definition zend_jit.h:184
#define ZEND_JIT_DEBUG_IR_CODEGEN
Definition zend_jit.h:85
#define ZREG_THIS
Definition zend_jit.h:185
#define TRACE_FRAME_IS_UNKNOWN_RETURN(frame)
#define TRACE_FRAME_IS_NESTED(frame)
#define ZEND_JIT_EXIT_CHECK_EXCEPTION
#define TRACE_FRAME_NO_NEED_RELEASE_THIS(frame)
void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
#define Z_LOAD(addr)
#define ZEND_JIT_EXIT_CLOSURE_CALL
#define TRACE_FRAME_SET_THIS_CLASS_CHECKED(frame)
#define OP1_DATA_ADDR()
#define TRACE_FRAME_SET_THIS_CHECKED(frame)
#define ZEND_JIT_EXIT_METHOD_CALL
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(EXECUTE_DATA_D)
#define TRACE_FRAME_IS_LAST_SEND_BY_REF(frame)
#define Z_REG(addr)
zend_ulong zend_jit_profile_counter
void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D)
struct _zend_jit_trace_exit_info zend_jit_trace_exit_info
#define STACK_FLAGS(_stack, _slot)
uintptr_t zend_jit_addr
#define ZEND_JIT_EXIT_PACKED_GUARD
#define IS_TRACE_REFERENCE
zend_constant *ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags)
#define Z_SSA_VAR(addr)
void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D)
#define TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame)
#define TRACE_FRAME_IS_CLOSURE_CALL(frame)
void ZEND_FASTCALL zend_jit_undefined_long_key_ex(zend_long key EXECUTE_DATA_DC)
#define TRACE_FRAME_SET_LAST_SEND_BY_VAL(frame)
#define OP1_ADDR()
#define TRACE_FRAME_ALWAYS_RELEASE_THIS(frame)
#define Z_MODE(addr)
#define IS_TRACE_PACKED
struct _zend_jit_trace_info zend_jit_trace_info
#define ZEND_ADDR_MEM_ZVAL(reg, offset)
bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D)
#define Z_STORE(addr)
#define OP2_ADDR()
#define CLEAR_STACK_REF(_stack, _slot)
#define IS_REF_ZVAL
struct _zend_jit_ref_snapshot zend_jit_ref_snapshot
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC)
@ ZEND_JIT_TRACE_ENTER
@ ZEND_JIT_TRACE_END
@ ZEND_JIT_TRACE_DO_ICALL
@ ZEND_JIT_TRACE_VM
@ ZEND_JIT_TRACE_INIT_CALL
@ ZEND_JIT_TRACE_BACK
#define IS_MEM_ZVAL
int zend_jit_profile_counter_rid
#define TRACE_FRAME_IS_THIS_CHECKED(frame)
struct _zend_jit_op_array_trace_extension zend_jit_op_array_trace_extension
#define STACK_REG(_stack, _slot)
#define SET_STACK_REG_EX(_stack, _slot, _reg, _flags)
#define STACK_TYPE(_stack, _slot)
#define ZEND_JIT_EXIT_TO_VM
#define TRACE_FRAME_IS_RETURN_VALUE_USED(frame)
void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
#define IS_TRACE_INDIRECT
#define RES_ADDR()
const zend_op * zend_jit_halt_op
void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC)
#define TRACE_FRAME_IS_RETURN_VALUE_UNUSED(frame)
#define ZEND_ADDR_REF_ZVAL(ref)
#define ZEND_JIT_EXIT_FIXED
#define Z_OFFSET(addr)
#define ZEND_ADDR_REG(reg)
#define Z_IR_REF(addr)
#define STACK_REF(_stack, _slot)
union _zend_jit_exit_const zend_jit_exit_const
ZEND_OPCODE_HANDLER_RET(ZEND_FASTCALL * zend_vm_opcode_handler_t)(ZEND_OPCODE_HANDLER_ARGS)
#define Z_ZV(addr)
#define SET_STACK_INFO(_stack, _slot, _info)
#define IS_CONST_ZVAL
#define ZEND_OP_TRACE_INFO(opline, offset)
struct _zend_jit_trace_stack zend_jit_trace_stack
#define TRACE_FRAME_NUM_ARGS(frame)
#define SET_STACK_REG(_stack, _slot, _reg)
#define ZEND_JIT_EXIT_FREE_OP1
#define IS_REG
struct _zend_jit_op_array_hot_extension zend_jit_op_array_hot_extension
#define STACK_MEM_TYPE(_stack, _slot)
zend_constant *ZEND_FASTCALL zend_jit_check_constant(const zval *key)
#define ZEND_JIT_EXIT_RESTORE_CALL
#define ZEND_JIT_TRACE_LOOP
#define ZEND_JIT_EXIT_POLYMORPHISM
#define TRACE_FRAME_IS_THIS_CLASS_CHECKED(frame)
#define STACK_INFO(_stack, _slot)
#define IS_UNKNOWN
#define SET_STACK_REF_EX(_stack, _slot, _ref, _flags)
#define SET_STACK_REF(_stack, _slot, _ref)
#define ZEND_JIT_EXIT_FREE_OP2
#define ZEND_JIT_EXIT_INVALIDATE
struct _zend_jit_op_array_extension zend_jit_op_array_extension
#define TRACE_FRAME_SET_LAST_SEND_BY_REF(frame)
union _zend_op_trace_info zend_op_trace_info
int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline)
#define SET_STACK_TYPE(_stack, _slot, _type, _set_mem_type)
#define jit_EX(_field)
#define ir_ADD_OV_L
#define ir_MOD_L
_jit_stub_id
@ jit_last_stub
#define ir_DIV_L
#define ir_AND_L
#define JIT_STUB_FORWARD(name, flags)
#define ir_BINARY_OP_L
void * zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
#define jit_CALL(_call, _field)
#define ZREG_RX
Definition zend_jit_ir.c:58
struct _zend_jit_ctx zend_jit_ctx
#define ir_CONST_FUNC(_addr)
Definition zend_jit_ir.c:68
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs)
uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
#define ir_ZEXT_L
void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
struct _Unwind_Context _Unwind_Context
#define ir_SUB_L
#define ir_CONST_LONG
#define ir_ADD_L
#define REGISTER_HELPER(n)
#define ZEND_JIT_EXIT_POINTS_SPACING
#define IR_LONG
#define ir_SHR_L
#define JIT_STUB(name, flags)
struct _zend_jit_unwind_arg zend_jit_unwind_arg
#define ir_CAST_FC_FUNC(_addr)
Definition zend_jit_ir.c:70
#define ir_SAR_L
int8_t zend_reg
struct _zend_jit_reg_var zend_jit_reg_var
struct _zend_jit_stub zend_jit_stub
#define jit_EG(_field)
#define ir_SUB_OV_L
#define ir_ADD_OFFSET(_addr, _offset)
Definition zend_jit_ir.c:77
#define ir_SHL_L
#define JIT_STUBS(_)
#define REGISTER_DATA(n)
uintptr_t _Unwind_GetCFA(_Unwind_Context *)
#define ir_BITCAST_L
#define ir_refs_init(_name, _n)
#define JIT_STUB_ID(name, flags)
#define ir_CONST_FUNC_PROTO(_addr, _proto)
Definition zend_jit_ir.c:73
enum _jit_stub_id jit_stub_id
struct _ir_refs ir_refs
#define ir_MUL_L
int _Unwind_Backtrace(_Unwind_Trace_Fn, void *)
#define jit_CG(_field)
#define jit_RX(_field)
#define ir_CONST_ADDR(_addr)
Definition zend_jit_ir.c:67
#define ir_LOAD_L
#define ir_CONST_FC_FUNC(_addr)
Definition zend_jit_ir.c:69
struct _zend_jit_registers_buf zend_jit_registers_buf
#define ZEND_JIT_EXIT_POINTS_PER_GROUP
int(* _Unwind_Trace_Fn)(_Unwind_Context *, void *)
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_MIN
Definition zend_long.h:46
uint32_t zend_ulong
Definition zend_long.h:43
#define SIZEOF_ZEND_LONG
Definition zend_long.h:50
#define ZEND_LONG_MAX
Definition zend_long.h:45
struct _zend_string zend_string
#define ZEND_MAP_PTR_IS_OFFSET(ptr)
#define ZEND_MAP_PTR(ptr)
#define ZEND_FIRST_PROPERTY_OFFSET
ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object)
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end_prechecked(zend_execute_data *execute_data, zval *return_value)
int zend_observer_fcall_op_array_extension
int zend_observer_fcall_internal_function_extension
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin_prechecked(zend_execute_data *execute_data, zend_observer_fcall_begin_handler *handler)
#define ZEND_OBSERVER_NONE_OBSERVED
#define ZEND_OBSERVER_ENABLED
#define ZEND_OBSERVER_HANDLE(function)
ZEND_API zend_result ZEND_FASTCALL decrement_function(zval *op1)
ZEND_API bool ZEND_FASTCALL zend_is_identical(const zval *op1, const zval *op2)
ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2)
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2)
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
ZEND_API zend_result ZEND_FASTCALL increment_function(zval *op1)
ZEND_API zend_result ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2)
ZEND_API zend_result ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2)
#define ALLOCA_FLAG(name)
#define zend_never_inline
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define do_alloca(p, use_heap)
#define ZEND_FASTCALL
#define ZEND_ASSERT(c)
#define ZEND_UNREACHABLE()
#define free_alloca(p, use_heap)
#define UNEXPECTED(condition)
struct _zend_array zend_array
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
bool zend_accel_in_shm(void *ptr)
struct _zend_ssa_range zend_ssa_range
struct _zend_ssa zend_ssa
struct _zend_ssa_phi zend_ssa_phi
Definition zend_ssa.h:62
struct _zend_ssa_op zend_ssa_op
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define dval(x)
#define MAY_BE_REF
#define MAY_BE_ARRAY_OF_ANY
#define MAY_BE_ARRAY_PACKED
#define MAY_BE_STRING
#define MAY_BE_HASH(t)
#define MAY_BE_ARRAY_OF_ARRAY
#define MAY_BE_RC1
#define MAY_BE_FALSE
#define MAY_BE_ARRAY_OF_OBJECT
#define MAY_BE_ARRAY_SHIFT
#define MAY_BE_ARRAY_KEY_STRING
#define MAY_BE_ARRAY_OF_REF
#define MAY_BE_UNDEF
#define MAY_BE_NULL
#define MAY_BE_DOUBLE
#define MAY_BE_ARRAY_OF_RESOURCE
#define MAY_BE_LONG
#define MAY_BE_TRUE
#define MAY_BE_ANY
#define MAY_BE_OBJECT
#define MAY_BE_ARRAY_KEY_LONG
#define MAY_BE_PACKED(t)
#define MAY_BE_ARRAY_KEY_ANY
#define MAY_BE_ARRAY_NUMERIC_HASH
#define MAY_BE_INDIRECT
#define MAY_BE_ARRAY_OF_STRING
#define MAY_BE_RESOURCE
#define MAY_BE_RCN
#define MAY_BE_ARRAY
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZEND_TYPE_PURE_MASK(t)
Definition zend_types.h:257
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define IS_STR_INTERNED
Definition zend_types.h:817
#define ZVAL_LONG(z, l)
#define GC_REFERENCE
Definition zend_types.h:789
#define IS_STRING
Definition zend_types.h:606
#define Z_REFCOUNTED_P(zval_p)
Definition zend_types.h:921
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_TYPE_COLLECTABLE
Definition zend_types.h:794
#define GC_INFO_MASK
Definition zend_types.h:738
#define IS_ARRAY
Definition zend_types.h:607
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_TYPE_INFO_P(zval_p)
Definition zend_types.h:669
#define _IS_ERROR
Definition zend_types.h:626
#define IS_REFERENCE_EX
Definition zend_types.h:811
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_PTR_P(zval_p)
#define ZEND_TYPE_FULL_MASK(t)
Definition zend_types.h:254
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_STRING_EX
Definition zend_types.h:807
#define IS_NULL
Definition zend_types.h:601
#define Z_CONSTANT_P(zval_p)
Definition zend_types.h:912
#define Z_TYPE_FLAGS_MASK
Definition zend_types.h:702
#define IS_OBJECT
Definition zend_types.h:608
#define IS_LONG
Definition zend_types.h:604
#define ZEND_TYPE_IS_SET(t)
Definition zend_types.h:166
#define IS_REFERENCE
Definition zend_types.h:610
struct _zend_refcounted zend_refcounted
Definition zend_types.h:95
struct _Bucket Bucket
#define Z_TYPE_FLAGS_P(zval_p)
Definition zend_types.h:663
#define GC_NOT_COLLECTABLE
Definition zend_types.h:778
#define IS_OBJECT_EX
Definition zend_types.h:809
#define Z_DVAL_P(zval_p)
Definition zend_types.h:969
#define IS_INDIRECT
Definition zend_types.h:623
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_EXTRA_P(zval_p)
Definition zend_types.h:696
struct _zend_reference zend_reference
Definition zend_types.h:100
#define GC_FLAGS_SHIFT
Definition zend_types.h:739
#define IS_ARRAY_EX
Definition zend_types.h:808
ZEND_API void ZEND_FASTCALL rc_dtor_func(zend_refcounted *p)
ZEND_API const void *ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *op)
ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op *opcode)
ZEND_API int zend_vm_kind(void)
uint32_t call_info
zval * return_value
zval * arg1
call prev_execute_data
zval * arg2
zend_property_info * prop_info
uint32_t arg_num
zend_string * name
zval * arg3
fbc internal_function handler(call, ret)
zend_function * fbc
bool result
op2
function(EX_VAR(opline->result.var))
op1
object
zval * ret
value
zend_execute_data * call
new_op_array scope
#define ZEND_FE_FREE
#define ZEND_SL
#define ZEND_SEND_VAR_EX
#define ZEND_IS_IDENTICAL
#define ZEND_YIELD
#define ZEND_FETCH_CONSTANT
#define ZEND_SWITCH_LONG
#define ZEND_ASSIGN_DIM_OP
#define ZEND_ASSIGN_STATIC_PROP_REF
#define ZEND_PRE_DEC_OBJ
#define ZEND_BOOL_NOT
#define ZEND_RECV_INIT
#define ZEND_FETCH_OBJ_W
#define ZEND_FE_FETCH_RW
#define ZEND_SEND_VAL_EX
#define ZEND_FETCH_LIST_R
#define ZEND_INCLUDE_OR_EVAL
#define ZEND_RETURN
#define ZEND_FE_RESET_RW
#define ZEND_THROW
#define ZEND_FE_FETCH_R
#define ZEND_GENERATOR_CREATE
#define ZEND_ROPE_INIT
#define ZEND_TICKS
#define ZEND_FETCH_LIST_W
#define ZEND_INIT_FCALL
#define ZEND_SEND_VAL
#define ZEND_RETURN_BY_REF
#define ZEND_SWITCH_STRING
#define ZEND_ASSIGN_DIM
#define ZEND_JMPZ
#define ZEND_FETCH_OBJ_FUNC_ARG
#define ZEND_PRE_INC_OBJ
#define ZEND_ASSIGN_STATIC_PROP_OP
#define ZEND_JMP_SET
#define ZEND_SUB
#define ZEND_EXT_FCALL_BEGIN
#define ZEND_JMPZ_EX
#define ZEND_IS_SMALLER
#define ZEND_PRE_INC
#define ZEND_HANDLE_EXCEPTION
#define ZEND_POST_INC
#define ZEND_PRE_DEC
#define ZEND_SEND_ARRAY
#define ZEND_SEND_UNPACK
#define ZEND_BW_XOR
#define ZEND_IS_NOT_EQUAL
#define ZEND_IS_NOT_IDENTICAL
#define ZEND_FETCH_OBJ_IS
#define ZEND_DO_UCALL
#define ZEND_DIV
#define ZEND_SEND_VAR
#define ZEND_POST_DEC_OBJ
#define ZEND_CONCAT
#define ZEND_MATCH
#define ZEND_BW_OR
#define ZEND_RECV
#define ZEND_VM_KIND_HYBRID
#define ZEND_FRAMELESS_ICALL_3
#define ZEND_INIT_NS_FCALL_BY_NAME
#define ZEND_JMPNZ_EX
#define ZEND_DO_FCALL
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_IS_EQUAL
#define ZEND_IS_SMALLER_OR_EQUAL
#define ZEND_POST_DEC
#define ZEND_BOOL
#define ZEND_INIT_FCALL_BY_NAME
#define ZEND_YIELD_FROM
#define ZEND_STRLEN
#define ZEND_MUL
#define ZEND_CASE_STRICT
#define ZEND_ROPE_END
#define ZEND_FAST_CALL
#define ZEND_SEND_VAR_NO_REF_EX
#define ZEND_DO_ICALL
#define ZEND_SEND_FUNC_ARG
#define ZEND_JMP_NULL
#define ZEND_FETCH_OBJ_R
#define ZEND_CHECK_UNDEF_ARGS
#define ZEND_ISSET_ISEMPTY_DIM_OBJ
#define ZEND_BIND_INIT_STATIC_OR_JMP
#define ZEND_BW_AND
#define ZEND_GENERATOR_RETURN
#define ZEND_FETCH_DIM_W
#define ZEND_JMP
#define ZEND_FE_RESET_R
#define ZEND_ASSIGN_OBJ
#define ZEND_ASSIGN_OBJ_OP
#define ZEND_ASSIGN_OBJ_REF
#define ZEND_ASSIGN
#define ZEND_SR
#define ZEND_COUNT
#define ZEND_FETCH_DIM_IS
#define ZEND_VERIFY_NEVER_TYPE
#define ZEND_FETCH_DIM_UNSET
#define ZEND_SEND_VAR_NO_REF
#define ZEND_POST_INC_OBJ
#define ZEND_FETCH_DIM_R
#define ZEND_DO_FCALL_BY_NAME
#define ZEND_JMPNZ
#define ZEND_INIT_METHOD_CALL
#define ZEND_QM_ASSIGN
#define ZEND_MOD
#define ZEND_CATCH
#define ZEND_ADD
#define ZEND_COALESCE
#define ZEND_ASSIGN_OP
#define ZEND_FETCH_DIM_RW
#define ZEND_MATCH_ERROR
#define ZEND_VM_KIND_CALL
#define ZEND_FAST_RET
#define ZEND_CASE
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap)
struct _zend_worklist zend_worklist
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap)